summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2013-06-22 02:09:52 +0200
committerwm4 <wm4@nowhere>2013-06-25 00:11:56 +0200
commitcfa45c40dc0cfe44b699029168b62d4d3e16c288 (patch)
tree5a80d3b6e82711a5816c509e803c029b93342892
parent1bfae45a88ac7c24b74a6f7ca6eb4aa27d20c653 (diff)
downloadmpv-cfa45c40dc0cfe44b699029168b62d4d3e16c288.tar.bz2
mpv-cfa45c40dc0cfe44b699029168b62d4d3e16c288.tar.xz
sub: add demux_libass wrapper, drop old hacks
demux_libass.c allows us to make subtitle format detection part of the normal file loading process. libass has no probe function, but trying to load the start of a file (the first 4 KB) is good enough. Hope that libass can even handle random binary input gracefully without printing stupid log messages, and that the libass parser doesn't accept too many non-ASS files as input. This doesn't handle the -subcp option correctly yet. This will be fixed later.
-rw-r--r--DOCS/man/en/changes.rst1
-rw-r--r--DOCS/man/en/options.rst11
-rw-r--r--Makefile4
-rw-r--r--core/command.c5
-rw-r--r--core/mp_core.h3
-rw-r--r--core/mplayer.c83
-rw-r--r--core/options.c1
-rw-r--r--core/options.h1
-rw-r--r--demux/demux.c17
-rw-r--r--demux/demux.h6
-rw-r--r--demux/demux_libass.c108
-rw-r--r--demux/demux_sub.c38
-rw-r--r--sub/ass_mp.c28
-rw-r--r--sub/ass_mp.h2
14 files changed, 131 insertions, 177 deletions
diff --git a/DOCS/man/en/changes.rst b/DOCS/man/en/changes.rst
index de3b24b710..ed83c402f3 100644
--- a/DOCS/man/en/changes.rst
+++ b/DOCS/man/en/changes.rst
@@ -128,6 +128,7 @@ Command line switches
-dumpstream --stream-dump=<filename>
-capture --stream-capture=<filename>
-stop-xscreensaver --stop-screensaver
+ -subfile --sub
=================================== ===================================
*NOTE*: ``-opt val`` becomes ``--opt=val``.
diff --git a/DOCS/man/en/options.rst b/DOCS/man/en/options.rst
index b9068b1562..83ceb15c49 100644
--- a/DOCS/man/en/options.rst
+++ b/DOCS/man/en/options.rst
@@ -1998,8 +1998,7 @@
subtitles muxed with audio/video, or subtitles in the ASS format.
--sub-demuxer=<[+]name>
- Force subtitle demuxer type for ``--subfile``. Using a '+' before the name
- will force it, this will skip some checks! Give the demuxer name as
+ Force subtitle demuxer type for ``--sub``. Give the demuxer name as
printed by ``--sub-demuxer=help``.
--sub-paths=<path1:path2:...>
@@ -2046,14 +2045,6 @@
--sub-delay=<sec>
Delays subtitles by <sec> seconds. Can be negative.
---subfile=<filename>
- Open the given file with a demuxer, and use its subtitle streams. Same as
- ``--audiofile``, but for subtitle streams.
-
- *NOTE*: use ``--sub`` for subtitle files. This option is useless, unless
- you want to force libavformat subtitle parsers instead of libass or
- internal subtitle parsers.
-
--subfps=<rate>
Specify the framerate of the subtitle file (default: movie fps).
diff --git a/Makefile b/Makefile
index 4e244d8489..1fa78d676b 100644
--- a/Makefile
+++ b/Makefile
@@ -37,7 +37,8 @@ SOURCES-$(DVDREAD) += stream/stream_dvd.c \
SOURCES-$(FTP) += stream/stream_ftp.c
SOURCES-$(HAVE_SYS_MMAN_H) += audio/filter/af_export.c osdep/mmap_anon.c
SOURCES-$(LADSPA) += audio/filter/af_ladspa.c
-SOURCES-$(LIBASS) += sub/ass_mp.c sub/sd_ass.c
+SOURCES-$(LIBASS) += sub/ass_mp.c sub/sd_ass.c \
+ demux/demux_libass.c
SOURCES-$(LIBBLURAY) += stream/stream_bluray.c
SOURCES-$(LIBBS2B) += audio/filter/af_bs2b.c
@@ -207,7 +208,6 @@ SOURCES = talloc.c \
demux/demux_mf.c \
demux/demux_mkv.c \
demux/demux_mpg.c \
- demux/demux_sub.c \
demux/demux_subreader.c \
demux/demux_ts.c \
demux/mp3_hdr.c \
diff --git a/core/command.c b/core/command.c
index 4da0653425..c39bb3c16d 100644
--- a/core/command.c
+++ b/core/command.c
@@ -2281,7 +2281,7 @@ void run_command(MPContext *mpctx, mp_cmd_t *cmd)
case MP_CMD_SUB_ADD:
if (sh_video) {
- mp_add_subtitles(mpctx, cmd->args[0].v.s, sh_video->fps, 0);
+ mp_add_subtitles(mpctx, cmd->args[0].v.s, 0);
}
break;
@@ -2296,8 +2296,7 @@ void run_command(MPContext *mpctx, mp_cmd_t *cmd)
struct track *sub = mp_track_by_tid(mpctx, STREAM_SUB, cmd->args[0].v.i);
if (sh_video && sub && sub->is_external && sub->external_filename)
{
- struct track *nsub = mp_add_subtitles(mpctx, sub->external_filename,
- sh_video->fps, 0);
+ struct track *nsub = mp_add_subtitles(mpctx, sub->external_filename, 0);
if (nsub) {
mp_remove_track(mpctx, sub);
mp_switch_track(mpctx, nsub->type, nsub);
diff --git a/core/mp_core.h b/core/mp_core.h
index a327e43822..c958132700 100644
--- a/core/mp_core.h
+++ b/core/mp_core.h
@@ -290,8 +290,7 @@ extern int forced_subs_only;
void uninit_player(struct MPContext *mpctx, unsigned int mask);
void reinit_audio_chain(struct MPContext *mpctx);
double playing_audio_pts(struct MPContext *mpctx);
-struct track *mp_add_subtitles(struct MPContext *mpctx, char *filename,
- float fps, int noerr);
+struct track *mp_add_subtitles(struct MPContext *mpctx, char *filename, int noerr);
int reinit_video_chain(struct MPContext *mpctx);
int reinit_video_filters(struct MPContext *mpctx);
void pause_player(struct MPContext *mpctx);
diff --git a/core/mplayer.c b/core/mplayer.c
index 67d82fdb35..6e453278f0 100644
--- a/core/mplayer.c
+++ b/core/mplayer.c
@@ -196,9 +196,6 @@ static const char av_desync_help_text[] = _(
static void reset_subtitles(struct MPContext *mpctx);
static void reinit_subs(struct MPContext *mpctx);
-static struct track *open_external_file(struct MPContext *mpctx, char *filename,
- char *demuxer_name, int stream_cache,
- enum stream_type filter);
static double get_relative_time(struct MPContext *mpctx)
{
@@ -981,6 +978,9 @@ static struct track *add_stream_track(struct MPContext *mpctx,
};
MP_TARRAY_APPEND(mpctx, mpctx->tracks, mpctx->num_tracks, track);
+ if (stream->type == STREAM_SUB)
+ track->preloaded = !!stream->sub->track;
+
// Needed for DVD and Blu-ray.
if (!track->lang) {
struct stream_lang_req req = {
@@ -1027,65 +1027,6 @@ static void add_dvd_tracks(struct MPContext *mpctx)
#endif
}
-#ifdef CONFIG_ASS
-static int free_sub_data(void *ptr)
-{
- struct sh_sub *sh_sub = *(struct sh_sub **)ptr;
- if (sh_sub->track)
- ass_free_track(sh_sub->track);
- talloc_free(sh_sub->sub_data);
- return 1;
-}
-#endif
-
-struct track *mp_add_subtitles(struct MPContext *mpctx, char *filename,
- float fps, int noerr)
-{
- struct MPOpts *opts = &mpctx->opts;
- struct ass_track *asst = NULL;
-
- if (filename == NULL)
- return NULL;
-
- // Note: no text subtitles without libass. This is mainly because sd_ass is
- // used for rendering. Even when showing subtitles with term-osd, going
- // through sd_ass makes the code much simpler, as sd_ass can handle all
- // the weird special-cases.
-#ifdef CONFIG_ASS
- asst = mp_ass_read_stream(mpctx->ass_library, filename, opts->sub_cp);
- if (asst) {
- struct demuxer *d = new_sub_pseudo_demuxer(opts);
- assert(d->num_streams == 1);
- struct sh_stream *s = d->streams[0];
- assert(s->type == STREAM_SUB);
-
- s->codec = "ass";
- s->sub->track = asst;
-
- struct sh_sub **pptr = talloc(d, struct sh_sub*);
- *pptr = s->sub;
- talloc_set_destructor(pptr, free_sub_data);
-
- struct track *t = add_stream_track(mpctx, s, false);
- t->is_external = true;
- t->preloaded = true;
- t->title = talloc_strdup(t, filename);
- t->external_filename = talloc_strdup(t, filename);
- MP_TARRAY_APPEND(NULL, mpctx->sources, mpctx->num_sources, d);
- return t;
- }
-#endif
-
- // Used with libavformat subtitles.
- struct track *ext = open_external_file(mpctx, filename, NULL, 0, STREAM_SUB);
- if (ext)
- return ext;
-
- mp_tmsg(MSGT_CPLAYER, noerr ? MSGL_WARN : MSGL_ERR,
- "Cannot load subtitles: %s\n", filename);
- return NULL;
-}
-
int mp_get_cache_percent(struct MPContext *mpctx)
{
if (mpctx->stream) {
@@ -3916,16 +3857,15 @@ static void open_subtitles_from_options(struct MPContext *mpctx)
// after reading video params we should load subtitles because
// we know fps so now we can adjust subtitle time to ~6 seconds AST
// check .sub
- double sub_fps = mpctx->sh_video ? mpctx->sh_video->fps : 25;
if (mpctx->opts.sub_name) {
for (int i = 0; mpctx->opts.sub_name[i] != NULL; ++i)
- mp_add_subtitles(mpctx, mpctx->opts.sub_name[i], sub_fps, 0);
+ mp_add_subtitles(mpctx, mpctx->opts.sub_name[i], 0);
}
if (mpctx->opts.sub_auto) { // auto load sub file ...
char **tmp = find_text_subtitles(&mpctx->opts, mpctx->filename);
int nsub = MP_TALLOC_ELEMS(tmp);
for (int i = 0; i < nsub; i++) {
- struct track *track = mp_add_subtitles(mpctx, tmp[i], sub_fps, 1);
+ struct track *track = mp_add_subtitles(mpctx, tmp[i], 1);
if (track)
track->auto_loaded = true;
}
@@ -3955,9 +3895,12 @@ static struct track *open_external_file(struct MPContext *mpctx, char *filename,
case STREAM_SUB: ss = -1; break;
}
vs = -1; // avi can't go without video
+ struct demuxer_params params = {
+ .ass_library = mpctx->ass_library, // demux_libass requires it
+ };
struct demuxer *demuxer =
demux_open_withparams(&mpctx->opts, stream, format, demuxer_name,
- as, vs, ss, filename, NULL);
+ as, vs, ss, filename, &params);
if (!demuxer) {
free_stream(stream);
goto err_out;
@@ -3995,12 +3938,11 @@ static void open_audiofiles_from_options(struct MPContext *mpctx)
opts->audio_stream_cache, STREAM_AUDIO);
}
-// Just for -subfile. open_subtitles_from_options handles -sub text sub files.
-static void open_subfiles_from_options(struct MPContext *mpctx)
+struct track *mp_add_subtitles(struct MPContext *mpctx, char *filename, int noerr)
{
struct MPOpts *opts = &mpctx->opts;
- open_external_file(mpctx, opts->sub_stream, opts->sub_demuxer_name,
- 0, STREAM_SUB);
+ return open_external_file(mpctx, filename, opts->sub_demuxer_name, 0,
+ STREAM_SUB);
}
static void print_timeline(struct MPContext *mpctx)
@@ -4303,7 +4245,6 @@ goto_reopen_demuxer: ;
open_subtitles_from_options(mpctx);
open_audiofiles_from_options(mpctx);
- open_subfiles_from_options(mpctx);
check_previous_track_selection(mpctx);
diff --git a/core/options.c b/core/options.c
index 2e0d32bb60..3ce4315572 100644
--- a/core/options.c
+++ b/core/options.c
@@ -406,7 +406,6 @@ const m_option_t mp_opts[] = {
// demuxer.c - select audio/sub file/demuxer
OPT_STRING("audiofile", audio_stream, 0),
OPT_INTRANGE("audiofile-cache", audio_stream_cache, 0, 50, 65536),
- OPT_STRING("subfile", sub_stream, 0),
OPT_STRING("demuxer", demuxer_name, 0),
OPT_STRING("audio-demuxer", audio_demuxer_name, 0),
OPT_STRING("sub-demuxer", sub_demuxer_name, 0),
diff --git a/core/options.h b/core/options.h
index c31d2063c9..6ec051ddca 100644
--- a/core/options.h
+++ b/core/options.h
@@ -150,7 +150,6 @@ typedef struct MPOpts {
char *audio_stream;
int audio_stream_cache;
- char *sub_stream;
char *demuxer_name;
char *audio_demuxer_name;
char *sub_demuxer_name;
diff --git a/demux/demux.c b/demux/demux.c
index 369e7f3226..b66f5e3e61 100644
--- a/demux/demux.c
+++ b/demux/demux.c
@@ -67,7 +67,7 @@ extern const demuxer_desc_t demuxer_desc_mpeg_es;
extern const demuxer_desc_t demuxer_desc_mpeg4_es;
extern const demuxer_desc_t demuxer_desc_h264_es;
extern const demuxer_desc_t demuxer_desc_mpeg_ts;
-extern const demuxer_desc_t demuxer_desc_sub;
+extern const demuxer_desc_t demuxer_desc_libass;
extern const demuxer_desc_t demuxer_desc_subreader;
/* Please do not add any new demuxers here. If you want to implement a new
@@ -82,6 +82,7 @@ const demuxer_desc_t *const demuxer_list[] = {
#ifdef CONFIG_TV
&demuxer_desc_tv,
#endif
+ &demuxer_desc_libass,
&demuxer_desc_matroska,
&demuxer_desc_lavf,
&demuxer_desc_subreader,
@@ -99,8 +100,6 @@ const demuxer_desc_t *const demuxer_list[] = {
&demuxer_desc_mpeg_ts,
// auto-probe last, because it checks file-extensions only
&demuxer_desc_mf,
- // no auto-probe
- &demuxer_desc_sub,
/* Please do not add any new demuxers here. If you want to implement a new
* demuxer, add it to libavformat, except for wrappers around external
* libraries and demuxers requiring binary support. */
@@ -289,18 +288,6 @@ static demuxer_t *new_demuxer(struct MPOpts *opts, stream_t *stream, int type,
return d;
}
-// for demux_sub.c
-demuxer_t *new_sub_pseudo_demuxer(struct MPOpts *opts)
-{
- struct stream *s = open_stream("null://", NULL, NULL);
- assert(s);
- struct demuxer *d = new_demuxer(opts, s, DEMUXER_TYPE_SUB,
- -1, -1, -1, NULL);
- new_sh_stream(d, STREAM_SUB);
- talloc_steal(d, s);
- return d;
-}
-
static struct sh_stream *new_sh_stream_id(demuxer_t *demuxer,
enum stream_type type,
int stream_index,
diff --git a/demux/demux.h b/demux/demux.h
index 9c10ca0201..f49a236b80 100644
--- a/demux/demux.h
+++ b/demux/demux.h
@@ -72,13 +72,13 @@ enum demuxer_type {
DEMUXER_TYPE_EDL,
DEMUXER_TYPE_CUE,
DEMUXER_TYPE_SUBREADER,
+ DEMUXER_TYPE_LIBASS,
/* Values after this are for internal use and can not be selected
* as demuxer type by the user (-demuxer option). */
DEMUXER_TYPE_END,
DEMUXER_TYPE_PLAYLIST,
- DEMUXER_TYPE_SUB,
};
enum timestamp_type {
@@ -217,6 +217,7 @@ struct demuxer_params {
unsigned char (*matroska_wanted_uids)[16];
int matroska_wanted_segment;
bool *matroska_was_valid;
+ struct ass_library *ass_library;
};
typedef struct demuxer {
@@ -307,9 +308,6 @@ static inline void *realloc_struct(void *ptr, size_t nmemb, size_t size)
return realloc(ptr, nmemb * size);
}
-demuxer_t *new_sub_pseudo_demuxer(struct MPOpts *opts);
-
-
void free_demuxer(struct demuxer *demuxer);
int demuxer_add_packet(demuxer_t *demuxer, struct sh_stream *stream,
diff --git a/demux/demux_libass.c b/demux/demux_libass.c
new file mode 100644
index 0000000000..1b7dc24452
--- /dev/null
+++ b/demux/demux_libass.c
@@ -0,0 +1,108 @@
+/*
+ * This file is part of mpv.
+ *
+ * mpv 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.
+ *
+ * mpv 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 mpv. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+// Note: just wraps libass, and makes the subtitle track available though
+// sh_sub->track. It doesn't produce packets and doesn't support seeking.
+
+#include <ass/ass.h>
+#include <ass/ass_types.h>
+
+#include "core/options.h"
+#include "core/mp_msg.h"
+#include "stream/stream.h"
+#include "demux.h"
+
+#define PROBE_SIZE (4 * 1024)
+
+struct priv {
+ ASS_Track *track;
+};
+
+static int d_check_file(struct demuxer *demuxer)
+{
+ struct stream *s = demuxer->stream;
+ // Older versions of libass will behave strange if renderer and track
+ // library handles mismatch, so make sure everything uses a global handle.
+ ASS_Library *lib = demuxer->params ? demuxer->params->ass_library : NULL;
+ if (!lib)
+ return 0;
+
+ // Probe by loading a part of the beginning of the file with libass.
+ // Incomplete scripts are usually ok, and we hope libass is not verbose
+ // when dealing with (from its perspective) completely broken binary
+ // garbage.
+
+ bstr buf = stream_peek(s, PROBE_SIZE);
+ // Older versions of libass will overwrite the input buffer, and despite
+ // passing length, expect a 0 termination.
+ void *tmp = talloc_size(NULL, buf.len + 1);
+ memcpy(tmp, buf.start, buf.len);
+ buf.start = tmp;
+ buf.start[buf.len] = '\0';
+ ASS_Track *track = ass_read_memory(lib, buf.start, buf.len, NULL);
+ talloc_free(buf.start);
+ if (!track)
+ return 0;
+ ass_free_track(track);
+
+ // Actually load the full thing.
+
+ buf = stream_read_complete(s, NULL, 100000000);
+ if (!buf.start) {
+ mp_tmsg(MSGT_ASS, MSGL_ERR, "Refusing to load subtitle file "
+ "larger than 100 MB: %s\n", demuxer->filename);
+ return 0;
+ }
+ track = ass_read_memory(lib, buf.start, buf.len, NULL);
+ talloc_free(buf.start);
+ if (!track)
+ return 0;
+
+ track->name = strdup(demuxer->filename);
+
+ struct priv *p = talloc_ptrtype(demuxer, p);
+ *p = (struct priv) {
+ .track = track,
+ };
+
+ struct sh_stream *sh = new_sh_stream(demuxer, STREAM_SUB);
+ sh->sub->track = track;
+ sh->codec = "ass";
+
+ return DEMUXER_TYPE_LIBASS;
+}
+
+static void d_close(struct demuxer *demuxer)
+{
+ struct priv *p = demuxer->priv;
+ if (p) {
+ if (p->track)
+ ass_free_track(p->track);
+ }
+}
+
+const struct demuxer_desc demuxer_desc_libass = {
+ .info = "Read subtitles with libass",
+ .name = "libass",
+ .shortdesc = "ASS/SSA subtitles (libass)",
+ .author = "",
+ .comment = "",
+ .safe_check = 1,
+ .type = DEMUXER_TYPE_LIBASS,
+ .check_file = d_check_file,
+ .close = d_close,
+};
diff --git a/demux/demux_sub.c b/demux/demux_sub.c
deleted file mode 100644
index ab99091215..0000000000
--- a/demux/demux_sub.c
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * This file is part of mpv.
- *
- * mpv 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.
- *
- * mpv 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 mpv. If not, see <http://www.gnu.org/licenses/>.
- */
-
-// Note: not a real demuxer. The frontend has its own code to open subtitle
-// code, and then creates a new dummy demuxer with new_sub_demuxer().
-// But eventually, all subtitles should be opened this way, and this
-// file can be removed.
-
-#include "demux.h"
-
-static int dummy_fill_buffer(struct demuxer *demuxer, struct demux_stream *ds)
-{
- return 0;
-}
-
-const struct demuxer_desc demuxer_desc_sub = {
- .info = "External subtitles pseudo demuxer",
- .name = "sub",
- .shortdesc = "sub",
- .author = "",
- .comment = "",
- .type = DEMUXER_TYPE_SUB,
- .fill_buffer = dummy_fill_buffer,
-};
diff --git a/sub/ass_mp.c b/sub/ass_mp.c
index 48a713f6ee..5e87223041 100644
--- a/sub/ass_mp.c
+++ b/sub/ass_mp.c
@@ -112,34 +112,6 @@ ASS_Track *mp_ass_default_track(ASS_Library *library, struct MPOpts *opts)
return track;
}
-ASS_Track *mp_ass_read_stream(ASS_Library *library, const char *fname,
- char *charset)
-{
- ASS_Track *track;
-
- struct stream *s = open_stream(fname, NULL, NULL);
- if (!s)
- // Stream code should have printed an error already
- return NULL;
- struct bstr content = stream_read_complete(s, NULL, 100000000);
- if (content.start == NULL)
- mp_tmsg(MSGT_ASS, MSGL_ERR, "Refusing to load subtitle file "
- "larger than 100 MB: %s\n", fname);
- free_stream(s);
- if (content.len == 0) {
- talloc_free(content.start);
- return NULL;
- }
- content.start[content.len] = 0;
- track = ass_read_memory(library, content.start, content.len, charset);
- if (track) {
- free(track->name);
- track->name = strdup(fname);
- }
- talloc_free(content.start);
- return track;
-}
-
void mp_ass_configure(ASS_Renderer *priv, struct MPOpts *opts,
struct mp_osd_res *dim)
{
diff --git a/sub/ass_mp.h b/sub/ass_mp.h
index dbdc95f031..c0fba934eb 100644
--- a/sub/ass_mp.h
+++ b/sub/ass_mp.h
@@ -49,8 +49,6 @@ void mp_ass_set_style(ASS_Style *style, int res_y, struct osd_style_opts *opts);
void mp_ass_add_default_styles(ASS_Track *track, struct MPOpts *opts);
ASS_Track *mp_ass_default_track(ASS_Library *library, struct MPOpts *opts);
-ASS_Track *mp_ass_read_stream(ASS_Library *library, const char *fname,
- char *charset);
struct MPOpts;
void mp_ass_configure(ASS_Renderer *priv, struct MPOpts *opts,