summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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;
}