From 3365514951e9c07ec3a21bb3898e5796c214f8b7 Mon Sep 17 00:00:00 2001 From: wm4 Date: Fri, 28 Sep 2012 21:38:52 +0200 Subject: sub: allow rendering OSD in ASS image format directly, simplify Before this commit, the OSD was drawn using libass, but the resulting bitmaps were converted to the internal mplayer OSD format. We want to get rid of the old OSD format, because it's monochrome, and can't even be rendered directly using modern video output methods (like with OpenGL/Direct3D/VDPAU). Change it so that VOs can get the ASS images directly, without additional conversions. (This also has the consequence that the OSD can render colors now.) Currently, this is vo_gl3 only. The other VOs still use the old method. Also, the old OSD format is still used for all VOs with DVD subtitles (spudec). Rewrite sub.c. Remove all the awkward flags and bounding boxes and change detection things. It turns out that much of that isn't needed. Move code related to converting subtitle images to img_convert.c. (It has to be noted that all of these conversions were already done before in some places, and that the new code actually makes less use of them.) --- sub/osd_libass.c | 195 +++++++++++++++++-------------------------------------- 1 file changed, 60 insertions(+), 135 deletions(-) (limited to 'sub/osd_libass.c') diff --git a/sub/osd_libass.c b/sub/osd_libass.c index e770215ce6..2d596a6516 100644 --- a/sub/osd_libass.c +++ b/sub/osd_libass.c @@ -55,117 +55,13 @@ 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); - } -} - -static bool ass_bb(ASS_Image *imgs, int *x1, int *y1, int *x2, int *y2) -{ - *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); + 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 update_font_scale(ASS_Track *track, ASS_Style *style, double factor) { // duplicated from ass_mp.c @@ -211,9 +107,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]; @@ -257,25 +160,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; + clear_obj(obj); return; } @@ -322,21 +227,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; } @@ -354,14 +254,39 @@ 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, osd->w, osd->h); + mp_ass_render_frame(osd->osd_render, obj->osd_track, 0, + &obj->parts_cache, out_imgs); + talloc_steal(obj, obj->parts_cache); +} -- cgit v1.2.3 From e62b3a175016eaf93ef5ead7ea3891bc85327a55 Mon Sep 17 00:00:00 2001 From: wm4 Date: Sat, 29 Sep 2012 09:53:28 +0200 Subject: sub: cosmetics: turn some defines into enums --- sub/osd_libass.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'sub/osd_libass.c') diff --git a/sub/osd_libass.c b/sub/osd_libass.c index 2d596a6516..6c325642c5 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}" -- cgit v1.2.3 From 252ddcc014b7672a4434823fc6275be1b039bd79 Mon Sep 17 00:00:00 2001 From: wm4 Date: Sat, 29 Sep 2012 11:03:53 +0200 Subject: sub: cleanup: remove vo_osd_probar_type/value global variables --- sub/osd_libass.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'sub/osd_libass.c') diff --git a/sub/osd_libass.c b/sub/osd_libass.c index 6c325642c5..dee60c7df7 100644 --- a/sub/osd_libass.c +++ b/sub/osd_libass.c @@ -176,7 +176,7 @@ static void update_osd(struct osd_state *osd, struct osd_object *obj) static void update_progbar(struct osd_state *osd, struct osd_object *obj) { - if (vo_osd_progbar_type < 0) { + if (osd->progbar_type < 0) { clear_obj(obj); return; } @@ -199,16 +199,16 @@ static void update_progbar(struct osd_state *osd, struct osd_object *obj) 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}"); } -- cgit v1.2.3 From 5357b38d40e28dda4032ddc8654f5877d4928860 Mon Sep 17 00:00:00 2001 From: wm4 Date: Tue, 2 Oct 2012 22:42:26 +0200 Subject: osd_libass: set RTL base direction to neutral We are using libass for OSD rendering. One problem with that is that libass has to be bug-compatible to VSFilter. This includes the setting for the default RTL base direction. Neutral would be most reasonable, but VSFilter assumes LTR. This commit forces the default to neutral. Unconfirmed whether this actually works as intended. See the following libass commits: 9dbd12d shaper: allow font encoding -1 for neutral base direction a80c45c shaper: always use LTR base direction by default --- sub/osd_libass.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'sub/osd_libass.c') diff --git a/sub/osd_libass.c b/sub/osd_libass.c index dee60c7df7..811bc009f3 100644 --- a/sub/osd_libass.c +++ b/sub/osd_libass.c @@ -59,8 +59,11 @@ void osd_destroy_backend(struct osd_state *osd) osd->osd_ass_library = NULL; } -static void update_font_scale(ASS_Track *track, ASS_Style *style, double factor) +static void update_font_style(ASS_Track *track, ASS_Style *style, double factor) { + // Set to neutral base direction, as opposed to VSFilter LTR default + style->Encoding = -1; + // duplicated from ass_mp.c double fs = track->PlayResY * factor / 100.; /* The font size is always proportional to video height only; @@ -86,7 +89,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; @@ -243,7 +246,7 @@ static void update_sub(struct osd_state *osd, struct osd_object *obj) ASS_Style *style = obj->osd_track->styles + obj->osd_track->default_style; style->MarginV = obj->osd_track->PlayResY * ((100 - sub_pos)/110.0); - update_font_scale(obj->osd_track, style, text_font_scale_factor); + update_font_style(obj->osd_track, style, text_font_scale_factor); char *text = talloc_strdup(NULL, ""); -- cgit v1.2.3 From cc05910f16a5ccd8e3dca26a89e9c3835cbdb645 Mon Sep 17 00:00:00 2001 From: wm4 Date: Thu, 4 Oct 2012 17:16:40 +0200 Subject: sub: cosmetics: move things around Move sub-bitmap definitions from dec_sub.h to sub.h. While it's a bit odd that OSD data structures are in a file named sub.h, it's definitely way too strange to have them in a file about subtitle decoding. (Maybe sub.h/.c and the sub/ directory should be split out and renamed "osd" at a later point.) Remove including ass_mp.h (and the libass headers) where possible. Remove typedefs for mp_eosd_res and sub_bitmaps structs. Store a mp_eosd_res struct in osd_state instead of just w/h. Note that sbtitles might be rendered using different sizes/margins when filters are involved (the subtitle renderer is not supposed to use the OSD res directly, and the "dim" member removed in the previous commit is something different). --- sub/osd_libass.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sub/osd_libass.c') diff --git a/sub/osd_libass.c b/sub/osd_libass.c index 811bc009f3..f3296c6091 100644 --- a/sub/osd_libass.c +++ b/sub/osd_libass.c @@ -196,7 +196,7 @@ static void update_progbar(struct osd_state *osd, struct osd_object *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)osd->res.w / osd->res.h; double scale = (asp / 1.77777) * (obj->osd_track->PlayResY / 288.0); style->ScaleX = style->ScaleY = scale; style->FontSize = 22.0; @@ -285,7 +285,7 @@ void osd_object_get_bitmaps(struct osd_state *osd, struct osd_object *obj, if (!obj->osd_track) return; - ass_set_frame_size(osd->osd_render, osd->w, osd->h); + ass_set_frame_size(osd->osd_render, osd->res.w, osd->res.h); mp_ass_render_frame(osd->osd_render, obj->osd_track, 0, &obj->parts_cache, out_imgs); talloc_steal(obj, obj->parts_cache); -- cgit v1.2.3 From 98f74335d509320f19db2da8786273f95cad2a69 Mon Sep 17 00:00:00 2001 From: wm4 Date: Thu, 18 Oct 2012 17:31:00 +0200 Subject: sub: fix text subtitle aspect ratio with vo_xv and vo_lavc, refactor This fixes that vo_xv didn't display text subtitles correctly when using anamorphic video. It didn't pass the aspect information to the subtitle renderer. Also, try to render OSD correctly with respect to aspect ratio settings: on vo_xv, the OSD is rendered into the video, and needs to be "stretched" too when playing anamorphic video. When the -monitorpixelaspect option is used, even with VOs such as vo_opengl the OSD has to be rendered with that aspect ratio. As preparation for future commits, replace the weird vsfilter_scale value with a somewhat more sensible video_par member. Also, struct mp_eosd_res is a better place for the aspect ratio parameters, as OSD needs this too. Use osd_draw_on_image() directly in vo_lavc, which fixes aspect ratio issues as well. --- sub/osd_libass.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sub/osd_libass.c') diff --git a/sub/osd_libass.c b/sub/osd_libass.c index d77c0d1af2..a182c6bdf2 100644 --- a/sub/osd_libass.c +++ b/sub/osd_libass.c @@ -283,6 +283,7 @@ void osd_object_get_bitmaps(struct osd_state *osd, struct osd_object *obj, return; ass_set_frame_size(osd->osd_render, osd->res.w, osd->res.h); + ass_set_aspect_ratio(osd->osd_render, osd->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); -- cgit v1.2.3 From 4d11f32162b08e3b48ae382e2ed0a151035f8aea Mon Sep 17 00:00:00 2001 From: wm4 Date: Fri, 19 Oct 2012 19:25:18 +0200 Subject: VO, sub: refactor Remove VFCTRL_DRAW_OSD, VFCAP_EOSD_FILTER, VFCAP_EOSD_RGBA, VFCAP_EOSD, VOCTRL_DRAW_EOSD, VOCTRL_GET_EOSD_RES, VOCTRL_QUERY_EOSD_FORMAT. Remove draw_osd_with_eosd(), which rendered the OSD by calling VOCTRL_DRAW_EOSD. Change VOs to call osd_draw() directly, which takes a callback as argument. (This basically works like the old OSD API, except multiple OSD bitmap formats are supported and caching is possible.) Remove all mentions of "eosd". It's simply "osd" now. Make OSD size per-OSD-object, as they can be different when using vf_sub. Include display_par/video_par in resolution change detection. Fix the issue with margin borders in vo_corevideo. --- sub/osd_libass.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'sub/osd_libass.c') diff --git a/sub/osd_libass.c b/sub/osd_libass.c index a182c6bdf2..4a6a0c88cb 100644 --- a/sub/osd_libass.c +++ b/sub/osd_libass.c @@ -191,7 +191,7 @@ static void update_progbar(struct osd_state *osd, struct osd_object *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->res.w / osd->res.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; @@ -282,8 +282,8 @@ void osd_object_get_bitmaps(struct osd_state *osd, struct osd_object *obj, if (!obj->osd_track) return; - ass_set_frame_size(osd->osd_render, osd->res.w, osd->res.h); - ass_set_aspect_ratio(osd->osd_render, osd->res.display_par, 1.0); + 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); -- cgit v1.2.3 From a8824f12ddfe66585db43fb0f92d7c90b5bbd19d Mon Sep 17 00:00:00 2001 From: wm4 Date: Tue, 23 Oct 2012 21:23:53 +0200 Subject: options: remove --subfont-autoscale (changes default font scale) The code for this option attempted to emulate the old as-documented behavior. It wasn't very good at it, and now that the old OSD code has been removed, it's entirely pointless. This removes the factor 1.7 with which --subfont-text-scale was multiplied. --- sub/osd_libass.c | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) (limited to 'sub/osd_libass.c') diff --git a/sub/osd_libass.c b/sub/osd_libass.c index 4a6a0c88cb..5f17f2fa6f 100644 --- a/sub/osd_libass.c +++ b/sub/osd_libass.c @@ -65,19 +65,7 @@ static void update_font_style(ASS_Track *track, ASS_Style *style, double factor) style->Encoding = -1; // 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; } -- cgit v1.2.3