diff options
Diffstat (limited to 'sub/osd_libass.c')
-rw-r--r-- | sub/osd_libass.c | 234 |
1 files changed, 74 insertions, 160 deletions
diff --git a/sub/osd_libass.c b/sub/osd_libass.c index 29450535bc..11173dad7a 100644 --- a/sub/osd_libass.c +++ b/sub/osd_libass.c @@ -35,9 +35,6 @@ static const char osd_font_pfb[] = #include "mp_core.h" -// Map OSD symbols (e.g. OSD_PLAY) to the glyphs in osd_font_pfb[]. -#define OSD_CODEPOINTS 0xE000 - // NOTE: \fs-5 to reduce the size of the symbols in relation to normal text. // Done because libass doesn't center characters that are too high. #define ASS_USE_OSD_FONT "{\\fnOSD\\fs-5}" @@ -55,133 +52,20 @@ void osd_init_backend(struct osd_state *osd) void osd_destroy_backend(struct osd_state *osd) { - if (osd) { - if (osd->osd_render) - ass_renderer_done(osd->osd_render); - osd->osd_render = NULL; - ass_library_done(osd->osd_ass_library); - osd->osd_ass_library = NULL; - } -} - -static void eosd_draw_alpha_a8i8(unsigned char *src, - int src_w, int src_h, - int src_stride, - unsigned char *dst_a, - unsigned char *dst_i, - size_t dst_stride, - int dst_x, int dst_y, - uint32_t color) -{ - const unsigned int r = (color >> 24) & 0xff; - const unsigned int g = (color >> 16) & 0xff; - const unsigned int b = (color >> 8) & 0xff; - const unsigned int a = 0xff - (color & 0xff); - - int gray = (r + g + b) / 3; // not correct - - dst_a += dst_y * dst_stride + dst_x; - dst_i += dst_y * dst_stride + dst_x; - - int src_skip = src_stride - src_w; - int dst_skip = dst_stride - src_w; - - for (int y = 0; y < src_h; y++) { - for (int x = 0; x < src_w; x++) { - unsigned char as = (*src * a) >> 8; - unsigned char bs = (gray * as) >> 8; - // to mplayer scale - as = -as; - - unsigned char *a = dst_a; - unsigned char *b = dst_i; - - // NOTE: many special cases, because alpha=0 means transparency, - // while alpha=1..255 is opaque..transparent - if (as) { - *b = ((*b * as) >> 8) + bs; - if (*a) { - *a = (*a * as) >> 8; - if (*a < 1) - *a = 1; - } else { - *a = as; - } - } - - dst_a++; - dst_i++; - src++; - } - dst_a += dst_skip; - dst_i += dst_skip; - src += src_skip; - } -} - -static void eosd_render_a8i8(unsigned char *a, unsigned char *i, size_t stride, - int x, int y, ASS_Image *imgs) -{ - for (ASS_Image *p = imgs; p; p = p->next) { - eosd_draw_alpha_a8i8(p->bitmap, p->w, p->h, p->stride, a, i, stride, - x + p->dst_x, y + p->dst_y, p->color); - } + if (osd->osd_render) + ass_renderer_done(osd->osd_render); + osd->osd_render = NULL; + ass_library_done(osd->osd_ass_library); + osd->osd_ass_library = NULL; } -static bool ass_bb(ASS_Image *imgs, int *x1, int *y1, int *x2, int *y2) +static void update_font_style(ASS_Track *track, ASS_Style *style, double factor) { - *x1 = *y1 = INT_MAX; - *x2 = *y2 = INT_MIN; - for (ASS_Image *p = imgs; p; p = p->next) { - *x1 = FFMIN(*x1, p->dst_x); - *y1 = FFMIN(*y1, p->dst_y); - *x2 = FFMAX(*x2, p->dst_x + p->w); - *y2 = FFMAX(*y2, p->dst_y + p->h); - } - return *x1 < *x2 && *y1 < *y2; -} - -static void draw_ass_osd(struct osd_state *osd, mp_osd_obj_t *obj) -{ - ass_set_frame_size(osd->osd_render, osd->w, osd->h); - - ASS_Image *imgs = ass_render_frame(osd->osd_render, obj->osd_track, 0, - NULL); - - int x1, y1, x2, y2; - if (!ass_bb(imgs, &x1, &y1, &x2, &y2)) { - obj->flags &= ~OSDFLAG_VISIBLE; - return; - } - - obj->bbox.x1 = x1; - obj->bbox.y1 = y1; - obj->bbox.x2 = x2; - obj->bbox.y2 = y2; - obj->flags |= OSDFLAG_BBOX; - osd_alloc_buf(obj); - - eosd_render_a8i8(obj->alpha_buffer, obj->bitmap_buffer, obj->stride, - -x1, -y1, imgs); -} - + // Set to neutral base direction, as opposed to VSFilter LTR default + style->Encoding = -1; -static void update_font_scale(ASS_Track *track, ASS_Style *style, double factor) -{ // duplicated from ass_mp.c - double fs = track->PlayResY * factor / 100.; - /* The font size is always proportional to video height only; - * real -subfont-autoscale behavior is not implemented. - * Apply a correction that corresponds to about 4:3 aspect ratio - * video to get a size somewhat closer to what non-libass rendering - * would produce with the same text_font_scale_factor - * and subtitle_autoscale. - */ - if (subtitle_autoscale == 2) - fs *= 1.3; - else if (subtitle_autoscale == 3) - fs *= 1.7; - style->FontSize = fs; + style->FontSize = track->PlayResY * factor / 100.; style->Outline = style->FontSize / 16; } @@ -193,7 +77,7 @@ static ASS_Track *create_osd_ass_track(struct osd_state *osd) track->PlayResX = track->PlayResY * 1.33333; - update_font_scale(track, style, text_font_scale_factor); + update_font_style(track, style, text_font_scale_factor); style->Alignment = 5; @@ -211,9 +95,16 @@ static ASS_Event *get_osd_ass_event(ASS_Track *track) event->Start = 0; event->Duration = 100; event->Style = track->default_style; + assert(event->Text == NULL); return event; } +static void clear_obj(struct osd_object *obj) +{ + if (obj->osd_track) + ass_flush_events(obj->osd_track); +} + static char *append_utf8_buffer(char *buffer, uint32_t codepoint) { char data[8]; @@ -252,25 +143,27 @@ static char *mangle_ass(const char *in) return res; } -void vo_update_text_osd(struct osd_state *osd, mp_osd_obj_t* obj) +static void update_osd(struct osd_state *osd, struct osd_object *obj) { + if (!osd->osd_text[0]) { + clear_obj(obj); + return; + } + if (!obj->osd_track) obj->osd_track = create_osd_ass_track(osd); ASS_Event *event = get_osd_ass_event(obj->osd_track); - event->Text = mangle_ass(osd->osd_text); - draw_ass_osd(osd, obj); - talloc_free(event->Text); - event->Text = NULL; + char *text = mangle_ass(osd->osd_text); + event->Text = strdup(text); + talloc_free(text); } #define OSDBAR_ELEMS 46 -void vo_update_text_progbar(struct osd_state *osd, mp_osd_obj_t* obj) +static void update_progbar(struct osd_state *osd, struct osd_object *obj) { - obj->flags |= OSDFLAG_CHANGED | OSDFLAG_VISIBLE; - - if (vo_osd_progbar_type < 0) { - obj->flags &= ~OSDFLAG_VISIBLE; + if (osd->progbar_type < 0) { + clear_obj(obj); return; } @@ -286,22 +179,22 @@ void vo_update_text_progbar(struct osd_state *osd, mp_osd_obj_t* obj) // Assume the OSD bar takes 2/3 of the OSD width at PlayResY=288 and // FontSize=22 with an OSD aspect ratio of 16:9. Rescale as needed. // xxx can fail when unknown fonts are involved - double asp = (double)osd->w / osd->h; + double asp = (double)obj->vo_res.w / obj->vo_res.h; double scale = (asp / 1.77777) * (obj->osd_track->PlayResY / 288.0); style->ScaleX = style->ScaleY = scale; style->FontSize = 22.0; style->Outline = style->FontSize / 16 * scale; - int active = (vo_osd_progbar_value * OSDBAR_ELEMS + 255) / 256; + int active = (osd->progbar_value * OSDBAR_ELEMS + 255) / 256; active = FFMIN(OSDBAR_ELEMS, FFMAX(active, 0)); char *text = talloc_strdup(NULL, "{\\q2}"); - if (vo_osd_progbar_type >= 32) { - text = append_utf8_buffer(text, vo_osd_progbar_type); - } else if (vo_osd_progbar_type > 0) { + if (osd->progbar_type >= 32) { + text = append_utf8_buffer(text, osd->progbar_type); + } else if (osd->progbar_type > 0) { text = talloc_strdup_append_buffer(text, ASS_USE_OSD_FONT); - text = append_utf8_buffer(text, OSD_CODEPOINTS + vo_osd_progbar_type); + text = append_utf8_buffer(text, OSD_CODEPOINTS + osd->progbar_type); text = talloc_strdup_append_buffer(text, "{\\r}"); } @@ -317,21 +210,16 @@ void vo_update_text_progbar(struct osd_state *osd, mp_osd_obj_t* obj) text = append_utf8_buffer(text, OSD_CODEPOINTS + OSD_PB_END); ASS_Event *event = get_osd_ass_event(obj->osd_track); - event->Text = text; - draw_ass_osd(osd, obj); - event->Text = NULL; - + event->Text = strdup(text); talloc_free(text); } -void vo_update_text_sub(struct osd_state *osd, mp_osd_obj_t* obj) +static void update_sub(struct osd_state *osd, struct osd_object *obj) { struct MPOpts *opts = osd->opts; - obj->flags |= OSDFLAG_CHANGED | OSDFLAG_VISIBLE; - - if (!vo_sub || !opts->sub_visibility) { - obj->flags &= ~OSDFLAG_VISIBLE; + if (!(vo_sub && opts->sub_visibility)) { + clear_obj(obj); return; } @@ -340,7 +228,7 @@ void vo_update_text_sub(struct osd_state *osd, mp_osd_obj_t* obj) ASS_Style *style = obj->osd_track->styles + obj->osd_track->default_style; - update_font_scale(obj->osd_track, style, text_font_scale_factor); + update_font_style(obj->osd_track, style, text_font_scale_factor); #if LIBASS_VERSION >= 0x01010000 ass_set_line_position(osd->osd_render, 100 - sub_pos); #endif @@ -351,14 +239,40 @@ void vo_update_text_sub(struct osd_state *osd, mp_osd_obj_t* obj) text = talloc_asprintf_append_buffer(text, "%s\n", vo_sub->text[n]); ASS_Event *event = get_osd_ass_event(obj->osd_track); - event->Text = mangle_ass(text); - draw_ass_osd(osd, obj); - talloc_free(event->Text); - event->Text = NULL; - + char *escaped_text = mangle_ass(text); + event->Text = strdup(escaped_text); + talloc_free(escaped_text); talloc_free(text); } -// unneeded -void osd_font_invalidate(void) {} -void osd_font_load(struct osd_state *osd) {} +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_SUBTITLE: + update_sub(osd, obj); + break; + case OSDTYPE_PROGBAR: + update_progbar(osd, obj); + break; + } +} + +void osd_object_get_bitmaps(struct osd_state *osd, struct osd_object *obj, + struct sub_bitmaps *out_imgs) +{ + if (obj->force_redraw) + update_object(osd, obj); + + *out_imgs = (struct sub_bitmaps) {0}; + if (!obj->osd_track) + return; + + ass_set_frame_size(osd->osd_render, obj->vo_res.w, obj->vo_res.h); + ass_set_aspect_ratio(osd->osd_render, obj->vo_res.display_par, 1.0); + mp_ass_render_frame(osd->osd_render, obj->osd_track, 0, + &obj->parts_cache, out_imgs); + talloc_steal(obj, obj->parts_cache); +} |