summaryrefslogtreecommitdiffstats
path: root/sub
diff options
context:
space:
mode:
Diffstat (limited to 'sub')
-rw-r--r--sub/ass_mp.c42
-rw-r--r--sub/ass_mp.h7
-rw-r--r--sub/dec_sub.c26
-rw-r--r--sub/dec_sub.h42
-rw-r--r--sub/img_convert.c280
-rw-r--r--sub/img_convert.h18
-rw-r--r--sub/osd_dummy.c22
-rw-r--r--sub/osd_libass.c219
-rw-r--r--sub/sd.h2
-rw-r--r--sub/sd_ass.c22
-rw-r--r--sub/sd_lavc.c130
-rw-r--r--sub/spudec.c151
-rw-r--r--sub/spudec.h6
-rw-r--r--sub/sub.c460
-rw-r--r--sub/sub.h226
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);
+}
diff --git a/sub/sd.h b/sub/sd.h
index 7a0740f823..b286d3691b 100644
--- a/sub/sd.h
+++ b/sub/sd.h
@@ -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_