diff options
| author | phintuka <phintuka> | 2011-07-13 18:25:56 +0000 |
|---|---|---|
| committer | phintuka <phintuka> | 2011-07-13 18:25:56 +0000 |
| commit | d4d43fa7b9895d86a5724fb53ffa6b3a45711995 (patch) | |
| tree | 93df962d40db7ca8141167009ce829ae6db28b6e | |
| parent | 0982f2c733ff2848948905683ad9eb13c90ea5ef (diff) | |
| download | xineliboutput-d4d43fa7b9895d86a5724fb53ffa6b3a45711995.tar.gz xineliboutput-d4d43fa7b9895d86a5724fb53ffa6b3a45711995.tar.bz2 | |
Added support for .iso images using loop device
(Thanks to LACARRIERE Jerome)
| -rw-r--r-- | xine/BluRay/input_bluray.c | 181 |
1 files changed, 180 insertions, 1 deletions
diff --git a/xine/BluRay/input_bluray.c b/xine/BluRay/input_bluray.c index 391bc5d5..609ec461 100644 --- a/xine/BluRay/input_bluray.c +++ b/xine/BluRay/input_bluray.c @@ -43,6 +43,13 @@ #include <dlfcn.h> #include <pthread.h> +/* for loop device (used with .iso images) */ +#include <sys/mount.h> +#include <linux/fs.h> +#include <linux/loop.h> +#include <fcntl.h> +#include <sys/ioctl.h> + #include <libbluray/bluray.h> #include <libbluray/keys.h> #include <libbluray/overlay.h> @@ -140,8 +147,165 @@ typedef struct { uint32_t cap_seekable; uint8_t nav_mode; + /* loop device for .iso image */ + char *iso_image; + char *loop_dev; + char mount_point[64]; + } bluray_input_plugin_t; +/* + * Loop device setup stuff, swiped from busybox. + */ + +int del_loop(const char *device) +{ + int fd; + + if ((fd = open(device, O_RDONLY)) < 0) { + perror(device); + return -1; + } + if (ioctl(fd, LOOP_CLR_FD, 0) < 0) { +/* umm... why? perror("ioctl: LOOP_CLR_FD"); */ + return -1; + } + close(fd); + return 0; +} + +int set_loop(const char *device, const char *file, int offset, int *loopro) +{ + struct loop_info loopinfo; + int fd, ffd, mode; + + mode = *loopro ? O_RDONLY : O_RDWR; + if ((ffd = open (file, mode)) < 0 && !*loopro + && (errno != EROFS || (ffd = open (file, mode = O_RDONLY)) < 0)) { + perror (file); + return 1; + } + if ((fd = open (device, mode)) < 0) { + close(ffd); + perror(device); + return 1; + } + *loopro = (mode == O_RDONLY); + + memset(&loopinfo, 0, sizeof(loopinfo)); + strncpy(loopinfo.lo_name, file, LO_NAME_SIZE); + loopinfo.lo_name[LO_NAME_SIZE-1] = 0; + + loopinfo.lo_offset = offset; + + loopinfo.lo_encrypt_key_size = 0; + if (ioctl(fd, LOOP_SET_FD, ffd) < 0) { + perror("ioctl: LOOP_SET_FD"); + close(fd); + close(ffd); + return 1; + } + if (ioctl(fd, LOOP_SET_STATUS, &loopinfo) < 0) { + (void) ioctl(fd, LOOP_CLR_FD, 0); + perror("ioctl: LOOP_SET_STATUS"); + close(fd); + close(ffd); + return 1; + } + close(fd); + close(ffd); + return 0; +} + +char *find_unused_loop_device (void) +{ + char dev[20]; + int i, fd; + struct stat statbuf; + struct loop_info loopinfo; + + for(i = 0; i <= 7; i++) { + sprintf(dev, "/dev/loop%d", i); + if (stat (dev, &statbuf) == 0 && S_ISBLK(statbuf.st_mode)) { + if ((fd = open (dev, O_RDONLY)) >= 0) { + if(ioctl (fd, LOOP_GET_STATUS, &loopinfo) == -1) { + if (errno == ENXIO) { /* probably free */ + close (fd); + return strdup(dev); + } + } + close (fd); + } + } + } + return NULL; +} + +/* + * + */ + +static void close_loop_device (bluray_input_plugin_t *this) +{ + if (this->iso_image) { + umount(this->mount_point); + rmdir(this->mount_point); + free(this->iso_image); + this->iso_image = NULL; + } + if (this->loop_dev) { + del_loop(this->loop_dev); + free(this->loop_dev); + this->loop_dev = NULL; + } +} + +static int mount_iso_image(bluray_input_plugin_t *this) +{ + close_loop_device(this); + + /* create temporary mount point */ + sprintf(this->mount_point, "/tmp/xine_bd.%d.XXXXXX", (int)getpid()); + if (mktemp(this->mount_point)) {}; + if (mkdir(this->mount_point, S_IRWXU)) { + LOGMSG("Failed to create temporary mount point %s: %s\n", + this->mount_point, strerror(errno)); + return 0; + } + + /* find and initialize unused loop device */ + + this->loop_dev = find_unused_loop_device(); + if (!this->loop_dev) { + LOGMSG("No free loop device for %s\n", this->disc_root); + return 0; + } + + int pro = O_RDONLY; + if (set_loop(this->loop_dev, this->disc_root, 0, &pro)) { + LOGMSG("Error setting up loop device %s for %s\n", this->loop_dev, this->disc_root); + return 0; + } + + /* mount .iso image */ + if (mount(this->loop_dev, this->mount_point, "udf", + MS_NODEV | MS_MGC_VAL | MS_NOSUID | MS_RDONLY, NULL)) { + LOGMSG("Error mounting loop device %s to %s\n", this->loop_dev, this->mount_point); + return 0; + } + + this->iso_image = this->disc_root; + this->disc_root = strdup(this->mount_point); + + LOGMSG("Mounted %s to %s using loop device %s\n", this->iso_image, this->mount_point, this->loop_dev); + + return 1; +} + +/* + * + */ + static void send_num_buttons(bluray_input_plugin_t *this, int n) { xine_event_t event; @@ -1096,6 +1260,8 @@ static void bluray_plugin_dispose (input_plugin_t *this_gen) free (this->disc_root); free (this->disc_name); + close_loop_device(this); + free (this); } @@ -1248,6 +1414,15 @@ static char *get_file_name(const char *path) return file_name; } +static int is_iso_image(const char *mrl) +{ + if (mrl) { + const char *pos = strrchr(mrl, '.'); + return pos && !strcasecmp(pos + 1, "iso"); + } + return 0; +} + static int bluray_plugin_open (input_plugin_t *this_gen) { bluray_input_plugin_t *this = (bluray_input_plugin_t *) this_gen; @@ -1266,6 +1441,10 @@ static int bluray_plugin_open (input_plugin_t *this_gen) if (!this->disc_root) this->disc_root = strdup(this->class->mountpoint); + /* mount .iso image */ + if (is_iso_image(this->disc_root) && !mount_iso_image(this)) + return -1; + /* open libbluray */ if (! (this->bdh = bd_open (this->disc_root, NULL))) { @@ -1324,7 +1503,7 @@ static int bluray_plugin_open (input_plugin_t *this_gen) this->disc_name = strdup(this->meta_dl->di_name); } else if (strcmp(this->disc_root, this->class->mountpoint)) { - this->disc_name = get_file_name(this->disc_root); + this->disc_name = get_file_name(this->iso_image ?: this->disc_root); } /* register overlay (graphics) handler */ |
