summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2015-11-17 01:54:02 +0100
committerwm4 <wm4@nowhere>2015-11-17 01:56:23 +0100
commit5a89150a4652d987f24d7d386d5cdc6d9109e66d (patch)
treefc6085143661672f537a604b6645f79e0dced3ad
parent85450d06a1b1a08fce277f7f14d5ee33b12f8eab (diff)
downloadmpv-5a89150a4652d987f24d7d386d5cdc6d9109e66d.tar.bz2
mpv-5a89150a4652d987f24d7d386d5cdc6d9109e66d.tar.xz
player: remove OSD subtitle render path
This was used with --no-sub-ass (aka --no-ass). This option (which is not yet removed) strips all styling from the subtitles, and renders them as plaintext only. For some reason, it originally seemed convenient to reuse all the OSD text rendering code (osd_libass.c). While this was indeed simple, it had a bad influence on the rest of the code. For example, it had to decide whether to go through the OSD code path, or the proper subtitle renderer in sd_ass.c. Kill the OSD subtitle renderer. Reimplement --no-sub-ass and also "secondary" subtitles in sd_ass.c. fill_plaintext() contains some rather minor code duplication with osd_libass.c for setting up a dummy ASS_Event and escaping the stripped text. Since sd_ass.c already has to handle "normal" text subtitles, and has code for stripping ASS tags, this remains all relatively simple. Remove all the unnecessary crap from the rest of the code.
-rw-r--r--player/command.c7
-rw-r--r--player/core.h4
-rw-r--r--player/osd.c11
-rw-r--r--player/sub.c53
-rw-r--r--sub/dec_sub.h1
-rw-r--r--sub/osd.c19
-rw-r--r--sub/osd.h10
-rw-r--r--sub/osd_libass.c30
-rw-r--r--sub/osd_state.h2
-rw-r--r--sub/sd_ass.c80
10 files changed, 90 insertions, 127 deletions
diff --git a/player/command.c b/player/command.c
index f6ccf22cae..7d520d78ac 100644
--- a/player/command.c
+++ b/player/command.c
@@ -4472,14 +4472,13 @@ int run_command(struct MPContext *mpctx, struct mp_cmd *cmd, struct mpv_node *re
case MP_CMD_SUB_SEEK: {
if (!mpctx->playback_initialized)
return -1;
- struct osd_sub_state state;
- update_osd_sub_state(mpctx, 0, &state);
+ struct dec_sub *sub = mpctx->d_sub[0];
double refpts = get_current_time(mpctx);
- if (state.dec_sub && refpts != MP_NOPTS_VALUE) {
+ if (sub && refpts != MP_NOPTS_VALUE) {
double a[2];
a[0] = refpts - opts->sub_delay;
a[1] = cmd->args[0].v.i;
- if (sub_control(state.dec_sub, SD_CTRL_SUB_STEP, a) > 0) {
+ if (sub_control(sub, SD_CTRL_SUB_STEP, a) > 0) {
if (cmd->id == MP_CMD_SUB_STEP) {
opts->sub_delay -= a[0];
osd_changed_all(mpctx->osd);
diff --git a/player/core.h b/player/core.h
index a7b643864d..2f9d2828ac 100644
--- a/player/core.h
+++ b/player/core.h
@@ -475,7 +475,7 @@ void set_osd_bar(struct MPContext *mpctx, int type,
bool set_osd_msg(struct MPContext *mpctx, int level, int time,
const char* fmt, ...) PRINTF_ATTRIBUTE(4,5);
void set_osd_function(struct MPContext *mpctx, int osd_function);
-void set_osd_subtitle(struct MPContext *mpctx, const char *text);
+void term_osd_set_subs(struct MPContext *mpctx, const char *text);
void get_current_osd_sym(struct MPContext *mpctx, char *buf, size_t buf_size);
void set_osd_bar_chapters(struct MPContext *mpctx, int type);
@@ -523,8 +523,6 @@ void uninit_sub_all(struct MPContext *mpctx);
void update_osd_msg(struct MPContext *mpctx);
void update_subtitles(struct MPContext *mpctx);
void uninit_sub_renderer(struct MPContext *mpctx);
-void update_osd_sub_state(struct MPContext *mpctx, int order,
- struct osd_sub_state *out_state);
// video.c
void reset_video_state(struct MPContext *mpctx);
diff --git a/player/osd.c b/player/osd.c
index ce3ba103cd..e26439432d 100644
--- a/player/osd.c
+++ b/player/osd.c
@@ -103,7 +103,7 @@ static void term_osd_update(struct MPContext *mpctx)
}
}
-static void term_osd_set_subs(struct MPContext *mpctx, const char *text)
+void term_osd_set_subs(struct MPContext *mpctx, const char *text)
{
if (mpctx->video_out || !text)
text = ""; // disable
@@ -386,15 +386,6 @@ void set_osd_function(struct MPContext *mpctx, int osd_function)
mpctx->sleeptime = 0;
}
-/**
- * \brief Display text subtitles on the OSD
- */
-void set_osd_subtitle(struct MPContext *mpctx, const char *text)
-{
- osd_set_text(mpctx->osd, OSDTYPE_SUB, text);
- term_osd_set_subs(mpctx, text);
-}
-
void get_current_osd_sym(struct MPContext *mpctx, char *buf, size_t buf_size)
{
int sym = mpctx->osd_function;
diff --git a/player/sub.c b/player/sub.c
index e326b3e2fd..0a55936f54 100644
--- a/player/sub.c
+++ b/player/sub.c
@@ -133,11 +133,9 @@ void uninit_sub_renderer(struct MPContext *mpctx) {}
static void reset_subtitles(struct MPContext *mpctx, int order)
{
- int obj = order ? OSDTYPE_SUB2 : OSDTYPE_SUB;
if (mpctx->d_sub[order])
sub_reset(mpctx->d_sub[order]);
- set_osd_subtitle(mpctx, NULL);
- osd_set_text(mpctx->osd, obj, NULL);
+ term_osd_set_subs(mpctx, NULL);
}
void reset_subtitle_state(struct MPContext *mpctx)
@@ -162,7 +160,7 @@ void uninit_sub(struct MPContext *mpctx, int order)
if (mpctx->d_sub[order]) {
reset_subtitles(mpctx, order);
mpctx->d_sub[order] = NULL; // Note: not free'd.
- update_osd_sub_state(mpctx, order, NULL); // unset
+ osd_set_sub(mpctx->osd, OSDTYPE_SUB + order, NULL);
reselect_demux_streams(mpctx);
}
}
@@ -191,33 +189,6 @@ static bool is_interleaved(struct MPContext *mpctx, struct track *track)
return track->demuxer == mpctx->demuxer;
}
-void update_osd_sub_state(struct MPContext *mpctx, int order,
- struct osd_sub_state *out_state)
-{
- struct MPOpts *opts = mpctx->opts;
- struct dec_sub *dec_sub = mpctx->d_sub[order];
- int obj = order ? OSDTYPE_SUB2 : OSDTYPE_SUB;
- bool textsub = dec_sub && sub_has_get_text(dec_sub);
-
- struct osd_sub_state state = {
- .dec_sub = dec_sub,
- // Decides whether to use OSD path or normal subtitle rendering path.
- .render_bitmap_subs = opts->ass_enabled || !textsub,
- };
-
- // Secondary subs are rendered with the "text" renderer to transform them
- // to toptitles.
- if (order == 1 && textsub)
- state.render_bitmap_subs = false;
-
- if (!mpctx->current_track[0][STREAM_VIDEO])
- state.render_bitmap_subs = false;
-
- osd_set_sub(mpctx->osd, obj, &state);
- if (out_state)
- *out_state = state;
-}
-
static void update_subtitle(struct MPContext *mpctx, int order)
{
struct MPOpts *opts = mpctx->opts;
@@ -227,17 +198,12 @@ static void update_subtitle(struct MPContext *mpctx, int order)
if (!track || !dec_sub)
return;
- int obj = order ? OSDTYPE_SUB2 : OSDTYPE_SUB;
-
if (mpctx->d_video) {
struct mp_image_params params = mpctx->d_video->vfilter->override_params;
if (params.imgfmt)
sub_control(dec_sub, SD_CTRL_SET_VIDEO_PARAMS, &params);
}
- struct osd_sub_state state;
- update_osd_sub_state(mpctx, order, &state);
-
double refpts_s = mpctx->playback_pts;
double curpts_s = refpts_s - opts->sub_delay;
@@ -272,12 +238,8 @@ static void update_subtitle(struct MPContext *mpctx, int order)
}
// Handle displaying subtitles on terminal; never done for secondary subs
- if (order == 0) {
- if (!state.render_bitmap_subs || !mpctx->video_out)
- set_osd_subtitle(mpctx, sub_get_text(dec_sub, curpts_s));
- } else if (order == 1) {
- osd_set_text(mpctx->osd, obj, sub_get_text(dec_sub, curpts_s));
- }
+ if (order == 0 && !mpctx->video_out)
+ term_osd_set_subs(mpctx, sub_get_text(dec_sub, curpts_s));
}
void update_subtitles(struct MPContext *mpctx)
@@ -335,8 +297,7 @@ void reinit_subs(struct MPContext *mpctx, int order)
sh->sub->dec_sub = sub_create(mpctx->global);
mpctx->d_sub[order] = sh->sub->dec_sub;
- struct dec_sub *dec_sub = mpctx->d_sub[order];
- reinit_subdec(mpctx, track, dec_sub);
-
- update_osd_sub_state(mpctx, order, NULL);
+ reinit_subdec(mpctx, track, sh->sub->dec_sub);
+ osd_set_sub(mpctx->osd, OSDTYPE_SUB + order, sh->sub->dec_sub);
+ sub_control(sh->sub->dec_sub, SD_CTRL_SET_TOP, &(bool){!!order});
}
diff --git a/sub/dec_sub.h b/sub/dec_sub.h
index ddec46e243..b9f81a77b7 100644
--- a/sub/dec_sub.h
+++ b/sub/dec_sub.h
@@ -21,6 +21,7 @@ enum sd_ctrl {
SD_CTRL_SUB_STEP,
SD_CTRL_SET_VIDEO_PARAMS,
SD_CTRL_GET_RESOLUTION,
+ SD_CTRL_SET_TOP,
};
struct dec_sub *sub_create(struct mpv_global *global);
diff --git a/sub/osd.c b/sub/osd.c
index 3090c2e5e7..93f188f09d 100644
--- a/sub/osd.c
+++ b/sub/osd.c
@@ -163,10 +163,10 @@ void osd_set_text(struct osd_state *osd, int obj, const char *text)
pthread_mutex_unlock(&osd->lock);
}
-void osd_set_sub(struct osd_state *osd, int obj, struct osd_sub_state *substate)
+void osd_set_sub(struct osd_state *osd, int obj, struct dec_sub *dec_sub)
{
pthread_mutex_lock(&osd->lock);
- osd->objs[obj]->sub_state = substate ? *substate : (struct osd_sub_state){0};
+ osd->objs[obj]->sub = dec_sub;
pthread_mutex_unlock(&osd->lock);
}
@@ -243,14 +243,11 @@ static void render_object(struct osd_state *osd, struct osd_object *obj,
obj->vo_res = res;
if (obj->type == OSDTYPE_SUB || obj->type == OSDTYPE_SUB2) {
- struct osd_sub_state *sub = &obj->sub_state;
- if (sub->render_bitmap_subs && sub->dec_sub) {
+ if (obj->sub) {
double sub_pts = video_pts;
if (sub_pts != MP_NOPTS_VALUE)
sub_pts -= opts->sub_delay;
- sub_get_bitmaps(sub->dec_sub, obj->vo_res, sub_pts, out_imgs);
- } else {
- osd_object_get_bitmaps(osd, obj, out_imgs);
+ sub_get_bitmaps(obj->sub, obj->vo_res, sub_pts, out_imgs);
}
} else if (obj->type == OSDTYPE_EXTERNAL2) {
if (obj->external2 && obj->external2->format) {
@@ -324,8 +321,8 @@ void osd_draw(struct osd_state *osd, struct mp_osd_res res,
if ((draw_flags & OSD_DRAW_OSD_ONLY) && obj->is_sub)
continue;
- if (obj->sub_state.dec_sub)
- sub_lock(obj->sub_state.dec_sub);
+ if (obj->sub)
+ sub_lock(obj->sub);
struct sub_bitmaps imgs;
render_object(osd, obj, res, video_pts, formats, &imgs);
@@ -338,8 +335,8 @@ void osd_draw(struct osd_state *osd, struct mp_osd_res res,
}
}
- if (obj->sub_state.dec_sub)
- sub_unlock(obj->sub_state.dec_sub);
+ if (obj->sub)
+ sub_unlock(obj->sub);
}
pthread_mutex_unlock(&osd->lock);
diff --git a/sub/osd.h b/sub/osd.h
index 0698ceee5c..6cacf60de4 100644
--- a/sub/osd.h
+++ b/sub/osd.h
@@ -80,7 +80,7 @@ struct mp_osd_res {
enum mp_osdtype {
OSDTYPE_SUB,
- OSDTYPE_SUB2,
+ OSDTYPE_SUB2, // IDs must be numerically successive
OSDTYPE_PROGBAR,
OSDTYPE_OSD,
@@ -141,6 +141,7 @@ extern const struct m_sub_options sub_style_conf;
struct osd_state;
struct osd_object;
struct mpv_global;
+struct dec_sub;
struct osd_state *osd_create(struct mpv_global *global);
void osd_changed(struct osd_state *osd, int new_value);
@@ -150,12 +151,7 @@ void osd_free(struct osd_state *osd);
bool osd_query_and_reset_want_redraw(struct osd_state *osd);
void osd_set_text(struct osd_state *osd, int obj, const char *text);
-
-struct osd_sub_state {
- struct dec_sub *dec_sub;
- bool render_bitmap_subs;
-};
-void osd_set_sub(struct osd_state *osd, int obj, struct osd_sub_state *substate);
+void osd_set_sub(struct osd_state *osd, int obj, struct dec_sub *dec_sub);
bool osd_get_render_subs_in_filter(struct osd_state *osd);
void osd_set_render_subs_in_filter(struct osd_state *osd, bool s);
diff --git a/sub/osd_libass.c b/sub/osd_libass.c
index e9225a891a..e8c64250c2 100644
--- a/sub/osd_libass.c
+++ b/sub/osd_libass.c
@@ -423,42 +423,12 @@ static void update_external(struct osd_state *osd, struct osd_object *obj)
}
}
-static void update_sub(struct osd_state *osd, struct osd_object *obj)
-{
- struct MPOpts *opts = osd->opts;
-
- clear_obj(obj);
-
- if (!obj->text || !obj->text[0] || obj->sub_state.render_bitmap_subs)
- return;
-
- create_ass_renderer(osd, obj);
- if (!obj->osd_track)
- obj->osd_track = mp_ass_default_track(obj->osd_ass_library, osd->opts);
-
- struct osd_style_opts font = *opts->sub_text_style;
- font.font_size *= opts->sub_scale;
-
- ASS_Style *style = obj->osd_track->styles + obj->osd_track->default_style;
- mp_ass_set_style(style, obj->osd_track->PlayResY, &font);
- if (obj->type == OSDTYPE_SUB2)
- style->Alignment = 6;
-
- ass_set_line_position(obj->osd_render, 100 - opts->sub_pos);
-
- add_osd_ass_event_escaped(obj->osd_track, obj->text);
-}
-
static void update_object(struct osd_state *osd, struct osd_object *obj)
{
switch (obj->type) {
case OSDTYPE_OSD:
update_osd(osd, obj);
break;
- case OSDTYPE_SUB:
- case OSDTYPE_SUB2:
- update_sub(osd, obj);
- break;
case OSDTYPE_PROGBAR:
update_progbar(osd, obj);
break;
diff --git a/sub/osd_state.h b/sub/osd_state.h
index 6fa03abe77..c3d4a6f295 100644
--- a/sub/osd_state.h
+++ b/sub/osd_state.h
@@ -20,7 +20,7 @@ struct osd_object {
struct osd_progbar_state progbar_state;
// OSDTYPE_SUB/OSDTYPE_SUB2
- struct osd_sub_state sub_state;
+ struct dec_sub *sub;
// OSDTYPE_EXTERNAL
int external_res_x, external_res_y;
diff --git a/sub/sd_ass.c b/sub/sd_ass.c
index baec35faa9..804e561e87 100644
--- a/sub/sd_ass.c
+++ b/sub/sd_ass.c
@@ -37,7 +37,9 @@
struct sd_ass_priv {
struct ass_track *ass_track;
+ struct ass_track *shadow_track; // for --sub-ass=no rendering
bool is_converted;
+ bool on_top;
struct sub_bitmap *parts;
bool flush_on_seek;
int extend_event;
@@ -47,6 +49,7 @@ struct sd_ass_priv {
};
static void mangle_colors(struct sd *sd, struct sub_bitmaps *parts);
+static void fill_plaintext(struct sd *sd, double pts);
static bool supports_format(const char *format)
{
@@ -76,6 +79,11 @@ static int init(struct sd *sd)
if (!ctx->is_converted)
ctx->ass_track->track_type = TRACK_TYPE_ASS;
+ ctx->shadow_track = ass_new_track(sd->ass_library);
+ ctx->shadow_track->PlayResX = 384;
+ ctx->shadow_track->PlayResY = 288;
+ mp_ass_add_default_styles(ctx->shadow_track, opts);
+
if (sd->extradata) {
ass_process_codec_private(ctx->ass_track, sd->extradata,
sd->extradata_len);
@@ -147,12 +155,11 @@ static void decode(struct sd *sd, struct demux_packet *packet)
event->Text = strdup(text);
}
-static void configure_ass(struct sd *sd, struct mp_osd_res *dim)
+static void configure_ass(struct sd *sd, struct mp_osd_res *dim,
+ bool converted, ASS_Track *track)
{
- struct sd_ass_priv *ctx = sd->priv;
struct MPOpts *opts = sd->opts;
ASS_Renderer *priv = sd->ass_renderer;
- ASS_Track *track = ctx->ass_track;
ass_set_frame_size(priv, dim->w, dim->h);
ass_set_margins(priv, dim->mt, dim->mb, dim->ml, dim->mr);
@@ -166,7 +173,7 @@ static void configure_ass(struct sd *sd, struct mp_osd_res *dim)
bool set_scale_by_window = true;
bool total_override = false;
// With forced overrides, apply the --sub-* specific options
- if (ctx->is_converted || opts->ass_style_override == 3) {
+ if (converted || opts->ass_style_override == 3) {
set_scale_with_window = opts->sub_scale_with_window;
set_use_margins = opts->sub_use_margins;
set_scale_by_window = opts->sub_scale_by_window;
@@ -175,7 +182,7 @@ static void configure_ass(struct sd *sd, struct mp_osd_res *dim)
set_scale_with_window = opts->ass_scale_with_window;
set_use_margins = opts->ass_use_margins;
}
- if (ctx->is_converted || opts->ass_style_override) {
+ if (converted || opts->ass_style_override) {
set_sub_pos = 100 - opts->sub_pos;
set_line_spacing = opts->ass_line_spacing;
set_hinting = opts->ass_hinting;
@@ -203,7 +210,7 @@ static void configure_ass(struct sd *sd, struct mp_osd_res *dim)
mp_ass_set_style(&style, 288, opts->sub_text_style);
ass_set_selective_style_override(priv, &style);
free(style.FontName);
- if (ctx->is_converted && track->default_style < track->n_styles) {
+ if (converted && track->default_style < track->n_styles) {
mp_ass_set_style(track->styles + track->default_style,
track->PlayResY, opts->sub_text_style);
}
@@ -217,6 +224,9 @@ static void get_bitmaps(struct sd *sd, struct mp_osd_res dim, double pts,
{
struct sd_ass_priv *ctx = sd->priv;
struct MPOpts *opts = sd->opts;
+ bool no_ass = !opts->ass_enabled;
+ bool converted = ctx->is_converted || no_ass;
+ ASS_Track *track = no_ass ? ctx->shadow_track : ctx->ass_track;
if (pts == MP_NOPTS_VALUE || !sd->ass_renderer)
return;
@@ -225,8 +235,8 @@ static void get_bitmaps(struct sd *sd, struct mp_osd_res dim, double pts,
ASS_Renderer *renderer = sd->ass_renderer;
double scale = dim.display_par;
- if (!ctx->is_converted && (!opts->ass_style_override ||
- opts->ass_vsfilter_aspect_compat))
+ if (!converted && (!opts->ass_style_override ||
+ opts->ass_vsfilter_aspect_compat))
{
// Let's use the original video PAR for vsfilter compatibility:
double par = scale
@@ -235,20 +245,21 @@ static void get_bitmaps(struct sd *sd, struct mp_osd_res dim, double pts,
if (isnormal(par))
scale = par;
}
- configure_ass(sd, &dim);
+ configure_ass(sd, &dim, converted, track);
ass_set_pixel_aspect(renderer, scale);
- if (!ctx->is_converted && (!opts->ass_style_override ||
- opts->ass_vsfilter_blur_compat))
+ if (!converted && (!opts->ass_style_override ||
+ opts->ass_vsfilter_blur_compat))
{
ass_set_storage_size(renderer, ctx->video_params.w, ctx->video_params.h);
} else {
ass_set_storage_size(renderer, 0, 0);
}
- mp_ass_render_frame(renderer, ctx->ass_track, pts * 1000 + .5,
- &ctx->parts, res);
+ if (no_ass)
+ fill_plaintext(sd, pts);
+ mp_ass_render_frame(renderer, track, pts * 1000 + .5, &ctx->parts, res);
talloc_steal(ctx, ctx->parts);
- if (!ctx->is_converted)
+ if (!converted)
mangle_colors(sd, res);
pthread_mutex_unlock(sd->ass_lock);
@@ -360,6 +371,42 @@ static char *get_text(struct sd *sd, double pts)
return ctx->last_text;
}
+static void fill_plaintext(struct sd *sd, double pts)
+{
+ struct sd_ass_priv *ctx = sd->priv;
+ ASS_Track *track = ctx->shadow_track;
+
+ ass_flush_events(track);
+
+ char *text = get_text(sd, pts);
+ if (!text)
+ return;
+
+ bstr dst = {0};
+ while (*text) {
+ if (*text == '{')
+ bstr_xappend(NULL, &dst, bstr0("\\"));
+ bstr_xappend(NULL, &dst, (bstr){text, 1});
+ // Break ASS escapes with U+2060 WORD JOINER
+ if (*text == '\\')
+ mp_append_utf8_bstr(NULL, &dst, 0x2060);
+ text++;
+ }
+
+ if (!dst.start || !dst.start[0])
+ return;
+
+ int n = ass_alloc_event(track);
+ ASS_Event *event = track->events + n;
+ event->Start = 0;
+ event->Duration = INT_MAX;
+ event->Style = track->default_style;
+ event->Text = strdup(dst.start);
+
+ if (track->default_style < track->n_styles)
+ track->styles[track->default_style].Alignment = ctx->on_top ? 6 : 2;
+}
+
static void fix_events(struct sd *sd)
{
struct sd_ass_priv *ctx = sd->priv;
@@ -395,10 +442,13 @@ static int control(struct sd *sd, enum sd_ctrl cmd, void *arg)
return false;
a[0] = res / 1000.0;
return true;
+ }
case SD_CTRL_SET_VIDEO_PARAMS:
ctx->video_params = *(struct mp_image_params *)arg;
return CONTROL_OK;
- }
+ case SD_CTRL_SET_TOP:
+ ctx->on_top = *(bool *)arg;
+ return CONTROL_OK;
default:
return CONTROL_UNKNOWN;
}