Compare commits

...
Sign in to create a new pull request.

4 commits

Author SHA1 Message Date
Martin Gansser
d12d91235d Merge branch 'rawhide' into f42 2025-05-11 15:05:53 +02:00
Peter Bieringer
6afb7dccf1 add current MainMenuHooks which got lost 2025-05-11 13:11:42 +02:00
Peter Bieringer
21947ffae1 add missing release in changelog 2025-05-11 13:10:43 +02:00
Martin Gansser
88a515bfa6 Add sysusers.d config file to allow rpm to create users/groups automatically 2025-04-25 09:49:06 +02:00
34 changed files with 0 additions and 4246 deletions

View file

@ -1,29 +0,0 @@
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

View file

@ -1,12 +0,0 @@
--- 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

@ -1,66 +0,0 @@
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,188 +0,0 @@
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
2012-04-06: Version 1.0.2
- Update für aktuelle VDR-Entwickler-Versionen (Manuel Reimer)
2010-10-15: Version 1.0.1
- return a cOsdObject instead of its subclass cOsdMenu (thanks to
Joe_D@vdrportal)
- version number defines in config.h now follow the ususal conventions:
MAINMENUHOOKSVERSNUM is now a number, the newly added define
MAINMENUHOOKSVERSION is a string (suggested by gnapheus@vdrportal)
- patch is now based on VDR 1.6.0
- updated documentation
2007-02-26: Version 1.0
- Initial revision.
* Authors:
Tobias Grimm <vdr at e-tobi dot net>
Martin Prochnow <nordlicht at martins-kabuff dot de>
Frank Schmirler <vdrdev at schmirler dot de>
Christian Wieninger <cwieninger at gmx dot de>
* Description:
This patch allows plugins to replace the VDR mainmenus "Schedule",
"Channels", "Timers" and "Recordings" by a different implementation.
The patch is based on a suggestion of Christian Wieninger back in 2006
(http://www.linuxtv.org/pipermail/vdr/2006-March/008234.html). It is
meant to be an interim solution for VDR 1.4 until (maybe) VDR 1.5
introduces an official API for this purpose.
* Installation
Change into the VDR source directory, then issue
patch -p1 < path/to/MainMenuHooks-v1_0_1.patch
and recompile.
* Notes for plugin authors
The following code sample shows the required plugin code for replacing
the original Schedule menu:
bool cMyPlugin::Service(const char *Id, void *Data)
{
cOsdMenu **menu = (cOsdMenu**) Data;
if (MySetup.replaceSchedule &&
strcmp(Id, "MainMenuHooksPatch-v1.0::osSchedule") == 0) {
if (menu)
*menu = (cOsdMenu*) MainMenuAction();
return true;
}
return false;
}
Since patch version 1.0.1 the service call may return a cOsdObject
instead of a cOsdMenu. Use "#ifdef MAINMENUHOOKSVERSION" to detect
version 1.0.1.
A plugin can replace more than one menu at a time. Simply replace the
call to MainMenuAction() in the sample above by appropriate code.
Note that a plugin *should* offer a setup option which allows the user
to enable or disable the replacement. "Disabled" would be a reasonable
default setting. By testing for define MAINMENUHOOKSVERSNUM, a plugin
can leave the setup option out at compiletime.
In case there is an internal problem when trying to open the replacement
menu, it is safe to return true even though Data is NULL. However an
OSD message should indicate the problem to the user.
Feel free to ship this patch along with your plugin. However if you
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.
Index: b/menu.c
===================================================================
--- a/menu.c
+++ b/menu.c
@@ -4620,15 +4620,31 @@
// 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, true);
+ 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)
@@ -4765,13 +4781,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)));
@@ -4857,6 +4894,12 @@
default: break;
}
}
+ if (menu) {
+ if (menu->IsMenu())
+ return AddSubMenu((cOsdMenu *) menu);
+ pluginOsdObject = menu;
+ return osPlugin;
+ }
if (!HasSubMenu() && Update(HadSubMenu))
Display();
if (Key != kNone) {
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

@ -1,21 +0,0 @@
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,106 +0,0 @@
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;

View file

@ -1,114 +0,0 @@
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()

View file

@ -1,107 +0,0 @@
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

@ -1,612 +0,0 @@
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,84 +0,0 @@
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

@ -1,109 +0,0 @@
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) {

View file

@ -1,621 +0,0 @@
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

File diff suppressed because it is too large Load diff

View file

@ -1,102 +0,0 @@
--- 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

@ -1,44 +0,0 @@
# 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

@ -1,108 +0,0 @@
--- 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) {

View file

@ -1,24 +0,0 @@
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

@ -1,115 +0,0 @@
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

@ -1,22 +0,0 @@
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

@ -1,62 +0,0 @@
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

@ -1,62 +0,0 @@
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);

View file

@ -1,26 +0,0 @@
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; }

Binary file not shown.

View file

@ -1,11 +0,0 @@
--- 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

@ -1,11 +0,0 @@
--- 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

View file

@ -1,31 +0,0 @@
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

@ -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;
}

View file

@ -1,10 +0,0 @@
--- remux.c 2024/10/08 08:46:38 5.14
+++ remux.c 2024/10/13 13:34:32
@@ -2274,6 +2274,7 @@
}
else // audio
framesPerSecond = double(PTSTICKS) / Delta; // PTS of audio frames is always increasing
+ frameChecker->SetFrameDelta(Delta);
dbgframes("\nDelta = %d FPS = %5.2f FPPU = %d NF = %d TRO = %d\n", Delta, framesPerSecond, framesPerPayloadUnit, numPtsValues + 1, parser->IFrameTemporalReferenceOffset());
synced = true;
parser->SetDebug(false);

View file

@ -1,26 +0,0 @@
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());

View file

@ -1,21 +0,0 @@
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;

View file

@ -1,11 +0,0 @@
--- 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

@ -1,306 +0,0 @@
#! /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

@ -1,15 +0,0 @@
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

@ -1,110 +0,0 @@
--- 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;