summaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2013-06-25 00:43:04 +0200
committerwm4 <wm4@nowhere>2013-06-25 00:43:04 +0200
commit403a266d466850621397c07e0b96cc2c493b2936 (patch)
tree0835a0908b3df8cca8374d173c34e0bf7df7d842 /core
parent536871d7e5848eb385b97202a33b9382b5e8ab0e (diff)
parent54851d60614e912fc422658302d72811a31b80f8 (diff)
downloadmpv-403a266d466850621397c07e0b96cc2c493b2936.tar.bz2
mpv-403a266d466850621397c07e0b96cc2c493b2936.tar.xz
Merge branch 'sub_mess2'
...the return.
Diffstat (limited to 'core')
-rw-r--r--core/charset_conv.c266
-rw-r--r--core/charset_conv.h17
-rw-r--r--core/command.c5
-rw-r--r--core/encode_lavc.c2
-rw-r--r--core/input/input.c2
-rw-r--r--core/mp_core.h3
-rw-r--r--core/mplayer.c110
-rw-r--r--core/options.c9
-rw-r--r--core/options.h3
9 files changed, 325 insertions, 92 deletions
diff --git a/core/charset_conv.c b/core/charset_conv.c
new file mode 100644
index 0000000000..680c8f83f9
--- /dev/null
+++ b/core/charset_conv.c
@@ -0,0 +1,266 @@
+/*
+ * This file is part of mpv.
+ *
+ * Based on code taken from libass (ISC license), which was originally part
+ * of MPlayer (GPL).
+ * Copyright (C) 2006 Evgeniy Stepanov <eugeni.stepanov@gmail.com>
+ *
+ * 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/>.
+ */
+
+#include <stdlib.h>
+#include <errno.h>
+#include <assert.h>
+
+#include "config.h"
+
+#include "core/mp_msg.h"
+
+#ifdef CONFIG_ENCA
+#include <enca.h>
+#endif
+
+#ifdef CONFIG_LIBGUESS
+#include <libguess.h>
+#endif
+
+#ifdef CONFIG_ICONV
+#include <iconv.h>
+#endif
+
+#include "charset_conv.h"
+
+// Split the string on ':' into components.
+// out_arr is at least max entries long.
+// Return number of out_arr entries filled.
+static int split_colon(const char *user_cp, int max, bstr *out_arr)
+{
+ if (!user_cp || max < 1)
+ return 0;
+
+ int count = 0;
+ while (1) {
+ const char *next = strchr(user_cp, ':');
+ if (next && max - count > 1) {
+ out_arr[count++] = (bstr){(char *)user_cp, next - user_cp};
+ user_cp = next + 1;
+ } else {
+ out_arr[count++] = (bstr){(char *)user_cp, strlen(user_cp)};
+ break;
+ }
+ }
+ return count;
+}
+
+// Returns true if user_cp implies that calling mp_charset_guess() on the
+// input data is required to determine the real codepage. This is the case
+// if user_cp is not a real iconv codepage, but a magic value that requests
+// for example ENCA charset auto-detection.
+bool mp_charset_requires_guess(const char *user_cp)
+{
+ bstr res[2] = {{0}};
+ split_colon(user_cp, 2, res);
+ return bstrcasecmp0(res[0], "enca") == 0 ||
+ bstrcasecmp0(res[0], "guess") == 0;
+}
+
+#ifdef CONFIG_ENCA
+static const char *enca_guess(bstr buf, const char *language)
+{
+ if (!language || !language[0])
+ language = "__"; // neutral language
+
+ const char *detected_cp = NULL;
+
+ EncaAnalyser analyser = enca_analyser_alloc(language);
+ if (analyser) {
+ enca_set_termination_strictness(analyser, 0);
+ EncaEncoding enc = enca_analyse_const(analyser, buf.start, buf.len);
+ const char *tmp = enca_charset_name(enc.charset, ENCA_NAME_STYLE_ICONV);
+ if (tmp && enc.charset != ENCA_CS_UNKNOWN)
+ detected_cp = tmp;
+ enca_analyser_free(analyser);
+ } else {
+ mp_msg(MSGT_SUBREADER, MSGL_ERR, "ENCA doesn't know language '%s'\n",
+ language);
+ size_t langcnt;
+ const char **languages = enca_get_languages(&langcnt);
+ mp_msg(MSGT_SUBREADER, MSGL_ERR, "ENCA supported languages:");
+ for (int i = 0; i < langcnt; i++)
+ mp_msg(MSGT_SUBREADER, MSGL_ERR, " %s", languages[i]);
+ mp_msg(MSGT_SUBREADER, MSGL_ERR, "\n");
+ free(languages);
+ }
+
+ return detected_cp;
+}
+#endif
+
+#ifdef CONFIG_LIBGUESS
+static const char *libguess_guess(bstr buf, const char *language)
+{
+ if (libguess_validate_utf8(buf.start, buf.len))
+ return "UTF-8";
+
+ if (!language || !language[0] || strcmp(language, "help") == 0) {
+ mp_msg(MSGT_SUBREADER, MSGL_ERR, "libguess needs a language: "
+ "japanese taiwanese chinese korean russian arabic turkish "
+ "greek hebrew polish baltic\n");
+ return NULL;
+ }
+
+ return libguess_determine_encoding(buf.start, buf.len, language);
+}
+#endif
+
+// Runs charset auto-detection on the input buffer, and returns the result.
+// If auto-detection fails, NULL is returned.
+// If user_cp doesn't refer to any known auto-detection (for example because
+// it's a real iconv codepage), user_cp is returned without even looking at
+// the buf data.
+const char *mp_charset_guess(bstr buf, const char *user_cp)
+{
+ if (!mp_charset_requires_guess(user_cp))
+ return user_cp;
+
+ bstr params[3] = {{0}};
+ split_colon(user_cp, 3, params);
+
+ bstr type = params[0];
+ char lang[100];
+ snprintf(lang, sizeof(lang), "%.*s", BSTR_P(params[1]));
+ const char *fallback = params[2].start; // last item, already 0-terminated
+
+ const char *res = NULL;
+
+#ifdef CONFIG_ENCA
+ if (bstrcasecmp0(type, "enca") == 0)
+ res = enca_guess(buf, lang);
+#endif
+#ifdef CONFIG_LIBGUESS
+ if (bstrcasecmp0(type, "guess") == 0)
+ res = libguess_guess(buf, lang);
+#endif
+
+ if (res) {
+ mp_msg(MSGT_SUBREADER, MSGL_DBG2, "%.*s detected charset: '%s'\n",
+ BSTR_P(type), res);
+ } else {
+ res = fallback;
+ mp_msg(MSGT_SUBREADER, MSGL_DBG2,
+ "Detection with %.*s failed: fallback to %s\n",
+ BSTR_P(type), res && res[0] ? res : "no conversion");
+ }
+
+ return res;
+}
+
+// Convert the data in buf to UTF-8. The charset argument can be an iconv
+// codepage, a value returned by mp_charset_conv_guess(), or a special value
+// that triggers autodetection of the charset (e.g. using ENCA).
+// The auto-detection is the only difference to mp_iconv_to_utf8().
+// buf: same as mp_iconv_to_utf8()
+// user_cp: iconv codepage, special value, NULL
+// flags: same as mp_iconv_to_utf8()
+// returns: same as mp_iconv_to_utf8()
+bstr mp_charset_guess_and_conv_to_utf8(bstr buf, const char *user_cp, int flags)
+{
+ return mp_iconv_to_utf8(buf, mp_charset_guess(buf, user_cp), flags);
+}
+
+// Use iconv to convert buf to UTF-8.
+// Returns buf.start==NULL on error. Returns buf if cp is NULL, or if there is
+// obviously no conversion required (e.g. if cp is "UTF-8").
+// Returns a newly allocated buffer if conversion is done and succeeds. The
+// buffer will be terminated with 0 for convenience (the terminating 0 is not
+// included in the returned length).
+// Free the returned buffer with talloc_free().
+// buf: input data
+// cp: iconv codepage (or NULL)
+// flags: combination of MP_ICONV_* flags
+// returns: buf (no conversion), .start==NULL (error), or allocated buffer
+bstr mp_iconv_to_utf8(bstr buf, const char *cp, int flags)
+{
+#ifdef CONFIG_ICONV
+ const char *tocp = "UTF-8";
+
+ if (!cp || !cp[0] || strcasecmp(cp, tocp) == 0)
+ return buf;
+
+ if (strcasecmp(cp, "ASCII") == 0)
+ return buf;
+
+ iconv_t icdsc;
+ if ((icdsc = iconv_open(tocp, cp)) == (iconv_t) (-1)) {
+ if (flags & MP_ICONV_VERBOSE)
+ mp_msg(MSGT_SUBREADER, MSGL_ERR,
+ "Error opening iconv with codepage '%s'\n", cp);
+ goto failure;
+ }
+
+ size_t size = buf.len;
+ size_t osize = size;
+ size_t ileft = size;
+ size_t oleft = size - 1;
+
+ char *outbuf = talloc_size(NULL, osize);
+ char *ip = buf.start;
+ char *op = outbuf;
+
+ while (1) {
+ int clear = 0;
+ size_t rc;
+ if (ileft)
+ rc = iconv(icdsc, &ip, &ileft, &op, &oleft);
+ else {
+ clear = 1; // clear the conversion state and leave
+ rc = iconv(icdsc, NULL, NULL, &op, &oleft);
+ }
+ if (rc == (size_t) (-1)) {
+ if (errno == E2BIG) {
+ size_t offset = op - outbuf;
+ outbuf = talloc_realloc_size(NULL, outbuf, osize + size);
+ op = outbuf + offset;
+ osize += size;
+ oleft += size;
+ } else {
+ if (errno == EINVAL && (flags & MP_ICONV_ALLOW_CUTOFF)) {
+ // This is intended for cases where the input buffer is cut
+ // at a random byte position. If this happens in the middle
+ // of the buffer, it should still be an error. We say it's
+ // fine if the error is within 10 bytes of the end.
+ if (ileft <= 10)
+ break;
+ }
+ if (flags & MP_ICONV_VERBOSE) {
+ mp_msg(MSGT_SUBREADER, MSGL_ERR,
+ "Error recoding text with codepage '%s'\n", cp);
+ }
+ talloc_free(outbuf);
+ iconv_close(icdsc);
+ goto failure;
+ }
+ } else if (clear)
+ break;
+ }
+
+ iconv_close(icdsc);
+
+ outbuf[osize - oleft - 1] = 0;
+ return (bstr){outbuf, osize - oleft - 1};
+#endif
+
+failure:
+ return (bstr){0};
+}
diff --git a/core/charset_conv.h b/core/charset_conv.h
new file mode 100644
index 0000000000..00a2658da3
--- /dev/null
+++ b/core/charset_conv.h
@@ -0,0 +1,17 @@
+#ifndef MP_CHARSET_CONV_H
+#define MP_CHARSET_CONV_H
+
+#include <stdbool.h>
+#include "core/bstr.h"
+
+enum {
+ MP_ICONV_VERBOSE = 1, // print errors instead of failing silently
+ MP_ICONV_ALLOW_CUTOFF = 2, // allow partial input data
+};
+
+bool mp_charset_requires_guess(const char *user_cp);
+const char *mp_charset_guess(bstr buf, const char *user_cp);
+bstr mp_charset_guess_and_conv_to_utf8(bstr buf, const char *user_cp, int flags);
+bstr mp_iconv_to_utf8(bstr buf, const char *cp, int flags);
+
+#endif
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/encode_lavc.c b/core/encode_lavc.c
index b09ecaa1ac..9fada7de58 100644
--- a/core/encode_lavc.c
+++ b/core/encode_lavc.c
@@ -404,7 +404,7 @@ static void encode_2pass_prepare(struct encode_lavc_context *ctx,
set_to_avdictionary(dictp, "flags", "-pass2");
} else {
struct bstr content = stream_read_complete(*bytebuf, NULL,
- 1000000000, 1);
+ 1000000000);
if (content.start == NULL) {
mp_msg(MSGT_ENCODE, MSGL_WARN, "%s: could not read '%s', "
"disabling 2-pass encoding at pass 1\n",
diff --git a/core/input/input.c b/core/input/input.c
index 2d7569c8e9..dfa7d1e5b4 100644
--- a/core/input/input.c
+++ b/core/input/input.c
@@ -1737,7 +1737,7 @@ static int parse_config_file(struct input_ctx *ictx, char *file, bool warn)
mp_msg(MSGT_INPUT, MSGL_ERR, "Can't open input config file %s.\n", file);
return 0;
}
- bstr res = stream_read_complete(s, NULL, 1000000, 0);
+ bstr res = stream_read_complete(s, NULL, 1000000);
free_stream(s);
mp_msg(MSGT_INPUT, MSGL_V, "Parsing input config file %s\n", file);
int n_binds = parse_config(ictx, false, res, file);
diff --git a/core/mp_core.h b/core/mp_core.h
index 98a92cbea4..0bd6ecda15 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 d28b5fdc4c..3cdd83021d 100644
--- a/core/mplayer.c
+++ b/core/mplayer.c
@@ -71,7 +71,6 @@
#include "core/mplayer.h"
#include "core/m_property.h"
-#include "sub/subreader.h"
#include "sub/find_subfiles.h"
#include "sub/dec_sub.h"
#include "sub/sd.h"
@@ -197,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)
{
@@ -982,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 = {
@@ -1028,69 +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;
- sub_data *subd = 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)
- subd = sub_read_file(filename, fps, &mpctx->opts);
- if (asst || subd) {
- 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 = asst ? "ass" : subd->codec;
- s->sub->track = asst;
- s->sub->sub_data = subd;
-
- 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) {
@@ -2001,7 +1937,8 @@ static void reinit_subs(struct MPContext *mpctx)
if (!mpctx->sh_sub->dec_sub)
mpctx->sh_sub->dec_sub = sub_create(opts);
- if (track->demuxer && !track->stream) {
+ assert(track->demuxer);
+ if (!track->stream) {
// Lazily added DVD track - we must not miss the first subtitle packet,
// which makes the demuxer create the sh_stream, and contains the first
// subtitle event.
@@ -2016,7 +1953,6 @@ static void reinit_subs(struct MPContext *mpctx)
return;
}
- assert(track->demuxer && track->stream);
mpctx->initialized_flags |= INITIALIZED_SUB;
@@ -2027,12 +1963,22 @@ static void reinit_subs(struct MPContext *mpctx)
if (!sub_is_initialized(dec_sub)) {
int w = mpctx->sh_video ? mpctx->sh_video->disp_w : 0;
int h = mpctx->sh_video ? mpctx->sh_video->disp_h : 0;
+ float fps = mpctx->sh_video ? mpctx->sh_video->fps : 25;
set_dvdsub_fake_extradata(dec_sub, track->demuxer->stream, w, h);
sub_set_video_res(dec_sub, w, h);
+ sub_set_video_fps(dec_sub, fps);
sub_set_ass_renderer(dec_sub, mpctx->osd->ass_library,
mpctx->osd->ass_renderer);
sub_init_from_sh(dec_sub, sh_sub);
+
+ // Don't do this if the file has video/audio streams. Don't do it even
+ // if it has only sub streams, because reading packets will change the
+ // demuxer position.
+ if (!track->preloaded && track->is_external) {
+ demux_seek(track->demuxer, 0, 0, SEEK_ABSOLUTE);
+ track->preloaded = sub_read_all_packets(dec_sub, sh_sub);
+ }
}
mpctx->osd->dec_sub = dec_sub;
@@ -3920,16 +3866,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;
}
@@ -3959,9 +3904,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;
@@ -3999,12 +3947,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)
@@ -4293,13 +4240,20 @@ goto_reopen_demuxer: ;
if (mpctx->timeline)
timeline_set_part(mpctx, mpctx->timeline_part, true);
+ // Decide correct-pts mode based on first segment of video track
+ opts->correct_pts = opts->user_correct_pts;
+ if (opts->correct_pts < 0) {
+ opts->correct_pts =
+ demux_control(mpctx->demuxer, DEMUXER_CTRL_CORRECT_PTS,
+ NULL) == DEMUXER_CTRL_OK;
+ }
+
mpctx->initialized_flags |= INITIALIZED_DEMUXER;
add_subtitle_fonts_from_sources(mpctx);
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 f3e262fc17..40c8527394 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),
@@ -493,12 +492,11 @@ const m_option_t mp_opts[] = {
OPT_STRING("subcp", sub_cp, 0),
OPT_FLOAT("sub-delay", sub_delay, 0),
OPT_FLOAT("subfps", sub_fps, 0),
+ OPT_FLOAT("sub-speed", sub_speed, 0),
OPT_FLAG("autosub", sub_auto, 0),
OPT_FLAG("sub-visibility", sub_visibility, 0),
OPT_FLAG("sub-forced-only", forced_subs_only, 0),
- // enable Closed Captioning display
- OPT_FLAG_CONSTANTS("overlapsub", suboverlap_enabled, 0, 0, 2),
- OPT_FLAG_STORE("sub-no-text-pp", sub_no_text_pp, 0, 1),
+ OPT_FLAG_CONSTANTS("sub-fix-timing", suboverlap_enabled, 0, 1, 0),
OPT_CHOICE("autosub-match", sub_match_fuzziness, 0,
({"exact", 0}, {"fuzzy", 1}, {"all", 2})),
OPT_INTRANGE("sub-pos", sub_pos, 0, 0, 100),
@@ -789,6 +787,7 @@ const struct MPOpts mp_default_opts = {
.audio_display = 1,
.sub_visibility = 1,
.sub_pos = 100,
+ .sub_speed = 1.0,
.extension_parsing = 1,
.audio_output_channels = MP_CHMAP_INIT_STEREO,
.audio_output_format = -1, // AF_FORMAT_UNKNOWN
@@ -804,7 +803,7 @@ const struct MPOpts mp_default_opts = {
.ass_vsfilter_aspect_compat = 1,
.ass_style_override = 1,
.use_embedded_fonts = 1,
- .suboverlap_enabled = 1,
+ .suboverlap_enabled = 0,
.hwdec_codecs = "all",
diff --git a/core/options.h b/core/options.h
index f925990a6c..0c6f6c7271 100644
--- a/core/options.h
+++ b/core/options.h
@@ -141,17 +141,16 @@ typedef struct MPOpts {
int sub_pos;
float sub_delay;
float sub_fps;
+ float sub_speed;
int forced_subs_only;
char *quvi_format;
// subreader.c
int suboverlap_enabled;
char *sub_cp;
- int sub_no_text_pp;
char *audio_stream;
int audio_stream_cache;
- char *sub_stream;
char *demuxer_name;
char *audio_demuxer_name;
char *sub_demuxer_name;