New Upstream Release - vdr-plugin-dvd

Ready changes

Summary

Merged new upstream version: 0.3.7 (was: 0.3.6~b03+git20211216).

Resulting package

Built on 2022-11-30T06:18 (took 2m43s)

The resulting binary packages can be installed (if you have the apt repository enabled) by running one of:

apt install -t fresh-releases vdr-plugin-dvd-dbgsymapt install -t fresh-releases vdr-plugin-dvd

Lintian Result

Diff

diff --git a/HISTORY b/HISTORY
index 1160687..bf9dcf6 100644
--- a/HISTORY
+++ b/HISTORY
@@ -1,6 +1,7 @@
 VDR Plugin 'dvd' Revision History
 ---------------------------------
 
+2021-12-17 Version 0.3.7
     - change i18n to gettext
     - fix GetIndex return value, remove lcdproc workaround
     - fix possible segfault's (thanks to Ioannis Petroglou)
diff --git a/Makefile b/Makefile
index 531ba0e..2f3a584 100644
--- a/Makefile
+++ b/Makefile
@@ -15,7 +15,8 @@ VERSION = $(shell grep 'static const char \*VERSION *=' $(PLUGIN).c | awk '{ pri
 
 ### The directory environment:
 
-PKGCFG = $(if $(VDRDIR),$(shell pkg-config --variable=$(1) $(VDRDIR)/vdr.pc),$(shell pkg-config --variable=$(1) vdr || pkg-config --variable=$(1) ../../../vdr.pc))
+PKG_CONFIG ?= pkg-config
+PKGCFG = $(if $(VDRDIR),$(shell $(PKG_CONFIG) --variable=$(1) $(VDRDIR)/vdr.pc),$(shell $(PKG_CONFIG) --variable=$(1) vdr || $(PKG_CONFIG) --variable=$(1) ../../../vdr.pc))
 LIBDIR = $(DESTDIR)$(call PKGCFG,libdir)
 LOCDIR = $(DESTDIR)$(call PKGCFG,locdir)
 
@@ -61,6 +62,10 @@ CXXFLAGS += -O3
 LDFLAGS  += -O3 -Wl,--retain-symbols-file,retain-sym
 endif
 
+ifdef RESUMEDIR
+  DEFINES += -DRESUMEDIR=\"$(RESUMEDIR)\"
+endif
+
 ### The object files (add further files here):
 
 OBJS = $(PLUGIN).o dvddev.o player-dvd.o control-dvd.o dvdspu.o     \
diff --git a/debian/changelog b/debian/changelog
index 15908a3..dd5cd3b 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,13 @@
+vdr-plugin-dvd (0.3.7-1) UNRELEASED; urgency=low
+
+  * New upstream release.
+  * Drop patch 04_vdr-dvd_resume.patch, present upstream.
+  * Drop patch 10_dvd.c.patch, present upstream.
+  * Drop patch 12_dvd-fixed-german-spelling.patch, present upstream.
+  * Drop patch cross.patch, present upstream.
+
+ -- Debian Janitor <janitor@jelmer.uk>  Wed, 30 Nov 2022 06:16:39 -0000
+
 vdr-plugin-dvd (0.3.6~b03+git20211216-2) unstable; urgency=medium
 
   * Remove Thomas Günther and Thomas Schmidt from uploaders
diff --git a/debian/patches/04_vdr-dvd_resume.patch b/debian/patches/04_vdr-dvd_resume.patch
deleted file mode 100644
index b0b78a4..0000000
--- a/debian/patches/04_vdr-dvd_resume.patch
+++ /dev/null
@@ -1,545 +0,0 @@
-#! /bin/sh /usr/share/dpatch/dpatch-run
-## 04_vdr-dvd_resume.dpatch by Patrick Cernko <errror@errror.org>
-## http://www.vdrportal.de/board/thread.php?threadid=31685
-##
-## Thomas G�nther <tom@toms-cafe.de>:
-##   - adapted to dvd plugin version cvs20070813
-##   - adapted to dvd plugin version cvs20090426.0013
-##
-## All lines beginning with `## DP:' are a description of the patch.
-## DP: Patch to resume a dvd where it was interrupted by the user.
-
-@DPATCH@
---- a/Makefile
-+++ b/Makefile
-@@ -61,6 +61,10 @@
- LDFLAGS  += -O3 -Wl,--retain-symbols-file,retain-sym
- endif
- 
-+ifdef RESUMEDIR
-+  DEFINES += -DRESUMEDIR=\"$(RESUMEDIR)\"
-+endif
-+
- ### The object files (add further files here):
- 
- OBJS = $(PLUGIN).o dvddev.o player-dvd.o control-dvd.o dvdspu.o     \
---- a/player-dvd.c
-+++ b/player-dvd.c
-@@ -21,6 +21,8 @@
- #include <vdr/thread.h>
- #include <vdr/device.h>
- #include <vdr/plugin.h>
-+// for VideoDirectory variable
-+#include <vdr/videodir.h>
- 
- #ifdef HAVE_CONFIG_H
- #include "config.h"
-@@ -231,6 +233,220 @@
- }
- 
- 
-+// --- cResumeEntry ------------------------------------------------------------
-+
-+// borrowed from the mplayer plugin code and adapted to the dvd resume requirements
-+class cResumeEntry : public cListObject {
-+public:
-+  char *key;
-+  int title;
-+  int chapter;
-+  int64_t second;
-+  //
-+  cResumeEntry(void);
-+  ~cResumeEntry();
-+  };
-+
-+cResumeEntry::cResumeEntry(void)
-+{
-+  key=0;
-+}
-+
-+cResumeEntry::~cResumeEntry()
-+{
-+  free(key);
-+}
-+
-+// --- cDVDPlayerResume ----------------------------------------------------------
-+
-+// store resume database to this file ...
-+#define RESUME_FILE "dvdplayer.resume"
-+
-+// ... in this directory (default: /video)
-+#ifndef RESUMEDIR
-+#if APIVERSNUM > 20101
-+#define RESUMEDIR cVideoDirectory::Name()
-+#else
-+#define RESUMEDIR VideoDirectory
-+#endif
-+#endif
-+
-+
-+// borrowed from the mplayer plugin code and adapted to the dvd resume requirements
-+class cDVDPlayerResume : public cList<cResumeEntry> {
-+private:
-+  char* resfile; // the full pathname of resume file
-+  bool modified; // flag to indicate that memory database was modified and needs to be saved
-+  /**
-+   * LoadResume():
-+   * reads in the resume database file from resfile.
-+   */
-+  void LoadResume();
-+  /**
-+   * SaveResume():
-+   * saves the resume database to the file resfile.
-+   * returns true on successful save.
-+   */
-+  bool SaveResume(void);
-+  /**
-+   * search the (loaded) resume database for the given key.
-+   * returns the cResumeEntry* if the key was found
-+   * or NULL if no resume entry was found for the given key.
-+   */
-+  cResumeEntry *FindResume(const char* key);
-+public:
-+  cDVDPlayerResume(void);
-+  ~cDVDPlayerResume();
-+  /**
-+   * SetResume():
-+   * set the given resume values for the given key into the resume database.
-+   * the resume database is loaded from file if not yet loaded.
-+   */
-+  void SetResume(const char* key, int title, int chapter, int64_t second);
-+  /**
-+   * GetResume():
-+   * tries looking up the given key into the resume database.
-+   * the resume database is loaded from file if not yet loaded.
-+   * returns true if resume data could be found. In this case
-+   * the givven arguments are filled with the resume data. Otherwise
-+   * the arguments are not modified!
-+   */
-+  bool GetResume(const char* key, int& title, int& chapter, int64_t& second);
-+  };
-+
-+cDVDPlayerResume::cDVDPlayerResume(void)
-+{
-+  // initialize the resume filename string.
-+  asprintf(&resfile, "%s/%s", RESUMEDIR, RESUME_FILE);
-+}
-+
-+cDVDPlayerResume::~cDVDPlayerResume()
-+{
-+  // save resume data to disc before self-destruction.
-+  SaveResume();
-+  // free the resume filename string, allocated in C'tor by asprintf
-+  free(resfile);
-+}
-+
-+void cDVDPlayerResume::SetResume(const char* key, int title, int chapter, int64_t second)
-+{
-+  // (re)load resume data from file to be actual
-+  LoadResume();
-+  cResumeEntry* re = FindResume(key);
-+  if (re) {
-+    // found a resume entry, so we can update it.
-+    DEBUGDVD("resume: setting resume %d:%d:%lld (update)", title, chapter, second);
-+  } else {
-+    // no resume entry found yet, creating a new one
-+    re = new cResumeEntry;
-+    re->key = strdup(key);
-+    Add(re);
-+    DEBUGDVD("resume: setting resume %d:%d:%lld (new)", title, chapter, second);
-+  }
-+  // set the new resume data for the found/created entry
-+  re->title = title;
-+  re->chapter = chapter;
-+  re->second = second;
-+  // and mark memory database as modified to be saved.
-+  modified = true;
-+  // save it now (sync!)
-+  SaveResume();
-+}
-+
-+bool cDVDPlayerResume::GetResume(const char* key, int& title, int& chapter, int64_t& second)
-+{
-+  // (re)load the resume file to have actual values
-+  LoadResume();
-+  cResumeEntry* re = FindResume(key);
-+  if (re) {
-+    // found a resume entry, copy values
-+    title = re->title;
-+    chapter = re->chapter;
-+    second = re->second;
-+    // indicate successful search
-+    return true;
-+  }
-+  // no resume entry found in database
-+  return false;
-+}
-+
-+void cDVDPlayerResume::LoadResume()
-+{
-+  // we will load the file for sure and add all entries, clear all old entries.
-+  Clear();
-+  // no entries == no modifications
-+  modified = false;
-+  DEBUGDVD("resume: resume file is \"%s\"\n",resfile);
-+  FILE *f = fopen(resfile,"r");
-+  if (f) {
-+    DEBUGDVD("resume: successfully opened resume file\n");
-+    char line[768];
-+    // read file line by line
-+    while(fgets(line,sizeof(line),f)) {
-+      char key[512];
-+      int t, c;
-+      int64_t s;
-+      // parse line as "title:chapter:second:key"
-+      if(sscanf(line,"%d:%d:%lld:%511[^\n]",&t,&c,&s,key) == 4) {
-+        // successful parse, save in resume entry
-+        cResumeEntry *re = new cResumeEntry;
-+        re->key = strdup(key);
-+        re->title = t;
-+        re->chapter = c;
-+        re->second = s;
-+        // and add it to memory database
-+        Add(re);
-+      }
-+    }
-+    // don't forget to close what you have opened!
-+    fclose(f);
-+  }
-+  // unsuccessful open leads to empty database as the file does not exists
-+}
-+
-+bool cDVDPlayerResume::SaveResume(void)
-+{
-+  if(modified) {
-+    // modification indicated, save the database to the resume file
-+    DEBUGDVD("resume: saving resume file\n");
-+    cSafeFile f(resfile);
-+    if(f.Open()) {
-+      // forall resume entries in the memory database
-+      for (cResumeEntry *re=First(); re; re=Next(re)) {
-+        // save the as one line in the format "title:chapter:second:key"
-+        fprintf(f, "%d:%d:%lld:%s\n", re->title, re->chapter, re->second, re->key);
-+      }
-+      // don't forget to close what you have opened!
-+      f.Close();
-+      // signal successful save
-+      return true;
-+    } else {
-+      DEBUGDVD("resume: failed to save resume file\n");
-+      // saving did not succeed!!!!
-+      return false;
-+    }
-+  } else {
-+    // no modifications -> successful "save" :-)
-+    return true;
-+  }
-+}
-+
-+cResumeEntry *cDVDPlayerResume::FindResume(const char* key)
-+{
-+  DEBUGDVD("resume: searching resume  position for \"%s\"\n", key);
-+  // iterate over all entries in the memory database
-+  for(cResumeEntry *re=First(); re; re=Next(re)) {
-+    if (!strcasecmp(re->key, key)) {
-+      // return the entry iff the keys match
-+      DEBUGDVD("resume: found resume position %d:%d:%lld\n",re->title, re->chapter, re->second);
-+      return re;
-+    }
-+  }
-+  DEBUGDVD("resume: no resume position found\n");
-+  return NULL;
-+}
-+
-+
- // --- cDvdPlayer ------------------------------------------------------------
- 
- //XXX+ also used in recorder.c - find a better place???
-@@ -288,6 +504,9 @@
-     skipPlayVideo=false;
-     fastWindFactor=1;
- 
-+    // resume
-+    resume = new cDVDPlayerResume;
-+
-     clearSeenSubpStream();
-     clearSeenAudioTrack();
- 
-@@ -334,6 +553,8 @@
- 
-     if(aspect_str)
- 		free(aspect_str);
-+
-+    delete resume;
- }
- 
- void cDvdPlayer::setController (cDvdPlayerControl *ctrl )
-@@ -570,6 +791,100 @@
- #endif
- }
- 
-+char* cDvdPlayer::GetDVDResumeKey() const {
-+  // first we fetch the total number of titles of the current dvd
-+  int totalTitles;
-+  if (dvdnav_get_number_of_titles(nav, &totalTitles)) {
-+    // then we sum up the numbers of chapters for each title
-+    int totalChapters = 0;
-+    for (int t = 1; t <= totalTitles; t++) {
-+      int curChapters;
-+      dvdnav_get_number_of_parts(nav, t, &curChapters);
-+      totalChapters += curChapters;
-+      DEBUGDVD("resume: cDvdPlayer::Action() Title %d has %d chapters.\n", t, curChapters);
-+    }
-+    DEBUGDVD("resume: cDvdPlayer::Action() Titles: %d with %d chapters all together, Title: \"%s\"\n",
-+             totalTitles, totalChapters, title_str);
-+    // finally the key is build as "DVDName_TotalTitles_OverallChapters"
-+    char* key;
-+    asprintf(&key, "%s_%d_%d", title_str, totalTitles, totalChapters);
-+    // note: this is not completly unique. Maybe some other informations are more suitable, like:
-+    // - the "serial number" of the dvd as displayed in the libdvdnav debug output, but:
-+    //   it is not available through the current libdvdnav api
-+    // - the total bytes of the dvd (quiet unique!!!), but:
-+    //   also not available through the libdvdnav api and no idea how to get it for a media not mounted.
-+    // - any other ideas???
-+    return key;
-+  } else {
-+    // if we cannot fetch the total number of titles of the current disc, there must be something wrong!
-+    // Who needs a key for resuming then?
-+    return NULL;
-+  }
-+}
-+
-+void cDvdPlayer::SaveResume() {
-+  // make sure resume database is allocated (might be a possibility to completly disable resuming!)
-+  if (resume) {
-+    // fetch the current title and chapter number via libdvdnav api
-+    int currentTitle, currentChapter;
-+    if (dvdnav_current_title_info(nav, &currentTitle, &currentChapter) &&
-+        (0 != currentTitle)) {
-+      // fetch current time position through own class api
-+      int64_t currentSec, totalSec;
-+      GetPositionInSec(currentSec, totalSec);
-+      // compute the resume key for the current dvd
-+      char* key = GetDVDResumeKey();
-+      if (key) {
-+        // store computed/fetched resume data in database
-+        DEBUGDVD("resume->SetResume(\"%s\", %d, %d, %lld)\n", key, currentTitle, currentChapter, currentSec);
-+        resume->SetResume(key, currentTitle, currentChapter, currentSec);
-+        // free the key string memory allocated by GetDVDResumeKey()
-+        free(key);
-+      } else {
-+        DEBUGDVD("resume: ERROR computing resume key for this dvd!\n");
-+      }
-+    } else {
-+      // in a menu title and chapter seams to be always 0 -> no way to resume there!
-+      DEBUGDVD("resume: ERROR fetching current title and chapter (maybe in menus?).\n");
-+    }
-+  }
-+}
-+
-+bool cDvdPlayer::LoadResume(int& title, int& chapter, int64_t& second) {
-+  // helper variable for the return value
-+  bool retval = false;
-+  // make sure resume database is allocated (might be a possibility to completly disable resuming!)
-+  if(resume) {
-+    // compute the resume key for the current dvd
-+    char* key = GetDVDResumeKey();
-+    if (key) {
-+      DEBUGDVD("resume->GetResume(\"%s\", ...): ", key);
-+      // try loading the resume data for the computed key into the given arguments
-+      if (resume->GetResume(key, title, chapter, second)) {
-+        DEBUGDVD("%d:%d:%lld\n", title, chapter, second);
-+        // continuing at the very same position might be inappropriate (vdr's recordings also rewind some seconds)
-+        int ResumeRewind = 30; // rewind 30s if possible
-+        // note: I used a variable here to show up, that this value might be made
-+        //       possible to configure (in the setup dialog). Doing so myself was
-+        //       not yet nesseccary and is so left to the plugin maintainers.
-+        // make sure we do not rewind before the beginning
-+        if (second > ResumeRewind) {
-+          second -= ResumeRewind;
-+        }
-+        retval = true;
-+      } else {
-+        DEBUGDVD("<none>\n");
-+        retval = false;
-+      }
-+      // free the key string memory allocated by GetDVDResumeKey()
-+      free(key);
-+    } else {
-+      DEBUGDVD("resume: ERROR computing resume key for this dvd.\n");
-+    }
-+  }
-+  return retval;
-+}
-+
- void cDvdPlayer::Action(void) {
-     memset(event_buf, 0, sizeof(uint8_t)*4096);
- 
-@@ -641,6 +956,13 @@
- 
-     bool firstClear = true;
- 
-+    // we need to know the very first VTS change to hook inthe resume call
-+    bool first_vts_change = true;
-+    // we cannot directly resume to the exact time, so we hook on the next cell change when resuming
-+    bool next_cell_change = false;
-+    // and seek the the exact time stored here
-+    int64_t resSecond = 0;
-+
-     while(running && nav) {
- 
-         if (!pframe) {
-@@ -1119,6 +1441,22 @@
- 	      SetTitleInfoString();
- 	      SetTitleString();
- 	      SetAspectString();
-+              if (first_vts_change) {
-+                first_vts_change = false;
-+
-+                // now all data for computing the resume key is available, so trying to resume
-+                int resTitle, resChapter;
-+                if (LoadResume(resTitle, resChapter, resSecond)) {
-+                  // if resume data could be found seek to the found title and chapter NOW
-+                  GotoTitle(resTitle, resChapter);
-+                  // and wait for the next cell change (= title and chapter reached)
-+                  // to seek to the exact time
-+                  next_cell_change = true;
-+                  // note: seeking to the exact time HERE leads to an error on the libdvdnav console:
-+                  //       "dvd error dvdnav_sector_search: New position not yet determined." and is
-+                  //       slightly ignored :-( .
-+                }
-+              }
- 	      break;
- 	  case DVDNAV_CELL_CHANGE: {
- 	      DEBUG_NAV("%s:%d:NAV CELL CHANGE\n", __FILE__, __LINE__);
-@@ -1139,6 +1477,11 @@
- 	      // cell change .. game over ..
- 	      changeNavSubpStreamOnceInSameCell=false;
-     	  SetTitleInfoString();
-+	      if (next_cell_change) {
-+	        next_cell_change = false;
-+	        // we are resuming the current dvd. NOW its time to seek to the correct second.
-+	        Goto(resSecond);
-+	      }
- 	      break;
- 	  }
- 	  case DVDNAV_NAV_PACKET: {
-@@ -1902,8 +2245,18 @@
-     if (!DVDActiveAndRunning())
-         return;
- 
--    if (running && nav)
-+    if (running && nav) {
-+        // we will stop replay now. Its time to save the current possition
-+        // for later resuming.
-+        SaveResume();
-+
-         dvdnav_stop(nav);
-+
-+        // don't know why Stop() is called twice, but this prevents from
-+        // twice save resume data and calling dvdnav_stop() twice.
-+        // Comments from maintainers are welcome.
-+        running = false;
-+    }
- }
- 
- void cDvdPlayer::Play(void)
-@@ -2219,24 +2572,41 @@
-     GotoAngle(++angleNumber);
- }
- 
--int cDvdPlayer::GotoTitle(int Title)
-+// GotoTitle now optionally takes a chapter to seek to in the given title.
-+int cDvdPlayer::GotoTitle(int Title, int Chapter /*= 1*/)
- {
-     int titleNumbers;
-+    int targetTitle = Title;
-+    int chapterNumber;
-     if (!DVDActiveAndRunning())
-         return -1;
-     LOCK_THREAD;
-     DEBUG_NAV("DVD NAV SPU clear & empty %s:%d\n", __FILE__, __LINE__);
-     Empty();
- 
-+    // check if the given title is in the title range of this dvd
-     dvdnav_get_number_of_titles(nav, &titleNumbers);
- 
-     if (Title > titleNumbers)
--        Title = 1;
-+        targetTitle = 1;
-     if (Title <= 0)
--        Title = titleNumbers;
-+        targetTitle = titleNumbers;
-+
-+    // if given title is in the bounds of this dvd's title range
-+    if (Title == targetTitle) {
-+        // check if the chapter is in the title's chapter range
-+        dvdnav_get_number_of_parts(nav, Title, &chapterNumber);
-+        if (Chapter > chapterNumber)
-+            Chapter = 1;
-+        if (Chapter <= 0)
-+            Chapter = chapterNumber;
-+    } else {
-+        // otherwise reset it to the first chapter.
-+        Chapter = 1;
-+    }
- 
-     if (stillTimer == 0) {
--        dvdnav_part_play(nav, Title, 1);
-+        dvdnav_part_play(nav, Title, Chapter);
-         // dvdnav_title_play(nav, Title);
-     }
- 
---- a/player-dvd.h
-+++ b/player-dvd.h
-@@ -54,6 +54,7 @@
- 
- class cDvdPlayerControl ;
- class cIframeAssembler;
-+class cDVDPlayerResume;
- 
- class cDvdPlayer : public cPlayer, cThread {
-  private:
-@@ -188,6 +189,32 @@
-     int  GetAudioStreamNumbers(void) const ;
-     uint16_t GetSubtitleLanguageCode(int Channel) const;
-     int  GetSubtitleStreamNumbers(void) const ;
-+
-+    //resuming
-+    /**
-+     * the resume database
-+     */
-+    cDVDPlayerResume* resume;
-+    /**
-+     * GetDVDResumeKey():
-+     * computes a (hopefully) unique id for storing the resume data of the current disc.
-+     *
-+     * this get returns a new allocated memory area ..
-+     * must be freed by callee ..
-+     */
-+    char* GetDVDResumeKey() const;
-+    /**
-+     * SaveResume():
-+     * handles everything to save the current position on the disc for later resuming.
-+     */
-+    void SaveResume();
-+    /**
-+     * LoadResume():
-+     * loads the resume data for the current disc and stores it in the given arguments.
-+     * returns false if no resume data for the disc can be found or and error occured while loading.
-+     */
-+    bool LoadResume(int& title, int& chapter, int64_t& second);
-+
- protected: //Player
-     virtual void Activate(bool On);
-     virtual void Action(void);
-@@ -320,7 +347,8 @@
-      *
-      * return set title ..
-      */
--    int GotoTitle(int Title);
-+    // GotoTitle now optionally takes a chapter to seek to in the given title
-+    int GotoTitle(int Title, int Chapter = 1);
- 
-     /**
-      * jump to the previous Title (rotate)
diff --git a/debian/patches/05_stdint.patch b/debian/patches/05_stdint.patch
index 2dbd6a5..1772a33 100644
--- a/debian/patches/05_stdint.patch
+++ b/debian/patches/05_stdint.patch
@@ -6,9 +6,11 @@
 ## DP: C++ code.
 
 @DPATCH@
---- a/Makefile
-+++ b/Makefile
-@@ -41,6 +41,7 @@
+Index: vdr-plugin-dvd.git/Makefile
+===================================================================
+--- vdr-plugin-dvd.git.orig/Makefile
++++ vdr-plugin-dvd.git/Makefile
+@@ -42,6 +42,7 @@ SOFILE = libvdr-$(PLUGIN).so
  INCLUDES +=
  
  DEFINES += -DPLUGIN_NAME_I18N='"$(PLUGIN)"'
diff --git a/debian/patches/10_dvd.c.patch b/debian/patches/10_dvd.c.patch
deleted file mode 100644
index d050e23..0000000
--- a/debian/patches/10_dvd.c.patch
+++ /dev/null
@@ -1,20 +0,0 @@
-#! /bin/sh /usr/share/dpatch/dpatch-run
-## dvd.c patch
-##
-## All lines beginning with `## DP:' are a description of the patch.
-## DP: Removes stderr output on correctly parsed -C parameter
-
-@DPATCH@
-Index: vdr-plugin-dvd-0.3.6~b03+cvs20090426.0013/dvd.c
-===================================================================
---- vdr-plugin-dvd-0.3.6~b03+cvs20090426.0013.orig/dvd.c	2007-09-16 18:31:50.000000000 +0200
-+++ vdr-plugin-dvd-0.3.6~b03+cvs20090426.0013/dvd.c	2011-04-09 17:23:43.000000000 +0200
-@@ -73,7 +73,7 @@
- #endif
-         switch (c) {
-             case 'C':
--                fprintf(stderr, "arg: %s\n", optarg);
-+                // fprintf(stderr, "arg: %s\n", optarg);
-                 cDVD::SetDeviceName(optarg);
-                 if (!cDVD::DriveExists()) {
-                     esyslog("vdr: DVD drive not found: %s", optarg);
diff --git a/debian/patches/11_allow-non-existing-dvd-drive.patch b/debian/patches/11_allow-non-existing-dvd-drive.patch
index 2c3f67e..0e42f6c 100644
--- a/debian/patches/11_allow-non-existing-dvd-drive.patch
+++ b/debian/patches/11_allow-non-existing-dvd-drive.patch
@@ -6,11 +6,11 @@
 ## DP: just log a warning and continue.
 
 @DPATCH@
-Index: vdr-plugin-dvd-0.3.6~b03+cvs20090426.0013/dvd.c
+Index: vdr-plugin-dvd.git/dvd.c
 ===================================================================
---- vdr-plugin-dvd-0.3.6~b03+cvs20090426.0013.orig/dvd.c	2011-04-09 17:23:43.000000000 +0200
-+++ vdr-plugin-dvd-0.3.6~b03+cvs20090426.0013/dvd.c	2011-04-09 17:23:46.000000000 +0200
-@@ -76,8 +76,7 @@
+--- vdr-plugin-dvd.git.orig/dvd.c
++++ vdr-plugin-dvd.git/dvd.c
+@@ -76,8 +76,7 @@ bool cPluginDvd::ProcessArgs(int argc, c
                  // fprintf(stderr, "arg: %s\n", optarg);
                  cDVD::SetDeviceName(optarg);
                  if (!cDVD::DriveExists()) {
diff --git a/debian/patches/12_dvd-fixed-german-spelling.patch b/debian/patches/12_dvd-fixed-german-spelling.patch
deleted file mode 100644
index bc0dfbf..0000000
--- a/debian/patches/12_dvd-fixed-german-spelling.patch
+++ /dev/null
@@ -1,71 +0,0 @@
-#! /bin/sh /usr/share/dpatch/dpatch-run
-## 12_dvd-fixed-german-spelling.dpatch by Thomas G�nther <tom@toms-cafe.de>
-##
-## All lines beginning with `## DP:' are a description of the patch.
-## DP: Fixed spelling errors in german translation.
-
-@DPATCH@
---- a/i18n.c
-+++ b/i18n.c
-@@ -125,7 +125,7 @@
-     },
-     {
-     "Setup.DVD$Preferred menu language",                    // English
--        "Bevorzugte Spache f�r Men�s",                      // Deutsch
-+        "Bevorzugte Sprache f�r Men�s",                     // Deutsch
-         "Prednostni jezik za menije",                       // Slovenski
-         "menu - linguaggio preferito",                      // Italiano
-         "Taalkeuze voor menu",                              // Nederlands
-@@ -177,7 +177,7 @@
-     },
-     {
-     "Setup.DVD$Preferred subtitle language",                // English
--        "Bevorzugte Spache f�r Untertitel",                 // Deutsch
-+        "Bevorzugte Sprache f�r Untertitel",                // Deutsch
-         "Prednostni jezik za podnapise",                    // Slovenski
-         "sottotitoli - linguaggio preferito",               // Italiano
-         "Taalkeuze voor ondertitels",                       // Nederlands
-@@ -333,7 +333,7 @@
-     },
-     {
-     "Error.DVD$Error opening DVD!",                         // English
--        "Fehler beim �ffnen der DVD!",                      // Deutsch
-+        "Fehler beim �ffnen der DVD!",                      // Deutsch
-         "Napaka pri odpiranju DVD-ja!",                     // Slovenski
-         "",                                                 // Italiano
-         "Fout bij het openen van de DVD!",                  // Nederlands
-@@ -359,7 +359,7 @@
-     },
-     {
-     "Error.DVD$Error fetching data from DVD!",              // English
--        "Fehler beim lesen von der DVD!",                   // Deutsch
-+        "Fehler beim Lesen von der DVD!",                   // Deutsch
-         "Napaka pri branju podatkov iz DVD-ja!",            // Slovenski
-         "",                                                 // Italiano
-         "Error bij het verkrijgen van data van de DVD!",    // Nederlands
---- a/po/de_DE.po
-+++ b/po/de_DE.po
-@@ -26,19 +26,19 @@
- msgstr "DVD"
- 
- msgid "Error.DVD$Error opening DVD!"
--msgstr "Fehler beim �ffnen der DVD!"
-+msgstr "Fehler beim �ffnen der DVD!"
- 
- msgid "Error.DVD$Error fetching data from DVD!"
--msgstr "Fehler beim lesen von der DVD!"
-+msgstr "Fehler beim Lesen von der DVD!"
- 
- msgid "Setup.DVD$Preferred menu language"
--msgstr "Bevorzugte Spache f�r Men�s"
-+msgstr "Bevorzugte Sprache f�r Men�s"
- 
- msgid "Setup.DVD$Preferred audio language"
- msgstr "Bevorzugte Sprache f�r Dialog"
- 
- msgid "Setup.DVD$Preferred subtitle language"
--msgstr "Bevorzugte Spache f�r Untertitel"
-+msgstr "Bevorzugte Sprache f�r Untertitel"
- 
- msgid "Setup.DVD$Player region code"
- msgstr "Regionalkode f�r DVD Spieler"
diff --git a/debian/patches/cross.patch b/debian/patches/cross.patch
deleted file mode 100644
index 830cc22..0000000
--- a/debian/patches/cross.patch
+++ /dev/null
@@ -1,12 +0,0 @@
---- a/Makefile
-+++ b/Makefile
-@@ -15,7 +15,8 @@
- 
- ### The directory environment:
- 
--PKGCFG = $(if $(VDRDIR),$(shell pkg-config --variable=$(1) $(VDRDIR)/vdr.pc),$(shell pkg-config --variable=$(1) vdr || pkg-config --variable=$(1) ../../../vdr.pc))
-+PKG_CONFIG ?= pkg-config
-+PKGCFG = $(if $(VDRDIR),$(shell $(PKG_CONFIG) --variable=$(1) $(VDRDIR)/vdr.pc),$(shell $(PKG_CONFIG) --variable=$(1) vdr || $(PKG_CONFIG) --variable=$(1) ../../../vdr.pc))
- LIBDIR = $(DESTDIR)$(call PKGCFG,libdir)
- LOCDIR = $(DESTDIR)$(call PKGCFG,locdir)
- 
diff --git a/debian/patches/series b/debian/patches/series
index 92111fe..144f0d9 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -1,6 +1,2 @@
-04_vdr-dvd_resume.patch
 05_stdint.patch
-10_dvd.c.patch
 11_allow-non-existing-dvd-drive.patch
-12_dvd-fixed-german-spelling.patch
-cross.patch
diff --git a/dvd.c b/dvd.c
index d87efad..8b22e6c 100644
--- a/dvd.c
+++ b/dvd.c
@@ -14,7 +14,7 @@
 
 #include "dvd.h"
 
-static const char *VERSION        = "0.3.6-b03";
+static const char *VERSION        = "0.3.7";
 #if VDRVERSNUM >= 10507
 static const char *DESCRIPTION    = trNOOP("Plugin.DVD$turn VDR into an (almost) full featured DVD player");
 static const char *MAINMENUENTRY  = trNOOP("Plugin.DVD$DVD");
@@ -73,7 +73,7 @@ bool cPluginDvd::ProcessArgs(int argc, char *argv[])
 #endif
         switch (c) {
             case 'C':
-                fprintf(stderr, "arg: %s\n", optarg);
+                // fprintf(stderr, "arg: %s\n", optarg);
                 cDVD::SetDeviceName(optarg);
                 if (!cDVD::DriveExists()) {
                     esyslog("vdr: DVD drive not found: %s", optarg);
diff --git a/i18n.c b/i18n.c
index 8381ed4..bf0d416 100644
--- a/i18n.c
+++ b/i18n.c
@@ -125,7 +125,7 @@ const tI18nPhrase DvdPhrases[] = {
     },
     {
     "Setup.DVD$Preferred menu language",                    // English
-        "Bevorzugte Spache f�r Men�s",                      // Deutsch
+        "Bevorzugte Sprache f�r Men�s",                     // Deutsch
         "Prednostni jezik za menije",                       // Slovenski
         "menu - linguaggio preferito",                      // Italiano
         "Taalkeuze voor menu",                              // Nederlands
@@ -177,7 +177,7 @@ const tI18nPhrase DvdPhrases[] = {
     },
     {
     "Setup.DVD$Preferred subtitle language",                // English
-        "Bevorzugte Spache f�r Untertitel",                 // Deutsch
+        "Bevorzugte Sprache f�r Untertitel",                // Deutsch
         "Prednostni jezik za podnapise",                    // Slovenski
         "sottotitoli - linguaggio preferito",               // Italiano
         "Taalkeuze voor ondertitels",                       // Nederlands
@@ -333,7 +333,7 @@ const tI18nPhrase DvdPhrases[] = {
     },
     {
     "Error.DVD$Error opening DVD!",                         // English
-        "Fehler beim �ffnen der DVD!",                      // Deutsch
+        "Fehler beim �ffnen der DVD!",                      // Deutsch
         "Napaka pri odpiranju DVD-ja!",                     // Slovenski
         "",                                                 // Italiano
         "Fout bij het openen van de DVD!",                  // Nederlands
@@ -359,7 +359,7 @@ const tI18nPhrase DvdPhrases[] = {
     },
     {
     "Error.DVD$Error fetching data from DVD!",              // English
-        "Fehler beim lesen von der DVD!",                   // Deutsch
+        "Fehler beim Lesen von der DVD!",                   // Deutsch
         "Napaka pri branju podatkov iz DVD-ja!",            // Slovenski
         "",                                                 // Italiano
         "Error bij het verkrijgen van data van de DVD!",    // Nederlands
diff --git a/player-dvd.c b/player-dvd.c
index ae03ce2..0d40696 100644
--- a/player-dvd.c
+++ b/player-dvd.c
@@ -21,6 +21,8 @@
 #include <vdr/thread.h>
 #include <vdr/device.h>
 #include <vdr/plugin.h>
+// for VideoDirectory variable
+#include <vdr/videodir.h>
 
 #ifdef HAVE_CONFIG_H
 #include "config.h"
@@ -231,6 +233,220 @@ void cIframeAssembler::Put(unsigned char *Data, int Length) {
 }
 
 
+// --- cResumeEntry ------------------------------------------------------------
+
+// borrowed from the mplayer plugin code and adapted to the dvd resume requirements
+class cResumeEntry : public cListObject {
+public:
+  char *key;
+  int title;
+  int chapter;
+  int64_t second;
+  //
+  cResumeEntry(void);
+  ~cResumeEntry();
+  };
+
+cResumeEntry::cResumeEntry(void)
+{
+  key=0;
+}
+
+cResumeEntry::~cResumeEntry()
+{
+  free(key);
+}
+
+// --- cDVDPlayerResume ----------------------------------------------------------
+
+// store resume database to this file ...
+#define RESUME_FILE "dvdplayer.resume"
+
+// ... in this directory (default: /video)
+#ifndef RESUMEDIR
+#if APIVERSNUM > 20101
+#define RESUMEDIR cVideoDirectory::Name()
+#else
+#define RESUMEDIR VideoDirectory
+#endif
+#endif
+
+
+// borrowed from the mplayer plugin code and adapted to the dvd resume requirements
+class cDVDPlayerResume : public cList<cResumeEntry> {
+private:
+  char* resfile; // the full pathname of resume file
+  bool modified; // flag to indicate that memory database was modified and needs to be saved
+  /**
+   * LoadResume():
+   * reads in the resume database file from resfile.
+   */
+  void LoadResume();
+  /**
+   * SaveResume():
+   * saves the resume database to the file resfile.
+   * returns true on successful save.
+   */
+  bool SaveResume(void);
+  /**
+   * search the (loaded) resume database for the given key.
+   * returns the cResumeEntry* if the key was found
+   * or NULL if no resume entry was found for the given key.
+   */
+  cResumeEntry *FindResume(const char* key);
+public:
+  cDVDPlayerResume(void);
+  ~cDVDPlayerResume();
+  /**
+   * SetResume():
+   * set the given resume values for the given key into the resume database.
+   * the resume database is loaded from file if not yet loaded.
+   */
+  void SetResume(const char* key, int title, int chapter, int64_t second);
+  /**
+   * GetResume():
+   * tries looking up the given key into the resume database.
+   * the resume database is loaded from file if not yet loaded.
+   * returns true if resume data could be found. In this case
+   * the givven arguments are filled with the resume data. Otherwise
+   * the arguments are not modified!
+   */
+  bool GetResume(const char* key, int& title, int& chapter, int64_t& second);
+  };
+
+cDVDPlayerResume::cDVDPlayerResume(void)
+{
+  // initialize the resume filename string.
+  asprintf(&resfile, "%s/%s", RESUMEDIR, RESUME_FILE);
+}
+
+cDVDPlayerResume::~cDVDPlayerResume()
+{
+  // save resume data to disc before self-destruction.
+  SaveResume();
+  // free the resume filename string, allocated in C'tor by asprintf
+  free(resfile);
+}
+
+void cDVDPlayerResume::SetResume(const char* key, int title, int chapter, int64_t second)
+{
+  // (re)load resume data from file to be actual
+  LoadResume();
+  cResumeEntry* re = FindResume(key);
+  if (re) {
+    // found a resume entry, so we can update it.
+    DEBUGDVD("resume: setting resume %d:%d:%lld (update)", title, chapter, second);
+  } else {
+    // no resume entry found yet, creating a new one
+    re = new cResumeEntry;
+    re->key = strdup(key);
+    Add(re);
+    DEBUGDVD("resume: setting resume %d:%d:%lld (new)", title, chapter, second);
+  }
+  // set the new resume data for the found/created entry
+  re->title = title;
+  re->chapter = chapter;
+  re->second = second;
+  // and mark memory database as modified to be saved.
+  modified = true;
+  // save it now (sync!)
+  SaveResume();
+}
+
+bool cDVDPlayerResume::GetResume(const char* key, int& title, int& chapter, int64_t& second)
+{
+  // (re)load the resume file to have actual values
+  LoadResume();
+  cResumeEntry* re = FindResume(key);
+  if (re) {
+    // found a resume entry, copy values
+    title = re->title;
+    chapter = re->chapter;
+    second = re->second;
+    // indicate successful search
+    return true;
+  }
+  // no resume entry found in database
+  return false;
+}
+
+void cDVDPlayerResume::LoadResume()
+{
+  // we will load the file for sure and add all entries, clear all old entries.
+  Clear();
+  // no entries == no modifications
+  modified = false;
+  DEBUGDVD("resume: resume file is \"%s\"\n",resfile);
+  FILE *f = fopen(resfile,"r");
+  if (f) {
+    DEBUGDVD("resume: successfully opened resume file\n");
+    char line[768];
+    // read file line by line
+    while(fgets(line,sizeof(line),f)) {
+      char key[512];
+      int t, c;
+      int64_t s;
+      // parse line as "title:chapter:second:key"
+      if(sscanf(line,"%d:%d:%lld:%511[^\n]",&t,&c,&s,key) == 4) {
+        // successful parse, save in resume entry
+        cResumeEntry *re = new cResumeEntry;
+        re->key = strdup(key);
+        re->title = t;
+        re->chapter = c;
+        re->second = s;
+        // and add it to memory database
+        Add(re);
+      }
+    }
+    // don't forget to close what you have opened!
+    fclose(f);
+  }
+  // unsuccessful open leads to empty database as the file does not exists
+}
+
+bool cDVDPlayerResume::SaveResume(void)
+{
+  if(modified) {
+    // modification indicated, save the database to the resume file
+    DEBUGDVD("resume: saving resume file\n");
+    cSafeFile f(resfile);
+    if(f.Open()) {
+      // forall resume entries in the memory database
+      for (cResumeEntry *re=First(); re; re=Next(re)) {
+        // save the as one line in the format "title:chapter:second:key"
+        fprintf(f, "%d:%d:%lld:%s\n", re->title, re->chapter, re->second, re->key);
+      }
+      // don't forget to close what you have opened!
+      f.Close();
+      // signal successful save
+      return true;
+    } else {
+      DEBUGDVD("resume: failed to save resume file\n");
+      // saving did not succeed!!!!
+      return false;
+    }
+  } else {
+    // no modifications -> successful "save" :-)
+    return true;
+  }
+}
+
+cResumeEntry *cDVDPlayerResume::FindResume(const char* key)
+{
+  DEBUGDVD("resume: searching resume  position for \"%s\"\n", key);
+  // iterate over all entries in the memory database
+  for(cResumeEntry *re=First(); re; re=Next(re)) {
+    if (!strcasecmp(re->key, key)) {
+      // return the entry iff the keys match
+      DEBUGDVD("resume: found resume position %d:%d:%lld\n",re->title, re->chapter, re->second);
+      return re;
+    }
+  }
+  DEBUGDVD("resume: no resume position found\n");
+  return NULL;
+}
+
+
 // --- cDvdPlayer ------------------------------------------------------------
 
 //XXX+ also used in recorder.c - find a better place???
@@ -288,6 +504,9 @@ cDvdPlayer::cDvdPlayer(void): cThread("dvd-plugin"), a52dec(*this) {
     skipPlayVideo=false;
     fastWindFactor=1;
 
+    // resume
+    resume = new cDVDPlayerResume;
+
     clearSeenSubpStream();
     clearSeenAudioTrack();
 
@@ -334,6 +553,8 @@ cDvdPlayer::~cDvdPlayer()
 
     if(aspect_str)
 		free(aspect_str);
+
+    delete resume;
 }
 
 void cDvdPlayer::setController (cDvdPlayerControl *ctrl )
@@ -570,6 +791,100 @@ uint64_t cDvdPlayer::delay_ticks(uint64_t ticks)
 #endif
 }
 
+char* cDvdPlayer::GetDVDResumeKey() const {
+  // first we fetch the total number of titles of the current dvd
+  int totalTitles;
+  if (dvdnav_get_number_of_titles(nav, &totalTitles)) {
+    // then we sum up the numbers of chapters for each title
+    int totalChapters = 0;
+    for (int t = 1; t <= totalTitles; t++) {
+      int curChapters;
+      dvdnav_get_number_of_parts(nav, t, &curChapters);
+      totalChapters += curChapters;
+      DEBUGDVD("resume: cDvdPlayer::Action() Title %d has %d chapters.\n", t, curChapters);
+    }
+    DEBUGDVD("resume: cDvdPlayer::Action() Titles: %d with %d chapters all together, Title: \"%s\"\n",
+             totalTitles, totalChapters, title_str);
+    // finally the key is build as "DVDName_TotalTitles_OverallChapters"
+    char* key;
+    asprintf(&key, "%s_%d_%d", title_str, totalTitles, totalChapters);
+    // note: this is not completly unique. Maybe some other informations are more suitable, like:
+    // - the "serial number" of the dvd as displayed in the libdvdnav debug output, but:
+    //   it is not available through the current libdvdnav api
+    // - the total bytes of the dvd (quiet unique!!!), but:
+    //   also not available through the libdvdnav api and no idea how to get it for a media not mounted.
+    // - any other ideas???
+    return key;
+  } else {
+    // if we cannot fetch the total number of titles of the current disc, there must be something wrong!
+    // Who needs a key for resuming then?
+    return NULL;
+  }
+}
+
+void cDvdPlayer::SaveResume() {
+  // make sure resume database is allocated (might be a possibility to completly disable resuming!)
+  if (resume) {
+    // fetch the current title and chapter number via libdvdnav api
+    int currentTitle, currentChapter;
+    if (dvdnav_current_title_info(nav, &currentTitle, &currentChapter) &&
+        (0 != currentTitle)) {
+      // fetch current time position through own class api
+      int64_t currentSec, totalSec;
+      GetPositionInSec(currentSec, totalSec);
+      // compute the resume key for the current dvd
+      char* key = GetDVDResumeKey();
+      if (key) {
+        // store computed/fetched resume data in database
+        DEBUGDVD("resume->SetResume(\"%s\", %d, %d, %lld)\n", key, currentTitle, currentChapter, currentSec);
+        resume->SetResume(key, currentTitle, currentChapter, currentSec);
+        // free the key string memory allocated by GetDVDResumeKey()
+        free(key);
+      } else {
+        DEBUGDVD("resume: ERROR computing resume key for this dvd!\n");
+      }
+    } else {
+      // in a menu title and chapter seams to be always 0 -> no way to resume there!
+      DEBUGDVD("resume: ERROR fetching current title and chapter (maybe in menus?).\n");
+    }
+  }
+}
+
+bool cDvdPlayer::LoadResume(int& title, int& chapter, int64_t& second) {
+  // helper variable for the return value
+  bool retval = false;
+  // make sure resume database is allocated (might be a possibility to completly disable resuming!)
+  if(resume) {
+    // compute the resume key for the current dvd
+    char* key = GetDVDResumeKey();
+    if (key) {
+      DEBUGDVD("resume->GetResume(\"%s\", ...): ", key);
+      // try loading the resume data for the computed key into the given arguments
+      if (resume->GetResume(key, title, chapter, second)) {
+        DEBUGDVD("%d:%d:%lld\n", title, chapter, second);
+        // continuing at the very same position might be inappropriate (vdr's recordings also rewind some seconds)
+        int ResumeRewind = 30; // rewind 30s if possible
+        // note: I used a variable here to show up, that this value might be made
+        //       possible to configure (in the setup dialog). Doing so myself was
+        //       not yet nesseccary and is so left to the plugin maintainers.
+        // make sure we do not rewind before the beginning
+        if (second > ResumeRewind) {
+          second -= ResumeRewind;
+        }
+        retval = true;
+      } else {
+        DEBUGDVD("<none>\n");
+        retval = false;
+      }
+      // free the key string memory allocated by GetDVDResumeKey()
+      free(key);
+    } else {
+      DEBUGDVD("resume: ERROR computing resume key for this dvd.\n");
+    }
+  }
+  return retval;
+}
+
 void cDvdPlayer::Action(void) {
     memset(event_buf, 0, sizeof(uint8_t)*4096);
 
@@ -641,6 +956,13 @@ void cDvdPlayer::Action(void) {
 
     bool firstClear = true;
 
+    // we need to know the very first VTS change to hook inthe resume call
+    bool first_vts_change = true;
+    // we cannot directly resume to the exact time, so we hook on the next cell change when resuming
+    bool next_cell_change = false;
+    // and seek the the exact time stored here
+    int64_t resSecond = 0;
+
     while(running && nav) {
 
         if (!pframe) {
@@ -1119,6 +1441,22 @@ void cDvdPlayer::Action(void) {
 	      SetTitleInfoString();
 	      SetTitleString();
 	      SetAspectString();
+              if (first_vts_change) {
+                first_vts_change = false;
+
+                // now all data for computing the resume key is available, so trying to resume
+                int resTitle, resChapter;
+                if (LoadResume(resTitle, resChapter, resSecond)) {
+                  // if resume data could be found seek to the found title and chapter NOW
+                  GotoTitle(resTitle, resChapter);
+                  // and wait for the next cell change (= title and chapter reached)
+                  // to seek to the exact time
+                  next_cell_change = true;
+                  // note: seeking to the exact time HERE leads to an error on the libdvdnav console:
+                  //       "dvd error dvdnav_sector_search: New position not yet determined." and is
+                  //       slightly ignored :-( .
+                }
+              }
 	      break;
 	  case DVDNAV_CELL_CHANGE: {
 	      DEBUG_NAV("%s:%d:NAV CELL CHANGE\n", __FILE__, __LINE__);
@@ -1139,6 +1477,11 @@ void cDvdPlayer::Action(void) {
 	      // cell change .. game over ..
 	      changeNavSubpStreamOnceInSameCell=false;
     	  SetTitleInfoString();
+	      if (next_cell_change) {
+	        next_cell_change = false;
+	        // we are resuming the current dvd. NOW its time to seek to the correct second.
+	        Goto(resSecond);
+	      }
 	      break;
 	  }
 	  case DVDNAV_NAV_PACKET: {
@@ -1902,8 +2245,18 @@ void cDvdPlayer::Stop(void)
     if (!DVDActiveAndRunning())
         return;
 
-    if (running && nav)
+    if (running && nav) {
+        // we will stop replay now. Its time to save the current possition
+        // for later resuming.
+        SaveResume();
+
         dvdnav_stop(nav);
+
+        // don't know why Stop() is called twice, but this prevents from
+        // twice save resume data and calling dvdnav_stop() twice.
+        // Comments from maintainers are welcome.
+        running = false;
+    }
 }
 
 void cDvdPlayer::Play(void)
@@ -2219,24 +2572,41 @@ void cDvdPlayer::NextAngle(void)
     GotoAngle(++angleNumber);
 }
 
-int cDvdPlayer::GotoTitle(int Title)
+// GotoTitle now optionally takes a chapter to seek to in the given title.
+int cDvdPlayer::GotoTitle(int Title, int Chapter /*= 1*/)
 {
     int titleNumbers;
+    int targetTitle = Title;
+    int chapterNumber;
     if (!DVDActiveAndRunning())
         return -1;
     LOCK_THREAD;
     DEBUG_NAV("DVD NAV SPU clear & empty %s:%d\n", __FILE__, __LINE__);
     Empty();
 
+    // check if the given title is in the title range of this dvd
     dvdnav_get_number_of_titles(nav, &titleNumbers);
 
     if (Title > titleNumbers)
-        Title = 1;
+        targetTitle = 1;
     if (Title <= 0)
-        Title = titleNumbers;
+        targetTitle = titleNumbers;
+
+    // if given title is in the bounds of this dvd's title range
+    if (Title == targetTitle) {
+        // check if the chapter is in the title's chapter range
+        dvdnav_get_number_of_parts(nav, Title, &chapterNumber);
+        if (Chapter > chapterNumber)
+            Chapter = 1;
+        if (Chapter <= 0)
+            Chapter = chapterNumber;
+    } else {
+        // otherwise reset it to the first chapter.
+        Chapter = 1;
+    }
 
     if (stillTimer == 0) {
-        dvdnav_part_play(nav, Title, 1);
+        dvdnav_part_play(nav, Title, Chapter);
         // dvdnav_title_play(nav, Title);
     }
 
diff --git a/player-dvd.h b/player-dvd.h
index 319314a..8f9d5c8 100644
--- a/player-dvd.h
+++ b/player-dvd.h
@@ -54,6 +54,7 @@ class IntegerListObject : public cListObject {
 
 class cDvdPlayerControl ;
 class cIframeAssembler;
+class cDVDPlayerResume;
 
 class cDvdPlayer : public cPlayer, cThread {
  private:
@@ -188,6 +189,32 @@ class cDvdPlayer : public cPlayer, cThread {
     int  GetAudioStreamNumbers(void) const ;
     uint16_t GetSubtitleLanguageCode(int Channel) const;
     int  GetSubtitleStreamNumbers(void) const ;
+
+    //resuming
+    /**
+     * the resume database
+     */
+    cDVDPlayerResume* resume;
+    /**
+     * GetDVDResumeKey():
+     * computes a (hopefully) unique id for storing the resume data of the current disc.
+     *
+     * this get returns a new allocated memory area ..
+     * must be freed by callee ..
+     */
+    char* GetDVDResumeKey() const;
+    /**
+     * SaveResume():
+     * handles everything to save the current position on the disc for later resuming.
+     */
+    void SaveResume();
+    /**
+     * LoadResume():
+     * loads the resume data for the current disc and stores it in the given arguments.
+     * returns false if no resume data for the disc can be found or and error occured while loading.
+     */
+    bool LoadResume(int& title, int& chapter, int64_t& second);
+
 protected: //Player
     virtual void Activate(bool On);
     virtual void Action(void);
@@ -320,7 +347,8 @@ public:
      *
      * return set title ..
      */
-    int GotoTitle(int Title);
+    // GotoTitle now optionally takes a chapter to seek to in the given title
+    int GotoTitle(int Title, int Chapter = 1);
 
     /**
      * jump to the previous Title (rotate)
diff --git a/po/de_DE.po b/po/de_DE.po
index 017e2e7..d59c68a 100644
--- a/po/de_DE.po
+++ b/po/de_DE.po
@@ -26,19 +26,19 @@ msgid "Plugin.DVD$DVD"
 msgstr "DVD"
 
 msgid "Error.DVD$Error opening DVD!"
-msgstr "Fehler beim �ffnen der DVD!"
+msgstr "Fehler beim �ffnen der DVD!"
 
 msgid "Error.DVD$Error fetching data from DVD!"
-msgstr "Fehler beim lesen von der DVD!"
+msgstr "Fehler beim Lesen von der DVD!"
 
 msgid "Setup.DVD$Preferred menu language"
-msgstr "Bevorzugte Spache f�r Men�s"
+msgstr "Bevorzugte Sprache f�r Men�s"
 
 msgid "Setup.DVD$Preferred audio language"
 msgstr "Bevorzugte Sprache f�r Dialog"
 
 msgid "Setup.DVD$Preferred subtitle language"
-msgstr "Bevorzugte Spache f�r Untertitel"
+msgstr "Bevorzugte Sprache f�r Untertitel"
 
 msgid "Setup.DVD$Player region code"
 msgstr "Regionalkode f�r DVD Spieler"

Debdiff

[The following lists of changes regard files as different if they have different names, permissions or owners.]

Files in second set of .debs but not in first

-rw-r--r--  root/root   /usr/lib/debug/.build-id/b3/18cad0522788200de6b43d9c9fd4a004f9fba7.debug
-rw-r--r--  root/root   /usr/lib/vdr/plugins/libvdr-dvd.so.2.6.1

Files in first set of .debs but not in second

-rw-r--r--  root/root   /usr/lib/debug/.build-id/49/db97d3249a6c475c4ad6585d79723d9a2c7700.debug
-rw-r--r--  root/root   /usr/lib/vdr/plugins/libvdr-dvd.so.2.6.0

No differences were encountered between the control files of package vdr-plugin-dvd

Control files of package vdr-plugin-dvd-dbgsym: lines which differ (wdiff format)

  • Build-Ids: 49db97d3249a6c475c4ad6585d79723d9a2c7700 b318cad0522788200de6b43d9c9fd4a004f9fba7

More details

Full run details