summaryrefslogtreecommitdiff
path: root/src/input/input_dvd.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/input/input_dvd.c')
-rw-r--r--src/input/input_dvd.c1841
1 files changed, 1184 insertions, 657 deletions
diff --git a/src/input/input_dvd.c b/src/input/input_dvd.c
index 6e87dc282..d37734d89 100644
--- a/src/input/input_dvd.c
+++ b/src/input/input_dvd.c
@@ -1,5 +1,6 @@
-/*
- * Copyright (C) 2000-2001 the xine project
+/*
+ * Copyright (C) 2000, 2001 the xine project,
+ * Rich Wareham <richwareham@users.sourceforge.net>
*
* This file is part of xine, a unix video player.
*
@@ -7,871 +8,1397 @@
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
+ *
* xine is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*
- * $Id: input_dvd.c,v 1.52 2002/07/05 17:32:01 mroi Exp $
+ * $Id: input_dvd.c,v 1.53 2002/08/08 17:49:21 richwareham Exp $
+ *
+ */
+
+/* This file was origninally part of the xine-dvdnav project
+ * at http://dvd.sf.net/.
+ */
+
+/* TODO:
+ *
+ * - Proper internationalisation of strings.
+ * - Failure dialogue.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
-#include <dlfcn.h>
+/* Standard includes */
#include <stdio.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <errno.h>
-#include <unistd.h>
#include <stdlib.h>
+#include <dirent.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <time.h>
#include <string.h>
-#include <inttypes.h>
-
-#ifdef HAVE_SYS_CDIO_H
-# include <sys/cdio.h>
-#endif
-#ifdef HAVE_LINUX_CDROM_H
-# include <linux/cdrom.h>
-#elif defined __FreeBSD__
-# include "sys/dvdio.h"
-#endif
-#if ! defined (HAVE_LINUX_CDROM_H) && ! defined (HAVE_SYS_CDIO_H)
-#error "you need to add dvd support for your platform to input_dvd.c and configure.in"
-#endif
+#include <errno.h>
-#include "xine_internal.h"
-#include "xineutils.h"
-#include "input_plugin.h"
-#include "dvd_udf.h"
-#include "read_cache.h"
+#include <sys/mount.h>
+#include <sys/wait.h>
-extern int errno;
+#include <sys/poll.h>
+#include <sys/ioctl.h>
-#ifdef __GNUC__
-#define LOG_MSG_STDERR(xine, message, args...) { \
- xine_log(xine, XINE_LOG_MSG, message, ##args); \
- fprintf(stderr, message, ##args); \
- }
-#define LOG_MSG(xine, message, args...) { \
- xine_log(xine, XINE_LOG_MSG, message, ##args); \
- printf(message, ##args); \
- }
+#if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__)
+#include <sys/dvdio.h>
+#include <sys/cdio.h> /* CDIOCALLOW etc... */
+#elif defined(__linux__)
+#include <linux/cdrom.h>
#else
-#define LOG_MSG_STDERR(xine, ...) { \
- xine_log(xine, XINE_LOG_MSG, __VA_ARGS__); \
- fprintf(stderr, __VA_ARGS__); \
- }
-#define LOG_MSG(xine, ...) { \
- xine_log(xine, XINE_LOG_MSG, __VA_ARGS__); \
- printf(__VA_ARGS__); \
- }
+#error "Need the DVD ioctls"
#endif
+/* Xine includes */
+#include <xine/xineutils.h>
+#include <xine/buffer.h>
+#include <xine/input_plugin.h>
+#include <xine/video_out.h>
+#include <xine/events.h>
+#include <xine/metronom.h>
+#include <xine/spu_decoder_api.h>
+#include <xine/xine_internal.h>
+
+/* DVDNAV includes */
+#include <dvdnav.h>
+
+/* libdvdread includes */
+#include <dvdread/nav_read.h>
+
+/* Print debug messages? */
+/* #define INPUT_DEBUG 1 */
+
+/* Print trace messages? */
+/* #define INPUT_DEBUG_TRACE */
+
+/* Print debug of eject */
+/* #define LOG_DVD_EJECT */
+
+/* Current play mode (title only or menus?) */
+#define MODE_NAVIGATE 0
+#define MODE_TITLE 1
+
+/* Is seeking enabled? 1 - Yes, 0 - No */
+#define CAN_SEEK 1
+
+/* The default DVD device on Solaris is not /dev/dvd */
#if defined(__sun)
-#define RDVD "/vol/dev/aliases/cdrom0"
-#define DVD RDVD
+#define DVD_PATH "/vol/dev/aliases/cdrom0"
#else
-#define DVD "/dev/dvd"
-#define RDVD "/dev/rdvd"
+#define DVD_PATH "/dev/dvd"
+#endif
+
+/* Some misc. defines */
+#define DVD_BLOCK_SIZE 2048
+#ifndef BUF_DEMUX_BLOCK
+#define BUF_DEMUX_BLOCK 0x05000000
#endif
+#define VIDEO_FILL_THROTTLE 5
-typedef struct {
+/* Debugging macros */
+#if INPUT_DEBUG
+#define dprint(s, args...) fprintf(stderr, __FUNCTION__ ": " s, ##args);
+#else
+#define dprint(s, args...) /* Nowt */
+#endif
- input_plugin_t input_plugin;
+#if INPUT_DEBUG_TRACE
+#define trace_print(s, args...) fprintf(stdout, __FUNCTION__ ": " s, ##args);
+#else
+#define trace_print(s, args...) /* Nothing */
+#endif
- xine_t *xine;
-
- char *mrl;
- config_values_t *config;
-
- int dvd_fd;
- int raw_fd;
- read_cache_t *read_cache;
- off_t file_size;
- off_t file_size_left;
- int file_lbstart;
- int file_lbcur;
- int gVTSMinor;
- int gVTSMajor;
-
- const char *device;
- const char *raw_device;
+/* Globals */
+extern int errno;
- /*
- * udf dir function
- */
+/* Array to hold MRLs returned by get_autoplay_list */
#define MAX_DIR_ENTRIES 250
-
- char *filelist[MAX_DIR_ENTRIES];
- char *filelist2[MAX_DIR_ENTRIES];
-
- int mrls_allocated_entries;
- mrl_t **mrls;
+#define MAX_STR_LEN 255
+char filelist[MAX_DIR_ENTRIES][MAX_STR_LEN];
+char *filelist2[MAX_DIR_ENTRIES];
-} dvd_input_plugin_t;
+/* A Temporary string (FIXME: May cause problems if multiple
+ * dvdnavs in multiple threads). */
+char temp_str[256];
+#define TEMP_STR_LEN 255
+typedef struct {
+ input_plugin_t input_plugin; /* Parent input plugin type */
+ int pause_timer; /* Cell stil-time timer */
+ int pause_counter;
+ time_t pause_end_time;
+ int32_t buttonN;
-/* ***************************************************************** */
-/* Private functions */
-/* ***************************************************************** */
-/*
- * Callbacks for configuratoin changes.
- */
-static void device_change_cb(void *data, cfg_entry_t *cfg) {
- dvd_input_plugin_t *this = (dvd_input_plugin_t *) data;
+ /* Flags */
+ int opened; /* 1 if the DVD device is already open */
- this->device = cfg->str_value;
-}
-
-static void rawdevice_change_cb(void *data, cfg_entry_t *cfg) {
- dvd_input_plugin_t *this = (dvd_input_plugin_t *) data;
+ /* Xine specific variables */
+ config_values_t *config; /* Pointer to XineRC config file */
+ char *dvd_device; /* Default DVD device */
+ char *current_dvd_device; /* DVD device currently open */
+ char *mrl; /* Current MRL */
+ int mode;
+ dvdnav_t *dvdnav; /* Handle for libdvdnav */
+ xine_t *xine;
+ char dvd_name[128];
+ size_t dvd_name_length;
+ mrl_t **mrls;
+ int num_mrls;
- this->raw_device = cfg->str_value;
-}
-
-static int openDrive (dvd_input_plugin_t *this) {
+ /* special buffer handling for libdvdnav caching */
+ pthread_mutex_t buf_mutex;
+ void *source;
+ void (*free_buffer)(buf_element_t *);
+ int mem_stack;
+ unsigned char *mem[1024];
+} dvdnav_input_plugin_t;
+
+static void flush_buffers(dvdnav_input_plugin_t *this);
+static void xine_dvdnav_send_button_update(dvdnav_input_plugin_t *this, int mode);
+
+/* Callback on device name change */
+static void device_change_cb(void *data, cfg_entry_t *cfg) {
+ dvdnav_input_plugin_t *this = (dvdnav_input_plugin_t *) data;
- this->dvd_fd = open(this->device, O_RDONLY /* | O_NONBLOCK */ );
-
- if (this->dvd_fd < 0) {
- LOG_MSG(this->xine, _("input_dvd: unable to open dvd drive (%s): %s\n"),
- this->device, strerror(errno));
- return -1;
- }
-
- this->raw_fd = open(this->raw_device, O_RDONLY /* | O_NONBLOCK */ );
- if (this->raw_fd < 0) {
- this->raw_fd = this->dvd_fd;
- }
+ this->dvd_device = cfg->str_value;
+}
- read_cache_set_fd (this->read_cache, this->raw_fd);
+static uint32_t dvdnav_plugin_get_capabilities (input_plugin_t *this_gen) {
+ trace_print("Called\n");
- return this->raw_fd;
+ return INPUT_CAP_AUTOPLAY | INPUT_CAP_BLOCK | INPUT_CAP_CLUT |
+#if CAN_SEEK
+ INPUT_CAP_SEEKABLE | INPUT_CAP_VARIABLE_BITRATE |
+#endif
+ INPUT_CAP_AUDIOLANG | INPUT_CAP_SPULANG | INPUT_CAP_GET_DIR | INPUT_CAP_CHAPTERS;
}
-static void closeDrive (dvd_input_plugin_t *this) {
+void read_ahead_cb(void *this_gen, cfg_entry_t *entry) {
+ dvdnav_input_plugin_t *this = (dvdnav_input_plugin_t*)this_gen;
- if (this->dvd_fd < 0)
- return;
-
- close (this->dvd_fd);
- if (this->raw_fd != this->dvd_fd)
- close (this->raw_fd);
+ if(!this)
+ return;
- this->dvd_fd = -1;
+ if(!this->dvdnav)
+ return;
+ dvdnav_set_readahead_flag(this->dvdnav, entry->num_value);
}
+
+void region_changed_cb(void *this_gen, cfg_entry_t *entry) {
+ dvdnav_input_plugin_t *this = (dvdnav_input_plugin_t*)this_gen;
-#ifdef __sun
-#include <sys/scsi/generic/commands.h>
-#include <sys/scsi/impl/uscsi.h>
-#include <sys/stat.h>
-
-/* SCSI mmc3 DVD Commands */
-#define GPCMD_READ_DVD_STRUCTURE 0xad
-#define GPCMD_SEND_DVD_STRUCTURE 0xad
-#define GPCMD_REPORT_KEY 0xa4
-#define GPCMD_SEND_KEY 0xa3
+ if(!this)
+ return;
-/* DVD struct types */
-#define DVD_STRUCT_PHYSICAL 0x00
-#define DVD_STRUCT_COPYRIGHT 0x01
-#define DVD_STRUCT_DISCKEY 0x02
-#define DVD_STRUCT_BCA 0x03
-#define DVD_STRUCT_MANUFACT 0x04
+ if(!this->dvdnav)
+ return;
-struct dvd_copyright {
- uint8_t type;
+ if((entry->num_value >= 1) && (entry->num_value <= 8)) {
+ /* FIXME: Remove debug message */
+ dprint("Setting region code to %i (0x%x)\n",
+ entry->num_value, 1<<(entry->num_value-1));
+ dvdnav_set_region_mask(this->dvdnav, 1<<(entry->num_value-1));
+ }
+}
- uint8_t layer_num;
- uint8_t cpst;
- uint8_t rmi;
-};
+void language_changed_cb(void *this_gen, cfg_entry_t *entry) {
+ dvdnav_input_plugin_t *this = (dvdnav_input_plugin_t*)this_gen;
-typedef union {
- uint8_t type;
+ if(!this)
+ return;
-/*
- struct dvd_physical physical;
-*/
- struct dvd_copyright copyright;
-/*
- struct dvd_disckey disckey;
- struct dvd_bca bca;
- struct dvd_manufact manufact;
-*/
-} dvd_struct;
+ if(!this->dvdnav)
+ return;
+ dvdnav_menu_language_select(this->dvdnav, entry->str_value);
+ dvdnav_audio_language_select(this->dvdnav, entry->str_value);
+ dvdnav_spu_language_select(this->dvdnav, entry->str_value);
+}
+
+void update_title_display(dvdnav_input_plugin_t *this) {
+ xine_ui_event_t uevent;
+ int tt=-1, pr=-1;
+ size_t temp_str_length=0;
-/*
- * Read DVD "Copyright Structure" from DVD Drive
- */
-static int
-dvd_read_copyright(dvd_input_plugin_t *this, dvd_struct *s)
-{
- struct uscsi_cmd sc;
- union scsi_cdb rs_cdb;
- uint8_t buf[8];
-
- memset(&rs_cdb, 0, sizeof(rs_cdb));
- rs_cdb.scc_cmd = GPCMD_READ_DVD_STRUCTURE;
- rs_cdb.cdb_opaque[6] = s->copyright.layer_num;
- rs_cdb.cdb_opaque[7] = s->type;
- rs_cdb.cdb_opaque[8] = (sizeof(buf) >> 8) & 0xff;
- rs_cdb.cdb_opaque[9] = sizeof(buf) & 0xff;
-
- memset(&sc, 0, sizeof(sc));
- sc.uscsi_cdb = (caddr_t)&rs_cdb;
- sc.uscsi_cdblen = 12;
- sc.uscsi_bufaddr = buf;
- sc.uscsi_buflen = sizeof(buf);
- sc.uscsi_flags = USCSI_ISOLATE|USCSI_READ;
- sc.uscsi_timeout = 15;
+ if(!this || !(this->xine))
+ return;
- memset(buf, 0, sizeof(buf));
+ /* Set title/chapter display */
+ uevent.event.type = XINE_EVENT_UI_SET_TITLE;
+ uevent.data = temp_str;
- if (ioctl(this->raw_fd, USCSICMD, &sc)) {
- LOG_MSG(this->xine, _("USCSICMD dvd_read_copyright: %s"), strerror(errno));
- return -1;
+ dvdnav_current_title_info(this->dvdnav, &tt, &pr);
+
+ if(tt != -1) {
+ int num_angle = 0, cur_angle = 0;
+ /* no menu here */
+ /* Reflect angle info if appropriate */
+ dvdnav_get_angle_info(this->dvdnav, &cur_angle, &num_angle);
+ if(num_angle > 1) {
+ snprintf(temp_str, TEMP_STR_LEN,
+ "Title %i, Chapter %i, Angle %i of %i",
+ tt,pr,cur_angle, num_angle);
+ } else {
+ snprintf(temp_str, TEMP_STR_LEN,
+ "Title %i, Chapter %i",
+ tt,pr);
+ }
+ } else {
+ strcpy(temp_str, "DVD Navigator: Menu");
}
- if (sc.uscsi_status) {
- LOG_MSG_STDERR(this->xine, _("bad status: READ DVD STRUCTURE (copyright)\n"));
- return -1;
+ temp_str_length = strlen(temp_str);
+
+ if (this->dvd_name[0] != 0 && (temp_str_length + this->dvd_name_length < TEMP_STR_LEN)) {
+ snprintf(temp_str+temp_str_length, TEMP_STR_LEN - temp_str_length,
+ ", %s",
+ &this->dvd_name[0]);
}
+
+ dprint("Changing title to read '%s'\n", temp_str);
+ xine_send_event(this->xine, &uevent.event);
+}
- s->copyright.cpst = buf[4];
- s->copyright.rmi = buf[5];
+static void dvdnav_plugin_stop (input_plugin_t *this_gen) {
+ dvdnav_input_plugin_t *this = (dvdnav_input_plugin_t*) this_gen;
+ fprintf(stderr, "dvdnav_plugin_stop called.\n");
+ if (this->dvdnav) {
+ fprintf(stderr, "Now get out of still.\n");
+ dvdnav_still_skip(this->dvdnav);
+ }
+}
- return 0;
+static void dvdnav_plugin_close (input_plugin_t *this_gen) {
+ dvdnav_input_plugin_t *this = (dvdnav_input_plugin_t*)this_gen;
+
+ trace_print("Called\n");
+
+ if(this->opened)
+ dvdnav_close(this->dvdnav);
+ this->dvdnav = NULL;
+ this->opened = 0;
+ this->dvd_name[0] = 0;
+ this->dvd_name_length = 0;
}
+static void dvdnav_build_mrl_list(dvdnav_input_plugin_t *this) {
+ int num_titles, *num_parts;
-/*
- * Check the environment, if we're running under sun's
- * vold/rmmount control.
- */
-static void
-check_solaris_vold_device(dvd_input_plugin_t *this)
-{
- char *volume_device;
- char *volume_name;
- char *volume_action;
- char *device;
- struct stat stb;
+ /* skip DVD if already open */
+ if (this->opened) return;
+ if (this->mrls) {
+ free(this->mrls);
+ this->mrls = NULL;
+ this->num_mrls = 0;
+ }
- if ((volume_device = getenv("VOLUME_DEVICE")) != NULL &&
- (volume_name = getenv("VOLUME_NAME")) != NULL &&
- (volume_action = getenv("VOLUME_ACTION")) != NULL &&
- strcmp(volume_action, "insert") == 0) {
+ if (dvdnav_open(&(this->dvdnav),
+ this->current_dvd_device) == DVDNAV_STATUS_ERR)
+ return;
+
+ dvdnav_get_number_of_titles(this->dvdnav, &num_titles);
+ if ((num_parts = (int *) calloc(num_titles, sizeof(int)))) {
+ int num_mrls = 1, i;
+ /* for each title, count the number of programs */
+ for (i = 1; i <= num_titles; i++) {
+ num_parts[i-1] = 0;
+ dvdnav_title_play(this->dvdnav, i);
+ dvdnav_get_number_of_programs(this->dvdnav, &num_parts[i-1]);
+ num_mrls += num_parts[i-1]; /* num_mrls = total number of programs */
+ }
- device = malloc(strlen(volume_device) + strlen(volume_name) + 2);
- if (device == NULL)
- return;
- sprintf(device, "%s/%s", volume_device, volume_name);
- if (stat(device, &stb) != 0 || !S_ISCHR(stb.st_mode)) {
- free(device);
- return;
+ /* allocate enough memory for:
+ * - a list of pointers to mrls sizeof(mrl_t *) * num_mrls + 1
+ * - an array of mrl structures sizeof(mrl_t) * num_mrls
+ * - enough chars for every filename sizeof(char)*25 * num_mrls
+ * - "dvd://:000000.000000\0" = 25 chars
+ */
+ if ((this->mrls = (mrl_t **) malloc(sizeof(mrl_t *) + num_mrls *
+ (sizeof(mrl_t*) + sizeof(mrl_t) + 25*sizeof(char))))) {
+
+ /* the first mrl struct comes after the pointer list */
+ mrl_t *mrl = (mrl_t *) &this->mrls[num_mrls+1];
+ /* the chars for filenames come after the mrl structs */
+ char *name = (char *) &mrl[num_mrls];
+ int pos = 0, j;
+ this->num_mrls = num_mrls;
+
+ for (i = 1; i <= num_titles; i++) {
+ for (j = (i == 1 ? 0 : 1); j <= num_parts[i-1]; j++) {
+ this->mrls[pos++] = mrl;
+ mrl->origin = NULL;
+ mrl->mrl = name;
+ mrl->link = NULL;
+ mrl->type = mrl_dvd;
+ mrl->size = 0;
+ snprintf(name, 25, (j == 0) ? "dvd://" :
+ (j == 1) ? "dvd://:%d" :
+ "dvd://:%d.%d", i, j);
+ name = &name[25];
+ mrl++;
+ }
+ }
+ this->mrls[pos] = NULL; /* terminate list */
}
- this->device = this->raw_device = device;
+ free(num_parts);
}
+
+ /* Reset the VM so that we don't break anything */
+ /* dvdnav_reset(this->dvdnav); */
+
+ dvdnav_close(this->dvdnav);
}
-#endif
/*
- * try to open dvd and prepare to read >filename<
+ * Opens the DVD plugin. The MRL takes the following form:
+ *
+ * dvd://[dvd_path][:vts[.program]]
*
- * returns lbnum on success, 0 otherwise
+ * e.g.
+ * dvd:// - Play (navigate) /dev/dvd
+ * dvd:///dev/dvd2 - Play (navigate) /dev/dvd2
+ * dvd:///dev/dvd2:1 - Play Title 1 from /dev/dvd2
+ * dvd://:1.3 - Play Title 1, program 3 from /dev/dvd
*/
-static int openDVDFile (dvd_input_plugin_t *this,
- char *filename, off_t *size) {
- char str[256];
- int lbnum;
- int encrypted=0;
-
- if (openDrive(this) < 0) {
- LOG_MSG(this->xine, _("input_dvd: cannot open dvd drive >%s<\n"), this->device);
+static int dvdnav_plugin_open (input_plugin_t *this_gen, char *mrl) {
+ char *locator;
+ int colon_point;
+ dvdnav_input_plugin_t *this = (dvdnav_input_plugin_t *) this_gen;
+ dvdnav_status_t ret;
+ char *intended_dvd_device;
+ cfg_entry_t *region_entry, *lang_entry, *cache_entry;
+
+ trace_print("Called\n");
+ /* printf("open1: dvdnav=%p opened=%d\n",this->dvdnav, this->opened); */
+
+ this->mrl = mrl;
+ this->pause_timer = 0;
+ this->dvd_name[0] = 0;
+ this->dvd_name_length = 0;
+
+ /* Check we can handle this MRL */
+ if (!strncasecmp (mrl, "dvd://",9))
+ locator = &mrl[9];
+ else {
return 0;
}
-#if defined HAVE_LINUX_CDROM_H
- {
- dvd_struct dvd;
-
- dvd.copyright.type = DVD_STRUCT_COPYRIGHT;
- dvd.copyright.layer_num = 0;
- if (ioctl (this->dvd_fd, DVD_READ_STRUCT, &dvd) < 0) {
- LOG_MSG(this->xine, _("input_dvd: Could not read Copyright Structure\n"));
- return 0;
- }
- encrypted = (dvd.copyright.cpst != 0) ;
+ /* Attempt to parse MRL */
+ colon_point=0;
+ while((locator[colon_point] != '\0') && (locator[colon_point] != ':')) {
+ colon_point++;
}
-#elif defined __FreeBSD__
- {
- struct dvd_struct dvd;
- dvd.format = DVD_STRUCT_COPYRIGHT;
- dvd.layer_num = 0;
+ if(locator[colon_point] == ':') {
+ this->mode = MODE_TITLE;
+ } else {
+ this->mode = MODE_NAVIGATE;
+ }
- if (ioctl(this->dvd_fd, DVDIOCREADSTRUCTURE, &dvd) < 0) {
- LOG_MSG(this->xine, _("input_dvd: Could not read Copyright Structure\n"));
+ locator[colon_point] = '\0';
+ ret = DVDNAV_STATUS_OK;
+ if(colon_point == 0) {
+ /* Use default device */
+ intended_dvd_device=this->dvd_device;
+ } else {
+ /* Use specified device */
+ intended_dvd_device=locator;
+ }
+
+ if(this->opened) {
+ if ( intended_dvd_device==this->current_dvd_device ) {
+ /* Already open, so skip opening */
+ } else {
+ /* Changing DVD device */
+ dvdnav_close(this->dvdnav);
+ this->dvdnav=NULL;
+ this->opened=0;
+ ret = dvdnav_open(&this->dvdnav, intended_dvd_device);
+ if(ret == DVDNAV_STATUS_ERR) {
+ fprintf(stderr, "Error opening DVD device\n");
+ return 0;
+ }
+ this->opened=1;
+ this->current_dvd_device=intended_dvd_device;
+ }
+ } else {
+ ret = dvdnav_open(&this->dvdnav, intended_dvd_device);
+ if(ret == DVDNAV_STATUS_ERR) {
+ fprintf(stderr, "Error opening DVD device\n");
return 0;
}
-
- encrypted = (dvd.cpst != 0);
+ this->opened=1;
+ this->current_dvd_device=intended_dvd_device;
}
-#elif defined __sun
- {
- dvd_struct dvd;
-
- dvd.copyright.type = DVD_STRUCT_COPYRIGHT;
- dvd.copyright.layer_num = 0;
- if (dvd_read_copyright(this, &dvd) < 0) {
- LOG_MSG(this->xine, _("input_dvd: Could not read Copyright Structure.\n"
- " Assuming disk is not encrypted.\n"));
- } else
- encrypted = (dvd.copyright.cpst != 0);
+ if (1) {
+ int fd, i;
+ off64_t off;
+ uint8_t data[DVD_VIDEO_LB_LEN];
+
+ /* Read DVD name */
+ fd=open(intended_dvd_device, O_RDONLY);
+ if (fd > 0) {
+ off = lseek64( fd, 32 * (int64_t) DVD_VIDEO_LB_LEN, SEEK_SET );
+ if( off == ( 32 * (int64_t) DVD_VIDEO_LB_LEN ) ) {
+ off = read( fd, data, DVD_VIDEO_LB_LEN );
+ close(fd);
+ if (off == ( (int64_t) DVD_VIDEO_LB_LEN )) {
+ fprintf( stderr, "DVD Title: ");
+ for(i=25; i < 73; i++ ) {
+ if((data[i] == 0)) break;
+ if((data[i] > 32) && (data[i] < 127)) {
+ fprintf(stderr, "%c", data[i]);
+ } else {
+ fprintf(stderr, " ");
+ }
+ }
+ strncpy(&this->dvd_name[0], &data[25], 48);
+ /* fprintf(stderr, "TITLE:%s\n",&this->dvd_name[0]); */
+ this->dvd_name[48]=0;
+ this->dvd_name_length=strlen(&this->dvd_name[0]);
+ fprintf( stderr, "\nDVD Serial Number: ");
+ for(i=73; i < 89; i++ ) {
+ if((data[i] == 0)) break;
+ if((data[i] > 32) && (data[i] < 127)) {
+ fprintf(stderr, "%c", data[i]);
+ } else {
+ fprintf(stderr, " ");
+ }
+ }
+ fprintf( stderr, "\nDVD Title (Alternative): ");
+ for(i=89; i < 128; i++ ) {
+ if((data[i] == 0)) break;
+ if((data[i] > 32) && (data[i] < 127)) {
+ fprintf(stderr, "%c", data[i]);
+ } else {
+ fprintf(stderr, " ");
+ }
+ }
+ fprintf( stderr, "\n");
+ } else {
+ fprintf( stderr, "libdvdread: Can't read name block. Probably not a DVD-ROM device.\n");
+ }
+ } else {
+ fprintf( stderr, "libdvdread: Can't seek to block %u\n", 32 );
+ }
+ } else {
+ fprintf(stderr,"NAME OPEN FAILED\n");
+ }
}
-#endif
- if( encrypted ) {
- LOG_MSG(this->xine,
- _("\ninput_dvd: Sorry, this plugin doesn't play encrypted DVDs. The legal status\n"
- " of CSS decryption is unclear and we can't provide such code.\n"
- " Please check http://dvd.sf.net for more information.\n"));
- return 0;
+
+ /* Set region code */
+ region_entry = this->config->lookup_entry(this->config,
+ "input.dvd_region");
+ if(region_entry) {
+ region_changed_cb(this, region_entry);
}
-
- snprintf (str, sizeof(str), "/VIDEO_TS/%s", filename);
-
- if (!(lbnum = UDFFindFile(this->dvd_fd, str, size))) {
- LOG_MSG(this->xine, _("input_dvd: cannot open file >%s<\n"), filename);
-
- closeDrive (this);
-
- return 0;
+
+ /* Set languages */
+ lang_entry = this->config->lookup_entry(this->config,
+ "input.dvdnav_language");
+ if(lang_entry) {
+ language_changed_cb(this, lang_entry);
}
+
+ /* Set cache usage */
+ cache_entry = this->config->lookup_entry(this->config,
+ "input.dvdnav_use_readahead");
+ if(cache_entry) {
+ read_ahead_cb(this, cache_entry);
+ }
+
+ if(this->mode == MODE_TITLE) {
+ int tt, i, pr, found;
+ int titles;
+
+ /* A program and/or VTS was specified */
+ locator += colon_point + 1;
- lseek (this->raw_fd, lbnum * (off_t) DVD_VIDEO_LB_LEN, SEEK_SET) ;
-
- return lbnum;
-}
-/* ***************************************************************** */
-/* END OF PRIVATES */
-/* ***************************************************************** */
-
-/*
- *
- */
-static uint32_t dvd_plugin_get_capabilities (input_plugin_t *this) {
- return INPUT_CAP_SEEKABLE | INPUT_CAP_PREVIEW | INPUT_CAP_BLOCK | INPUT_CAP_AUTOPLAY | INPUT_CAP_GET_DIR;
-}
-
-/*
- *
- */
-static int dvd_plugin_open (input_plugin_t *this_gen, char *mrl) {
- char *filename;
- dvd_input_plugin_t *this = (dvd_input_plugin_t *) this_gen;
-
- this->mrl = mrl;
-
- /*
- * do we handle this kind of MRL ?
- */
- if (strncasecmp (mrl, "dvd://", 6))
- return 0;
+ if(locator[0] == '\0') {
+ /* Empty specifier */
+ fprintf(stderr, "Incorrect MRL format.\n");
+ dvdnav_close(this->dvdnav);
+ return 0;
+ }
- filename = (char *) &mrl[6];
+ /* See if there is a period. */
+ found = -1;
+ for(i=0; i<strlen(locator); i++) {
+ if(locator[i] == '.') {
+ found = i;
+ locator[i] = '\0';
+ }
+ }
+ tt = strtol(locator, NULL,10);
- sscanf (filename, "VTS_%d_%d.VOB", &this->gVTSMajor, &this->gVTSMinor);
+ dvdnav_get_number_of_titles(this->dvdnav, &titles);
+ if((tt <= 0) || (tt > titles)) {
+ fprintf(stderr, "Title %i is out of range (1 to %i).\n", tt,
+ titles);
+ dvdnav_close(this->dvdnav);
+ return 0;
+ }
- this->file_lbstart = openDVDFile (this, filename, &this->file_size) ;
- this->file_lbcur = this->file_lbstart;
+ /* If there was a program specified, get that too. */
+ pr = -1;
+ if(found != -1) {
+ pr = strtol(locator+found+1, NULL,10);
+ }
- if (!this->file_lbstart) {
- LOG_MSG(this->xine, _("input_dvd: Unable to find >%s< on dvd.\n"), filename);
- return 0;
+ dprint("Jumping to VTS >%i<, prog >%i<\n", tt, pr);
+ if(pr != -1) {
+ dvdnav_part_play(this->dvdnav, tt, pr);
+ } else {
+ dvdnav_title_play(this->dvdnav, tt);
+ }
}
-
- this->file_size_left = this->file_size;
-
- return 1 ;
-}
-
-static int dvd_plugin_is_branch_possible(input_plugin_t *this_gen, char *nextmrl ) {
- dvd_input_plugin_t *this = (dvd_input_plugin_t *) this_gen;
- char *mrl;
-
- if (strncasecmp (nextmrl, "dvd://", 6))
- return 0;
-
- mrl = this->mrl;
- mrl += 6;
- nextmrl += 6;
+ dprint("DVD device successfully opened.\n");
- if( strncasecmp (mrl, "VTS_", 4) || strncasecmp (nextmrl, "VTS_", 4) )
- return 0;
-
return 1;
-}
-
-static off_t dvd_plugin_read (input_plugin_t *this_gen,
- char *buf, off_t nlen) {
-
- dvd_input_plugin_t *this = (dvd_input_plugin_t *) this_gen;
- int bytes_read;
+}
- if (nlen != DVD_VIDEO_LB_LEN) {
+static void dvdnav_plugin_free_buffer(buf_element_t *buf) {
+ dvdnav_input_plugin_t *this = buf->source;
+
+ pthread_mutex_lock(&this->buf_mutex);
+ /* give this buffer back to libdvdnav */
+ dvdnav_free_cache_block(this->dvdnav, buf->mem);
+ /* reconstruct the original xine buffer */
+ buf->free_buffer = this->free_buffer;
+ buf->source = this->source;
+ buf->mem = this->mem[--this->mem_stack];
+ pthread_mutex_unlock(&this->buf_mutex);
+ /* give this buffer back to xine's pool */
+ buf->free_buffer(buf);
+}
- LOG_MSG(this->xine, _("input_dvd: error read: %Ld bytes is not a sector!\n"),
- nlen);
+static buf_element_t *dvdnav_plugin_read_block (input_plugin_t *this_gen,
+ fifo_buffer_t *fifo, off_t nlen) {
+ dvdnav_input_plugin_t *this = (dvdnav_input_plugin_t*)this_gen;
+ buf_element_t *buf;
+ dvdnav_status_t result;
+ int event, len;
+ int finished = 0;
+ unsigned char *block;
- return 0;
+ if(fifo == NULL) {
+ dprint("values of \\beta will give rise to dom!\n");
+ return NULL;
}
- if (this->file_size_left < nlen)
- return 0;
+ /* Read buffer */
+ buf = fifo->buffer_pool_alloc (fifo);
+ block = buf->mem;
- bytes_read = read (this->raw_fd, buf, DVD_VIDEO_LB_LEN);
- if (bytes_read == DVD_VIDEO_LB_LEN) {
+ while(!finished) {
+ if (block != buf->mem) {
+ /* if we already have a dvdnav cache block, give it back first */
+ dvdnav_free_cache_block(this->dvdnav, block);
+ block = buf->mem;
+ }
+ result = dvdnav_get_next_cache_block (this->dvdnav, &block, &event, &len);
+ if(result == DVDNAV_STATUS_ERR) {
+ fprintf(stderr, "Error getting next block from DVD (%s)\n",
+ dvdnav_err_to_string(this->dvdnav));
+ if (block != buf->mem) dvdnav_free_cache_block(this->dvdnav, block);
+ buf->free_buffer(buf);
+ return NULL;
+ }
- this->file_lbcur++;
- this->file_size_left -= DVD_VIDEO_LB_LEN;
+ switch(event) {
+ case DVDNAV_BLOCK_OK:
+ {
+ buf->content = block;
+ buf->type = BUF_DEMUX_BLOCK;
- return DVD_VIDEO_LB_LEN;
- } else if (bytes_read < 0) {
- LOG_MSG(this->xine, _("input_dvd: read error in input_dvd plugin (%s)\n"),
- strerror (errno));
+ /* Make sure we don't think we are still paused */
+ this->pause_timer = 0;
+
+ finished = 1;
+ }
+ break;
+ case DVDNAV_NOP:
+ {
+ /* Nothing */
+ }
+ break;
+ case DVDNAV_STILL_FRAME:
+ {
+
+ /* OK, So xine no-longer accepts BUF_VIDEO_FILLs, find out
+ * how else we provide the hint
+ */
+ dvdnav_still_event_t *still_event =
+ (dvdnav_still_event_t*)(block);
+ buf->type = BUF_CONTROL_NOP;
+ finished = 1;
+
+ /* Xine's method of doing still-frames */
+ if (this->pause_timer == 0) {
+ dprint("dvd:input_dvdnav.c:Stillframe! (pause time = 0x%02x)\n",
+ still_event->length);
+ this->pause_timer = still_event->length;
+ this->pause_end_time = time(NULL) + this->pause_timer;
+ this->pause_counter = 0;
+ break;
+ }
+
+ if(this->pause_timer == 0xff) {
+ this->pause_counter++;
+ xine_usec_sleep(100000);
+ break;
+ }
+ if ( (this->pause_timer != 0xFF) &&
+ (time(NULL) >= this->pause_end_time) ){
+ this->pause_timer = 0;
+ this->pause_end_time = 0;
+ dvdnav_still_skip(this->dvdnav);
+ break;
+ }
+ if(this->pause_timer) {
+ this->pause_counter++;
+ dprint("dvd:input_dvdnav.c:Stillframe! (pause_timer = 0x%02x) counter=%d\n",
+ still_event->length, this->pause_counter);
+ xine_usec_sleep(100000);
+ break;
+ }
+ }
+ break;
+ case DVDNAV_SPU_STREAM_CHANGE:
+ {
+ dvdnav_spu_stream_change_event_t *stream_event =
+ (dvdnav_spu_stream_change_event_t*) (block);
+ buf->content = block;
+ buf->type = BUF_CONTROL_SPU_CHANNEL;
+ buf->decoder_info[0] = stream_event->physical_wide;
+ buf->decoder_info[1] = stream_event->physical_letterbox;
+ buf->decoder_info[2] = stream_event->physical_pan_scan;
+ dprint("SPU stream wide %d, letterbox %d, pan&scan %d\n",
+ stream_event->physical_wide,
+ stream_event->physical_letterbox,
+ stream_event->physical_pan_scan);
+ finished = 1;
+ }
+ break;
+ case DVDNAV_AUDIO_STREAM_CHANGE:
+ {
+ dvdnav_audio_stream_change_event_t *stream_event =
+ (dvdnav_audio_stream_change_event_t*) (block);
+ buf->content = block;
+ buf->type = BUF_CONTROL_AUDIO_CHANNEL;
+ buf->decoder_info[0] = stream_event->physical;
+ dprint("AUDIO stream %d\n", stream_event->physical);
+ finished = 1;
+ }
+ break;
+ case DVDNAV_HIGHLIGHT:
+ {
+ xine_dvdnav_send_button_update(this, 0);
+ }
+ break;
+ case DVDNAV_VTS_CHANGE:
+ {
+ int aspect, permission;
+
+ dprint("VTS change\n");
+
+ /* Check for video aspect change and scaling permissions */
+ aspect = dvdnav_get_video_aspect(this->dvdnav);
+ permission = dvdnav_get_video_scale_permission(this->dvdnav);
+
+ buf->type = BUF_VIDEO_MPEG;
+ buf->decoder_flags = BUF_FLAG_SPECIAL;
+ buf->decoder_info[1] = BUF_SPECIAL_ASPECT;
+ buf->decoder_info[2] = aspect;
+ buf->decoder_info[3] = permission;
+ finished = 1;
+ }
+ break;
+ case DVDNAV_CELL_CHANGE:
+ {
+ xine_ui_event_t uevent;
+
+ /* Tell Xine to update the UI */
+ uevent.event.type = XINE_EVENT_UI_CHANNELS_CHANGED;
+ uevent.data = NULL;
+ xine_send_event(this->xine, &uevent.event);
+
+ update_title_display(this);
+ }
+ break;
+ case DVDNAV_SEEK_DONE:
+ {
+ dprint("Seek done\n");
+ /* FIXME: This should send a message to clear all currently displaying subtitle. */
+ }
+ break;
+ case DVDNAV_HOP_CHANNEL:
+ {
+ flush_buffers(this);
+ break;
+ }
+ case DVDNAV_NAV_PACKET:
+ {
+ buf->content = block;
+ buf->type = BUF_DEMUX_BLOCK;
+ finished = 1;
+ }
+ break;
+ case DVDNAV_SPU_CLUT_CHANGE:
+ {
+ buf->content = block;
+ buf->type = BUF_SPU_CLUT;
+ finished = 1;
+ }
+ break;
+ case DVDNAV_STOP:
+ {
+ if (buf->mem != block) dvdnav_free_cache_block(this->dvdnav, block);
+ buf->free_buffer(buf);
+ /* return NULL to indicate end of stream */
+ return NULL;
+ }
+ default:
+ dprint("FIXME: Unknown event (%i)\n", event);
+ break;
+ }
}
- else {
- LOG_MSG(this->xine, _("input_dvd: short read in input_dvd (%d != %d)\n"),
- bytes_read, DVD_VIDEO_LB_LEN);
+
+ if (block != buf->mem) {
+ /* we have received a buffer from the libdvdnav cache, store all
+ * necessary values to reconstruct xine's buffer and modify it according to
+ * our needs. */
+ pthread_mutex_lock(&this->buf_mutex);
+ if (this->mem_stack < 1024) {
+ this->mem[this->mem_stack++] = buf->mem;
+ this->free_buffer = buf->free_buffer;
+ this->source = buf->source;
+ buf->mem = block;
+ buf->free_buffer = dvdnav_plugin_free_buffer;
+ buf->source = this;
+ } else {
+ /* the stack for storing the memory chunks from xine is full, we cannot
+ * modify the buffer, because we would not be able to reconstruct it.
+ * Therefore we copy the data and give the buffer back. */
+ dprint("too many buffers issued, memory stack exceeded\n");
+ memcpy(buf->mem, block, 2048);
+ dvdnav_free_cache_block(this->dvdnav, block);
+ buf->content = buf->mem;
+ }
+ pthread_mutex_unlock(&this->buf_mutex);
}
- return 0;
+ return buf;
}
+static off_t dvdnav_plugin_read (input_plugin_t *this_gen, char *ch_buf, off_t len) {
+/* dvdnav_input_plugin_t *this = (dvdnav_input_plugin_t*)this_gen; */
-static buf_element_t *dvd_plugin_read_block (input_plugin_t *this_gen,
- fifo_buffer_t *fifo, off_t nlen) {
- dvd_input_plugin_t *this = (dvd_input_plugin_t *) this_gen;
- buf_element_t *buf;
-
- if (nlen != DVD_VIDEO_LB_LEN || this->file_size_left < nlen) {
- /*
- * Hide the error reporting now, demuxer try to read 6 bytes
- * at STAGE_BY_CONTENT probe stage
- */
- if(nlen != DVD_VIDEO_LB_LEN)
- LOG_MSG(this->xine,
- _("input_dvd: error in input_dvd plugin read: %Ld bytes "
- "is not a sector!\n"), nlen);
- return NULL;
- }
-
- if ((buf = read_cache_read_block (this->read_cache, (off_t)this->file_lbcur*DVD_VIDEO_LB_LEN))) {
+ /* FIXME: Implement somehow */
- this->file_lbcur++;
- this->file_size_left -= DVD_VIDEO_LB_LEN;
- buf->type = BUF_DEMUX_BLOCK;
+ return 0;
+}
+
+static off_t dvdnav_plugin_seek (input_plugin_t *this_gen, off_t offset, int origin) {
+ dvdnav_input_plugin_t *this = (dvdnav_input_plugin_t*)this_gen;
+
+ trace_print("Called\n");
- } else {
- LOG_MSG(this->xine, _("input_dvd: read error in input_dvd plugin\n"));
+ if(!this || !this->dvdnav) {
+ return -1;
}
+
+ return dvdnav_sector_search(this->dvdnav, offset / DVD_BLOCK_SIZE , origin) * DVD_BLOCK_SIZE;
-
- return buf;
+ return -1;
}
+static off_t dvdnav_plugin_get_current_pos (input_plugin_t *this_gen){
+ dvdnav_input_plugin_t *this = (dvdnav_input_plugin_t*)this_gen;
+ uint32_t pos=0;
+ uint32_t length=1;
+ dvdnav_status_t result;
+ trace_print("Called\n");
-static off_t dvd_plugin_seek (input_plugin_t *this_gen, off_t offset, int origin) {
- dvd_input_plugin_t *this = (dvd_input_plugin_t *) this_gen;
-
- offset /= DVD_VIDEO_LB_LEN;
-
- switch (origin) {
- case SEEK_END:
- offset = (this->file_size / DVD_VIDEO_LB_LEN) - offset;
-
- case SEEK_SET:
- this->file_lbcur = this->file_lbstart + offset;
- this->file_size_left = this->file_size - (offset * DVD_VIDEO_LB_LEN);
- break;
- case SEEK_CUR:
- if (offset) {
- this->file_lbcur += offset;
- this->file_size_left = this->file_size -
- ((this->file_lbcur - this->file_lbstart) * DVD_VIDEO_LB_LEN);
- } else {
- return (this->file_lbcur - this->file_lbstart) *
- (off_t) DVD_VIDEO_LB_LEN;
- }
-
- break;
- default:
- LOG_MSG(this->xine, _("input_dvd: seek: %d is an unknown origin\n"), origin);
+ if(!this || !this->dvdnav) {
+ return 0;
}
-
- return lseek (this->raw_fd,
- this->file_lbcur * (off_t) DVD_VIDEO_LB_LEN, SEEK_SET)
- - this->file_lbstart * (off_t) DVD_VIDEO_LB_LEN;
+ result = dvdnav_get_position(this->dvdnav, &pos, &length);
+ return (off_t)pos * (off_t)2048;
}
+static off_t dvdnav_plugin_get_length (input_plugin_t *this_gen) {
+ dvdnav_input_plugin_t *this = (dvdnav_input_plugin_t*)this_gen;
+ uint32_t pos=0;
+ uint32_t length=1;
+ dvdnav_status_t result;
+
+ trace_print("Called\n");
-static off_t dvd_plugin_get_current_pos (input_plugin_t *this_gen){
- dvd_input_plugin_t *this = (dvd_input_plugin_t *) this_gen;
+ if(!this || !this->dvdnav) {
+ return 0;
+ }
- return ((this->file_lbcur - this->file_lbstart) * DVD_VIDEO_LB_LEN);
+ result = dvdnav_get_position(this->dvdnav, &pos, &length);
+ return (off_t)length * (off_t)2048;
}
+static uint32_t dvdnav_plugin_get_blocksize (input_plugin_t *this_gen) {
+ trace_print("Called\n");
-static off_t dvd_plugin_get_length (input_plugin_t *this_gen) {
- dvd_input_plugin_t *this = (dvd_input_plugin_t *) this_gen;
-
- return this->file_size;
+ return DVD_BLOCK_SIZE;
}
+static mrl_t **dvdnav_plugin_get_dir (input_plugin_t *this_gen,
+ char *filename, int *nFiles) {
+ dvdnav_input_plugin_t *this = (dvdnav_input_plugin_t*)this_gen;
-static uint32_t dvd_plugin_get_blocksize (input_plugin_t *this_gen) {
+ trace_print("Called\n");
+ if (filename) { *nFiles = 0; return NULL; }
- return DVD_VIDEO_LB_LEN;
+ dvdnav_build_mrl_list((dvdnav_input_plugin_t *) this_gen);
+ *nFiles = this->num_mrls;
+ return this->mrls;
}
+static int dvdnav_umount_media(char *device)
+{
+ char *argv[10];
+ int i;
+ pid_t pid;
+ int status;
+ argv[0]="umount";
+ argv[1]=device;
+ argv[2]=0;
+ pid=fork();
+ if (pid == 0) {
+ i= execv("/bin/umount", argv);
+ exit(127);
+ }
+ do {
+ if(waitpid(pid, &status, 0) == -1) {
+ if (errno != EINTR)
+ return -1;
+ }
+ else {
+ return WEXITSTATUS(status);
+ }
+ } while(1);
+
+ return -1;
+}
+
-static int dvd_plugin_eject_media (input_plugin_t *this_gen) {
- dvd_input_plugin_t *this = (dvd_input_plugin_t *) this_gen;
+static int dvdnav_plugin_eject_media (input_plugin_t *this_gen) {
+ dvdnav_input_plugin_t *this = (dvdnav_input_plugin_t *) this_gen;
int ret, status;
int fd;
- if((fd = open(this->device, O_RDONLY|O_NONBLOCK)) > -1) {
+ /* printf("dvd:Eject Device %s current device %s opened=%d handle=%p trying...\n",this->dvd_device, this->current_dvd_device, this->opened, this->dvdnav); */
+ dvdnav_plugin_close (this_gen) ;
+ ret=dvdnav_umount_media(this->current_dvd_device);
+ /**********
+ printf ("umount result: %s\n",
+ strerror(errno));
+ ***********/
+ if ((fd = open (this->current_dvd_device, O_RDONLY|O_NONBLOCK)) > -1) {
-#if defined (HAVE_LINUX_CDROM_H)
+#if defined (__linux__)
if((status = ioctl(fd, CDROM_DRIVE_STATUS, CDSL_CURRENT)) > 0) {
switch(status) {
case CDS_TRAY_OPEN:
- if((ret = ioctl(fd, CDROMCLOSETRAY)) != 0) {
- LOG_MSG(this->xine, _("input_dvd: CDROMCLOSETRAY failed: %s\n"),
- strerror(errno));
- }
- break;
+ if((ret = ioctl(fd, CDROMCLOSETRAY)) != 0) {
+#ifdef LOG_DVD_EJECT
+ dprint ("CDROMCLOSETRAY failed: %s\n",
+ strerror(errno));
+#endif
+ }
+ break;
case CDS_DISC_OK:
- if((ret = ioctl(fd, CDROMEJECT)) != 0) {
- LOG_MSG(this->xine, _("input_dvd: CDROMEJECT failed: %s\n"), strerror(errno));
- }
- break;
+ if((ret = ioctl(fd, CDROMEJECT)) != 0) {
+#ifdef LOG_DVD_EJECT
+ dprint ("CDROMEJECT failed: %s\n", strerror(errno));
+#endif
+ }
+ break;
}
}
else {
- LOG_MSG(this->xine, _("input_dvd: CDROM_DRIVE_STATUS failed: %s\n"),
- strerror(errno));
+#ifdef LOG_DVD_EJECT
+ dprint ("CDROM_DRIVE_STATUS failed: %s\n",
+ strerror(errno));
+#endif
close(fd);
return 0;
}
+#elif defined (__NetBSD__) || defined (__OpenBSD__) || defined (__FreeBSD__)
-#elif defined (HAVE_CDIO_H)
-
-# if defined (__sun)
- status = 0;
- if ((ret = ioctl(fd, CDROMEJECT)) != 0) {
- LOG_MSG(this->xine, _("input_dvd: CDROMEJECT failed: %s\n"), strerror(errno));
- }
-
-# else
if (ioctl(fd, CDIOCALLOW) == -1) {
- LOG_MSG(this->xine, _("ioctl(cdromallow): %s"), strerror(errno));
+ perror("ioctl(cdromallow)");
} else {
if (ioctl(fd, CDIOCEJECT) == -1) {
- LOG_MSG(this->xine, _("ioctl(cdromeject): %s"), strerror(errno));
+ perror("ioctl(cdromeject)");
}
}
-# endif
#endif
close(fd);
+ } else {
+ dprint("Device %s failed to open during eject calls\n",this->current_dvd_device);
}
return 1;
}
+static char* dvdnav_plugin_get_mrl (input_plugin_t *this_gen) {
+ dvdnav_input_plugin_t *this = (dvdnav_input_plugin_t*)this_gen;
+
+ trace_print("Called\n");
-static void dvd_plugin_close (input_plugin_t *this_gen) {
- dvd_input_plugin_t *this = (dvd_input_plugin_t *) this_gen;
-
- closeDrive (this);
+ return this->mrl;
}
+static char *dvdnav_plugin_get_description (input_plugin_t *this_gen) {
+ trace_print("Called\n");
-static void dvd_plugin_stop (input_plugin_t *this_gen) {
- dvd_plugin_close(this_gen);
+ return "DVD Navigator";
}
+static char *dvdnav_plugin_get_identifier (input_plugin_t *this_gen) {
+ trace_print("Called\n");
-static char *dvd_plugin_get_description (input_plugin_t *this_gen) {
-
- return _("dvd device input plugin as shipped with xine");
+ return "DVD";
}
+static void flush_buffers(dvdnav_input_plugin_t *this) {
+ /* Small hack for still menus with audio. Thanks to
+ * the Captain for doing this in d5d. The changes are necessary to
+ * stop some audio problems (esp. with R2 'Dalekmania').
+ */
-static char *dvd_plugin_get_identifier (input_plugin_t *this_gen) {
+ if (this->xine->audio_fifo)
+ this->xine->audio_fifo->clear (this->xine->audio_fifo);
+
+ if (this->xine->video_fifo)
+ this->xine->video_fifo->clear (this->xine->video_fifo);
- return "DVD";
+
+ if (this->xine->cur_audio_decoder_plugin)
+ this->xine->cur_audio_decoder_plugin->reset(this->xine->cur_audio_decoder_plugin);
+ if (this->xine->cur_video_decoder_plugin)
+ this->xine->cur_video_decoder_plugin->flush(this->xine->cur_video_decoder_plugin);
}
+static void xine_dvdnav_send_button_update(dvdnav_input_plugin_t *this, int mode) {
+ int button;
+ spu_button_t spu_button;
+ xine_spu_event_t spu_event;
+ dvdnav_get_current_highlight(this->dvdnav, &button);
+ if (button == this->buttonN && (mode ==0) ) return;
+ this->buttonN = button; /* Avoid duplicate sending of button info */
+ dprint("sending_button_update button=%d mode=%d\n", button, mode);
+ /* Do we want to show or hide the button? */
+ /* libspudec will control hiding */
+ spu_event.event.type = XINE_EVENT_SPU_BUTTON;
+ spu_event.data = &spu_button;
+ spu_button.show = mode + 1; /* mode=0 select, 1 activate. */
+ spu_button.buttonN = button;
+ xine_send_event(this->xine, &spu_event.event);
+}
-static mrl_t **dvd_plugin_get_dir (input_plugin_t *this_gen,
- char *filename, int *nEntries) {
- dvd_input_plugin_t *this = (dvd_input_plugin_t *) this_gen;
- int i, fd;
+static void dvdnav_event_listener (void *this_gen, xine_event_t *event) {
- *nEntries = 0;
-
- if (filename)
- return NULL;
-
- if((fd = open(this->device, O_RDONLY /* | O_NONBLOCK */ )) > -1) {
- int nFiles, nFiles2;
-
- UDFListDir (fd, "/VIDEO_TS", MAX_DIR_ENTRIES, this->filelist, &nFiles);
+ dvdnav_input_plugin_t *this = (dvdnav_input_plugin_t *) this_gen;
- nFiles2 = 0;
- for (i=0; i<nFiles; i++) {
- int nLen;
+ if(!this->dvdnav) {
+ return;
+ }
- nLen = strlen (this->filelist[i]);
+ switch(event->type) {
+ case XINE_EVENT_INPUT_MENU1:
+ dvdnav_menu_call(this->dvdnav, DVD_MENU_Root);
+ break;
+ case XINE_EVENT_INPUT_MENU2:
+ dvdnav_menu_call(this->dvdnav, DVD_MENU_Title);
+ break;
+ case XINE_EVENT_INPUT_MENU3:
+ dvdnav_menu_call(this->dvdnav, DVD_MENU_Audio);
+ break;
+ case XINE_EVENT_INPUT_NEXT:
+ dvdnav_next_pg_search(this->dvdnav);
+ break;
+ case XINE_EVENT_INPUT_PREVIOUS:
+ dvdnav_prev_pg_search(this->dvdnav);
+ break;
+ case XINE_EVENT_INPUT_ANGLE_NEXT:
+ {
+ int num = 0, current = 0;
+ dvdnav_get_angle_info(this->dvdnav, &current, &num);
+
+ if(num != 0) {
+ current ++;
+ if(current > num)
+ current = 1;
+ }
+ dvdnav_angle_change(this->dvdnav, current);
+ dprint("Changing to angle %i\n", current);
+
+ update_title_display(this);
+ }
+ break;
+ case XINE_EVENT_INPUT_ANGLE_PREVIOUS:
+ {
+ int num = 0, current = 0;
+ dvdnav_get_angle_info(this->dvdnav, &current, &num);
+
+ if(num != 0) {
+ current --;
+ if(current <= 0)
+ current = num;
+ }
+ dvdnav_angle_change(this->dvdnav, current);
+ dprint("Changing to angle %i\n", current);
+
+ update_title_display(this);
+ }
+ break;
+ case XINE_EVENT_INPUT_SELECT:
+ {
+ xine_dvdnav_send_button_update(this, 1);
+ dvdnav_button_activate(this->dvdnav);
+ }
+ break;
+ case XINE_EVENT_MOUSE_BUTTON:
+ {
+ xine_input_event_t *input_event = (xine_input_event_t*) event;
+ xine_dvdnav_send_button_update(this, 1);
+ dvdnav_mouse_activate(this->dvdnav, input_event->x,
+ input_event->y);
+ }
+ break;
+ case XINE_EVENT_INPUT_BUTTON_FORCE: /* For libspudec to feedback forced button select from NAV PCI packets. */
+ {
+ xine_spu_event_t *spu_event = (xine_spu_event_t *) event;
+ spu_button_t *but = spu_event->data;
+ fprintf(stderr, "xine_dvd:BUTTON_FORCE %d\n", but->buttonN);
+ dvdnav_button_select(this->dvdnav, but->buttonN);
+ }
+ break;
+ case XINE_EVENT_MOUSE_MOVE:
+ {
+ xine_input_event_t *input_event = (xine_input_event_t*) event;
+ /* printf("Mouse move (x,y) = (%i,%i)\n", input_event->x,
+ input_event->y); */
+ dvdnav_mouse_select(this->dvdnav, input_event->x, input_event->y);
+ xine_dvdnav_send_button_update(this, 0);
+ }
+ break;
+ case XINE_EVENT_INPUT_UP:
+ dvdnav_upper_button_select(this->dvdnav);
+ xine_dvdnav_send_button_update(this, 0);
+ break;
+ case XINE_EVENT_INPUT_DOWN:
+ dvdnav_lower_button_select(this->dvdnav);
+ xine_dvdnav_send_button_update(this, 0);
+ break;
+ case XINE_EVENT_INPUT_LEFT:
+ dvdnav_left_button_select(this->dvdnav);
+ xine_dvdnav_send_button_update(this, 0);
+ break;
+ case XINE_EVENT_INPUT_RIGHT:
+ dvdnav_right_button_select(this->dvdnav);
+ xine_dvdnav_send_button_update(this, 0);
+ break;
+ }
+
+ return;
+}
- if (nLen<4)
- continue;
+static int dvdnav_plugin_get_optional_data (input_plugin_t *this_gen,
+ void *data, int data_type) {
+ dvdnav_input_plugin_t *this = (dvdnav_input_plugin_t *) this_gen;
+
+ switch(data_type) {
- if (!strcasecmp (&this->filelist[i][nLen-4], ".VOB")) {
- char str[1024];
+ case INPUT_OPTIONAL_DATA_AUDIOLANG: {
+ uint16_t lang;
+ int8_t channel;
+
+ /* Be paranoid */
+ if(this && this->xine && this->dvdnav) {
- if(nFiles2 >= this->mrls_allocated_entries) {
- ++this->mrls_allocated_entries;
- /* note: 1 extra pointer for terminating NULL */
- this->mrls = realloc(this->mrls, (this->mrls_allocated_entries+1) * sizeof(mrl_t*));
- this->mrls[nFiles2] = (mrl_t *) xine_xmalloc(sizeof(mrl_t));
- }
+ if(!(dvdnav_is_domain_vts(this->dvdnav))) {
+ sprintf(data, "%s", "nav");
+ goto __audio_success;
+ }
+
+ channel = (int8_t) xine_get_audio_channel(this->xine);
+ /* printf("********* AUDIO CHANNEL = %d\n", channel); */
+ channel = dvdnav_get_audio_logical_stream(this->dvdnav, channel);
+ if(channel != -1) {
+ lang = dvdnav_audio_stream_to_lang(this->dvdnav, channel);
- if(this->mrls[nFiles2]->mrl) {
- this->mrls[nFiles2]->mrl = (char *)
- realloc(this->mrls[nFiles2]->mrl, strlen(this->filelist[i]) + 7);
- }
+ if(lang != 0xffff) {
+ sprintf(data, " %c%c", lang >> 8, lang & 0xff);
+ }
else {
- this->mrls[nFiles2]->mrl = (char *)
- xine_xmalloc(strlen(this->filelist[i]) + 7);
+ sprintf(data, "%3i", xine_get_audio_channel(this->xine));
}
+ }
+ else {
+ channel = xine_get_audio_channel(this->xine);
+ sprintf(data, "%3i", channel);
+ }
+
+ __audio_success:
+ /* printf("********** RETURNING '%s'\n", (char *)data); */
+ return INPUT_OPTIONAL_SUCCESS;
+ }
+ return INPUT_OPTIONAL_UNSUPPORTED;
+ }
+ break;
- this->mrls[nFiles2]->origin = NULL;
- sprintf(this->mrls[nFiles2]->mrl, "dvd://%s", this->filelist[i]);
- this->mrls[nFiles2]->link = NULL;
- this->mrls[nFiles2]->type = (0 | mrl_dvd);
- /* determine size */
- memset(&str, 0, sizeof(str));
- sprintf (str, "/VIDEO_TS/%s", this->filelist[i]);
- UDFFindFile(fd, str, &this->mrls[nFiles2]->size);
+ case INPUT_OPTIONAL_DATA_SPULANG: {
+ uint16_t lang;
+ int8_t channel;
+
+ /* Be paranoid */
+ if(this && this->xine && this->dvdnav) {
- nFiles2++;
+ if(!(dvdnav_is_domain_vts(this->dvdnav))) {
+ sprintf(data, "%3s", "off");
+ goto __spu_success;
}
+ channel = (int8_t) xine_get_spu_channel(this->xine);
+ /* printf("********* SPU CHANNEL = %i\n", channel); */
+ if(channel == -1)
+ channel = dvdnav_get_spu_logical_stream(this->dvdnav, this->xine->spu_channel);
+ else
+ channel = dvdnav_get_spu_logical_stream(this->dvdnav, channel);
+
+ if(channel != -1) {
+ lang = dvdnav_spu_stream_to_lang(this->dvdnav, channel);
+
+ if(lang != 0xffff) {
+ sprintf(data, " %c%c", lang >> 8, lang & 0xff);
+ }
+ else {
+ sprintf(data, "%3i", xine_get_spu_channel(this->xine));
+ }
+ }
+ else {
+ channel = xine_get_spu_channel(this->xine);
+ if(channel == -1)
+ sprintf(data, "%3s", "off");
+ else
+ sprintf(data, "%3i", channel);
+ }
+
+ __spu_success:
+ /* printf("********** RETURNING '%s'\n", (char *)data); */
+ return INPUT_OPTIONAL_SUCCESS;
}
-
- *nEntries = nFiles2;
-
- close (fd);
-
- }
- else {
- LOG_MSG(this->xine, _("input_dvd: unable to open dvd drive (%s): %s\n"),
- this->device, strerror(errno));
- return NULL;
+ return INPUT_OPTIONAL_UNSUPPORTED;
}
- /*
- * Freeing exceeded mrls if exists.
- */
- while(this->mrls_allocated_entries > *nEntries) {
- MRL_ZERO(this->mrls[this->mrls_allocated_entries - 1]);
- free(this->mrls[this->mrls_allocated_entries--]);
+ break;
+
}
- /*
- * This is useful to let UI know where it should stops ;-).
- */
- this->mrls[*nEntries] = NULL;
-
- return this->mrls;
+ return INPUT_OPTIONAL_UNSUPPORTED;
}
+static char **dvdnav_plugin_get_autoplay_list (input_plugin_t *this_gen,
+ int *nFiles) {
+ dvdnav_input_plugin_t *this = (dvdnav_input_plugin_t *) this_gen;
+ dvdnav_status_t res;
+ int titles, i;
+ trace_print("get_autoplay_list entered\n");
+ /* Close the plugin is opened */
+ if(this->opened) {
+ dvdnav_close(this->dvdnav);
+ this->opened = 0;
+ }
-static char **dvd_plugin_get_autoplay_list (input_plugin_t *this_gen,
- int *nFiles) {
- dvd_input_plugin_t *this = (dvd_input_plugin_t *) this_gen;
- int i, fd;
-
- if((fd = open(this->device, O_RDONLY /* | O_NONBLOCK */ )) > -1) {
- int nFiles3, nFiles2;
-
- UDFListDir (fd, "/VIDEO_TS", MAX_DIR_ENTRIES, this->filelist, &nFiles3);
-
- nFiles2 = 0;
- for (i=0; i<nFiles3; i++) {
- int nLen;
-
- nLen = strlen (this->filelist[i]);
-
- if (nLen<4)
- continue;
-
- if (!strcasecmp (&this->filelist[i][nLen-4], ".VOB")) {
-
- if(this->filelist2[nFiles2] == NULL)
- this->filelist2[nFiles2] = (char *) realloc(this->filelist2[nFiles2],
- sizeof(char *) * 256);
-
- sprintf (this->filelist2[nFiles2], "dvd://%s", this->filelist[i]);
-
- nFiles2++;
- }
-
- }
-
- *nFiles = nFiles2;
+ /* rebuild thie MRL browser list */
+ dvdnav_build_mrl_list(this);
- this->filelist2[*nFiles] = (char *) realloc(this->filelist2[*nFiles], sizeof(char *));
- this->filelist2[*nFiles] = NULL;
- close (fd);
-
- } else {
- LOG_MSG(this->xine, _("input_dvd: unable to open dvd drive (%s): %s\n"),
- this->device, strerror(errno));
- *nFiles = 0;
+ /* Use default path */
+ res = dvdnav_open(&(this->dvdnav), this->current_dvd_device);
+ if(res == DVDNAV_STATUS_ERR) {
return NULL;
}
- return this->filelist2;
-}
-
+ this->opened = 1;
+
+ /* Return a list of all titles */
+ snprintf (&(filelist[0][0]), MAX_STR_LEN, "dvd://");
+ filelist2[0] = &(filelist[0][0]);
-static char* dvd_plugin_get_mrl (input_plugin_t *this_gen) {
- dvd_input_plugin_t *this = (dvd_input_plugin_t *) this_gen;
+ dvdnav_get_number_of_titles(this->dvdnav, &titles);
+ for(i=1; i<=titles; i++) {
+ snprintf (&(filelist[i][0]), MAX_STR_LEN, "dvd://:%i", i);
+ filelist2[i] = &(filelist[i][0]);
+ }
+ *nFiles=titles+1;
+ filelist2[*nFiles] = NULL;
+ dprint("get_autoplay_list exiting opened=%d dvdnav=%p\n",this->opened, this->dvdnav);
- return this->mrl;
+ return filelist2;
}
-
-static int dvd_plugin_get_optional_data (input_plugin_t *this_gen,
- void *data, int data_type) {
- /*
- switch(data_type) {
-
- case INPUT_OPTIONAL_DATA_CLUT:
- ...
- return INPUT_OPTIONAL_SUCCESS;
- break;
-
- case INPUT_OPTIONAL_DATA_AUDIOLANG:
- ...
- return INPUT_OPTIONAL_SUCCESS;
- break;
-
- }
- */
- return INPUT_OPTIONAL_UNSUPPORTED;
+void dvdnav_plugin_dispose(input_plugin_t *this_gen) {
+ dvdnav_input_plugin_t *this = (dvdnav_input_plugin_t*)this_gen;
+ pthread_mutex_destroy(&this->buf_mutex);
+ free(this->mrls); this->mrls = NULL;
}
-static void dvd_plugin_dispose (input_plugin_t *this_gen ) {
- dvd_input_plugin_t *this = (dvd_input_plugin_t *) this_gen;
- int i;
+#ifdef __sun
+/*
+ * Check the environment, if we're running under sun's
+ * vold/rmmount control.
+ */
+static void
+check_solaris_vold_device(dvdnav_input_plugin_t *this)
+{
+ char *volume_device;
+ char *volume_name;
+ char *volume_action;
+ char *device;
+ struct stat stb;
- read_cache_free (this->read_cache);
+ if ((volume_device = getenv("VOLUME_DEVICE")) != NULL &&
+ (volume_name = getenv("VOLUME_NAME")) != NULL &&
+ (volume_action = getenv("VOLUME_ACTION")) != NULL &&
+ strcmp(volume_action, "insert") == 0) {
- for (i = 0; i < MAX_DIR_ENTRIES; i++) {
- free (this->filelist[i]);
- free (this->filelist2[i]);
+ device = malloc(strlen(volume_device) + strlen(volume_name) + 2);
+ if (device == NULL)
+ return;
+ sprintf(device, "%s/%s", volume_device, volume_name);
+ if (stat(device, &stb) != 0 || !S_ISCHR(stb.st_mode)) {
+ free(device);
+ return;
+ }
+ this->dvd_device = device;
}
-
- free (this->mrls);
- free (this);
}
-
+#endif
input_plugin_t *init_input_plugin (int iface, xine_t *xine) {
+ dvdnav_input_plugin_t *this;
+ config_values_t *config = xine->config;
+
+ trace_print("Called\n");
+
+ switch (iface) {
+ case 8:
+ this = (dvdnav_input_plugin_t *) malloc (sizeof (dvdnav_input_plugin_t));
+
+ this->input_plugin.interface_version = INPUT_PLUGIN_IFACE_VERSION;
+ this->input_plugin.get_capabilities = dvdnav_plugin_get_capabilities;
+ this->input_plugin.open = dvdnav_plugin_open;
+ this->input_plugin.read = dvdnav_plugin_read;
+ this->input_plugin.read_block = dvdnav_plugin_read_block;
+ this->input_plugin.seek = dvdnav_plugin_seek;
+ this->input_plugin.get_current_pos = dvdnav_plugin_get_current_pos;
+ this->input_plugin.get_length = dvdnav_plugin_get_length;
+ this->input_plugin.get_blocksize = dvdnav_plugin_get_blocksize;
+ this->input_plugin.get_dir = dvdnav_plugin_get_dir;
+ this->input_plugin.eject_media = dvdnav_plugin_eject_media;
+ this->input_plugin.get_mrl = dvdnav_plugin_get_mrl;
+ this->input_plugin.stop = dvdnav_plugin_stop;
+ this->input_plugin.close = dvdnav_plugin_close;
+ this->input_plugin.get_description = dvdnav_plugin_get_description;
+ this->input_plugin.get_identifier = dvdnav_plugin_get_identifier;
+ this->input_plugin.get_autoplay_list = dvdnav_plugin_get_autoplay_list;
+ this->input_plugin.get_optional_data = dvdnav_plugin_get_optional_data;
+ this->input_plugin.is_branch_possible = NULL;
+ this->input_plugin.dispose = dvdnav_plugin_dispose;
+
+ this->config = config;
+ this->xine = xine;
+ this->dvdnav = NULL;
+ this->opened = 0;
+ this->buttonN = 0;
+ this->dvd_name[0] = 0;
+ this->dvd_name_length = 0;
+ this->mrls = NULL;
+ this->num_mrls = 0;
+
+ pthread_mutex_init(&this->buf_mutex, NULL);
+ this->mem_stack = 0;
+
+ xine_register_event_listener(this->xine, dvdnav_event_listener, this);
+ this->dvd_device = config->register_string(config,
+ "input.dvd_device",
+ DVD_PATH,
+ "device used for dvd drive",
+ NULL,
+ device_change_cb, (void *)this);
+ this->current_dvd_device = this->dvd_device;
+
+ config->register_num(config, "input.dvd_region",
+ 1,
+ "Region that DVD player claims "
+ "to be (1 -> 8)",
+ "This only needs to be changed "
+ "if your DVD jumps to a screen "
+ "complaining about region code ",
+ region_changed_cb,
+ this);
+ config->register_string(config, "input.dvdnav_language",
+ "en",
+ "The default language for dvd",
+ "The dvdnav plugin tries to use this "
+ "language as a default. This must be a"
+ "two character ISO country code.",
+ language_changed_cb, this);
+ config->register_bool(config, "input.dvdnav_use_readahead",
+ 1,
+ "Do we use read-ahead caching?",
+ "This "
+ "may lead to jerky playback on low-end "
+ "machines.",
+ read_ahead_cb, this);
+
+#ifdef __sun
+ check_solaris_vold_device(this);
+#endif
- dvd_input_plugin_t *this;
- config_values_t *config;
- int i;
-
- if (iface != 8) {
- LOG_MSG(xine,
- _("dvd input plugin doesn't support plugin API version %d.\n"
- "PLUGIN DISABLED.\n"
- "This means there's a version mismatch between xine and this input"
- "plugin.\nInstalling current input plugins should help.\n"),
+ return (input_plugin_t *) this;
+ break;
+ default:
+ fprintf(stderr,
+ "DVD Navigator input plugin doesn't support plugin API version %d.\n"
+ "PLUGIN DISABLED.\n"
+ "This means there's a version mismatch between xine and this input"
+ "plugin.\nInstalling current input plugins should help.\n",
iface);
return NULL;
}
-
- this = (dvd_input_plugin_t *) xine_xmalloc (sizeof (dvd_input_plugin_t));
- config = xine->config;
- this->xine = xine;
-
- for (i = 0; i < MAX_DIR_ENTRIES; i++) {
- this->filelist[i] = (char *) xine_xmalloc(sizeof(char *) * 256);
- this->filelist2[i] = (char *) xine_xmalloc(sizeof(char *) * 256);
- }
-
- this->input_plugin.interface_version = INPUT_PLUGIN_IFACE_VERSION;
- this->input_plugin.get_capabilities = dvd_plugin_get_capabilities;
- this->input_plugin.open = dvd_plugin_open;
- this->input_plugin.read = dvd_plugin_read;
- this->input_plugin.read_block = dvd_plugin_read_block;
- this->input_plugin.seek = dvd_plugin_seek;
- this->input_plugin.get_current_pos = dvd_plugin_get_current_pos;
- this->input_plugin.get_length = dvd_plugin_get_length;
- this->input_plugin.get_blocksize = dvd_plugin_get_blocksize;
- this->input_plugin.eject_media = dvd_plugin_eject_media;
- this->input_plugin.close = dvd_plugin_close;
- this->input_plugin.stop = dvd_plugin_stop;
- this->input_plugin.get_identifier = dvd_plugin_get_identifier;
- this->input_plugin.get_description = dvd_plugin_get_description;
- this->input_plugin.get_dir = dvd_plugin_get_dir;
- this->input_plugin.get_mrl = dvd_plugin_get_mrl;
- this->input_plugin.get_autoplay_list = dvd_plugin_get_autoplay_list;
- this->input_plugin.get_optional_data = dvd_plugin_get_optional_data;
- this->input_plugin.dispose = dvd_plugin_dispose;
- this->input_plugin.is_branch_possible= NULL;
- /* disable branch until we fix the problems branching from
- menu vob to video vob
- this->input_plugin.is_branch_possible= dvd_plugin_is_branch_possible;
- */
-
- this->device = config->register_string(config, "input.dvd_device", DVD,
- _("path to your local dvd device file"),
- NULL, device_change_cb, (void *)this);
- this->raw_device = config->register_string(config, "input.dvd_raw_device", RDVD,
- _("path to a raw device set up for dvd access"),
- NULL, rawdevice_change_cb, (void*)this);
-#ifdef __sun
- check_solaris_vold_device(this);
-#endif
-
- this->mrls_allocated_entries = 0;
- this->mrls = xine_xmalloc(sizeof(mrl_t*));
-
- this->mrl = NULL;
- this->config = config;
- this->dvd_fd = -1;
- this->raw_fd = -1;
-
- this->read_cache = read_cache_new ();
-
- return (input_plugin_t *) this;
}
+
+/*
+ * $Log: input_dvd.c,v $
+ * Revision 1.53 2002/08/08 17:49:21 richwareham
+ * First stage of DVD plugin -> dvdnav conversion
+ *
+ */