summaryrefslogtreecommitdiffstats
path: root/sub/osd_libass.c
diff options
context:
space:
mode:
Diffstat (limited to 'sub/osd_libass.c')
-rw-r--r--sub/osd_libass.c138
1 files changed, 106 insertions, 32 deletions
diff --git a/sub/osd_libass.c b/sub/osd_libass.c
index 01c0337eb4..f2de27bd64 100644
--- a/sub/osd_libass.c
+++ b/sub/osd_libass.c
@@ -21,8 +21,6 @@
#include <string.h>
#include <assert.h>
-#include "config.h"
-
#include "mpv_talloc.h"
#include "misc/bstr.h"
#include "common/common.h"
@@ -31,7 +29,7 @@
#include "osd_state.h"
static const char osd_font_pfb[] =
-#include "sub/osd_font.h"
+#include "sub/osd_font.otf.inc"
;
#include "sub/ass_mp.h"
@@ -40,6 +38,9 @@ static const char osd_font_pfb[] =
#define ASS_USE_OSD_FONT "{\\fnmpv-osd-symbols}"
+static void append_ass(struct ass_state *ass, struct mp_osd_res *res,
+ ASS_Image **img_list, bool *changed);
+
void osd_init_backend(struct osd_state *osd)
{
}
@@ -50,7 +51,7 @@ static void create_ass_renderer(struct osd_state *osd, struct ass_state *ass)
return;
ass->log = mp_log_new(NULL, osd->log, "libass");
- ass->library = mp_ass_init(osd->global, ass->log);
+ ass->library = mp_ass_init(osd->global, osd->opts->osd_style, ass->log);
ass_add_font(ass->library, "mpv-osd-symbols", (void *)osd_font_pfb,
sizeof(osd_font_pfb) - 1);
@@ -60,7 +61,7 @@ static void create_ass_renderer(struct osd_state *osd, struct ass_state *ass)
mp_ass_configure_fonts(ass->render, osd->opts->osd_style,
osd->global, ass->log);
- ass_set_aspect_ratio(ass->render, 1.0, 1.0);
+ ass_set_pixel_aspect(ass->render, 1.0);
}
static void destroy_ass_renderer(struct ass_state *ass)
@@ -101,6 +102,8 @@ static void update_playres(struct ass_state *ass, struct mp_osd_res *vo_res)
int old_res_x = track->PlayResX;
int old_res_y = track->PlayResY;
+ ass->vo_res = *vo_res;
+
double aspect = 1.0 * vo_res->w / MPMAX(vo_res->h, 1);
if (vo_res->display_par > 0)
aspect = aspect / vo_res->display_par;
@@ -127,7 +130,10 @@ static void create_ass_track(struct osd_state *osd, struct osd_object *obj,
track->Timer = 100.;
track->WrapStyle = 1; // end-of-line wrapping instead of smart wrapping
track->Kerning = true;
-
+ track->ScaledBorderAndShadow = true;
+#if LIBASS_VERSION >= 0x01600010
+ ass_track_set_feature(track, ASS_FEATURE_WRAP_UNICODE, 1);
+#endif
update_playres(ass, &obj->vo_res);
}
@@ -187,7 +193,7 @@ void osd_get_function_sym(char *buffer, size_t buffer_size, int osd_function)
snprintf(buffer, buffer_size, "\xFF%c", osd_function);
}
-static void mangle_ass(bstr *dst, const char *in)
+void osd_mangle_ass(bstr *dst, const char *in, bool replace_newlines)
{
const char *start = in;
bool escape_ass = true;
@@ -207,6 +213,14 @@ static void mangle_ass(bstr *dst, const char *in)
}
if (escape_ass && *in == '{')
bstr_xappend(NULL, dst, bstr0("\\"));
+ // Replace newlines with \N for escape-ass. This is necessary to apply
+ // ASS tags past newlines and to preserve consecutive newlines with
+ // osd-overlay because update_external() adds a ASS event per line.
+ if (replace_newlines && *in == '\n') {
+ bstr_xappend(NULL, dst, bstr0("\\N"));
+ in += 1;
+ continue;
+ }
// Libass will strip leading whitespace
if (in[0] == ' ' && (in == start || in[-1] == '\n')) {
bstr_xappend(NULL, dst, bstr0("\\h"));
@@ -225,7 +239,7 @@ static ASS_Event *add_osd_ass_event_escaped(ASS_Track *track, const char *style,
const char *text)
{
bstr buf = {0};
- mangle_ass(&buf, text);
+ osd_mangle_ass(&buf, text, false);
ASS_Event *e = add_osd_ass_event(track, style, buf.start);
talloc_free(buf.start);
return e;
@@ -262,12 +276,12 @@ static void update_osd_text(struct osd_state *osd, struct osd_object *obj)
void osd_get_text_size(struct osd_state *osd, int *out_screen_h, int *out_font_h)
{
- pthread_mutex_lock(&osd->lock);
+ mp_mutex_lock(&osd->lock);
struct osd_object *obj = osd->objs[OSDTYPE_OSD];
ASS_Style *style = prepare_osd_ass(osd, obj);
*out_screen_h = obj->ass.track->PlayResY - style->MarginV;
*out_font_h = style->FontSize;
- pthread_mutex_unlock(&osd->lock);
+ mp_mutex_unlock(&osd->lock);
}
// align: -1 .. +1
@@ -361,15 +375,18 @@ static void get_osd_bar_box(struct osd_state *osd, struct osd_object *obj,
mp_ass_set_style(style, track->PlayResY, opts->osd_style);
+ if (osd->opts->osd_style->back_color.a) {
+ // override the default osd opaque-box into plain outline. Otherwise
+ // the opaque box is not aligned with the bar (even without shadow),
+ // and each bar ass event gets its own opaque box - breaking the bar.
+ style->BackColour = MP_ASS_COLOR(opts->osd_style->shadow_color);
+ style->BorderStyle = 1; // outline
+ }
+
*o_w = track->PlayResX * (opts->osd_bar_w / 100.0);
*o_h = track->PlayResY * (opts->osd_bar_h / 100.0);
- float base_size = 0.03125;
- style->Outline *= *o_h / track->PlayResY / base_size;
- // So that the chapter marks have space between them
- style->Outline = MPMIN(style->Outline, *o_h / 5.2);
- // So that the border is not 0
- style->Outline = MPMAX(style->Outline, *o_h / 32.0);
+ style->Outline = opts->osd_bar_border_size;
// Rendering with shadow is broken (because there's more than one shape)
style->Shadow = 0;
@@ -410,6 +427,22 @@ static void update_progbar(struct osd_state *osd, struct osd_object *obj)
talloc_free(buf.start);
struct ass_draw *d = &(struct ass_draw) { .scale = 4 };
+
+ if (osd->opts->osd_style->back_color.a) {
+ // the bar style always ignores the --osd-back-color config - it messes
+ // up the bar. draw an artificial box at the original back color.
+ struct m_color bc = osd->opts->osd_style->back_color;
+ d->text = talloc_asprintf_append(d->text,
+ "{\\pos(%f,%f)\\bord0\\1a&H%02X\\1c&H%02X%02X%02X&}",
+ px, py, 255 - bc.a, (int)bc.b, (int)bc.g, (int)bc.r);
+
+ ass_draw_start(d);
+ ass_draw_rect_cw(d, -border, -border, width + border, height + border);
+ ass_draw_stop(d);
+ add_osd_ass_event(track, "progbar", d->text);
+ ass_draw_reset(d);
+ }
+
// filled area
d->text = talloc_asprintf_append(d->text, "{\\bord0\\pos(%f,%f)}", px, py);
ass_draw_start(d);
@@ -441,7 +474,7 @@ static void update_progbar(struct osd_state *osd, struct osd_object *obj)
// chapter marks
for (int n = 0; n < obj->progbar_state.num_stops; n++) {
float s = obj->progbar_state.stops[n] * width;
- float dent = border * 1.3;
+ float dent = MPMAX(border * 1.3, 1.6);
if (s > dent && s < width - dent) {
ass_draw_move_to(d, s + dent, 0);
@@ -504,7 +537,7 @@ static int cmp_zorder(const void *pa, const void *pb)
void osd_set_external(struct osd_state *osd, struct osd_external_ass *ov)
{
- pthread_mutex_lock(&osd->lock);
+ mp_mutex_lock(&osd->lock);
struct osd_object *obj = osd->objs[OSDTYPE_EXTERNAL];
bool zorder_changed = false;
int index = -1;
@@ -531,11 +564,18 @@ void osd_set_external(struct osd_state *osd, struct osd_external_ass *ov)
struct osd_external *entry = obj->externals[index];
if (!ov->format) {
+ if (!entry->ov.hidden) {
+ obj->changed = true;
+ osd->want_redraw_notification = true;
+ }
destroy_external(entry);
MP_TARRAY_REMOVE_AT(obj->externals, obj->num_externals, index);
+ goto done;
+ }
+
+ if (!entry->ov.hidden || !ov->hidden) {
obj->changed = true;
osd->want_redraw_notification = true;
- goto done;
}
entry->ov.format = ov->format;
@@ -547,24 +587,44 @@ void osd_set_external(struct osd_state *osd, struct osd_external_ass *ov)
entry->ov.res_y = ov->res_y;
zorder_changed |= entry->ov.z != ov->z;
entry->ov.z = ov->z;
+ entry->ov.hidden = ov->hidden;
update_external(osd, obj, entry);
- obj->changed = true;
- osd->want_redraw_notification = true;
-
if (zorder_changed) {
qsort(obj->externals, obj->num_externals, sizeof(obj->externals[0]),
cmp_zorder);
}
+ if (ov->out_rc) {
+ struct mp_osd_res vo_res = entry->ass.vo_res;
+ // Defined fallback if VO has not drawn this yet
+ if (vo_res.w < 1 || vo_res.h < 1) {
+ vo_res = (struct mp_osd_res){
+ .w = entry->ov.res_x,
+ .h = entry->ov.res_y,
+ .display_par = 1,
+ };
+ // According to osd-overlay command description.
+ if (vo_res.w < 1)
+ vo_res.w = 1280;
+ if (vo_res.h < 1)
+ vo_res.h = 720;
+ }
+
+ ASS_Image *img_list = NULL;
+ append_ass(&entry->ass, &vo_res, &img_list, NULL);
+
+ mp_ass_get_bb(img_list, entry->ass.track, &vo_res, ov->out_rc);
+ }
+
done:
- pthread_mutex_unlock(&osd->lock);
+ mp_mutex_unlock(&osd->lock);
}
void osd_set_external_remove_owner(struct osd_state *osd, void *owner)
{
- pthread_mutex_lock(&osd->lock);
+ mp_mutex_lock(&osd->lock);
struct osd_object *obj = osd->objs[OSDTYPE_EXTERNAL];
for (int n = obj->num_externals - 1; n >= 0; n--) {
struct osd_external *e = obj->externals[n];
@@ -575,7 +635,7 @@ void osd_set_external_remove_owner(struct osd_state *osd, void *owner)
osd->want_redraw_notification = true;
}
}
- pthread_mutex_unlock(&osd->lock);
+ mp_mutex_unlock(&osd->lock);
}
static void append_ass(struct ass_state *ass, struct mp_osd_res *res,
@@ -589,15 +649,21 @@ static void append_ass(struct ass_state *ass, struct mp_osd_res *res,
update_playres(ass, res);
ass_set_frame_size(ass->render, res->w, res->h);
- ass_set_aspect_ratio(ass->render, res->display_par, 1.0);
+ ass_set_pixel_aspect(ass->render, res->display_par);
int ass_changed;
*img_list = ass_render_frame(ass->render, ass->track, 0, &ass_changed);
- *changed |= ass_changed;
+
+ ass->changed |= ass_changed;
+
+ if (changed) {
+ *changed |= ass->changed;
+ ass->changed = false;
+ }
}
-void osd_object_get_bitmaps(struct osd_state *osd, struct osd_object *obj,
- int format, struct sub_bitmaps *out_imgs)
+struct sub_bitmaps *osd_object_get_bitmaps(struct osd_state *osd,
+ struct osd_object *obj, int format)
{
if (obj->type == OSDTYPE_OSD && obj->osd_changed)
update_osd(osd, obj);
@@ -609,12 +675,20 @@ void osd_object_get_bitmaps(struct osd_state *osd, struct osd_object *obj,
append_ass(&obj->ass, &obj->vo_res, &obj->ass_imgs[0], &obj->changed);
for (int n = 0; n < obj->num_externals; n++) {
- append_ass(&obj->externals[n]->ass, &obj->vo_res,
- &obj->ass_imgs[n + 1], &obj->changed);
+ if (obj->externals[n]->ov.hidden) {
+ update_playres(&obj->externals[n]->ass, &obj->vo_res);
+ obj->ass_imgs[n + 1] = NULL;
+ } else {
+ append_ass(&obj->externals[n]->ass, &obj->vo_res,
+ &obj->ass_imgs[n + 1], &obj->changed);
+ }
}
+ struct sub_bitmaps out_imgs = {0};
mp_ass_packer_pack(obj->ass_packer, obj->ass_imgs, obj->num_externals + 1,
- obj->changed, format, out_imgs);
+ obj->changed, false, format, &out_imgs);
obj->changed = false;
+
+ return sub_bitmaps_copy(&obj->copy_cache, &out_imgs);
}