Compare commits

..

No commits in common. "rawhide" and "f39" have entirely different histories.

39 changed files with 4163 additions and 183 deletions

1
.gitignore vendored
View file

@ -4,4 +4,3 @@
/2ea854ae8c7a.zip
/vdr-dvbsddevice-2.2.0.tgz
/vdr-rcu-2.2.0.tgz
/3473a7b939d7.zip

View file

@ -0,0 +1,29 @@
From 0376d2e4adc38528c0cbdde759a56700bee95872 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ville=20Skytt=C3=A4?= <ville.skytta@iki.fi>
Date: Fri, 17 Jun 2016 17:08:31 +0300
Subject: [PATCH] Fix build with systemd >= 230
libsystemd-daemon has been merged to libsystemd.
---
Makefile | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/Makefile b/Makefile
index b90cbd2..9193cde 100644
--- a/Makefile
+++ b/Makefile
@@ -95,9 +95,9 @@ DEFINES += -DBIDI
LIBS += $(shell pkg-config --libs fribidi)
endif
ifdef SDNOTIFY
-INCLUDES += $(shell pkg-config --cflags libsystemd-daemon)
+INCLUDES += $(shell pkg-config --silence-errors --cflags libsystemd-daemon || pkg-config --cflags libsystemd)
DEFINES += -DSDNOTIFY
-LIBS += $(shell pkg-config --libs libsystemd-daemon)
+LIBS += $(shell pkg-config --silence-errors --libs libsystemd-daemon || pkg-config --libs libsystemd)
endif
LIRC_DEVICE ?= /var/run/lirc/lircd
--
2.5.5

12
dvbhdffdevice.patch Normal file
View file

@ -0,0 +1,12 @@
--- dvbhddevice/dvbhdffdevice.c.orig 2018-04-17 13:57:26.871268867 +0200
+++ dvbhddevice/dvbhdffdevice.c 2018-04-17 13:58:45.698264299 +0200
@@ -461,7 +461,8 @@
const tTrackId *TrackId = GetTrack(Type);
if (TrackId && TrackId->id) {
int streamType = 0;
- cChannel * channel = Channels.GetByNumber(CurrentChannel());
+ LOCK_CHANNELS_READ;
+ const cChannel * channel = Channels->GetByNumber(CurrentChannel());
if (channel) {
if (IS_AUDIO_TRACK(Type))
streamType = channel->Atype(Type - ttAudioFirst);

View file

@ -0,0 +1,66 @@
diff -Naur vdr-2.4.7/PLUGINS/src/dvbhddevice/dvbhdffdevice.c vdr-2.4.7-new/PLUGINS/src/dvbhddevice/dvbhdffdevice.c
--- vdr-2.4.7/PLUGINS/src/dvbhddevice/dvbhdffdevice.c 2018-04-20 22:23:47.000000000 +0200
+++ vdr-2.4.7-new/PLUGINS/src/dvbhddevice/dvbhdffdevice.c 2021-08-03 14:22:36.172626332 +0200
@@ -11,9 +11,9 @@
#include <limits.h>
#include <libsi/si.h>
#include <linux/videodev2.h>
-#include <linux/dvb/audio.h>
+#include <../kernel-headers-5.13/audio.h>
#include <linux/dvb/dmx.h>
-#include <linux/dvb/video.h>
+#include <../kernel-headers-5.13/video.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <vdr/eitscan.h>
diff -Naur vdr-2.4.7/PLUGINS/src/dvbhddevice/hdffosd.c vdr-2.4.7-new/PLUGINS/src/dvbhddevice/hdffosd.c
--- vdr-2.4.7/PLUGINS/src/dvbhddevice/hdffosd.c 2018-04-20 22:23:47.000000000 +0200
+++ vdr-2.4.7-new/PLUGINS/src/dvbhddevice/hdffosd.c 2021-08-03 14:22:36.177626332 +0200
@@ -5,7 +5,7 @@
*/
#include "hdffosd.h"
-#include <linux/dvb/osd.h>
+#include <../kernel-headers-5.13/osd.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include "hdffcmd.h"
diff -Naur vdr-2.4.7/PLUGINS/src/dvbhddevice/dvbsdffosd.c vdr-2.4.7-new/PLUGINS/src/dvbhddevice/dvbsdffosd.c
--- vdr-2.4.7/PLUGINS/src/dvbsddevice/dvbsdffosd.c 2011-04-17 14:55:09.000000000 +0200
+++ vdr-2.4.7-new/PLUGINS/src/dvbsddevice/dvbsdffosd.c 2021-08-03 14:22:36.188626333 +0200
@@ -7,7 +7,7 @@
*/
#include "dvbsdffosd.h"
-#include <linux/dvb/osd.h>
+#include <../kernel-headers-5.13/osd.h>
#include <signal.h>
#include <sys/ioctl.h>
#include <sys/unistd.h>
diff -Naur vdr-2.4.7/PLUGINS/src/dvbhddevice/libhdffcmd/hdffcmd_base.h vdr-2.4.7-new/PLUGINS/src/dvbhddevice/libhdffcmd/hdffcmd_base.h
--- vdr-2.4.7/PLUGINS/src/dvbhddevice/libhdffcmd/hdffcmd_base.h 2018-04-20 22:23:47.000000000 +0200
+++ vdr-2.4.7-new/PLUGINS/src/dvbhddevice/libhdffcmd/hdffcmd_base.h 2021-08-03 14:22:36.193626333 +0200
@@ -24,7 +24,7 @@
#ifndef HDFFCMD_BASE_H
#define HDFFCMD_BASE_H
-#include <linux/dvb/osd.h>
+#include <../kernel-headers-5.13/osd.h>
#if !defined OSD_RAW_CMD
typedef struct osd_raw_cmd_s {
diff -Naur vdr-2.4.7/PLUGINS/src/dvbsddevice/dvbsdffdevice.c vdr-2.4.7-new/PLUGINS/src/dvbsddevice/dvbsdffdevice.c
--- vdr-2.4.7/PLUGINS/src/dvbsddevice/dvbsdffdevice.c 2014-03-15 13:35:21.000000000 +0100
+++ vdr-2.4.7-new/PLUGINS/src/dvbsddevice/dvbsdffdevice.c 2021-08-03 14:22:36.203626334 +0200
@@ -10,9 +10,9 @@
#include <errno.h>
#include <limits.h>
#include <linux/videodev2.h>
-#include <linux/dvb/audio.h>
+#include <../kernel-headers-5.13/audio.h>
#include <linux/dvb/dmx.h>
-#include <linux/dvb/video.h>
+#include <../kernel-headers-5.13/video.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <vdr/eitscan.h>

View file

@ -1,12 +1,8 @@
Description: This patch allows plugins to replace the VDR mainmenus "Schedule", "Channels", "Timers" and "Recordings" by a different implementation.
Author: Frank Schmirler <vdrdev@schmirler.de>
This is a "patch" for the Video Disk Recorder (VDR).
* History
2025-02-26: Version 1.0.4
Update für vdr-2.7.4 (Jörg Riechardt)
2013-11-08: Version 1.0.3
Update für vdr-2.1.2 (Jörg Riechardt)
2012-04-06: Version 1.0.2
- Update für aktuelle VDR-Entwickler-Versionen (Manuel Reimer)
@ -79,25 +75,11 @@ think you need to modify the patch, we'd encourage you to contact the
authors first or at least use a service id which differs in more than
just the version number.
diff -Nrup vdr-2.7.4/config.h vdr-2.7.4-test/config.h
--- vdr-2.7.4/config.h 2025-02-26 10:35:03.000000000 +0100
+++ vdr-2.7.4-test/config.h 2025-02-26 14:46:28.768820964 +0100
@@ -35,6 +35,10 @@
// only when there are changes to the plugin API. This allows compiled
// plugins to work with newer versions of the core VDR as long as no
// interfaces have changed. APIVERSNUM begins with "300.." for backwards
+
+// The MainMenuHook Patch's version number:
+#define MAINMENUHOOKSVERSION "1.0.1"
+#define MAINMENUHOOKSVERSNUM 10001 // Version * 10000 + Major * 100 + Minor
// compatibility and can be used in #if preprocessor statements to handle
// version dependent code.
diff -Nrup vdr-2.7.4/menu.c vdr-2.7.4-test/menu.c
--- vdr-2.7.4/menu.c 2025-02-26 10:35:03.000000000 +0100
+++ vdr-2.7.4-test/menu.c 2025-02-26 15:20:42.252563574 +0100
@@ -4493,15 +4493,31 @@ cMenuMain::cMenuMain(eOSState State, boo
Index: b/menu.c
===================================================================
--- a/menu.c
+++ b/menu.c
@@ -4620,15 +4620,31 @@
// Initial submenus:
@ -123,7 +105,7 @@ diff -Nrup vdr-2.7.4/menu.c vdr-2.7.4-test/menu.c
+ break;
+ case osRecordings:
+ if (!cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osRecordings", &menu))
+ menu = new cMenuRecordings(NULL, 0, OpenSubMenus);
+ menu = new cMenuRecordings(NULL, 0, true);
+ break;
+ case osSetup: menu = new cMenuSetup; break;
+ case osCommands: menu = new cMenuCommands(tr("Commands"), &Commands); break;
@ -135,7 +117,7 @@ diff -Nrup vdr-2.7.4/menu.c vdr-2.7.4-test/menu.c
}
cOsdObject *cMenuMain::PluginOsdObject(void)
@@ -4613,13 +4629,34 @@ eOSState cMenuMain::ProcessKey(eKeys Key
@@ -4765,13 +4781,34 @@
eOSState state = cOsdMenu::ProcessKey(Key);
HadSubMenu |= HasSubMenu();
@ -176,7 +158,7 @@ diff -Nrup vdr-2.7.4/menu.c vdr-2.7.4-test/menu.c
case osStopRecord: if (Interface->Confirm(tr("Stop recording?"))) {
if (cOsdItem *item = Get(Current())) {
cRecordControls::Stop(item->Text() + strlen(tr(STOP_RECORDING)));
@@ -4670,6 +4707,12 @@ eOSState cMenuMain::ProcessKey(eKeys Key
@@ -4857,6 +4894,12 @@
default: break;
}
}
@ -185,7 +167,22 @@ diff -Nrup vdr-2.7.4/menu.c vdr-2.7.4-test/menu.c
+ return AddSubMenu((cOsdMenu *) menu);
+ pluginOsdObject = menu;
+ return osPlugin;
+ }
bool DoDisplay = Update();
+ }
if (!HasSubMenu() && Update(HadSubMenu))
Display();
if (Key != kNone) {
if (I18nCurrentLanguage() != osdLanguage) {
Index: b/config.h
===================================================================
--- a/config.h
+++ b/config.h
@@ -36,6 +36,10 @@
// plugins to work with newer versions of the core VDR as long as no
// VDR header files have changed.
+// The MainMenuHook Patch's version number:
+#define MAINMENUHOOKSVERSION "1.0.1"
+#define MAINMENUHOOKSVERSNUM 10001 // Version * 10000 + Major * 100 + Minor
+
#define MAXPRIORITY 99
#define MINPRIORITY (-MAXPRIORITY)
#define LIVEPRIORITY 0 // priority used when selecting a device for live viewing

View file

@ -0,0 +1,21 @@
Description: Log an error message when skincures can't initialize the screen
Author: Tobias Grimm <etobi@debian.org>
--- a/PLUGINS/src/skincurses/skincurses.c
+++ b/PLUGINS/src/skincurses/skincurses.c
@@ -11,6 +11,7 @@
#include <vdr/plugin.h>
#include <vdr/skins.h>
#include <vdr/videodir.h>
+#include <vdr/tools.h>
static const char *VERSION = "2.4.0";
static const char *DESCRIPTION = trNOOP("A text only skin");
@@ -833,6 +834,7 @@
ScOsdHeight = w->_maxy - w->_begy + 1;
return true;
}
+ esyslog("skincurses: unable to initialize curses screen");
return false;
}

View file

@ -1,7 +1,7 @@
SHA512 (vdr-2.7.7.tar.bz2) = 22c561aea6c2ae29f27d024249501c3c748cd77e9c182ed969a59f24b4b360b59cf807e1214665bbec7797b6ec11beeac0b2f02e8427f0c91cf9c29144bd5154
SHA512 (vdr-2.6.4.tar.bz2) = 2e69b67c82dd9dd1473c8776524b3888944957d4c6d7cf8f7713de4935819853dc481f04a87936bba8b1f56d9f3d8018f0820a3b1505bec2fceea6863e5d3776
SHA512 (vdr-rcu-2.2.0.tgz) = 56abebcfde3511c4dcf6f414915c7aa70a16b8e138e2d9364080828edc9b0da045acaadaaa4094d1315ddefdafa5f966aebcfacf979c068e077f1e32e29773b7
SHA512 (vdr-dvbsddevice-2.2.0.tgz) = ac0b94b8b192208ad7e736d7c4f27cca6517134b17fc86a79cdd19453176d5f6076418bf679435899cd953053f3b54776342bcdab23a659e8331e9f2ed4ee364
SHA512 (3473a7b939d7.zip) = fc405ac81cc1374de3a2d457f76972e605cf51c20c5e86f4fb683bb7fc78fde51690e65f463870c6881a65308722ccecd60d4a8957e3e2d43ecfd665f0e5aa8f
SHA512 (2ea854ae8c7a.zip) = 2b3e5c91646e4250afc53577393c9d10f11fcbc46353535e38e9ddcfbf5642a4dd0355bd7583262bd684ef76cf75373585b3f67fdf154f22ee85541625fa467f
SHA512 (vdr_2.2.0-5.debian.tar.bz2) = 6ba924fee84673be2a2652a26bccde4dc07dd9c7bcc871868f44bdc2748136a8ac26feb026c5b5dd9b3831c641ef1e729052c1190a45cc805f3fa563c3a59798
SHA512 (vdr_1.4.5-2.ds.diff.gz) = dc82ca24e830a4fc4bfed51b2d112301b9058f2d1fea93761a42df8715dbe3ba0e9e8621464c8a6fe2dd3bd62d33efaff911182d3489ef741096654b7a3eb326
SHA512 (vdr-2.4.6-editrecording.patch.gz) = 0935fdbe6b557c8b03396ff31021b35758a040f297315f39bdf605961a8ad77897884b527e2655e36ff8241e06cd1b2592c3bd0be09e78434263e43e85368e86

View file

@ -0,0 +1,106 @@
diff -Nru vdr-1.5.17-orig/skinclassic.c vdr-1.5.17-progressbar/skinclassic.c
--- vdr-1.5.17-orig/skinclassic.c
+++ vdr-1.5.17-progressbar/skinclassic.c
@@ -314,8 +314,47 @@
for (int i = 0; i < MaxTabs; i++) {
const char *s = GetTabbedText(Text, i);
if (s) {
- int xt = x0 + Tab(i);
- osd->DrawText(xt, y, s, ColorFg, ColorBg, font, x2 - xt);
+ bool isprogressbar = false;
+ int now = 0, total = 0;
+ // check if progress bar: "[||||||| ]"
+ if ((strlen(s) > 5 && s[0] == '[' && s[strlen(s) - 1] == ']')) {
+ const char *p = s + 1;
+ // update status
+ isprogressbar = true;
+ for (; *p != ']'; ++p) {
+ // check if progressbar characters
+ if (*p == ' ' || *p == '|') {
+ // update counters
+ ++total;
+ if (*p == '|')
+ ++now;
+ }
+ else {
+ // wrong character detected; not a progressbar
+ isprogressbar = false;
+ break;
+ }
+ }
+ }
+ int xt = x0 + Tab(i);
+ if (isprogressbar) {
+ // define x coordinates of progressbar
+ int px0 = xt;
+ int px1 = (Tab(i + 1)?Tab(i+1):x1) - 5;
+ int px = px0 + max((int)((float) now * (float) (px1 - px0) / (float) total), 1);
+ // define y coordinates of progressbar
+ int py0 = y + 4;
+ int py1 = y + lineHeight - 4;
+ // draw background
+ osd->DrawRectangle(px0, y, (Tab(i + 1)?Tab(i+1):x1) - 1, y + lineHeight - 1, ColorBg);
+ // draw progressbar
+ osd->DrawRectangle(px0, py0, px, py1, ColorFg);
+ osd->DrawRectangle(px + 1, py0, px1, py0 + 1, ColorFg);
+ osd->DrawRectangle(px + 1, py1 - 1, px1, py1, ColorFg);
+ osd->DrawRectangle(px1 - 1, py0, px1, py1, ColorFg);
+ }
+ else
+ osd->DrawText(xt, y, s, ColorFg, ColorBg, font, x2 - xt);
}
if (!Tab(i + 1))
break;
diff -Nru vdr-1.5.17-orig/skinsttng.c vdr-1.5.17-progressbar/skinsttng.c
--- vdr-1.5.17-orig/skinsttng.c
+++ vdr-1.5.17-progressbar/skinsttng.c
@@ -558,8 +558,47 @@
for (int i = 0; i < MaxTabs; i++) {
const char *s = GetTabbedText(Text, i);
if (s) {
- int xt = x3 + 5 + Tab(i);
- osd->DrawText(xt, y, s, ColorFg, ColorBg, font, x4 - xt);
+ bool isprogressbar = false;
+ int now = 0, total = 0;
+ // check if progress bar: "[||||||| ]"
+ if ((strlen(s) > 5 && s[0] == '[' && s[strlen(s) - 1] == ']')) {
+ const char *p = s + 1;
+ // update status
+ isprogressbar = true;
+ for (; *p != ']'; ++p) {
+ // check if progressbar characters
+ if (*p == ' ' || *p == '|') {
+ // update counters
+ ++total;
+ if (*p == '|')
+ ++now;
+ }
+ else {
+ // wrong character detected; not a progressbar
+ isprogressbar = false;
+ break;
+ }
+ }
+ }
+ int xt = x3 + 5 + Tab(i);
+ if (isprogressbar) {
+ // define x coordinates of progressbar
+ int px0 = xt;
+ int px1 = x3 + (Tab(i + 1)?Tab(i + 1):x4-x3-5) - 1;
+ int px = px0 + max((int)((float) now * (float) (px1 - px0) / (float) total), 1);
+ // define y coordinates of progressbar
+ int py0 = y + 4;
+ int py1 = y + lineHeight - 4;
+ // draw background
+ osd->DrawRectangle(px0, y, (Tab(i + 1)?Tab(i + 1):x4-x3-5) - 1, y + lineHeight - 1, ColorBg);
+ // draw progressbar
+ osd->DrawRectangle(px0, py0, px, py1, ColorFg);
+ osd->DrawRectangle(px + 1, py0, px1, py0 + 1, ColorFg);
+ osd->DrawRectangle(px + 1, py1 - 1, px1, py1, ColorFg);
+ osd->DrawRectangle(px1 - 1, py0, px1, py1, ColorFg);
+ }
+ else
+ osd->DrawText(xt, y, s, ColorFg, ColorBg, font, x4 - xt);
}
if (!Tab(i + 1))
break;

114
vdr-1.5.18-syncearly.patch Normal file
View file

@ -0,0 +1,114 @@
Sync early parts extracted from the non-dvbs2 patch at
http://article.gmane.org/gmane.linux.vdr/36097, fprintf(stderr) calls
changed to dsyslog().
diff -Nurp ../vdr-1.5.18-orig/device.c ./device.c
--- ../vdr-1.5.18-orig/device.c 2008-03-09 11:03:34.000000000 +0100
+++ ./device.c 2008-03-19 22:34:40.000000000 +0100
@@ -840,7 +840,7 @@ eSetChannelResult cDevice::SetChannel(co
}
for (int i = 0; i < MAXSPIDS; i++)
SetAvailableTrack(ttSubtitle, i, Channel->Spid(i), Channel->Slang(i));
- if (!NeedsTransferMode)
+ if (!NeedsTransferMode || GetCurrentAudioTrack() == ttNone)
EnsureAudioTrack(true);
EnsureSubtitleTrack();
}
diff -Nurp ../vdr-1.5.18-orig/remux.c ./remux.c
--- ../vdr-1.5.18-orig/remux.c 2007-11-25 14:56:03.000000000 +0100
+++ ./remux.c 2008-02-24 19:47:40.000000000 +0100
@@ -1896,12 +2526,13 @@ int cRingBufferLinearPes::DataReady(cons
#define RESULTBUFFERSIZE KILOBYTE(256)
-cRemux::cRemux(int VPid, const int *APids, const int *DPids, const int *SPids, bool ExitOnFailure)
+cRemux::cRemux(int VPid, const int *APids, const int *DPids, const int *SPids, bool ExitOnFailure, bool SyncEarly)
{
exitOnFailure = ExitOnFailure;
noVideo = VPid == 0 || VPid == 1 || VPid == 0x1FFF;
numUPTerrors = 0;
synced = false;
+ syncEarly = SyncEarly;
skipped = 0;
numTracks = 0;
resultSkipped = 0;
@@ -2105,12 +2840,14 @@ uchar *cRemux::Get(int &Count, uchar *Pi
}
}
else if (!synced) {
- if (pt == I_FRAME) {
+ if (pt == I_FRAME || syncEarly) {
if (PictureType)
*PictureType = pt;
resultSkipped = i; // will drop everything before this position
- SetBrokenLink(data + i, l);
synced = true;
+ if (pt == I_FRAME) // syncEarly: it's ok but there is no need to call SetBrokenLink()
+ SetBrokenLink(data + i, l);
+else dsyslog("video: synced early");
}
}
else if (Count)
@@ -2123,17 +2860,19 @@ uchar *cRemux::Get(int &Count, uchar *Pi
l = GetPacketLength(data, resultCount, i);
if (l < 0)
return resultData;
- if (noVideo) {
+ if (noVideo || !synced && syncEarly) {
+ uchar pt = NO_PICTURE;
if (!synced) {
- if (PictureType)
- *PictureType = I_FRAME;
+ if (PictureType && noVideo)
+ *PictureType = pt;
resultSkipped = i; // will drop everything before this position
synced = true;
+if (!noVideo) dsyslog("audio: synced early");
}
else if (Count)
return resultData;
else if (PictureType)
- *PictureType = I_FRAME;
+ *PictureType = pt;
}
}
if (synced) {
diff -Nurp ../vdr-1.5.18-orig/remux.h ./remux.h
--- ../vdr-1.5.18-orig/remux.h 2007-09-02 12:19:06.000000000 +0200
+++ ./remux.h 2008-02-24 19:47:40.000000000 +0100
@@ -40,6 +40,7 @@
bool noVideo;
int numUPTerrors;
bool synced;
+ bool syncEarly;
int skipped;
cTS2PES *ts2pes[MAXTRACKS];
int numTracks;
@@ -47,12 +48,13 @@
int resultSkipped;
int GetPid(const uchar *Data);
public:
- cRemux(int VPid, const int *APids, const int *DPids, const int *SPids, bool ExitOnFailure = false);
+ cRemux(int VPid, const int *APids, const int *DPids, const int *SPids, bool ExitOnFailure = false, bool SyncEarly = false);
///< Creates a new remuxer for the given PIDs. VPid is the video PID, while
///< APids, DPids and SPids are pointers to zero terminated lists of audio,
///< dolby and subtitle PIDs (the pointers may be NULL if there is no such
///< PID). If ExitOnFailure is true, the remuxer will initiate an "emergency
- ///< exit" in case of problems with the data stream.
+ ///< exit" in case of problems with the data stream. SyncEarly causes cRemux
+ ///< to sync as soon as a video or audio frame is seen.
~cRemux();
void SetTimeouts(int PutTimeout, int GetTimeout) { resultBuffer->SetTimeouts(PutTimeout, GetTimeout); }
///< By default cRemux assumes that Put() and Get() are called from different
diff -Nurp ../vdr-1.5.18-orig/transfer.c ./transfer.c
--- ../vdr-1.5.18-orig/transfer.c 2007-01-05 11:45:28.000000000 +0100
+++ ./transfer.c 2008-02-24 19:47:40.000000000 +0100
@@ -19,7 +19,7 @@ cTransfer::cTransfer(tChannelID ChannelI
,cThread("transfer")
{
ringBuffer = new cRingBufferLinear(TRANSFERBUFSIZE, TS_SIZE * 2, true, "Transfer");
- remux = new cRemux(VPid, APids, Setup.UseDolbyDigital ? DPids : NULL, SPids);
+ remux = new cRemux(VPid, APids, Setup.UseDolbyDigital ? DPids : NULL, SPids, false, true);
}
cTransfer::~cTransfer()

107
vdr-1.7.21-timercmd.patch Normal file
View file

@ -0,0 +1,107 @@
diff -up vdr-1.7.21/config.c~ vdr-1.7.21/config.c
--- vdr-1.7.21/config.c~ 2011-10-18 00:02:51.394223695 +0300
+++ vdr-1.7.21/config.c 2011-10-18 00:12:30.255855027 +0300
@@ -211,6 +211,7 @@ bool cNestedItemList::Save(void)
cNestedItemList Folders;
cNestedItemList Commands;
cNestedItemList RecordingCommands;
+cNestedItemList TimerCommands;
// --- cSVDRPhosts -----------------------------------------------------------
diff -up vdr-1.7.21/config.h~ vdr-1.7.21/config.h
--- vdr-1.7.21/config.h~ 2011-10-18 00:02:51.438227770 +0300
+++ vdr-1.7.21/config.h 2011-10-18 00:12:30.702896536 +0300
@@ -187,6 +187,7 @@ public:
extern cNestedItemList Folders;
extern cNestedItemList Commands;
extern cNestedItemList RecordingCommands;
+extern cNestedItemList TimerCommands;
extern cSVDRPhosts SVDRPhosts;
class cSetupLine : public cListObject {
diff -up vdr-1.7.21/menu.c~ vdr-1.7.21/menu.c
--- vdr-1.7.21/menu.c~ 2011-10-18 00:02:51.428226843 +0300
+++ vdr-1.7.21/menu.c 2011-10-18 00:12:29.520786768 +0300
@@ -1142,6 +1142,7 @@ void cTimerEntry::SetDiskStatus(char Dis
class cMenuTimers : public cOsdMenu {
private:
+ eOSState Commands(eKeys Key = kNone);
int helpKeys;
eOSState Edit(void);
eOSState New(void);
@@ -1259,6 +1260,53 @@ eOSState cMenuTimers::Delete(void)
return osContinue;
}
+#define CHECK_2PTR_NULL(x_,y_) ((x_)? ((y_)? y_:""):"")
+
+eOSState cMenuTimers::Commands(eKeys Key)
+{
+ if (HasSubMenu() || Count() == 0)
+ return osContinue;
+ cTimer *ti = CurrentTimer();
+ if (ti) {
+ char *parameter = NULL;
+ const cEvent *pEvent = ti->Event();
+ int iRecNumber=0;
+
+ if(!pEvent) {
+ Timers.SetEvents();
+ pEvent = ti->Event();
+ }
+ if(pEvent) {
+// create a dummy recording to get the real filename
+ cRecording *rc_dummy = new cRecording(ti, pEvent);
+ Recordings.Load();
+ cRecording *rc = Recordings.GetByName(rc_dummy->FileName());
+
+ delete rc_dummy;
+ if(rc)
+ iRecNumber=rc->Index() + 1;
+ }
+//Parameter format TimerNumber 'ChannelId' Start Stop 'Titel' 'Subtitel' 'file' RecNumer
+// 1 2 3 4 5 6 7 8
+ asprintf(&parameter, "%d '%s' %d %d '%s' '%s' '%s' %d", ti->Index(),
+ *ti->Channel()->GetChannelID().ToString(),
+ (int)ti->StartTime(),
+ (int)ti->StopTime(),
+ CHECK_2PTR_NULL(pEvent, pEvent->Title()),
+ CHECK_2PTR_NULL(pEvent, pEvent->ShortText()),
+ ti->File(),
+ iRecNumber);
+ isyslog("timercmd: %s", parameter);
+ cMenuCommands *menu;
+ eOSState state = AddSubMenu(menu = new cMenuCommands(tr("Timer commands"), &TimerCommands, parameter));
+ free(parameter);
+ if (Key != kNone)
+ state = menu->ProcessKey(Key);
+ return state;
+ }
+ return osContinue;
+}
+
eOSState cMenuTimers::Info(void)
{
if (HasSubMenu() || Count() == 0)
@@ -1346,6 +1394,8 @@ eOSState cMenuTimers::ProcessKey(eKeys K
case kInfo:
case kBlue: return Info();
break;
+ case k1...k9: return Commands(Key);
+ case k0: return (TimerCommands.Count()? Commands():osContinue);
default: break;
}
}
diff -up vdr-1.7.21/vdr.c~ vdr-1.7.21/vdr.c
--- vdr-1.7.21/vdr.c~ 2011-10-18 00:02:51.284213503 +0300
+++ vdr-1.7.21/vdr.c 2011-10-18 00:12:31.901007794 +0300
@@ -602,6 +602,7 @@ int main(int argc, char *argv[])
Timers.Load(AddDirectory(ConfigDirectory, "timers.conf"));
Commands.Load(AddDirectory(ConfigDirectory, "commands.conf"));
RecordingCommands.Load(AddDirectory(ConfigDirectory, "reccmds.conf"));
+ TimerCommands.Load(AddDirectory(ConfigDirectory, "timercmds.conf"));
SVDRPhosts.Load(AddDirectory(ConfigDirectory, "svdrphosts.conf"), true);
Keys.Load(AddDirectory(ConfigDirectory, "remote.conf"));
KeyMacros.Load(AddDirectory(ConfigDirectory, "keymacros.conf"), true);

View file

@ -0,0 +1,612 @@
diff -Naur vdr-1.7.27/config.c vdr-1.7.27-hlcutter/config.c
--- vdr-1.7.27/config.c 2012-02-29 11:15:54.000000000 +0100
+++ vdr-1.7.27-hlcutter/config.c 2012-03-31 13:25:56.000000000 +0200
@@ -445,8 +445,10 @@
FontSmlSize = 18;
FontFixSize = 20;
MaxVideoFileSize = MAXVIDEOFILESIZEDEFAULT;
+ MaxRecordingSize = DEFAULTRECORDINGSIZE;
SplitEditedFiles = 0;
DelTimeshiftRec = 0;
+ HardLinkCutter = 0;
MinEventTimeout = 30;
MinUserInactivity = 300;
NextWakeupTime = 0;
@@ -639,8 +641,10 @@
else if (!strcasecmp(Name, "FontSmlSize")) FontSmlSize = atoi(Value);
else if (!strcasecmp(Name, "FontFixSize")) FontFixSize = atoi(Value);
else if (!strcasecmp(Name, "MaxVideoFileSize")) MaxVideoFileSize = atoi(Value);
+ else if (!strcasecmp(Name, "MaxRecordingSize")) MaxRecordingSize = atoi(Value);
else if (!strcasecmp(Name, "SplitEditedFiles")) SplitEditedFiles = atoi(Value);
else if (!strcasecmp(Name, "DelTimeshiftRec")) DelTimeshiftRec = atoi(Value);
+ else if (!strcasecmp(Name, "HardLinkCutter")) HardLinkCutter = atoi(Value);
else if (!strcasecmp(Name, "MinEventTimeout")) MinEventTimeout = atoi(Value);
else if (!strcasecmp(Name, "MinUserInactivity")) MinUserInactivity = atoi(Value);
else if (!strcasecmp(Name, "NextWakeupTime")) NextWakeupTime = atoi(Value);
@@ -736,8 +740,10 @@
Store("FontSmlSize", FontSmlSize);
Store("FontFixSize", FontFixSize);
Store("MaxVideoFileSize", MaxVideoFileSize);
+ Store("MaxRecordingSize", MaxRecordingSize);
Store("SplitEditedFiles", SplitEditedFiles);
Store("DelTimeshiftRec", DelTimeshiftRec);
+ Store("HardLinkCutter", HardLinkCutter);
Store("MinEventTimeout", MinEventTimeout);
Store("MinUserInactivity", MinUserInactivity);
Store("NextWakeupTime", NextWakeupTime);
diff -Naur vdr-1.7.27/config.h vdr-1.7.27-hlcutter/config.h
--- vdr-1.7.27/config.h 2012-03-11 11:41:44.000000000 +0100
+++ vdr-1.7.27-hlcutter/config.h 2012-03-31 13:25:56.000000000 +0200
@@ -299,8 +299,10 @@
int FontSmlSize;
int FontFixSize;
int MaxVideoFileSize;
+ int MaxRecordingSize;
int SplitEditedFiles;
int DelTimeshiftRec;
+ int HardLinkCutter;
int MinEventTimeout, MinUserInactivity;
time_t NextWakeupTime;
int MultiSpeedMode;
diff -Naur vdr-1.7.27/cutter.c vdr-1.7.27-hlcutter/cutter.c
--- vdr-1.7.27/cutter.c 2012-02-16 13:08:39.000000000 +0100
+++ vdr-1.7.27-hlcutter/cutter.c 2012-03-31 13:26:51.000000000 +0200
@@ -80,6 +80,7 @@
Mark = fromMarks.Next(Mark);
off_t FileSize = 0;
int CurrentFileNumber = 0;
+ bool SkipThisSourceFile = false;
int LastIFrame = 0;
toMarks.Add(0);
toMarks.Save();
@@ -98,13 +99,93 @@
// Read one frame:
- if (fromIndex->Get(Index++, &FileNumber, &FileOffset, &Independent, &Length)) {
- if (FileNumber != CurrentFileNumber) {
- fromFile = fromFileName->SetOffset(FileNumber, FileOffset);
- if (fromFile)
- fromFile->SetReadAhead(MEGABYTE(20));
- CurrentFileNumber = FileNumber;
- }
+ if (!fromIndex->Get(Index++, &FileNumber, &FileOffset, &Independent, &Length)) {
+ // Error, unless we're past last cut-in and there's no cut-out
+ if (Mark || LastMark)
+ error = "index";
+ break;
+ }
+
+ if (FileNumber != CurrentFileNumber) {
+ fromFile = fromFileName->SetOffset(FileNumber, FileOffset);
+ if (fromFile)
+ fromFile->SetReadAhead(MEGABYTE(20));
+ CurrentFileNumber = FileNumber;
+ if (SkipThisSourceFile) {
+ // At end of fast forward: Always skip to next file
+ toFile = toFileName->NextFile();
+ if (!toFile) {
+ error = "toFile 4";
+ break;
+ }
+ FileSize = 0;
+ SkipThisSourceFile = false;
+ }
+
+
+ if (Setup.HardLinkCutter && FileOffset == 0) {
+ // We are at the beginning of a new source file.
+ // Do we need to copy the whole file?
+
+ // if !Mark && LastMark, then we're past the last cut-out and continue to next I-frame
+ // if !Mark && !LastMark, then there's just a cut-in, but no cut-out
+ // if Mark, then we're between a cut-in and a cut-out
+
+ uint16_t MarkFileNumber;
+ off_t MarkFileOffset;
+ // Get file number of next cut mark
+ if (!Mark && !LastMark
+ || Mark
+ && fromIndex->Get(Mark->Position(), &MarkFileNumber, &MarkFileOffset)
+ && (MarkFileNumber != CurrentFileNumber)) {
+ // The current source file will be copied completely.
+ // Start new output file unless we did that already
+ if (FileSize != 0) {
+ toFile = toFileName->NextFile();
+ if (!toFile) {
+ error = "toFile 3";
+ break;
+ }
+ FileSize = 0;
+ }
+
+ // Safety check that file has zero size
+ struct stat buf;
+ if (stat(toFileName->Name(), &buf) == 0) {
+ if (buf.st_size != 0) {
+ esyslog("cCuttingThread: File %s exists and has nonzero size", toFileName->Name());
+ error = "nonzero file exist";
+ break;
+ }
+ }
+ else if (errno != ENOENT) {
+ esyslog("cCuttingThread: stat failed on %s", toFileName->Name());
+ error = "stat";
+ break;
+ }
+
+ // Clean the existing 0-byte file
+ toFileName->Close();
+ cString ActualToFileName(ReadLink(toFileName->Name()), true);
+ unlink(ActualToFileName);
+ unlink(toFileName->Name());
+
+ // Try to create a hard link
+ if (HardLinkVideoFile(fromFileName->Name(), toFileName->Name())) {
+ // Success. Skip all data transfer for this file
+ SkipThisSourceFile = true;
+ cutIn = false;
+ toFile = NULL; // was deleted by toFileName->Close()
+ }
+ else {
+ // Fallback: Re-open the file if necessary
+ toFile = toFileName->Open();
+ }
+ }
+ }
+ }
+
+ if (!SkipThisSourceFile) {
if (fromFile) {
int len = ReadFrame(fromFile, buffer, Length, sizeof(buffer));
if (len < 0) {
@@ -121,19 +202,12 @@
break;
}
}
- else {
- // Error, unless we're past the last cut-in and there's no cut-out
- if (Mark || LastMark)
- error = "index";
- break;
- }
-
// Write one frame:
if (Independent) { // every file shall start with an independent frame
if (LastMark) // edited version shall end before next I-frame
break;
- if (FileSize > maxVideoFileSize) {
+ if (!SkipThisSourceFile && FileSize > toFileName->MaxFileSize()) {
toFile = toFileName->NextFile();
if (!toFile) {
error = "toFile 1";
@@ -143,7 +217,7 @@
}
CheckForSeamlessStream = false;
}
- if (cutIn) {
+ if (!SkipThisSourceFile && cutIn) {
if (isPesRecording)
cRemux::SetBrokenLink(buffer, Length);
else
@@ -151,7 +225,7 @@
cutIn = false;
}
}
- if (toFile->Write(buffer, Length) < 0) {
+ if (!SkipThisSourceFile && toFile->Write(buffer, Length) < 0) {
error = "safe_write";
break;
}
@@ -186,7 +260,7 @@
}
}
else
- LastMark = true;
+ LastMark = true; // After last cut-out: Write on until next I-frame, then exit
}
}
Recordings.TouchUpdate();
diff -Naur vdr-1.7.27/menu.c vdr-1.7.27-hlcutter/menu.c
--- vdr-1.7.27/menu.c 2012-03-13 14:14:38.000000000 +0100
+++ vdr-1.7.27-hlcutter/menu.c 2012-03-31 13:25:56.000000000 +0200
@@ -3116,8 +3116,10 @@
Add(new cMenuEditStrItem( tr("Setup.Recording$Name instant recording"), data.NameInstantRecord, sizeof(data.NameInstantRecord)));
Add(new cMenuEditIntItem( tr("Setup.Recording$Instant rec. time (min)"), &data.InstantRecordTime, 1, MAXINSTANTRECTIME));
Add(new cMenuEditIntItem( tr("Setup.Recording$Max. video file size (MB)"), &data.MaxVideoFileSize, MINVIDEOFILESIZE, MAXVIDEOFILESIZETS));
+ Add(new cMenuEditIntItem( tr("Setup.Recording$Max. recording size (GB)"), &data.MaxRecordingSize, MINRECORDINGSIZE, MAXRECORDINGSIZE));
Add(new cMenuEditBoolItem(tr("Setup.Recording$Split edited files"), &data.SplitEditedFiles));
Add(new cMenuEditStraItem(tr("Setup.Recording$Delete timeshift recording"),&data.DelTimeshiftRec, 3, delTimeshiftRecTexts));
+ Add(new cMenuEditBoolItem(tr("Setup.Recording$Hard Link Cutter"), &data.HardLinkCutter));
}
// --- cMenuSetupReplay ------------------------------------------------------
diff -Naur vdr-1.7.27/po/de_DE.po vdr-1.7.27-hlcutter/po/de_DE.po
--- vdr-1.7.27/po/de_DE.po 2012-03-11 11:44:44.000000000 +0100
+++ vdr-1.7.27-hlcutter/po/de_DE.po 2012-03-31 13:36:31.000000000 +0200
@@ -1071,12 +1071,18 @@
msgid "Setup.Recording$Max. video file size (MB)"
msgstr "Max. Videodateigröße (MB)"
+msgid "Setup.Recording$Max. recording size (GB)"
+msgstr "Max. Aufnahmegröße (GB)"
+
msgid "Setup.Recording$Split edited files"
msgstr "Editierte Dateien aufteilen"
msgid "Setup.Recording$Delete timeshift recording"
msgstr "Zeitversetzte Aufnahme löschen"
+msgid "Setup.Recording$Hard Link Cutter"
+msgstr "Hard Link Cutter"
+
msgid "Replay"
msgstr "Wiedergabe"
diff -Naur vdr-1.7.27/po/fi_FI.po vdr-1.7.27-hlcutter/po/fi_FI.po
--- vdr-1.7.27/po/fi_FI.po 2012-03-11 11:44:43.000000000 +0100
+++ vdr-1.7.27-hlcutter/po/fi_FI.po 2012-03-31 13:39:33.000000000 +0200
@@ -1074,12 +1074,18 @@
msgid "Setup.Recording$Max. video file size (MB)"
msgstr "Suurin tiedostokoko (Mt)"
+msgid "Setup.Recording$Max. recording size (GB)"
+msgstr "Suurin tallennekoko (Gt)"
+
msgid "Setup.Recording$Split edited files"
msgstr "Jaottele muokatut tallenteet"
msgid "Setup.Recording$Delete timeshift recording"
msgstr "Poista ajansiirtotallenne"
+msgid "Setup.Recording$Hard Link Cutter"
+msgstr "Käytä kovia linkkejä muokkauksessa"
+
msgid "Replay"
msgstr "Toisto"
diff -Naur vdr-1.7.27/README-HLCUTTER vdr-1.7.27-hlcutter/README-HLCUTTER
--- vdr-1.7.27/README-HLCUTTER 1970-01-01 01:00:00.000000000 +0100
+++ vdr-1.7.27-hlcutter/README-HLCUTTER 2012-03-31 13:40:55.000000000 +0200
@@ -0,0 +1,128 @@
+
+ VDR-HLCUTTER README
+
+
+Written by: Udo Richter
+Available at: http://www.udo-richter.de/vdr/patches.html#hlcutter
+ http://www.udo-richter.de/vdr/patches.en.html#hlcutter
+Contact: udo_richter@gmx.de
+
+
+
+About
+-----
+
+The hard link cutter patch changes the recording editing algorithms of VDR to
+use filesystem hard links to 'copy' recording files whenever possible to speed
+up editing recordings noticeably.
+
+The patch has matured to be quite stable, at least I'm using it without issues.
+Nevertheless the patch is still in development and should be used with caution.
+The patch is EXPERIMENTAL for multiple /videoxx folders. The safety checks
+should prevent data loss, but you should always carefully check the results.
+
+While editing a recording, the patch searches for any 00x.vdr files that don't
+contain editing marks and would normally be copied 1:1 unmodified to the edited
+recording. In this case the current target 00x.vdr file will be aborted, and
+the cutter process attempts to duplicate the source file as a hard link, so
+that both files share the same disk space. If this succeeds, the editing
+process fast-forwards through the duplicated file and continues normally
+beginning with the next source file. If hard linking fails, the cutter process
+continues with plain old copying. (but does not take up the aborted last file.)
+
+After editing, the un-edited recording can be deleted as usual, the hard linked
+copies will continue to exist as the only remaining copy.
+
+To be effective, the default 'Max. video file size (MB)' should be lowered.
+The patch lowers the smallest possible file size to 1mb. Since VDR only
+supports up to 255 files, this would limit the recording size to 255Mb or
+10 minutes, in other words: This setting is insane!
+
+To make sure that the 255 file limit will not be reached, the patch also
+introduces "Max. recording size (GB)" with a default of 100Gb (66 hours), and
+increases the file size to 2000Mb early enough, so that 100Gb-recordings will
+fit into the 255 files.
+
+Picking the right parameters can be tricky. The smaller the file size, the
+faster the editing process works. However, with a small file size, long
+recordings will fall back to 2000Mb files soon, that are slow on editing again.
+
+Here are some examples:
+
+Max file size: 100Gb 100Gb 100Gb 100Gb 100Gb 100Gb 100Gb
+Max recording size: 1Mb 10Mb 20Mb 30Mb 40Mb 50Mb 100Mb
+
+Small files: 1-203 1-204 1-205 1-206 1-207 1-209 1-214
+ GBytes: 0.2 2.0 4.0 6.0 8.1 10.2 20.9
+ Hours: 0.13 1.3 2.65 4 5.4 6.8 13.9
+
+Big (2000mb) files: 204-255 204-255 206-255 207-255 208-255 210-255 215-255
+ GBytes: 101.5 99.6 97.7 95.7 93.8 89.8 80.1
+ Hours: 67 66 65 63 62 60 53
+
+A recording limit of 100Gb keeps plenty of reserve without blocking too much
+file numbers. And with a file size of 30-40Mb, recordings of 4-5 hours fit into
+small files completely. (depends on bit rate of course)
+
+
+
+The patch must be enabled in Setup-> Recordings-> Hard Link Cutter. When
+disabled, the cutter process behaves identical to VDR's default cutter.
+
+There's a //#define HARDLINK_TEST_ONLY in the videodir.c file that enables a
+test-mode that hard-links 00x.vdr_ files only, and continues the classic
+editing. The resulting 00x.vdr and 00x.vdr_ files should be identical. If you
+delete the un-edited recording, don't forget to delete the *.vdr_ files too,
+they will now eat real disk space.
+
+Note: 'du' displays the disk space of hard links only on first appearance, and
+usually you will see a noticeably smaller size on the edited recording.
+
+
+History
+-------
+
+Version 0.2.3
+ Fix: Compatible to VDR-1.7.27+ thx to Ville Skyttä
+ New: Add German translation
+ New: Add Finnish translation, thx to Ville Skyttä
+
+Version 0.2.2
+ Fix: Adapt to GCC-4.4, thx to Ville Skyttä
+
+Version 0.2.1
+ New: Support for TS recordings with up to 65535 files and up to 1TB per file
+
+Version 0.2.0
+ New: Support for multiple /videoXX recording folders, using advanced searching
+ for matching file systems where a hard link can be created.
+ Also supports deep mounted file systems.
+ Fix: Do not fail if last mark is a cut-in. (Again.)
+
+Version 0.1.4
+ New: Dynamic increase of file size before running out of xxx.vdr files
+ Fix: Last edit mark is not a cut-out
+ Fix: Write error if link-copied file is smaller than allowed file size
+ Fix: Broken index/marks if cut-in is at the start of a new file
+ Fix: Clear dangling pointer to free'd cUnbufferedFile,
+ thx to Matthias Schwarzott
+
+Version 0.1.0
+ Initial release
+
+
+
+
+Future plans
+------------
+
+Since original and edited copy share disk space, free space is wrong if one of
+them is moved to *.del. Free space should only count files with hard link
+count = 1. This still goes wrong if all copies get deleted.
+
+
+For more safety, the hard-linked files may be made read-only, as modifications
+to one copy will affect the other copy too. (except deleting, of course)
+
+
+SetBrokenLink may get lost on rare cases, this needs some more thoughts.
diff -Naur vdr-1.7.27/recorder.c vdr-1.7.27-hlcutter/recorder.c
--- vdr-1.7.27/recorder.c 2011-09-04 11:26:44.000000000 +0200
+++ vdr-1.7.27-hlcutter/recorder.c 2012-03-31 13:25:56.000000000 +0200
@@ -89,7 +89,7 @@
bool cRecorder::NextFile(void)
{
if (recordFile && frameDetector->IndependentFrame()) { // every file shall start with an independent frame
- if (fileSize > MEGABYTE(off_t(Setup.MaxVideoFileSize)) || RunningLowOnDiskSpace()) {
+ if (fileSize > fileName->MaxFileSize() || RunningLowOnDiskSpace()) {
recordFile = fileName->NextFile();
fileSize = 0;
}
diff -Naur vdr-1.7.27/recording.c vdr-1.7.27-hlcutter/recording.c
--- vdr-1.7.27/recording.c 2012-03-13 14:17:57.000000000 +0100
+++ vdr-1.7.27-hlcutter/recording.c 2012-03-31 13:25:56.000000000 +0200
@@ -2064,6 +2064,20 @@
return NULL;
}
+off_t cFileName::MaxFileSize() {
+ const int maxVideoFileSize = isPesRecording ? MAXVIDEOFILESIZEPES : MAXVIDEOFILESIZETS;
+ const int setupMaxVideoFileSize = min(maxVideoFileSize, Setup.MaxVideoFileSize);
+ const int maxFileNumber = isPesRecording ? 255 : 65535;
+
+ const off_t smallFiles = (maxFileNumber * off_t(maxVideoFileSize) - 1024 * Setup.MaxRecordingSize)
+ / max(maxVideoFileSize - setupMaxVideoFileSize, 1);
+
+ if (fileNumber <= smallFiles)
+ return MEGABYTE(off_t(setupMaxVideoFileSize));
+
+ return MEGABYTE(off_t(maxVideoFileSize));
+}
+
cUnbufferedFile *cFileName::NextFile(void)
{
return SetOffset(fileNumber + 1);
diff -Naur vdr-1.7.27/recording.h vdr-1.7.27-hlcutter/recording.h
--- vdr-1.7.27/recording.h 2012-03-13 13:41:05.000000000 +0100
+++ vdr-1.7.27-hlcutter/recording.h 2012-03-31 13:25:56.000000000 +0200
@@ -264,9 +264,17 @@
// before the next independent frame, to have a complete Group Of Pictures):
#define MAXVIDEOFILESIZETS 1048570 // MB
#define MAXVIDEOFILESIZEPES 2000 // MB
-#define MINVIDEOFILESIZE 100 // MB
+#define MINVIDEOFILESIZE 1 // MB
#define MAXVIDEOFILESIZEDEFAULT MAXVIDEOFILESIZEPES
+#define MINRECORDINGSIZE 25 // GB
+#define MAXRECORDINGSIZE 500 // GB
+#define DEFAULTRECORDINGSIZE 100 // GB
+// Dynamic recording size:
+// Keep recording file size at Setup.MaxVideoFileSize for as long as possible,
+// but switch to MAXVIDEOFILESIZE early enough, so that Setup.MaxRecordingSize
+// will be reached, before recording to file 65535.vdr
+
struct tIndexTs;
class cIndexFileGenerator;
@@ -319,6 +327,8 @@
cUnbufferedFile *Open(void);
void Close(void);
cUnbufferedFile *SetOffset(int Number, off_t Offset = 0); // yes, Number is int for easier internal calculating
+ off_t MaxFileSize();
+ // Dynamic file size for this file
cUnbufferedFile *NextFile(void);
};
diff -Naur vdr-1.7.27/videodir.c vdr-1.7.27-hlcutter/videodir.c
--- vdr-1.7.27/videodir.c 2008-02-16 14:00:03.000000000 +0100
+++ vdr-1.7.27-hlcutter/videodir.c 2012-03-31 13:25:56.000000000 +0200
@@ -19,6 +19,9 @@
#include "recording.h"
#include "tools.h"
+
+//#define HARDLINK_TEST_ONLY
+
const char *VideoDirectory = VIDEODIR;
class cVideoDirectory {
@@ -168,6 +171,120 @@
return RemoveFileOrDir(FileName, true);
}
+static bool StatNearestDir(const char *FileName, struct stat *Stat)
+{
+ cString Name(FileName);
+ char *p;
+ while ((p = strrchr((char*)(const char*)Name + 1, '/')) != NULL) {
+ *p = 0; // truncate at last '/'
+ if (stat(Name, Stat) == 0) {
+ isyslog("StatNearestDir: Stating %s", (const char*)Name);
+ return true;
+ }
+ }
+ return false;
+}
+
+bool HardLinkVideoFile(const char *OldName, const char *NewName)
+{
+ // Incoming name must be in base video directory:
+ if (strstr(OldName, VideoDirectory) != OldName) {
+ esyslog("ERROR: %s not in %s", OldName, VideoDirectory);
+ return false;
+ }
+ if (strstr(NewName, VideoDirectory) != NewName) {
+ esyslog("ERROR: %s not in %s", NewName, VideoDirectory);
+ return false;
+ }
+
+ const char *ActualNewName = NewName;
+ cString ActualOldName(ReadLink(OldName), true);
+
+ // Some safety checks:
+ struct stat StatOldName;
+ if (lstat(ActualOldName, &StatOldName) == 0) {
+ if (S_ISLNK(StatOldName.st_mode)) {
+ esyslog("HardLinkVideoFile: Failed to resolve symbolic link %s", (const char*)ActualOldName);
+ return false;
+ }
+ }
+ else {
+ esyslog("HardLinkVideoFile: lstat failed on %s", (const char*)ActualOldName);
+ return false;
+ }
+ isyslog("HardLinkVideoFile: %s is on %i", (const char*)ActualOldName, (int)StatOldName.st_dev);
+
+ // Find the video directory where ActualOldName is located
+
+ cVideoDirectory Dir;
+ struct stat StatDir;
+ if (!StatNearestDir(NewName, &StatDir)) {
+ esyslog("HardLinkVideoFile: stat failed on %s", NewName);
+ return false;
+ }
+
+ isyslog("HardLinkVideoFile: %s is on %i", NewName, (int)StatDir.st_dev);
+ if (StatDir.st_dev != StatOldName.st_dev) {
+ // Not yet found.
+
+ if (!Dir.IsDistributed()) {
+ esyslog("HardLinkVideoFile: No matching video folder to hard link %s", (const char*)ActualOldName);
+ return false;
+ }
+
+ // Search in video01 and upwards
+ bool found = false;
+ while (Dir.Next()) {
+ Dir.Store();
+ const char *TmpNewName = Dir.Adjust(NewName);
+ if (StatNearestDir(TmpNewName, &StatDir) && StatDir.st_dev == StatOldName.st_dev) {
+ isyslog("HardLinkVideoFile: %s is on %i (match)", TmpNewName, (int)StatDir.st_dev);
+ ActualNewName = TmpNewName;
+ found = true;
+ break;
+ }
+ isyslog("HardLinkVideoFile: %s is on %i", TmpNewName, (int)StatDir.st_dev);
+ }
+ if (ActualNewName == NewName) {
+ esyslog("HardLinkVideoFile: No matching video folder to hard link %s", (const char*)ActualOldName);
+ return false;
+ }
+
+ // Looking good, we have a match. Create necessary folders.
+ if (!MakeDirs(ActualNewName, false))
+ return false;
+ // There's no guarantee that the directory of ActualNewName
+ // is on the same device as the dir that StatNearestDir found.
+ // But worst case is that the link fails.
+ }
+
+#ifdef HARDLINK_TEST_ONLY
+ // Do the hard link to *.vdr_ for testing only
+ char *name = NULL;
+ asprintf(&name, "%s_",ActualNewName);
+ link(ActualOldName, name);
+ free(name);
+ return false;
+#endif // HARDLINK_TEST_ONLY
+
+ // Try creating the hard link
+ if (link(ActualOldName, ActualNewName) != 0) {
+ // Failed to hard link. Maybe not allowed on file system.
+ LOG_ERROR_STR(ActualNewName);
+ isyslog("HardLinkVideoFile: failed to hard link from %s to %s", (const char*)ActualOldName, ActualNewName);
+ return false;
+ }
+
+ if (ActualNewName != NewName) {
+ // video01 and up. Do the remaining symlink
+ if (symlink(ActualNewName, NewName) < 0) {
+ LOG_ERROR_STR(NewName);
+ return false;
+ }
+ }
+ return true;
+}
+
bool VideoFileSpaceAvailable(int SizeMB)
{
cVideoDirectory Dir;
diff -Naur vdr-1.7.27/videodir.h vdr-1.7.27-hlcutter/videodir.h
--- vdr-1.7.27/videodir.h 2008-02-16 13:53:11.000000000 +0100
+++ vdr-1.7.27-hlcutter/videodir.h 2012-03-31 13:25:56.000000000 +0200
@@ -19,6 +19,7 @@
int CloseVideoFile(cUnbufferedFile *File);
bool RenameVideoFile(const char *OldName, const char *NewName);
bool RemoveVideoFile(const char *FileName);
+bool HardLinkVideoFile(const char *OldName, const char *NewName);
bool VideoFileSpaceAvailable(int SizeMB);
int VideoDiskSpace(int *FreeMB = NULL, int *UsedMB = NULL); // returns the used disk space in percent
cString PrefixVideoFileName(const char *FileName, char Prefix);

View file

@ -1,6 +1,7 @@
--- vdr-2.7.4/Makefile.orig 2025-02-26 14:07:24.323718942 +0100
+++ vdr-2.7.4/Makefile 2025-02-26 14:08:33.583687374 +0100
@@ -186,6 +186,12 @@
diff -up vdr-1.7.37/Makefile~ vdr-1.7.37/Makefile
--- vdr-1.7.37/Makefile~ 2013-02-14 21:57:22.306077727 +0200
+++ vdr-1.7.37/Makefile 2013-02-14 22:05:04.016086224 +0200
@@ -152,6 +152,12 @@ vdr.pc:
@echo "cflags=$(CFLAGS) $(CDEFINES) $(CINCLUDES) $(HDRDIR)" >> $@
@echo "cxxflags=$(CXXFLAGS) $(CDEFINES) $(CINCLUDES) $(HDRDIR)" >> $@
@echo "" >> $@
@ -12,4 +13,4 @@
+ @echo "" >> $@
@echo "Name: VDR" >> $@
@echo "Description: Video Disk Recorder" >> $@
@echo "URL: https://www.tvdr.de/" >> $@
@echo "URL: http://www.tvdr.de/" >> $@

84
vdr-1.7.41-paths.patch Normal file
View file

@ -0,0 +1,84 @@
diff -up vdr-1.7.41/epg2html~ vdr-1.7.41/epg2html
--- vdr-1.7.41/epg2html~ 2013-03-04 15:02:20.000000000 +0200
+++ vdr-1.7.41/epg2html 2013-03-16 19:08:17.467701640 +0200
@@ -2,12 +2,12 @@
# A simple EPG to HTML converter
#
-# Converts the EPG data written by 'vdr' into the file /video/epg.data
+# Converts the EPG data written by 'vdr' into the file __CACHEDIR__/epg.data
# into a simple HTML programme listing, consisting of one file per channel
# plus an 'index.htm' file. All output files are written into the current
# directory.
#
-# Usage: epg2html < /video/epg.data
+# Usage: epg2html < __CACHEDIR__/epg.data
#
# See the main source file 'vdr.c' for copyright information and
# how to reach the author.
diff -up vdr-1.7.41/newplugin~ vdr-1.7.41/newplugin
--- vdr-1.7.41/newplugin~ 2013-01-12 15:46:00.000000000 +0200
+++ vdr-1.7.41/newplugin 2013-03-16 19:08:18.140713300 +0200
@@ -24,7 +24,7 @@ $PLUGIN_VERSION = "0.0.1";
$PLUGIN_DESCRIPTION = "Enter description for '$PLUGIN_NAME' plugin";
$PLUGIN_MAINENTRY = $PLUGIN_CLASS;
-$PLUGINS_SRC = "PLUGINS/src";
+$PLUGINS_SRC = ".";
$README = qq
{This is a "plugin" for the Video Disk Recorder (VDR).
diff -up vdr-1.7.41/vdr.1~ vdr-1.7.41/vdr.1
--- vdr-1.7.41/vdr.1~ 2013-03-15 12:44:54.000000000 +0200
+++ vdr-1.7.41/vdr.1 2013-03-16 19:08:16.621686914 +0200
@@ -51,7 +51,7 @@ Save cache files in \fIdir\fR
.TP
.BI \-c\ dir ,\ \-\-config= dir
Read config files from directory \fIdir\fR
-(default is to read them from the video directory).
+(default is to read them from __CONFIGDIR__).
.TP
.B \-d, \-\-daemon
Run in daemon mode (implies \-\-no\-kbd).
@@ -130,7 +130,7 @@ If logging should be done to LOG_LOCAL\f
LOG_USER, add '.n' to LEVEL, as in 3.7 (n=0..7).
.TP
.BI \-L\ dir ,\ \-\-lib= dir
-Search for plugins in directory \fIdir\fR (default is ./PLUGINS/lib).
+Search for plugins in directory \fIdir\fR (default is __PLUGINDIR__).
There can be several \fB\-L\fR options with different \fIdir\fR values.
Each of them will apply to the \fB\-P\fR options following it.
.TP
@@ -205,7 +205,7 @@ For backwards compatibility (same as \-\
.TP
.BI \-v\ dir ,\ \-\-video= dir
Use \fIdir\fR as video directory.
-The default is \fI/video\fR.
+The default is \fI__VIDEODIR__\fR.
.TP
.B \-V, \-\-version
Print version information and exit.
diff -up vdr-1.7.41/vdr.5~ vdr-1.7.41/vdr.5
--- vdr-1.7.41/vdr.5~ 2013-03-11 15:17:12.000000000 +0200
+++ vdr-1.7.41/vdr.5 2013-03-16 19:08:18.908726601 +0200
@@ -711,7 +711,7 @@ The file \fIsetup.conf\fR contains the b
Each line contains one option in the format "Name = Value".
See the MANUAL file for a description of the available options.
.SS THEMES
-The files \fIthemes/<skin>\-<theme>.theme\fR in the config directory contain the
+The files \fI__VARDIR__/themes/<skin>\-<theme>.theme\fR contain the
color theme definitions for the various skins. In the actual file names \fI<skin>\fR
will be replaced by the name if the skin this theme belongs to, and \fI<theme>\fR
will be the name of this theme.
diff -up vdr-1.7.41/vdr.c~ vdr-1.7.41/vdr.c
--- vdr-1.7.41/vdr.c~ 2013-03-15 12:44:54.000000000 +0200
+++ vdr-1.7.41/vdr.c 2013-03-16 19:08:15.861673670 +0200
@@ -673,7 +673,7 @@ int main(int argc, char *argv[])
if (!ResourceDirectory)
ResourceDirectory = DEFAULTRESDIR;
cPlugin::SetResourceDirectory(ResourceDirectory);
- cThemes::SetThemesDirectory(AddDirectory(ConfigDirectory, "themes"));
+ cThemes::SetThemesDirectory("__VARDIR__/themes");
// Configuration data:

View file

@ -0,0 +1,109 @@
diff -up vdr-2.0.4/config.h~ vdr-2.0.4/config.h
--- vdr-2.0.4/config.h~ 2013-09-07 13:25:10.000000000 +0300
+++ vdr-2.0.4/config.h 2013-10-23 19:43:24.731445495 +0300
@@ -47,6 +47,10 @@
#define TIMERMACRO_TITLE "TITLE"
#define TIMERMACRO_EPISODE "EPISODE"
+// The MainMenuHook Patch's version number:
+#define MAINMENUHOOKSVERSION "1.0.1"
+#define MAINMENUHOOKSVERSNUM 10001 // Version * 10000 + Major * 100 + Minor
+
#define MINOSDWIDTH 480
#define MAXOSDWIDTH 1920
#define MINOSDHEIGHT 324
diff -up vdr-2.0.4/menu.c~ vdr-2.0.4/menu.c
--- vdr-2.0.4/menu.c~ 2013-10-16 12:46:24.000000000 +0300
+++ vdr-2.0.4/menu.c 2013-10-23 19:43:24.275436244 +0300
@@ -3377,15 +3377,31 @@ cMenuMain::cMenuMain(eOSState State, boo
// Initial submenus:
+ cOsdObject *menu = NULL;
switch (State) {
- case osSchedule: AddSubMenu(new cMenuSchedule); break;
- case osChannels: AddSubMenu(new cMenuChannels); break;
- case osTimers: AddSubMenu(new cMenuTimers); break;
- case osRecordings: AddSubMenu(new cMenuRecordings(NULL, 0, OpenSubMenus)); break;
- case osSetup: AddSubMenu(new cMenuSetup); break;
- case osCommands: AddSubMenu(new cMenuCommands(tr("Commands"), &Commands)); break;
+ case osSchedule:
+ if (!cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osSchedule", &menu))
+ menu = new cMenuSchedule;
+ break;
+ case osChannels:
+ if (!cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osChannels", &menu))
+ menu = new cMenuChannels;
+ break;
+ case osTimers:
+ if (!cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osTimers", &menu))
+ menu = new cMenuTimers;
+ break;
+ case osRecordings:
+ if (!cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osRecordings", &menu))
+ menu = new cMenuRecordings(NULL, 0, OpenSubMenus);
+ break;
+ case osSetup: menu = new cMenuSetup; break;
+ case osCommands: menu = new cMenuCommands(tr("Commands"), &Commands); break;
default: break;
}
+ if (menu)
+ if (menu->IsMenu())
+ AddSubMenu((cOsdMenu *) menu);
}
cOsdObject *cMenuMain::PluginOsdObject(void)
@@ -3493,13 +3509,34 @@ eOSState cMenuMain::ProcessKey(eKeys Key
eOSState state = cOsdMenu::ProcessKey(Key);
HadSubMenu |= HasSubMenu();
+ cOsdObject *menu = NULL;
switch (state) {
- case osSchedule: return AddSubMenu(new cMenuSchedule);
- case osChannels: return AddSubMenu(new cMenuChannels);
- case osTimers: return AddSubMenu(new cMenuTimers);
- case osRecordings: return AddSubMenu(new cMenuRecordings);
- case osSetup: return AddSubMenu(new cMenuSetup);
- case osCommands: return AddSubMenu(new cMenuCommands(tr("Commands"), &Commands));
+ case osSchedule:
+ if (!cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osSchedule", &menu))
+ menu = new cMenuSchedule;
+ else
+ state = osContinue;
+ break;
+ case osChannels:
+ if (!cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osChannels", &menu))
+ menu = new cMenuChannels;
+ else
+ state = osContinue;
+ break;
+ case osTimers:
+ if (!cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osTimers", &menu))
+ menu = new cMenuTimers;
+ else
+ state = osContinue;
+ break;
+ case osRecordings:
+ if (!cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osRecordings", &menu))
+ menu = new cMenuRecordings;
+ else
+ state = osContinue;
+ break;
+ case osSetup: menu = new cMenuSetup; break;
+ case osCommands: menu = new cMenuCommands(tr("Commands"), &Commands); break;
case osStopRecord: if (Interface->Confirm(tr("Stop recording?"))) {
cOsdItem *item = Get(Current());
if (item) {
@@ -3551,6 +3588,12 @@ eOSState cMenuMain::ProcessKey(eKeys Key
default: break;
}
}
+ if (menu) {
+ if (menu->IsMenu())
+ return AddSubMenu((cOsdMenu *) menu);
+ pluginOsdObject = menu;
+ return osPlugin;
+ }
if (!HasSubMenu() && Update(HadSubMenu))
Display();
if (Key != kNone) {

621
vdr-2.1.5-naludump-0.1.diff Normal file
View file

@ -0,0 +1,621 @@
diff -Naur vdr-2.1.6/config.c vdr-2.1.6-naludump-0.1/config.c
--- vdr-2.1.6/config.c 2013-08-31 14:41:28.000000000 +0200
+++ vdr-2.1.6-naludump-0.1/config.c 2014-03-30 17:47:25.000000000 +0200
@@ -462,6 +462,7 @@
MaxVideoFileSize = MAXVIDEOFILESIZEDEFAULT;
SplitEditedFiles = 0;
DelTimeshiftRec = 0;
+ DumpNaluFill = 0;
MinEventTimeout = 30;
MinUserInactivity = 300;
NextWakeupTime = 0;
@@ -673,6 +674,7 @@
else if (!strcasecmp(Name, "MaxVideoFileSize")) MaxVideoFileSize = atoi(Value);
else if (!strcasecmp(Name, "SplitEditedFiles")) SplitEditedFiles = atoi(Value);
else if (!strcasecmp(Name, "DelTimeshiftRec")) DelTimeshiftRec = atoi(Value);
+ else if (!strcasecmp(Name, "DumpNaluFill")) DumpNaluFill = atoi(Value);
else if (!strcasecmp(Name, "MinEventTimeout")) MinEventTimeout = atoi(Value);
else if (!strcasecmp(Name, "MinUserInactivity")) MinUserInactivity = atoi(Value);
else if (!strcasecmp(Name, "NextWakeupTime")) NextWakeupTime = atoi(Value);
@@ -788,6 +790,7 @@
Store("MaxVideoFileSize", MaxVideoFileSize);
Store("SplitEditedFiles", SplitEditedFiles);
Store("DelTimeshiftRec", DelTimeshiftRec);
+ Store("DumpNaluFill", DumpNaluFill);
Store("MinEventTimeout", MinEventTimeout);
Store("MinUserInactivity", MinUserInactivity);
Store("NextWakeupTime", NextWakeupTime);
diff -Naur vdr-2.1.6/config.h vdr-2.1.6-naludump-0.1/config.h
--- vdr-2.1.6/config.h 2014-02-25 11:00:23.000000000 +0100
+++ vdr-2.1.6-naludump-0.1/config.h 2014-03-30 17:47:25.000000000 +0200
@@ -326,6 +326,7 @@
int MaxVideoFileSize;
int SplitEditedFiles;
int DelTimeshiftRec;
+ int DumpNaluFill;
int MinEventTimeout, MinUserInactivity;
time_t NextWakeupTime;
int MultiSpeedMode;
diff -Naur vdr-2.1.6/menu.c vdr-2.1.6-naludump-0.1/menu.c
--- vdr-2.1.6/menu.c 2014-03-16 11:38:31.000000000 +0100
+++ vdr-2.1.6-naludump-0.1/menu.c 2014-03-30 17:47:25.000000000 +0200
@@ -3547,6 +3547,7 @@
Add(new cMenuEditIntItem( tr("Setup.Recording$Max. video file size (MB)"), &data.MaxVideoFileSize, MINVIDEOFILESIZE, MAXVIDEOFILESIZETS));
Add(new cMenuEditBoolItem(tr("Setup.Recording$Split edited files"), &data.SplitEditedFiles));
Add(new cMenuEditStraItem(tr("Setup.Recording$Delete timeshift recording"),&data.DelTimeshiftRec, 3, delTimeshiftRecTexts));
+ Add(new cMenuEditBoolItem(tr("Setup.Recording$Dump NALU Fill data"), &data.DumpNaluFill));
}
// --- cMenuSetupReplay ------------------------------------------------------
diff -Naur vdr-2.1.6/recorder.c vdr-2.1.6-naludump-0.1/recorder.c
--- vdr-2.1.6/recorder.c 2014-02-21 10:19:52.000000000 +0100
+++ vdr-2.1.6-naludump-0.1/recorder.c 2014-03-30 17:47:25.000000000 +0200
@@ -46,6 +46,14 @@
Type = 0x06;
}
frameDetector = new cFrameDetector(Pid, Type);
+ if ( Type == 0x1B // MPEG4 video
+ && (Setup.DumpNaluFill ? (strstr(FileName, "NALUKEEP") == NULL) : (strstr(FileName, "NALUDUMP") != NULL))) { // MPEG4
+ isyslog("Starting NALU fill dumper");
+ naluStreamProcessor = new cNaluStreamProcessor();
+ naluStreamProcessor->SetPid(Pid);
+ }
+ else
+ naluStreamProcessor = NULL;
index = NULL;
fileSize = 0;
lastDiskSpaceCheck = time(NULL);
@@ -67,6 +75,12 @@
cRecorder::~cRecorder()
{
Detach();
+ if (naluStreamProcessor) {
+ long long int TotalPackets = naluStreamProcessor->GetTotalPackets();
+ long long int DroppedPackets = naluStreamProcessor->GetDroppedPackets();
+ isyslog("NALU fill dumper: %lld of %lld packets dropped, %lli%%", DroppedPackets, TotalPackets, TotalPackets ? DroppedPackets*100/TotalPackets : 0);
+ delete naluStreamProcessor;
+ }
delete index;
delete fileName;
delete frameDetector;
@@ -157,11 +171,32 @@
}
t.Set(MAXBROKENTIMEOUT);
}
- if (recordFile->Write(b, Count) < 0) {
- LOG_ERROR_STR(fileName->Name());
- break;
+ if (naluStreamProcessor) {
+ naluStreamProcessor->PutBuffer(b, Count);
+ bool Fail = false;
+ while (true) {
+ int OutLength = 0;
+ uchar *OutData = naluStreamProcessor->GetBuffer(OutLength);
+ if (!OutData || OutLength <= 0)
+ break;
+ if (recordFile->Write(OutData, OutLength) < 0) {
+ LOG_ERROR_STR(fileName->Name());
+ Fail = true;
+ break;
+ }
+ fileSize += OutLength;
+ }
+ if (Fail)
+ break;
+ }
+ else {
+ if (recordFile->Write(b, Count) < 0) {
+ LOG_ERROR_STR(fileName->Name());
+ break;
+ }
+ fileSize += Count;
}
- fileSize += Count;
+
}
}
ringBuffer->Del(Count);
diff -Naur vdr-2.1.6/recorder.h vdr-2.1.6-naludump-0.1/recorder.h
--- vdr-2.1.6/recorder.h 2010-12-27 12:17:04.000000000 +0100
+++ vdr-2.1.6-naludump-0.1/recorder.h 2014-03-30 17:47:25.000000000 +0200
@@ -21,6 +21,7 @@
cRingBufferLinear *ringBuffer;
cFrameDetector *frameDetector;
cPatPmtGenerator patPmtGenerator;
+ cNaluStreamProcessor *naluStreamProcessor;
cFileName *fileName;
cIndexFile *index;
cUnbufferedFile *recordFile;
diff -Naur vdr-2.1.6/remux.c vdr-2.1.6-naludump-0.1/remux.c
--- vdr-2.1.6/remux.c 2014-03-08 16:05:35.000000000 +0100
+++ vdr-2.1.6-naludump-0.1/remux.c 2014-03-30 17:47:25.000000000 +0200
@@ -343,6 +343,42 @@
dsyslog("WARNING: required %d video TS packets to determine frame type", numPacketsPid);
}
+void TsExtendAdaptionField(unsigned char *Packet, int ToLength)
+{
+ // Hint: ExtenAdaptionField(p, TsPayloadOffset(p) - 4) is a null operation
+
+ int Offset = TsPayloadOffset(Packet); // First byte after existing adaption field
+
+ if (ToLength <= 0)
+ {
+ // Remove adaption field
+ Packet[3] = Packet[3] & ~TS_ADAPT_FIELD_EXISTS;
+ return;
+ }
+
+ // Set adaption field present
+ Packet[3] = Packet[3] | TS_ADAPT_FIELD_EXISTS;
+
+ // Set new length of adaption field:
+ Packet[4] = ToLength <= TS_SIZE-4 ? ToLength-1 : TS_SIZE-4-1;
+
+ if (Packet[4] == TS_SIZE-4-1)
+ {
+ // No more payload, remove payload flag
+ Packet[3] = Packet[3] & ~TS_PAYLOAD_EXISTS;
+ }
+
+ int NewPayload = TsPayloadOffset(Packet); // First byte after new adaption field
+
+ // Fill new adaption field
+ if (Offset == 4 && Offset < NewPayload)
+ Offset++; // skip adaptation_field_length
+ if (Offset == 5 && Offset < NewPayload)
+ Packet[Offset++] = 0; // various flags set to 0
+ while (Offset < NewPayload)
+ Packet[Offset++] = 0xff; // stuffing byte
+}
+
// --- cPatPmtGenerator ------------------------------------------------------
cPatPmtGenerator::cPatPmtGenerator(const cChannel *Channel)
@@ -1547,3 +1583,344 @@
}
return Processed;
}
+
+// --- cNaluDumper ---------------------------------------------------------
+
+cNaluDumper::cNaluDumper()
+{
+ LastContinuityOutput = -1;
+ reset();
+}
+
+void cNaluDumper::reset()
+{
+ LastContinuityInput = -1;
+ ContinuityOffset = 0;
+ PesId = -1;
+ PesOffset = 0;
+ NaluFillState = NALU_NONE;
+ NaluOffset = 0;
+ History = 0xffffffff;
+ DropAllPayload = false;
+}
+
+void cNaluDumper::ProcessPayload(unsigned char *Payload, int size, bool PayloadStart, sPayloadInfo &Info)
+{
+ Info.DropPayloadStartBytes = 0;
+ Info.DropPayloadEndBytes = 0;
+ int LastKeepByte = -1;
+
+ if (PayloadStart)
+ {
+ History = 0xffffffff;
+ PesId = -1;
+ NaluFillState = NALU_NONE;
+ }
+
+ for (int i=0; i<size; i++) {
+ History = (History << 8) | Payload[i];
+
+ PesOffset++;
+ NaluOffset++;
+
+ bool DropByte = false;
+
+ if (History >= 0x00000180 && History <= 0x000001FF)
+ {
+ // Start of PES packet
+ PesId = History & 0xff;
+ PesOffset = 0;
+ NaluFillState = NALU_NONE;
+ }
+ else if (PesId >= 0xe0 && PesId <= 0xef // video stream
+ && History >= 0x00000100 && History <= 0x0000017F) // NALU start code
+ {
+ int NaluId = History & 0xff;
+ NaluOffset = 0;
+ NaluFillState = ((NaluId & 0x1f) == 0x0c) ? NALU_FILL : NALU_NONE;
+ }
+
+ if (PesId >= 0xe0 && PesId <= 0xef // video stream
+ && PesOffset >= 1 && PesOffset <= 2)
+ {
+ Payload[i] = 0; // Zero out PES length field
+ }
+
+ if (NaluFillState == NALU_FILL && NaluOffset > 0) // Within NALU fill data
+ {
+ // We expect a series of 0xff bytes terminated by a single 0x80 byte.
+
+ if (Payload[i] == 0xFF)
+ {
+ DropByte = true;
+ }
+ else if (Payload[i] == 0x80)
+ {
+ NaluFillState = NALU_TERM; // Last byte of NALU fill, next byte sets NaluFillEnd=true
+ DropByte = true;
+ }
+ else // Invalid NALU fill
+ {
+ dsyslog("cNaluDumper: Unexpected NALU fill data: %02x", Payload[i]);
+ NaluFillState = NALU_END;
+ if (LastKeepByte == -1)
+ {
+ // Nalu fill from beginning of packet until last byte
+ // packet start needs to be dropped
+ Info.DropPayloadStartBytes = i;
+ }
+ }
+ }
+ else if (NaluFillState == NALU_TERM) // Within NALU fill data
+ {
+ // We are after the terminating 0x80 byte
+ NaluFillState = NALU_END;
+ if (LastKeepByte == -1)
+ {
+ // Nalu fill from beginning of packet until last byte
+ // packet start needs to be dropped
+ Info.DropPayloadStartBytes = i;
+ }
+ }
+
+ if (!DropByte)
+ LastKeepByte = i; // Last useful byte
+ }
+
+ Info.DropAllPayloadBytes = (LastKeepByte == -1);
+ Info.DropPayloadEndBytes = size-1-LastKeepByte;
+}
+
+bool cNaluDumper::ProcessTSPacket(unsigned char *Packet)
+{
+ bool HasAdaption = TsHasAdaptationField(Packet);
+ bool HasPayload = TsHasPayload(Packet);
+
+ // Check continuity:
+ int ContinuityInput = TsContinuityCounter(Packet);
+ if (LastContinuityInput >= 0)
+ {
+ int NewContinuityInput = HasPayload ? (LastContinuityInput + 1) & TS_CONT_CNT_MASK : LastContinuityInput;
+ int Offset = (NewContinuityInput - ContinuityInput) & TS_CONT_CNT_MASK;
+ if (Offset > 0)
+ dsyslog("cNaluDumper: TS continuity offset %i", Offset);
+ if (Offset > ContinuityOffset)
+ ContinuityOffset = Offset; // max if packets get dropped, otherwise always the current one.
+ }
+ LastContinuityInput = ContinuityInput;
+
+ if (HasPayload) {
+ sPayloadInfo Info;
+ int Offset = TsPayloadOffset(Packet);
+ ProcessPayload(Packet + Offset, TS_SIZE - Offset, TsPayloadStart(Packet), Info);
+
+ if (DropAllPayload && !Info.DropAllPayloadBytes)
+ {
+ // Return from drop packet mode to normal mode
+ DropAllPayload = false;
+
+ // Does the packet start with some remaining NALU fill data?
+ if (Info.DropPayloadStartBytes > 0)
+ {
+ // Add these bytes as stuffing to the adaption field.
+
+ // Sample payload layout:
+ // FF FF FF FF FF 80 00 00 01 xx xx xx xx
+ // ^DropPayloadStartBytes
+
+ TsExtendAdaptionField(Packet, Offset - 4 + Info.DropPayloadStartBytes);
+ }
+ }
+
+ bool DropThisPayload = DropAllPayload;
+
+ if (!DropAllPayload && Info.DropPayloadEndBytes > 0) // Payload ends with 0xff NALU Fill
+ {
+ // Last packet of useful data
+ // Do early termination of NALU fill data
+ Packet[TS_SIZE-1] = 0x80;
+ DropAllPayload = true;
+ // Drop all packets AFTER this one
+
+ // Since we already wrote the 0x80, we have to make sure that
+ // as soon as we stop dropping packets, any beginning NALU fill of next
+ // packet gets dumped. (see DropPayloadStartBytes above)
+ }
+
+ if (DropThisPayload && HasAdaption)
+ {
+ // Drop payload data, but keep adaption field data
+ TsExtendAdaptionField(Packet, TS_SIZE-4);
+ DropThisPayload = false;
+ }
+
+ if (DropThisPayload)
+ {
+ return true; // Drop packet
+ }
+ }
+
+ // Fix Continuity Counter and reproduce incoming offsets:
+ int NewContinuityOutput = TsHasPayload(Packet) ? (LastContinuityOutput + 1) & TS_CONT_CNT_MASK : LastContinuityOutput;
+ NewContinuityOutput = (NewContinuityOutput + ContinuityOffset) & TS_CONT_CNT_MASK;
+ TsSetContinuityCounter(Packet, NewContinuityOutput);
+ LastContinuityOutput = NewContinuityOutput;
+ ContinuityOffset = 0;
+
+ return false; // Keep packet
+}
+
+// --- cNaluStreamProcessor ---------------------------------------------------------
+
+cNaluStreamProcessor::cNaluStreamProcessor()
+{
+ pPatPmtParser = NULL;
+ vpid = -1;
+ data = NULL;
+ length = 0;
+ tempLength = 0;
+ tempLengthAtEnd = false;
+ TotalPackets = 0;
+ DroppedPackets = 0;
+}
+
+void cNaluStreamProcessor::PutBuffer(uchar *Data, int Length)
+{
+ if (length > 0)
+ esyslog("cNaluStreamProcessor::PutBuffer: New data before old data was processed!");
+
+ data = Data;
+ length = Length;
+}
+
+uchar* cNaluStreamProcessor::GetBuffer(int &OutLength)
+{
+ if (length <= 0)
+ {
+ // Need more data - quick exit
+ OutLength = 0;
+ return NULL;
+ }
+ if (tempLength > 0) // Data in temp buffer?
+ {
+ if (tempLengthAtEnd) // Data is at end, copy to beginning
+ {
+ // Overlapping src and dst!
+ for (int i=0; i<tempLength; i++)
+ tempBuffer[i] = tempBuffer[TS_SIZE-tempLength+i];
+ }
+ // Normalize TempBuffer fill
+ if (tempLength < TS_SIZE && length > 0)
+ {
+ int Size = min(TS_SIZE-tempLength, length);
+ memcpy(tempBuffer+tempLength, data, Size);
+ data += Size;
+ length -= Size;
+ tempLength += Size;
+ }
+ if (tempLength < TS_SIZE)
+ {
+ // All incoming data buffered, but need more data
+ tempLengthAtEnd = false;
+ OutLength = 0;
+ return NULL;
+ }
+ // Now: TempLength==TS_SIZE
+ if (tempBuffer[0] != TS_SYNC_BYTE)
+ {
+ // Need to sync on TS within temp buffer
+ int Skipped = 1;
+ while (Skipped < TS_SIZE && (tempBuffer[Skipped] != TS_SYNC_BYTE || (Skipped < length && data[Skipped] != TS_SYNC_BYTE)))
+ Skipped++;
+ esyslog("ERROR: skipped %d bytes to sync on start of TS packet", Skipped);
+ // Pass through skipped bytes
+ tempLengthAtEnd = true;
+ tempLength = TS_SIZE - Skipped; // may be 0, thats ok
+ OutLength = Skipped;
+ return tempBuffer;
+ }
+ // Now: TempBuffer is a TS packet
+ int Pid = TsPid(tempBuffer);
+ if (pPatPmtParser)
+ {
+ if (Pid == 0)
+ pPatPmtParser->ParsePat(tempBuffer, TS_SIZE);
+ else if (pPatPmtParser->IsPmtPid(Pid))
+ pPatPmtParser->ParsePmt(tempBuffer, TS_SIZE);
+ }
+
+ TotalPackets++;
+ bool Drop = false;
+ if (Pid == vpid || (pPatPmtParser && Pid == pPatPmtParser->Vpid() && pPatPmtParser->Vtype() == 0x1B))
+ Drop = NaluDumper.ProcessTSPacket(tempBuffer);
+ if (!Drop)
+ {
+ // Keep this packet, then continue with new data
+ tempLength = 0;
+ OutLength = TS_SIZE;
+ return tempBuffer;
+ }
+ // Drop TempBuffer
+ DroppedPackets++;
+ tempLength = 0;
+ }
+ // Now: TempLength==0, just process data/length
+
+ // Pointer to processed data / length:
+ uchar *Out = data;
+ uchar *OutEnd = Out;
+
+ while (length >= TS_SIZE)
+ {
+ if (data[0] != TS_SYNC_BYTE) {
+ int Skipped = 1;
+ while (Skipped < length && (data[Skipped] != TS_SYNC_BYTE || (length - Skipped > TS_SIZE && data[Skipped + TS_SIZE] != TS_SYNC_BYTE)))
+ Skipped++;
+ esyslog("ERROR: skipped %d bytes to sync on start of TS packet", Skipped);
+
+ // Pass through skipped bytes
+ if (OutEnd != data)
+ memcpy(OutEnd, data, Skipped);
+ OutEnd += Skipped;
+ continue;
+ }
+ // Now: Data starts with complete TS packet
+
+ int Pid = TsPid(data);
+ if (pPatPmtParser)
+ {
+ if (Pid == 0)
+ pPatPmtParser->ParsePat(data, TS_SIZE);
+ else if (pPatPmtParser->IsPmtPid(Pid))
+ pPatPmtParser->ParsePmt(data, TS_SIZE);
+ }
+
+ TotalPackets++;
+ bool Drop = false;
+ if (Pid == vpid || (pPatPmtParser && Pid == pPatPmtParser->Vpid() && pPatPmtParser->Vtype() == 0x1B))
+ Drop = NaluDumper.ProcessTSPacket(data);
+ if (!Drop)
+ {
+ if (OutEnd != data)
+ memcpy(OutEnd, data, TS_SIZE);
+ OutEnd += TS_SIZE;
+ }
+ else
+ {
+ DroppedPackets++;
+ }
+ data += TS_SIZE;
+ length -= TS_SIZE;
+ }
+ // Now: Less than a packet remains.
+ if (length > 0)
+ {
+ // copy remains into temp buffer
+ memcpy(tempBuffer, data, length);
+ tempLength = length;
+ tempLengthAtEnd = false;
+ length = 0;
+ }
+ OutLength = (OutEnd - Out);
+ return OutLength > 0 ? Out : NULL;
+}
diff -Naur vdr-2.1.6/remux.h vdr-2.1.6-naludump-0.1/remux.h
--- vdr-2.1.6/remux.h 2014-02-08 13:41:50.000000000 +0100
+++ vdr-2.1.6-naludump-0.1/remux.h 2014-03-30 17:47:25.000000000 +0200
@@ -62,6 +62,11 @@
return p[3] & TS_PAYLOAD_EXISTS;
}
+inline bool TsSetPayload(const uchar *p)
+{
+ return p[3] & TS_PAYLOAD_EXISTS;
+}
+
inline bool TsHasAdaptationField(const uchar *p)
{
return p[3] & TS_ADAPT_FIELD_EXISTS;
@@ -143,6 +148,7 @@
int64_t TsGetDts(const uchar *p, int l);
void TsSetPts(uchar *p, int l, int64_t Pts);
void TsSetDts(uchar *p, int l, int64_t Dts);
+void TsExtendAdaptionField(unsigned char *Packet, int ToLength);
// Some PES handling tools:
// The following functions that take a pointer to PES data all assume that
@@ -518,4 +524,78 @@
///< available.
};
+
+#define PATCH_NALUDUMP 100
+
+class cNaluDumper {
+ unsigned int History;
+
+ int LastContinuityInput;
+ int LastContinuityOutput;
+ int ContinuityOffset;
+
+ bool DropAllPayload;
+
+ int PesId;
+ int PesOffset;
+
+ int NaluOffset;
+
+ enum eNaluFillState {
+ NALU_NONE=0, // currently not NALU fill stream
+ NALU_FILL, // Within NALU fill stream, 0xff bytes and NALU start code in byte 0
+ NALU_TERM, // Within NALU fill stream, read 0x80 terminating byte
+ NALU_END // Beyond end of NALU fill stream, expecting 0x00 0x00 0x01 now
+ };
+
+ eNaluFillState NaluFillState;
+
+ struct sPayloadInfo {
+ int DropPayloadStartBytes;
+ int DropPayloadEndBytes;
+ bool DropAllPayloadBytes;
+ };
+
+public:
+ cNaluDumper();
+
+ void reset();
+
+ // Single packet interface:
+ bool ProcessTSPacket(unsigned char *Packet);
+
+private:
+ void ProcessPayload(unsigned char *Payload, int size, bool PayloadStart, sPayloadInfo &Info);
+};
+
+class cNaluStreamProcessor {
+ //Buffer stream interface:
+ int vpid;
+ uchar *data;
+ int length;
+ uchar tempBuffer[TS_SIZE];
+ int tempLength;
+ bool tempLengthAtEnd;
+ cPatPmtParser *pPatPmtParser;
+ cNaluDumper NaluDumper;
+
+ long long int TotalPackets;
+ long long int DroppedPackets;
+public:
+ cNaluStreamProcessor();
+
+ void SetPid(int VPid) { vpid = VPid; }
+ void SetPatPmtParser(cPatPmtParser *_pPatPmtParser) { pPatPmtParser = _pPatPmtParser; }
+ // Set either a PID or set a pointer to an PatPmtParser that will detect _one_ PID
+
+ void PutBuffer(uchar *Data, int Length);
+ // Add new data to be processed. Data must be valid until Get() returns NULL.
+ uchar* GetBuffer(int &OutLength);
+ // Returns filtered data, or NULL/0 to indicate that all data from Put() was processed
+ // or buffered.
+
+ long long int GetTotalPackets() { return TotalPackets; }
+ long long int GetDroppedPackets() { return DroppedPackets; }
+};
+
#endif // __REMUX_H

1016
vdr-2.2.0-ttxtsubs.patch Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,102 @@
--- a/diseqc.c 2015/01/26 12:02:14 4.0
+++ b/diseqc.c 2017/01/09 15:10:40
@@ -253,10 +253,10 @@
return result;
}
-uint cDiseqc::SetScrFrequency(uint SatFrequency, const cScr *Scr, uint8_t *Codes) const
+int cDiseqc::SetScrFrequency(int SatFrequency, const cScr *Scr, uint8_t *Codes) const
{
if ((Codes[0] & 0xF0) == 0x70 ) { // EN50607 aka JESS
- uint t = SatFrequency == 0 ? 0 : (SatFrequency - 100);
+ int t = SatFrequency == 0 ? 0 : (SatFrequency - 100);
if (t < 2048 && Scr->Channel() >= 0 && Scr->Channel() < 32) {
Codes[1] = t >> 8 | Scr->Channel() << 3;
Codes[2] = t;
@@ -266,7 +266,7 @@
}
}
else { // EN50494 aka Unicable
- uint t = SatFrequency == 0 ? 0 : (SatFrequency + Scr->UserBand() + 2) / 4 - 350; // '+ 2' together with '/ 4' results in rounding!
+ int t = SatFrequency == 0 ? 0 : (SatFrequency + Scr->UserBand() + 2) / 4 - 350; // '+ 2' together with '/ 4' results in rounding!
if (t < 1024 && Scr->Channel() >= 0 && Scr->Channel() < 8) {
Codes[3] = t >> 8 | (t == 0 ? 0 : scrBank << 2) | Scr->Channel() << 5;
Codes[4] = t;
@@ -399,7 +399,7 @@
return NULL;
}
-cDiseqc::eDiseqcActions cDiseqc::Execute(const char **CurrentAction, uchar *Codes, uint8_t *MaxCodes, const cScr *Scr, uint *Frequency) const
+cDiseqc::eDiseqcActions cDiseqc::Execute(const char **CurrentAction, uchar *Codes, uint8_t *MaxCodes, const cScr *Scr, int *Frequency) const
{
if (!*CurrentAction)
*CurrentAction = commands;
--- a/diseqc.h 2013/06/12 11:52:17 4.0
+++ b/diseqc.h 2017/01/09 15:11:19
@@ -86,7 +86,7 @@
mutable int scrBank;
char *commands;
bool parsing;
- uint SetScrFrequency(uint SatFrequency, const cScr *Scr, uint8_t *Codes) const;
+ int SetScrFrequency(int SatFrequency, const cScr *Scr, uint8_t *Codes) const;
int SetScrPin(const cScr *Scr, uint8_t *Codes) const;
const char *Wait(const char *s) const;
const char *GetPosition(const char *s) const;
@@ -96,7 +96,7 @@
cDiseqc(void);
~cDiseqc();
bool Parse(const char *s);
- eDiseqcActions Execute(const char **CurrentAction, uchar *Codes, uint8_t *MaxCodes, const cScr *Scr, uint *Frequency) const;
+ eDiseqcActions Execute(const char **CurrentAction, uchar *Codes, uint8_t *MaxCodes, const cScr *Scr, int *Frequency) const;
///< Parses the DiSEqC commands and returns the appropriate action code
///< with every call. CurrentAction must be the address of a character pointer,
///< which is initialized to NULL. This pointer is used internally while parsing
--- a/dvbdevice.c 2016/11/07 13:55:58 4.3
+++ b/dvbdevice.c 2017/01/09 15:11:39
@@ -329,7 +329,7 @@
void ClearEventQueue(void) const;
bool GetFrontendStatus(fe_status_t &Status) const;
cPositioner *GetPositioner(void);
- void ExecuteDiseqc(const cDiseqc *Diseqc, unsigned int *Frequency);
+ void ExecuteDiseqc(const cDiseqc *Diseqc, int *Frequency);
void ResetToneAndVoltage(void);
bool SetFrontend(void);
virtual void Action(void);
@@ -696,7 +696,7 @@
return positioner;
}
-void cDvbTuner::ExecuteDiseqc(const cDiseqc *Diseqc, unsigned int *Frequency)
+void cDvbTuner::ExecuteDiseqc(const cDiseqc *Diseqc, int *Frequency)
{
if (!lnbPowerTurnedOn) {
CHECK(ioctl(fd_frontend, FE_SET_VOLTAGE, SEC_VOLTAGE_13)); // must explicitly turn on LNB power
@@ -806,7 +806,7 @@
SETCMD(DTV_DELIVERY_SYSTEM, frontendType);
if (frontendType == SYS_DVBS || frontendType == SYS_DVBS2) {
- unsigned int frequency = channel.Frequency();
+ int frequency = channel.Frequency();
if (Setup.DiSEqC) {
if (const cDiseqc *diseqc = Diseqcs.Get(device->CardIndex() + 1, channel.Source(), frequency, dtp.Polarization(), &scr)) {
frequency -= diseqc->Lof();
@@ -829,7 +829,7 @@
}
else {
int tone = SEC_TONE_OFF;
- if (frequency < (unsigned int)Setup.LnbSLOF) {
+ if (frequency < Setup.LnbSLOF) {
frequency -= Setup.LnbFrequLo;
tone = SEC_TONE_OFF;
}
--- a/remux.c.orig 2017-03-02 13:22:31.133182283 +0100
+++ b/remux.c 2017-03-02 13:23:50.300598025 +0100
@@ -1638,7 +1638,7 @@
Div += parser->IFrameTemporalReferenceOffset();
if (Div <= 0)
Div = 1;
- uint32_t Delta = ptsValues[0] / Div;
+ int Delta = ptsValues[0] / Div;
// determine frame info:
if (isVideo) {
if (abs(Delta - 3600) <= 1)

View file

@ -0,0 +1,44 @@
# This patch fixes a bug in handling the tfRecording flag in the SVDRP commands MODT
# and UPDT. The tfRecording flag must only be handled by the VDR that actually hosts
# and processes the timer.
#
--- svdrp.c 2018/03/19 12:16:33 5.0
+++ svdrp.c 2018/04/19 09:45:08
@@ -2036,6 +2036,7 @@
LOCK_TIMERS_WRITE;
Timers->SetExplicitModify();
if (cTimer *Timer = Timers->GetById(Id)) {
+ bool IsRecording = Timer->HasFlags(tfRecording);
cTimer t = *Timer;
if (strcasecmp(tail, "ON") == 0)
t.SetFlags(tfActive);
@@ -2046,6 +2047,10 @@
return;
}
*Timer = t;
+ if (IsRecording)
+ Timer->SetFlags(tfRecording);
+ else
+ Timer->ClrFlags(tfRecording);
Timers->SetModified();
isyslog("SVDRP %s < %s modified timer %s (%s)", Setup.SVDRPHostName, *clientName, *Timer->ToDescr(), Timer->HasFlags(tfActive) ? "active" : "inactive");
Reply(250, "%d %s", Timer->Id(), *Timer->ToText(true));
@@ -2478,12 +2483,18 @@
if (Timer->Parse(Option)) {
LOCK_TIMERS_WRITE;
if (cTimer *t = Timers->GetTimer(Timer)) {
+ bool IsRecording = t->HasFlags(tfRecording);
t->Parse(Option);
delete Timer;
Timer = t;
+ if (IsRecording)
+ Timer->SetFlags(tfRecording);
+ else
+ Timer->ClrFlags(tfRecording);
isyslog("SVDRP %s < %s updated timer %s", Setup.SVDRPHostName, *clientName, *Timer->ToDescr());
}
else {
+ Timer->ClrFlags(tfRecording);
Timers->Add(Timer);
isyslog("SVDRP %s < %s added timer %s", Setup.SVDRPHostName, *clientName, *Timer->ToDescr());
}

View file

@ -0,0 +1,108 @@
--- vdr-2.4.0/config.h.orig 2018-04-16 09:36:30.655036427 +0200
+++ vdr-2.4.0/config.h 2018-04-16 09:37:43.068036894 +0200
@@ -47,6 +47,10 @@
#define TIMERMACRO_TITLE "TITLE"
#define TIMERMACRO_EPISODE "EPISODE"
+// The MainMenuHook Patch's version number:
+#define MAINMENUHOOKSVERSION "1.0.1"
+#define MAINMENUHOOKSVERSNUM 10001 // Version * 10000 + Major * 100 + Minor
+
#define MINOSDWIDTH 480
#define MAXOSDWIDTH 1920
#define MINOSDHEIGHT 324
--- vdr-2.4.0/menu.c.orig 2018-04-16 09:39:22.013037531 +0200
+++ vdr-2.4.0/menu.c 2018-04-16 10:24:50.584055109 +0200
@@ -4475,16 +4475,31 @@
Set();
// Initial submenus:
-
+ cOsdObject *menu = NULL;
switch (State) {
- case osSchedule: AddSubMenu(new cMenuSchedule); break;
- case osChannels: AddSubMenu(new cMenuChannels); break;
- case osTimers: AddSubMenu(new cMenuTimers); break;
- case osRecordings: AddSubMenu(new cMenuRecordings(NULL, 0, OpenSubMenus)); break;
- case osSetup: AddSubMenu(new cMenuSetup); break;
- case osCommands: AddSubMenu(new cMenuCommands(tr("Commands"), &Commands)); break;
+ case osSchedule:
+ if (!cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osSchedule", &menu))
+ menu = new cMenuSchedule;
+ break;
+ case osChannels:
+ if (!cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osChannels", &menu))
+ menu = new cMenuChannels;
+ break;
+ case osTimers:
+ if (!cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osTimers", &menu))
+ menu = new cMenuTimers;
+ break;
+ case osRecordings:
+ if (!cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osRecordings", &menu))
+ menu = new cMenuRecordings(NULL, 0, OpenSubMenus);
+ break;
+ case osSetup: menu = new cMenuSetup; break;
+ case osCommands: menu = new cMenuCommands(tr("Commands"), &Commands); break;
default: break;
}
+ if (menu)
+ if (menu->IsMenu())
+ AddSubMenu((cOsdMenu *) menu);
}
cOsdObject *cMenuMain::PluginOsdObject(void)
@@ -4592,13 +4607,34 @@
eOSState state = cOsdMenu::ProcessKey(Key);
HadSubMenu |= HasSubMenu();
+ cOsdObject *menu = NULL;
switch (state) {
- case osSchedule: return AddSubMenu(new cMenuSchedule);
- case osChannels: return AddSubMenu(new cMenuChannels);
- case osTimers: return AddSubMenu(new cMenuTimers);
- case osRecordings: return AddSubMenu(new cMenuRecordings);
- case osSetup: return AddSubMenu(new cMenuSetup);
- case osCommands: return AddSubMenu(new cMenuCommands(tr("Commands"), &Commands));
+ case osSchedule:
+ if (!cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osSchedule", &menu))
+ menu = new cMenuSchedule;
+ else
+ state = osContinue;
+ break;
+ case osChannels:
+ if (!cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osChannels", &menu))
+ menu = new cMenuChannels;
+ else
+ state = osContinue;
+ break;
+ case osTimers:
+ if (!cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osTimers", &menu))
+ menu = new cMenuTimers;
+ else
+ state = osContinue;
+ break;
+ case osRecordings:
+ if (!cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osRecordings", &menu))
+ menu = new cMenuRecordings;
+ else
+ state = osContinue;
+ break;
+ case osSetup: menu = new cMenuSetup; break;
+ case osCommands: menu = new cMenuCommands(tr("Commands"), &Commands); break;
case osStopRecord: if (Interface->Confirm(tr("Stop recording?"))) {
if (cOsdItem *item = Get(Current())) {
cRecordControls::Stop(item->Text() + strlen(tr(STOP_RECORDING)));
@@ -4649,6 +4685,12 @@
default: break;
}
}
+ if (menu) {
+ if (menu->IsMenu())
+ return AddSubMenu((cOsdMenu *) menu);
+ pluginOsdObject = menu;
+ return osPlugin;
+ }
if (!HasSubMenu() && Update(HadSubMenu))
Display();
if (Key != kNone) {

24
vdr-2.4.1-glibc231.patch Normal file
View file

@ -0,0 +1,24 @@
From dcfa8ba29f4c95edbdceb0f1bbae0e62fa40c4e2 Mon Sep 17 00:00:00 2001
From: Manuel Reimer <manuel.reimer@gmx.de>
Date: Sat, 14 Dec 2019 12:01:13 +0100
Subject: [PATCH] Replace obsolete stime() function with clock_settime()
---
eit.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/eit.c b/eit.c
index 50d8229..82294dc 100644
--- a/eit.c
+++ b/eit.c
@@ -391,7 +391,9 @@ cTDT::cTDT(const u_char *Data)
if (abs(diff) > MAX_TIME_DIFF) {
mutex.Lock();
if (abs(diff) > MAX_ADJ_DIFF) {
- if (stime(&dvbtim) == 0)
+ timespec ts = {};
+ ts.tv_sec = dvbtim;
+ if (clock_settime(CLOCK_REALTIME, &ts) == 0)
isyslog("system time changed from %s (%ld) to %s (%ld)", *TimeToString(loctim), loctim, *TimeToString(dvbtim), dvbtim);
else
esyslog("ERROR while setting system time: %m");

View file

@ -0,0 +1,115 @@
diff -Nurp vdr-2.4.1.orig/channels.c vdr-2.4.1.NitTid/channels.c
--- vdr-2.4.1.orig/channels.c 2017-06-10 17:08:56.000000000 +0200
+++ vdr-2.4.1.NitTid/channels.c 2019-09-24 20:48:49.243342312 +0200
@@ -1096,11 +1096,13 @@ cChannel *cChannels::NewChannel(const cC
#define CHANNELMARKOBSOLETE "OBSOLETE"
#define CHANNELTIMEOBSOLETE 3600 // seconds to wait before declaring a channel obsolete (in case it has actually been seen before)
-bool cChannels::MarkObsoleteChannels(int Source, int Nid, int Tid)
+bool cChannels::MarkObsoleteChannels(int Source, int Nid, int Tid, int Transponder)
{
bool ChannelsModified = false;
for (cChannel *Channel = First(); Channel; Channel = Next(Channel)) {
if (time(NULL) - Channel->Seen() > CHANNELTIMEOBSOLETE && Channel->Source() == Source && Channel->Nid() == Nid && Channel->Tid() == Tid && Channel->Rid() == 0) {
+ if (Transponder && !ISTRANSPONDER(Channel->Transponder(), Transponder)) // mark channels only on specified transponder
+ continue;
int OldShowChannelNamesWithSource = Setup.ShowChannelNamesWithSource;
Setup.ShowChannelNamesWithSource = 0;
if (!endswith(Channel->Name(), CHANNELMARKOBSOLETE))
diff -Nurp vdr-2.4.1.orig/channels.h vdr-2.4.1.NitTid/channels.h
--- vdr-2.4.1.orig/channels.h 2017-06-10 17:06:40.000000000 +0200
+++ vdr-2.4.1.NitTid/channels.h 2019-09-23 22:46:20.231197911 +0200
@@ -251,7 +251,7 @@ public:
///< and will be set to the current value of the list's internal state variable upon
///< return from this function.
cChannel *NewChannel(const cChannel *Transponder, const char *Name, const char *ShortName, const char *Provider, int Nid, int Tid, int Sid, int Rid = 0);
- bool MarkObsoleteChannels(int Source, int Nid, int Tid);
+ bool MarkObsoleteChannels(int Source, int Nid, int Tid, int Transponder = 0);
};
// Provide lock controlled access to the list:
diff -Nurp vdr-2.4.1.orig/eitscan.c vdr-2.4.1.NitTid/eitscan.c
--- vdr-2.4.1.orig/eitscan.c 2019-03-12 12:54:27.000000000 +0100
+++ vdr-2.4.1.NitTid/eitscan.c 2019-09-23 23:31:26.778124945 +0200
@@ -60,8 +60,11 @@ void cScanList::AddTransponder(const cCh
{
if (Channel->Source() && Channel->Transponder()) {
for (cScanData *sd = First(); sd; sd = Next(sd)) {
- if (sd->Source() == Channel->Source() && ISTRANSPONDER(sd->Transponder(), Channel->Transponder()))
- return;
+ if (sd->Source() == Channel->Source() && ISTRANSPONDER(sd->Transponder(), Channel->Transponder())) {
+ const cChannel *ch = sd->GetChannel();
+ if (ch->Nid() == Channel->Nid() && ch->Tid() == Channel->Tid()) // add a channel for each unique transponder/Nid/Tid triple
+ return;
+ }
}
Add(new cScanData(Channel));
}
@@ -78,8 +81,10 @@ void cTransponderList::AddTransponder(cC
{
for (cChannel *ch = First(); ch; ch = Next(ch)) {
if (ch->Source() == Channel->Source() && ch->Transponder() == Channel->Transponder()) {
- delete Channel;
- return;
+ if (ch->Nid() == Channel->Nid() && ch->Tid() == Channel->Tid()) { // add a channel for each unique transponder/Nid/Tid triple
+ delete Channel;
+ return;
+ }
}
}
Add(Channel);
diff -Nurp vdr-2.4.1.orig/nit.c vdr-2.4.1.NitTid/nit.c
--- vdr-2.4.1.orig/nit.c 2019-05-31 23:47:02.000000000 +0200
+++ vdr-2.4.1.NitTid/nit.c 2019-09-25 00:09:04.140501158 +0200
@@ -107,6 +107,7 @@ void cNitFilter::Process(u_short Pid, u_
}
for (SI::Loop::Iterator it2; (d = ts.transportStreamDescriptors.getNext(it2)); ) {
+ int tsTransponder = 0;
switch (d->getDescriptorTag()) {
case SI::SatelliteDeliverySystemDescriptorTag: {
SI::SatelliteDeliverySystemDescriptor *sd = (SI::SatelliteDeliverySystemDescriptor *)d;
@@ -125,6 +126,7 @@ void cNitFilter::Process(u_short Pid, u_
dtp.SetRollOff(System ? RollOffs[sd->getRollOff()] : ROLLOFF_AUTO);
int SymbolRate = BCD2INT(sd->getSymbolRate()) / 10;
dbgnit(" %s %d %c %d %d DVB-S%d\n", *cSource::ToString(Source), Frequency, dtp.Polarization(), SymbolRate, cChannel::Transponder(Frequency, dtp.Polarization()), System ? 2 : 1);
+ tsTransponder = cChannel::Transponder(Frequency, dtp.Polarization());
if (Setup.UpdateChannels >= 5) {
bool found = false;
bool forceTransponderUpdate = false;
@@ -192,6 +194,7 @@ void cNitFilter::Process(u_short Pid, u_
dtp.SetModulation(Modulations[min(sd->getModulation(), 6)]);
int SymbolRate = BCD2INT(sd->getSymbolRate()) / 10;
dbgnit(" %s %d %d %d %d\n", *cSource::ToString(Source), Frequency, dtp.CoderateH(), dtp.Modulation(), SymbolRate);
+ tsTransponder = Frequency / 1000;
if (Setup.UpdateChannels >= 5) {
bool found = false;
bool forceTransponderUpdate = false;
@@ -248,6 +251,7 @@ void cNitFilter::Process(u_short Pid, u_
static int TransmissionModes[] = { TRANSMISSION_MODE_2K, TRANSMISSION_MODE_8K, TRANSMISSION_MODE_4K, TRANSMISSION_MODE_AUTO };
dtp.SetTransmission(TransmissionModes[sd->getTransmissionMode()]);
dbgnit(" %s %d %d %d %d %d %d %d %d\n", *cSource::ToString(Source), Frequency, dtp.Bandwidth(), dtp.Modulation(), dtp.Hierarchy(), dtp.CoderateH(), dtp.CoderateL(), dtp.Guard(), dtp.Transmission());
+ tsTransponder = Frequency / 1000000;
if (Setup.UpdateChannels >= 5) {
bool found = false;
bool forceTransponderUpdate = false;
@@ -298,6 +302,7 @@ void cNitFilter::Process(u_short Pid, u_
SI::ExtensionDescriptor *sd = (SI::ExtensionDescriptor *)d;
switch (sd->getExtensionDescriptorTag()) {
case SI::T2DeliverySystemDescriptorTag: {
+ tsTransponder = Transponder();
if (Setup.UpdateChannels >= 5) {
for (cChannel *Channel = Channels->First(); Channel; Channel = Channels->Next(Channel)) {
int Source = cSource::FromData(cSource::stTerr);
@@ -368,6 +373,11 @@ void cNitFilter::Process(u_short Pid, u_
break;
default: ;
}
+ if (Setup.UpdateChannels == 1 || Setup.UpdateChannels >= 3) {
+ // mark all channels with obsolete Nid/Tid on tuned transponder
+ if (tsTransponder && ISTRANSPONDER(tsTransponder, Transponder()) && (Channel()->Nid() != ts.getOriginalNetworkId() || Channel()->Tid() != ts.getTransportStreamId()))
+ ChannelsModified |= Channels->MarkObsoleteChannels(Source(), Channel()->Nid(), Channel()->Tid(), Transponder());
+ }
delete d;
}
}

View file

@ -0,0 +1,22 @@
Description: Log an error message when skincures can't initialize the screen
Author: Tobias Grimm <etobi@debian.org>
--- a/PLUGINS/src/skincurses/skincurses.c.orig 2019-06-17 18:31:59.351079418 +0200
+++ b/PLUGINS/src/skincurses/skincurses.c 2019-06-17 18:35:21.586034302 +0200
@@ -11,6 +11,7 @@
#include <vdr/plugin.h>
#include <vdr/skins.h>
#include <vdr/videodir.h>
+#include <vdr/tools.h>
static const char *VERSION = "2.4.1";
static const char *DESCRIPTION = trNOOP("A text only skin");
@@ -841,6 +842,7 @@
ScOsdHeight = maxy - begy + 1;
return true;
}
+ esyslog("skincurses: unable to initialize curses screen");
return false;
}

View file

@ -0,0 +1,62 @@
diff --git a/recording.h b/recording.h
index 6f26f2f6..718df343 100644
--- a/recording.h
+++ b/recording.h
@@ -41,6 +41,11 @@ enum eRecordingUsage {
ruCanceled = 0x8000, // the operation has been canceled, waiting for cleanup
};
+// workaround patch for enabling extra features in extrecmenung until vdr 2.5.2 is released
+#ifndef EPGRENAME
+#define EPGRENAME
+#endif
+
void RemoveDeletedRecordings(void);
void AssertFreeDiskSpace(int Priority = 0, bool Force = false);
///< The special Priority value -1 means that we shall get rid of any
@@ -74,8 +79,6 @@ private:
char *fileName;
cRecordingInfo(const cChannel *Channel = NULL, const cEvent *Event = NULL);
bool Read(FILE *f);
- void SetData(const char *Title, const char *ShortText, const char *Description);
- void SetAux(const char *Aux);
public:
cRecordingInfo(const char *FileName);
~cRecordingInfo();
@@ -93,6 +96,8 @@ public:
bool Write(FILE *f, const char *Prefix = "") const;
bool Read(void);
bool Write(void) const;
+ void SetData(const char *Title, const char *ShortText, const char *Description);
+ void SetAux(const char *Aux);
};
class cRecording : public cListObject {
@@ -150,7 +155,7 @@ public:
///< Returns the full path name to the recording directory, including the
///< video directory and the actual '*.rec'. For disk file access use.
const char *Title(char Delimiter = ' ', bool NewIndicator = false, int Level = -1) const;
- const cRecordingInfo *Info(void) const { return info; }
+ cRecordingInfo *Info(void) const { return info; }
const char *PrefixFileName(char Prefix);
int HierarchyLevels(void) const;
void ResetResume(void) const;
diff --git a/recording.c b/recording.c
index 17467e36..a7f08a26 100644
--- a/recording.c
+++ b/recording.c
@@ -430,11 +430,11 @@ cRecordingInfo::~cRecordingInfo()
void cRecordingInfo::SetData(const char *Title, const char *ShortText, const char *Description)
{
- if (!isempty(Title))
+ if (Title)
((cEvent *)event)->SetTitle(Title);
- if (!isempty(ShortText))
+ if (ShortText)
((cEvent *)event)->SetShortText(ShortText);
- if (!isempty(Description))
+ if (Description)
((cEvent *)event)->SetDescription(Description);
}

View file

@ -0,0 +1,78 @@
diff -Nurp vdr-2.4.6.orig/channels.c vdr-2.4.6/channels.c
--- vdr-2.4.6.orig/channels.c 2020-04-11 11:22:05.000000000 +0200
+++ vdr-2.4.6/channels.c 2021-01-02 14:56:49.883831519 +0100
@@ -16,6 +16,8 @@
// format characters in order to allow any number of blanks after a numeric
// value!
+#define CHANNELMARKOBSOLETE "OBSOLETE"
+
// --- tChannelID ------------------------------------------------------------
const tChannelID tChannelID::InvalidID;
@@ -434,6 +436,24 @@ void cChannel::SetSeen(void)
seen = time(NULL);
}
+bool cChannel::ClearObsoleteChannel(void)
+{
+ bool ChannelsModified = false;
+ if (endswith(name, CHANNELMARKOBSOLETE)) {
+ int mlen = strlen(CHANNELMARKOBSOLETE);
+ int e = strlen(name) - mlen - 1;
+ name[e] = '\0';
+ cString clrname = cString::sprintf("%s", name);
+ name[e] = ' ';
+
+ int OldShowChannelNamesWithSource = Setup.ShowChannelNamesWithSource;
+ Setup.ShowChannelNamesWithSource = 0;
+ ChannelsModified |= SetName(clrname, shortName, provider + mlen + 1);
+ Setup.ShowChannelNamesWithSource = OldShowChannelNamesWithSource;
+ }
+ return ChannelsModified;
+}
+
void cChannel::DelLinkChannel(cChannel *LinkChannel)
{
if (linkChannels) {
@@ -1112,7 +1132,6 @@ cChannel *cChannels::NewChannel(const cC
return NULL;
}
-#define CHANNELMARKOBSOLETE "OBSOLETE"
#define CHANNELTIMEOBSOLETE 3600 // seconds to wait before declaring a channel obsolete (in case it has actually been seen before)
bool cChannels::MarkObsoleteChannels(int Source, int Nid, int Tid)
diff -Nurp vdr-2.4.6.orig/channels.h vdr-2.4.6/channels.h
--- vdr-2.4.6.orig/channels.h 2020-06-10 16:00:36.000000000 +0200
+++ vdr-2.4.6/channels.h 2021-01-02 12:58:13.693581025 +0100
@@ -202,6 +202,7 @@ public:
void SetRefChannel(cChannel *RefChannel);
bool SetSubtitlingDescriptors(uchar *SubtitlingTypes, uint16_t *CompositionPageIds, uint16_t *AncillaryPageIds);
void SetSeen(void);
+ bool ClearObsoleteChannel(void);
void DelLinkChannel(cChannel *LinkChannel);
};
diff -Nurp vdr-2.4.6.orig/pat.c vdr-2.4.6/pat.c
--- vdr-2.4.6.orig/pat.c 2020-12-18 15:51:57.000000000 +0100
+++ vdr-2.4.6/pat.c 2021-01-02 12:56:25.480243876 +0100
@@ -489,6 +489,9 @@ void cPatFilter::Process(u_short Pid, u_
SwitchToNextPmtPid();
cChannel *Channel = Channels->GetByServiceID(Source(), Transponder(), pmt.getServiceId());
if (Channel) {
+ bool seen = Channel->Seen();
+ if (!seen) // not yet seen in sdt.c
+ Channel->SetSeen();
SI::CaDescriptor *d;
cCaDescriptors *CaDescriptors = new cCaDescriptors(Channel->Source(), Channel->Transponder(), Channel->Sid(), Pid);
// Scan the common loop:
@@ -723,6 +726,8 @@ void cPatFilter::Process(u_short Pid, u_
ChannelsModified |= Channel->SetCaIds(CaDescriptors->CaIds());
ChannelsModified |= Channel->SetSubtitlingDescriptors(SubtitlingTypes, CompositionPageIds, AncillaryPageIds);
}
+ if (!seen && (Setup.UpdateChannels == 1 || Setup.UpdateChannels >= 3))
+ ChannelsModified |= Channel->ClearObsoleteChannel(); // just in case
ChannelsModified |= Channel->SetCaDescriptors(CaDescriptorHandler.AddCaDescriptors(CaDescriptors));
}
StateKey.Remove(ChannelsModified);

View file

@ -0,0 +1,62 @@
diff -Nurp vdr-2.4.6.orig/channels.c vdr-2.4.6/channels.c
--- vdr-2.4.6.orig/channels.c 2020-04-11 11:22:05.000000000 +0200
+++ vdr-2.4.6/channels.c 2021-01-01 12:35:10.946734352 +0100
@@ -1115,11 +1116,20 @@ cChannel *cChannels::NewChannel(const cC
#define CHANNELMARKOBSOLETE "OBSOLETE"
#define CHANNELTIMEOBSOLETE 3600 // seconds to wait before declaring a channel obsolete (in case it has actually been seen before)
-bool cChannels::MarkObsoleteChannels(int Source, int Nid, int Tid)
+bool cChannels::MarkObsoleteChannels(int Source, int Transponder, int StreamId, int Nid, int Tid)
{
bool ChannelsModified = false;
for (cChannel *Channel = First(); Channel; Channel = Next(Channel)) {
- if (time(NULL) - Channel->Seen() > CHANNELTIMEOBSOLETE && Channel->Source() == Source && Channel->Nid() == Nid && Channel->Tid() == Tid && Channel->Rid() == 0) {
+ if (Channel->Source() != Source)
+ continue;
+ bool obsolete = false;
+ if (Channel->Nid() == Nid && Channel->Tid() == Tid)
+ obsolete = time(NULL) - Channel->Seen() > CHANNELTIMEOBSOLETE && Channel->Rid() == 0; // obsolete Sid
+ else if (ISTRANSPONDER(Channel->Transponder(), Transponder)) {
+ cDvbTransponderParameters dtp(Channel->Parameters());
+ obsolete = dtp.StreamId() == StreamId; // obsolete Nid/Tid
+ }
+ if (obsolete) {
int OldShowChannelNamesWithSource = Setup.ShowChannelNamesWithSource;
Setup.ShowChannelNamesWithSource = 0;
if (!endswith(Channel->Name(), CHANNELMARKOBSOLETE))
diff -Nurp vdr-2.4.6.orig/channels.h vdr-2.4.6/channels.h
--- vdr-2.4.6.orig/channels.h 2020-06-10 16:00:36.000000000 +0200
+++ vdr-2.4.6/channels.h 2020-12-31 18:35:07.050191444 +0100
@@ -252,7 +252,7 @@ public:
///< and will be set to the current value of the list's internal state variable upon
///< return from this function.
cChannel *NewChannel(const cChannel *Transponder, const char *Name, const char *ShortName, const char *Provider, int Nid, int Tid, int Sid, int Rid = 0);
- bool MarkObsoleteChannels(int Source, int Nid, int Tid);
+ bool MarkObsoleteChannels(int Source, int Transponder, int Streamid, int Nid, int Tid);
};
// Provide lock controlled access to the list:
diff -Nurp vdr-2.4.6.orig/sdt.c vdr-2.4.6/sdt.c
--- vdr-2.4.6.orig/sdt.c 2020-06-16 16:50:07.000000000 +0200
+++ vdr-2.4.6/sdt.c 2020-12-31 18:40:31.853536210 +0100
@@ -12,6 +12,7 @@
#include "config.h"
#include "libsi/section.h"
#include "libsi/descriptor.h"
+#include "dvbdevice.h"
// Set to 'true' for debug output:
static bool DebugSdt = false;
@@ -205,9 +206,10 @@ void cSdtFilter::Process(u_short Pid, u_
}
if (sdt.getSectionNumber() == sdt.getLastSectionNumber()) {
if (Setup.UpdateChannels == 1 || Setup.UpdateChannels >= 3) {
- ChannelsModified |= Channels->MarkObsoleteChannels(source, sdt.getOriginalNetworkId(), sdt.getTransportStreamId());
+ cDvbTransponderParameters dtp(Channel()->Parameters());
+ ChannelsModified |= Channels->MarkObsoleteChannels(source, Transponder(), dtp.StreamId(), sdt.getOriginalNetworkId(), sdt.getTransportStreamId());
if (source != Source())
- ChannelsModified |= Channels->MarkObsoleteChannels(Source(), sdt.getOriginalNetworkId(), sdt.getTransportStreamId());
+ ChannelsModified |= Channels->MarkObsoleteChannels(Source(), Transponder(), dtp.StreamId(), sdt.getOriginalNetworkId(), sdt.getTransportStreamId());
}
}
StateKey.Remove(ChannelsModified);

26
vdr-2.4.7_gcc11.patch Normal file
View file

@ -0,0 +1,26 @@
Fix compile with gcc-11, officially from kls
Signed-off-by: Martin Dummer <martin.dummer@gmx.net>
--- a/tools.h 2021/01/19 20:38:28 5.3
+++ b/tools.h 2021/05/05 15:16:45
@@ -53,17 +53,15 @@
// In case some plugin needs to use the STL and gets an error message regarding one
// of these functions, you can #define DISABLE_TEMPLATES_COLLIDING_WITH_STL before
-// including tools.h.
-#if !defined(__STL_CONFIG_H) // for old versions of the STL
-#if !defined(DISABLE_TEMPLATES_COLLIDING_WITH_STL) && !defined(_STL_ALGOBASE_H)
+// including any VDR header files.
+#if !defined(DISABLE_TEMPLATES_COLLIDING_WITH_STL)
template<class T> inline T min(T a, T b) { return a <= b ? a : b; }
template<class T> inline T max(T a, T b) { return a >= b ? a : b; }
#endif
template<class T> inline int sgn(T a) { return a < 0 ? -1 : a > 0 ? 1 : 0; }
-#if !defined(DISABLE_TEMPLATES_COLLIDING_WITH_STL) && !defined(_MOVE_H)
+#if !defined(DISABLE_TEMPLATES_COLLIDING_WITH_STL)
template<class T> inline void swap(T &a, T &b) { T t = a; a = b; b = t; }
#endif
-#endif
template<class T> inline T constrain(T v, T l, T h) { return v < l ? l : v > h ? h : v; }

BIN
vdr-2.6.0-eit.patch Normal file

Binary file not shown.

View file

@ -0,0 +1,11 @@
--- a/dvbplayer.c 2019/05/27 13:54:19 5.0
+++ b/dvbplayer.c 2022/01/13 10:18:27
@@ -914,7 +914,7 @@
ptsIndex.Put(isPesRecording ? PesGetPts(b) : TsGetPts(b, r), Index, true);
}
playMode = pmStill;
- readIndex = Index;
+ readIndex = Index - 1; // makes sure a later play starts with this I-frame
}
}
else {

View file

@ -0,0 +1,11 @@
--- a/recording.c 2022/11/28 14:39:23 5.19
+++ b/recording.c 2022/12/01 12:39:42
@@ -2579,7 +2579,7 @@
cCondWait::SleepMs(INDEXFILETESTINTERVAL);
}
int delta = 0;
- if (!Record && (access(fileName, R_OK) != 0 || FileSize(fileName) == 0)) {
+ if (!Record && (access(fileName, R_OK) != 0 || FileSize(fileName) == 0 && time(NULL) - LastModifiedTime(fileName) > MAXWAITFORINDEXFILE)) {
// Index file doesn't exist, so try to regenerate it:
if (!isPesRecording) { // sorry, can only do this for TS recordings
resumeFile.Delete(); // just in case

31
vdr-2.6.2-remux.patch Normal file
View file

@ -0,0 +1,31 @@
diff --git a/remux.c b/remux.c
index 391fd6ff..54fc50fd 100644
--- a/remux.c
+++ b/remux.c
@@ -1333,7 +1333,7 @@ int cMpeg2Parser::Parse(const uchar *Data, int Length, int Pid)
seenScanType = true;
if (debug) {
cString s = cString::sprintf("MPEG2: %d x %d%c %.2f fps", frameWidth, frameHeight, progressive ? 'p' : 'i', framesPerSecond);
- dsyslog(s);
+ dsyslog("%s",*s);
dbgframes("\n%s", *s);
}
}
@@ -1607,7 +1607,7 @@ void cH264Parser::ParseSequenceParameterSet(void)
}
if (debug) {
cString s = cString::sprintf("H.264: %d x %d%c %.2f fps %d Bit", frameWidth, frameHeight, progressive ? 'p':'i', framesPerSecond, bitDepth);
- dsyslog(s);
+ dsyslog("%s", *s);
dbgframes("\n%s", *s);
}
}
@@ -1908,7 +1908,7 @@ void cH265Parser::ParseSequenceParameterSet(void)
}
if (debug) {
cString s = cString::sprintf("H.265: %d x %d%c %.2f fps %d Bit", frameWidth, frameHeight, progressive ? 'p':'i', framesPerSecond, bitDepth);
- dsyslog(s);
+ dsyslog("%s", *s);
dbgframes("\n%s", *s);
}
}

View file

@ -0,0 +1,11 @@
--- a/menu.c 2022/11/22 15:53:07 5.8
+++ b/menu.c 2022/12/01 12:55:34
@@ -3250,7 +3250,7 @@
int Id;
char *RemoteBuf = NULL;
cString Remote;
- if (2 == sscanf(TimerId, "%d@%m[^ \n]", &Id, &RemoteBuf)) {
+ if (2 == sscanf(TimerId, "%d@%m[^ \n]", &Id, &RemoteBuf) && Id != 0) {
Remote = RemoteBuf;
free(RemoteBuf);
if (Interface->Confirm(tr("Timer still recording - really delete?"))) {

View file

@ -1,44 +0,0 @@
--- timers.c 2024/03/06 14:37:15 5.20
+++ timers.c 2024/10/10 09:23:34
@@ -726,10 +726,39 @@
bool cTimer::Expired(void) const
{
if (IsSingleEvent() && !Recording()) {
+ time_t Now = time(NULL);
time_t ExpireTime = StopTimeEvent();
- if (HasFlags(tfVps))
+ if (HasFlags(tfVps)) {
ExpireTime += EXPIRELATENCY;
- return ExpireTime <= time(NULL);
+ if (ExpireTime <= Now) {
+ LOCK_SCHEDULES_READ;
+ const cSchedule *Schedule = event ? event->Schedule() : NULL;
+ const cEvent *FirstEvent = event;
+ if (Schedule)
+ FirstEvent = Schedule->Events()->Next(FirstEvent);
+ else if ((Schedule = Schedules->GetSchedule(Channel())) != NULL) {
+ FirstEvent = Schedule->Events()->First();
+ if (FirstEvent)
+ dsyslog("timer %s had no event, got %s from channel/schedule", *ToDescr(), *FirstEvent->ToDescr());
+ }
+ if (FirstEvent) {
+ if (Schedule) {
+ for (const cEvent *e = FirstEvent; e; e = Schedule->Events()->Next(e)) {
+ if (e->Vps() == startTime) {
+ ExpireTime = e->EndTime() + EXPIRELATENCY;
+ dsyslog("timer %s is waiting for next VPS event %s", *ToDescr(), *e->ToDescr());
+ break;
+ }
+ }
+ }
+ }
+ else {
+ dsyslog("timer %s has no event, setting expiration to +24h", *ToDescr());
+ ExpireTime += 3600 * 24;
+ }
+ }
+ }
+ return ExpireTime <= Now;
}
return false;
}

26
vdr-channel+epg.patch Normal file
View file

@ -0,0 +1,26 @@
diff -up vdr-1.6.0/menu.c~ vdr-1.6.0/menu.c
--- vdr-1.6.0/menu.c~ 2008-03-16 13:15:28.000000000 +0200
+++ vdr-1.6.0/menu.c 2011-02-15 00:39:42.267224859 +0200
@@ -399,11 +399,20 @@ int cMenuChannelItem::Compare(const cLis
void cMenuChannelItem::Set(void)
{
cString buffer;
+ const cEvent *Event = NULL;
if (!channel->GroupSep()) {
+ cSchedulesLock SchedulesLock;
+ const cSchedules *Schedules = cSchedules::Schedules(SchedulesLock);
+ const cSchedule *Schedule = Schedules->GetSchedule(channel->GetChannelID());
+ if (Schedule)
+ Event = Schedule->GetPresentEvent();
+
if (sortMode == csmProvider)
- buffer = cString::sprintf("%d\t%s - %s", channel->Number(), channel->Provider(), channel->Name());
+ buffer = cString::sprintf("%d\t%s - %s %c%s%c", channel->Number(), channel->Provider(), channel->Name(),
+ Event ? '(' : ' ', Event ? Event->Title() : "", Event ? ')' : ' ');
else
- buffer = cString::sprintf("%d\t%s", channel->Number(), channel->Name());
+ buffer = cString::sprintf("%d\t%s %c%s%c", channel->Number(), channel->Name(),
+ Event ? '(' : ' ', Event ? Event->Title() : "", Event ? ')' : ' ');
}
else
buffer = cString::sprintf("---\t%s ----------------------------------------------------------------", channel->Name());

21
vdr-gcc11.patch Normal file
View file

@ -0,0 +1,21 @@
diff --git a/recording.c b/recording.c
index e493b57..e50ef7d 100644
--- a/recording.c
+++ b/recording.c
@@ -3025,7 +3025,15 @@ cUnbufferedFile *cFileName::SetOffset(int Number, off_t Offset)
}
// found a non existing file suffix
}
- if (Open() >= 0) {
+ /* This used to test Open() >= 0, but Open() returns a pointer
+ and we shouldn't be doing ordered comparisons of pointers
+ against constants. Furthermore, on some systems pointers
+ are unsigned meaning this test always succeeded.
+
+ Finally, AFAICT Open() is always going to return NULL or a
+ valid pointer and can never return a negative value based on my
+ reading of these sources. */
+ if (1) {
if (!record && Offset >= 0 && file && file->Seek(Offset, SEEK_SET) != Offset) {
LOG_ERROR_STR(fileName);
return NULL;

11
vdr-gcc7-fix.patch Normal file
View file

@ -0,0 +1,11 @@
--- a/osdbase.c.orig 2017-02-15 15:55:34.555128665 +0100
+++ b/osdbase.c 2017-02-15 15:56:30.898068614 +0100
@@ -510,7 +510,7 @@
const char *s = item->Text();
i = 0;
item_nr = 0;
- if (s && (s = skipspace(s)) != '\0' && '0' <= s[i] && s[i] <= '9') {
+ if (s && (s = skipspace(s)) != NULL && '0' <= s[i] && s[i] <= '9') {
do {
item_nr = item_nr * 10 + (s[i] - '0');
}

View file

@ -0,0 +1,306 @@
#! /bin/sh /usr/share/dpatch/dpatch-run
## opt-41-x_timer-info.dpatch by Andreas Brugger <brougs78@gmx.net>, Thomas Günther <tom@toms-cafe.de>
## http://toms-cafe.de/vdr/download/vdr-timer-info-0.5-1.7.13.diff
##
## All lines beginning with `## DP:' are a description of the patch.
## DP: Shows info, if it is possible to record an event in the timer-info of
## DP: vdr - see README.timer-info for details.
@DPATCH@
diff -Naurp vdr-1.7.13/README.timer-info vdr-1.7.13-timer-info-0.5/README.timer-info
--- vdr-1.7.13/README.timer-info 1970-01-01 00:00:00.000000000 +0000
+++ vdr-1.7.13-timer-info-0.5/README.timer-info 2010-02-28 18:26:31.000000000 +0000
@@ -0,0 +1,69 @@
++------------------------------------------------------------------------------+
+| Info about the timer-info-patch by Brougs78 |
+| brougs78@gmx.net / home.pages.at/brougs78 |
++------------------------------------------------------------------------------+
+
+
+README timer-info:
+------------------
+
+Features:
+ - Shows info, if it is possible to record an event in the timer menu of vdr.
+ For calculations the free space incl. the deleted recordings is used,
+ considering an average consumtion of 25.75 MB/min (also used by vdr itself).
+ The first column in the timer-list shows:
+ ( + ) recording will be most probably possible (enough space)
+ (+/-) recording may be possible
+ ( - ) recording will most probably fail (to less space)
+ The calculations also consider repeating timers.
+ - It is possible to deactivate the patch in the OSD-menu of VDR.
+
+
+HISTORY timer-info:
+-------------------
+
+25.11.2004: v0.1
+ - Initial release
+
+11.01.2005: v0.1b
+ - Bugfixes for vdr-1.3.18
+ - In the menu the free recording-time no longer includes the space of the
+ deleted recordings, because this slowed the vdr down to much.
+
+08.07.2005: v0.1c
+ - Made the patch configurable
+
+29.01.2006: v0.2 - Thomas Günther <tom@toms-cafe.de>
+ - Rewritten great parts for vdr-1.3.38+
+ http://toms-cafe.de/vdr/download/vdr-timer-info-0.2-1.3.38+.diff
+
+05.02.2006: v0.3 - Thomas Günther <tom@toms-cafe.de>
+ - Fixed refresh of timer menu in cMenuTimers::OnOff
+ - Fixed check of repeating timers
+ - Syslog debug messages can be enabled with Define DEBUG_TIMER_INFO
+ http://toms-cafe.de/vdr/download/vdr-timer-info-0.3-1.3.38+.diff
+
+03.03.2006: v0.4 - Thomas Günther <tom@toms-cafe.de>
+ - Adapted to vdr-1.3.44
+ - Removed setup parameter "Show timer-info"
+ http://toms-cafe.de/vdr/download/vdr-timer-info-0.4-1.3.44.diff
+
+26.03.2006: - Tobias Grimm <tg@e-tobi.net>
+ - Adapted to vdr-1.3.45
+ http://toms-cafe.de/vdr/download/vdr-timer-info-0.4-1.3.45.diff
+
+14.01.2008: - Thomas Günther <tom@toms-cafe.de>
+ - Adapted to vdr-1.5.13
+ http://toms-cafe.de/vdr/download/vdr-timer-info-0.4-1.5.13.diff
+
+17.02.2008: - Tobias Grimm <tg@e-tobi.net>
+ - Adapted to vdr-1.5.15
+ http://toms-cafe.de/vdr/download/vdr-timer-info-0.4-1.5.15.diff
+
+12.04.2008: v0.5 - Thomas Günther <tom@toms-cafe.de>
+ - Fixed display of +/- sign with UTF-8
+ http://toms-cafe.de/vdr/download/vdr-timer-info-0.5-1.5.15.diff
+
+28.02.2010: - Thomas Günther <tom@toms-cafe.de>
+ - Adapted to vdr-1.7.13
+ http://toms-cafe.de/vdr/download/vdr-timer-info-0.5-1.7.13.diff
diff -Naurp vdr-1.7.13/menu.c vdr-1.7.13-timer-info-0.5/menu.c
--- vdr-1.7.13/menu.c 2010-02-21 14:09:19.000000000 +0000
+++ vdr-1.7.13-timer-info-0.5/menu.c 2010-02-28 18:24:26.000000000 +0000
@@ -1010,8 +1010,10 @@ eOSState cMenuEditTimer::ProcessKey(eKey
class cMenuTimerItem : public cOsdItem {
private:
cTimer *timer;
+ char diskStatus;
public:
cMenuTimerItem(cTimer *Timer);
+ void SetDiskStatus(char DiskStatus);
virtual int Compare(const cListObject &ListObject) const;
virtual void Set(void);
cTimer *Timer(void) { return timer; }
@@ -1020,6 +1022,7 @@ public:
cMenuTimerItem::cMenuTimerItem(cTimer *Timer)
{
timer = Timer;
+ diskStatus = ' ';
Set();
}
@@ -1050,7 +1053,10 @@ void cMenuTimerItem::Set(void)
File++;
else
File = timer->File();
- SetText(cString::sprintf("%c\t%d\t%s%s%s\t%02d:%02d\t%02d:%02d\t%s",
+ cCharSetConv csc("ISO-8859-1", cCharSetConv::SystemCharacterTable());
+ char diskStatusString[2] = { diskStatus, 0 };
+ SetText(cString::sprintf("%s%c\t%d\t%s%s%s\t%02d:%02d\t%02d:%02d\t%s",
+ csc.Convert(diskStatusString),
!(timer->HasFlags(tfActive)) ? ' ' : timer->FirstDay() ? '!' : timer->Recording() ? '#' : '>',
timer->Channel()->Number(),
*name,
@@ -1063,6 +1069,57 @@ void cMenuTimerItem::Set(void)
File));
}
+void cMenuTimerItem::SetDiskStatus(char DiskStatus)
+{
+ diskStatus = DiskStatus;
+ Set();
+}
+
+// --- cTimerEntry -----------------------------------------------------------
+
+class cTimerEntry : public cListObject {
+private:
+ cMenuTimerItem *item;
+ const cTimer *timer;
+ time_t start;
+public:
+ cTimerEntry(cMenuTimerItem *item) : item(item), timer(item->Timer()), start(timer->StartTime()) {}
+ cTimerEntry(const cTimer *timer, time_t start) : item(NULL), timer(timer), start(start) {}
+ virtual int Compare(const cListObject &ListObject) const;
+ bool active(void) const { return timer->HasFlags(tfActive); }
+ time_t startTime(void) const { return start; }
+ int priority(void) const { return timer->Priority(); }
+ int duration(void) const;
+ bool repTimer(void) const { return !timer->IsSingleEvent(); }
+ bool isDummy(void) const { return item == NULL; }
+ const cTimer *Timer(void) const { return timer; }
+ void SetDiskStatus(char DiskStatus);
+ };
+
+int cTimerEntry::Compare(const cListObject &ListObject) const
+{
+ cTimerEntry *entry = (cTimerEntry *)&ListObject;
+ int r = startTime() - entry->startTime();
+ if (r == 0)
+ r = entry->priority() - priority();
+ return r;
+}
+
+int cTimerEntry::duration(void) const
+{
+ int dur = (timer->Stop() / 100 * 60 + timer->Stop() % 100) -
+ (timer->Start() / 100 * 60 + timer->Start() % 100);
+ if (dur < 0)
+ dur += 24 * 60;
+ return dur;
+}
+
+void cTimerEntry::SetDiskStatus(char DiskStatus)
+{
+ if (item)
+ item->SetDiskStatus(DiskStatus);
+}
+
// --- cMenuTimers -----------------------------------------------------------
class cMenuTimers : public cOsdMenu {
@@ -1075,14 +1132,17 @@ private:
eOSState Info(void);
cTimer *CurrentTimer(void);
void SetHelpKeys(void);
+ void ActualiseDiskStatus(void);
+ bool actualiseDiskStatus;
public:
cMenuTimers(void);
virtual ~cMenuTimers();
+ virtual void Display(void);
virtual eOSState ProcessKey(eKeys Key);
};
cMenuTimers::cMenuTimers(void)
-:cOsdMenu(tr("Timers"), 2, CHNUMWIDTH, 10, 6, 6)
+:cOsdMenu(tr("Timers"), 3, CHNUMWIDTH, 10, 6, 6)
{
helpKeys = -1;
for (cTimer *timer = Timers.First(); timer; timer = Timers.Next(timer)) {
@@ -1093,6 +1153,7 @@ cMenuTimers::cMenuTimers(void)
SetCurrent(First());
SetHelpKeys();
Timers.IncBeingEdited();
+ actualiseDiskStatus = true;
}
cMenuTimers::~cMenuTimers()
@@ -1131,7 +1192,7 @@ eOSState cMenuTimers::OnOff(void)
timer->OnOff();
timer->SetEventFromSchedule();
RefreshCurrent();
- DisplayCurrent(true);
+ Display();
if (timer->FirstDay())
isyslog("timer %s first day set to %s", *timer->ToDescr(), *timer->PrintFirstDay());
else
@@ -1190,6 +1251,67 @@ eOSState cMenuTimers::Info(void)
return osContinue;
}
+void cMenuTimers::ActualiseDiskStatus(void)
+{
+ if (!actualiseDiskStatus || !Count())
+ return;
+
+ // compute free disk space
+ int freeMB, freeMinutes, runshortMinutes;
+ VideoDiskSpace(&freeMB);
+ freeMinutes = int(double(freeMB) * 1.1 / MB_PER_MINUTE); // overestimate by 10 percent
+ runshortMinutes = freeMinutes / 5; // 20 Percent
+
+ // fill entries list
+ cTimerEntry *entry;
+ cList<cTimerEntry> entries;
+ for (cOsdItem *item = First(); item; item = Next(item))
+ entries.Add(new cTimerEntry((cMenuTimerItem *)item));
+
+ // search last start time
+ time_t last = 0;
+ for (entry = entries.First(); entry; entry = entries.Next(entry))
+ last = max(entry->startTime(), last);
+
+ // add entries for repeating timers
+ for (entry = entries.First(); entry; entry = entries.Next(entry))
+ if (entry->repTimer() && !entry->isDummy())
+ for (time_t start = cTimer::IncDay(entry->startTime(), 1);
+ start <= last;
+ start = cTimer::IncDay(start, 1))
+ if (entry->Timer()->DayMatches(start))
+ entries.Add(new cTimerEntry(entry->Timer(), start));
+
+ // set the disk-status
+ entries.Sort();
+ for (entry = entries.First(); entry; entry = entries.Next(entry)) {
+ char status = ' ';
+ if (entry->active()) {
+ freeMinutes -= entry->duration();
+ status = freeMinutes > runshortMinutes ? '+' : freeMinutes > 0 ? 177 /* +/- */ : '-';
+ }
+ entry->SetDiskStatus(status);
+#ifdef DEBUG_TIMER_INFO
+ dsyslog("timer-info: %c | %d | %s | %s | %3d | %+5d -> %+5d",
+ status,
+ entry->startTime(),
+ entry->active() ? "aktiv " : "n.akt.",
+ entry->repTimer() ? entry->isDummy() ? " dummy " : "mehrmalig" : "einmalig ",
+ entry->duration(),
+ entry->active() ? freeMinutes + entry->duration() : freeMinutes,
+ freeMinutes);
+#endif
+ }
+
+ actualiseDiskStatus = false;
+}
+
+void cMenuTimers::Display(void)
+{
+ ActualiseDiskStatus();
+ cOsdMenu::Display();
+}
+
eOSState cMenuTimers::ProcessKey(eKeys Key)
{
int TimerNumber = HasSubMenu() ? Count() : -1;
@@ -1198,18 +1320,22 @@ eOSState cMenuTimers::ProcessKey(eKeys K
if (state == osUnknown) {
switch (Key) {
case kOk: return Edit();
- case kRed: state = OnOff(); break; // must go through SetHelpKeys()!
+ case kRed: actualiseDiskStatus = true;
+ state = OnOff(); break; // must go through SetHelpKeys()!
case kGreen: return New();
- case kYellow: state = Delete(); break;
+ case kYellow: actualiseDiskStatus = true;
+ state = Delete(); break;
case kInfo:
case kBlue: return Info();
break;
default: break;
}
}
- if (TimerNumber >= 0 && !HasSubMenu() && Timers.Get(TimerNumber)) {
- // a newly created timer was confirmed with Ok
- Add(new cMenuTimerItem(Timers.Get(TimerNumber)), true);
+ if (TimerNumber >= 0 && !HasSubMenu()) {
+ if (Timers.Get(TimerNumber)) // a newly created timer was confirmed with Ok
+ Add(new cMenuTimerItem(Timers.Get(TimerNumber)), true);
+ Sort();
+ actualiseDiskStatus = true;
Display();
}
if (Key != kNone)

View file

@ -0,0 +1,15 @@
diff --git a/menu.c b/menu.c
index 14be0ed..9c6a0ff 100644
--- a/menu.c
+++ b/menu.c
@@ -1377,8 +1377,8 @@ void cMenuTimers::ActualiseDiskStatus(void)
// compute free disk space
int freeMB, freeMinutes, runshortMinutes;
- VideoDiskSpace(&freeMB);
- freeMinutes = int(double(freeMB) * 1.1 / MB_PER_MINUTE); // overestimate by 10 percent
+ cVideoDirectory::VideoDiskSpace(&freeMB);
+ freeMinutes = int(double(freeMB) * 1.1 / 25.75); // overestimate by 10 percent
runshortMinutes = freeMinutes / 5; // 20 Percent
// fill entries list

View file

@ -0,0 +1,110 @@
--- menu.c.orig 2009-04-11 14:47:08.000000000 +0200
+++ menu.c 2009-04-17 13:53:05.000000000 +0200
@@ -853,6 +853,7 @@ eOSState cMenuEditTimer::ProcessKey(eKey
class cMenuTimerItem : public cOsdItem {
private:
cTimer *timer;
+ void DoSet(void);
public:
cMenuTimerItem(cTimer *Timer);
virtual int Compare(const cListObject &ListObject) const;
@@ -863,7 +864,7 @@ public:
cMenuTimerItem::cMenuTimerItem(cTimer *Timer)
{
timer = Timer;
- Set();
+ DoSet();
}
int cMenuTimerItem::Compare(const cListObject &ListObject) const
@@ -873,6 +874,18 @@ int cMenuTimerItem::Compare(const cListO
void cMenuTimerItem::Set(void)
{
+ // check for deleted timer
+ for (cTimer *t = Timers.First(); ; t = Timers.Next(t)) {
+ if (t == timer)
+ break; // timer still there
+ if (t == NULL)
+ return; // no matching timer found
+ }
+ DoSet();
+}
+
+void cMenuTimerItem::DoSet(void)
+{
cString day, name("");
if (timer->WeekDays())
day = timer->PrintDay(0, timer->WeekDays(), false);
@@ -906,8 +919,7 @@ void cMenuTimerItem::Set(void)
class cMenuTimers : public cOsdMenu {
private:
int helpKeys;
- eOSState Edit(void);
- eOSState New(void);
+ eOSState Edit(bool New = false);
eOSState Delete(void);
eOSState OnOff(void);
eOSState Info(void);
@@ -980,19 +992,30 @@ eOSState cMenuTimers::OnOff(void)
return osContinue;
}
-eOSState cMenuTimers::Edit(void)
+eOSState cMenuTimers::Edit(bool New)
{
- if (HasSubMenu() || Count() == 0)
+ if (HasSubMenu() || (Count() == 0 && !New))
return osContinue;
- isyslog("editing timer %s", *CurrentTimer()->ToDescr());
- return AddSubMenu(new cMenuEditTimer(CurrentTimer()));
-}
+ if (!New)
+ isyslog("editing timer %s", *CurrentTimer()->ToDescr());
-eOSState cMenuTimers::New(void)
-{
- if (HasSubMenu())
- return osContinue;
- return AddSubMenu(new cMenuEditTimer(new cTimer, true));
+ // Data structure for service "Epgsearch-exttimeredit-v1.0"
+ struct Epgsearch_exttimeredit_v1_0
+ {
+ // in
+ cTimer* timer; // pointer to the timer to edit
+ bool bNew; // flag that indicates, if this is a new timer or an existing one
+ const cEvent* event; // pointer to the event corresponding to this timer (may be NULL)
+ // out
+ cOsdMenu* pTimerMenu; // pointer to the menu of results
+ } exttimeredit;
+ exttimeredit.timer = New ? (new cTimer) : CurrentTimer();
+ exttimeredit.bNew = New;
+ exttimeredit.event = exttimeredit.timer->Event();
+ if (cPluginManager::CallFirstService("Epgsearch-exttimeredit-v1.0", &exttimeredit))
+ return AddSubMenu(exttimeredit.pTimerMenu);
+
+ return AddSubMenu(new cMenuEditTimer(exttimeredit.timer, New));
}
eOSState cMenuTimers::Delete(void)
@@ -1038,7 +1061,7 @@ eOSState cMenuTimers::ProcessKey(eKeys K
switch (Key) {
case kOk: return Edit();
case kRed: state = OnOff(); break; // must go through SetHelpKeys()!
- case kGreen: return New();
+ case kGreen: return Edit(true);
case kYellow: state = Delete(); break;
case kInfo:
case kBlue: return Info();
@@ -1051,6 +1074,11 @@ eOSState cMenuTimers::ProcessKey(eKeys K
Add(new cMenuTimerItem(Timers.Get(TimerNumber)), true);
Display();
}
+ if (!HasSubMenu() && Timers.Count()<Count()) {
+ // timer was deleted
+ cOsdMenu::Del(Current());
+ Display();
+ }
if (Key != kNone)
SetHelpKeys();
return state;

136
vdr.spec
View file

@ -10,6 +10,7 @@
# - The dvbsddevice and rcu plugins are no longer part of the VDR source archive.
# You can get the latest versions of these plugins from ftp://ftp.tvdr.de/vdr/Plugins.
%undefine _package_note_flags
%{!?_pkgdocdir: %global _pkgdocdir %{_docdir}/%{name}-%{version}}
%global _hardened_build 1
%bcond_without docs
@ -24,17 +25,16 @@
%global vdr_user vdr
%global vdr_group video
# From APIVERSION in config.h
%global apiver 9
%global apiver 2.6.3
Name: vdr
Version: 2.7.7
Release: 1%{?dist}
Version: 2.6.4
Release: 2%{?dist}
Summary: Video Disk Recorder
License: GPL-2.0-or-later
License: GPLv2+
URL: http://www.tvdr.de/
# Get vdr source from http://git.tvdr.de/?p=vdr.git;a=snapshot;h=refs/tags/2.7.7;sf=tbz2
# wget --content-disposition "http://git.tvdr.de/?p=vdr.git;a=snapshot;h=refs/tags/2.7.7;sf=tbz2"
# Get vdr source from http://git.tvdr.de/?p=vdr.git;a=snapshot;h=refs/tags/2.6.4;sf=tbz2
Source0: %{name}-%{version}.tar.bz2
Source1: %{name}.service
Source2: %{name}.sysconfig
@ -56,7 +56,7 @@ Source18: http://cdn.debian.net/debian/pool/main/v/vdr/vdr_2.2.0-5.debian.
Source19: %{name}-check-setup.sh
Source20: %{name}-rcu.conf
Source21: %{name}-set-wakeup.sh
Source30: https://bitbucket.org/powARman/dvbhddevice/get/3473a7b939d7.zip
Source30: https://bitbucket.org/powARman/dvbhddevice/get/2ea854ae8c7a.zip
Source31: ftp://ftp.tvdr.de/vdr/Plugins/vdr-dvbsddevice-2.2.0.tgz
Source32: ftp://ftp.tvdr.de/vdr/Plugins/vdr-rcu-2.2.0.tgz
@ -67,11 +67,12 @@ Patch2: http://www.saunalahti.fi/~rahrenbe/vdr/patches/vdr-2.4.6-editrec
Patch3: %{name}-1.7.21-plugin-missing.patch
Patch4: %{name}-2.4.0-paths.patch
# http://vdrportal.de/board/thread.php?postid=343665#post343665
Patch5: 12_osdbase-maxitems.patch
# https://www.vdr-portal.de/forum/thread/135091-installation-eines-vdr-plugins-nativ-auf-coreelec-boxen/?postID=1379567#post1379567
Patch11: MainMenuHooks-v1_0_4.diff.txt
Patch15: %{name}-2.7.4-fedora-pkgconfig.patch
# https://www.vdr-portal.de/index.php?attachment/44831-vdr-2-4-6-clearobsoletechannels-diff
Patch7: 12_osdbase-maxitems.patch
# https://www.vdr-portal.de/index.php?attachment/46192-opt-42-x-mainmenuhooks-v1-0-3-patch/
Patch11: opt-42-x_MainMenuHooks-v1.0.3.patch
# Sent upstream 2016-06-17
Patch15: %{name}-1.7.37-fedora-pkgconfig.patch
# https://www.vdr-portal.de/index.php?attachment/44831-vdr-2-4-6-clearobsoletechannels-diff/
Patch99: %{name}-2.4.6-ClearObsoleteChannels2.diff
BuildRequires: make
@ -90,7 +91,7 @@ BuildRequires: systemd-devel
%if %{with docs}
BuildRequires: doxygen
BuildRequires: graphviz
%endif
%endif # docs
# udev >= 136-1 for the audio, cdrom, dialout, and video groups
Requires: udev >= 136-1
# sudo for the shutdown script, >= 1.7.2p2-3 for sudoers.d functionality
@ -98,6 +99,8 @@ Requires: sudo >= 1.7.2p2-3
# util-linux >= 2.15 for "rtcwake -m no" timer driven wakeups
Requires: util-linux >= 2.15
Requires: vdrsymbol-fonts
# shadow-utils >= 4.1.1 for useradd -N
Requires(pre): shadow-utils >= 2:4.1.1
# systemd >= 189 for RestartPreventExitStatus=
Requires(post,preun,postun): systemd >= 189
Provides: vdr(abi)%{?_isa} = %{apiver}
@ -112,7 +115,7 @@ is required to run VDR.
%package devel
Summary: Development files for VDR
Requires: gettext-runtime
Requires: gettext
Provides: vdr-devel(api) = %{apiver}
%description devel
@ -166,9 +169,9 @@ window, using only plain text output.
%setup -q -a 18
# dvbhddevice
unzip -o %{SOURCE30} -d $RPM_BUILD_DIR/vdr-%{version}/PLUGINS/src
mv $RPM_BUILD_DIR/vdr-%{version}/PLUGINS/src/powARman-dvbhddevice-3473a7b939d7 $RPM_BUILD_DIR/vdr-%{version}/PLUGINS/src/dvbhddevice
mv $RPM_BUILD_DIR/vdr-%{version}/PLUGINS/src/powARman-dvbhddevice-2ea854ae8c7a $RPM_BUILD_DIR/vdr-%{version}/PLUGINS/src/dvbhddevice
cd PLUGINS/src
%patch 0 -p3
%patch0 -p3
cd ../..
# dvbsddevice
tar -xzf %{SOURCE31} -C $RPM_BUILD_DIR/vdr-%{version}/PLUGINS/src
@ -177,14 +180,14 @@ mv $RPM_BUILD_DIR/vdr-%{version}/PLUGINS/src/dvbsddevice-2.2.0 $RPM_BUILD_DIR/vd
tar -xzf %{SOURCE32} -C $RPM_BUILD_DIR/vdr-%{version}/PLUGINS/src
mv $RPM_BUILD_DIR/vdr-%{version}/PLUGINS/src/rcu-2.2.0 $RPM_BUILD_DIR/vdr-%{version}/PLUGINS/src/rcu
%patch 1 -p1
%patch1 -p1
# sort_options would be nice, but it conflicts with channel+epg which is nicer
#patch -F 0 -i debian/patches/02_sort_options.dpatch
# TODO: does not apply since 1.7.24
#patch -F 0 -i debian/patches/06_recording_scan_speedup.dpatch
patch -F 2 -i debian/patches/07_blockify_define.dpatch
%patch 2 -p1
%patch 3 -p1
%patch2 -p1
%patch3 -p1
sed \
-e 's|__CACHEDIR__|%{cachedir}|' \
-e 's|__CONFIGDIR__|%{configdir}|' \
@ -192,10 +195,10 @@ sed \
-e 's|__VARDIR__|%{vardir}|' \
-e 's|__VIDEODIR__|%{videodir}|' \
%{PATCH4} | %{__patch} -p1
%patch 5 -p1
%patch 11 -p1
%patch 15 -p1
%patch 99 -p1
%patch7 -p1
%patch11 -p1
%patch15 -p1
%patch99 -p1
# Patch APIVERSION TO 2.4.8 to match VDRVERSION
# sed -i 's/2\.4\.3/2.4.8/' config.h
@ -232,14 +235,6 @@ for g in COLLABORATION INCLUDE INCLUDED_BY ; do
sed -i -e 's/^\(\s*'$g'_GRAPH\s*=\s*\).*/\1NO/' Doxyfile
done
# Create a sysusers.d config file
cat >vdr.sysusers.conf <<EOF
u vdr -:%{vdr_group} 'Video Disk Recorder' %{vardir} -
m vdr audio
m vdr cdrom
m vdr dialout
EOF
%build
cat << EOF > Make.config
CC = %{__cc}
@ -298,7 +293,7 @@ done
%if %{with docs}
%make_build srcdoc
%endif
%endif # docs
%install
@ -311,12 +306,7 @@ make install-bin install-dirs install-conf install-doc install-i18n \
install -pm 755 epg2html $RPM_BUILD_ROOT%{_bindir}
install -dm 755 $RPM_BUILD_ROOT%{_sbindir}
#mv $RPM_BUILD_ROOT%{_bindir}/vdr $RPM_BUILD_ROOT%{_sbindir}
# Avoid mv error by checking if source and destination are the same
if [ "$RPM_BUILD_ROOT%{_bindir}/vdr" != "$RPM_BUILD_ROOT%{_sbindir}/vdr" ]; then
mv $RPM_BUILD_ROOT%{_bindir}/vdr $RPM_BUILD_ROOT%{_sbindir}
fi
mv $RPM_BUILD_ROOT%{_bindir}/vdr $RPM_BUILD_ROOT%{_sbindir}
install -dm 755 $RPM_BUILD_ROOT%{configdir}/plugins
@ -438,8 +428,6 @@ install -pm 644 %{SOURCE11} \
$RPM_BUILD_ROOT%{_sysconfdir}/sysconfig/vdr-plugins.d/skincurses.conf
%find_lang %{name}-skincurses
install -m0644 -D vdr.sysusers.conf %{buildroot}%{_sysusersdir}/vdr.conf
%check
export PKG_CONFIG_PATH=$RPM_BUILD_ROOT%{_libdir}/pkgconfig
@ -448,6 +436,12 @@ if [ "$(pkg-config vdr --variable=apiversion)" != "%{apiver}" ] ; then
fi
%pre
# dialout for serial port remote controllers
getent passwd %{vdr_user} >/dev/null || \
useradd -r -g %{vdr_group} -d %{vardir} -s /sbin/nologin -M -N \
-G audio,cdrom,dialout -c "Video Disk Recorder" %{vdr_user} || :
%post
%systemd_post %{name}.service
systemctl daemon-reload
@ -499,14 +493,13 @@ systemctl daemon-reload
%dir %{vardir}/
%dir %{vardir}/themes/
%dir %{cachedir}/
%{_sysusersdir}/vdr.conf
%files devel -f %{name}-devel.files
%{!?_with_docs:%dir %{_pkgdocdir}}
%license COPYING
%if ! %{with docs}
%{_pkgdocdir}/PLUGINS.html
%endif
%endif # with docs
%{_bindir}/vdr-config
%{_bindir}/vdr-newplugin
%{_includedir}/libsi/
@ -552,65 +545,6 @@ systemctl daemon-reload
%changelog
* Fri Jul 25 2025 Martin Gansser <martinkg@fedoraproject.org> - 2.7.7-1
- Update to 2.7.7
* Fri Jul 25 2025 Fedora Release Engineering <releng@fedoraproject.org> - 2.7.6-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_43_Mass_Rebuild
* Sat Jun 21 2025 Martin Gansser <martinkg@fedoraproject.org> - 2.7.6-1
- Update to 2.7.6
* Tue May 27 2025 Martin Gansser <martinkg@fedoraproject.org> - 2.7.5-1
- Update to 2.7.5
- Add vdr-2.7.5-override-keyword.patch
* Sun May 11 2025 Peter Bieringer <pb@bieringer.de> - 2.7.4-3
- Re-add MainMenuHooks patch for 2.7.x
* Thu Apr 24 2025 Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl> - 2.7.4-2
- Add sysusers.d config file to allow rpm to create users/groups automatically
* Wed Feb 26 2025 Martin Gansser <martinkg@fedoraproject.org> - 2.7.4-1
- Update to 2.7.4
- Add vdr-2.7.4-fedora-pkgconfig.patch
* Fri Jan 24 2025 Martin Gansser <martinkg@fedoraproject.org> - 2.7.3-3
- Fix FTBFS #2341505
* Sun Jan 19 2025 Fedora Release Engineering <releng@fedoraproject.org> - 2.7.3-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_42_Mass_Rebuild
* Mon Oct 14 2024 Martin Gansser <martinkg@fedoraproject.org> - 2.7.3-1
- Update to 2.7.3
- Use recent dvbhddevice Source file 3473a7b939d7.zip
- Add %%{name}-2.7.3-remux-radio.patch
* Sat Jul 20 2024 Fedora Release Engineering <releng@fedoraproject.org> - 2.6.9-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_41_Mass_Rebuild
* Mon Jul 15 2024 Martin Gansser <martinkg@fedoraproject.org> - 2.6.9-1
- Update to 2.6.9
* Sun Jul 14 2024 Martin Gansser <martinkg@fedoraproject.org> - 2.6.8-2
- Add vdr-2.6.8-fix-timeout-open-frontend.diff.txt
- Add vdr-2.6.8-fix-pause-epg-scan.diff.txt
* Tue Jul 09 2024 Martin Gansser <martinkg@fedoraproject.org> - 2.6.8-1
- Update to 2.6.8
- Add strreplace.patch
* Tue Apr 02 2024 Martin Gansser <martinkg@fedoraproject.org> - 2.6.7-1
- Update to 2.6.7
* Fri Jan 26 2024 Martin Gansser <martinkg@fedoraproject.org> - 2.6.6-1
- Update to 2.6.6
* Wed Jan 03 2024 Martin Gansser <martinkg@fedoraproject.org> - 2.6.5-1
- Update to 2.6.5
- vdr-devel does not require any translation management tools (BZ#2119032)
use RR gettext-runtime
* Sat Jul 22 2023 Fedora Release Engineering <releng@fedoraproject.org> - 2.6.4-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_39_Mass_Rebuild