diff options
author | wm4 <wm4@nowhere> | 2012-11-01 02:12:47 +0100 |
---|---|---|
committer | wm4 <wm4@nowhere> | 2012-11-01 02:12:47 +0100 |
commit | 84829a4ea1903e5db5782b72861fabc503a589cb (patch) | |
tree | 26b4acbaf6dd4b255278dcc67f28bd83357c3b86 /sub | |
parent | e45dd051c304dec189d0d4d792a89c2988c3fa71 (diff) | |
parent | f4069259cf7ffd24ac2a5b64e26a386185e94c7b (diff) | |
download | mpv-84829a4ea1903e5db5782b72861fabc503a589cb.tar.bz2 mpv-84829a4ea1903e5db5782b72861fabc503a589cb.tar.xz |
Merge branch 'osd_changes' into master
Conflicts:
DOCS/man/en/options.rst
Diffstat (limited to 'sub')
-rw-r--r-- | sub/ass_mp.c | 53 | ||||
-rw-r--r-- | sub/ass_mp.h | 11 | ||||
-rw-r--r-- | sub/dec_sub.c | 26 | ||||
-rw-r--r-- | sub/dec_sub.h | 39 | ||||
-rw-r--r-- | sub/draw_bmp.c | 530 | ||||
-rw-r--r-- | sub/draw_bmp.h | 17 | ||||
-rw-r--r-- | sub/find_subfiles.c | 1 | ||||
-rw-r--r-- | sub/img_convert.c | 89 | ||||
-rw-r--r-- | sub/img_convert.h | 15 | ||||
-rw-r--r-- | sub/osd_dummy.c | 22 | ||||
-rw-r--r-- | sub/osd_libass.c | 234 | ||||
-rw-r--r-- | sub/sd.h | 5 | ||||
-rw-r--r-- | sub/sd_ass.c | 22 | ||||
-rw-r--r-- | sub/sd_lavc.c | 133 | ||||
-rw-r--r-- | sub/spudec.c | 823 | ||||
-rw-r--r-- | sub/spudec.h | 21 | ||||
-rw-r--r-- | sub/sub.c | 426 | ||||
-rw-r--r-- | sub/sub.h | 262 |
18 files changed, 1282 insertions, 1447 deletions
diff --git a/sub/ass_mp.c b/sub/ass_mp.c index 908a552acf..1867880f38 100644 --- a/sub/ass_mp.c +++ b/sub/ass_mp.c @@ -61,17 +61,6 @@ ASS_Track *mp_ass_default_track(ASS_Library *library, struct MPOpts *opts) style->treat_fontname_as_pattern = 1; double fs = track->PlayResY * text_font_scale_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; uint32_t c1 = 0xFFFFFF00; uint32_t c2 = 0x00000000; @@ -228,7 +217,7 @@ ASS_Track *mp_ass_read_stream(ASS_Library *library, const char *fname, } void mp_ass_configure(ASS_Renderer *priv, struct MPOpts *opts, - struct mp_eosd_res *dim, bool unscaled) + struct mp_osd_res *dim) { ass_set_frame_size(priv, dim->w, dim->h); ass_set_margins(priv, dim->mt, dim->mb, dim->ml, dim->mr); @@ -243,10 +232,7 @@ void mp_ass_configure(ASS_Renderer *priv, struct MPOpts *opts, set_sub_pos = 100 - sub_pos; set_line_spacing = opts->ass_line_spacing; set_font_scale = opts->ass_font_scale; - if (!unscaled && (opts->ass_hinting & 4)) - set_hinting = 0; - else - set_hinting = opts->ass_hinting & 3; + set_hinting = opts->ass_hinting & 3; // +4 was for no hinting if scaled } ass_set_use_margins(priv, set_use_margins); @@ -281,6 +267,41 @@ void mp_ass_configure_fonts(ASS_Renderer *priv) free(family); } +void mp_ass_render_frame(ASS_Renderer *renderer, ASS_Track *track, double time, + struct sub_bitmap **parts, struct sub_bitmaps *res) +{ + int changed; + ASS_Image *imgs = ass_render_frame(renderer, track, time, &changed); + if (changed == 2) + res->bitmap_id = ++res->bitmap_pos_id; + else if (changed) + res->bitmap_pos_id++; + res->format = SUBBITMAP_LIBASS; + + res->parts = *parts; + res->num_parts = 0; + int num_parts_alloc = MP_TALLOC_ELEMS(res->parts); + for (struct ass_image *img = imgs; img; img = img->next) { + if (img->w == 0 || img->h == 0) + continue; + if (res->num_parts >= num_parts_alloc) { + num_parts_alloc = FFMAX(num_parts_alloc * 2, 32); + res->parts = talloc_realloc(NULL, res->parts, struct sub_bitmap, + num_parts_alloc); + } + struct sub_bitmap *p = &res->parts[res->num_parts]; + p->bitmap = img->bitmap; + p->stride = img->stride; + p->libass.color = img->color; + p->dw = p->w = img->w; + p->dh = p->h = img->h; + p->x = img->dst_x; + p->y = img->dst_y; + res->num_parts++; + } + *parts = res->parts; +} + static int map_ass_level[] = { MSGL_ERR, // 0 "FATAL errors" MSGL_WARN, diff --git a/sub/ass_mp.h b/sub/ass_mp.h index 3cfbe147b7..c3dbc5e28f 100644 --- a/sub/ass_mp.h +++ b/sub/ass_mp.h @@ -32,7 +32,7 @@ #include <ass/ass_types.h> struct MPOpts; -struct mp_eosd_res; +struct mp_osd_res; ASS_Track *mp_ass_default_track(ASS_Library *library, struct MPOpts *opts); ASS_Track *mp_ass_read_subdata(ASS_Library *library, struct MPOpts *opts, @@ -42,13 +42,18 @@ ASS_Track *mp_ass_read_stream(ASS_Library *library, const char *fname, struct MPOpts; void mp_ass_configure(ASS_Renderer *priv, struct MPOpts *opts, - struct mp_eosd_res *dim, bool unscaled); + struct mp_osd_res *dim); void mp_ass_configure_fonts(ASS_Renderer *priv); ASS_Library *mp_ass_init(struct MPOpts *opts); +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); + #else /* CONFIG_ASS */ -/* Needed for EOSD code using this type to compile */ +/* Needed for OSD code using this type to compile */ typedef struct ass_image { int w, h; diff --git a/sub/dec_sub.c b/sub/dec_sub.c index 4a048b27a6..5ceb3b2422 100644 --- a/sub/dec_sub.c +++ b/sub/dec_sub.c @@ -39,13 +39,13 @@ void sub_init(struct sh_sub *sh, struct osd_state *osd) if (opts->ass_enabled && is_text_sub(sh->type)) sh->sd_driver = &sd_ass; #endif - if (strchr("bpx", sh->type)) + if (strchr("bpxv", sh->type)) sh->sd_driver = &sd_lavc; if (sh->sd_driver) { if (sh->sd_driver->init(sh, osd) < 0) return; osd->sh_sub = sh; - osd->bitmap_id = ++osd->bitmap_pos_id; + osd->switch_sub_id++; sh->initialized = true; sh->active = true; } @@ -58,13 +58,12 @@ void sub_decode(struct sh_sub *sh, struct osd_state *osd, void *data, sh->sd_driver->decode(sh, osd, data, data_len, pts, duration); } -void sub_get_bitmaps(struct osd_state *osd, struct sub_bitmaps *res) +void sub_get_bitmaps(struct osd_state *osd, struct mp_osd_res dim, double pts, + struct sub_bitmaps *res) { struct MPOpts *opts = osd->opts; - *res = (struct sub_bitmaps){ .type = SUBBITMAP_EMPTY, - .bitmap_id = osd->bitmap_id, - .bitmap_pos_id = osd->bitmap_pos_id }; + *res = (struct sub_bitmaps) {0}; if (!opts->sub_visibility || !osd->sh_sub || !osd->sh_sub->active) { /* Change ID in case we just switched from visible subtitles * to current state. Hopefully, unnecessarily claiming that @@ -72,14 +71,15 @@ void sub_get_bitmaps(struct osd_state *osd, struct sub_bitmaps *res) * Increase osd-> values ahead so that _next_ returned id * is also guaranteed to differ from this one. */ - res->bitmap_id = ++res->bitmap_pos_id; - osd->bitmap_id = osd->bitmap_pos_id += 2; - return; + osd->switch_sub_id++; + } else { + if (osd->sh_sub->sd_driver->get_bitmaps) + osd->sh_sub->sd_driver->get_bitmaps(osd->sh_sub, osd, dim, pts, res); } - if (osd->sh_sub->sd_driver->get_bitmaps) - osd->sh_sub->sd_driver->get_bitmaps(osd->sh_sub, osd, res); - osd->bitmap_id = res->bitmap_id; - osd->bitmap_pos_id = res->bitmap_pos_id; + + res->bitmap_id += osd->switch_sub_id; + res->bitmap_pos_id += osd->switch_sub_id; + osd->switch_sub_id = 0; } void sub_reset(struct sh_sub *sh, struct osd_state *osd) diff --git a/sub/dec_sub.h b/sub/dec_sub.h index c71a2348aa..f66f05c021 100644 --- a/sub/dec_sub.h +++ b/sub/dec_sub.h @@ -1,38 +1,14 @@ #ifndef MPLAYER_DEC_SUB_H #define MPLAYER_DEC_SUB_H -struct sh_sub; -struct osd_state; -struct ass_track; - -enum sub_bitmap_type { - SUBBITMAP_EMPTY, - SUBBITMAP_LIBASS, - SUBBITMAP_RGBA, -}; - -typedef struct mp_eosd_res { - int w, h; // screen dimensions, including black borders - int mt, mb, ml, mr; // borders (top, bottom, left, right) -} mp_eosd_res_t; +#include <stdbool.h> +#include <stdint.h> -typedef struct sub_bitmaps { - enum sub_bitmap_type type; +#include "sub/sub.h" - struct ass_image *imgs; - - struct sub_bitmap { - int w, h; - int x, y; - // Note: not clipped, going outside the screen area is allowed - int dw, dh; - void *bitmap; - } *parts; - int part_count; - - bool scaled; - int bitmap_id, bitmap_pos_id; -} mp_eosd_images_t; +struct sh_sub; +struct ass_track; +struct MPOpts; static inline bool is_text_sub(int type) { @@ -41,7 +17,8 @@ static inline bool is_text_sub(int type) void sub_decode(struct sh_sub *sh, struct osd_state *osd, void *data, int data_len, double pts, double duration); -void sub_get_bitmaps(struct osd_state *osd, struct sub_bitmaps *res); +void sub_get_bitmaps(struct osd_state *osd, struct mp_osd_res dim, double pts, + struct sub_bitmaps *res); void sub_init(struct sh_sub *sh, struct osd_state *osd); void sub_reset(struct sh_sub *sh, struct osd_state *osd); void sub_switchoff(struct sh_sub *sh, struct osd_state *osd); diff --git a/sub/draw_bmp.c b/sub/draw_bmp.c new file mode 100644 index 0000000000..9a72a5b738 --- /dev/null +++ b/sub/draw_bmp.c @@ -0,0 +1,530 @@ +/* + * This file is part of mpv. + * + * mpv is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * mpv is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with mpv; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <stddef.h> +#include <stdbool.h> +#include <assert.h> +#include <math.h> +#include <inttypes.h> + +#include <libavutil/common.h> + +#include "mpcommon.h" +#include "sub/draw_bmp.h" +#include "sub/sub.h" +#include "libmpcodecs/mp_image.h" +#include "libmpcodecs/sws_utils.h" +#include "libmpcodecs/img_format.h" +#include "libvo/csputils.h" + +const bool mp_draw_sub_formats[SUBBITMAP_COUNT] = { + [SUBBITMAP_LIBASS] = true, + [SUBBITMAP_RGBA] = true, +}; + +struct sub_cache { + struct mp_image *i, *a; +}; + +struct part { + int bitmap_pos_id; + int imgfmt; + enum mp_csp colorspace; + enum mp_csp_levels levels; + int num_imgs; + struct sub_cache *imgs; +}; + +struct mp_draw_sub_cache +{ + struct part *parts[MAX_OSD_PARTS]; +}; + +static struct part *get_cache(struct mp_draw_sub_cache **cache, + struct sub_bitmaps *sbs, struct mp_image *format); +static bool get_sub_area(struct mp_rect bb, struct mp_image *temp, + struct sub_bitmap *sb, struct mp_image *out_area, + int *out_src_x, int *out_src_y); + +#define ACCURATE +#define CONDITIONAL + +static void blend_const16_alpha(void *dst, int dst_stride, uint16_t srcp, + uint8_t *srca, int srca_stride, uint8_t srcamul, + int w, int h) +{ + if (!srcamul) + return; + for (int y = 0; y < h; y++) { + uint16_t *dst_r = (uint16_t *)((uint8_t *)dst + dst_stride * y); + uint8_t *srca_r = srca + srca_stride * y; + for (int x = 0; x < w; x++) { + uint32_t srcap = srca_r[x]; +#ifdef CONDITIONAL + if (!srcap) + continue; +#endif + srcap *= srcamul; // now 0..65025 + dst_r[x] = (srcp * srcap + dst_r[x] * (65025 - srcap) + 32512) / 65025; + } + } +} + +static void blend_const8_alpha(void *dst, int dst_stride, uint16_t srcp, + uint8_t *srca, int srca_stride, uint8_t srcamul, + int w, int h) +{ + if (!srcamul) + return; + for (int y = 0; y < h; y++) { + uint8_t *dst_r = (uint8_t *)dst + dst_stride * y; + uint8_t *srca_r = srca + srca_stride * y; + for (int x = 0; x < w; x++) { + uint32_t srcap = srca_r[x]; +#ifdef CONDITIONAL + if (!srcap) + continue; +#endif +#ifdef ACCURATE + srcap *= srcamul; // now 0..65025 + dst_r[x] = (srcp * srcap + dst_r[x] * (65025 - srcap) + 32512) / 65025; +#else + srcap = (srcap * srcamul + 255) >> 8; + dst_r[x] = (srcp * srcap + dst_r[x] * (255 - srcap) + 255) >> 8; +#endif + } + } +} + +static void blend_const_alpha(void *dst, int dst_stride, int srcp, + uint8_t *srca, int srca_stride, uint8_t srcamul, + int w, int h, int bytes) +{ + if (bytes == 2) { + blend_const16_alpha(dst, dst_stride, srcp, srca, srca_stride, srcamul, + w, h); + } else if (bytes == 1) { + blend_const8_alpha(dst, dst_stride, srcp, srca, srca_stride, srcamul, + w, h); + } +} + +static void blend_src16_alpha(void *dst, int dst_stride, void *src, + int src_stride, uint8_t *srca, int srca_stride, + int w, int h) +{ + for (int y = 0; y < h; y++) { + uint16_t *dst_r = (uint16_t *)((uint8_t *)dst + dst_stride * y); + uint16_t *src_r = (uint16_t *)((uint8_t *)src + src_stride * y); + uint8_t *srca_r = srca + srca_stride * y; + for (int x = 0; x < w; x++) { + uint32_t srcap = srca_r[x]; +#ifdef CONDITIONAL + if (!srcap) + continue; +#endif + dst_r[x] = (src_r[x] * srcap + dst_r[x] * (255 - srcap) + 127) / 255; + } + } +} + +static void blend_src8_alpha(void *dst, int dst_stride, void *src, + int src_stride, uint8_t *srca, int srca_stride, + int w, int h) +{ + for (int y = 0; y < h; y++) { + uint8_t *dst_r = (uint8_t *)dst + dst_stride * y; + uint8_t *src_r = (uint8_t *)src + src_stride * y; + uint8_t *srca_r = srca + srca_stride * y; + for (int x = 0; x < w; x++) { + uint16_t srcap = srca_r[x]; +#ifdef CONDITIONAL + if (!srcap) + continue; +#endif +#ifdef ACCURATE + dst_r[x] = (src_r[x] * srcap + dst_r[x] * (255 - srcap) + 127) / 255; +#else + dst_r[x] = (src_r[x] * srcap + dst_r[x] * (255 - srcap) + 255) >> 8; +#endif + } + } +} + +static void blend_src_alpha(void *dst, int dst_stride, void *src, + int src_stride, uint8_t *srca, int srca_stride, + int w, int h, int bytes) +{ + if (bytes == 2) { + blend_src16_alpha(dst, dst_stride, src, src_stride, srca, srca_stride, + w, h); + } else if (bytes == 1) { + blend_src8_alpha(dst, dst_stride, src, src_stride, srca, srca_stride, + w, h); + } +} + +static void unpremultiply_and_split_BGR32(struct mp_image *img, + struct mp_image *alpha) +{ + for (int y = 0; y < img->h; ++y) { + uint32_t *irow = (uint32_t *) &img->planes[0][img->stride[0] * y]; + uint8_t *arow = &alpha->planes[0][alpha->stride[0] * y]; + for (int x = 0; x < img->w; ++x) { + uint32_t pval = irow[x]; + uint8_t aval = (pval >> 24); + uint8_t rval = (pval >> 16) & 0xFF; + uint8_t gval = (pval >> 8) & 0xFF; + uint8_t bval = pval & 0xFF; + // multiplied = separate * alpha / 255 + // separate = rint(multiplied * 255 / alpha) + // = floor(multiplied * 255 / alpha + 0.5) + // = floor((multiplied * 255 + 0.5 * alpha) / alpha) + // = floor((multiplied * 255 + floor(0.5 * alpha)) / alpha) + int div = (int) aval; + int add = div / 2; + if (aval) { + rval = FFMIN(255, (rval * 255 + add) / div); + gval = FFMIN(255, (gval * 255 + add) / div); + bval = FFMIN(255, (bval * 255 + add) / div); + irow[x] = bval + (gval << 8) + (rval << 16) + (aval << 24); + } + arow[x] = aval; + } + } +} + +// dst_format merely contains the target colorspace/format information +static void scale_sb_rgba(struct sub_bitmap *sb, struct mp_image *dst_format, + struct mp_image **out_sbi, struct mp_image **out_sba) +{ + struct mp_image *sbisrc = new_mp_image(sb->w, sb->h); + mp_image_setfmt(sbisrc, IMGFMT_BGR32); + sbisrc->planes[0] = sb->bitmap; + sbisrc->stride[0] = sb->stride; + struct mp_image *sbisrc2 = alloc_mpi(sb->dw, sb->dh, IMGFMT_BGR32); + mp_image_swscale(sbisrc2, sbisrc, SWS_BILINEAR); + + struct mp_image *sba = alloc_mpi(sb->dw, sb->dh, IMGFMT_Y8); + unpremultiply_and_split_BGR32(sbisrc2, sba); + + struct mp_image *sbi = alloc_mpi(sb->dw, sb->dh, dst_format->imgfmt); + sbi->colorspace = dst_format->colorspace; + sbi->levels = dst_format->levels; + mp_image_swscale(sbi, sbisrc2, SWS_BILINEAR); + + free_mp_image(sbisrc); + free_mp_image(sbisrc2); + + *out_sbi = sbi; + *out_sba = sba; +} + +static void draw_rgba(struct mp_draw_sub_cache **cache, struct mp_rect bb, + struct mp_image *temp, int bits, + struct sub_bitmaps *sbs) +{ + struct part *part = get_cache(cache, sbs, temp); + + for (int i = 0; i < sbs->num_parts; ++i) { + struct sub_bitmap *sb = &sbs->parts[i]; + + if (sb->w < 1 || sb->h < 1) + continue; + + struct mp_image dst; + int src_x, src_y; + if (!get_sub_area(bb, temp, sb, &dst, &src_x, &src_y)) + continue; + + struct mp_image *sbi = NULL; + struct mp_image *sba = NULL; + if (part) { + sbi = part->imgs[i].i; + sba = part->imgs[i].a; + } + + if (!(sbi && sba)) + scale_sb_rgba(sb, temp, &sbi, &sba); + + int bytes = (bits + 7) / 8; + uint8_t *alpha_p = sba->planes[0] + src_y * sba->stride[0] + src_x; + for (int p = 0; p < 3; p++) { + void *src = sbi->planes[p] + src_y * sbi->stride[p] + src_x * bytes; + blend_src_alpha(dst.planes[p], dst.stride[p], src, sbi->stride[p], + alpha_p, sba->stride[0], dst.w, dst.h, bytes); + } + + if (part) { + part->imgs[i].i = talloc_steal(part, sbi); + part->imgs[i].a = talloc_steal(part, sba); + } else { + free_mp_image(sbi); + free_mp_image(sba); + } + } +} + +static void draw_ass(struct mp_draw_sub_cache **cache, struct mp_rect bb, + struct mp_image *temp, int bits, struct sub_bitmaps *sbs) +{ + struct mp_csp_params cspar = MP_CSP_PARAMS_DEFAULTS; + cspar.colorspace.format = temp->colorspace; + cspar.colorspace.levels_in = temp->levels; + cspar.colorspace.levels_out = MP_CSP_LEVELS_PC; // RGB (libass.color) + cspar.int_bits_in = bits; + cspar.int_bits_out = 8; + + float yuv2rgb[3][4], rgb2yuv[3][4]; + mp_get_yuv2rgb_coeffs(&cspar, yuv2rgb); + mp_invert_yuv2rgb(rgb2yuv, yuv2rgb); + + for (int i = 0; i < sbs->num_parts; ++i) { + struct sub_bitmap *sb = &sbs->parts[i]; + + struct mp_image dst; + int src_x, src_y; + if (!get_sub_area(bb, temp, sb, &dst, &src_x, &src_y)) + continue; + + int r = (sb->libass.color >> 24) & 0xFF; + int g = (sb->libass.color >> 16) & 0xFF; + int b = (sb->libass.color >> 8) & 0xFF; + int a = 255 - (sb->libass.color & 0xFF); + int color_yuv[3] = {r, g, b}; + mp_map_int_color(rgb2yuv, bits, color_yuv); + + int bytes = (bits + 7) / 8; + uint8_t *alpha_p = (uint8_t *)sb->bitmap + src_y * sb->stride + src_x; + for (int p = 0; p < 3; p++) { + blend_const_alpha(dst.planes[p], dst.stride[p], color_yuv[p], + alpha_p, sb->stride, a, dst.w, dst.h, bytes); + } + } +} + +static void mp_image_crop(struct mp_image *img, struct mp_rect rc) +{ + for (int p = 0; p < img->num_planes; ++p) { + int bits = MP_IMAGE_BITS_PER_PIXEL_ON_PLANE(img, p); + img->planes[p] += + (rc.y0 >> (p ? img->chroma_y_shift : 0)) * img->stride[p] + + (rc.x0 >> (p ? img->chroma_x_shift : 0)) * bits / 8; + } + img->w = rc.x1 - rc.x0; + img->h = rc.y1 - rc.y0; + img->chroma_width = img->w >> img->chroma_x_shift; + img->chroma_height = img->h >> img->chroma_y_shift; + img->display_w = img->display_h = 0; +} + +static bool clip_to_bb(struct mp_rect bb, struct mp_rect *rc) +{ + rc->x0 = FFMAX(bb.x0, rc->x0); + rc->y0 = FFMAX(bb.y0, rc->y0); + rc->x1 = FFMIN(bb.x1, rc->x1); + rc->y1 = FFMIN(bb.y1, rc->y1); + + return rc->x1 > rc->x0 && rc->y1 > rc->y0; +} + +static void get_swscale_alignment(const struct mp_image *img, int *out_xstep, + int *out_ystep) +{ + int sx = (1 << img->chroma_x_shift); + int sy = (1 << img->chroma_y_shift); + + // Hack for IMGFMT_Y8 + if (img->chroma_x_shift == 31 && img->chroma_y_shift == 31) { + sx = 1; + sy = 1; + } + + for (int p = 0; p < img->num_planes; ++p) { + int bits = MP_IMAGE_BITS_PER_PIXEL_ON_PLANE(img, p); + // the * 2 fixes problems with writing past the destination width + while (((sx >> img->chroma_x_shift) * bits) % (SWS_MIN_BYTE_ALIGN * 8 * 2)) + sx *= 2; + } + + *out_xstep = sx; + *out_ystep = sy; +} + +static void align_bbox(int xstep, int ystep, struct mp_rect *rc) +{ + rc->x0 = rc->x0 & ~(xstep - 1); + rc->y0 = rc->y0 & ~(ystep - 1); + rc->x1 = FFALIGN(rc->x1, xstep); + rc->y1 = FFALIGN(rc->y1, ystep); +} + +static bool align_bbox_for_swscale(struct mp_image *img, struct mp_rect *rc) +{ + struct mp_rect img_rect = {0, 0, img->w, img->h}; + // Get rid of negative coordinates + if (!clip_to_bb(img_rect, rc)) + return false; + int xstep, ystep; + get_swscale_alignment(img, &xstep, &ystep); + align_bbox(xstep, ystep, rc); + return clip_to_bb(img_rect, rc); +} + +// Try to find best/closest YUV 444 format for imgfmt +static void get_closest_y444_format(int imgfmt, int *out_format, int *out_bits) +{ +#ifdef ACCURATE + struct mp_image tmp = {0}; + mp_image_setfmt(&tmp, imgfmt); + if (tmp.flags & MP_IMGFLAG_YUV) { + int bits; + if (mp_get_chroma_shift(imgfmt, NULL, NULL, &bits)) { + switch (bits) { + case 8: + *out_format = IMGFMT_444P; + *out_bits = 8; + return; + case 9: + *out_format = IMGFMT_444P9; + *out_bits = 9; + return; + case 10: + *out_format = IMGFMT_444P10; + *out_bits = 10; + return; + } + } + } + *out_format = IMGFMT_444P16; + *out_bits = 16; +#else + *out_format = IMGFMT_444P; + *out_bits = 8; +#endif +} + +static struct part *get_cache(struct mp_draw_sub_cache **cache, + struct sub_bitmaps *sbs, struct mp_image *format) +{ + if (cache && !*cache) + *cache = talloc_zero(NULL, struct mp_draw_sub_cache); + + struct part *part = NULL; + + bool use_cache = sbs->format == SUBBITMAP_RGBA; + if (cache && use_cache) { + part = (*cache)->parts[sbs->render_index]; + if (part) { + if (part->bitmap_pos_id != sbs->bitmap_pos_id + || part->imgfmt != format->imgfmt + || part->colorspace != format->colorspace + || part->levels != format->levels) + { + talloc_free(part); + part = NULL; + } + } + if (!part) { + part = talloc(*cache, struct part); + *part = (struct part) { + .bitmap_pos_id = sbs->bitmap_pos_id, + .num_imgs = sbs->num_parts, + .imgfmt = format->imgfmt, + .levels = format->levels, + .colorspace = format->colorspace, + }; + part->imgs = talloc_zero_array(part, struct sub_cache, + part->num_imgs); + } + assert(part->num_imgs == sbs->num_parts); + (*cache)->parts[sbs->render_index] = part; + } + + return part; +} + +// Return area of intersection between target and sub-bitmap as cropped image +static bool get_sub_area(struct mp_rect bb, struct mp_image *temp, + struct sub_bitmap *sb, struct mp_image *out_area, + int *out_src_x, int *out_src_y) +{ + // coordinates are relative to the bbox + struct mp_rect dst = {sb->x - bb.x0, sb->y - bb.y0}; + dst.x1 = dst.x0 + sb->dw; + dst.y1 = dst.y0 + sb->dh; + if (!clip_to_bb((struct mp_rect){0, 0, temp->w, temp->h}, &dst)) + return false; + + *out_src_x = (dst.x0 - sb->x) + bb.x0; + *out_src_y = (dst.y0 - sb->y) + bb.y0; + *out_area = *temp; + mp_image_crop(out_area, dst); + + return true; +} + +// cache: if not NULL, the function will set *cache to a talloc-allocated cache +// containing scaled versions of sbs contents - free the cache with +// talloc_free() +void mp_draw_sub_bitmaps(struct mp_draw_sub_cache **cache, struct mp_image *dst, + struct sub_bitmaps *sbs) +{ + assert(mp_draw_sub_formats[sbs->format]); + if (!mp_sws_supported_format(dst->imgfmt)) + return; + + int format, bits; + get_closest_y444_format(dst->imgfmt, &format, &bits); + + struct mp_rect bb; + if (!sub_bitmaps_bb(sbs, &bb)) + return; + + if (!align_bbox_for_swscale(dst, &bb)) + return; + + struct mp_image *temp; + struct mp_image dst_region = *dst; + mp_image_crop(&dst_region, bb); + if (dst->imgfmt == format) { + temp = &dst_region; + } else { + temp = alloc_mpi(bb.x1 - bb.x0, bb.y1 - bb.y0, format); + // temp is always YUV, dst_region not + // reduce amount of conversions in YUV case (upsampling/shifting only) + if (dst_region.flags & MP_IMGFLAG_YUV) { + temp->colorspace = dst_region.colorspace; + temp->levels = dst_region.levels; + } + mp_image_swscale(temp, &dst_region, SWS_POINT); // chroma up + } + + if (sbs->format == SUBBITMAP_RGBA) { + draw_rgba(cache, bb, temp, bits, sbs); + } else if (sbs->format == SUBBITMAP_LIBASS) { + draw_ass(cache, bb, temp, bits, sbs); + } + + if (temp != &dst_region) { + mp_image_swscale(&dst_region, temp, SWS_AREA); // chroma down + free_mp_image(temp); + } +} + +// vim: ts=4 sw=4 et tw=80 diff --git a/sub/draw_bmp.h b/sub/draw_bmp.h new file mode 100644 index 0000000000..489e91f666 --- /dev/null +++ b/sub/draw_bmp.h @@ -0,0 +1,17 @@ +#ifndef MPLAYER_DRAW_BMP_H +#define MPLAYER_DRAW_BMP_H + +#include "sub/sub.h" + +struct mp_image; +struct sub_bitmaps; +struct mp_csp_details; +struct mp_draw_sub_cache; +void mp_draw_sub_bitmaps(struct mp_draw_sub_cache **cache, struct mp_image *dst, + struct sub_bitmaps *sbs); + +extern const bool mp_draw_sub_formats[SUBBITMAP_COUNT]; + +#endif /* MPLAYER_DRAW_BMP_H */ + +// vim: ts=4 sw=4 et tw=80 diff --git a/sub/find_subfiles.c b/sub/find_subfiles.c index b073a722c6..2e705bd4d1 100644 --- a/sub/find_subfiles.c +++ b/sub/find_subfiles.c @@ -12,6 +12,7 @@ #include "mpcommon.h" #include "sub/find_subfiles.h" #include "sub/sub.h" +#include "sub/subreader.h" static struct bstr strip_ext(struct bstr str) { diff --git a/sub/img_convert.c b/sub/img_convert.c new file mode 100644 index 0000000000..aa5c89401a --- /dev/null +++ b/sub/img_convert.c @@ -0,0 +1,89 @@ +/* + * This file is part of mplayer. + * + * mplayer is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * mplayer is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with mplayer. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <string.h> +#include <assert.h> + +#include <libavutil/mem.h> +#include <libavutil/common.h> + +#include "talloc.h" + +#include "img_convert.h" +#include "sub.h" +#include "spudec.h" +#include "libmpcodecs/img_format.h" +#include "libmpcodecs/mp_image.h" +#include "libmpcodecs/sws_utils.h" + +struct osd_conv_cache { + struct sub_bitmap part; + struct sub_bitmap *parts; +}; + +struct osd_conv_cache *osd_conv_cache_new(void) +{ + return talloc_zero(NULL, struct osd_conv_cache); +} + +static void rgba_to_premultiplied_rgba(uint32_t *colors, size_t count) +{ + for (int n = 0; n < count; n++) { + uint32_t c = colors[n]; + int b = c & 0xFF; |