summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile1
-rw-r--r--libvo/video_out.h1
-rw-r--r--libvo/vo_gl3.c6
-rw-r--r--sub/ass_mp.c35
-rw-r--r--sub/ass_mp.h5
-rw-r--r--sub/dec_sub.h13
-rw-r--r--sub/img_convert.c214
-rw-r--r--sub/img_convert.h16
-rw-r--r--sub/osd_dummy.c22
-rw-r--r--sub/osd_libass.c195
-rw-r--r--sub/sd_ass.c36
-rw-r--r--sub/spudec.c40
-rw-r--r--sub/spudec.h3
-rw-r--r--sub/sub.c453
-rw-r--r--sub/sub.h83
15 files changed, 600 insertions, 523 deletions
diff --git a/Makefile b/Makefile
index c93fa6b31c..27aa1997dd 100644
--- a/Makefile
+++ b/Makefile
@@ -266,6 +266,7 @@ SRCS_COMMON = asxparser.c \
sub/sd_lavc.c \
sub/spudec.c \
sub/sub.c \
+ sub/img_convert.c \
sub/subassconvert.c \
sub/subreader.c \
sub/vobsub.c \
diff --git a/libvo/video_out.h b/libvo/video_out.h
index 2cd314f281..cdda6ec79f 100644
--- a/libvo/video_out.h
+++ b/libvo/video_out.h
@@ -66,6 +66,7 @@ enum mp_voctrl {
VOCTRL_BORDER,
VOCTRL_DRAW_EOSD,
VOCTRL_GET_EOSD_RES, // struct mp_eosd_res
+ VOCTRL_QUERY_EOSD_FORMAT, // int
VOCTRL_SET_DEINTERLACE,
VOCTRL_GET_DEINTERLACE,
diff --git a/libvo/vo_gl3.c b/libvo/vo_gl3.c
index 08f1514094..2af63700b4 100644
--- a/libvo/vo_gl3.c
+++ b/libvo/vo_gl3.c
@@ -1851,6 +1851,10 @@ static int control(struct vo *vo, uint32_t request, void *data)
r->mt = r->mb = p->border_y;
return VO_TRUE;
}
+ case VOCTRL_QUERY_EOSD_FORMAT: {
+ int *p = data;
+ return osd_to_gl_formats[*p].shader ? VO_TRUE : VO_NOTIMPL;
+ }
case VOCTRL_ONTOP:
if (!p->glctx->ontop)
break;
@@ -2366,7 +2370,7 @@ const struct vo_driver video_out_gl3 = {
.config = config,
.control = control,
.draw_slice = draw_slice,
- .draw_osd = emulate_draw_osd,
+ .draw_osd = draw_osd_with_eosd,
.flip_page = flip_page,
.check_events = check_events,
.uninit = uninit,
diff --git a/sub/ass_mp.c b/sub/ass_mp.c
index 202664578b..5766a847f8 100644
--- a/sub/ass_mp.c
+++ b/sub/ass_mp.c
@@ -264,6 +264,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..805e9d7310 100644
--- a/sub/ass_mp.h
+++ b/sub/ass_mp.h
@@ -46,6 +46,11 @@ void mp_ass_configure(ASS_Renderer *priv, struct MPOpts *opts,
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.h b/sub/dec_sub.h
index df6aaf9b91..9c75506c4c 100644
--- a/sub/dec_sub.h
+++ b/sub/dec_sub.h
@@ -4,21 +4,26 @@
#include <stdbool.h>
#include <stdint.h>
-#define MAX_OSD_PARTS 8
-
struct sh_sub;
struct osd_state;
struct ass_track;
enum sub_bitmap_format {
- SUBBITMAP_EMPTY,
+ SUBBITMAP_EMPTY = 0,// no bitmaps; always has num_parts==0
SUBBITMAP_LIBASS, // A8, with a per-surface blend color (libass.color)
- SUBBITMAP_RGBA, // B8G8R8A8
+ SUBBITMAP_RGBA, // B8G8R8A8, can be scaled
SUBBITMAP_OLD, // I8A8 (monochrome), premultiplied alpha
+ SUBBITMAP_OLD_PLANAR, // like previous, but bitmap points to old_osd_planar
SUBBITMAP_COUNT
};
+// For SUBBITMAP_OLD_PANAR
+struct old_osd_planar {
+ unsigned char *bitmap;
+ unsigned char *alpha;
+};
+
typedef struct mp_eosd_res {
int w, h; // screen dimensions, including black borders
int mt, mb, ml, mr; // borders (top, bottom, left, right)
diff --git a/sub/img_convert.c b/sub/img_convert.c
new file mode 100644
index 0000000000..38a367253c
--- /dev/null
+++ b/sub/img_convert.c
@@ -0,0 +1,214 @@
+/*
+ * 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"
+
+struct osd_conv_cache {
+ struct sub_bitmap part;
+ // for osd_conv_cache_alloc_old_p() (SUBBITMAP_PLANAR)
+ int allocated, stride;
+ struct old_osd_planar bmp;
+ // for osd_conv_cache_alloc_old() (SUBBITMAP_OLD_PLANAR)
+ unsigned char *packed;
+};
+
+static int osd_conv_cache_destroy(void *p)
+{
+ struct osd_conv_cache *c = p;
+ av_free(c->bmp.bitmap);
+ av_free(c->bmp.alpha);
+ 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 osd_conv_cache_alloc_old(struct osd_conv_cache *c, int w, int h)
+{
+ size_t size = talloc_get_size(c->packed);
+ size_t new_size = w * 2 * h;
+ if (new_size > size)
+ c->packed = talloc_realloc(c, c->packed, unsigned char, new_size);
+ c->part = (struct sub_bitmap) {
+ .bitmap = c->packed,
+ .stride = w * 2,
+ .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;
+}
+
+// SUBBITMAP_OLD_PLANAR -> SUBBITMAP_OLD
+bool osd_conv_old_p_to_old(struct osd_conv_cache *c, struct sub_bitmaps *imgs)
+{
+ struct sub_bitmaps src = *imgs;
+ if (src.format != SUBBITMAP_OLD_PLANAR || src.num_parts > 1)
+ return false;
+
+ imgs->format = SUBBITMAP_OLD;
+ imgs->num_parts = 0;
+ imgs->parts = NULL;
+
+ if (src.num_parts == 0)
+ return true;
+
+ struct sub_bitmap *s = &src.parts[0];
+ struct old_osd_planar *p = s->bitmap;
+
+ osd_conv_cache_alloc_old(c, s->w, s->h);
+
+ for (int y = 0; y < s->h; y++) {
+ unsigned char *y_src = p->bitmap + s->stride * y;
+ unsigned char *y_srca = p->alpha + s->stride * y;
+ unsigned char *cur = c->packed + y * s->w * 2;
+ for (int x = 0; x < s->w; x++) {
+ cur[x*2+0] = y_src[x];
+ cur[x*2+1] = -y_srca[x];
+ }
+ }
+
+ c->part.x = s->x;
+ c->part.y = s->y;
+
+ imgs->parts = &c->part;
+ imgs->num_parts = 1;
+ return true;
+}
diff --git a/sub/img_convert.h b/sub/img_convert.h
new file mode 100644
index 0000000000..c40a8de2e4
--- /dev/null
+++ b/sub/img_convert.h
@@ -0,0 +1,16 @@
+#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_old_p_to_old(struct osd_conv_cache *c, struct sub_bitmaps *imgs);
+bool osd_conv_ass_to_old_p(struct osd_conv_cache *c, struct sub_bitmaps *imgs);
+
+#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 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);
+}
diff --git a/sub/sd_ass.c b/sub/sd_ass.c
index aa190ee4ac..478b1c96a9 100644
--- a/sub/sd_ass.c
+++ b/sub/sd_ass.c
@@ -141,39 +141,9 @@ static void get_bitmaps(struct sh_sub *sh, struct osd_state *osd,
ASS_Renderer *renderer = osd->ass_renderer;
mp_ass_configure(renderer, opts, &osd->dim, osd->unscaled);
ass_set_aspect_ratio(renderer, scale, 1);
- int changed;
- res->imgs = ass_render_frame(renderer, ctx->ass_track,
- osd->sub_pts * 1000 + .5, &changed);
- if (changed == 2)
- res->bitmap_id = ++res->bitmap_pos_id;
- else if (changed)
- res->bitmap_pos_id++;
- res->format = SUBBITMAP_LIBASS;
-
- int num_parts = 0;
- int num_parts_alloc = MP_TALLOC_ELEMS(ctx->parts);
- struct ass_image *img = res->imgs;
- while (img) {
- if (img->w == 0 || img->h == 0)
- continue;
- if (num_parts >= num_parts_alloc) {
- num_parts_alloc = FFMAX(num_parts_alloc * 2, 32);
- ctx->parts = talloc_realloc(ctx, ctx->parts, struct sub_bitmap,
- num_parts_alloc);
- }
- struct sub_bitmap *p = &ctx->parts[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;
- img = img->next;
- num_parts++;
- }
- res->parts = ctx->parts;
- res->num_parts = num_parts;
+ mp_ass_render_frame(renderer, ctx->ass_track, osd->sub_pts * 1000 + .5,
+ &ctx->parts, res);
+ talloc_steal(ctx, ctx->parts);
}
static void reset(struct sh_sub *sh, struct osd_state *osd)
diff --git a/sub/spudec.c b/sub/spudec.c
index 47e1676e2e..a58df60b17 100644
--- a/sub/spudec.c
+++ b/sub/spudec.c
@@ -34,6 +34,7 @@
#include <unistd.h>
#include <string.h>
#include <math.h>
+#include <assert.h>
#include <libavutil/common.h>
#include <libavutil/intreadwrite.h>
@@ -44,6 +45,7 @@
#include "spudec.h"
#include "vobsub.h"
+#include "sub.h"
#include "mpcommon.h"
/* Valid values for spu_aamode:
@@ -57,7 +59,6 @@
int spu_aamode = 3;
int spu_alignment = -1;
float spu_gaussvar = 1.0;
-extern int sub_pos;
typedef struct spu_packet_t packet_t;
struct spu_packet_t {
@@ -123,6 +124,9 @@ typedef struct {
unsigned int is_forced_sub; /* true if current subtitle is a forced subtitle */
struct palette_crop_cache palette_crop_cache;
+
+ struct sub_bitmap borrowed_sub_part;
+ struct old_osd_planar borrowed_sub_image;
} spudec_handle_t;
static void spudec_queue_packet(spudec_handle_t *this, packet_t *packet)
@@ -722,6 +726,40 @@ void spudec_set_forced_subs_only(void * const this, const unsigned int flag)
}
}
+static void get_data(void *ctx, int x0,int y0, int w,int h, unsigned char* src,
+ unsigned char *srca, int stride)
+{
+ struct sub_bitmaps *bmp = ctx;
+ assert(bmp->num_parts == 0);
+ bmp->num_parts = 1;
+ struct sub_bitmap *s = &bmp->parts[0];
+ struct old_osd_planar *p = s->bitmap;
+ // We know that the data stays valid until the next SPU related call
+ p->bitmap = src;
+ p->alpha = srca;
+ *s = (struct sub_bitmap) {
+ .bitmap = p, .stride = stride,
+ .x = x0, .y = y0,
+ .w = w, .h = h,
+ .dw = w, .dh = h,
+ };
+}
+
+void spudec_get_bitmap(void *this, int w, int h, struct sub_bitmaps *res)
+{
+ spudec_handle_t *spu = this;
+ *res = (struct sub_bitmaps) {
+ .format = SUBBITMAP_OLD_PLANAR,
+ .parts = &spu->borrowed_sub_part,
+ };
+ res->parts[0].bitmap = &spu->borrowed_sub_image;
+ if (w == -1 && h == -1) {
+ spudec_draw(this, get_data, res);
+ } else {
+ spudec_draw_scaled(this, w, h, get_data, res);
+ }
+}
+
void spudec_draw(void *this, void (*draw_alpha)(void *ctx, int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride), void *ctx)
{
spudec_handle_t *spu = this;
diff --git a/sub/spudec.h b/sub/spudec.h
index 6104ad7228..2e2542128a 100644
--- a/sub/spudec.h
+++ b/sub/spudec.h
@@ -21,10 +21,13 @@
#include <stdint.h>
+struct sub_bitmaps;
+
void spudec_heartbeat(void *this, unsigned int pts100);
void spudec_assemble(void *this, unsigned char *packet, unsigned int len, int pts100);
void spudec_draw(void *this, void (*draw_alpha)(void *ctx, int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride), void *ctx);
void spudec_draw_scaled(void *this, unsigned int dxs, unsigned int dys, void (*draw_alpha)(void *ctx, int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride), void *ctx);
+void spudec_get_bitmap(void *this, int w, int h, struct sub_bitmaps *res);
int spudec_apply_palette_crop(void *this, uint32_t palette, int sx, int ex, int sy, int ey);
void *spudec_new_scaled(unsigned int *palette, unsigned int frame_width, unsigned int frame_height, uint8_t *extradata, int extradata_len);
void *spudec_new(unsigned int *palette);
diff --git a/sub/sub.c b/sub/sub.c
index 8b89ca497c..3f1b08c185 100644
--- a/sub/sub.c
+++ b/sub/sub.c
@@ -21,7 +21,6 @@
#include <string.h>
#include <assert.h>
-#include <libavutil/mem.h>
#include <libavutil/common.h>
#include "config.h"
@@ -37,6 +36,7 @@
#include "libvo/video_out.h"
#include "sub.h"
#include "sub/ass_mp.h"
+#include "img_convert.h"
#include "spudec.h"
@@ -86,185 +86,57 @@ float font_factor = 0.75;
float sub_delay = 0;
float sub_fps = 0;
-// allocates/enlarges the alpha/bitmap buffer
-void osd_alloc_buf(mp_osd_obj_t* obj)
-{
- int len;
- if (obj->bbox.x2 < obj->bbox.x1) obj->bbox.x2 = obj->bbox.x1;
- if (obj->bbox.y2 < obj->bbox.y1) obj->bbox.y2 = obj->bbox.y1;
- obj->stride = ((obj->bbox.x2-obj->bbox.x1)+7)&(~7);
- len = obj->stride*(obj->bbox.y2-obj->bbox.y1);
- if (obj->allocated<len) {
- obj->allocated = len;
- av_free(obj->bitmap_buffer);
- av_free(obj->alpha_buffer);
- obj->bitmap_buffer = av_malloc(len);
- obj->alpha_buffer = av_malloc(len);
- }
- memset(obj->bitmap_buffer, sub_bg_color, len);
- memset(obj->alpha_buffer, sub_bg_alpha, len);
-}
-
-// renders the buffer
-void vo_draw_text_from_buffer(mp_osd_obj_t* obj,void (*draw_alpha)(void *ctx, int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride), void *ctx)
-{
- if (obj->allocated > 0) {
- draw_alpha(ctx,
- obj->bbox.x1,obj->bbox.y1,
- obj->bbox.x2-obj->bbox.x1,
- obj->bbox.y2-obj->bbox.y1,
- obj->bitmap_buffer,
- obj->alpha_buffer,
- obj->stride);
- }
-}
-
-inline static void vo_update_spudec_sub(struct osd_state *osd, mp_osd_obj_t* obj)
-{
- unsigned int bbox[4];
- spudec_calc_bbox(vo_spudec, osd->w, osd->h, bbox);
- obj->bbox.x1 = bbox[0];
- obj->bbox.x2 = bbox[1];
- obj->bbox.y1 = bbox[2];
- obj->bbox.y2 = bbox[3];
- obj->flags |= OSDFLAG_BBOX;
-}
-
-inline static void vo_draw_spudec_sub(mp_osd_obj_t* obj, void (*draw_alpha)(void *ctx, int x0, int y0, int w, int h, unsigned char* src, unsigned char* srca, int stride), void *ctx)
-{
- spudec_draw_scaled(vo_spudec, obj->dxs, obj->dys, draw_alpha, ctx);
-}
-
void *vo_spudec=NULL;
void *vo_vobsub=NULL;
-mp_osd_obj_t* vo_osd_list=NULL;
-
-static mp_osd_obj_t* new_osd_obj(int type){
- mp_osd_obj_t* osd=malloc(sizeof(mp_osd_obj_t));
- memset(osd,0,sizeof(mp_osd_obj_t));
- osd->next=vo_osd_list;
- vo_osd_list=osd;
- osd->type=type;
- osd->alpha_buffer = NULL;
- osd->bitmap_buffer = NULL;
- osd->allocated = -1;
- return osd;
-}
+static struct osd_state *global_osd;
-void osd_free(struct osd_state *osd)
-{
- osd_destroy_backend(osd);
- mp_osd_obj_t* obj=vo_osd_list;
- while(obj){
- mp_osd_obj_t* next=obj->next;
- av_free(obj->alpha_buffer);
- av_free(obj->bitmap_buffer);
- free(obj);
- obj=next;
- }
- vo_osd_list=NULL;
- talloc_free(osd);
-}
-static int osd_update_ext(struct osd_state *osd, int dxs, int dys,
- int left_border, int top_border, int right_border,
- int bottom_border, int orig_w, int orig_h)
+static void osd_update_ext(struct osd_state *osd, struct mp_eosd_res res)
{
- struct MPOpts *opts = osd->opts;
- mp_osd_obj_t* obj=vo_osd_list;
- int chg=0;
-
- osd->w = dxs;
- osd->h = dys;
-
- osd_font_load(osd);
-
- while(obj){
- if(dxs!=obj->dxs || dys!=obj->dys || obj->flags&OSDFLAG_FORCE_UPDATE){
- int vis=obj->flags&OSDFLAG_VISIBLE;
- obj->flags&=~OSDFLAG_BBOX;
- switch(obj->type){
- case OSDTYPE_SUBTITLE:
- vo_update_text_sub(osd, obj);
- break;
- case OSDTYPE_PROGBAR:
- vo_update_text_progbar(osd, obj);
- break;
- case OSDTYPE_SPU:
- if (opts->sub_visibility && vo_spudec && spudec_visible(vo_spudec)){
- vo_update_spudec_sub(osd, obj);
- obj->flags|=OSDFLAG_VISIBLE|OSDFLAG_CHANGED;
- }
- else
- obj->flags&=~OSDFLAG_VISIBLE;
- break;
- case OSDTYPE_OSD:
- if(osd->osd_text[0]){
- vo_update_text_osd(osd, obj);
- obj->flags|=OSDFLAG_VISIBLE|OSDFLAG_CHANGED;
- } else
- obj->flags&=~OSDFLAG_VISIBLE;
- break;
- }
- // check bbox:
- if(!(obj->flags&OSDFLAG_BBOX)){
- // we don't know, so assume the whole screen changed :(
- obj->bbox.x1=obj->bbox.y1=0;
- obj->bbox.x2=dxs;
- obj->bbox.y2=dys;
- obj->flags|=OSDFLAG_BBOX;
- } else {
- // check bbox, reduce it if it's out of bounds (corners):
- if(obj->bbox.x1<0) obj->bbox.x1=0;
- if(obj->bbox.y1<0) obj->bbox.y1=0;
- if(obj->bbox.x2>dxs) obj->bbox.x2=dxs;
- if(obj->bbox.y2>dys) obj->bbox.y2=dys;
- if(obj->flags&OSDFLAG_VISIBLE)
- // debug:
- mp_msg(MSGT_OSD,MSGL_DBG2,"OSD update: %d;%d %dx%d \n",
- obj->bbox.x1,obj->bbox.y1,obj->bbox.x2-obj->bbox.x1,
- obj->bbox.y2-obj->bbox.y1);
- }
- // check if visibility changed:
- if(vis != (obj->flags&OSDFLAG_VISIBLE) ) obj->flags|=OSDFLAG_CHANGED;
- // remove the cause of automatic update:
- obj->dxs=dxs; obj->dys=dys;
- obj->flags&=~OSDFLAG_FORCE_UPDATE;
- }
- if(obj->flags&OSDFLAG_CHANGED){
- chg|=1<<obj->type;
- mp_msg(MSGT_OSD,MSGL_DBG2,"OSD chg: %d V: %s pb:%d \n",obj->type,(obj->flags&OSDFLAG_VISIBLE)?"yes":"no",vo_osd_progbar_type);
- }
- obj=obj->next;
+ if (osd->w != res.w || osd->h != res.h) {
+ osd->w = res.w;
+ osd->h = res.h;
+ for (int n = 0; n < MAX_OSD_PARTS; n++)
+ osd->objs[n]->force_redraw = true;
}
- return chg;
}
-int osd_update(struct osd_state *osd, int dxs, int dys)
+void osd_update(struct osd_state *osd, int w, int h)
{
- return osd_update_ext(osd, dxs, dys, 0, 0, 0, 0, dxs, dys);
+ osd_update_ext(osd, (struct mp_eosd_res) {.w = w, .h = h});
}
struct osd_state *osd_create(struct MPOpts *opts, struct ass_library *asslib)
{
struct osd_state *osd = talloc_zero(NULL, struct osd_state);
- *osd = (struct osd_state){
+ *osd = (struct osd_state) {
.opts = opts,
.ass_library = asslib,
};
- // temp hack, should be moved to mplayer later
- new_osd_obj(OSDTYPE_ASS);
- new_osd_obj(OSDTYPE_OSD);
- new_osd_obj(OSDTYPE_SUBTITLE);
- new_osd_obj(OSDTYPE_PROGBAR);
- new_osd_obj(OSDTYPE_SPU);
- osd_font_invalidate();
+ for (int n = 0; n < MAX_OSD_PARTS; n++) {
+ struct osd_object *obj = talloc_struct(osd, struct osd_object, {
+ .type = n,
+ });
+ for (int i = 0; i < OSD_CONV_CACHE_MAX; i++)
+ obj->cache[i] = talloc_steal(obj, osd_conv_cache_new());
+ osd->objs[n] = obj;
+ }
osd->osd_text = talloc_strdup(osd, "");
osd_init_backend(osd);
+ global_osd = osd;
return osd;
}
+void osd_free(struct osd_state *osd)
+{
+ if (!osd)
+ return;
+ osd_destroy_backend(osd);
+ talloc_free(osd);
+ global_osd = NULL;
+}
+
void osd_set_text(struct osd_state *osd, const char *text)
{
if (!text)
@@ -276,169 +148,180 @@ void osd_set_text(struct osd_state *osd, const char *text)
vo_osd_changed(OSDTYPE_OSD);
}
-void osd_draw_text_ext(struct osd_state *osd, int dxs, int dys,
- int left_border, int top_border, int right_border,
- int bottom_border, int orig_w, int orig_h,
+static bool spu_visible(struct osd_state *osd, struct osd_object *obj)
+{
+ struct MPOpts *opts = osd->opts;
+ return opts->sub_visibility && vo_spudec && spudec_visible(vo_spudec);
+}
+
+// Return true if *out_imgs has been filled with valid values.
+// Return false on format mismatch, or if nothing to be renderer.
+static bool render_object(struct osd_state *osd, struct osd_object *obj,
+ struct sub_bitmaps *out_imgs,
+ const bool formats[SUBBITMAP_COUNT])
+{
+ memset(out_imgs, 0x55, sizeof(*out_imgs));
+
+ if (obj->type == OSDTYPE_SPU) {
+ *out_imgs = (struct sub_bitmaps) {0};
+ if (spu_visible(osd, obj))
+ spudec_get_bitmap(vo_spudec, osd->w, osd->h, out_imgs);
+ // Normal change-detection (sub. dec. calls vo_osd_changed(OSDTYPE_SPU))
+ if (obj->force_redraw) {
+ out_imgs->bitmap_id++;
+ out_imgs->bitmap_pos_id++;
+ }
+ } else {
+ osd_object_get_bitmaps(osd, obj, out_imgs);
+ }
+
+ obj->force_redraw = false;
+ obj->vo_bitmap_id += out_imgs->bitmap_id;
+ obj->vo_bitmap_pos_id += out_imgs->bitmap_pos_id;
+
+ if (out_imgs->num_parts == 0)
+ return false;
+
+ if (out_imgs->bitmap_id == 0 && out_imgs->bitmap_pos_id == 0
+ && obj->cached.bitmap_id == obj->vo_bitmap_id
+ && obj->cached.bitmap_pos_id == obj->vo_bitmap_pos_id
+ && formats[obj->cached.format])
+ {
+ *out_imgs = obj->cached;
+ return true;
+ }
+
+ out_imgs->render_index = obj->type;
+ out_imgs->bitmap_id = obj->vo_bitmap_id;
+ out_imgs->bitmap_pos_id = obj->vo_bitmap_pos_id;
+
+ if (formats[out_imgs->format])
+ return true;
+
+ bool cached = false; // do we have a copy of all the image data?
+
+ if ((formats[SUBBITMAP_OLD_PLANAR] || formats[SUBBITMAP_OLD])
+ && out_imgs->format == SUBBITMAP_LIBASS)
+ {
+ cached |= osd_conv_ass_to_old_p(obj->cache[0], out_imgs);
+ }
+
+ if (formats[SUBBITMAP_OLD] && out_imgs->format == SUBBITMAP_OLD_PLANAR) {
+ cached |= osd_conv_old_p_to_old(obj->cache[1], out_imgs);
+ }
+
+ if (cached)
+ obj->cached = *out_imgs;
+
+ return formats[out_imgs->format];
+}
+
+void draw_osd_with_eosd(struct vo *vo, struct osd_state *osd)
+{
+ mp_eosd_res_t res = {0};
+ if (vo_control(vo, VOCTRL_GET_EOSD_RES, &res) != VO_TRUE)
+ return;
+
+ bool formats[SUBBITMAP_COUNT];
+ for (int n = 0; n < SUBBITMAP_COUNT; n++) {
+ int data = n;
+ formats[n] = vo_control(vo, VOCTRL_QUERY_EOSD_FORMAT, &data) == VO_TRUE;
+ }
+
+ osd_update_ext(osd, res);
+
+ for (int n = 0; n < MAX_OSD_PARTS; n++) {
+ struct osd_object *obj = osd->objs[n];
+ struct sub_bitmaps imgs;
+ if (render_object(osd, obj, &imgs, formats))
+ vo_control(vo, VOCTRL_DRAW_EOSD, &imgs);
+ }
+}
+
+void osd_draw_text_ext(struct osd_state *osd, int w, int h,
+ int ml, int mt, int mr, int mb, int unused0, int unused1,
void (*draw_alpha)(void *ctx, int x0, int y0, int w,
int h, unsigned char* src,
unsigned char *srca,
int stride),
void *ctx)
{
- mp_osd_obj_t* obj=vo_osd_list;
- osd_update_ext(osd, dxs, dys, left_border, top_border, right_border,
- bottom_border, orig_w, orig_h);
- while(obj){
- if(obj->flags&OSDFLAG_VISIBLE){
- switch(obj->type){
- case OSDTYPE_SPU:
- if (vo_spudec)
- vo_draw_spudec_sub(obj, draw_alpha, ctx); // FIXME
- break;
- case OSDTYPE_OSD:
- case OSDTYPE_SUBTITLE:
- case OSDTYPE_PROGBAR:
- vo_draw_text_from_buffer(obj, draw_alpha, ctx);
- break;
- }
- obj->old_bbox=obj->bbox;
- obj->flags|=OSDFLAG_OLD_BBOX;
- }
- obj->flags&=~OSDFLAG_CHANGED;
- obj=obj->next;
+ struct mp_eosd_res res =
+ {.w = w, .h = h, .ml = ml, .mt = mt, .mr = mr, .mb = mb};
+ osd_update_ext(osd, res);
+ for (int n = 0; n < MAX_OSD_PARTS; n++) {
+ struct osd_object *obj = osd->objs[n];
+ struct sub_bitmaps imgs;
+ bool formats[SUBBITMAP_COUNT] = {[SUBBITMAP_OLD_PLANAR] = true};
+ if (render_object(osd, obj, &imgs, formats)) {
+ assert(imgs.num_parts == 1);
+ struct sub_bitmap *part = &imgs.parts[0];
+ struct old_osd_planar *bmp = part->bitmap;
+ draw_alpha(ctx, part->x, part->y, part->w, part->h,
+ bmp->bitmap, bmp->alpha, part->stride);
+ }
}
}
-void osd_draw_text(struct osd_state *osd, int dxs, int dys,
+void osd_draw_text(struct osd_state *osd, int w, int h,
void (*draw_alpha)(void *ctx, int x0, int y0, int w, int h,
unsigned char* src, unsigned char *srca,
int stride),
void *ctx)
{
- osd_draw_text_ext(osd, dxs, dys, 0, 0, 0, 0, dxs, dys, draw_alpha, ctx);
+ osd_draw_text_ext(osd, w, h, 0, 0, 0, 0, 0, 0, draw_alpha, ctx);
}
void vo_osd_changed(int new_value)
{
- mp_osd_obj_t* obj=vo_osd_list;
-
- while(obj){
- if(obj->type==new_value) obj->flags|=OSDFLAG_FORCE_UPDATE;
- obj=obj->next;
- }
-}
-
-void vo_osd_reset_changed(void)
-{
- mp_osd_obj_t* obj = vo_osd_list;
- while (obj) {
- obj->flags = obj->flags & ~OSDFLAG_FORCE_UPDATE;
- obj = obj->next;
+ struct osd_state *osd = global_osd;
+ for (int n = 0; n < MAX_OSD_PARTS; n++) {
+ if (osd->objs[n]->type == new_value)
+ osd->objs[n]->force_redraw = true;
}
}
bool vo_osd_has_changed(struct osd_state *osd)
{
- mp_osd_obj_t* obj = vo_osd_list;
- while (obj) {
- if (obj->flags & OSDFLAG_FORCE_UPDATE)
+ for (int n = 0; n < MAX_OSD_PARTS; n++) {
+ if (osd->objs[n]->force_redraw)
return true;
- obj = obj->next;
}
return false;
}
-void vo_osd_resized()
+// Needed for VOs using the old OSD API (osd_draw_text_[ext]).
+void vo_osd_reset_changed(void)
{
- // font needs to be adjusted
- osd_font_invalidate();
- // OSD needs to be drawn fresh for new size
- vo_osd_changed(OSDTYPE_OSD);
- vo_osd_changed(OSDTYPE_SUBTITLE);
+ struct osd_state *osd = global_osd;
+ for (int n = 0; n < MAX_OSD_PARTS; n++)
+ osd->objs[n]->force_redraw = false;
}
-// return TRUE if we have osd in the specified rectangular area:
-int vo_osd_check_range_update(int x1,int y1,int x2,int y2){
- mp_osd_obj_t* obj=vo_osd_list;
- while(obj){
- if(obj->flags&OSDFLAG_VISIBLE){
- if( (obj->bbox.x1<=x2 && obj->bbox.x2>=x1) &&
- (obj->bbox.y1<=y2 && obj->bbox.y2>=y1) &&
- obj->bbox.y2 > obj->bbox.y1 && obj->bbox.x2 > obj->bbox.x1
- ) return 1;
- }
- obj=obj->next;
- }
- return 0;
+void vo_osd_resized(void)
+{
+ // Counter the typical vo_osd_has_changed(osd) call in VO's draw_osd()
+ struct osd_state *osd = global_osd;
+ for (int n = 0; n < MAX_OSD_PARTS; n++)
+ osd->objs[n]->force_redraw = true;
}
-struct draw_osd_closure {
- struct vo *vo;
- struct osd_state *osd;
- int render_index;
-};
-
-static void eosd_draw_osd_part(void *ctx, int x0, int y0, int w, int h,
- unsigned char *src, unsigned char *srca,
- int stride)
+bool sub_bitmaps_bb(struct sub_bitmaps *imgs, int *x1, int *y1,
+ int *x2, int *y2)
{
- struct draw_osd_closure *c = ctx;
-
- assert(c->render_index < MAX_OSD_PARTS);
- assert(w > 0 && h > 0);
-
- size_t scratch_size = talloc_get_size(c->osd->scratch);
- size_t new_size = stride * h * 2;
- if (new_size > scratch_size) {
- scratch_size = new_size;
- c->osd->scratch = talloc_realloc(c->osd, c->osd->scratch, char *,
- new_size);
- }
-
- unsigned char *tmp = c->osd->scratch;
-
- for (int y = 0; y < h; y++) {
- unsigned char *y_src = src + stride * y;
- unsigned char *y_srca = srca + stride * y;
- unsigned char *cur = tmp + y * w * 2;
- for (int x = 0; x < w; x++) {
- cur[x*2+0] = y_src[x];
- cur[x*2+1] = -y_srca[x];
- }
+ *x1 = *y1 = INT_MAX;
+ *x2 = *y2 = INT_MIN;
+ for (int n = 0; n < imgs->num_parts; n++) {
+ struct sub_bitmap *p = &imgs->parts[n];
+ *x1 = FFMIN(*x1, p->x);
+ *y1 = FFMIN(*y1, p->y);
+ *x2 = FFMAX(*x2, p->x + p->dw);
+ *y2 = FFMAX(*y2, p->y + p->dh);
}
- struct sub_bitmaps *imgs = &c->osd->eosd[c->render_index];
- imgs->render_index = c->render_index;
- imgs->format = SUBBITMAP_OLD;
- imgs->bitmap_id++;
- imgs->bitmap_pos_id++;
- if (!imgs->num_parts) {
- imgs->num_parts = 1;
- imgs->parts = talloc_array(c->osd, struct sub_bitmap, imgs->num_parts);
- }
-
- imgs->parts[0] = (struct sub_bitmap) {
- .bitmap = tmp,
- .stride = w * 2,
- .x = x0, .y = y0,
- .w = w, .h = h,
- .dw = w, .dh = h,
- };
-
- vo_control(c->vo, VOCTRL_DRAW_EOSD, imgs);
-
- c->render_index++;
-}
-
-// draw old-OSD using EOSD
-void emulate_draw_osd(struct vo *vo, struct osd_state *osd)
-{
- mp_eosd_res_t res = {0};
- if (vo_control(vo, VOCTRL_GET_EOSD_RES, &res) != VO_TRUE)
- return;
+ // avoid degenerate bounding box if empty
+ *x1 = FFMIN(*x1, *x2);
+ *y1 = FFMIN(*y1, *y2);
- struct draw_osd_closure c = {vo, osd};
- c.render_index = 1; // 0 is the "normal" EOSD renderer for subtitles
- osd_draw_text_ext(osd, res.w, res.h, res.ml, res.mt, res.mr, res.mb, 0, 0,
- eosd_draw_osd_part, &c);
+ return *x1 < *x2 && *y1 < *y2;
}
diff --git a/sub/sub.h b/sub/sub.h
index 74d2b5a37a..1dee0c8a8f 100644
--- a/sub/sub.h
+++ b/sub/sub.h
@@ -26,48 +26,40 @@
struct vo;
-typedef struct mp_osd_bbox_s {
- int x1,y1,x2,y2;
-} mp_osd_bbox_t;
-
#define OSDTYPE_ASS 0
#define OSDTYPE_OSD 1
#define OSDTYPE_SUBTITLE 2
#define OSDTYPE_PROGBAR 3
#define OSDTYPE_SPU 4
-#define OSDFLAG_VISIBLE 1
-#define OSDFLAG_CHANGED 2
-#define OSDFLAG_BBOX 4
-#define OSDFLAG_OLD_BBOX 8
-#define OSDFLAG_FORCE_UPDATE 16
-
-#define MAX_UCS 1600
-#define MAX_UCSLINES 16
-
-typedef struct mp_osd_obj_s {
- struct mp_osd_obj_s* next;
- unsigned char type;
- unsigned short flags;
- int x,y;
- int dxs,dys;
- mp_osd_bbox_t bbox; // bounding box
- mp_osd_bbox_t old_bbox; // the renderer will save bbox here
- int stride;
-
- int allocated;
- unsigned char *alpha_buffer;
- unsigned char *bitmap_buffer;
+#define MAX_OSD_PARTS 5
+
+#define OSD_CONV_CACHE_MAX 2
+
+struct osd_object {
+ int type; // OSDTYPE_*
+ bool force_redraw;
+
+ // caches for OSD conversion (internal to render_object())
+ struct osd_conv_cache *cache[OSD_CONV_CACHE_MAX];
+
+ struct sub_bitmaps cached;
+ // VO cache state
+ int vo_bitmap_id;
+ int vo_bitmap_pos_id;
+
+ // Internally used by osd_libass.c
struct ass_track *osd_track;
-} mp_osd_obj_t;
+ struct sub_bitmap *parts_cache;
+};
struct osd_state {
+ struct osd_object *objs[MAX_OSD_PARTS];
+
struct ass_library *ass_library;
struct ass_renderer *ass_renderer;
struct sh_sub *sh_sub;
- int bitmap_id;
- int bitmap_pos_id;
double sub_pts;
double sub_offset;
struct mp_eosd_res dim;
@@ -76,16 +68,19 @@ struct osd_state {
bool unscaled;
bool support_rgba;
- struct ass_renderer *osd_render;
- struct ass_library *osd_ass_library;
- char *osd_text;
int w, h;
- struct sub_bitmaps eosd[MAX_OSD_PARTS];
+ char *osd_text; // OSDTYPE_OSD
- void *scratch;
+ // temporary for sub decoders
+ int bitmap_id;
+ int bitmap_pos_id;
struct MPOpts *opts;
+
+ // Internally used by osd_libass.c
+ struct ass_renderer *osd_render;
+ struct ass_library *osd_ass_library;
};
extern subtitle* vo_sub;
@@ -160,29 +155,25 @@ void osd_draw_text_ext(struct osd_state *osd, int dxs, int dys,
int stride),
void *ctx);
-void emulate_draw_osd(struct vo *vo, struct osd_state *osd);
+void draw_osd_with_eosd(struct vo *vo, struct osd_state *osd);
struct osd_state *osd_create(struct MPOpts *opts, struct ass_library *asslib);
void osd_set_text(struct osd_state *osd, const char *text);
-int osd_update(struct osd_state *osd, int dxs, int dys);
+void osd_update(struct osd_state *osd, int dxs, int dys);
void vo_osd_changed(int new_value);
void vo_osd_reset_changed(void);
bool vo_osd_has_changed(struct osd_state *osd);
void vo_osd_resized(void);
-int vo_osd_check_range_update(int,int,int,int);
void osd_free(struct osd_state *osd);
-// used only by osd_ft.c or osd_libass.c
-void osd_alloc_buf(mp_osd_obj_t* obj);
-void vo_draw_text_from_buffer(mp_osd_obj_t* obj,void (*draw_alpha)(void *ctx, int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride), void *ctx);
+bool sub_bitmaps_bb(struct sub_bitmaps *imgs, int *x1, int *y1,
+ int *x2, int *y2);
+
+// defined in osd_libass.c and osd_dummy.c
-// defined in osd_ft.c or osd_libass.c
-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_object_get_bitmaps(struct osd_state *osd, struct osd_object *obj,
+ struct sub_bitmaps *out_imgs);
void osd_get_function_sym(char *buffer, size_t buffer_size, int osd_function);
-void osd_font_invalidate(void);
-void osd_font_load(struct osd_state *osd);
void osd_init_backend(struct osd_state *osd);
void osd_destroy_backend(struct osd_state *osd);