#! /bin/sh /usr/share/dpatch/dpatch-run ## opt-24_jumpplay-0.9.dpatch by Torsten Kunkel , Thomas Günther ## http://toms-cafe.de/vdr/download/vdr-jumpplay-0.9-1.4.0.diff (applicable to VDR >= 1.3.35) ## ## All lines beginning with `## DP:' are a description of the patch. ## DP: Play after jump to next mark. Automatically jump over commercial breaks. ## DP: See README.jumpplay and MANUAL for details. @DPATCH@ diff -Naur vdr-1.4.0/MANUAL vdr-1.4.0-jumpplay-0.9/MANUAL --- vdr-1.4.0/MANUAL 2006-04-28 15:07:08.000000000 +0200 +++ vdr-1.4.0-jumpplay-0.9/MANUAL 2006-05-28 00:18:51.000000000 +0200 @@ -767,6 +767,30 @@ 0 resulting in a file named 'resume.vdr', and any other value resulting in 'resume.n.vdr'. + Jump&Play = no Turns playing on or off after jumping forward to the + next editing mark with the '9' key. + + Play&Jump = no Turns automatic jumping over commercial breaks on or + off. This includes jumping to the first mark, if the + replay starts at the beginning of a recording - and + stopping the replay at the last mark. + With this setting enabled, the behaviour of the '8' + key during replay is changed too. It moves the actual + replay position not only three seconds before the + next "start" mark, but also before the next "end" + mark. This can be used to test, if the editing marks + are correctly positioned for a "smooth" jump over a + commercial break. + + Pause at last mark = no + Turns pausing of replay at the last editing mark on or + off. + + Reload marks = no Turns reloading of editing marks on or off. This can + be used if an external programme adjusts the editing + marks, e.g. noad in online mode. The marks are reloaded + in 10 seconds intervals. + Miscellaneous: Min. event timeout = 30 diff -Naur vdr-1.4.0/README.jumpplay vdr-1.4.0-jumpplay-0.9/README.jumpplay --- vdr-1.4.0/README.jumpplay 1970-01-01 01:00:00.000000000 +0100 +++ vdr-1.4.0-jumpplay-0.9/README.jumpplay 2006-05-28 00:29:42.000000000 +0200 @@ -0,0 +1,87 @@ +JumpPlay patch for VDR +---------------------- + +This patch changes the replay behaviour for recordings that contain editing +marks. It allows to immediately continue the replay after jumping forward to +the next mark, and to automatically jump over the commercial break to the next +"start" mark, if an "end" mark is reached. + +The features of this patch can be turned on or off with parameters in the replay +setup. See MANUAL for description of this parameters: "Jump&Play", "Play&Jump", +"Pause at last mark" and "Reload marks". + + +* History + + 2003-07-04: jumpandrun.diff - the Noad + Jump&Play + + 2003-12-06: Version 0.0 - Torsten Kunkel + Play&Jump (only if progressbar is visible) + Setup parameters Jump&Play and Play&Jump in the replay setup + + 2004-01-20: Version 0.1 - Thomas Günther + Jump&Play: + - fixed speed after jump + - fixed removing of marks + Play&Jump: + - jump only on "end" marks + + 2004-01-27: Version 0.2 - Thomas Günther + Jump&Play: + - fixed double jump + Play&Jump: + - fixed mark detection: fuzzy detection (until 3 seconds after mark) + - jump without progressbar + - mode "progressbar only" for old behaviour + + 2004-01-31: Version 0.3 - Thomas Günther + Jump&Play: + - fixed display frames + Play&Jump: + - fixed end of playing at last mark + + 2004-07-11: Version 0.4 - Thomas Günther + Jump&Play: + - don't play after jump to end + Play&Jump: + - don't prevent jumping after hide or show + Less conflicts with other patches (Elchi/AutoPID) + + 2004-08-21: Version 0.5 - Thomas Günther + Play&Jump: + - exact jumps, replay like edited recording (no fuzzy mark detection) + - jump to first mark if replay starts at the beginning + - check jump marks with '8' key + - mode "progressbar only" removed + Description in README.jumpplay + + 2004-12-28: Version 0.6 - Thomas Günther + Adapted noad extensions (from the Noad ) to + jumpplay-0.5: + - cyclic reloading of marks found by noad online-scan + - don't stop after the last mark in case of live-recordings + New setup parameter "Load marks interval (s)" + Updated description in README.jumpplay + + 2006-04-14: Version 0.7 - Thomas Günther + Fixed jump to first mark (crashed with plugin extrecmenu-0.9) + Added version define JUMPPLAYVERSNUM + Added placeholders for Czech language texts + Cleaned up i18n entries (support only VDR >= 1.3.29) + Improved description of i18n placeholders - hoping for real language texts + + 2006-05-12: Version 0.8 - Thomas Günther + Fixed segfault in dvbplayer thread while the replaycontrol thread is + reloading the marks (thanks to horchi at vdrportal.de for reporting this - + see http://vdrportal.de/board/thread.php?postid=450463#post450463): + New class cMarksReload checks the timestamp of marks.vdr in 10 seconds + intervals, so the marks in the threads dvbplayer and replaycontrol can be + reloaded independently + Changed setup parameter "Load marks interval (s)" to "Reload marks" + Updated description in README.jumpplay + + 2006-05-28: Version 0.9 - Thomas Günther + New setup parameter "Pause at last mark" + Updated description in README.jumpplay + Moved parameters description to MANUAL diff -Naur vdr-1.4.0/config.c vdr-1.4.0-jumpplay-0.9/config.c --- vdr-1.4.0/config.c 2006-04-17 14:43:57.000000000 +0200 +++ vdr-1.4.0-jumpplay-0.9/config.c 2006-05-28 15:03:01.000000000 +0200 @@ -268,6 +268,10 @@ MultiSpeedMode = 0; ShowReplayMode = 0; ResumeID = 0; + JumpPlay = 0; + PlayJump = 0; + PauseLastMark = 0; + ReloadMarks = 0; CurrentChannel = -1; CurrentVolume = MAXVOLUME; CurrentDolby = 0; @@ -429,6 +433,10 @@ else if (!strcasecmp(Name, "MultiSpeedMode")) MultiSpeedMode = atoi(Value); else if (!strcasecmp(Name, "ShowReplayMode")) ShowReplayMode = atoi(Value); else if (!strcasecmp(Name, "ResumeID")) ResumeID = atoi(Value); + else if (!strcasecmp(Name, "JumpPlay")) JumpPlay = atoi(Value); + else if (!strcasecmp(Name, "PlayJump")) PlayJump = atoi(Value); + else if (!strcasecmp(Name, "PauseLastMark")) PauseLastMark = atoi(Value); + else if (!strcasecmp(Name, "ReloadMarks")) ReloadMarks = atoi(Value); else if (!strcasecmp(Name, "CurrentChannel")) CurrentChannel = atoi(Value); else if (!strcasecmp(Name, "CurrentVolume")) CurrentVolume = atoi(Value); else if (!strcasecmp(Name, "CurrentDolby")) CurrentDolby = atoi(Value); @@ -497,6 +505,10 @@ Store("MultiSpeedMode", MultiSpeedMode); Store("ShowReplayMode", ShowReplayMode); Store("ResumeID", ResumeID); + Store("JumpPlay", JumpPlay); + Store("PlayJump", PlayJump); + Store("PauseLastMark", PauseLastMark); + Store("ReloadMarks", ReloadMarks); Store("CurrentChannel", CurrentChannel); Store("CurrentVolume", CurrentVolume); Store("CurrentDolby", CurrentDolby); diff -Naur vdr-1.4.0/config.h vdr-1.4.0-jumpplay-0.9/config.h --- vdr-1.4.0/config.h 2006-04-29 11:24:07.000000000 +0200 +++ vdr-1.4.0-jumpplay-0.9/config.h 2006-05-28 15:03:01.000000000 +0200 @@ -35,6 +35,8 @@ // plugins to work with newer versions of the core VDR as long as no // VDR header files have changed. +#define JUMPPLAYVERSNUM 9 + #define MAXPRIORITY 99 #define MAXLIFETIME 99 @@ -247,6 +249,10 @@ int MultiSpeedMode; int ShowReplayMode; int ResumeID; + int JumpPlay; + int PlayJump; + int PauseLastMark; + int ReloadMarks; int CurrentChannel; int CurrentVolume; int CurrentDolby; diff -Naur vdr-1.4.0/dvbplayer.c vdr-1.4.0-jumpplay-0.9/dvbplayer.c --- vdr-1.4.0/dvbplayer.c 2006-04-17 14:45:48.000000000 +0200 +++ vdr-1.4.0-jumpplay-0.9/dvbplayer.c 2006-05-28 19:13:25.000000000 +0200 @@ -193,6 +193,7 @@ cNonBlockingFileReader *nonBlockingFileReader; cRingBufferFrame *ringBuffer; cBackTrace *backTrace; + cMarksReload marks; cFileName *fileName; cIndexFile *index; cUnbufferedFile *replayFile; @@ -234,7 +235,7 @@ int cDvbPlayer::Speeds[] = { 0, -2, -4, -8, 1, 2, 4, 12, 0 }; cDvbPlayer::cDvbPlayer(const char *FileName) -:cThread("dvbplayer") +:cThread("dvbplayer"), marks(FileName) { nonBlockingFileReader = NULL; ringBuffer = NULL; @@ -368,11 +369,26 @@ uchar *b = NULL; uchar *p = NULL; int pc = 0; + bool cutIn = false; + int total = -1; readIndex = Resume(); if (readIndex >= 0) isyslog("resuming replay at index %d (%s)", readIndex, *IndexToHMSF(readIndex, true)); + if (Setup.PlayJump && readIndex <= 0 && marks.First() && index) { + int Index = marks.First()->position; + uchar FileNumber; + int FileOffset; + if (index->Get(Index, &FileNumber, &FileOffset) && + NextFile(FileNumber, FileOffset)) { + isyslog("PlayJump: start replay at first mark %d (%s)", + Index, *IndexToHMSF(Index, true)); + readIndex = Index; + } + } + + bool LastMarkPause = false; nonBlockingFileReader = new cNonBlockingFileReader; int Length = 0; bool Sleep = false; @@ -393,7 +409,7 @@ // Read the next frame from the file: - if (playMode != pmStill && playMode != pmPause) { + if (playMode != pmStill && playMode != pmPause && !LastMarkPause) { if (!readFrame && (replayFile || readIndex >= 0)) { if (!nonBlockingFileReader->Reading()) { if (playMode == pmFast || (playMode == pmSlow && playDir == pdBackward)) { @@ -430,6 +446,44 @@ uchar FileNumber; int FileOffset; readIndex++; + if (Setup.PlayJump || Setup.PauseLastMark) { + // check for end mark - jump to next mark or pause + marks.Reload(); + cMark *m = marks.Get(readIndex); + if (m && (m->Index() & 0x01) != 0) { + m = marks.Next(m); + int Index; + if (m) + Index = m->position; + else if (Setup.PauseLastMark) { + // pause at last mark + isyslog("PauseLastMark: pause at position %d (%s)", + readIndex, *IndexToHMSF(readIndex, true)); + LastMarkPause = true; + Index = -1; + } + else if (total == index->Last()) + // at last mark jump to end of recording + Index = index->Last() - 1; + else + // jump but stay off end of live-recordings + Index = index->GetNextIFrame(index->Last() - 150, true); + // don't jump in edited recordings + if (Setup.PlayJump && Index > readIndex && + Index > index->GetNextIFrame(readIndex, true)) { + isyslog("PlayJump: %d frames to %d (%s)", + Index - readIndex, Index, + *IndexToHMSF(Index, true)); + readIndex = Index; + cutIn = true; + } + } + } + // for detecting growing length of live-recordings + uchar PictureType; + if (index->Get(readIndex, &FileNumber, &FileOffset, &PictureType) && + PictureType == I_FRAME) + total = index->Last(); if (!(index->Get(readIndex, &FileNumber, &FileOffset, NULL, &Length) && NextFile(FileNumber, FileOffset))) { readIndex = -1; eof = true; @@ -465,6 +519,10 @@ // Store the frame in the buffer: if (readFrame) { + if (cutIn) { + cRemux::SetBrokenLink(readFrame->Data(), readFrame->Count()); + cutIn = false; + } if (ringBuffer->Put(readFrame)) readFrame = NULL; } @@ -513,8 +571,14 @@ p = NULL; } } - else + else { + if (LastMarkPause) { + LastMarkPause = false; + playMode = pmPause; + writeIndex = readIndex; + } Sleep = true; + } } } diff -Naur vdr-1.4.0/i18n.c vdr-1.4.0-jumpplay-0.9/i18n.c --- vdr-1.4.0/i18n.c 2006-04-30 10:51:10.000000000 +0200 +++ vdr-1.4.0-jumpplay-0.9/i18n.c 2006-05-28 15:03:01.000000000 +0200 @@ -4382,6 +4382,102 @@ "Genoptagelses ID", "ID obnovení", }, + { "Setup.Replay$Jump&Play", // English + "Wiedergabe nach Sprung", // Deutsch / German + "", // Slovenski / Slovenian + "", // Italiano / Italian + "", // Nederlands / Dutch + "", // Português / Portuguese + "", // Français / French + "", // Norsk / Norwegian + "", // suomi / Finnish + "", // Polski / Polish + "", // Español / Spanish + "", // ÅëëçíéêÜ / Greek + "", // Svenska / Swedish + "", // Românã / Romanian + "", // Magyar / Hungarian + "", // Català / Catalanian + "", // ÀãááÚØÙ / Russian + "", // Hrvatski / Croatian + "", // Eesti / Estonian + "", // Dansk / Danish +#if VDRVERSNUM >= 10342 + "", // Èesky / Czech +#endif + }, + { "Setup.Replay$Play&Jump", // English + "Sprung bei Schnittmarke", // Deutsch / German + "", // Slovenski / Slovenian + "", // Italiano / Italian + "", // Nederlands / Dutch + "", // Português / Portuguese + "", // Français / French + "", // Norsk / Norwegian + "", // suomi / Finnish + "", // Polski / Polish + "", // Español / Spanish + "", // ÅëëçíéêÜ / Greek + "", // Svenska / Swedish + "", // Românã / Romanian + "", // Magyar / Hungarian + "", // Català / Catalanian + "", // ÀãááÚØÙ / Russian + "", // Hrvatski / Croatian + "", // Eesti / Estonian + "", // Dansk / Danish +#if VDRVERSNUM >= 10342 + "", // Èesky / Czech +#endif + }, + { "Setup.Replay$Pause at last mark", // English + "Pause bei letzter Marke", // Deutsch / German + "", // Slovenski / Slovenian + "", // Italiano / Italian + "", // Nederlands / Dutch + "", // Português / Portuguese + "", // Français / French + "", // Norsk / Norwegian + "", // suomi / Finnish + "", // Polski / Polish + "", // Español / Spanish + "", // ÅëëçíéêÜ / Greek + "", // Svenska / Swedish + "", // Românã / Romanian + "", // Magyar / Hungarian + "", // Català / Catalanian + "", // ÀãááÚØÙ / Russian + "", // Hrvatski / Croatian + "", // Eesti / Estonian + "", // Dansk / Danish +#if VDRVERSNUM >= 10342 + "", // Èesky / Czech +#endif + }, + { "Setup.Replay$Reload marks", // English + "Marken aktualisieren", // Deutsch / German + "", // Slovenski / Slovenian + "", // Italiano / Italian + "", // Nederlands / Dutch + "", // Português / Portuguese + "", // Français / French + "", // Norsk / Norwegian + "", // suomi / Finnish + "", // Polski / Polish + "", // Español / Spanish + "", // ÅëëçíéêÜ / Greek + "", // Svenska / Swedish + "", // Românã / Romanian + "", // Magyar / Hungarian + "", // Català / Catalanian + "", // ÀãááÚØÙ / Russian + "", // Hrvatski / Croatian + "", // Eesti / Estonian + "", // Dansk / Danish +#if VDRVERSNUM >= 10342 + "", // Èesky / Czech +#endif + }, { "Setup.Miscellaneous$Min. event timeout (min)", "Brückenzeit zwischen Timern (min)", "Najmanj¹i èas dogodka (min)", diff -Naur vdr-1.4.0/menu.c vdr-1.4.0-jumpplay-0.9/menu.c --- vdr-1.4.0/menu.c 2006-04-28 14:48:01.000000000 +0200 +++ vdr-1.4.0-jumpplay-0.9/menu.c 2006-05-28 15:03:01.000000000 +0200 @@ -2570,6 +2570,10 @@ Add(new cMenuEditBoolItem(tr("Setup.Replay$Multi speed mode"), &data.MultiSpeedMode)); Add(new cMenuEditBoolItem(tr("Setup.Replay$Show replay mode"), &data.ShowReplayMode)); Add(new cMenuEditIntItem(tr("Setup.Replay$Resume ID"), &data.ResumeID, 0, 99)); + Add(new cMenuEditBoolItem(tr("Setup.Replay$Jump&Play"), &data.JumpPlay)); + Add(new cMenuEditBoolItem(tr("Setup.Replay$Play&Jump"), &data.PlayJump)); + Add(new cMenuEditBoolItem(tr("Setup.Replay$Pause at last mark"), &data.PauseLastMark)); + Add(new cMenuEditBoolItem(tr("Setup.Replay$Reload marks"), &data.ReloadMarks)); } void cMenuSetupReplay::Store(void) @@ -3790,7 +3794,7 @@ char *cReplayControl::title = NULL; cReplayControl::cReplayControl(void) -:cDvbPlayerControl(fileName) +:cDvbPlayerControl(fileName), marks(fileName) { displayReplay = NULL; visible = modeOnly = shown = displayFrames = false; @@ -3799,7 +3803,6 @@ lastSpeed = -1; timeoutShow = 0; timeSearchActive = false; - marks.Load(fileName); cRecording Recording(fileName); cStatus::MsgReplaying(this, Recording.Name(), Recording.FileName(), true); SetTrackDescriptions(false); @@ -4018,8 +4021,10 @@ ShowTimed(2); bool Play, Forward; int Speed; - if (GetReplayMode(Play, Forward, Speed) && !Play) + if (GetReplayMode(Play, Forward, Speed) && !Play) { Goto(Current, true); + displayFrames = true; + } } marks.Save(); } @@ -4032,8 +4037,17 @@ if (GetIndex(Current, Total)) { cMark *m = Forward ? marks.GetNext(Current) : marks.GetPrev(Current); if (m) { - Goto(m->position, true); - displayFrames = true; + bool Play2, Forward2; + int Speed; + if (Setup.JumpPlay && GetReplayMode(Play2, Forward2, Speed) && + Play2 && Forward && m->position < Total - SecondsToFrames(3)) { + Goto(m->position); + Play(); + } + else { + Goto(m->position, true); + displayFrames = true; + } } } } @@ -4088,7 +4102,7 @@ if (!m) m = marks.GetNext(Current); if (m) { - if ((m->Index() & 0x01) != 0) + if ((m->Index() & 0x01) != 0 && !Setup.PlayJump) m = marks.Next(m); if (m) { Goto(m->position - SecondsToFrames(3)); @@ -4110,6 +4124,7 @@ { if (!Active()) return osEnd; + marks.Reload(); if (visible) { if (timeoutShow && time(NULL) > timeoutShow) { Hide(); diff -Naur vdr-1.4.0/menu.h vdr-1.4.0-jumpplay-0.9/menu.h --- vdr-1.4.0/menu.h 2006-03-25 13:15:19.000000000 +0100 +++ vdr-1.4.0-jumpplay-0.9/menu.h 2006-05-26 16:36:37.000000000 +0200 @@ -221,7 +221,7 @@ class cReplayControl : public cDvbPlayerControl { private: cSkinDisplayReplay *displayReplay; - cMarks marks; + cMarksReload marks; bool visible, modeOnly, shown, displayFrames; int lastCurrent, lastTotal; bool lastPlay, lastForward; diff -Naur vdr-1.4.0/recording.c vdr-1.4.0-jumpplay-0.9/recording.c --- vdr-1.4.0/recording.c 2006-04-29 15:22:20.000000000 +0200 +++ vdr-1.4.0-jumpplay-0.9/recording.c 2006-05-28 15:03:01.000000000 +0200 @@ -1123,6 +1123,49 @@ return NULL; } +// --- cMarksReload ---------------------------------------------------------- + +#define MARKS_RELOAD_MS 10000 + +time_t cMarksReload::lastsavetime = 0; + +cMarksReload::cMarksReload(const char *RecordingFileName) +:recDir(RecordingFileName) +{ + struct stat sbuf; + if (Load(recDir) && stat(FileName(), &sbuf) == 0) + lastmodtime = sbuf.st_mtime; + else + lastmodtime = 0; + nextreload.Set(MARKS_RELOAD_MS - cTimeMs::Now() % MARKS_RELOAD_MS); +} + +bool cMarksReload::Reload(void) +{ + // Check the timestamp of marks.vdr in 10 seconds intervals + // Independent but synchronized reloading of marks in two threads + if ((Setup.ReloadMarks && nextreload.TimedOut()) || + lastsavetime > lastmodtime) { + nextreload.Set(MARKS_RELOAD_MS - cTimeMs::Now() % MARKS_RELOAD_MS); + struct stat sbuf; + if (stat(FileName(), &sbuf) == 0 && sbuf.st_mtime != lastmodtime) { + lastmodtime = sbuf.st_mtime; + if (Load(recDir)) + return true; + } + } + return false; +} + +bool cMarksReload::Save(void) +{ + bool ok = cMarks::Save(); + struct stat sbuf; + if (ok && stat(FileName(), &sbuf) == 0) + lastsavetime = lastmodtime = sbuf.st_mtime; + return ok; +} + // --- cRecordingUserCommand ------------------------------------------------- const char *cRecordingUserCommand::command = NULL; diff -Naur vdr-1.4.0/recording.h vdr-1.4.0-jumpplay-0.9/recording.h --- vdr-1.4.0/recording.h 2006-04-09 15:47:11.000000000 +0200 +++ vdr-1.4.0-jumpplay-0.9/recording.h 2006-05-26 16:36:37.000000000 +0200 @@ -162,6 +162,18 @@ cMark *GetNext(int Position); }; +class cMarksReload : public cMarks { +private: + cString recDir; + cTimeMs nextreload; + time_t lastmodtime; + static time_t lastsavetime; +public: + cMarksReload(const char *RecordingFileName); + bool Reload(void); + bool Save(void); + }; + #define RUC_BEFORERECORDING "before" #define RUC_AFTERRECORDING "after" #define RUC_EDITEDRECORDING "edited"