Index: src/dvdnav.c
===================================================================
--- libdvdnav.orig/src/dvdnav.c	(revision 1168)
+++ libdvdnav/src/dvdnav.c	(working copy)
@@ -71,6 +71,67 @@
   return DVDNAV_STATUS_OK;
 }
 
+dvdnav_status_t dvdnav_dup(dvdnav_t **dest, dvdnav_t *src) {
+  dvdnav_t *this;
+
+  (*dest) = NULL;
+  this = (dvdnav_t*)malloc(sizeof(dvdnav_t));
+  if(!this)
+    return DVDNAV_STATUS_ERR;
+
+  memcpy(this, src, sizeof(dvdnav_t));
+  this->file = NULL;
+
+  pthread_mutex_init(&this->vm_lock, NULL);
+
+  this->vm = vm_new_copy(src->vm);
+  if(!this->vm) {
+    printerr("Error initialising the DVD VM.");
+    pthread_mutex_destroy(&this->vm_lock);
+    free(this);
+    return DVDNAV_STATUS_ERR;
+  }
+
+  /* Start the read-ahead cache. */
+  this->cache = dvdnav_read_cache_new(this);
+
+  (*dest) = this;
+  return DVDNAV_STATUS_OK;
+}
+
+dvdnav_status_t dvdnav_free_dup(dvdnav_t *this) {
+
+#ifdef LOG_DEBUG
+  fprintf(MSG_OUT, "libdvdnav: free_dup:called\n");
+#endif
+
+  if (this->file) {
+    pthread_mutex_lock(&this->vm_lock);
+    DVDCloseFile(this->file);
+#ifdef LOG_DEBUG
+    fprintf(MSG_OUT, "libdvdnav: close:file closing\n");
+#endif
+    this->file = NULL;
+    pthread_mutex_unlock(&this->vm_lock);
+  }
+
+  /* Free the VM */
+  if(this->vm)
+    vm_free_copy(this->vm);
+
+  pthread_mutex_destroy(&this->vm_lock);
+
+  /* We leave the final freeing of the entire structure to the cache,
+   * because we don't know, if there are still buffers out in the wild,
+   * that must return first. */
+  if(this->cache)
+    dvdnav_read_cache_free(this->cache);
+  else
+    free(this);
+
+  return DVDNAV_STATUS_OK;
+}
+
 dvdnav_status_t dvdnav_open(dvdnav_t** dest, const char *path) {
   dvdnav_t *this;
   struct timeval time;
Index: src/dvdnav/dvdnav.h
===================================================================
--- libdvdnav.orig/src/dvdnav/dvdnav.h	(revision 1168)
+++ libdvdnav/src/dvdnav/dvdnav.h	(working copy)
@@ -89,6 +89,9 @@
  */
 dvdnav_status_t dvdnav_open(dvdnav_t **dest, const char *path);
 
+dvdnav_status_t dvdnav_dup(dvdnav_t **dest, dvdnav_t *src);
+dvdnav_status_t dvdnav_free_dup(dvdnav_t *this);
+
 /*
  * Closes a dvdnav_t previously opened with dvdnav_open(), freeing any
  * memory associated with it.
Index: src/vm/vm.c
===================================================================
--- libdvdnav.orig/src/vm/vm.c	(revision 1168)
+++ libdvdnav/src/vm/vm.c	(working copy)
@@ -96,6 +98,7 @@
 
 static pgcit_t* get_MENU_PGCIT(vm_t *vm, ifo_handle_t *h, uint16_t lang);
 static pgcit_t* get_PGCIT(vm_t *vm);
+static void vm_close(vm_t *vm);
 
 
 /* Helper functions */
@@ -262,7 +265,7 @@
 }
 
 void vm_free_vm(vm_t *vm) {
-  vm_stop(vm);
+  vm_close(vm);
   free(vm);
 }
 
@@ -289,12 +292,20 @@
 
 int vm_start(vm_t *vm) {
   /* Set pgc to FP (First Play) pgc */
+  if (vm->stopped) {
+    vm_reset(vm, NULL);
+    vm->stopped = 0;
+  }
   set_FP_PGC(vm);
   process_command(vm, play_PGC(vm));
   return !vm->stopped;
 }
 
 void vm_stop(vm_t *vm) {
+  vm->stopped = 1;
+}
+
+static void vm_close(vm_t *vm) {
   if(vm->vmgi) {
     ifoClose(vm->vmgi);
     vm->vmgi=NULL;
@@ -346,7 +357,7 @@
 
   if (vm->dvd && dvdroot) {
     /* a new dvd device has been requested */
-    vm_stop(vm);
+    vm_close(vm);
   }
   if (!vm->dvd) {
     vm->dvd = DVDOpen(dvdroot);
