summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--DOCS/man/en/mplayer.16
-rw-r--r--Makefile1
-rw-r--r--cfg-mplayer.h5
-rwxr-xr-xconfigure20
-rw-r--r--unrar_exec.c236
-rw-r--r--unrar_exec.h38
-rw-r--r--vobsub.c39
7 files changed, 338 insertions, 7 deletions
diff --git a/DOCS/man/en/mplayer.1 b/DOCS/man/en/mplayer.1
index e81a442d0a..55279b8192 100644
--- a/DOCS/man/en/mplayer.1
+++ b/DOCS/man/en/mplayer.1
@@ -2481,6 +2481,12 @@ used for the OSD and clear it (default: ^[[A\\r^[[K).
Tells MPlayer to handle the subtitle file as unicode.
.
.TP
+.B \-unrarexec <path to unrar executable> (does not support MingW currently.)
+Specify the path to the unrar executable so MPlayer can use it to access
+rar-compressed vobsub files (default: not set, so the feature is off).
+The path must include the executable's filename, i.e.\& /usr/local/bin/unrar.
+.
+.TP
.B "\-utf8 \ \ "
Tells MPlayer to handle the subtitle file as UTF-8.
.
diff --git a/Makefile b/Makefile
index 796071de60..9f79e1991b 100644
--- a/Makefile
+++ b/Makefile
@@ -35,6 +35,7 @@ SRCS_COMMON = asxparser.c \
vobsub.c \
SRCS_COMMON-$(UNRARLIB) += unrarlib.c
+SRCS_COMMON-$(UNRAR_EXEC) += unrar_exec.c
SRCS_MPLAYER = mplayer.c \
m_property.c \
diff --git a/cfg-mplayer.h b/cfg-mplayer.h
index cc5caa8c09..e968dd6d34 100644
--- a/cfg-mplayer.h
+++ b/cfg-mplayer.h
@@ -35,6 +35,8 @@ extern char *menu_fribidi_charset;
extern int menu_flip_hebrew;
extern int menu_fribidi_flip_commas;
+extern char *unrar_executable;
+
extern int vo_zr_parseoption(const m_option_t* conf, char *opt, char * param);
extern void vo_zr_revertoption(const m_option_t* opt,char* pram);
@@ -267,6 +269,9 @@ const m_option_t mplayer_opts[]={
// these should be moved to -common, and supported in MEncoder
{"vobsub", &vobsub_name, CONF_TYPE_STRING, 0, 0, 0, NULL},
{"vobsubid", &vobsub_id, CONF_TYPE_INT, CONF_RANGE, 0, 31, NULL},
+#ifdef USE_UNRAR_EXEC
+ {"unrarexec", &unrar_executable, CONF_TYPE_STRING, 0, 0, 0, NULL},
+#endif
{"sstep", &step_sec, CONF_TYPE_INT, CONF_MIN, 0, 0, NULL},
diff --git a/configure b/configure
index 4fb13fb26f..c00dc7d3a0 100755
--- a/configure
+++ b/configure
@@ -256,6 +256,7 @@ Optional features:
--disable-freetype disable FreeType 2 font rendering [autodetect]
--disable-fontconfig disable fontconfig font lookup [autodetect]
--disable-unrarlib disable Unique RAR File Library [enabled]
+ --disable-unrarexec disable using of UnRAR executable [enabled]
--enable-menu enable OSD menu (not DVD menu) [disabled]
--disable-sortsub disable subtitle sorting [enabled]
--enable-fribidi enable the FriBiDi libs [autodetect]
@@ -592,6 +593,7 @@ _sunaudio=auto
_alsa=auto
_fastmemcpy=yes
_unrarlib=yes
+_unrar_exec=auto
_win32dll=auto
_select=yes
_radio=no
@@ -1097,6 +1099,8 @@ for ac_option do
--disable-fontconfig) _fontconfig=no ;;
--enable-unrarlib) _unrarlib=yes ;;
--disable-unrarlib) _unrarlib=no ;;
+ --enable-unrarexec) _unrar_exec=yes ;;
+ --disable-unrarexec) _unrar_exec=no ;;
--enable-ftp) _ftp=yes ;;
--disable-ftp) _ftp=no ;;
--enable-vstream) _vstream=yes ;;
@@ -6715,6 +6719,18 @@ else
fi
echores "$_unrarlib"
+echocheck "UnRAR executable"
+if test "$_unrar_exec" = auto ; then
+ _unrar_exec="yes"
+ mingw32 && _unrar_exec="no"
+fi
+if test "$_unrar_exec" = yes ; then
+ _def_unrar_exec='#define USE_UNRAR_EXEC 1'
+else
+ _def_unrar_exec='#undef USE_UNRAR_EXEC'
+fi
+echores "$_unrar_exec"
+
echocheck "TV interface"
if test "$_tv" = yes ; then
_def_tv='#define USE_TV 1'
@@ -7611,6 +7627,7 @@ SPEEX = $_speex
MUSEPACK = $_musepack
UNRARLIB = $_unrarlib
+UNRAR_EXEC = $_unrar_exec
PNG = $_png
JPEG = $_jpeg
GIF = $_gif
@@ -8165,6 +8182,9 @@ $_def_fastmemcpy
/* Use unrarlib for Vobsubs */
$_def_unrarlib
+/* Use UnRAR executable for Vobsubs */
+$_def_unrar_exec
+
/* gui support, please do not edit this option */
$_def_gui
$_def_gtk2_gui
diff --git a/unrar_exec.c b/unrar_exec.c
new file mode 100644
index 0000000000..29a531fb61
--- /dev/null
+++ b/unrar_exec.c
@@ -0,0 +1,236 @@
+/*
+ * List files and extract file from rars by using external executable unrar.
+ *
+ * Copyright (C) 2005 Jindrich Makovicka <makovick gmail com>
+ * Copyright (C) 2007 Ulion <ulion2002 gmail com>
+ *
+ * This file is part of MPlayer.
+ *
+ * MPlayer is free software; you can redistribute it and/or modify
+ * 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.
+ *
+ * MPlayer 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 MPlayer; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <locale.h>
+#include "unrar_exec.h"
+
+#include "mp_msg.h"
+
+#define UNRAR_LIST 1
+#define UNRAR_EXTRACT 2
+
+char* unrar_executable = NULL;
+
+static FILE* launch_pipe(pid_t *apid, const char *executable, int action,
+ const char *archive, const char *filename)
+{
+ if (!executable || access(executable, R_OK | X_OK)) return NULL;
+ if (access(archive, R_OK)) return NULL;
+ {
+ int mypipe[2];
+ pid_t pid;
+
+ if (pipe(mypipe)) {
+ mp_msg(MSGT_GLOBAL, MSGL_ERR, "UnRAR: Cannot create pipe.\n");
+ return NULL;
+ }
+
+ pid = fork();
+ if (pid == 0) {
+ /* This is the child process. Execute the unrar executable. */
+ close(mypipe[0]);
+ // Close MPlayer's stdin, stdout and stderr so the unrar binary
+ // can not mess them up.
+ // TODO: Close all other files except the pipe.
+ close(0); close(1); close(2);
+ // Assign new stdin, stdout and stderr and check they actually got the
+ // right descriptors.
+ if (open("/dev/null", O_RDONLY) != 0 || dup(mypipe[1]) != 1
+ || open("/dev/null", O_WRONLY) != 2)
+ _exit(EXIT_FAILURE);
+ if (action == UNRAR_LIST)
+ execl(executable, executable, "v", archive, NULL);
+ else if (action == UNRAR_EXTRACT)
+ execl(executable, executable, "p", "-inul", "-p-",
+ archive,filename,NULL);
+ mp_msg(MSGT_GLOBAL, MSGL_ERR, "UnRAR: Cannot execute %s\n", executable);
+ _exit(EXIT_FAILURE);
+ }
+ if (pid < 0) {
+ /* The fork failed. Report failure. */
+ mp_msg(MSGT_GLOBAL, MSGL_ERR, "UnRAR: Fork failed\n");
+ return NULL;
+ }
+ /* This is the parent process. Prepare the pipe stream. */
+ close(mypipe[1]);
+ *apid = pid;
+ if (action == UNRAR_LIST)
+ mp_msg(MSGT_GLOBAL, MSGL_V,
+ "UnRAR: call unrar with command line: %s v %s\n",
+ executable, archive);
+ else if (action == UNRAR_EXTRACT)
+ mp_msg(MSGT_GLOBAL, MSGL_V,
+ "UnRAR: call unrar with command line: %s p -inul -p- %s %s\n",
+ executable, archive, filename);
+ return fdopen(mypipe[0], "r");
+ }
+}
+
+#define ALLOC_INCR 1 * 1024 * 1024
+int unrar_exec_get(unsigned char **output, unsigned long *size,
+ const char *filename, const char *rarfile)
+{
+ int bufsize = ALLOC_INCR, bytesread;
+ pid_t pid;
+ int status = 0;
+ FILE *rar_pipe;
+
+ rar_pipe=launch_pipe(&pid,unrar_executable,UNRAR_EXTRACT,rarfile,filename);
+ if (!rar_pipe) return 0;
+
+ *size = 0;
+
+ *output = malloc(bufsize);
+
+ while (*output) {
+ bytesread=fread(*output+*size, 1, bufsize-*size, rar_pipe);
+ if (bytesread <= 0)
+ break;
+ *size += bytesread;
+ if (*size == bufsize) {
+ char *p;
+ bufsize += ALLOC_INCR;
+ p = realloc(*output, bufsize);
+ if (!p)
+ free(*output);
+ *output = p;
+ }
+ }
+ fclose(rar_pipe);
+ pid = waitpid(pid, &status, 0);
+ if (!*output || !*size || (pid == -1 && errno != ECHILD) ||
+ (pid > 0 && status)) {
+ free(*output);
+ *output = NULL;
+ *size = 0;
+ return 0;
+ }
+ if (bufsize > *size) {
+ char *p = realloc(*output, *size);
+ if (p)
+ *output = p;
+ }
+ mp_msg(MSGT_GLOBAL, MSGL_V, "UnRAR: got file %s len %lu\n", filename,*size);
+ return 1;
+}
+
+#define PARSE_NAME 0
+#define PARSE_PROPS 1
+
+int unrar_exec_list(const char *rarfile, ArchiveList_struct **list)
+{
+ char buf[1024], fname[1024];
+ char *p;
+ pid_t pid;
+ int status = 0, file_num = -1, ignore_next_line = 0, state = PARSE_NAME;
+ FILE *rar_pipe;
+ ArchiveList_struct *alist = NULL, *current = NULL, *new;
+
+ rar_pipe = launch_pipe(&pid, unrar_executable, UNRAR_LIST, rarfile, NULL);
+ if (!rar_pipe) return -1;
+ while (fgets(buf, sizeof(buf), rar_pipe)) {
+ int packsize, unpsize, ratio, day, month, year, hour, min;
+ int llen = strlen(buf);
+ // If read nothing, we got a file_num -1.
+ if (file_num == -1)
+ file_num = 0;
+ if (buf[llen-1] != '\n')
+ // The line is too long, ignore it.
+ ignore_next_line = 2;
+ if (ignore_next_line) {
+ --ignore_next_line;
+ state = PARSE_NAME;
+ continue;
+ }
+ // Trim the line.
+ while (llen > 0 && strchr(" \t\n\r\v\f", buf[llen-1]))
+ --llen;
+ buf[llen] = '\0';
+ p = buf;
+ while (*p && strchr(" \t\n\r\v\f", *p))
+ ++p;
+ if (!*p) {
+ state = PARSE_NAME;
+ continue;
+ }
+
+ if (state == PARSE_PROPS && sscanf(p, "%d %d %d%% %d-%d-%d %d:%d",
+ &unpsize, &packsize, &ratio, &day,
+ &month, &year, &hour, &min) == 8) {
+ new = calloc(1, sizeof(ArchiveList_struct));
+ if (!new) {
+ file_num = -1;
+ break;
+ }
+ if (!current)
+ alist = new;
+ else
+ current->next = new;
+ current = new;
+ current->item.Name = strdup(fname);
+ state = PARSE_NAME;
+ if (!current->item.Name) {
+ file_num = -1;
+ break;
+ }
+ current->item.PackSize = packsize;
+ current->item.UnpSize = unpsize;
+ ++file_num;
+ continue;
+ }
+ strcpy(fname, p);
+ state = PARSE_PROPS;
+ }
+ fclose(rar_pipe);
+ pid = waitpid(pid, &status, 0);
+ if (file_num < 0 || (pid == -1 && errno != ECHILD) ||
+ (pid > 0 && status)) {
+ unrar_exec_freelist(alist);
+ return -1;
+ }
+ if (!alist)
+ return -1;
+ *list = alist;
+ mp_msg(MSGT_GLOBAL, MSGL_V, "UnRAR: list got %d files\n", file_num);
+ return file_num;
+}
+
+void unrar_exec_freelist(ArchiveList_struct *list)
+{
+ ArchiveList_struct* tmp;
+
+ while (list) {
+ tmp = list->next;
+ free(list->item.Name);
+ free(list);
+ list = tmp;
+ }
+}
+
diff --git a/unrar_exec.h b/unrar_exec.h
new file mode 100644
index 0000000000..f34cac4f10
--- /dev/null
+++ b/unrar_exec.h
@@ -0,0 +1,38 @@
+/*
+ * List files and extract file from rars by using external executable unrar.
+ *
+ * Copyright (C) 2005 Jindrich Makovicka <makovick gmail com>
+ * Copyright (C) 2007 Ulion <ulion2002 gmail com>
+ *
+ * This file is part of MPlayer.
+ *
+ * MPlayer is free software; you can redistribute it and/or modify
+ * 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.
+ *
+ * MPlayer 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 MPlayer; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef UNRAR_EXEC_H
+#define UNRAR_EXEC_H
+
+#include "unrarlib.h"
+
+extern char* unrar_executable;
+
+int unrar_exec_get(unsigned char **output, unsigned long *size,
+ const char *filename, const char *rarfile);
+
+int unrar_exec_list(const char *rarfile, ArchiveList_struct **list);
+
+void unrar_exec_freelist(ArchiveList_struct *list);
+
+#endif /* UNRAR_EXEC_H */
diff --git a/vobsub.c b/vobsub.c
index ce804c3b77..3a075bb021 100644
--- a/vobsub.c
+++ b/vobsub.c
@@ -20,7 +20,9 @@
#include "vobsub.h"
#include "spudec.h"
#include "mp_msg.h"
-#ifdef USE_UNRARLIB
+#ifdef USE_UNRAR_EXEC
+#include "unrar_exec.h"
+#elif defined(USE_UNRARLIB)
#include "unrarlib.h"
#endif
#include "libavutil/common.h"
@@ -35,7 +37,7 @@ static int vobsubid = -2;
* The RAR file must have the same basename as the file to open
* See <URL:http://www.unrarlib.org/>
**********************************************************************/
-#ifdef USE_UNRARLIB
+#if defined(USE_UNRARLIB) || defined(USE_UNRAR_EXEC)
typedef struct {
FILE *file;
unsigned char *data;
@@ -59,7 +61,7 @@ rar_open(const char *const filename, const char *const mode)
if (stream->file == NULL) {
char *rar_filename;
const char *p;
- int rc;
+ int rc = 0;
/* Guess the RAR archive filename */
rar_filename = NULL;
p = strrchr(filename, '.');
@@ -88,15 +90,27 @@ rar_open(const char *const filename, const char *const mode)
} else {
p++;
}
+#ifdef USE_UNRAR_EXEC
+ rc = unrar_exec_get(&stream->data, &stream->size, p, rar_filename);
+#endif
+#ifdef USE_UNRARLIB
+ if (!rc)
rc = urarlib_get(&stream->data, &stream->size, (char*) p, rar_filename, "");
+#endif
if (!rc) {
/* There is no matching filename in the archive. However, sometimes
* the files we are looking for have been given arbitrary names in the archive.
* Let's look for a file with an exact match in the extension only. */
- int i, num_files, name_len;
+ int i, num_files = -1, name_len;
ArchiveList_struct *list, *lp;
+#ifdef USE_UNRARLIB
/* the cast in the next line is a hack to overcome a design flaw (IMHO) in unrarlib */
num_files = urarlib_list (rar_filename, (ArchiveList_struct *)&list);
+#endif
+#ifdef USE_UNRAR_EXEC
+ if (num_files <= 0)
+ num_files = unrar_exec_list(rar_filename, &list);
+#endif
if (num_files > 0) {
char *demanded_ext;
demanded_ext = strrchr (p, '.');
@@ -105,13 +119,24 @@ rar_open(const char *const filename, const char *const mode)
for (i=0, lp=list; i<num_files; i++, lp=lp->next) {
name_len = strlen (lp->item.Name);
if (name_len >= demanded_ext_len && !strcasecmp (lp->item.Name + name_len - demanded_ext_len, demanded_ext)) {
- if ((rc = urarlib_get(&stream->data, &stream->size, lp->item.Name, rar_filename, ""))) {
- break;
- }
+#ifdef USE_UNRAR_EXEC
+ rc = unrar_exec_get(&stream->data, &stream->size,
+ lp->item.Name, rar_filename);
+ if (rc) break;
+#endif
+#ifdef USE_UNRARLIB
+ rc = urarlib_get(&stream->data, &stream->size,
+ lp->item.Name, rar_filename, "");
+ if (rc) break;
+#endif
}
}
}
+#ifdef USE_UNRARLIB
urarlib_freelist (list);
+#else
+ unrar_exec_freelist(list);
+#endif
}
if (!rc) {
free(rar_filename);