From 03730e73dc0439e0e673857d8c376a70cfcc8152 Mon Sep 17 00:00:00 2001 From: wm4 Date: Fri, 28 Dec 2012 15:46:23 +0100 Subject: img_convert: add sub_bitmap bounding box functions mp_sub_bitmaps_bb is just sub_bitmaps_bb renamed/moved. --- sub/draw_bmp.c | 3 +- sub/img_convert.c | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- sub/img_convert.h | 12 ++++++++ sub/sub.c | 20 ------------- sub/sub.h | 3 -- 5 files changed, 97 insertions(+), 25 deletions(-) (limited to 'sub') diff --git a/sub/draw_bmp.c b/sub/draw_bmp.c index 4cf89349a0..f8fbe2e643 100644 --- a/sub/draw_bmp.c +++ b/sub/draw_bmp.c @@ -27,6 +27,7 @@ #include "core/mp_common.h" #include "sub/draw_bmp.h" #include "sub/sub.h" +#include "sub/img_convert.h" #include "video/mp_image.h" #include "video/sws_utils.h" #include "video/img_format.h" @@ -543,7 +544,7 @@ void mp_draw_sub_bitmaps(struct mp_draw_sub_cache **cache, struct mp_image *dst, get_closest_y444_format(dst->imgfmt, &format, &bits); struct mp_rect bb; - if (!sub_bitmaps_bb(sbs, &bb)) + if (!mp_sub_bitmaps_bb(sbs, &bb)) return; if (!align_bbox_for_swscale(dst, &bb)) diff --git a/sub/img_convert.c b/sub/img_convert.c index 5e74ba9e84..abbb6ad301 100644 --- a/sub/img_convert.c +++ b/sub/img_convert.c @@ -211,7 +211,7 @@ bool osd_conv_ass_to_rgba(struct osd_conv_cache *c, struct sub_bitmaps *imgs) imgs->num_parts = 0; struct mp_rect bb; - if (!sub_bitmaps_bb(&src, &bb)) + if (!mp_sub_bitmaps_bb(&src, &bb)) return true; bmp->x = bb.x0; @@ -239,3 +239,85 @@ bool osd_conv_ass_to_rgba(struct osd_conv_cache *c, struct sub_bitmaps *imgs) imgs->num_parts = 1; return true; } + +bool mp_sub_bitmaps_bb(struct sub_bitmaps *imgs, struct mp_rect *out_bb) +{ + struct mp_rect bb = {INT_MAX, INT_MAX, INT_MIN, INT_MIN}; + for (int n = 0; n < imgs->num_parts; n++) { + struct sub_bitmap *p = &imgs->parts[n]; + bb.x0 = FFMIN(bb.x0, p->x); + bb.y0 = FFMIN(bb.y0, p->y); + bb.x1 = FFMAX(bb.x1, p->x + p->dw); + bb.y1 = FFMAX(bb.y1, p->y + p->dh); + } + + // avoid degenerate bounding box if empty + bb.x0 = FFMIN(bb.x0, bb.x1); + bb.y0 = FFMIN(bb.y0, bb.y1); + + *out_bb = bb; + + return bb.x0 < bb.x1 && bb.y0 < bb.y1; +} + +// Merge bounding rectangles if they're closer than the given amount of pixels. +// Avoids having too many rectangles due to spacing between letter. +#define MERGE_RC_PIXELS 50 + +static void remove_intersecting_rcs(struct mp_rect *list, int *count) +{ + int M = MERGE_RC_PIXELS; + bool changed = true; + while (changed) { + changed = false; + for (int a = 0; a < *count; a++) { + struct mp_rect *rc_a = &list[a]; + for (int b = *count - 1; b > a; b--) { + struct mp_rect *rc_b = &list[b]; + if (rc_a->x0 - M <= rc_b->x1 && rc_a->x1 + M >= rc_b->x0 && + rc_a->y0 - M <= rc_b->y1 && rc_a->y1 + M >= rc_b->y0) + { + mp_rect_union(rc_a, rc_b); + MP_TARRAY_REMOVE_AT(list, *count, b); + changed = true; + } + } + } + } +} + +// Cluster the given subrectangles into a small numbers of bounding rectangles, +// and store them into list. E.g. when subtitles and toptitles are visible at +// the same time, there should be two bounding boxes, so that the video between +// the text is left untouched (need to resample less pixels -> faster). +// Returns number of rectangles added to out_rc_list (<= rc_list_count) +// NOTE: some callers assume that sub bitmaps are never split or partially +// covered by returned rectangles. +int mp_get_sub_bb_list(struct sub_bitmaps *sbs, struct mp_rect *out_rc_list, + int rc_list_count) +{ + int M = MERGE_RC_PIXELS; + int num_rc = 0; + for (int n = 0; n < sbs->num_parts; n++) { + struct sub_bitmap *sb = &sbs->parts[n]; + struct mp_rect bb = {sb->x, sb->y, sb->x + sb->dw, sb->y + sb->dh}; + bool intersects = false; + for (int r = 0; r < num_rc; r++) { + struct mp_rect *rc = &out_rc_list[r]; + if ((bb.x0 - M <= rc->x1 && bb.x1 + M >= rc->x0 && + bb.y0 - M <= rc->y1 && bb.y1 + M >= rc->y0) || + num_rc == rc_list_count) + { + mp_rect_union(rc, &bb); + intersects = true; + break; + } + } + if (!intersects) { + out_rc_list[num_rc++] = bb; + remove_intersecting_rcs(out_rc_list, &num_rc); + } + } + remove_intersecting_rcs(out_rc_list, &num_rc); + return num_rc; +} diff --git a/sub/img_convert.h b/sub/img_convert.h index 0a46916f60..383a2c8003 100644 --- a/sub/img_convert.h +++ b/sub/img_convert.h @@ -5,6 +5,7 @@ struct osd_conv_cache; struct sub_bitmaps; +struct mp_rect; struct osd_conv_cache *osd_conv_cache_new(void); @@ -17,4 +18,15 @@ bool osd_conv_blur_rgba(struct osd_conv_cache *c, struct sub_bitmaps *imgs, double gblur); bool osd_conv_idx_to_gray(struct osd_conv_cache *c, struct sub_bitmaps *imgs); + +bool mp_sub_bitmaps_bb(struct sub_bitmaps *imgs, struct mp_rect *out_bb); + +// Intentionally limit the maximum number of bounding rects to something low. +// This prevents the algorithm from degrading to O(N^2). +// Most subtitles yield a very low number of bounding rects (<5). +#define MP_SUB_BB_LIST_MAX 15 + +int mp_get_sub_bb_list(struct sub_bitmaps *sbs, struct mp_rect *out_rc_list, + int rc_list_count); + #endif diff --git a/sub/sub.c b/sub/sub.c index ea9c51a758..b01493a790 100644 --- a/sub/sub.c +++ b/sub/sub.c @@ -333,23 +333,3 @@ void osd_subs_changed(struct osd_state *osd) vo_osd_changed(n); } } - -bool sub_bitmaps_bb(struct sub_bitmaps *imgs, struct mp_rect *out_bb) -{ - struct mp_rect bb = {INT_MAX, INT_MAX, INT_MIN, INT_MIN}; - for (int n = 0; n < imgs->num_parts; n++) { - struct sub_bitmap *p = &imgs->parts[n]; - bb.x0 = FFMIN(bb.x0, p->x); - bb.y0 = FFMIN(bb.y0, p->y); - bb.x1 = FFMAX(bb.x1, p->x + p->dw); - bb.y1 = FFMAX(bb.y1, p->y + p->dh); - } - - // avoid degenerate bounding box if empty - bb.x0 = FFMIN(bb.x0, bb.x1); - bb.y0 = FFMIN(bb.y0, bb.y1); - - *out_bb = bb; - - return bb.x0 < bb.x1 && bb.y0 < bb.y1; -} diff --git a/sub/sub.h b/sub/sub.h index c7f8a8b022..b1059819ee 100644 --- a/sub/sub.h +++ b/sub/sub.h @@ -227,9 +227,6 @@ 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); -struct mp_rect; -bool sub_bitmaps_bb(struct sub_bitmaps *imgs, struct mp_rect *out_bb); - // defined in osd_libass.c and osd_dummy.c void osd_object_get_bitmaps(struct osd_state *osd, struct osd_object *obj, -- cgit v1.2.3