diff options
Diffstat (limited to 'sub')
-rw-r--r-- | sub/ass_mp.c | 42 | ||||
-rw-r--r-- | sub/ass_mp.h | 7 | ||||
-rw-r--r-- | sub/dec_sub.c | 26 | ||||
-rw-r--r-- | sub/dec_sub.h | 42 | ||||
-rw-r--r-- | sub/img_convert.c | 280 | ||||
-rw-r--r-- | sub/img_convert.h | 18 | ||||
-rw-r--r-- | sub/osd_dummy.c | 22 | ||||
-rw-r--r-- | sub/osd_libass.c | 219 | ||||
-rw-r--r-- | sub/sd.h | 2 | ||||
-rw-r--r-- | sub/sd_ass.c | 22 | ||||
-rw-r--r-- | sub/sd_lavc.c | 130 | ||||
-rw-r--r-- | sub/spudec.c | 151 | ||||
-rw-r--r-- | sub/spudec.h | 6 | ||||
-rw-r--r-- | sub/sub.c | 460 | ||||
-rw-r--r-- | sub/sub.h | 226 |
15 files changed, 1048 insertions, 605 deletions
diff --git a/sub/ass_mp.c b/sub/ass_mp.c index 908a552acf..65b34d0a18 100644 --- a/sub/ass_mp.c +++ b/sub/ass_mp.c @@ -228,7 +228,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_eosd_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 +243,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 +278,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; + res->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 = res->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..4ca43dfb2e 100644 --- a/sub/ass_mp.h +++ b/sub/ass_mp.h @@ -42,10 +42,15 @@ 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_eosd_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 */ diff --git a/sub/dec_sub.c b/sub/dec_sub.c index 4a048b27a6..09d9989494 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 sub_render_params *params, + 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, params, 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..0c5c1ab7ee 100644 --- a/sub/dec_sub.h +++ b/sub/dec_sub.h @@ -1,39 +1,22 @@ #ifndef MPLAYER_DEC_SUB_H #define MPLAYER_DEC_SUB_H +#include <stdbool.h> +#include <stdint.h> + +#include "sub.h" + struct sh_sub; -struct osd_state; struct ass_track; +struct MPOpts *opts; -enum sub_bitmap_type { - SUBBITMAP_EMPTY, - SUBBITMAP_LIBASS, - SUBBITMAP_RGBA, +struct sub_render_params { + double pts; + struct mp_eosd_res dim; + double normal_scale; + double vsfilter_scale; }; -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; - -typedef struct sub_bitmaps { - enum sub_bitmap_type type; - - 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; - static inline bool is_text_sub(int type) { return type == 't' || type == 'm' || type == 'a'; @@ -41,7 +24,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 sub_render_params *params, + 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/img_convert.c b/sub/img_convert.c new file mode 100644 index 0000000000..888380cf70 --- /dev/null +++ b/sub/img_convert.c @@ -0,0 +1,280 @@ +/* + * 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" + +struct osd_conv_cache { + struct sub_bitmap part; + struct sub_bitmap *parts; + // for osd_conv_cache_alloc_old_p() (SUBBITMAP_PLANAR) + int allocated, stride; + struct old_osd_planar bmp; + // for osd_conv_idx_to_old_p(), a spudec.c handle + void *spudec; +}; + +static int osd_conv_cache_destroy(void *p) +{ + struct osd_conv_cache *c = p; + av_free(c->bmp.bitmap); + av_free(c->bmp.alpha); + if (c->spudec) + spudec_free(c->spudec); + return 0; +} + +struct osd_conv_cache *osd_conv_cache_new(void) +{ + struct osd_conv_cache *c = talloc_zero(NULL, struct osd_conv_cache); + talloc_set_destructor(c, &osd_conv_cache_destroy); + return c; +} + +// allocates/enlarges the alpha/bitmap buffer +static void osd_conv_cache_alloc_old_p(struct osd_conv_cache *c, int w, int h) +{ + assert(w > 0 && h > 0); + c->stride = (w + 7) & (~7); + int len = c->stride * h; + if (c->allocated < len) { + av_free(c->bmp.bitmap); + av_free(c->bmp.alpha); + c->allocated = len; + c->bmp.bitmap = av_malloc(len); + c->bmp.alpha = av_malloc(len); + } + memset(c->bmp.bitmap, sub_bg_color, len); + memset(c->bmp.alpha, sub_bg_alpha, len); + c->part = (struct sub_bitmap) { + .bitmap = &c->bmp, + .stride = c->stride, + .w = w, .h = h, + .dw = w, .dh = h, + }; +} + +static void draw_alpha_ass_to_old(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 render_ass_to_old(unsigned char *a, unsigned char *i, + size_t stride, int x, int y, + struct sub_bitmaps *imgs) +{ + for (int n = 0; n < imgs->num_parts; n++) { + struct sub_bitmap *p = &imgs->parts[n]; + draw_alpha_ass_to_old(p->bitmap, p->w, p->h, p->stride, a, i, stride, + x + p->x, y + p->y, p->libass.color); + } +} + +// SUBBITMAP_LIBASS -> SUBBITMAP_OLD_PLANAR +bool osd_conv_ass_to_old_p(struct osd_conv_cache *c, struct sub_bitmaps *imgs) +{ + struct sub_bitmaps src = *imgs; + if (src.format != SUBBITMAP_LIBASS || src.scaled) + return false; + + imgs->format = SUBBITMAP_OLD_PLANAR; + imgs->num_parts = 0; + imgs->parts = NULL; + + int x1, y1, x2, y2; + if (!sub_bitmaps_bb(&src, &x1, &y1, &x2, &y2)) + return true; + + osd_conv_cache_alloc_old_p(c, x2 - x1, y2 - y1); + + render_ass_to_old(c->bmp.alpha, c->bmp.bitmap, c->stride, -x1, -y1, &src); + + c->part.x = x1; + c->part.y = y1; + + imgs->parts = &c->part; + imgs->num_parts = 1; + return true; +} + +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; + int g = (c >> 8) & 0xFF; + int r = (c >> 16) & 0xFF; + int a = (c >> 24) & 0xFF; + b = b * a / 255; + g = g * a / 255; + r = r * a / 255; + colors[n] = b | (g << 8) | (r << 16) | (a << 24); + } +} + +bool osd_conv_idx_to_rgba(struct osd_conv_cache *c, struct sub_bitmaps *imgs) +{ + struct sub_bitmaps src = *imgs; + if (src.format != SUBBITMAP_INDEXED) + return false; + + imgs->format = SUBBITMAP_RGBA; + talloc_free(c->parts); + imgs->parts = c->parts = talloc_array(c, struct sub_bitmap, src.num_parts); + + for (int n = 0; n < src.num_parts; n++) { + struct sub_bitmap *d = &imgs->parts[n]; + struct sub_bitmap *s = &src.parts[n]; + struct osd_bmp_indexed sb = *(struct osd_bmp_indexed *)s->bitmap; + + rgba_to_premultiplied_rgba(sb.palette, 256); + + *d = *s; + d->stride = s->w * 4; + d->bitmap = talloc_size(c->parts, s->h * d->stride); + + uint32_t *outbmp = d->bitmap; + for (int y = 0; y < s->h; y++) { + uint8_t *inbmp = sb.bitmap + y * s->stride; + for (int x = 0; x < s->w; x++) + *outbmp++ = sb.palette[*inbmp++]; + } + } + return true; +} + +bool osd_conv_idx_to_old_p(struct osd_conv_cache *c, struct sub_bitmaps *imgs, + int screen_w, int screen_h) +{ + struct sub_bitmaps src = *imgs; + if (src.format != SUBBITMAP_INDEXED) + return false; + + imgs->format = SUBBITMAP_OLD_PLANAR; + imgs->num_parts = 0; + imgs->parts = NULL; + if (src.num_parts == 0) + return true; + + // assume they are all evenly scaled (and size 0 is not possible) + // could put more effort into it to reduce rounding errors, but it doesn't + // make much sense anyway + struct sub_bitmap *s0 = &src.parts[0]; + double scale_x = (double)s0->w / s0->dw; + double scale_y = (double)s0->h / s0->dh; + double scale = FFMIN(scale_x, scale_y); + + int xmin, ymin, xmax, ymax; + + xmin = ymin = INT_MAX; + xmax = ymax = INT_MIN; + for (int n = 0; n < src.num_parts; n++) { + struct sub_bitmap *s = &src.parts[n]; + int sx = s->x * scale; + int sy = s->y * scale; + xmin = FFMIN(xmin, sx); + ymin = FFMIN(ymin, sy); + xmax = FFMAX(xmax, sx + s->w); + ymax = FFMAX(ymax, sy + s->h); + } + + int w = xmax - xmin; + int h = ymax - ymin; + + struct spu_packet_t *packet = spudec_packet_create(xmin, ymin, w, h); + if (!packet) + return false; + spudec_packet_clear(packet); + for (int n = 0; n < src.num_parts; n++) { + struct sub_bitmap *s = &src.parts[n]; + struct osd_bmp_indexed *sb = s->bitmap; + int sx = s->x * scale; + int sy = s->y * scale; + assert(sx >= xmin); + assert(sy >= ymin); + assert(sx - xmin + s->w <= w); + assert(sy - ymin + s->h <= h); + // assumes sub-images are not overlapping + spudec_packet_fill(packet, sb->bitmap, s->stride, sb->palette, + sx - xmin, sy - ymin, s->w, s->h); + } + if (!c->spudec) + c->spudec = spudec_new_scaled(NULL, 0, 0, NULL, 0); + spudec_packet_send(c->spudec, packet, MP_NOPTS_VALUE, MP_NOPTS_VALUE); + spudec_set_res(c->spudec, screen_w * scale, screen_h * scale); + spudec_heartbeat(c->spudec, 0); + spudec_get_bitmap(c->spudec, screen_w, screen_h, imgs); + imgs->render_index = src.render_index; + imgs->bitmap_id = src.bitmap_id; + imgs->bitmap_pos_id = src.bitmap_pos_id; + return true; +} diff --git a/sub/img_convert.h b/sub/img_convert.h new file mode 100644 index 0000000000..ac766fb0ed --- /dev/null +++ b/sub/img_convert.h @@ -0,0 +1,18 @@ +#ifndef MPLAYER_SUB_IMG_CONVERT_H +#define MPLAYER_SUB_IMG_CONVERT_H + +#include <stdbool.h> + +struct osd_conv_cache; +struct sub_bitmaps; + +struct osd_conv_cache *osd_conv_cache_new(void); + +// These functions convert from one OSD format to another. On success, they copy +// the converted image data into c, and change imgs to point to the data. +bool osd_conv_ass_to_old_p(struct osd_conv_cache *c, struct sub_bitmaps *imgs); +bool osd_conv_idx_to_rgba(struct osd_conv_cache *c, struct sub_bitmaps *imgs); +bool osd_conv_idx_to_old_p(struct osd_conv_cache *c, struct sub_bitmaps *imgs, + int screen_w, int screen_h); + +#endif diff --git a/sub/osd_dummy.c b/sub/osd_dummy.c index d869fe16c8..782ce21942 100644 --- a/sub/osd_dummy.c +++ b/sub/osd_dummy.c @@ -6,18 +6,6 @@ #include "talloc.h" #include "sub.h" -void vo_update_text_osd(struct osd_state *osd, mp_osd_obj_t *obj) -{ -} - -void vo_update_text_progbar(struct osd_state *osd, mp_osd_obj_t *obj) -{ -} - -void vo_update_text_sub(struct osd_state *osd, mp_osd_obj_t *obj) -{ -} - void osd_init_backend(struct osd_state *osd) { } @@ -26,14 +14,12 @@ void osd_destroy_backend(struct osd_state *osd) { } -void osd_font_invalidate(void) -{ -} - -void osd_font_load(struct osd_state *osd) +void osd_get_function_sym(char *buffer, size_t buffer_size, int osd_function) { } -void osd_get_function_sym(char *buffer, size_t buffer_size, int osd_function) +void osd_object_get_bitmaps(struct osd_state *osd, struct osd_object *obj, + struct sub_bitmaps *out_imgs) { + *out_imgs = (struct sub_bitmaps) {0}; } diff --git a/sub/osd_libass.c b/sub/osd_libass.c index de9f31b2cb..d77c0d1af2 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,119 +52,18 @@ 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; @@ -193,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; @@ -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]; @@ -252,25 +155,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 +191,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)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; 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 +222,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 +240,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 +251,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->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); +} @@ -2,6 +2,7 @@ #define MPLAYER_SD_H struct osd_state; +struct sub_render_params; struct sh_sub; struct sub_bitmaps; @@ -10,6 +11,7 @@ struct sd_functions { void (*decode)(struct sh_sub *sh, struct osd_state *osd, void *data, int data_len, double pts, double duration); void (*get_bitmaps)(struct sh_sub *sh, struct osd_state *osd, + struct sub_render_params *params, struct sub_bitmaps *res); void (*reset)(struct sh_sub *sh, struct osd_state *osd); void (*switch_off)(struct sh_sub *sh, struct osd_state *osd); diff --git a/sub/sd_ass.c b/sub/sd_ass.c index fcedc9fec5..a5e23d74da 100644 --- a/sub/sd_ass.c +++ b/sub/sd_ass.c @@ -28,6 +28,7 @@ #include "mp_msg.h" #include "libmpdemux/stheader.h" #include "sub.h" +#include "dec_sub.h" #include "ass_mp.h" #include "sd.h" #include "subassconvert.h" @@ -36,6 +37,7 @@ struct sd_ass_priv { struct ass_track *ass_track; bool vsfilter_aspect; bool incomplete_ |