diff options
author | Martin Herkt <lachs0r@srsfckn.biz> | 2016-04-11 17:42:55 +0200 |
---|---|---|
committer | Martin Herkt <lachs0r@srsfckn.biz> | 2016-04-11 17:42:55 +0200 |
commit | 0803f4ad21c195519209bae8d18840dd810191f8 (patch) | |
tree | f9a869011ba90c106cf5c05c3e346912a669f63a /sub | |
parent | 9d2980dab752280468620df49cabe7f4843f0551 (diff) | |
parent | b968d779afb9114694976792e903b0591a71a816 (diff) | |
download | mpv-0803f4ad21c195519209bae8d18840dd810191f8.tar.bz2 mpv-0803f4ad21c195519209bae8d18840dd810191f8.tar.xz |
Merge branch 'master' into release/current
Diffstat (limited to 'sub')
-rw-r--r-- | sub/ass_mp.c | 8 | ||||
-rw-r--r-- | sub/ass_mp.h | 2 | ||||
-rw-r--r-- | sub/dec_sub.c | 49 | ||||
-rw-r--r-- | sub/dec_sub.h | 13 | ||||
-rw-r--r-- | sub/lavc_conv.c | 8 | ||||
-rw-r--r-- | sub/osd.c | 100 | ||||
-rw-r--r-- | sub/osd.h | 37 | ||||
-rw-r--r-- | sub/osd_dummy.c | 6 | ||||
-rw-r--r-- | sub/osd_libass.c | 209 | ||||
-rw-r--r-- | sub/osd_state.h | 39 | ||||
-rw-r--r-- | sub/sd.h | 6 | ||||
-rw-r--r-- | sub/sd_ass.c | 40 | ||||
-rw-r--r-- | sub/sd_lavc.c | 30 |
13 files changed, 324 insertions, 223 deletions
diff --git a/sub/ass_mp.c b/sub/ass_mp.c index 8d40b5256a..2f9b39740f 100644 --- a/sub/ass_mp.c +++ b/sub/ass_mp.c @@ -22,6 +22,7 @@ #include <stdlib.h> #include <stdarg.h> #include <stdbool.h> +#include <assert.h> #include <ass/ass.h> #include <ass/ass_types.h> @@ -76,6 +77,7 @@ void mp_ass_set_style(ASS_Style *style, double res_y, style->Alignment = 1 + (opts->align_x + 1) + (opts->align_y + 2) % 3 * 4; style->Blur = opts->blur; style->Bold = opts->bold; + style->Italic = opts->italic; } void mp_ass_configure_fonts(ASS_Renderer *priv, struct osd_style_opts *opts, @@ -96,16 +98,15 @@ void mp_ass_configure_fonts(ASS_Renderer *priv, struct osd_style_opts *opts, } void mp_ass_render_frame(ASS_Renderer *renderer, ASS_Track *track, double time, - struct sub_bitmap **parts, struct sub_bitmaps *res) + struct sub_bitmaps *res) { int changed; ASS_Image *imgs = ass_render_frame(renderer, track, time, &changed); if (changed) res->change_id++; + assert(res->format == 0 || res->format == SUBBITMAP_LIBASS); res->format = SUBBITMAP_LIBASS; - res->parts = *parts; - res->num_parts = 0; int num_parts_alloc = MP_TALLOC_AVAIL(res->parts); for (struct ass_image *img = imgs; img; img = img->next) { if (img->w == 0 || img->h == 0) @@ -125,7 +126,6 @@ void mp_ass_render_frame(ASS_Renderer *renderer, ASS_Track *track, double time, p->y = img->dst_y; res->num_parts++; } - *parts = res->parts; } static const int map_ass_level[] = { diff --git a/sub/ass_mp.h b/sub/ass_mp.h index 789a53acb1..b4cae24ddc 100644 --- a/sub/ass_mp.h +++ b/sub/ass_mp.h @@ -55,7 +55,7 @@ ASS_Library *mp_ass_init(struct mpv_global *global, struct mp_log *log); struct sub_bitmap; struct sub_bitmaps; void mp_ass_render_frame(ASS_Renderer *renderer, ASS_Track *track, double time, - struct sub_bitmap **parts, struct sub_bitmaps *res); + struct sub_bitmaps *res); #endif /* HAVE_LIBASS */ #endif /* MPLAYER_ASS_MP_H */ diff --git a/sub/dec_sub.c b/sub/dec_sub.c index 75f5509c62..3b1e957038 100644 --- a/sub/dec_sub.c +++ b/sub/dec_sub.c @@ -49,10 +49,11 @@ struct dec_sub { struct mpv_global *global; struct MPOpts *opts; - struct demuxer *demuxer; + struct attachment_list *attachments; struct sh_stream *sh; double last_pkt_pts; + bool preload_attempted; struct mp_codec_params *codec; double start, end; @@ -94,8 +95,9 @@ static struct sd *init_decoder(struct dec_sub *sub) .log = mp_log_new(sd, sub->log, driver->name), .opts = sub->opts, .driver = driver, - .demuxer = sub->demuxer, + .attachments = sub->attachments, .codec = sub->codec, + .preload_ok = true, }; if (sd->driver->init(sd) >= 0) @@ -112,10 +114,12 @@ static struct sd *init_decoder(struct dec_sub *sub) // Thread-safety of the returned object: all functions are thread-safe, // except sub_get_bitmaps() and sub_get_text(). Decoder backends (sd_*) // do not need to acquire locks. -struct dec_sub *sub_create(struct mpv_global *global, struct demuxer *demuxer, - struct sh_stream *sh) +// Ownership of attachments goes to the caller, and is released with +// talloc_free() (even on failure). +struct dec_sub *sub_create(struct mpv_global *global, struct sh_stream *sh, + struct attachment_list *attachments) { - assert(demuxer && sh && sh->type == STREAM_SUB); + assert(sh && sh->type == STREAM_SUB); struct dec_sub *sub = talloc(NULL, struct dec_sub); *sub = (struct dec_sub){ @@ -124,7 +128,7 @@ struct dec_sub *sub_create(struct mpv_global *global, struct demuxer *demuxer, .opts = global->opts, .sh = sh, .codec = sh->codec, - .demuxer = demuxer, + .attachments = talloc_steal(sub, attachments), .last_pkt_pts = MP_NOPTS_VALUE, .last_vo_pts = MP_NOPTS_VALUE, .start = MP_NOPTS_VALUE, @@ -146,6 +150,9 @@ static void update_segment(struct dec_sub *sub) if (sub->new_segment && sub->last_vo_pts != MP_NOPTS_VALUE && sub->last_vo_pts >= sub->new_segment->start) { + MP_VERBOSE(sub, "Switch segment: %f at %f\n", sub->new_segment->start, + sub->last_vo_pts); + sub->codec = sub->new_segment->codec; sub->start = sub->new_segment->start; sub->end = sub->new_segment->end; @@ -165,16 +172,20 @@ static void update_segment(struct dec_sub *sub) } } -// Read all packets from the demuxer and decode/add them. Returns false if -// there are circumstances which makes this not possible. -bool sub_read_all_packets(struct dec_sub *sub) +bool sub_can_preload(struct dec_sub *sub) { + bool r; pthread_mutex_lock(&sub->lock); + r = sub->sd->driver->accept_packets_in_advance && !sub->preload_attempted; + pthread_mutex_unlock(&sub->lock); + return r; +} - if (!sub->sd->driver->accept_packets_in_advance) { - pthread_mutex_unlock(&sub->lock); - return false; - } +void sub_preload(struct dec_sub *sub) +{ + pthread_mutex_lock(&sub->lock); + + sub->preload_attempted = true; for (;;) { struct demux_packet *pkt = demux_read_packet(sub->sh); @@ -185,7 +196,6 @@ bool sub_read_all_packets(struct dec_sub *sub) } pthread_mutex_unlock(&sub->lock); - return true; } // Read packets from the demuxer stream passed to sub_create(). Return true if @@ -203,6 +213,11 @@ bool sub_read_packets(struct dec_sub *sub, double video_pts) if (!read_more) break; + if (sub->new_segment && sub->new_segment->start < video_pts) { + sub->last_vo_pts = video_pts; + update_segment(sub); + } + if (sub->new_segment) break; @@ -228,7 +243,9 @@ bool sub_read_packets(struct dec_sub *sub, double video_pts) break; } - sub->sd->driver->decode(sub->sd, pkt); + if (!(sub->preload_attempted && sub->sd->preload_ok)) + sub->sd->driver->decode(sub->sd, pkt); + talloc_free(pkt); } pthread_mutex_unlock(&sub->lock); @@ -243,8 +260,6 @@ void sub_get_bitmaps(struct dec_sub *sub, struct mp_osd_res dim, double pts, { struct MPOpts *opts = sub->opts; - *res = (struct sub_bitmaps) {0}; - sub->last_vo_pts = pts; update_segment(sub); diff --git a/sub/dec_sub.h b/sub/dec_sub.h index b3f30520e3..63603e2174 100644 --- a/sub/dec_sub.h +++ b/sub/dec_sub.h @@ -6,7 +6,6 @@ #include "osd.h" -struct demuxer; struct sh_stream; struct mpv_global; struct demux_packet; @@ -22,13 +21,19 @@ enum sd_ctrl { SD_CTRL_SET_VIDEO_DEF_FPS, }; -struct dec_sub *sub_create(struct mpv_global *global, struct demuxer *demuxer, - struct sh_stream *sh); +struct attachment_list { + struct demux_attachment *entries; + int num_entries; +}; + +struct dec_sub *sub_create(struct mpv_global *global, struct sh_stream *sh, + struct attachment_list *attachments); void sub_destroy(struct dec_sub *sub); void sub_lock(struct dec_sub *sub); void sub_unlock(struct dec_sub *sub); -bool sub_read_all_packets(struct dec_sub *sub); +bool sub_can_preload(struct dec_sub *sub); +void sub_preload(struct dec_sub *sub); bool sub_read_packets(struct dec_sub *sub, double video_pts); void sub_get_bitmaps(struct dec_sub *sub, struct mp_osd_res dim, double pts, struct sub_bitmaps *res); diff --git a/sub/lavc_conv.c b/sub/lavc_conv.c index 3dd6097d0f..3e0165a84c 100644 --- a/sub/lavc_conv.c +++ b/sub/lavc_conv.c @@ -47,6 +47,9 @@ static const char *get_lavc_format(const char *format) // For the hack involving parse_webvtt(). if (format && strcmp(format, "webvtt-webm") == 0) format = "webvtt"; + // Most text subtitles are srt/html style anyway. + if (format && strcmp(format, "text") == 0) + format = "subrip"; return format; } @@ -79,11 +82,8 @@ struct lavc_conv *lavc_conv_create(struct mp_log *log, const char *codec_name, avctx = avcodec_alloc_context3(codec); if (!avctx) goto error; - avctx->extradata_size = extradata_len; - avctx->extradata = av_malloc(extradata_len); - if (!avctx->extradata) + if (mp_lavc_set_extradata(avctx, extradata, extradata_len) < 0) goto error; - memcpy(avctx->extradata, extradata, extradata_len); if (strcmp(codec_name, "eia_608") == 0) av_dict_set(&opts, "real_time", "1", 0); if (avcodec_open2(avctx, codec, &opts) < 0) @@ -61,6 +61,7 @@ static const m_option_t style_opts[] = { ({"top", -1}, {"center", 0}, {"bottom", +1})), OPT_FLOATRANGE("blur", blur, 0, 0, 20), OPT_FLAG("bold", bold, 0), + OPT_FLAG("italic", italic, 0), {0} }; @@ -109,6 +110,8 @@ static bool osd_res_equals(struct mp_osd_res a, struct mp_osd_res b) struct osd_state *osd_create(struct mpv_global *global) { + assert(MAX_OSD_PARTS >= OSDTYPE_COUNT); + struct osd_state *osd = talloc_zero(NULL, struct osd_state); *osd = (struct osd_state) { .opts = global->opts, @@ -145,30 +148,31 @@ void osd_free(struct osd_state *osd) talloc_free(osd); } -static void osd_changed_unlocked(struct osd_state *osd, int obj) +void osd_changed_unlocked(struct osd_state *osd, int obj) { osd->objs[obj]->force_redraw = true; osd->want_redraw = true; } -void osd_set_text(struct osd_state *osd, int obj, const char *text) +void osd_set_text(struct osd_state *osd, const char *text) { pthread_mutex_lock(&osd->lock); - struct osd_object *osd_obj = osd->objs[obj]; + struct osd_object *osd_obj = osd->objs[OSDTYPE_OSD]; if (!text) text = ""; if (strcmp(osd_obj->text, text) != 0) { talloc_free(osd_obj->text); osd_obj->text = talloc_strdup(osd_obj, text); - osd_changed_unlocked(osd, obj); + osd_changed_unlocked(osd, osd_obj->type); } pthread_mutex_unlock(&osd->lock); } -void osd_set_sub(struct osd_state *osd, int obj, struct dec_sub *dec_sub) +void osd_set_sub(struct osd_state *osd, int index, struct dec_sub *dec_sub) { pthread_mutex_lock(&osd->lock); - osd->objs[obj]->sub = dec_sub; + if (index >= 0 && index < 2) + osd->objs[OSDTYPE_SUB + index]->sub = dec_sub; pthread_mutex_unlock(&osd->lock); } @@ -201,28 +205,38 @@ void osd_set_progbar(struct osd_state *osd, struct osd_progbar_state *s) pthread_mutex_unlock(&osd->lock); } -void osd_set_external(struct osd_state *osd, int res_x, int res_y, char *text) +void osd_set_external2(struct osd_state *osd, struct sub_bitmaps *imgs) { pthread_mutex_lock(&osd->lock); - struct osd_object *osd_obj = osd->objs[OSDTYPE_EXTERNAL]; - if (strcmp(osd_obj->text, text) != 0 || - osd_obj->external_res_x != res_x || - osd_obj->external_res_y != res_y) - { - talloc_free(osd_obj->text); - osd_obj->text = talloc_strdup(osd_obj, text); - osd_obj->external_res_x = res_x; - osd_obj->external_res_y = res_y; - osd_changed_unlocked(osd, osd_obj->type); - } + osd->objs[OSDTYPE_EXTERNAL2]->external2 = imgs; + osd_changed_unlocked(osd, OSDTYPE_EXTERNAL2); pthread_mutex_unlock(&osd->lock); } -void osd_set_external2(struct osd_state *osd, struct sub_bitmaps *imgs) +static void check_obj_resize(struct osd_state *osd, struct mp_osd_res res, + struct osd_object *obj) +{ + if (!osd_res_equals(res, obj->vo_res)) { + obj->vo_res = res; + obj->force_redraw = true; + mp_client_broadcast_event(mp_client_api_get_core(osd->global->client_api), + MP_EVENT_WIN_RESIZE, NULL); + } +} + +// Optional. Can be called for faster reaction of OSD-generating scripts like +// osc.lua. This can achieve that the resize happens first, so that the OSD is +// generated at the correct resolution the first time the resized frame is +// rendered. Since the OSD doesn't (and can't) wait for the script, this +// increases the time in which the script can react, and also gets rid of the +// unavoidable redraw delay (though it will still be racy). +// Unnecessary for anything else. +void osd_resize(struct osd_state *osd, struct mp_osd_res res) { pthread_mutex_lock(&osd->lock); - osd->objs[OSDTYPE_EXTERNAL2]->external2 = imgs; - osd_changed_unlocked(osd, OSDTYPE_EXTERNAL2); + int types[] = {OSDTYPE_OSD, OSDTYPE_EXTERNAL, OSDTYPE_EXTERNAL2, -1}; + for (int n = 0; types[n] >= 0; n++) + check_obj_resize(osd, res, osd->objs[types[n]]); pthread_mutex_unlock(&osd->lock); } @@ -240,12 +254,7 @@ static void render_object(struct osd_state *osd, struct osd_object *obj, *out_imgs = (struct sub_bitmaps) {0}; - if (!osd_res_equals(res, obj->vo_res)) { - obj->vo_res = res; - obj->force_redraw = true; - mp_client_broadcast_event(mp_client_api_get_core(osd->global->client_api), - MP_EVENT_WIN_RESIZE, NULL); - } + check_obj_resize(osd, res, obj); if (obj->type == OSDTYPE_SUB || obj->type == OSDTYPE_SUB2) { if (obj->sub) { @@ -422,44 +431,11 @@ bool osd_query_and_reset_want_redraw(struct osd_state *osd) return r; } -// Scale factor to translate OSD coordinates to what the obj uses internally. -// osd_coordinates * (sw, sh) = obj_coordinates -void osd_object_get_scale_factor(struct osd_state *osd, int obj, - double *sw, double *sh) -{ - int nw, nh; - osd_object_get_resolution(osd, obj, &nw, &nh); - pthread_mutex_lock(&osd->lock); - int vow = osd->objs[obj]->vo_res.w; - int voh = osd->objs[obj]->vo_res.h; - pthread_mutex_unlock(&osd->lock); - *sw = vow ? nw / (double)vow : 0; - *sh = voh ? nh / (double)voh : 0; -} - -// Turn *x and *y, which are given in OSD coordinates, to video coordinates. -// frame_w and frame_h give the dimensions of the original, unscaled video. -// (This gives correct results only after the OSD has been updated after a -// resize or video reconfig.) -void osd_coords_to_video(struct osd_state *osd, int frame_w, int frame_h, - int *x, int *y) +struct mp_osd_res osd_get_vo_res(struct osd_state *osd) { pthread_mutex_lock(&osd->lock); + // Any OSDTYPE is fine; but it mustn't be a subtitle one (can have lower res.) struct mp_osd_res res = osd->objs[OSDTYPE_OSD]->vo_res; - int vidw = res.w - res.ml - res.mr; - int vidh = res.h - res.mt - res.mb; - double xscale = (double)vidw / frame_w; - double yscale = (double)vidh / frame_h; - // The OSD size + margins make up the scaled rectangle of the video. - *x = (*x - res.ml) / xscale; - *y = (*y - res.mt) / yscale; - pthread_mutex_unlock(&osd->lock); -} - -struct mp_osd_res osd_get_vo_res(struct osd_state *osd, int obj) -{ - pthread_mutex_lock(&osd->lock); - struct mp_osd_res res = osd->objs[obj]->vo_res; pthread_mutex_unlock(&osd->lock); return res; } @@ -78,17 +78,8 @@ struct mp_osd_res { double display_par; }; -enum mp_osdtype { - OSDTYPE_SUB, - OSDTYPE_SUB2, // IDs must be numerically successive - - OSDTYPE_OSD, - - OSDTYPE_EXTERNAL, - OSDTYPE_EXTERNAL2, - - MAX_OSD_PARTS -}; +// 0 <= sub_bitmaps.render_index < MAX_OSD_PARTS +#define MAX_OSD_PARTS 5 // Start of OSD symbols in osd_font.pfb #define OSD_CODEPOINTS 0xE000 @@ -132,6 +123,7 @@ struct osd_style_opts { int align_y; float blur; int bold; + int italic; }; extern const struct m_sub_options osd_style_conf; @@ -149,8 +141,8 @@ 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); -void osd_set_sub(struct osd_state *osd, int obj, struct dec_sub *dec_sub); +void osd_set_text(struct osd_state *osd, const char *text); +void osd_set_sub(struct osd_state *osd, int index, 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); @@ -163,8 +155,6 @@ struct osd_progbar_state { }; void osd_set_progbar(struct osd_state *osd, struct osd_progbar_state *s); -void osd_set_external(struct osd_state *osd, int res_x, int res_y, char *text); - void osd_set_external2(struct osd_state *osd, struct sub_bitmaps *imgs); enum mp_osd_draw_flags { @@ -187,16 +177,12 @@ void osd_draw_on_image_p(struct osd_state *osd, struct mp_osd_res res, double video_pts, int draw_flags, struct mp_image_pool *pool, struct mp_image *dest); +void osd_resize(struct osd_state *osd, struct mp_osd_res res); + struct mp_image_params; struct mp_osd_res osd_res_from_image_params(const struct mp_image_params *p); -void osd_object_get_scale_factor(struct osd_state *osd, int obj, - double *sw, double *sh); - -void osd_coords_to_video(struct osd_state *osd, int frame_w, int frame_h, - int *x, int *y); - -struct mp_osd_res osd_get_vo_res(struct osd_state *osd, int obj); +struct mp_osd_res osd_get_vo_res(struct osd_state *osd); void osd_rescale_bitmaps(struct sub_bitmaps *imgs, int frame_w, int frame_h, struct mp_osd_res res, double compensate_par); @@ -209,13 +195,12 @@ void osd_object_get_bitmaps(struct osd_state *osd, struct osd_object *obj, void osd_init_backend(struct osd_state *osd); void osd_destroy_backend(struct osd_state *osd); +void osd_set_external(struct osd_state *osd, void *id, int res_x, int res_y, + char *text); + // doesn't need locking void osd_get_function_sym(char *buffer, size_t buffer_size, int osd_function); extern const char *const osd_ass_0; extern const char *const osd_ass_1; -// defined in backend, but locks if required -void osd_object_get_resolution(struct osd_state *osd, int obj, - int *out_w, int *out_h); - #endif /* MPLAYER_SUB_H */ diff --git a/sub/osd_dummy.c b/sub/osd_dummy.c index 5c50569dd6..5c3cc76200 100644 --- a/sub/osd_dummy.c +++ b/sub/osd_dummy.c @@ -27,9 +27,7 @@ void osd_object_get_bitmaps(struct osd_state *osd, struct osd_object *obj, *out_imgs = (struct sub_bitmaps) {0}; } -void osd_object_get_resolution(struct osd_state *osd, int obj, - int *out_w, int *out_h) +void osd_set_external(struct osd_state *osd, void *id, int res_x, int res_y, + char *text) { - *out_w = 0; - *out_h = 0; } diff --git a/sub/osd_libass.c b/sub/osd_libass.c index eed2822380..30d404d8c6 100644 --- a/sub/osd_libass.c +++ b/sub/osd_libass.c @@ -45,49 +45,66 @@ void osd_init_backend(struct osd_state *osd) { } -static void create_ass_renderer(struct osd_state *osd, struct osd_object *obj) +static void create_ass_renderer(struct osd_state *osd, struct ass_state *ass) { - if (obj->osd_render) + if (ass->render) return; - struct mp_log *ass_log = mp_log_new(obj, osd->log, "libass"); - obj->osd_ass_library = mp_ass_init(osd->global, ass_log); - ass_add_font(obj->osd_ass_library, "mpv-osd-symbols", (void *)osd_font_pfb, + ass->log = mp_log_new(NULL, osd->log, "libass"); + ass->library = mp_ass_init(osd->global, ass->log); + ass_add_font(ass->library, "mpv-osd-symbols", (void *)osd_font_pfb, sizeof(osd_font_pfb) - 1); - obj->osd_render = ass_renderer_init(obj->osd_ass_library); - if (!obj->osd_render) + ass->render = ass_renderer_init(ass->library); + if (!ass->render) abort(); - mp_ass_configure_fonts(obj->osd_render, osd->opts->osd_style, - osd->global, ass_log); - ass_set_aspect_ratio(obj->osd_render, 1.0, 1.0); + mp_ass_configure_fonts(ass->render, osd->opts->osd_style, + osd->global, ass->log); + ass_set_aspect_ratio(ass->render, 1.0, 1.0); +} + +static void destroy_ass_renderer(struct ass_state *ass) +{ + if (ass->track) + ass_free_track(ass->track); + ass->track = NULL; + if (ass->render) + ass_renderer_done(ass->render); + ass->render = NULL; + if (ass->library) + ass_library_done(ass->library); + ass->library = NULL; + talloc_free(ass->log); + ass->log = NULL; +} + +static void destroy_external(struct osd_external *ext) +{ + talloc_free(ext->text); + destroy_ass_renderer(&ext->ass); } void osd_destroy_backend(struct osd_state *osd) { for (int n = 0; n < MAX_OSD_PARTS; n++) { struct osd_object *obj = osd->objs[n]; - if (obj->osd_track) - ass_free_track(obj->osd_track); - obj->osd_track = NULL; - if (obj->osd_render) - ass_renderer_done(obj->osd_render); - obj->osd_render = NULL; - if (obj->osd_ass_library) - ass_library_done(obj->osd_ass_library); - obj->osd_ass_library = NULL; + destroy_ass_renderer(&obj->ass); + talloc_free(obj->parts_cache.parts); + for (int i = 0; i < obj->num_externals; i++) + destroy_external(&obj->externals[i]); + obj->num_externals = 0; } } static void create_ass_track(struct osd_state *osd, struct osd_object *obj, - int res_x, int res_y) + struct ass_state *ass, int res_x, int res_y) { - create_ass_renderer(osd, obj); + create_ass_renderer(osd, ass); - ASS_Track *track = obj->osd_track; + ASS_Track *track = ass->track; if (!track) - track = ass_new_track(obj->osd_ass_library); + track = ass_new_track(ass->library); int old_res_x = track->PlayResX; int old_res_y = track->PlayResY; @@ -105,9 +122,9 @@ static void create_ass_track(struct osd_state *osd, struct osd_object *obj, // Force libass to clear its internal cache - it doesn't check for // PlayRes changes itself. if (old_res_x != track->PlayResX || old_res_y != track->PlayResY) - ass_set_frame_size(obj->osd_render, 1, 1); + ass_set_frame_size(ass->render, 1, 1); - obj->osd_track = track; + ass->track = track; } static int find_style(ASS_Track *track, const char *name, int def) @@ -120,10 +137,9 @@ static int find_style(ASS_Track *track, const char *name, int def) } // Find a given style, or add it if it's missing. -static ASS_Style *get_style(struct osd_state *osd, struct osd_object *obj, - char *name) +static ASS_Style *get_style(struct ass_state *ass, char *name) { - ASS_Track *track = obj->osd_track; + ASS_Track *track = ass->track; if (!track) return NULL; @@ -154,10 +170,10 @@ static ASS_Event *add_osd_ass_event(ASS_Track *track, const char *style, return event; } -static void clear_obj(struct osd_object *obj) +static void clear_ass(struct ass_state *ass) { - if (obj->osd_track) - ass_flush_events(obj->osd_track); + if (ass->track) + ass_flush_events(ass->track); } void osd_get_function_sym(char *buffer, size_t buffer_size, int osd_function) @@ -214,18 +230,18 @@ static void update_osd_text(struct osd_state *osd, struct osd_object *obj) if (!obj->text[0]) return; - create_ass_track(osd, obj, 0, 0); + create_ass_track(osd, obj, &obj->ass, 0, 0); struct osd_style_opts font = *opts->osd_style; font.font_size *= opts->osd_scale; - double playresy = obj->osd_track->PlayResY; + double playresy = obj->ass.track->PlayResY; // Compensate for libass and mp_ass_set_style scaling the font etc. if (!opts->osd_scale_by_window) playresy *= 720.0 / obj->vo_res.h; - mp_ass_set_style(get_style(osd, obj, "OSD"), playresy, &font); - add_osd_ass_event_escaped(obj->osd_track, "OSD", obj->text); + mp_ass_set_style(get_style(&obj->ass, "OSD"), playresy, &font); + add_osd_ass_event_escaped(obj->ass.track, "OSD", obj->text); } // align: -1 .. +1 @@ -308,10 +324,10 @@ static void get_osd_bar_box(struct osd_state *osd, struct osd_object *obj, { struct MPOpts *opts = osd->opts; - create_ass_track(osd, obj, 0, 0); - ASS_Track *track = obj->osd_track; + create_ass_track(osd, obj, &obj->ass, 0, 0); + ASS_Track *track = obj->ass.track; - ASS_Style *style = get_style(osd, obj, "progbar"); + ASS_Style *style = get_style(&obj->ass, "progbar"); if (!style) { *o_x = *o_y = *o_w = *o_h = *o_border = 0; return; @@ -347,6 +363,8 @@ static void update_progbar(struct osd_state *osd, struct osd_object *obj) float px, py, width, height, border; get_osd_bar_box(osd, obj, &px, &py, &width, &height, &border); + ASS_Track *track = obj->ass.track; + float sx = px - border * 2 - height / 4; // includes additional spacing float sy = py + height / 2; @@ -362,7 +380,7 @@ static void update_progbar(struct osd_state *osd, struct osd_object *obj) bstr_xappend(NULL, &buf, bstr0("{\\r}")); } - add_osd_ass_event(obj->osd_track, "progbar", buf.start); + add_osd_ass_event(track, "progbar", buf.start); talloc_free(buf.start); struct ass_draw *d = &(struct ass_draw) { .scale = 4 }; @@ -372,7 +390,7 @@ static void update_progbar(struct osd_state *osd, struct osd_object *obj) float pos = obj->progbar_state.value * width - border / 2; ass_draw_rect_cw(d, 0, 0, pos, height); ass_draw_stop(d); - add_osd_ass_event(obj->osd_track, "progbar", d->text); + add_osd_ass_event(track, "progbar", d->text); ass_draw_reset(d); // position marker @@ -382,7 +400,7 @@ static void update_progbar(struct osd_state *osd, struct osd_object *obj) ass_draw_move_to(d, pos + border / 2, 0); ass_draw_line_to(d, pos + border / 2, height); ass_draw_stop(d); - add_osd_ass_event(obj->osd_track, "progbar", d->text); + add_osd_ass_event(track, "progbar", d->text); ass_draw_reset(d); d->text = talloc_asprintf_append(d->text, "{\\pos(%f,%f)}", px, py); @@ -411,79 +429,112 @@ static void update_progbar(struct osd_state *osd, struct osd_object *obj) } ass_draw_stop(d); - add_osd_ass_event(obj->osd_track, "progbar", d->text); + add_osd_ass_event(track, "progbar", d->text); ass_draw_reset(d); } static void update_osd(struct osd_state *osd, struct osd_object *obj) { - clear_obj(obj); + clear_ass(&obj->ass); update_osd_text(osd, obj); update_progbar(osd, obj); } -static void update_external(struct osd_state *osd, struct osd_object *obj) +static void update_external(struct osd_state *osd, struct osd_object *obj, + struct osd_external *ext) { - clear_obj(obj); - - bstr t = bstr0(obj->text); + bstr t = bstr0(ext->text); if (!t.len) return; - create_ass_track(osd, obj, obj->external_res_x, obj->external_res_y); + create_ass_track(osd, obj, &ext->ass, ext->res_x, ext->res_y); - int resy = obj->osd_track->PlayResY; - mp_ass_set_style(get_style(osd, obj, "OSD"), resy, osd->opts->osd_style); + clear_ass(&ext->ass); + + int resy = ext->ass.track->PlayResY; + mp_ass_set_style(get_style(&ext->ass, "OSD"), resy, osd->opts->osd_style); // Some scripts will reference this style name with \r tags. const struct osd_style_opts *def = osd_style_conf.defaults; - mp_ass_set_style(get_style(osd, obj, "Default"), resy, def); + mp_ass_set_style(get_style(&ext->ass, "Default"), resy, def); while (t.len) { bstr line; bstr_split_tok(t, "\n", &line, &t); if (line.len) { char *tmp = bstrdup0(NULL, line); - add_osd_ass_event(obj->osd_track, "OSD", tmp); + add_osd_ass_event(ext->ass.track, "OSD", tmp); talloc_free(tmp); } } } -static void update_object(struct osd_state *osd, struct osd_object *obj) +void osd_set_external(struct osd_state *osd, void *id, int res_x, int res_y, + char *text) { - switch (obj->type) { - case OSDTYPE_OSD: - update_osd(osd, obj); - break; - case OSDTYPE_EXTERNAL: - update_external(osd, obj); - break; + pthread_mutex_lock(&osd->lock); + struct osd_object *obj = osd->objs[OSDTYPE_EXTERNAL]; + struct osd_external *entry = 0; + for (int n = 0; n < obj->num_externals; n++) { + if (obj->externals[n].id == id) { + entry = &obj->externals[n]; + break; + } + } + if (!entry && !text) + goto done; + + if (!entry) { + struct osd_external new = { .id = id }; + MP_TARRAY_APPEND(obj, obj->externals, obj->num_externals, new); + entry = &obj->externals[obj->num_externals - 1]; + } + + if (!text) { + int index = entry - &obj->externals[0]; + destroy_external(entry); + MP_TARRAY_REMOVE_AT(obj->externals, obj->num_externals, index); + goto done; } + + if (!entry->text || strcmp(entry->text, text) != 0 || + entry->res_x != res_x || entry->res_y != res_y) + { + talloc_free(entry->text); + entry->text = talloc_strdup(NULL, text); + entry->res_x = res_x; + entry->res_y = res_y; + update_external(osd, obj, entry); + obj->parts_cache.change_id = 1; + osd_changed_unlocked(osd, obj->type); + } + +done: + pthread_mutex_unlock(&osd->lock); } -void osd_object_get_bitmaps(struct osd_state *osd, struct osd_object *obj, - struct sub_bitmaps *out_imgs) +static void append_ass(struct ass_state *ass, struct mp_osd_res *res, + struct sub_bitmaps *imgs) { - if (obj->force_redraw) - update_object(osd, obj); - - *out_imgs = (struct sub_bitmaps) {0}; - if (!obj->osd_track) + if (!ass->render || !ass->track) return; - ass_set_frame_size(obj->osd_render, obj->vo_res.w, obj->vo_res.h); |