diff options
-rw-r--r-- | player/command.c | 7 | ||||
-rw-r--r-- | player/core.h | 4 | ||||
-rw-r--r-- | player/osd.c | 11 | ||||
-rw-r--r-- | player/sub.c | 53 | ||||
-rw-r--r-- | sub/dec_sub.h | 1 | ||||
-rw-r--r-- | sub/osd.c | 19 | ||||
-rw-r--r-- | sub/osd.h | 10 | ||||
-rw-r--r-- | sub/osd_libass.c | 30 | ||||
-rw-r--r-- | sub/osd_state.h | 2 | ||||
-rw-r--r-- | sub/sd_ass.c | 80 |
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, ¶ms); } - 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); @@ -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); @@ -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; } |