summaryrefslogtreecommitdiffstats
path: root/sub
diff options
context:
space:
mode:
authorMartin Herkt <lachs0r@srsfckn.biz>2016-04-11 17:42:55 +0200
committerMartin Herkt <lachs0r@srsfckn.biz>2016-04-11 17:42:55 +0200
commit0803f4ad21c195519209bae8d18840dd810191f8 (patch)
treef9a869011ba90c106cf5c05c3e346912a669f63a /sub
parent9d2980dab752280468620df49cabe7f4843f0551 (diff)
parentb968d779afb9114694976792e903b0591a71a816 (diff)
downloadmpv-0803f4ad21c195519209bae8d18840dd810191f8.tar.bz2
mpv-0803f4ad21c195519209bae8d18840dd810191f8.tar.xz
Merge branch 'master' into release/current
Diffstat (limited to 'sub')
-rw-r--r--sub/ass_mp.c8
-rw-r--r--sub/ass_mp.h2
-rw-r--r--sub/dec_sub.c49
-rw-r--r--sub/dec_sub.h13
-rw-r--r--sub/lavc_conv.c8
-rw-r--r--sub/osd.c100
-rw-r--r--sub/osd.h37
-rw-r--r--sub/osd_dummy.c6
-rw-r--r--sub/osd_libass.c209
-rw-r--r--sub/osd_state.h39
-rw-r--r--sub/sd.h6
-rw-r--r--sub/sd_ass.c40
-rw-r--r--sub/sd_lavc.c30
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)
diff --git a/sub/osd.c b/sub/osd.c
index fd821923e5..4e269ce5aa 100644
--- a/sub/osd.c
+++ b/sub/osd.c
@@ -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;
}
diff --git a/sub/osd.h b/sub/osd.h
index b41a2eec7a..550b31e5a7 100644
--- a/sub/osd.h
+++ b/sub/osd.h
@@ -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);