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);