[vdr] Update to 1.7.29.
Ville Skyttä
scop at fedoraproject.org
Wed Jul 18 20:22:54 UTC 2012
commit d512308c9d5c2a370110cd767f3c543e9f0d2a2b
Author: Ville Skyttä <ville.skytta at iki.fi>
Date: Wed Jul 18 23:22:34 2012 +0300
Update to 1.7.29.
.gitignore | 1 -
sources | 7 +-
vdr-1.7.28-epghandledexternally.diff | 118 ----
vdr-1.7.29-hlcutter-0.2.3.diff | 1228 ++++++++++++++++++++++++++++++++++
vdr.spec | 16 +-
5 files changed, 1239 insertions(+), 131 deletions(-)
---
diff --git a/.gitignore b/.gitignore
index 98dfeb2..c4cc295 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,4 +4,3 @@
/vdr-1.7.21-ttxtsubs.patch
/vdr-timer-info-0.5-1.7.13.diff
/vdr.epgsearch-exttimeredit-0.0.2.diff
-/vdr-1.7.27-hlcutter-0.2.3.diff
diff --git a/sources b/sources
index 09daafe..c1d32be 100644
--- a/sources
+++ b/sources
@@ -4,7 +4,6 @@ fae3698214bd45de1f675c2b037d5f3b vdr-1.7.21-ttxtsubs.patch
04511ae02243eb1bab94f3f45b59e574 vdr-timer-info-0.5-1.7.13.diff
71f7281d55eba1957f4267f596b11e29 vdr.epgsearch-exttimeredit-0.0.2.diff
d40db7bea1b9af94d7625e611ef3dae2 vdr_1.7.23-1.debian.tar.bz2
-ef7a35dc23c5ed700e1ce873274f7793 vdr-1.7.27-hlcutter-0.2.3.diff
-bed5d492fa7faf2065f6b2cc44e841a3 vdr-1.7.28-vasarajanauloja.patch.gz
-a086781712c57ab6c255035201fb508b vdr-1.7.28-finnish.patch.gz
-3ccff2dcc42d112e23dd64f2c39f02f1 vdr-1.7.28.tar.bz2
+1c90e06b1de3961f901b9c35c00e51c2 vdr-1.7.29-finnish.patch.gz
+a53fe4b858611d8c21afebe7d5e03a6c vdr-1.7.29-vasarajanauloja.patch.gz
+a3f0ae42ba456aa1865c9ed065a64d80 vdr-1.7.29.tar.bz2
diff --git a/vdr-1.7.29-hlcutter-0.2.3.diff b/vdr-1.7.29-hlcutter-0.2.3.diff
new file mode 100644
index 0000000..5d49647
--- /dev/null
+++ b/vdr-1.7.29-hlcutter-0.2.3.diff
@@ -0,0 +1,1228 @@
+diff -Nru vdr-1.7.29/config.c vdr-1.7.29-hlcutter/config.c
+--- vdr-1.7.29/config.c 2012-06-17 15:27:07.000000000 +0300
++++ vdr-1.7.29-hlcutter/config.c 2012-07-16 17:47:24.632631338 +0300
+@@ -446,8 +446,10 @@
+ FontSmlSize = 18;
+ FontFixSize = 20;
+ MaxVideoFileSize = MAXVIDEOFILESIZEDEFAULT;
++ MaxRecordingSize = DEFAULTRECORDINGSIZE;
+ SplitEditedFiles = 0;
+ DelTimeshiftRec = 0;
++ HardLinkCutter = 0;
+ MinEventTimeout = 30;
+ MinUserInactivity = 300;
+ NextWakeupTime = 0;
+@@ -642,8 +644,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);
+@@ -741,8 +745,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 -Nru vdr-1.7.29/config.h vdr-1.7.29-hlcutter/config.h
+--- vdr-1.7.29/config.h 2012-06-17 14:14:50.000000000 +0300
++++ vdr-1.7.29-hlcutter/config.h 2012-07-16 17:47:24.635631290 +0300
+@@ -310,8 +310,10 @@
+ int FontSmlSize;
+ int FontFixSize;
+ int MaxVideoFileSize;
++ int MaxRecordingSize;
+ int SplitEditedFiles;
+ int DelTimeshiftRec;
++ int HardLinkCutter;
+ int MinEventTimeout, MinUserInactivity;
+ time_t NextWakeupTime;
+ int MultiSpeedMode;
+diff -Nru vdr-1.7.29/cutter.c vdr-1.7.29-hlcutter/cutter.c
+--- vdr-1.7.29/cutter.c 2012-06-10 17:33:36.000000000 +0300
++++ vdr-1.7.29-hlcutter/cutter.c 2012-07-16 17:47:24.626631359 +0300
+@@ -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();
+@@ -100,13 +101,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) {
+@@ -123,19 +204,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";
+@@ -159,7 +233,7 @@
+ }
+ CheckForSeamlessStream = false;
+ }
+- if (cutIn) {
++ if (!SkipThisSourceFile && cutIn) {
+ if (isPesRecording)
+ cRemux::SetBrokenLink(buffer, Length);
+ else
+@@ -167,7 +241,7 @@
+ cutIn = false;
+ }
+ }
+- if (toFile->Write(buffer, Length) < 0) {
++ if (!SkipThisSourceFile && toFile->Write(buffer, Length) < 0) {
+ error = "safe_write";
+ break;
+ }
+@@ -212,7 +286,7 @@
+ }
+ }
+ else
+- LastMark = true;
++ LastMark = true; // After last cut-out: Write on until next I-frame, then exit
+ }
+ }
+ Recordings.TouchUpdate();
+diff -Nru vdr-1.7.29/menu.c vdr-1.7.29-hlcutter/menu.c
+--- vdr-1.7.29/menu.c 2012-06-17 14:12:25.000000000 +0300
++++ vdr-1.7.29-hlcutter/menu.c 2012-07-16 17:47:24.638631250 +0300
+@@ -3111,8 +3111,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 -Nru vdr-1.7.29/po/de_DE.po vdr-1.7.29-hlcutter/po/de_DE.po
+--- vdr-1.7.29/po/de_DE.po 2012-06-17 15:00:25.000000000 +0300
++++ vdr-1.7.29-hlcutter/po/de_DE.po 2012-07-16 17:47:24.645631154 +0300
+@@ -1068,12 +1068,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 -Nru vdr-1.7.29/po/fi_FI.po vdr-1.7.29-hlcutter/po/fi_FI.po
+--- vdr-1.7.29/po/fi_FI.po 2012-06-17 14:59:42.000000000 +0300
++++ vdr-1.7.29-hlcutter/po/fi_FI.po 2012-07-16 17:47:24.651631074 +0300
+@@ -1071,12 +1071,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 -Nru vdr-1.7.29/README-HLCUTTER vdr-1.7.29-hlcutter/README-HLCUTTER
+--- vdr-1.7.29/README-HLCUTTER 1970-01-01 02:00:00.000000000 +0200
++++ vdr-1.7.29-hlcutter/README-HLCUTTER 2012-07-16 17:46:54.286042815 +0300
+@@ -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 at 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 -Nru vdr-1.7.29/recorder.c vdr-1.7.29-hlcutter/recorder.c
+--- vdr-1.7.29/recorder.c 2011-09-04 12:26:44.000000000 +0300
++++ vdr-1.7.29-hlcutter/recorder.c 2012-07-16 17:47:24.654631032 +0300
+@@ -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 -Nru vdr-1.7.29/recording.c vdr-1.7.29-hlcutter/recording.c
+--- vdr-1.7.29/recording.c 2012-06-09 16:57:30.000000000 +0300
++++ vdr-1.7.29-hlcutter/recording.c 2012-07-16 17:47:24.657630993 +0300
+@@ -2087,6 +2087,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 -Nru vdr-1.7.29/recording.h vdr-1.7.29-hlcutter/recording.h
+--- vdr-1.7.29/recording.h 2012-06-09 16:55:22.000000000 +0300
++++ vdr-1.7.29-hlcutter/recording.h 2012-07-16 17:47:24.660630952 +0300
+@@ -259,9 +259,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;
+
+@@ -314,6 +322,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 -Nru vdr-1.7.29/vdr-1.7.27-hlcutter-0.2.3.diff vdr-1.7.29-hlcutter/vdr-1.7.27-hlcutter-0.2.3.diff
+--- vdr-1.7.29/vdr-1.7.27-hlcutter-0.2.3.diff 1970-01-01 02:00:00.000000000 +0200
++++ vdr-1.7.29-hlcutter/vdr-1.7.27-hlcutter-0.2.3.diff 2012-04-02 21:42:11.000000000 +0300
+@@ -0,0 +1,612 @@
++diff -Naur vdr-1.7.27/config.c vdr-1.7.27-hlcutter/config.c
++--- vdr-1.7.27/config.c 2012-02-29 11:15:54.000000000 +0100
+++++ vdr-1.7.27-hlcutter/config.c 2012-03-31 13:25:56.000000000 +0200
++@@ -445,8 +445,10 @@
++ FontSmlSize = 18;
++ FontFixSize = 20;
++ MaxVideoFileSize = MAXVIDEOFILESIZEDEFAULT;
+++ MaxRecordingSize = DEFAULTRECORDINGSIZE;
++ SplitEditedFiles = 0;
++ DelTimeshiftRec = 0;
+++ HardLinkCutter = 0;
++ MinEventTimeout = 30;
++ MinUserInactivity = 300;
++ NextWakeupTime = 0;
++@@ -639,8 +641,10 @@
++ else if (!strcasecmp(Name, "FontSmlSize")) FontSmlSize = atoi(Value);
++ else if (!strcasecmp(Name, "FontFixSize")) FontFixSize = atoi(Value);
++ else if (!strcasecmp(Name, "MaxVideoFileSize")) MaxVideoFileSize = atoi(Value);
+++ else if (!strcasecmp(Name, "MaxRecordingSize")) MaxRecordingSize = atoi(Value);
++ else if (!strcasecmp(Name, "SplitEditedFiles")) SplitEditedFiles = atoi(Value);
++ else if (!strcasecmp(Name, "DelTimeshiftRec")) DelTimeshiftRec = atoi(Value);
+++ else if (!strcasecmp(Name, "HardLinkCutter")) HardLinkCutter = atoi(Value);
++ else if (!strcasecmp(Name, "MinEventTimeout")) MinEventTimeout = atoi(Value);
++ else if (!strcasecmp(Name, "MinUserInactivity")) MinUserInactivity = atoi(Value);
++ else if (!strcasecmp(Name, "NextWakeupTime")) NextWakeupTime = atoi(Value);
++@@ -736,8 +740,10 @@
++ Store("FontSmlSize", FontSmlSize);
++ Store("FontFixSize", FontFixSize);
++ Store("MaxVideoFileSize", MaxVideoFileSize);
+++ Store("MaxRecordingSize", MaxRecordingSize);
++ Store("SplitEditedFiles", SplitEditedFiles);
++ Store("DelTimeshiftRec", DelTimeshiftRec);
+++ Store("HardLinkCutter", HardLinkCutter);
++ Store("MinEventTimeout", MinEventTimeout);
++ Store("MinUserInactivity", MinUserInactivity);
++ Store("NextWakeupTime", NextWakeupTime);
++diff -Naur vdr-1.7.27/config.h vdr-1.7.27-hlcutter/config.h
++--- vdr-1.7.27/config.h 2012-03-11 11:41:44.000000000 +0100
+++++ vdr-1.7.27-hlcutter/config.h 2012-03-31 13:25:56.000000000 +0200
++@@ -299,8 +299,10 @@
++ int FontSmlSize;
++ int FontFixSize;
++ int MaxVideoFileSize;
+++ int MaxRecordingSize;
++ int SplitEditedFiles;
++ int DelTimeshiftRec;
+++ int HardLinkCutter;
++ int MinEventTimeout, MinUserInactivity;
++ time_t NextWakeupTime;
++ int MultiSpeedMode;
++diff -Naur vdr-1.7.27/cutter.c vdr-1.7.27-hlcutter/cutter.c
++--- vdr-1.7.27/cutter.c 2012-02-16 13:08:39.000000000 +0100
+++++ vdr-1.7.27-hlcutter/cutter.c 2012-03-31 13:26:51.000000000 +0200
++@@ -80,6 +80,7 @@
++ Mark = fromMarks.Next(Mark);
++ off_t FileSize = 0;
++ int CurrentFileNumber = 0;
+++ bool SkipThisSourceFile = false;
++ int LastIFrame = 0;
++ toMarks.Add(0);
++ toMarks.Save();
++@@ -98,13 +99,93 @@
++
++ // Read one frame:
++
++- if (fromIndex->Get(Index++, &FileNumber, &FileOffset, &Independent, &Length)) {
++- if (FileNumber != CurrentFileNumber) {
++- fromFile = fromFileName->SetOffset(FileNumber, FileOffset);
++- if (fromFile)
++- fromFile->SetReadAhead(MEGABYTE(20));
++- CurrentFileNumber = FileNumber;
++- }
+++ if (!fromIndex->Get(Index++, &FileNumber, &FileOffset, &Independent, &Length)) {
+++ // Error, unless we're past last cut-in and there's no cut-out
+++ if (Mark || LastMark)
+++ error = "index";
+++ break;
+++ }
+++
+++ if (FileNumber != CurrentFileNumber) {
+++ fromFile = fromFileName->SetOffset(FileNumber, FileOffset);
+++ if (fromFile)
+++ fromFile->SetReadAhead(MEGABYTE(20));
+++ CurrentFileNumber = FileNumber;
+++ if (SkipThisSourceFile) {
+++ // At end of fast forward: Always skip to next file
+++ toFile = toFileName->NextFile();
+++ if (!toFile) {
+++ error = "toFile 4";
+++ break;
+++ }
+++ FileSize = 0;
+++ SkipThisSourceFile = false;
+++ }
+++
+++
+++ if (Setup.HardLinkCutter && FileOffset == 0) {
+++ // We are at the beginning of a new source file.
+++ // Do we need to copy the whole file?
+++
+++ // if !Mark && LastMark, then we're past the last cut-out and continue to next I-frame
+++ // if !Mark && !LastMark, then there's just a cut-in, but no cut-out
+++ // if Mark, then we're between a cut-in and a cut-out
+++
+++ uint16_t MarkFileNumber;
+++ off_t MarkFileOffset;
+++ // Get file number of next cut mark
+++ if (!Mark && !LastMark
+++ || Mark
+++ && fromIndex->Get(Mark->Position(), &MarkFileNumber, &MarkFileOffset)
+++ && (MarkFileNumber != CurrentFileNumber)) {
+++ // The current source file will be copied completely.
+++ // Start new output file unless we did that already
+++ if (FileSize != 0) {
+++ toFile = toFileName->NextFile();
+++ if (!toFile) {
+++ error = "toFile 3";
+++ break;
+++ }
+++ FileSize = 0;
+++ }
+++
+++ // Safety check that file has zero size
+++ struct stat buf;
+++ if (stat(toFileName->Name(), &buf) == 0) {
+++ if (buf.st_size != 0) {
+++ esyslog("cCuttingThread: File %s exists and has nonzero size", toFileName->Name());
+++ error = "nonzero file exist";
+++ break;
+++ }
+++ }
+++ else if (errno != ENOENT) {
+++ esyslog("cCuttingThread: stat failed on %s", toFileName->Name());
+++ error = "stat";
+++ break;
+++ }
+++
+++ // Clean the existing 0-byte file
+++ toFileName->Close();
+++ cString ActualToFileName(ReadLink(toFileName->Name()), true);
+++ unlink(ActualToFileName);
+++ unlink(toFileName->Name());
+++
+++ // Try to create a hard link
+++ if (HardLinkVideoFile(fromFileName->Name(), toFileName->Name())) {
+++ // Success. Skip all data transfer for this file
+++ SkipThisSourceFile = true;
+++ cutIn = false;
+++ toFile = NULL; // was deleted by toFileName->Close()
+++ }
+++ else {
+++ // Fallback: Re-open the file if necessary
+++ toFile = toFileName->Open();
+++ }
+++ }
+++ }
+++ }
+++
+++ if (!SkipThisSourceFile) {
++ if (fromFile) {
++ int len = ReadFrame(fromFile, buffer, Length, sizeof(buffer));
++ if (len < 0) {
++@@ -121,19 +202,12 @@
++ break;
++ }
++ }
++- else {
++- // Error, unless we're past the last cut-in and there's no cut-out
++- if (Mark || LastMark)
++- error = "index";
++- break;
++- }
++-
++ // Write one frame:
++
++ if (Independent) { // every file shall start with an independent frame
++ if (LastMark) // edited version shall end before next I-frame
++ break;
++- if (FileSize > maxVideoFileSize) {
+++ if (!SkipThisSourceFile && FileSize > toFileName->MaxFileSize()) {
++ toFile = toFileName->NextFile();
++ if (!toFile) {
++ error = "toFile 1";
++@@ -143,7 +217,7 @@
++ }
++ LastIFrame = 0;
++
++- 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 at 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);
+diff -Nru vdr-1.7.29/videodir.c vdr-1.7.29-hlcutter/videodir.c
+--- vdr-1.7.29/videodir.c 2012-06-10 16:45:21.000000000 +0300
++++ vdr-1.7.29-hlcutter/videodir.c 2012-07-16 17:47:24.663630910 +0300
+@@ -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 -Nru vdr-1.7.29/videodir.h vdr-1.7.29-hlcutter/videodir.h
+--- vdr-1.7.29/videodir.h 2012-04-22 18:07:56.000000000 +0300
++++ vdr-1.7.29-hlcutter/videodir.h 2012-07-16 17:47:24.665630884 +0300
+@@ -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);
diff --git a/vdr.spec b/vdr.spec
index 3d6a262..836011f 100644
--- a/vdr.spec
+++ b/vdr.spec
@@ -25,7 +25,7 @@
%global migrfile %{_var}/run/systemd-migr_%{name}-%{version}-%{release}.%{_arch}
Name: vdr
-Version: 1.7.28
+Version: 1.7.29
Release: 1%{?dist}
Summary: Video Disk Recorder
@@ -54,7 +54,7 @@ Source19: %{name}-check-setup.sh
Source20: %{name}-rcu.conf
Patch0: %{name}-channel+epg.patch
Patch1: http://zap.tartarus.org/~ds/debian/dists/stable/main/source/vdr_1.4.5-2.ds.diff.gz
-Patch2: http://www.saunalahti.fi/~rahrenbe/vdr/patches/vdr-1.7.28-vasarajanauloja.patch.gz
+Patch2: http://www.saunalahti.fi/~rahrenbe/vdr/patches/vdr-1.7.29-vasarajanauloja.patch.gz
# Extracted from http://copperhead.htpc-forum.de/downloads/extensionpatch/extpngvdr1.7.21v1.diff.gz
Patch3: %{name}-1.7.21-plugin-missing.patch
Patch4: %{name}-1.7.22-paths.patch
@@ -66,7 +66,7 @@ Patch7: http://projects.vdr-developer.org/projects/plg-ttxtsubs/reposito
# Original at http://toms-cafe.de/vdr/download/vdr-jumpplay-1.0-1.7.6.diff
Patch8: %{name}-1.7.28-vasarajanauloja-jumpplay.patch
# http://www.udo-richter.de/vdr/patches.en.html#hlcutter
-Patch9: http://www.udo-richter.de/vdr/files/vdr-1.7.27-hlcutter-0.2.3.diff
+Patch9: %{name}-1.7.29-hlcutter-0.2.3.diff
Patch10: %{name}-1.7.27-libhdffcmd-cflags.patch
# http://article.gmane.org/gmane.linux.vdr/43590
Patch11: %{name}-1.7.25-mainmenuhooks101.patch
@@ -74,15 +74,13 @@ Patch11: %{name}-1.7.25-mainmenuhooks101.patch
# Modified so that it applies over the timer-info patch
Patch12: %{name}-1.7.21-timercmd.patch
Patch13: http://projects.vdr-developer.org/git/vdr-plugin-epgsearch.git/plain/patches/vdr-1.5.17-progressbar-support-0.0.1.diff
-Patch14: http://www.saunalahti.fi/~rahrenbe/vdr/patches/vdr-1.7.28-finnish.patch.gz
+Patch14: http://www.saunalahti.fi/~rahrenbe/vdr/patches/vdr-1.7.29-finnish.patch.gz
Patch15: %{name}-1.7.21-fedora-pkgconfig.patch
Patch16: %{name}-1.7.21-jumpplay-finnish.patch
Patch17: http://projects.vdr-developer.org/git/vdr-plugin-epgsearch.git/plain/patches/vdr.epgsearch-exttimeredit-0.0.2.diff
Patch18: %{name}-timer-info-1.7.28.patch
# http://projects.vdr-developer.org/issues/819
Patch19: %{name}-1.7.22-ttxtsubs-on.patch
-# http://www.linuxtv.org/pipermail/vdr/2012-June/026400.html
-Patch20: %{name}-1.7.28-epghandledexternally.diff
BuildRequires: libjpeg-devel
BuildRequires: libcap-devel
@@ -201,7 +199,7 @@ sed \
# TODO: does not apply
#patch6 -p0
%patch7 -p1 -F 2
-%patch8 -p1
+%patch8 -p1 -F 2
%patch9 -p1
%patch10 -p1
%patch11 -p1
@@ -215,7 +213,6 @@ sed \
#patch17 -p0 -F 3
%patch18 -p1
%patch19 -p1
-%patch20 -p1
for f in CONTRIBUTORS HISTORY UPDATE-1.4.0 README.timer-info ; do
iconv -f iso-8859-1 -t utf-8 -o $f.utf8 $f && mv $f.utf8 $f
@@ -552,6 +549,9 @@ rm -f %{migrfile} &>/dev/null || :
%changelog
+* Wed Jul 18 2012 Ville Skyttä <ville.skytta at iki.fi> - 1.7.29-1
+- Update to 1.7.29.
+
* Wed Jun 27 2012 Ville Skyttä <ville.skytta at iki.fi> - 1.7.28-1
- Update to 1.7.28.
- Add softhdddevice to sysconfig's VDR_PLUGIN_ORDER.
More information about the scm-commits
mailing list