1 |
commit: 8fb604b710052829970783edc8de32804b2ad7ca |
2 |
Author: Martin Dummer <martin.dummer <AT> gmx <DOT> net> |
3 |
AuthorDate: Mon Jun 20 09:38:59 2022 +0000 |
4 |
Commit: Joonas Niilola <juippis <AT> gentoo <DOT> org> |
5 |
CommitDate: Sun Jul 3 08:57:54 2022 +0000 |
6 |
URL: https://gitweb.gentoo.org/repo/gentoo.git/commit/?id=8fb604b7 |
7 |
|
8 |
media-video/vdr: version bump to 2.6.1 |
9 |
|
10 |
- new stable release |
11 |
- rebase most patches for this version |
12 |
- retirement of http://projects.vdr-developer.org: move some SRC_URI |
13 |
to github.com/vdr-projects |
14 |
|
15 |
Package-Manager: Portage-3.0.30, Repoman-3.0.3 |
16 |
Signed-off-by: Martin Dummer <martin.dummer <AT> gmx.net> |
17 |
Closes: https://github.com/gentoo/gentoo/pull/26000 |
18 |
Signed-off-by: Joonas Niilola <juippis <AT> gentoo.org> |
19 |
|
20 |
media-video/vdr/Manifest | 2 + |
21 |
.../vdr/files/vdr-2.4.1_mainmenuhook-1.0.1.patch | 114 ++++ |
22 |
.../vdr/files/vdr-2.6.1-patch-for-permashift.patch | 517 ++++++++++++++++++ |
23 |
media-video/vdr/files/vdr-2.6.1_naludump.patch | 598 +++++++++++++++++++++ |
24 |
media-video/vdr/files/vdr-2.6.1_pinplugin.patch | 447 +++++++++++++++ |
25 |
media-video/vdr/vdr-2.6.1.ebuild | 197 +++++++ |
26 |
6 files changed, 1875 insertions(+) |
27 |
|
28 |
diff --git a/media-video/vdr/Manifest b/media-video/vdr/Manifest |
29 |
index 42d12f50673f..b4c6683d67bb 100644 |
30 |
--- a/media-video/vdr/Manifest |
31 |
+++ b/media-video/vdr/Manifest |
32 |
@@ -6,4 +6,6 @@ DIST vdr-2.4.1_mainmenuhook-1.0.1.patch.bz2 1463 BLAKE2B 2be3597a273a92d02be0d07 |
33 |
DIST vdr-2.4.6_pinplugin.patch.bz2 5176 BLAKE2B 142ad6551b8e37d223acf86f8c2f511cf2cb3664b5ff968bac5e44420c56bf5fdb974360df574141c424cd7a4b1e1489c4a504207420af10f722a77e6d2bad2f SHA512 d5c7263b908302ebf88a5e5ddcb658f56ee92656b40797fd48af1ff9852454adc1d1672cc97411e7744cc31a56f4d0f51df5ece102c21b2aa25d87e3c3c8fe12 |
34 |
DIST vdr-2.4.6_ttxtsubs_v2.patch.bz2 51971 BLAKE2B e4915314e8f659df1c3e0ff631fd0c3dcec89053ff727fd28400dc6eecc49c1d4743a9bedaf3b11fce03fc6082309d4b4658d00a5b01aa5cbe8686e05412f882 SHA512 14c7b4397ba65e0ff9a5fb0705872f1cb6f1cdd1752b14f83f260540da25b5957632900232f83904c3d4fd6759e537c85bda2cce61455729eab3050a96441548 |
35 |
DIST vdr-2.4.7.tbz2 919632 BLAKE2B be4e1ec365330855e4b2b26f44b1f35dc323e4783e96ef344a67b3e9fe2c0499760ab0f3d27c5e3bdddf5a65ebb65b0c81a62092301d34370aa19d0dd63bb1ab SHA512 41b8453bc6cdbb0db728b5d7d6624ab3ff9034b58ba443a8196f5fcc9fa78d18698cc91905890244e69d482ffc493374e6da2c97baed95fe742b888bdc63e42b |
36 |
+DIST vdr-2.6.1.tbz2 937103 BLAKE2B d8bbf8cb74f79c328ba7a367cd120d9472be667def851fbdff2f2fda3addbf33ae1f0ab0f20dc0ea6b3a03667e36164a5acf5a17cff8f7934c15f4e61b3a8db2 SHA512 235ffd1654d8f13ba658533bfa5db9c9669e93106a63a770297997f9b8342807f270f26e7a6f5a3c127cd9f760bb94ae77f884dcad42a500615c28e1cf3fd92f |
37 |
+DIST vdr-2.6.1_ttxtsubs_v2.patch 40549 BLAKE2B 525c05b72fa957372cc1ef91428428f664f42d92eebc06fd0b179afbe99e4ecc4919c69cef000cc15c8340c9a2506d38cbf755fd6665cde1708ce17d4320a35f SHA512 590c43e63818de8be9637cb3b32bf3399b82a181ca151d67e2341232669619020ab78ba9934da3a9c58cdb3bac56fc2a332a5838a92ee0851e42c3707726eb49 |
38 |
DIST vdr-menuorg-2.3.x.diff 8852 BLAKE2B 19b98d51a69f52ecda5500f51ef1741a8397953b20c490055eab0393da5f56ff9598c3e1e8ed8b915f5877e08deeb9ba7a9ef8d9356ad3a1fa12e3778869174a SHA512 7b41c3a529858a4953a57f21619ea01864e140cc1755ee0b03caf1c4de41e80c3f805653502bc8d39d02a4dfcddf720acd4a8c8bd91f4871eef31d86e8e915c0 |
39 |
|
40 |
diff --git a/media-video/vdr/files/vdr-2.4.1_mainmenuhook-1.0.1.patch b/media-video/vdr/files/vdr-2.4.1_mainmenuhook-1.0.1.patch |
41 |
new file mode 100644 |
42 |
index 000000000000..deec2cd7cfdb |
43 |
--- /dev/null |
44 |
+++ b/media-video/vdr/files/vdr-2.4.1_mainmenuhook-1.0.1.patch |
45 |
@@ -0,0 +1,114 @@ |
46 |
+original https://raw.githubusercontent.com/VDR4Arch/vdr4arch/master/vdr/vdr-MainMenuHooks.patch |
47 |
+ |
48 |
+rebased for media-video/vdr-2.4.1 |
49 |
+ |
50 |
+Signed-off-by: Joerg Bornkessel <hd_brummy@g.o> ( 2019 Dez 22 ) |
51 |
+diff -Naur vdr-2.4.1.orig/config.h vdr-2.4.1/config.h |
52 |
+--- vdr-2.4.1.orig/config.h 2019-12-22 00:04:59.000000000 +0100 |
53 |
++++ vdr-2.4.1/config.h 2019-12-22 00:11:25.000000000 +0100 |
54 |
+@@ -36,6 +36,10 @@ |
55 |
+ // plugins to work with newer versions of the core VDR as long as no |
56 |
+ // VDR header files have changed. |
57 |
+ |
58 |
++// The MainMenuHook Patch's version number: |
59 |
++#define MAINMENUHOOKSVERSION "1.0.1" |
60 |
++#define MAINMENUHOOKSVERSNUM 10001 // Version * 10000 + Major * 100 + Minor |
61 |
++ |
62 |
+ #define MAXPRIORITY 99 |
63 |
+ #define MINPRIORITY (-MAXPRIORITY) |
64 |
+ #define LIVEPRIORITY 0 // priority used when selecting a device for live viewing |
65 |
+diff -Naur vdr-2.4.1.orig/menu.c vdr-2.4.1/menu.c |
66 |
+--- vdr-2.4.1.orig/menu.c 2019-12-22 00:04:59.000000000 +0100 |
67 |
++++ vdr-2.4.1/menu.c 2019-12-22 00:11:25.000000000 +0100 |
68 |
+@@ -4395,15 +4395,31 @@ |
69 |
+ |
70 |
+ // Initial submenus: |
71 |
+ |
72 |
++ cOsdObject *menu = NULL; |
73 |
+ switch (State) { |
74 |
+- case osSchedule: AddSubMenu(new cMenuSchedule); break; |
75 |
+- case osChannels: AddSubMenu(new cMenuChannels); break; |
76 |
+- case osTimers: AddSubMenu(new cMenuTimers); break; |
77 |
+- case osRecordings: AddSubMenu(new cMenuRecordings(NULL, 0, OpenSubMenus)); break; |
78 |
+- case osSetup: AddSubMenu(new cMenuSetup); break; |
79 |
+- case osCommands: AddSubMenu(new cMenuCommands(tr("Commands"), &Commands)); break; |
80 |
++ case osSchedule: |
81 |
++ if (!cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osSchedule", &menu)) |
82 |
++ menu = new cMenuSchedule; |
83 |
++ break; |
84 |
++ case osChannels: |
85 |
++ if (!cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osChannels", &menu)) |
86 |
++ menu = new cMenuChannels; |
87 |
++ break; |
88 |
++ case osTimers: |
89 |
++ if (!cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osTimers", &menu)) |
90 |
++ menu = new cMenuTimers; |
91 |
++ break; |
92 |
++ case osRecordings: |
93 |
++ if (!cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osRecordings", &menu)) |
94 |
++ menu = new cMenuRecordings(NULL, 0, OpenSubMenus); |
95 |
++ break; |
96 |
++ case osSetup: menu = new cMenuSetup; break; |
97 |
++ case osCommands: menu = new cMenuCommands(tr("Commands"), &Commands); break; |
98 |
+ default: break; |
99 |
+ } |
100 |
++ if (menu) |
101 |
++ if (menu->IsMenu()) |
102 |
++ AddSubMenu((cOsdMenu *) menu); |
103 |
+ } |
104 |
+ |
105 |
+ cOsdObject *cMenuMain::PluginOsdObject(void) |
106 |
+@@ -4511,13 +4527,34 @@ |
107 |
+ eOSState state = cOsdMenu::ProcessKey(Key); |
108 |
+ HadSubMenu |= HasSubMenu(); |
109 |
+ |
110 |
++ cOsdObject *menu = NULL; |
111 |
+ switch (state) { |
112 |
+- case osSchedule: return AddSubMenu(new cMenuSchedule); |
113 |
+- case osChannels: return AddSubMenu(new cMenuChannels); |
114 |
+- case osTimers: return AddSubMenu(new cMenuTimers); |
115 |
+- case osRecordings: return AddSubMenu(new cMenuRecordings); |
116 |
+- case osSetup: return AddSubMenu(new cMenuSetup); |
117 |
+- case osCommands: return AddSubMenu(new cMenuCommands(tr("Commands"), &Commands)); |
118 |
++ case osSchedule: |
119 |
++ if (!cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osSchedule", &menu)) |
120 |
++ menu = new cMenuSchedule; |
121 |
++ else |
122 |
++ state = osContinue; |
123 |
++ break; |
124 |
++ case osChannels: |
125 |
++ if (!cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osChannels", &menu)) |
126 |
++ menu = new cMenuChannels; |
127 |
++ else |
128 |
++ state = osContinue; |
129 |
++ break; |
130 |
++ case osTimers: |
131 |
++ if (!cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osTimers", &menu)) |
132 |
++ menu = new cMenuTimers; |
133 |
++ else |
134 |
++ state = osContinue; |
135 |
++ break; |
136 |
++ case osRecordings: |
137 |
++ if (!cPluginManager::CallFirstService("MainMenuHooksPatch-v1.0::osRecordings", &menu)) |
138 |
++ menu = new cMenuRecordings; |
139 |
++ else |
140 |
++ state = osContinue; |
141 |
++ break; |
142 |
++ case osSetup: menu = new cMenuSetup; break; |
143 |
++ case osCommands: menu = new cMenuCommands(tr("Commands"), &Commands); break; |
144 |
+ case osStopRecord: if (Interface->Confirm(tr("Stop recording?"))) { |
145 |
+ if (cOsdItem *item = Get(Current())) { |
146 |
+ cRecordControls::Stop(item->Text() + strlen(tr(STOP_RECORDING))); |
147 |
+@@ -4568,6 +4605,12 @@ |
148 |
+ default: break; |
149 |
+ } |
150 |
+ } |
151 |
++ if (menu) { |
152 |
++ if (menu->IsMenu()) |
153 |
++ return AddSubMenu((cOsdMenu *) menu); |
154 |
++ pluginOsdObject = menu; |
155 |
++ return osPlugin; |
156 |
++ } |
157 |
+ if (!HasSubMenu() && Update(HadSubMenu)) |
158 |
+ Display(); |
159 |
+ if (Key != kNone) { |
160 |
|
161 |
diff --git a/media-video/vdr/files/vdr-2.6.1-patch-for-permashift.patch b/media-video/vdr/files/vdr-2.6.1-patch-for-permashift.patch |
162 |
new file mode 100644 |
163 |
index 000000000000..03b476f986bb |
164 |
--- /dev/null |
165 |
+++ b/media-video/vdr/files/vdr-2.6.1-patch-for-permashift.patch |
166 |
@@ -0,0 +1,517 @@ |
167 |
+Adapted Patch from forum post |
168 |
+https://www.vdr-portal.de/forum/index.php?thread/134171-permashift-1-0-4-f%C3%BCr-vdr-2-4-betaversion/&postID=1341243#post1341243 |
169 |
+ |
170 |
+SRC Url https://www.vdr-portal.de/index.php?attachment/45632-vdr-2-5-4-patch-for-permashift-diff-gz/ adapted for vdr-2.6.1 |
171 |
+ |
172 |
+Signed-off-by: Martin Dummer <martin.dummer@×××.net> |
173 |
+ |
174 |
+diff -Naur vdr-2.6.1.orig/device.c vdr-2.6.1/device.c |
175 |
+--- vdr-2.6.1.orig/device.c 2022-02-02 10:56:43.000000000 +0100 |
176 |
++++ vdr-2.6.1/device.c 2022-02-06 18:05:26.452890690 +0100 |
177 |
+@@ -1880,6 +1880,17 @@ |
178 |
+ ReleaseCamSlot(); |
179 |
+ } |
180 |
+ |
181 |
++cRecorder* cDevice::GetPreRecording(const cChannel *Channel) |
182 |
++{ |
183 |
++ cMutexLock MutexLock(&mutexReceiver); |
184 |
++ for (int i = 0; i < MAXRECEIVERS; i++) { |
185 |
++ if (receiver[i]) |
186 |
++ if (receiver[i]->IsPreRecording(Channel)) |
187 |
++ return (cRecorder*)receiver[i]; |
188 |
++ } |
189 |
++ return NULL; |
190 |
++} |
191 |
++ |
192 |
+ // --- cTSBuffer ------------------------------------------------------------- |
193 |
+ |
194 |
+ cTSBuffer::cTSBuffer(int File, int Size, int DeviceNumber) |
195 |
+diff -Naur vdr-2.6.1.orig/device.h vdr-2.6.1/device.h |
196 |
+--- vdr-2.6.1.orig/device.h 2022-02-02 10:56:43.000000000 +0100 |
197 |
++++ vdr-2.6.1/device.h 2022-02-06 18:05:51.541429884 +0100 |
198 |
+@@ -85,6 +85,7 @@ |
199 |
+ |
200 |
+ class cPlayer; |
201 |
+ class cReceiver; |
202 |
++class cRecorder; |
203 |
+ class cLiveSubtitle; |
204 |
+ |
205 |
+ class cDeviceHook : public cListObject { |
206 |
+@@ -854,6 +855,8 @@ |
207 |
+ ///< Returns true if we are currently receiving. The parameter has no meaning (for backwards compatibility only). |
208 |
+ bool AttachReceiver(cReceiver *Receiver); |
209 |
+ ///< Attaches the given receiver to this device. |
210 |
++ cRecorder* GetPreRecording(const cChannel *Channel); |
211 |
++ ///< Get precocious recording for the channel if there is one. |
212 |
+ void Detach(cReceiver *Receiver, bool ReleaseCam = true); |
213 |
+ ///< Detaches the given receiver from this device. |
214 |
+ ///< If ReleaseCam is true, the CAM slot will be released if it |
215 |
+diff -Naur vdr-2.6.1.orig/dvbplayer.c vdr-2.6.1/dvbplayer.c |
216 |
+--- vdr-2.6.1.orig/dvbplayer.c 2022-02-02 10:56:43.000000000 +0100 |
217 |
++++ vdr-2.6.1/dvbplayer.c 2022-02-06 18:05:26.452890690 +0100 |
218 |
+@@ -249,13 +249,14 @@ |
219 |
+ cUnbufferedFile *replayFile; |
220 |
+ double framesPerSecond; |
221 |
+ bool isPesRecording; |
222 |
+- bool pauseLive; |
223 |
++ ReplayState replayState; |
224 |
+ bool eof; |
225 |
+ bool firstPacket; |
226 |
+ ePlayModes playMode; |
227 |
+ ePlayDirs playDir; |
228 |
+ int trickSpeed; |
229 |
+ int readIndex; |
230 |
++ int startIndex; |
231 |
+ bool readIndependent; |
232 |
+ cFrame *readFrame; |
233 |
+ cFrame *playFrame; |
234 |
+@@ -271,6 +272,8 @@ |
235 |
+ virtual void Action(void); |
236 |
+ public: |
237 |
+ cDvbPlayer(const char *FileName, bool PauseLive); |
238 |
++ cDvbPlayer(const char *FileName, ReplayState newReplayState); |
239 |
++ void Construct(const char *FileName, ReplayState newReplayState); |
240 |
+ virtual ~cDvbPlayer(); |
241 |
+ void SetMarks(const cMarks *Marks); |
242 |
+ bool Active(void) { return cThread::Running(); } |
243 |
+@@ -297,6 +300,17 @@ |
244 |
+ cDvbPlayer::cDvbPlayer(const char *FileName, bool PauseLive) |
245 |
+ :cThread("dvbplayer") |
246 |
+ { |
247 |
++ Construct(FileName, PauseLive? restPauseLive : restNormal); |
248 |
++} |
249 |
++ |
250 |
++cDvbPlayer::cDvbPlayer(const char *FileName, ReplayState newReplayState) |
251 |
++:cThread("dvbplayer") |
252 |
++{ |
253 |
++ Construct(FileName, newReplayState); |
254 |
++} |
255 |
++ |
256 |
++void cDvbPlayer::Construct(const char *FileName, ReplayState newReplayState) |
257 |
++{ |
258 |
+ nonBlockingFileReader = NULL; |
259 |
+ ringBuffer = NULL; |
260 |
+ marks = NULL; |
261 |
+@@ -304,7 +318,8 @@ |
262 |
+ cRecording Recording(FileName); |
263 |
+ framesPerSecond = Recording.FramesPerSecond(); |
264 |
+ isPesRecording = Recording.IsPesRecording(); |
265 |
+- pauseLive = PauseLive; |
266 |
++ replayState = newReplayState; |
267 |
++ bool reuse = (replayState == restReusePause || replayState == restReuseRewind); |
268 |
+ eof = false; |
269 |
+ firstPacket = true; |
270 |
+ playMode = pmPlay; |
271 |
+@@ -323,15 +338,21 @@ |
272 |
+ return; |
273 |
+ ringBuffer = new cRingBufferFrame(PLAYERBUFSIZE); |
274 |
+ // Create the index file: |
275 |
+- index = new cIndexFile(FileName, false, isPesRecording, pauseLive); |
276 |
++ index = new cIndexFile(FileName, false, isPesRecording, replayState == restPauseLive); |
277 |
+ if (!index) |
278 |
+ esyslog("ERROR: can't allocate index"); |
279 |
+ else if (!index->Ok()) { |
280 |
+ delete index; |
281 |
+ index = NULL; |
282 |
+ } |
283 |
+- else if (PauseLive) |
284 |
++ else if (reuse) |
285 |
+ framesPerSecond = cRecording(FileName).FramesPerSecond(); // the fps rate might have changed from the default |
286 |
++ startIndex = 0; |
287 |
++ if (replayState == restReuseRewind || replayState == restReusePause) { |
288 |
++ int Current, Total; |
289 |
++ GetIndex(Current, Total, false); |
290 |
++ startIndex = max(Total - 1, 0); |
291 |
++ } |
292 |
+ } |
293 |
+ |
294 |
+ cDvbPlayer::~cDvbPlayer() |
295 |
+@@ -481,8 +502,21 @@ |
296 |
+ bool CutIn = false; |
297 |
+ bool AtLastMark = false; |
298 |
+ |
299 |
+- if (pauseLive) |
300 |
+- Goto(0, true); |
301 |
++ if (replayState == restPauseLive) { |
302 |
++ Goto(0, true); |
303 |
++ } |
304 |
++ else if (replayState == restReuseRewind || replayState == restReusePause) { |
305 |
++ readIndex = startIndex; |
306 |
++ Goto(readIndex, true); |
307 |
++ playMode = pmPlay; |
308 |
++ if (replayState == restReuseRewind) { |
309 |
++ Backward(); |
310 |
++ } |
311 |
++ else if (replayState == restReusePause) { |
312 |
++ Pause(); |
313 |
++ } |
314 |
++ } |
315 |
++ |
316 |
+ while (Running()) { |
317 |
+ if (WaitingForData) |
318 |
+ WaitingForData = !nonBlockingFileReader->WaitForDataMs(3); // this keeps the CPU load low, but reacts immediately on new data |
319 |
+@@ -985,6 +1019,11 @@ |
320 |
+ { |
321 |
+ } |
322 |
+ |
323 |
++cDvbPlayerControl::cDvbPlayerControl(const char *FileName, ReplayState replayState) |
324 |
++:cControl(player = new cDvbPlayer(FileName, replayState)) |
325 |
++{ |
326 |
++} |
327 |
++ |
328 |
+ cDvbPlayerControl::~cDvbPlayerControl() |
329 |
+ { |
330 |
+ Stop(); |
331 |
+diff -Naur vdr-2.6.1.orig/dvbplayer.h vdr-2.6.1/dvbplayer.h |
332 |
+--- vdr-2.6.1.orig/dvbplayer.h 2022-02-02 10:56:43.000000000 +0100 |
333 |
++++ vdr-2.6.1/dvbplayer.h 2022-02-06 18:05:26.452890690 +0100 |
334 |
+@@ -16,6 +16,14 @@ |
335 |
+ |
336 |
+ class cDvbPlayer; |
337 |
+ |
338 |
++enum ReplayState |
339 |
++{ |
340 |
++ restNormal, |
341 |
++ restPauseLive, |
342 |
++ restReusePause, |
343 |
++ restReuseRewind |
344 |
++}; |
345 |
++ |
346 |
+ class cDvbPlayerControl : public cControl { |
347 |
+ private: |
348 |
+ cDvbPlayer *player; |
349 |
+@@ -25,6 +33,8 @@ |
350 |
+ // If PauseLive is true, special care is taken to make sure the index |
351 |
+ // file of the recording is long enough to allow the player to display |
352 |
+ // the first frame in still picture mode. |
353 |
++ cDvbPlayerControl(const char *FileName, ReplayState replayState); |
354 |
++ // Sets up a player for the given file. replayState represents the initial state. |
355 |
+ virtual ~cDvbPlayerControl(); |
356 |
+ void SetMarks(const cMarks *Marks); |
357 |
+ bool Active(void); |
358 |
+diff -Naur vdr-2.6.1.orig/menu.c vdr-2.6.1/menu.c |
359 |
+--- vdr-2.6.1.orig/menu.c 2022-02-02 10:56:43.000000000 +0100 |
360 |
++++ vdr-2.6.1/menu.c 2022-02-06 18:05:26.452890690 +0100 |
361 |
+@@ -5303,6 +5303,16 @@ |
362 |
+ |
363 |
+ cRecordControl::cRecordControl(cDevice *Device, cTimers *Timers, cTimer *Timer, bool Pause) |
364 |
+ { |
365 |
++ Construct(Device, Timers, Timer, Pause, NULL); |
366 |
++} |
367 |
++ |
368 |
++cRecordControl::cRecordControl(cDevice *Device, cTimers *Timers, cTimer *Timer, bool Pause, bool* reused) |
369 |
++{ |
370 |
++ Construct(Device, Timers, Timer, Pause, reused); |
371 |
++} |
372 |
++ |
373 |
++void cRecordControl::Construct(cDevice *Device, cTimers *Timers, cTimer *Timer, bool Pause, bool* reused) |
374 |
++{ |
375 |
+ const char *LastReplayed = cReplayControl::LastReplayed(); // must do this before locking schedules! |
376 |
+ // Whatever happens here, the timers will be modified in some way... |
377 |
+ Timers->SetModified(); |
378 |
+@@ -5331,6 +5341,7 @@ |
379 |
+ timer->SetPending(true); |
380 |
+ timer->SetRecording(true); |
381 |
+ event = timer->Event(); |
382 |
++ if (reused != NULL) *reused = false; |
383 |
+ |
384 |
+ if (event || GetEvent()) |
385 |
+ dsyslog("Title: '%s' Subtitle: '%s'", event->Title(), event->ShortText()); |
386 |
+@@ -5360,8 +5371,21 @@ |
387 |
+ if (MakeDirs(fileName, true)) { |
388 |
+ Recording.WriteInfo(); // we write this *before* attaching the recorder to the device, to make sure the info file is present when the recorder needs to update the fps value! |
389 |
+ const cChannel *ch = timer->Channel(); |
390 |
+- recorder = new cRecorder(fileName, ch, timer->Priority()); |
391 |
+- if (device->AttachReceiver(recorder)) { |
392 |
++ |
393 |
++ if (!Timer) { |
394 |
++ recorder = device->GetPreRecording(ch); |
395 |
++ if (recorder != NULL) { |
396 |
++ recorder->ActivatePreRecording(fileName, timer->Priority()); |
397 |
++ if (reused != NULL) *reused = true; |
398 |
++ } |
399 |
++ } |
400 |
++ |
401 |
++ if (recorder == NULL) { |
402 |
++ recorder = new cRecorder(fileName, ch, timer->Priority()); |
403 |
++ if (!device->AttachReceiver(recorder)) DELETENULL(recorder); |
404 |
++ } |
405 |
++ |
406 |
++ if (recorder != NULL) { |
407 |
+ cStatus::MsgRecording(device, Recording.Name(), Recording.FileName(), true); |
408 |
+ if (!Timer && !LastReplayed) // an instant recording, maybe from cRecordControls::PauseLiveVideo() |
409 |
+ cReplayControl::SetRecording(fileName); |
410 |
+@@ -5371,8 +5395,6 @@ |
411 |
+ Recordings->AddByName(fileName); |
412 |
+ return; |
413 |
+ } |
414 |
+- else |
415 |
+- DELETENULL(recorder); |
416 |
+ } |
417 |
+ else |
418 |
+ timer->SetDeferred(DEFERTIMER); |
419 |
+@@ -5452,7 +5474,7 @@ |
420 |
+ cRecordControl *cRecordControls::RecordControls[MAXRECORDCONTROLS] = { NULL }; |
421 |
+ int cRecordControls::state = 0; |
422 |
+ |
423 |
+-bool cRecordControls::Start(cTimers *Timers, cTimer *Timer, bool Pause) |
424 |
++bool cRecordControls::Start(cTimers *Timers, cTimer *Timer, bool Pause, bool* reused) |
425 |
+ { |
426 |
+ static time_t LastNoDiskSpaceMessage = 0; |
427 |
+ int FreeMB = 0; |
428 |
+@@ -5490,7 +5512,7 @@ |
429 |
+ if (!Timer || Timer->Matches()) { |
430 |
+ for (int i = 0; i < MAXRECORDCONTROLS; i++) { |
431 |
+ if (!RecordControls[i]) { |
432 |
+- RecordControls[i] = new cRecordControl(device, Timers, Timer, Pause); |
433 |
++ RecordControls[i] = new cRecordControl(device, Timers, Timer, Pause, reused); |
434 |
+ return RecordControls[i]->Process(time(NULL)); |
435 |
+ } |
436 |
+ } |
437 |
+@@ -5514,6 +5536,11 @@ |
438 |
+ return Start(Timers, NULL, Pause); |
439 |
+ } |
440 |
+ |
441 |
++bool cRecordControls::Start(cTimers *Timers, cTimer *Timer, bool Pause) |
442 |
++{ |
443 |
++ return Start(Timers, Timer, Pause, NULL); |
444 |
++} |
445 |
++ |
446 |
+ void cRecordControls::Stop(const char *InstantId) |
447 |
+ { |
448 |
+ LOCK_TIMERS_WRITE; |
449 |
+@@ -5549,10 +5576,17 @@ |
450 |
+ |
451 |
+ bool cRecordControls::PauseLiveVideo(void) |
452 |
+ { |
453 |
++ return PauseLiveVideo(false); |
454 |
++} |
455 |
++ |
456 |
++bool cRecordControls::PauseLiveVideo(bool rewind) |
457 |
++{ |
458 |
+ Skins.Message(mtStatus, tr("Pausing live video...")); |
459 |
++ bool reused = false; |
460 |
+ cReplayControl::SetRecording(NULL); // make sure the new cRecordControl will set cReplayControl::LastReplayed() |
461 |
+- if (Start(true)) { |
462 |
+- cReplayControl *rc = new cReplayControl(true); |
463 |
++ LOCK_TIMERS_WRITE; |
464 |
++ if (Start(Timers, NULL, true, &reused)) { |
465 |
++ cReplayControl *rc = new cReplayControl(rewind? restReuseRewind : reused? restReusePause : restPauseLive); |
466 |
+ cControl::Launch(rc); |
467 |
+ cControl::Attach(); |
468 |
+ Skins.Message(mtStatus, NULL); |
469 |
+@@ -5695,7 +5729,18 @@ |
470 |
+ cReplayControl::cReplayControl(bool PauseLive) |
471 |
+ :cDvbPlayerControl(fileName, PauseLive) |
472 |
+ { |
473 |
+- cDevice::PrimaryDevice()->SetKeepTracks(PauseLive); |
474 |
++ Construct(PauseLive? restPauseLive : restNormal); |
475 |
++} |
476 |
++ |
477 |
++cReplayControl::cReplayControl(ReplayState replayState) |
478 |
++:cDvbPlayerControl(fileName, replayState) |
479 |
++{ |
480 |
++ Construct(replayState); |
481 |
++} |
482 |
++ |
483 |
++void cReplayControl::Construct(ReplayState replayState) |
484 |
++{ |
485 |
++ cDevice::PrimaryDevice()->SetKeepTracks(replayState == restPauseLive); |
486 |
+ currentReplayControl = this; |
487 |
+ displayReplay = NULL; |
488 |
+ marksModified = false; |
489 |
+diff -Naur vdr-2.6.1.orig/menu.h vdr-2.6.1/menu.h |
490 |
+--- vdr-2.6.1.orig/menu.h 2022-02-02 10:56:43.000000000 +0100 |
491 |
++++ vdr-2.6.1/menu.h 2022-02-06 18:05:26.452890690 +0100 |
492 |
+@@ -246,6 +246,8 @@ |
493 |
+ bool GetEvent(void); |
494 |
+ public: |
495 |
+ cRecordControl(cDevice *Device, cTimers *Timers, cTimer *Timer = NULL, bool Pause = false); |
496 |
++ cRecordControl(cDevice *Device, cTimers *Timers, cTimer *Timer, bool Pause, bool* reused); |
497 |
++ void Construct(cDevice *Device, cTimers *Timers, cTimer *Timer, bool Pause, bool* reused); |
498 |
+ virtual ~cRecordControl(); |
499 |
+ bool Process(time_t t); |
500 |
+ cDevice *Device(void) { return device; } |
501 |
+@@ -261,10 +263,12 @@ |
502 |
+ static int state; |
503 |
+ public: |
504 |
+ static bool Start(cTimers *Timers, cTimer *Timer, bool Pause = false); |
505 |
++ static bool Start(cTimers *Timers, cTimer *Timer, bool Pause, bool* reused); |
506 |
+ static bool Start(bool Pause = false); |
507 |
+ static void Stop(const char *InstantId); |
508 |
+ static void Stop(cTimer *Timer); |
509 |
+ static bool PauseLiveVideo(void); |
510 |
++ static bool PauseLiveVideo(bool rewind); |
511 |
+ static const char *GetInstantId(const char *LastInstantId); |
512 |
+ static cRecordControl *GetRecordControl(const char *FileName); |
513 |
+ static cRecordControl *GetRecordControl(const cTimer *Timer); |
514 |
+@@ -320,6 +324,8 @@ |
515 |
+ void EditTest(void); |
516 |
+ public: |
517 |
+ cReplayControl(bool PauseLive = false); |
518 |
++ cReplayControl(ReplayState replayState); |
519 |
++ void Construct(ReplayState replayState); |
520 |
+ virtual ~cReplayControl(); |
521 |
+ void Stop(void); |
522 |
+ virtual cOsdObject *GetInfo(void); |
523 |
+diff -Naur vdr-2.6.1.orig/receiver.h vdr-2.6.1/receiver.h |
524 |
+--- vdr-2.6.1.orig/receiver.h 2022-02-02 10:56:43.000000000 +0100 |
525 |
++++ vdr-2.6.1/receiver.h 2022-02-06 18:05:26.452890690 +0100 |
526 |
+@@ -85,6 +85,10 @@ |
527 |
+ ///< case the device is needed otherwise, so code that uses a cReceiver |
528 |
+ ///< should repeatedly check whether it is still attached, and if |
529 |
+ ///< it isn't, delete it (or take any other appropriate measures). |
530 |
++ virtual bool IsPreRecording(const cChannel *Channel) { return false; } |
531 |
++ ///< prerecords given channel; may be turned into a disc recording. |
532 |
++ virtual bool ActivatePreRecording(const char* fileName, int Priority) { return false; } |
533 |
++ ///< turn prerecording into a disc recording |
534 |
+ }; |
535 |
+ |
536 |
+ #endif //__RECEIVER_H |
537 |
+diff -Naur vdr-2.6.1.orig/recorder.c vdr-2.6.1/recorder.c |
538 |
+--- vdr-2.6.1.orig/recorder.c 2022-02-02 10:56:43.000000000 +0100 |
539 |
++++ vdr-2.6.1/recorder.c 2022-02-06 18:05:26.452890690 +0100 |
540 |
+@@ -164,11 +164,25 @@ |
541 |
+ cRecorder::cRecorder(const char *FileName, const cChannel *Channel, int Priority) |
542 |
+ :cReceiver(Channel, Priority) |
543 |
+ ,cThread("recording") |
544 |
++,tsChecker(NULL), frameChecker(NULL), recordingInfo(NULL), ringBuffer(NULL), frameDetector(NULL), fileName(NULL), index(NULL), recordFile(NULL), recordingName(NULL) |
545 |
+ { |
546 |
+- tsChecker = new cTsChecker; |
547 |
+- frameChecker = new cFrameChecker; |
548 |
++ if (FileName != NULL) { |
549 |
++ InitializeFile(FileName, Channel); |
550 |
++ } |
551 |
++} |
552 |
++ |
553 |
++void cRecorder::InitializeFile(const char *FileName, const cChannel *Channel) |
554 |
++{ |
555 |
++ if (tsChecker == NULL) { |
556 |
++ tsChecker = new cTsChecker; |
557 |
++ } |
558 |
++ if (frameChecker == NULL) { |
559 |
++ frameChecker = new cFrameChecker; |
560 |
++ } |
561 |
+ recordingName = strdup(FileName); |
562 |
+- recordingInfo = new cRecordingInfo(recordingName); |
563 |
++ if (recordingInfo == NULL) { |
564 |
++ recordingInfo = new cRecordingInfo(recordingName); |
565 |
++ } |
566 |
+ recordingInfo->Read(); |
567 |
+ oldErrors = max(0, recordingInfo->Errors()); // in case this is a re-started recording |
568 |
+ errors = oldErrors; |
569 |
+@@ -193,7 +207,9 @@ |
570 |
+ Pid = Channel->Dpid(0); |
571 |
+ Type = 0x06; |
572 |
+ } |
573 |
+- frameDetector = new cFrameDetector(Pid, Type); |
574 |
++ if (frameDetector == NULL) { |
575 |
++ frameDetector = new cFrameDetector(Pid, Type); |
576 |
++ } |
577 |
+ index = NULL; |
578 |
+ fileSize = 0; |
579 |
+ lastDiskSpaceCheck = time(NULL); |
580 |
+diff -Naur vdr-2.6.1.orig/recorder.h vdr-2.6.1/recorder.h |
581 |
+--- vdr-2.6.1.orig/recorder.h 2022-02-02 10:56:43.000000000 +0100 |
582 |
++++ vdr-2.6.1/recorder.h 2022-02-06 18:05:26.452890690 +0100 |
583 |
+@@ -19,8 +19,8 @@ |
584 |
+ class cTsChecker; |
585 |
+ class cFrameChecker; |
586 |
+ |
587 |
+-class cRecorder : public cReceiver, cThread { |
588 |
+-private: |
589 |
++class cRecorder : public cReceiver, protected cThread { |
590 |
++protected: |
591 |
+ cTsChecker *tsChecker; |
592 |
+ cFrameChecker *frameChecker; |
593 |
+ cRingBufferLinear *ringBuffer; |
594 |
+@@ -41,7 +41,6 @@ |
595 |
+ bool RunningLowOnDiskSpace(void); |
596 |
+ bool NextFile(void); |
597 |
+ void HandleErrors(bool Force = false); |
598 |
+-protected: |
599 |
+ virtual void Activate(bool On); |
600 |
+ ///< If you override Activate() you need to call Detach() (which is a |
601 |
+ ///< member of the cReceiver class) from your own destructor in order |
602 |
+@@ -49,6 +48,9 @@ |
603 |
+ ///< destroyed. |
604 |
+ virtual void Receive(const uchar *Data, int Length); |
605 |
+ virtual void Action(void); |
606 |
++ void InitializeFile(const char *FileName, const cChannel *Channel); |
607 |
++ ///< Starts recording to file. |
608 |
++ ///< Called in constructor if file name has been given. |
609 |
+ public: |
610 |
+ cRecorder(const char *FileName, const cChannel *Channel, int Priority); |
611 |
+ ///< Creates a new recorder for the given Channel and |
612 |
+diff -Naur vdr-2.6.1.orig/ringbuffer.c vdr-2.6.1/ringbuffer.c |
613 |
+--- vdr-2.6.1.orig/ringbuffer.c 2022-02-02 10:56:43.000000000 +0100 |
614 |
++++ vdr-2.6.1/ringbuffer.c 2022-02-06 18:05:26.452890690 +0100 |
615 |
+@@ -368,6 +368,25 @@ |
616 |
+ return NULL; |
617 |
+ } |
618 |
+ |
619 |
++uchar *cRingBufferLinear::GetRest(int &Count) |
620 |
++{ |
621 |
++ int Head = head; |
622 |
++ if (getThreadTid <= 0) |
623 |
++ getThreadTid = cThread::ThreadId(); |
624 |
++ int rest = Size() - tail; |
625 |
++ int diff = Head - tail; |
626 |
++ int cont = (diff >= 0) ? diff : Size() + diff - margin; |
627 |
++ if (cont > rest) |
628 |
++ cont = rest; |
629 |
++ uchar *p = buffer + tail; |
630 |
++ if (cont > 0) { |
631 |
++ Count = gotten = cont; |
632 |
++ return p; |
633 |
++ } |
634 |
++ WaitForGet(); |
635 |
++ return NULL; |
636 |
++} |
637 |
++ |
638 |
+ void cRingBufferLinear::Del(int Count) |
639 |
+ { |
640 |
+ if (Count > gotten) { |
641 |
+diff -Naur vdr-2.6.1.orig/ringbuffer.h vdr-2.6.1/ringbuffer.h |
642 |
+--- vdr-2.6.1.orig/ringbuffer.h 2022-02-02 10:56:43.000000000 +0100 |
643 |
++++ vdr-2.6.1/ringbuffer.h 2022-02-06 18:05:26.452890690 +0100 |
644 |
+@@ -98,6 +98,12 @@ |
645 |
+ ///< The data will remain in the buffer until a call to Del() deletes it. |
646 |
+ ///< Returns a pointer to the data, and stores the number of bytes |
647 |
+ ///< actually available in Count. If the returned pointer is NULL, Count has no meaning. |
648 |
++ uchar *GetRest(int &Count); |
649 |
++ ///< Gets data from the ring buffer disregarding the margin. |
650 |
++ ///< Might have to be called several times to get all data. |
651 |
++ ///< The data will remain in the buffer until a call to Del() deletes it. |
652 |
++ ///< Returns a pointer to the data, and stores the number of bytes |
653 |
++ ///< actually available in Count. If the returned pointer is NULL, Count has no meaning. |
654 |
+ void Del(int Count); |
655 |
+ ///< Deletes at most Count bytes from the ring buffer. |
656 |
+ ///< Count must be less or equal to the number that was returned by a previous |
657 |
+diff -Naur vdr-2.6.1.orig/vdr.c vdr-2.6.1/vdr.c |
658 |
+--- vdr-2.6.1.orig/vdr.c 2022-02-02 10:56:43.000000000 +0100 |
659 |
++++ vdr-2.6.1/vdr.c 2022-02-06 18:05:26.452890690 +0100 |
660 |
+@@ -1352,13 +1352,22 @@ |
661 |
+ key = kNone; |
662 |
+ break; |
663 |
+ // Pausing live video: |
664 |
++ case kFastRew: |
665 |
++ { |
666 |
++ // test if there's a live buffer to rewind into... |
667 |
++ LOCK_CHANNELS_READ; |
668 |
++ if (cDevice::ActualDevice()->GetPreRecording(Channels->GetByNumber(cDevice::CurrentChannel())) == NULL) { |
669 |
++ break; |
670 |
++ } |
671 |
++ } |
672 |
++ // fall through to pause |
673 |
+ case kPlayPause: |
674 |
+ case kPause: |
675 |
+ if (!Control) { |
676 |
+ DELETE_MENU; |
677 |
+ if (Setup.PauseKeyHandling) { |
678 |
+ if (Setup.PauseKeyHandling > 1 || Interface->Confirm(tr("Pause live video?"))) { |
679 |
+- if (!cRecordControls::PauseLiveVideo()) |
680 |
++ if (!cRecordControls::PauseLiveVideo(int(key) == kFastRew)) |
681 |
+ Skins.QueueMessage(mtError, tr("No free DVB device to record!")); |
682 |
+ } |
683 |
+ } |
684 |
|
685 |
diff --git a/media-video/vdr/files/vdr-2.6.1_naludump.patch b/media-video/vdr/files/vdr-2.6.1_naludump.patch |
686 |
new file mode 100644 |
687 |
index 000000000000..efea3a1d74f7 |
688 |
--- /dev/null |
689 |
+++ b/media-video/vdr/files/vdr-2.6.1_naludump.patch |
690 |
@@ -0,0 +1,598 @@ |
691 |
+diff -a -U 2 -r a/config.c b/config.c |
692 |
+--- a/config.c |
693 |
++++ b/config.c |
694 |
+@@ -469,4 +469,5 @@ |
695 |
+ SplitEditedFiles = 0; |
696 |
+ DelTimeshiftRec = 0; |
697 |
++ DumpNaluFill = 0; |
698 |
+ MinEventTimeout = 30; |
699 |
+ MinUserInactivity = 300; |
700 |
+@@ -697,4 +698,5 @@ |
701 |
+ else if (!strcasecmp(Name, "SplitEditedFiles")) SplitEditedFiles = atoi(Value); |
702 |
+ else if (!strcasecmp(Name, "DelTimeshiftRec")) DelTimeshiftRec = atoi(Value); |
703 |
++ else if (!strcasecmp(Name, "DumpNaluFill")) DumpNaluFill = atoi(Value); |
704 |
+ else if (!strcasecmp(Name, "MinEventTimeout")) MinEventTimeout = atoi(Value); |
705 |
+ else if (!strcasecmp(Name, "MinUserInactivity")) MinUserInactivity = atoi(Value); |
706 |
+@@ -829,4 +831,5 @@ |
707 |
+ Store("SplitEditedFiles", SplitEditedFiles); |
708 |
+ Store("DelTimeshiftRec", DelTimeshiftRec); |
709 |
++ Store("DumpNaluFill", DumpNaluFill); |
710 |
+ Store("MinEventTimeout", MinEventTimeout); |
711 |
+ Store("MinUserInactivity", MinUserInactivity); |
712 |
+diff -a -U 2 -r a/config.h b/config.h |
713 |
+--- a/config.h |
714 |
++++ b/config.h |
715 |
+@@ -341,4 +341,5 @@ |
716 |
+ int SplitEditedFiles; |
717 |
+ int DelTimeshiftRec; |
718 |
++ int DumpNaluFill; |
719 |
+ int MinEventTimeout, MinUserInactivity; |
720 |
+ time_t NextWakeupTime; |
721 |
+diff -a -U 2 -r a/menu.c b/menu.c |
722 |
+--- a/menu.c |
723 |
++++ b/menu.c |
724 |
+@@ -4185,4 +4185,5 @@ |
725 |
+ Add(new cMenuEditBoolItem(tr("Setup.Recording$Split edited files"), &data.SplitEditedFiles)); |
726 |
+ Add(new cMenuEditStraItem(tr("Setup.Recording$Delete timeshift recording"),&data.DelTimeshiftRec, 3, delTimeshiftRecTexts)); |
727 |
++ Add(new cMenuEditBoolItem(tr("Setup.Recording$Dump NALU Fill data"), &data.DumpNaluFill)); |
728 |
+ } |
729 |
+ |
730 |
+diff -a -U 2 -r a/recorder.c b/recorder.c |
731 |
+--- a/recorder.c |
732 |
++++ b/recorder.c |
733 |
+@@ -195,4 +195,12 @@ |
734 |
+ } |
735 |
+ frameDetector = new cFrameDetector(Pid, Type); |
736 |
++ if ( Type == 0x1B // MPEG4 video |
737 |
++ && (Setup.DumpNaluFill ? (strstr(FileName, "NALUKEEP") == NULL) : (strstr(FileName, "NALUDUMP") != NULL))) { // MPEG4 |
738 |
++ isyslog("Starting NALU fill dumper"); |
739 |
++ naluStreamProcessor = new cNaluStreamProcessor(); |
740 |
++ naluStreamProcessor->SetPid(Pid); |
741 |
++ } |
742 |
++ else |
743 |
++ naluStreamProcessor = NULL; |
744 |
+ index = NULL; |
745 |
+ fileSize = 0; |
746 |
+@@ -217,4 +225,10 @@ |
747 |
+ { |
748 |
+ Detach(); |
749 |
++ if (naluStreamProcessor) { |
750 |
++ long long int TotalPackets = naluStreamProcessor->GetTotalPackets(); |
751 |
++ long long int DroppedPackets = naluStreamProcessor->GetDroppedPackets(); |
752 |
++ isyslog("NALU fill dumper: %lld of %lld packets dropped, %lli%%", DroppedPackets, TotalPackets, TotalPackets ? DroppedPackets*100/TotalPackets : 0); |
753 |
++ delete naluStreamProcessor; |
754 |
++ } |
755 |
+ delete index; |
756 |
+ delete fileName; |
757 |
+@@ -357,10 +371,32 @@ |
758 |
+ t.Set(MAXBROKENTIMEOUT); |
759 |
+ } |
760 |
+- if (recordFile->Write(b, Count) < 0) { |
761 |
+- LOG_ERROR_STR(fileName->Name()); |
762 |
+- break; |
763 |
++ if (naluStreamProcessor) { |
764 |
++ naluStreamProcessor->PutBuffer(b, Count); |
765 |
++ bool Fail = false; |
766 |
++ while (true) { |
767 |
++ int OutLength = 0; |
768 |
++ uchar *OutData = naluStreamProcessor->GetBuffer(OutLength); |
769 |
++ if (!OutData || OutLength <= 0) |
770 |
++ break; |
771 |
++ if (recordFile->Write(OutData, OutLength) < 0) { |
772 |
++ LOG_ERROR_STR(fileName->Name()); |
773 |
++ Fail = true; |
774 |
++ break; |
775 |
++ } |
776 |
++ HandleErrors(); |
777 |
++ fileSize += OutLength; |
778 |
++ } |
779 |
++ if (Fail) |
780 |
++ break; |
781 |
++ } |
782 |
++ else { |
783 |
++ if (recordFile->Write(b, Count) < 0) { |
784 |
++ LOG_ERROR_STR(fileName->Name()); |
785 |
++ break; |
786 |
++ } |
787 |
++ HandleErrors(); |
788 |
++ fileSize += Count; |
789 |
+ } |
790 |
+- HandleErrors(); |
791 |
+- fileSize += Count; |
792 |
++ |
793 |
+ } |
794 |
+ } |
795 |
+diff -a -U 2 -r a/recorder.h b/recorder.h |
796 |
+--- a/recorder.h |
797 |
++++ b/recorder.h C2022-01-08 17:51:00.397595525 +0100 |
798 |
+@@ -27,4 +27,5 @@ |
799 |
+ cFrameDetector *frameDetector; |
800 |
+ cPatPmtGenerator patPmtGenerator; |
801 |
++ cNaluStreamProcessor *naluStreamProcessor; |
802 |
+ cFileName *fileName; |
803 |
+ cRecordingInfo *recordingInfo; |
804 |
+diff -a -U 2 -r a/remux.c b/remux.c |
805 |
+--- a/remux.c |
806 |
++++ b/remux.c |
807 |
+@@ -357,4 +357,40 @@ |
808 |
+ } |
809 |
+ |
810 |
++void TsExtendAdaptionField(unsigned char *Packet, int ToLength) |
811 |
++{ |
812 |
++ // Hint: ExtenAdaptionField(p, TsPayloadOffset(p) - 4) is a null operation |
813 |
++ |
814 |
++ int Offset = TsPayloadOffset(Packet); // First byte after existing adaption field |
815 |
++ |
816 |
++ if (ToLength <= 0) |
817 |
++ { |
818 |
++ // Remove adaption field |
819 |
++ Packet[3] = Packet[3] & ~TS_ADAPT_FIELD_EXISTS; |
820 |
++ return; |
821 |
++ } |
822 |
++ |
823 |
++ // Set adaption field present |
824 |
++ Packet[3] = Packet[3] | TS_ADAPT_FIELD_EXISTS; |
825 |
++ |
826 |
++ // Set new length of adaption field: |
827 |
++ Packet[4] = ToLength <= TS_SIZE-4 ? ToLength-1 : TS_SIZE-4-1; |
828 |
++ |
829 |
++ if (Packet[4] == TS_SIZE-4-1) |
830 |
++ { |
831 |
++ // No more payload, remove payload flag |
832 |
++ Packet[3] = Packet[3] & ~TS_PAYLOAD_EXISTS; |
833 |
++ } |
834 |
++ |
835 |
++ int NewPayload = TsPayloadOffset(Packet); // First byte after new adaption field |
836 |
++ |
837 |
++ // Fill new adaption field |
838 |
++ if (Offset == 4 && Offset < NewPayload) |
839 |
++ Offset++; // skip adaptation_field_length |
840 |
++ if (Offset == 5 && Offset < NewPayload) |
841 |
++ Packet[Offset++] = 0; // various flags set to 0 |
842 |
++ while (Offset < NewPayload) |
843 |
++ Packet[Offset++] = 0xff; // stuffing byte |
844 |
++} |
845 |
++ |
846 |
+ // --- cPatPmtGenerator ------------------------------------------------------ |
847 |
+ |
848 |
+@@ -1765,2 +1801,343 @@ |
849 |
+ return Processed; |
850 |
+ } |
851 |
++ |
852 |
++// --- cNaluDumper --------------------------------------------------------- |
853 |
++ |
854 |
++cNaluDumper::cNaluDumper() |
855 |
++{ |
856 |
++ LastContinuityOutput = -1; |
857 |
++ reset(); |
858 |
++} |
859 |
++ |
860 |
++void cNaluDumper::reset() |
861 |
++{ |
862 |
++ LastContinuityInput = -1; |
863 |
++ ContinuityOffset = 0; |
864 |
++ PesId = -1; |
865 |
++ PesOffset = 0; |
866 |
++ NaluFillState = NALU_NONE; |
867 |
++ NaluOffset = 0; |
868 |
++ History = 0xffffffff; |
869 |
++ DropAllPayload = false; |
870 |
++} |
871 |
++ |
872 |
++void cNaluDumper::ProcessPayload(unsigned char *Payload, int size, bool PayloadStart, sPayloadInfo &Info) |
873 |
++{ |
874 |
++ Info.DropPayloadStartBytes = 0; |
875 |
++ Info.DropPayloadEndBytes = 0; |
876 |
++ int LastKeepByte = -1; |
877 |
++ |
878 |
++ if (PayloadStart) |
879 |
++ { |
880 |
++ History = 0xffffffff; |
881 |
++ PesId = -1; |
882 |
++ NaluFillState = NALU_NONE; |
883 |
++ } |
884 |
++ |
885 |
++ for (int i=0; i<size; i++) { |
886 |
++ History = (History << 8) | Payload[i]; |
887 |
++ |
888 |
++ PesOffset++; |
889 |
++ NaluOffset++; |
890 |
++ |
891 |
++ bool DropByte = false; |
892 |
++ |
893 |
++ if (History >= 0x00000180 && History <= 0x000001FF) |
894 |
++ { |
895 |
++ // Start of PES packet |
896 |
++ PesId = History & 0xff; |
897 |
++ PesOffset = 0; |
898 |
++ NaluFillState = NALU_NONE; |
899 |
++ } |
900 |
++ else if (PesId >= 0xe0 && PesId <= 0xef // video stream |
901 |
++ && History >= 0x00000100 && History <= 0x0000017F) // NALU start code |
902 |
++ { |
903 |
++ int NaluId = History & 0xff; |
904 |
++ NaluOffset = 0; |
905 |
++ NaluFillState = ((NaluId & 0x1f) == 0x0c) ? NALU_FILL : NALU_NONE; |
906 |
++ } |
907 |
++ |
908 |
++ if (PesId >= 0xe0 && PesId <= 0xef // video stream |
909 |
++ && PesOffset >= 1 && PesOffset <= 2) |
910 |
++ { |
911 |
++ Payload[i] = 0; // Zero out PES length field |
912 |
++ } |
913 |
++ |
914 |
++ if (NaluFillState == NALU_FILL && NaluOffset > 0) // Within NALU fill data |
915 |
++ { |
916 |
++ // We expect a series of 0xff bytes terminated by a single 0x80 byte. |
917 |
++ |
918 |
++ if (Payload[i] == 0xFF) |
919 |
++ { |
920 |
++ DropByte = true; |
921 |
++ } |
922 |
++ else if (Payload[i] == 0x80) |
923 |
++ { |
924 |
++ NaluFillState = NALU_TERM; // Last byte of NALU fill, next byte sets NaluFillEnd=true |
925 |
++ DropByte = true; |
926 |
++ } |
927 |
++ else // Invalid NALU fill |
928 |
++ { |
929 |
++ dsyslog("cNaluDumper: Unexpected NALU fill data: %02x", Payload[i]); |
930 |
++ NaluFillState = NALU_END; |
931 |
++ if (LastKeepByte == -1) |
932 |
++ { |
933 |
++ // Nalu fill from beginning of packet until last byte |
934 |
++ // packet start needs to be dropped |
935 |
++ Info.DropPayloadStartBytes = i; |
936 |
++ } |
937 |
++ } |
938 |
++ } |
939 |
++ else if (NaluFillState == NALU_TERM) // Within NALU fill data |
940 |
++ { |
941 |
++ // We are after the terminating 0x80 byte |
942 |
++ NaluFillState = NALU_END; |
943 |
++ if (LastKeepByte == -1) |
944 |
++ { |
945 |
++ // Nalu fill from beginning of packet until last byte |
946 |
++ // packet start needs to be dropped |
947 |
++ Info.DropPayloadStartBytes = i; |
948 |
++ } |
949 |
++ } |
950 |
++ |
951 |
++ if (!DropByte) |
952 |
++ LastKeepByte = i; // Last useful byte |
953 |
++ } |
954 |
++ |
955 |
++ Info.DropAllPayloadBytes = (LastKeepByte == -1); |
956 |
++ Info.DropPayloadEndBytes = size-1-LastKeepByte; |
957 |
++} |
958 |
++ |
959 |
++bool cNaluDumper::ProcessTSPacket(unsigned char *Packet) |
960 |
++{ |
961 |
++ bool HasAdaption = TsHasAdaptationField(Packet); |
962 |
++ bool HasPayload = TsHasPayload(Packet); |
963 |
++ |
964 |
++ // Check continuity: |
965 |
++ int ContinuityInput = TsContinuityCounter(Packet); |
966 |
++ if (LastContinuityInput >= 0) |
967 |
++ { |
968 |
++ int NewContinuityInput = HasPayload ? (LastContinuityInput + 1) & TS_CONT_CNT_MASK : LastContinuityInput; |
969 |
++ int Offset = (NewContinuityInput - ContinuityInput) & TS_CONT_CNT_MASK; |
970 |
++ if (Offset > 0) |
971 |
++ dsyslog("cNaluDumper: TS continuity offset %i", Offset); |
972 |
++ if (Offset > ContinuityOffset) |
973 |
++ ContinuityOffset = Offset; // max if packets get dropped, otherwise always the current one. |
974 |
++ } |
975 |
++ LastContinuityInput = ContinuityInput; |
976 |
++ |
977 |
++ if (HasPayload) { |
978 |
++ sPayloadInfo Info; |
979 |
++ int Offset = TsPayloadOffset(Packet); |
980 |
++ ProcessPayload(Packet + Offset, TS_SIZE - Offset, TsPayloadStart(Packet), Info); |
981 |
++ |
982 |
++ if (DropAllPayload && !Info.DropAllPayloadBytes) |
983 |
++ { |
984 |
++ // Return from drop packet mode to normal mode |
985 |
++ DropAllPayload = false; |
986 |
++ |
987 |
++ // Does the packet start with some remaining NALU fill data? |
988 |
++ if (Info.DropPayloadStartBytes > 0) |
989 |
++ { |
990 |
++ // Add these bytes as stuffing to the adaption field. |
991 |
++ |
992 |
++ // Sample payload layout: |
993 |
++ // FF FF FF FF FF 80 00 00 01 xx xx xx xx |
994 |
++ // ^DropPayloadStartBytes |
995 |
++ |
996 |
++ TsExtendAdaptionField(Packet, Offset - 4 + Info.DropPayloadStartBytes); |
997 |
++ } |
998 |
++ } |
999 |
++ |
1000 |
++ bool DropThisPayload = DropAllPayload; |
1001 |
++ |
1002 |
++ if (!DropAllPayload && Info.DropPayloadEndBytes > 0) // Payload ends with 0xff NALU Fill |
1003 |
++ { |
1004 |
++ // Last packet of useful data |
1005 |
++ // Do early termination of NALU fill data |
1006 |
++ Packet[TS_SIZE-1] = 0x80; |
1007 |
++ DropAllPayload = true; |
1008 |
++ // Drop all packets AFTER this one |
1009 |
++ |
1010 |
++ // Since we already wrote the 0x80, we have to make sure that |
1011 |
++ // as soon as we stop dropping packets, any beginning NALU fill of next |
1012 |
++ // packet gets dumped. (see DropPayloadStartBytes above) |
1013 |
++ } |
1014 |
++ |
1015 |
++ if (DropThisPayload && HasAdaption) |
1016 |
++ { |
1017 |
++ // Drop payload data, but keep adaption field data |
1018 |
++ TsExtendAdaptionField(Packet, TS_SIZE-4); |
1019 |
++ DropThisPayload = false; |
1020 |
++ } |
1021 |
++ |
1022 |
++ if (DropThisPayload) |
1023 |
++ { |
1024 |
++ return true; // Drop packet |
1025 |
++ } |
1026 |
++ } |
1027 |
++ |
1028 |
++ // Fix Continuity Counter and reproduce incoming offsets: |
1029 |
++ int NewContinuityOutput = TsHasPayload(Packet) ? (LastContinuityOutput + 1) & TS_CONT_CNT_MASK : LastContinuityOutput; |
1030 |
++ NewContinuityOutput = (NewContinuityOutput + ContinuityOffset) & TS_CONT_CNT_MASK; |
1031 |
++ TsSetContinuityCounter(Packet, NewContinuityOutput); |
1032 |
++ LastContinuityOutput = NewContinuityOutput; |
1033 |
++ ContinuityOffset = 0; |
1034 |
++ |
1035 |
++ return false; // Keep packet |
1036 |
++} |
1037 |
++ |
1038 |
++// --- cNaluStreamProcessor --------------------------------------------------------- |
1039 |
++ |
1040 |
++cNaluStreamProcessor::cNaluStreamProcessor() |
1041 |
++{ |
1042 |
++ pPatPmtParser = NULL; |
1043 |
++ vpid = -1; |
1044 |
++ data = NULL; |
1045 |
++ length = 0; |
1046 |
++ tempLength = 0; |
1047 |
++ tempLengthAtEnd = false; |
1048 |
++ TotalPackets = 0; |
1049 |
++ DroppedPackets = 0; |
1050 |
++} |
1051 |
++ |
1052 |
++void cNaluStreamProcessor::PutBuffer(uchar *Data, int Length) |
1053 |
++{ |
1054 |
++ if (length > 0) |
1055 |
++ esyslog("cNaluStreamProcessor::PutBuffer: New data before old data was processed!"); |
1056 |
++ |
1057 |
++ data = Data; |
1058 |
++ length = Length; |
1059 |
++} |
1060 |
++ |
1061 |
++uchar* cNaluStreamProcessor::GetBuffer(int &OutLength) |
1062 |
++{ |
1063 |
++ if (length <= 0) |
1064 |
++ { |
1065 |
++ // Need more data - quick exit |
1066 |
++ OutLength = 0; |
1067 |
++ return NULL; |
1068 |
++ } |
1069 |
++ if (tempLength > 0) // Data in temp buffer? |
1070 |
++ { |
1071 |
++ if (tempLengthAtEnd) // Data is at end, copy to beginning |
1072 |
++ { |
1073 |
++ // Overlapping src and dst! |
1074 |
++ for (int i=0; i<tempLength; i++) |
1075 |
++ tempBuffer[i] = tempBuffer[TS_SIZE-tempLength+i]; |
1076 |
++ } |
1077 |
++ // Normalize TempBuffer fill |
1078 |
++ if (tempLength < TS_SIZE && length > 0) |
1079 |
++ { |
1080 |
++ int Size = min(TS_SIZE-tempLength, length); |
1081 |
++ memcpy(tempBuffer+tempLength, data, Size); |
1082 |
++ data += Size; |
1083 |
++ length -= Size; |
1084 |
++ tempLength += Size; |
1085 |
++ } |
1086 |
++ if (tempLength < TS_SIZE) |
1087 |
++ { |
1088 |
++ // All incoming data buffered, but need more data |
1089 |
++ tempLengthAtEnd = false; |
1090 |
++ OutLength = 0; |
1091 |
++ return NULL; |
1092 |
++ } |
1093 |
++ // Now: TempLength==TS_SIZE |
1094 |
++ if (tempBuffer[0] != TS_SYNC_BYTE) |
1095 |
++ { |
1096 |
++ // Need to sync on TS within temp buffer |
1097 |
++ int Skipped = 1; |
1098 |
++ while (Skipped < TS_SIZE && (tempBuffer[Skipped] != TS_SYNC_BYTE || (Skipped < length && data[Skipped] != TS_SYNC_BYTE))) |
1099 |
++ Skipped++; |
1100 |
++ esyslog("ERROR: skipped %d bytes to sync on start of TS packet", Skipped); |
1101 |
++ // Pass through skipped bytes |
1102 |
++ tempLengthAtEnd = true; |
1103 |
++ tempLength = TS_SIZE - Skipped; // may be 0, thats ok |
1104 |
++ OutLength = Skipped; |
1105 |
++ return tempBuffer; |
1106 |
++ } |
1107 |
++ // Now: TempBuffer is a TS packet |
1108 |
++ int Pid = TsPid(tempBuffer); |
1109 |
++ if (pPatPmtParser) |
1110 |
++ { |
1111 |
++ if (Pid == 0) |
1112 |
++ pPatPmtParser->ParsePat(tempBuffer, TS_SIZE); |
1113 |
++ else if (pPatPmtParser->IsPmtPid(Pid)) |
1114 |
++ pPatPmtParser->ParsePmt(tempBuffer, TS_SIZE); |
1115 |
++ } |
1116 |
++ |
1117 |
++ TotalPackets++; |
1118 |
++ bool Drop = false; |
1119 |
++ if (Pid == vpid || (pPatPmtParser && Pid == pPatPmtParser->Vpid() && pPatPmtParser->Vtype() == 0x1B)) |
1120 |
++ Drop = NaluDumper.ProcessTSPacket(tempBuffer); |
1121 |
++ if (!Drop) |
1122 |
++ { |
1123 |
++ // Keep this packet, then continue with new data |
1124 |
++ tempLength = 0; |
1125 |
++ OutLength = TS_SIZE; |
1126 |
++ return tempBuffer; |
1127 |
++ } |
1128 |
++ // Drop TempBuffer |
1129 |
++ DroppedPackets++; |
1130 |
++ tempLength = 0; |
1131 |
++ } |
1132 |
++ // Now: TempLength==0, just process data/length |
1133 |
++ |
1134 |
++ // Pointer to processed data / length: |
1135 |
++ uchar *Out = data; |
1136 |
++ uchar *OutEnd = Out; |
1137 |
++ |
1138 |
++ while (length >= TS_SIZE) |
1139 |
++ { |
1140 |
++ if (data[0] != TS_SYNC_BYTE) { |
1141 |
++ int Skipped = 1; |
1142 |
++ while (Skipped < length && (data[Skipped] != TS_SYNC_BYTE || (length - Skipped > TS_SIZE && data[Skipped + TS_SIZE] != TS_SYNC_BYTE))) |
1143 |
++ Skipped++; |
1144 |
++ esyslog("ERROR: skipped %d bytes to sync on start of TS packet", Skipped); |
1145 |
++ |
1146 |
++ // Pass through skipped bytes |
1147 |
++ if (OutEnd != data) |
1148 |
++ memcpy(OutEnd, data, Skipped); |
1149 |
++ OutEnd += Skipped; |
1150 |
++ continue; |
1151 |
++ } |
1152 |
++ // Now: Data starts with complete TS packet |
1153 |
++ |
1154 |
++ int Pid = TsPid(data); |
1155 |
++ if (pPatPmtParser) |
1156 |
++ { |
1157 |
++ if (Pid == 0) |
1158 |
++ pPatPmtParser->ParsePat(data, TS_SIZE); |
1159 |
++ else if (pPatPmtParser->IsPmtPid(Pid)) |
1160 |
++ pPatPmtParser->ParsePmt(data, TS_SIZE); |
1161 |
++ } |
1162 |
++ |
1163 |
++ TotalPackets++; |
1164 |
++ bool Drop = false; |
1165 |
++ if (Pid == vpid || (pPatPmtParser && Pid == pPatPmtParser->Vpid() && pPatPmtParser->Vtype() == 0x1B)) |
1166 |
++ Drop = NaluDumper.ProcessTSPacket(data); |
1167 |
++ if (!Drop) |
1168 |
++ { |
1169 |
++ if (OutEnd != data) |
1170 |
++ memcpy(OutEnd, data, TS_SIZE); |
1171 |
++ OutEnd += TS_SIZE; |
1172 |
++ } |
1173 |
++ else |
1174 |
++ { |
1175 |
++ DroppedPackets++; |
1176 |
++ } |
1177 |
++ data += TS_SIZE; |
1178 |
++ length -= TS_SIZE; |
1179 |
++ } |
1180 |
++ // Now: Less than a packet remains. |
1181 |
++ if (length > 0) |
1182 |
++ { |
1183 |
++ // copy remains into temp buffer |
1184 |
++ memcpy(tempBuffer, data, length); |
1185 |
++ tempLength = length; |
1186 |
++ tempLengthAtEnd = false; |
1187 |
++ length = 0; |
1188 |
++ } |
1189 |
++ OutLength = (OutEnd - Out); |
1190 |
++ return OutLength > 0 ? Out : NULL; |
1191 |
++} |
1192 |
+diff -a -U 2 -r a/remux.h b/remux.h |
1193 |
+--- a/remux.h |
1194 |
++++ b/remux.h |
1195 |
+@@ -65,4 +65,9 @@ |
1196 |
+ } |
1197 |
+ |
1198 |
++inline bool TsSetPayload(const uchar *p) |
1199 |
++{ |
1200 |
++ return p[3] & TS_PAYLOAD_EXISTS; |
1201 |
++} |
1202 |
++ |
1203 |
+ inline bool TsHasAdaptationField(const uchar *p) |
1204 |
+ { |
1205 |
+@@ -156,4 +161,5 @@ |
1206 |
+ void TsSetPts(uchar *p, int l, int64_t Pts); |
1207 |
+ void TsSetDts(uchar *p, int l, int64_t Dts); |
1208 |
++void TsExtendAdaptionField(unsigned char *Packet, int ToLength); |
1209 |
+ |
1210 |
+ // Some PES handling tools: |
1211 |
+@@ -550,3 +556,77 @@ |
1212 |
+ }; |
1213 |
+ |
1214 |
++ |
1215 |
++#define PATCH_NALUDUMP 100 |
1216 |
++ |
1217 |
++class cNaluDumper { |
1218 |
++ unsigned int History; |
1219 |
++ |
1220 |
++ int LastContinuityInput; |
1221 |
++ int LastContinuityOutput; |
1222 |
++ int ContinuityOffset; |
1223 |
++ |
1224 |
++ bool DropAllPayload; |
1225 |
++ |
1226 |
++ int PesId; |
1227 |
++ int PesOffset; |
1228 |
++ |
1229 |
++ int NaluOffset; |
1230 |
++ |
1231 |
++ enum eNaluFillState { |
1232 |
++ NALU_NONE=0, // currently not NALU fill stream |
1233 |
++ NALU_FILL, // Within NALU fill stream, 0xff bytes and NALU start code in byte 0 |
1234 |
++ NALU_TERM, // Within NALU fill stream, read 0x80 terminating byte |
1235 |
++ NALU_END // Beyond end of NALU fill stream, expecting 0x00 0x00 0x01 now |
1236 |
++ }; |
1237 |
++ |
1238 |
++ eNaluFillState NaluFillState; |
1239 |
++ |
1240 |
++ struct sPayloadInfo { |
1241 |
++ int DropPayloadStartBytes; |
1242 |
++ int DropPayloadEndBytes; |
1243 |
++ bool DropAllPayloadBytes; |
1244 |
++ }; |
1245 |
++ |
1246 |
++public: |
1247 |
++ cNaluDumper(); |
1248 |
++ |
1249 |
++ void reset(); |
1250 |
++ |
1251 |
++ // Single packet interface: |
1252 |
++ bool ProcessTSPacket(unsigned char *Packet); |
1253 |
++ |
1254 |
++private: |
1255 |
++ void ProcessPayload(unsigned char *Payload, int size, bool PayloadStart, sPayloadInfo &Info); |
1256 |
++}; |
1257 |
++ |
1258 |
++class cNaluStreamProcessor { |
1259 |
++ //Buffer stream interface: |
1260 |
++ int vpid; |
1261 |
++ uchar *data; |
1262 |
++ int length; |
1263 |
++ uchar tempBuffer[TS_SIZE]; |
1264 |
++ int tempLength; |
1265 |
++ bool tempLengthAtEnd; |
1266 |
++ cPatPmtParser *pPatPmtParser; |
1267 |
++ cNaluDumper NaluDumper; |
1268 |
++ |
1269 |
++ long long int TotalPackets; |
1270 |
++ long long int DroppedPackets; |
1271 |
++public: |
1272 |
++ cNaluStreamProcessor(); |
1273 |
++ |
1274 |
++ void SetPid(int VPid) { vpid = VPid; } |
1275 |
++ void SetPatPmtParser(cPatPmtParser *_pPatPmtParser) { pPatPmtParser = _pPatPmtParser; } |
1276 |
++ // Set either a PID or set a pointer to an PatPmtParser that will detect _one_ PID |
1277 |
++ |
1278 |
++ void PutBuffer(uchar *Data, int Length); |
1279 |
++ // Add new data to be processed. Data must be valid until Get() returns NULL. |
1280 |
++ uchar* GetBuffer(int &OutLength); |
1281 |
++ // Returns filtered data, or NULL/0 to indicate that all data from Put() was processed |
1282 |
++ // or buffered. |
1283 |
++ |
1284 |
++ long long int GetTotalPackets() { return TotalPackets; } |
1285 |
++ long long int GetDroppedPackets() { return DroppedPackets; } |
1286 |
++}; |
1287 |
++ |
1288 |
+ #endif // __REMUX_H |
1289 |
|
1290 |
diff --git a/media-video/vdr/files/vdr-2.6.1_pinplugin.patch b/media-video/vdr/files/vdr-2.6.1_pinplugin.patch |
1291 |
new file mode 100644 |
1292 |
index 000000000000..2552f9e7109f |
1293 |
--- /dev/null |
1294 |
+++ b/media-video/vdr/files/vdr-2.6.1_pinplugin.patch |
1295 |
@@ -0,0 +1,447 @@ |
1296 |
+original vdr-pinplugin_vdr-2.3.1.diff |
1297 |
+rebased for media-video/vdr-2.6.1 |
1298 |
+ |
1299 |
+Signed-off-by: Christian Kunkel <ch.kunkel@×××.de> ( 2021 Feb 12 ) |
1300 |
+Reviewed-by: Martin Dummer <martin.dummer@×××.net> ( 2022-06-22 ) |
1301 |
+diff -Naur a/Makefile b/Makefile |
1302 |
+--- a/Makefile 2022-02-02 10:56:43.000000000 +0100 |
1303 |
++++ b/Makefile 2022-06-20 08:08:11.346956148 +0200 |
1304 |
+@@ -351,7 +351,7 @@ |
1305 |
+ clean: |
1306 |
+ @$(MAKE) --no-print-directory -C $(LSIDIR) clean |
1307 |
+ @-rm -f $(OBJS) $(DEPFILE) vdr vdr.pc core* *~ |
1308 |
+- @-rm -rf $(LOCALEDIR) $(PODIR)/*.mo $(PODIR)/*.pot |
1309 |
++ @-rm -rf $(LOCALEDIR) $(PODIR)/*~ $(PODIR)/*.mo $(PODIR)/*.pot |
1310 |
+ @-rm -rf include |
1311 |
+ @-rm -rf srcdoc |
1312 |
+ CLEAN: clean |
1313 |
+diff -Naur a/device.c b/device.c |
1314 |
+--- a/device.c 2022-02-02 10:56:43.000000000 +0100 |
1315 |
++++ b/device.c 2022-06-20 08:08:11.346956148 +0200 |
1316 |
+@@ -839,6 +839,7 @@ |
1317 |
+ const cChannel *Channel; |
1318 |
+ while ((Channel = Channels->GetByNumber(n, Direction)) != NULL) { |
1319 |
+ // try only channels which are currently available |
1320 |
++ if (!cStatus::MsgChannelProtected(0, Channel)) // PIN PATCH |
1321 |
+ if (GetDevice(Channel, LIVEPRIORITY, true, true)) |
1322 |
+ break; |
1323 |
+ n = Channel->Number() + Direction; |
1324 |
+@@ -860,6 +861,12 @@ |
1325 |
+ |
1326 |
+ eSetChannelResult cDevice::SetChannel(const cChannel *Channel, bool LiveView) |
1327 |
+ { |
1328 |
++ // I hope 'LiveView = false' indicates a channel switch for recording, // PIN PATCH |
1329 |
++ // I really don't know, but it works ... // PIN PATCH |
1330 |
++ |
1331 |
++ if (LiveView && cStatus::MsgChannelProtected(this, Channel)) // PIN PATCH |
1332 |
++ return scrNotAvailable; // PIN PATCH |
1333 |
++ |
1334 |
+ cMutexLock MutexLock(&mutexChannel); // to avoid a race between SVDRP CHAN and HasProgramme() |
1335 |
+ cStatus::MsgChannelSwitch(this, 0, LiveView); |
1336 |
+ |
1337 |
+diff -Naur a/menu.c b/menu.c |
1338 |
+--- a/menu.c 2022-02-02 10:56:43.000000000 +0100 |
1339 |
++++ b/menu.c 2022-06-20 08:08:11.346956148 +0200 |
1340 |
+@@ -1035,6 +1035,18 @@ |
1341 |
+ Add(new cMenuEditBitItem( tr("VPS"), &data.flags, tfVps)); |
1342 |
+ Add(new cMenuEditIntItem( tr("Priority"), &data.priority, 0, MAXPRIORITY)); |
1343 |
+ Add(new cMenuEditIntItem( tr("Lifetime"), &data.lifetime, 0, MAXLIFETIME)); |
1344 |
++ |
1345 |
++ // PIN PATCH |
1346 |
++ if (cOsd::pinValid || !data.fskProtection) Add(new cMenuEditBoolItem(tr("Childlock"),&data.fskProtection)); |
1347 |
++ else { |
1348 |
++ char* buf = 0; |
1349 |
++ int res = 0; |
1350 |
++ res = asprintf(&buf, "%s\t%s", tr("Childlock"), data.fskProtection ? tr("yes") : tr("no")); |
1351 |
++ if (res < 0) ; // memory problems :o |
1352 |
++ Add(new cOsdItem(buf)); |
1353 |
++ free(buf); |
1354 |
++ } |
1355 |
++ |
1356 |
+ Add(file = new cMenuEditStrItem( tr("File"), data.file, sizeof(data.file))); |
1357 |
+ SetFirstDayItem(); |
1358 |
+ SetPatternItem(true); |
1359 |
+@@ -3130,7 +3142,8 @@ |
1360 |
+ } |
1361 |
+ } |
1362 |
+ } |
1363 |
+- if (*Item->Text() && !LastDir) { |
1364 |
++ if (*Item->Text() && !LastDir |
1365 |
++ && (!cStatus::MsgReplayProtected(Item->Recording(), Item->Name(), base, Item->IsDirectory(), true))) { // PIN PATCH |
1366 |
+ Add(Item); |
1367 |
+ LastItem = Item; |
1368 |
+ if (Item->IsDirectory()) |
1369 |
+@@ -3201,6 +3214,9 @@ |
1370 |
+ { |
1371 |
+ cMenuRecordingItem *ri = (cMenuRecordingItem *)Get(Current()); |
1372 |
+ if (ri) { |
1373 |
++ if (cStatus::MsgReplayProtected(ri->Recording(), ri->Name(), base, |
1374 |
++ ri->IsDirectory()) == true) // PIN PATCH |
1375 |
++ return osContinue; |
1376 |
+ if (ri->IsDirectory()) |
1377 |
+ Open(); |
1378 |
+ else { |
1379 |
+@@ -4506,28 +4522,32 @@ |
1380 |
+ |
1381 |
+ // Basic menu items: |
1382 |
+ |
1383 |
+- Add(new cOsdItem(hk(tr("Schedule")), osSchedule)); |
1384 |
+- Add(new cOsdItem(hk(tr("Channels")), osChannels)); |
1385 |
+- Add(new cOsdItem(hk(tr("Timers")), osTimers)); |
1386 |
+- Add(new cOsdItem(hk(tr("Recordings")), osRecordings)); |
1387 |
++ // PIN PATCH |
1388 |
++ if (!cStatus::MsgMenuItemProtected("Schedule", true)) Add(new cOsdItem(hk(tr("Schedule")), osSchedule)); |
1389 |
++ if (!cStatus::MsgMenuItemProtected("Channels", true)) Add(new cOsdItem(hk(tr("Channels")), osChannels)); |
1390 |
++ if (!cStatus::MsgMenuItemProtected("Timers", true)) Add(new cOsdItem(hk(tr("Timers")), osTimers)); |
1391 |
++ if (!cStatus::MsgMenuItemProtected("Recordings", true)) Add(new cOsdItem(hk(tr("Recordings")), osRecordings)); |
1392 |
+ |
1393 |
+ // Plugins: |
1394 |
+ |
1395 |
+ for (int i = 0; ; i++) { |
1396 |
+ cPlugin *p = cPluginManager::GetPlugin(i); |
1397 |
+ if (p) { |
1398 |
++ if (!cStatus::MsgPluginProtected(p, true)) { // PIN PATCH |
1399 |
+ const char *item = p->MainMenuEntry(); |
1400 |
+ if (item) |
1401 |
+ Add(new cMenuPluginItem(hk(item), i)); |
1402 |
+ } |
1403 |
++ } |
1404 |
+ else |
1405 |
+ break; |
1406 |
+ } |
1407 |
+ |
1408 |
+ // More basic menu items: |
1409 |
+ |
1410 |
+- Add(new cOsdItem(hk(tr("Setup")), osSetup)); |
1411 |
++ if (!cStatus::MsgMenuItemProtected("Setup", true)) Add(new cOsdItem(hk(tr("Setup")), osSetup)); // PIN PATCH |
1412 |
+ if (Commands.Count()) |
1413 |
++ if (!cStatus::MsgMenuItemProtected("Commands", true)) // PIN PATCH |
1414 |
+ Add(new cOsdItem(hk(tr("Commands")), osCommands)); |
1415 |
+ |
1416 |
+ Update(true); |
1417 |
+@@ -4600,6 +4620,14 @@ |
1418 |
+ eOSState state = cOsdMenu::ProcessKey(Key); |
1419 |
+ HadSubMenu |= HasSubMenu(); |
1420 |
+ |
1421 |
++ // > PIN PATCH |
1422 |
++ cOsdItem* item = Get(Current()); |
1423 |
++ |
1424 |
++ if (item && item->Text() && state != osContinue && state != osUnknown && state != osBack) |
1425 |
++ if (cStatus::MsgMenuItemProtected(item->Text())) |
1426 |
++ return osContinue; |
1427 |
++ // PIN PATCH < |
1428 |
++ |
1429 |
+ switch (state) { |
1430 |
+ case osSchedule: return AddSubMenu(new cMenuSchedule); |
1431 |
+ case osChannels: return AddSubMenu(new cMenuChannels); |
1432 |
+@@ -4624,6 +4652,7 @@ |
1433 |
+ if (item) { |
1434 |
+ cPlugin *p = cPluginManager::GetPlugin(item->PluginIndex()); |
1435 |
+ if (p) { |
1436 |
++ if (!cStatus::MsgPluginProtected(p)) { // PIN PATCH |
1437 |
+ cOsdObject *menu = p->MainMenuAction(); |
1438 |
+ if (menu) { |
1439 |
+ if (menu->IsMenu()) |
1440 |
+@@ -4635,6 +4664,7 @@ |
1441 |
+ } |
1442 |
+ } |
1443 |
+ } |
1444 |
++ } |
1445 |
+ state = osEnd; |
1446 |
+ } |
1447 |
+ break; |
1448 |
+@@ -4814,6 +4844,7 @@ |
1449 |
+ Channel = Direction > 0 ? Channels->Next(Channel) : Channels->Prev(Channel); |
1450 |
+ if (!Channel && Setup.ChannelsWrap) |
1451 |
+ Channel = Direction > 0 ? Channels->First() : Channels->Last(); |
1452 |
++ if (!cStatus::MsgChannelProtected(0, Channel)) // PIN PATCH |
1453 |
+ if (Channel && !Channel->GroupSep() && cDevice::GetDevice(Channel, LIVEPRIORITY, true, true)) |
1454 |
+ return Channel; |
1455 |
+ } |
1456 |
+@@ -5491,6 +5522,7 @@ |
1457 |
+ for (int i = 0; i < MAXRECORDCONTROLS; i++) { |
1458 |
+ if (!RecordControls[i]) { |
1459 |
+ RecordControls[i] = new cRecordControl(device, Timers, Timer, Pause); |
1460 |
++ cStatus::MsgRecordingFile(RecordControls[i]->FileName()); // PIN PATCH |
1461 |
+ return RecordControls[i]->Process(time(NULL)); |
1462 |
+ } |
1463 |
+ } |
1464 |
+diff -Naur a/osd.c b/osd.c |
1465 |
+--- a/osd.c 2022-02-02 10:56:43.000000000 +0100 |
1466 |
++++ b/osd.c 2022-06-20 08:08:11.346956148 +0200 |
1467 |
+@@ -1844,6 +1844,7 @@ |
1468 |
+ cSize cOsd::maxPixmapSize(INT_MAX, INT_MAX); |
1469 |
+ cVector<cOsd *> cOsd::Osds; |
1470 |
+ cMutex cOsd::mutex; |
1471 |
++bool cOsd::pinValid = false; // PIN PATCH |
1472 |
+ |
1473 |
+ cOsd::cOsd(int Left, int Top, uint Level) |
1474 |
+ { |
1475 |
+diff -Naur a/osd.h b/osd.h |
1476 |
+--- a/osd.h 2022-02-02 10:56:43.000000000 +0100 |
1477 |
++++ b/osd.h 2022-06-20 08:08:11.346956148 +0200 |
1478 |
+@@ -957,6 +957,7 @@ |
1479 |
+ ///< |
1480 |
+ ///< If a plugin uses a derived cPixmap implementation, it needs to use that |
1481 |
+ ///< type instead of cPixmapMemory. |
1482 |
++ static bool pinValid; // PIN PATCH |
1483 |
+ }; |
1484 |
+ |
1485 |
+ #define MAXOSDIMAGES 64 |
1486 |
+diff -Naur a/status.c b/status.c |
1487 |
+--- a/status.c 2022-02-02 10:56:43.000000000 +0100 |
1488 |
++++ b/status.c 2022-06-20 08:08:11.346956148 +0200 |
1489 |
+@@ -136,3 +136,55 @@ |
1490 |
+ for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) |
1491 |
+ sm->OsdProgramme(PresentTime, PresentTitle, PresentSubtitle, FollowingTime, FollowingTitle, FollowingSubtitle); |
1492 |
+ } |
1493 |
++ |
1494 |
++bool cStatus::MsgChannelProtected(const cDevice* Device, const cChannel* Channel) // PIN PATCH |
1495 |
++{ |
1496 |
++ for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) |
1497 |
++ if (sm->ChannelProtected(Device, Channel) == true) |
1498 |
++ return true; |
1499 |
++ |
1500 |
++ return false; |
1501 |
++} |
1502 |
++ |
1503 |
++bool cStatus::MsgReplayProtected(const cRecording* Recording, const char* Name, |
1504 |
++ const char* Base, bool isDirectory, int menuView) // PIN PATCH |
1505 |
++{ |
1506 |
++ for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) |
1507 |
++ if (sm->ReplayProtected(Recording, Name, Base, isDirectory, menuView) == true) |
1508 |
++ return true; |
1509 |
++ return false; |
1510 |
++} |
1511 |
++ |
1512 |
++void cStatus::MsgRecordingFile(const char* FileName) |
1513 |
++{ |
1514 |
++ for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) // PIN PATCH |
1515 |
++ sm->RecordingFile(FileName); |
1516 |
++} |
1517 |
++ |
1518 |
++void cStatus::MsgTimerCreation(cTimer* Timer, const cEvent *Event) |
1519 |
++{ |
1520 |
++ for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) // PIN PATCH |
1521 |
++ sm->TimerCreation(Timer, Event); |
1522 |
++} |
1523 |
++ |
1524 |
++bool cStatus::MsgPluginProtected(cPlugin* Plugin, int menuView) // PIN PATCH |
1525 |
++{ |
1526 |
++ for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) |
1527 |
++ if (sm->PluginProtected(Plugin, menuView) == true) |
1528 |
++ return true; |
1529 |
++ return false; |
1530 |
++} |
1531 |
++ |
1532 |
++void cStatus::MsgUserAction(const eKeys key) // PIN PATCH |
1533 |
++{ |
1534 |
++ for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) |
1535 |
++ sm->UserAction(key); |
1536 |
++} |
1537 |
++ |
1538 |
++bool cStatus::MsgMenuItemProtected(const char* Name, int menuView) // PIN PATCH |
1539 |
++{ |
1540 |
++ for (cStatus *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm)) |
1541 |
++ if (sm->MenuItemProtected(Name, menuView) == true) |
1542 |
++ return true; |
1543 |
++ return false; |
1544 |
++} |
1545 |
+diff -Naur a/status.h b/status.h |
1546 |
+--- a/status.h 2022-02-02 10:56:43.000000000 +0100 |
1547 |
++++ b/status.h 2022-06-20 08:08:11.350956230 +0200 |
1548 |
+@@ -14,6 +14,7 @@ |
1549 |
+ #include "device.h" |
1550 |
+ #include "player.h" |
1551 |
+ #include "tools.h" |
1552 |
++#include "plugin.h" |
1553 |
+ |
1554 |
+ // Several member functions of the following classes are called with a pointer to |
1555 |
+ // an object from a global list (cTimer, cChannel, cRecording or cEvent). In these |
1556 |
+@@ -99,6 +100,22 @@ |
1557 |
+ // The OSD displays the single line Text with the current channel information. |
1558 |
+ virtual void OsdProgramme(time_t PresentTime, const char *PresentTitle, const char *PresentSubtitle, time_t FollowingTime, const char *FollowingTitle, const char *FollowingSubtitle) {} |
1559 |
+ // The OSD displays the given programme information. |
1560 |
++ virtual bool ChannelProtected(const cDevice *Device, const cChannel* Channel) { return false; } // PIN PATCH |
1561 |
++ // Checks if a channel is protected. |
1562 |
++ virtual bool ReplayProtected(const cRecording* Recording, const char* Name, |
1563 |
++ const char* Base, bool isDirectory, int menuView = false) { return false; } // PIN PATCH |
1564 |
++ // Checks if a recording is protected. |
1565 |
++ virtual void RecordingFile(const char* FileName) {} // PIN PATCH |
1566 |
++ // The given DVB device has started recording to FileName. FileName is the name of the |
1567 |
++ // recording directory |
1568 |
++ virtual void TimerCreation(cTimer* Timer, const cEvent *Event) {} // PIN PATCH |
1569 |
++ // The given timer is created |
1570 |
++ virtual bool PluginProtected(cPlugin* Plugin, int menuView = false) { return false; } // PIN PATCH |
1571 |
++ // Checks if a plugin is protected. |
1572 |
++ virtual void UserAction(const eKeys key) {} // PIN PATCH |
1573 |
++ // report user action |
1574 |
++ virtual bool MenuItemProtected(const char* Name, int menuView = false) { return false; } // PIN PATCH |
1575 |
++ |
1576 |
+ public: |
1577 |
+ cStatus(void); |
1578 |
+ virtual ~cStatus(); |
1579 |
+@@ -122,6 +139,14 @@ |
1580 |
+ static void MsgOsdTextItem(const char *Text, bool Scroll = false); |
1581 |
+ static void MsgOsdChannel(const char *Text); |
1582 |
+ static void MsgOsdProgramme(time_t PresentTime, const char *PresentTitle, const char *PresentSubtitle, time_t FollowingTime, const char *FollowingTitle, const char *FollowingSubtitle); |
1583 |
++ static bool MsgChannelProtected(const cDevice* Device, const cChannel* Channel); // PIN PATCH |
1584 |
++ static bool MsgReplayProtected(const cRecording* Recording, const char* Name, |
1585 |
++ const char* Base, bool isDirectory, int menuView = false); // PIN PATCH |
1586 |
++ static void MsgRecordingFile(const char* FileName); // PIN PATCH |
1587 |
++ static void MsgTimerCreation(cTimer* Timer, const cEvent *Event); // PIN PATCH |
1588 |
++ static bool MsgPluginProtected(cPlugin* Plugin, int menuView = false); // PIN PATCH |
1589 |
++ static void MsgUserAction(const eKeys key); // PIN PATCH |
1590 |
++ static bool MsgMenuItemProtected(const char* Name, int menuView = false); // PIN PATCH |
1591 |
+ }; |
1592 |
+ |
1593 |
+ #endif //__STATUS_H |
1594 |
+diff -Naur a/timers.c b/timers.c |
1595 |
+--- a/timers.c 2022-02-02 10:56:43.000000000 +0100 |
1596 |
++++ b/timers.c 2022-06-20 08:14:07.898392829 +0200 |
1597 |
+@@ -81,6 +81,7 @@ |
1598 |
+ stop -= 2400; |
1599 |
+ priority = Pause ? Setup.PausePriority : Setup.DefaultPriority; |
1600 |
+ lifetime = Pause ? Setup.PauseLifetime : Setup.DefaultLifetime; |
1601 |
++ fskProtection = 0; // PIN PATCH |
1602 |
+ if (Instant && channel) |
1603 |
+ snprintf(file, sizeof(file), "%s%s", Setup.MarkInstantRecord ? "@" : "", *Setup.NameInstantRecord ? Setup.NameInstantRecord : channel->Name()); |
1604 |
+ } |
1605 |
+@@ -212,11 +213,13 @@ |
1606 |
+ stop -= 2400; |
1607 |
+ priority = PatternTimer ? PatternTimer->Priority() : Setup.DefaultPriority; |
1608 |
+ lifetime = PatternTimer ? PatternTimer->Lifetime() : Setup.DefaultLifetime; |
1609 |
++ fskProtection = 0; // PIN PATCH |
1610 |
+ if (!FileName) |
1611 |
+ FileName = Event->Title(); |
1612 |
+ if (!isempty(FileName)) |
1613 |
+ Utf8Strn0Cpy(file, FileName, sizeof(file)); |
1614 |
+ SetEvent(Event); |
1615 |
++ cStatus::MsgTimerCreation(this, Event); // PIN PATCH |
1616 |
+ } |
1617 |
+ |
1618 |
+ cTimer::cTimer(const cTimer &Timer) |
1619 |
+@@ -255,6 +258,7 @@ |
1620 |
+ stop = Timer.stop; |
1621 |
+ priority = Timer.priority; |
1622 |
+ lifetime = Timer.lifetime; |
1623 |
++ fskProtection = Timer.fskProtection; // PIN PATCH |
1624 |
+ strncpy(pattern, Timer.pattern, sizeof(pattern)); |
1625 |
+ strncpy(file, Timer.file, sizeof(file)); |
1626 |
+ free(aux); |
1627 |
+@@ -484,6 +488,7 @@ |
1628 |
+ result = false; |
1629 |
+ } |
1630 |
+ } |
1631 |
++ fskProtection = aux && strstr(aux, "<pin-plugin><protected>yes</protected></pin-plugin>"); // PIN PATCH |
1632 |
+ free(channelbuffer); |
1633 |
+ free(daybuffer); |
1634 |
+ free(filebuffer); |
1635 |
+@@ -1037,6 +1042,36 @@ |
1636 |
+ Matches(); // refresh start and end time |
1637 |
+ } |
1638 |
+ |
1639 |
++void cTimer::SetFskProtection(int aFlag) // PIN PATCH |
1640 |
++{ |
1641 |
++ char* p; |
1642 |
++ char* tmp = 0; |
1643 |
++ int res = 0; |
1644 |
++ |
1645 |
++ fskProtection = aFlag; |
1646 |
++ |
1647 |
++ if (fskProtection && (!aux || !strstr(aux, "<pin-plugin><protected>yes</protected></pin-plugin>"))) |
1648 |
++ { |
1649 |
++ // add protection info to aux |
1650 |
++ |
1651 |
++ if (aux) { tmp = strdup(aux); free(aux); } |
1652 |
++ res = asprintf(&aux, "%s<pin-plugin><protected>yes</protected></pin-plugin>", tmp ? tmp : ""); |
1653 |
++ } |
1654 |
++ else if (!fskProtection && aux && (p = strstr(aux, "<pin-plugin><protected>yes</protected></pin-plugin>"))) |
1655 |
++ { |
1656 |
++ // remove protection info from aux |
1657 |
++ |
1658 |
++ res = asprintf(&tmp, "%.*s%s", (int)(p-aux), aux, p+strlen("<pin-plugin><protected>yes</protected></pin-plugin>")); |
1659 |
++ free(aux); |
1660 |
++ aux = strdup(tmp); |
1661 |
++ } |
1662 |
++ |
1663 |
++ if (res < 0) ; // memory problems :o |
1664 |
++ |
1665 |
++ if (tmp) |
1666 |
++ free(tmp); |
1667 |
++} |
1668 |
++ |
1669 |
+ // --- cTimers --------------------------------------------------------------- |
1670 |
+ |
1671 |
+ cTimers cTimers::timers; |
1672 |
+diff -Naur a/timers.h b/timers.h |
1673 |
+--- a/timers.h 2022-02-02 10:56:43.000000000 +0100 |
1674 |
++++ b/timers.h 2022-06-20 08:08:11.350956230 +0200 |
1675 |
+@@ -45,6 +45,7 @@ |
1676 |
+ int start; ///< the start and stop time of this timer as given by the user, |
1677 |
+ int stop; ///< in the form hhmm, with hh (00..23) and mm (00..59) added as hh*100+mm |
1678 |
+ int priority; |
1679 |
++ int fskProtection; // PIN PATCH |
1680 |
+ int lifetime; |
1681 |
+ mutable char pattern[NAME_MAX * 2 + 1]; // same size as 'file', to be able to initially fill 'pattern' with 'file' in the 'Edit timer' menu |
1682 |
+ mutable char file[NAME_MAX * 2 + 1]; // *2 to be able to hold 'title' and 'episode', which can each be up to 255 characters long |
1683 |
+@@ -70,6 +71,7 @@ |
1684 |
+ int Start(void) const { return start; } |
1685 |
+ int Stop(void) const { return stop; } |
1686 |
+ int Priority(void) const { return priority; } |
1687 |
++ int FskProtection(void) const { return fskProtection; } // PIN PATCH |
1688 |
+ int Lifetime(void) const { return lifetime; } |
1689 |
+ const char *Pattern(void) const { return pattern; } |
1690 |
+ const char *File(void) const { return file; } |
1691 |
+@@ -120,6 +122,7 @@ |
1692 |
+ void SetRemote(const char *Remote); |
1693 |
+ void SetDeferred(int Seconds); |
1694 |
+ void SetFlags(uint Flags); |
1695 |
++ void SetFskProtection(int aFlag); // PIN PATCH |
1696 |
+ void ClrFlags(uint Flags); |
1697 |
+ void InvFlags(uint Flags); |
1698 |
+ bool HasFlags(uint Flags) const; |
1699 |
+diff -Naur a/vdr.c b/vdr.c |
1700 |
+--- a/vdr.c 2022-02-02 10:56:43.000000000 +0100 |
1701 |
++++ b/vdr.c 2022-06-20 08:08:11.350956230 +0200 |
1702 |
+@@ -71,6 +71,7 @@ |
1703 |
+ #include "tools.h" |
1704 |
+ #include "transfer.h" |
1705 |
+ #include "videodir.h" |
1706 |
++#include "status.h" // PIN PATCH |
1707 |
+ |
1708 |
+ #define MINCHANNELWAIT 10 // seconds to wait between failed channel switchings |
1709 |
+ #define ACTIVITYTIMEOUT 60 // seconds before starting housekeeping |
1710 |
+@@ -1210,6 +1211,7 @@ |
1711 |
+ if (!Menu) |
1712 |
+ Interact = Control = cControl::Control(ControlMutexLock); |
1713 |
+ if (ISREALKEY(key)) { |
1714 |
++ cStatus::MsgUserAction(key); // PIN PATCH |
1715 |
+ EITScanner.Activity(); |
1716 |
+ // Cancel shutdown countdown: |
1717 |
+ if (ShutdownHandler.countdown) |
1718 |
+@@ -1282,10 +1284,12 @@ |
1719 |
+ Control->Hide(); |
1720 |
+ cPlugin *plugin = cPluginManager::GetPlugin(PluginName); |
1721 |
+ if (plugin) { |
1722 |
++ if (!cStatus::MsgPluginProtected(plugin)) { // PIN PATCH |
1723 |
+ Menu = plugin->MainMenuAction(); |
1724 |
+ if (Menu) |
1725 |
+ Menu->Show(); |
1726 |
+ } |
1727 |
++ } |
1728 |
+ else |
1729 |
+ esyslog("ERROR: unknown plugin '%s'", PluginName); |
1730 |
+ } |
1731 |
+@@ -1505,9 +1509,11 @@ |
1732 |
+ case kPlay: |
1733 |
+ if (cReplayControl::LastReplayed()) { |
1734 |
+ Control = NULL; |
1735 |
++ if (cStatus::MsgReplayProtected(0, cReplayControl::LastReplayed(), 0, false) == false) { // PIN PATCH |
1736 |
+ cControl::Shutdown(); |
1737 |
+ cControl::Launch(new cReplayControl); |
1738 |
+ } |
1739 |
++ } |
1740 |
+ else |
1741 |
+ DirectMainFunction(osRecordings); // no last viewed recording, so enter the Recordings menu |
1742 |
+ break; |
1743 |
|
1744 |
diff --git a/media-video/vdr/vdr-2.6.1.ebuild b/media-video/vdr/vdr-2.6.1.ebuild |
1745 |
new file mode 100644 |
1746 |
index 000000000000..4300433dcc75 |
1747 |
--- /dev/null |
1748 |
+++ b/media-video/vdr/vdr-2.6.1.ebuild |
1749 |
@@ -0,0 +1,197 @@ |
1750 |
+# Copyright 2021-2022 Gentoo Authors |
1751 |
+# Distributed under the terms of the GNU General Public License v2 |
1752 |
+ |
1753 |
+EAPI=8 |
1754 |
+ |
1755 |
+inherit flag-o-matic strip-linguas toolchain-funcs user-info |
1756 |
+ |
1757 |
+DESCRIPTION="Video Disk Recorder - turns a pc into a powerful set top box for DVB" |
1758 |
+HOMEPAGE="http://www.tvdr.de/" |
1759 |
+SRC_URI="http://git.tvdr.de/?p=vdr.git;a=snapshot;h=refs/tags/${PV};sf=tbz2 -> ${P}.tbz2 |
1760 |
+ menuorg? ( https://github.com/vdr-projects/vdr-plugin-menuorg/raw/master/vdr-patch/vdr-menuorg-2.3.x.diff ) |
1761 |
+ ttxtsubs? ( https://md11.it.cx/download/${PN}/${PN}-2.6.1_ttxtsubs_v2.patch )" |
1762 |
+ |
1763 |
+LICENSE="GPL-2+" |
1764 |
+SLOT="0" |
1765 |
+KEYWORDS="~amd64 ~arm ~arm64 ~ppc ~x86" |
1766 |
+IUSE="bidi debug demoplugins html keyboard mainmenuhooks menuorg naludump permashift pinplugin systemd ttxtsubs verbose" |
1767 |
+ |
1768 |
+COMMON_DEPEND=" |
1769 |
+ media-libs/fontconfig |
1770 |
+ media-libs/freetype |
1771 |
+ media-libs/libjpeg-turbo |
1772 |
+ sys-libs/libcap" |
1773 |
+DEPEND="${COMMON_DEPEND} |
1774 |
+ >=virtual/linuxtv-dvb-headers-5.3" |
1775 |
+RDEPEND="${COMMON_DEPEND} |
1776 |
+ dev-lang/perl |
1777 |
+ media-tv/gentoo-vdr-scripts |
1778 |
+ media-fonts/corefonts |
1779 |
+ bidi? ( dev-libs/fribidi ) |
1780 |
+ systemd? ( sys-apps/systemd )" |
1781 |
+BDEPEND=" |
1782 |
+ acct-user/vdr |
1783 |
+ sys-devel/gettext" |
1784 |
+ |
1785 |
+REQUIRED_USE="permashift? ( !naludump !pinplugin )" |
1786 |
+ |
1787 |
+CONF_DIR="/etc/vdr" |
1788 |
+CAP_FILE="${S}/capabilities.sh" |
1789 |
+CAPS="# Capabilities of the vdr-executable for use by startscript etc." |
1790 |
+ |
1791 |
+pkg_setup() { |
1792 |
+ use debug && append-flags -g |
1793 |
+ |
1794 |
+ PLUGIN_LIBDIR="/usr/$(get_libdir)/vdr/plugins" |
1795 |
+ VIDEO_DIR="$(egethome vdr)/video" |
1796 |
+ |
1797 |
+ tc-export CC CXX AR |
1798 |
+} |
1799 |
+ |
1800 |
+add_cap() { |
1801 |
+ local arg |
1802 |
+ for arg; do |
1803 |
+ CAPS="${CAPS}\n${arg}=1" |
1804 |
+ done |
1805 |
+} |
1806 |
+ |
1807 |
+lang_po() { |
1808 |
+ LING_PO=$( ls ${S}/po | sed -e "s:.po::g" | cut -d_ -f1 | tr \\\012 ' ' ) |
1809 |
+} |
1810 |
+ |
1811 |
+src_prepare() { |
1812 |
+ # apply maintenance-patches |
1813 |
+ ebegin "Changing paths for gentoo" |
1814 |
+ |
1815 |
+ local DVBDIR=/usr/include |
1816 |
+ local i |
1817 |
+ for i in ${DVB_HEADER_PATH} /usr/include/v4l-dvb-hg /usr/include; do |
1818 |
+ [[ -d ${i} ]] || continue |
1819 |
+ if [[ -f ${i}/linux/dvb/dmx.h ]]; then |
1820 |
+ einfo "Found DVB header files in ${i}" |
1821 |
+ DVBDIR=${i} |
1822 |
+ break |
1823 |
+ fi |
1824 |
+ done |
1825 |
+ |
1826 |
+ # checking for s2api headers |
1827 |
+ local api_version |
1828 |
+ api_version=$(awk -F' ' '/define DVB_API_VERSION / {print $3}' "${DVBDIR}"/linux/dvb/version.h) |
1829 |
+ api_version=${api_version}*$(awk -F' ' '/define DVB_API_VERSION_MINOR / {print $3}' "${DVBDIR}"/linux/dvb/version.h) |
1830 |
+ |
1831 |
+ if [[ ${api_version:-0} -lt 5*3 ]]; then |
1832 |
+ eerror "DVB header files do not contain s2api support or too old for ${P}" |
1833 |
+ eerror "You cannot compile VDR against old dvb-header" |
1834 |
+ die "DVB headers too old" |
1835 |
+ fi |
1836 |
+ |
1837 |
+ cat > Make.config <<-EOT || die "cannot write to Make.config" |
1838 |
+ # |
1839 |
+ # Generated by ebuild ${PF} |
1840 |
+ # |
1841 |
+ PREFIX = /usr |
1842 |
+ DVBDIR = ${DVBDIR} |
1843 |
+ PLUGINLIBDIR = ${PLUGIN_LIBDIR} |
1844 |
+ CONFDIR = ${CONF_DIR} |
1845 |
+ ARGSDIR = \$(CONFDIR)/conf.d |
1846 |
+ VIDEODIR = ${VIDEO_DIR} |
1847 |
+ LOCDIR = \$(PREFIX)/share/locale |
1848 |
+ INCDIR = \$(PREFIX)/include |
1849 |
+ |
1850 |
+ DEFINES += -DCONFDIR=\"\$(CONFDIR)\" |
1851 |
+ INCLUDES += -I\$(DVBDIR) |
1852 |
+ |
1853 |
+ # >=vdr-1.7.36-r1; parameter only used for compiletime on vdr |
1854 |
+ # PLUGINLIBDIR (plugin Makefile old) = LIBDIR (plugin Makefile new) |
1855 |
+ LIBDIR = ${PLUGIN_LIBDIR} |
1856 |
+ PCDIR = /usr/$(get_libdir)/pkgconfig |
1857 |
+ |
1858 |
+ EOT |
1859 |
+ eend 0 |
1860 |
+ |
1861 |
+ eapply "${FILESDIR}/${PN}-2.4.6_gentoo.patch" |
1862 |
+ use demoplugins || eapply "${FILESDIR}/vdr-2.4_remove_plugins.patch" |
1863 |
+ eapply "${FILESDIR}/${PN}-2.4.6_makefile-variables.patch" |
1864 |
+ |
1865 |
+ # fix clang/LLVM compile |
1866 |
+ eapply "${FILESDIR}/${PN}-2.4.6_clang.patch" |
1867 |
+ |
1868 |
+ use naludump && eapply "${FILESDIR}/${P}_naludump.patch" |
1869 |
+ use permashift && eapply "${FILESDIR}/${P}-patch-for-permashift.patch" |
1870 |
+ use pinplugin && eapply "${FILESDIR}/${P}_pinplugin.patch" |
1871 |
+ use ttxtsubs && eapply "${DISTDIR}/${P}_ttxtsubs_v2.patch" |
1872 |
+ use menuorg && eapply "${DISTDIR}/vdr-menuorg-2.3.x.diff" |
1873 |
+ use mainmenuhooks && eapply "${FILESDIR}/${PN}-2.4.1_mainmenuhook-1.0.1.patch" |
1874 |
+ |
1875 |
+ add_cap CAP_UTF8 \ |
1876 |
+ CAP_IRCTRL_RUNTIME_PARAM \ |
1877 |
+ CAP_VFAT_RUNTIME_PARAM \ |
1878 |
+ CAP_CHUID \ |
1879 |
+ CAP_SHUTDOWN_AUTO_RETRY |
1880 |
+ |
1881 |
+ echo -e ${CAPS} > "${CAP_FILE}" || die "cannot write to CAP_FILE" |
1882 |
+ |
1883 |
+ # LINGUAS support |
1884 |
+ einfo "\n \t VDR supports the LINGUAS values" |
1885 |
+ |
1886 |
+ lang_po |
1887 |
+ |
1888 |
+ einfo "\t Please set one of this values in your sytem make.conf" |
1889 |
+ einfo "\t LINGUAS=\"${LING_PO}\"\n" |
1890 |
+ |
1891 |
+ if [[ -z ${LINGUAS} ]]; then |
1892 |
+ einfo "\n \t No values in LINGUAS=" |
1893 |
+ einfo "\t You will get only english text on OSD \n" |
1894 |
+ fi |
1895 |
+ |
1896 |
+ strip-linguas ${LING_PO} en |
1897 |
+ |
1898 |
+ default |
1899 |
+} |
1900 |
+ |
1901 |
+src_configure() { |
1902 |
+ # support languages, written from right to left |
1903 |
+ export "BIDI=$(usex bidi 1 0)" |
1904 |
+ # systemd notification support |
1905 |
+ export "SDNOTIFY=$(usex systemd 1 0)" |
1906 |
+ # with/without keyboard |
1907 |
+ export "USE_KBD=$(usex keyboard 1 0)" |
1908 |
+ # detailed compile output for debug |
1909 |
+ export "VERBOSE=$(usex verbose 1 0)" |
1910 |
+} |
1911 |
+ |
1912 |
+src_install() { |
1913 |
+ # trick the makefile to not create a VIDEODIR by supplying it with an |
1914 |
+ # existing directory |
1915 |
+ emake VIDEODIR="/" DESTDIR="${ED}" install |
1916 |
+ |
1917 |
+ keepdir "${PLUGIN_LIBDIR}" |
1918 |
+ |
1919 |
+ # backup for plugins they don't be able to create this dir |
1920 |
+ keepdir "${CONF_DIR}/plugins" |
1921 |
+ |
1922 |
+ if use html; then |
1923 |
+ local HTML_DOCS=( *.html ) |
1924 |
+ fi |
1925 |
+ local DOCS=( MANUAL INSTALL README* HISTORY CONTRIBUTORS UPDATE-2* ) |
1926 |
+ einstalldocs |
1927 |
+ |
1928 |
+ insinto /usr/share/vdr |
1929 |
+ doins "${CAP_FILE}" |
1930 |
+ |
1931 |
+ fowners vdr:vdr "${CONF_DIR}" -R |
1932 |
+} |
1933 |
+ |
1934 |
+pkg_postinst() { |
1935 |
+ elog "Please read the /usr/share/doc/${PF}/UPDATE-2.4" |
1936 |
+ elog "for major changes in this version\n" |
1937 |
+ |
1938 |
+ elog "It is a good idea to run vdrplugin-rebuild now.\n" |
1939 |
+ |
1940 |
+ elog "To get nice symbols in OSD we recommend to install" |
1941 |
+ elog "\t1. emerge media-fonts/vdrsymbols-ttf" |
1942 |
+ elog "\t2. select font VDRSymbolsSans in Setup\n" |
1943 |
+ |
1944 |
+ elog "To get an idea how to proceed now, have a look at our vdr-guide:" |
1945 |
+ elog "\thttps://wiki.gentoo.org/wiki/VDR" |
1946 |
+} |