From ffb7a2fe17af204635db6694b5b49b6368be91e6 Mon Sep 17 00:00:00 2001 From: wm4 Date: Fri, 28 Sep 2012 21:19:36 +0200 Subject: [PATCH 01/83] sub: create sub_bitmap array even when using libass One sub_bitmaps struct could contain either a libass ASS_Image list, or a mplayer native list of sub-bitmaps. This caused code duplication in vo_vdpau.c and bitmap_packer.c. Avoid this by creating such a sub_bitmap array even with libass. This basically copies the list and recreates it in mplayer's native format. It gets rid of the code duplication, and will make implementing extended subtitle and OSD rendering in other VOs easier. Also do some cosmetic changes and other preparations for the following commits. --- libmpcodecs/vfcap.h | 1 - libvo/bitmap_packer.c | 47 +++++++++++----------- libvo/bitmap_packer.h | 9 ++++- libvo/vo_corevideo.m | 7 ++-- libvo/vo_gl.c | 3 -- libvo/vo_gl3.c | 3 -- libvo/vo_vdpau.c | 92 ++++++++++++++++--------------------------- mplayer.c | 2 - sub/dec_sub.c | 3 +- sub/dec_sub.h | 51 +++++++++++++++++------- sub/sd_ass.c | 28 ++++++++++++- sub/sd_lavc.c | 5 ++- 12 files changed, 135 insertions(+), 116 deletions(-) diff --git a/libmpcodecs/vfcap.h b/libmpcodecs/vfcap.h index aef75840ae..0bb255b3cd 100644 --- a/libmpcodecs/vfcap.h +++ b/libmpcodecs/vfcap.h @@ -46,7 +46,6 @@ #define VFCAP_EOSD_UNSCALED 0x4000 // used by libvo and vf_vo, indicates the VO does not support draw_slice for this format #define VOCAP_NOSLICES 0x8000 -#define VFCAP_OSD_FILTER 0x10000 // OSD is drawn in filter chain #define VFCAP_EOSD_FILTER 0x20000 // EOSD is drawn in filter chain #define VFCAP_EOSD_RGBA 0x40000 diff --git a/libvo/bitmap_packer.c b/libvo/bitmap_packer.c index eedc2e2242..5e5bafea0c 100644 --- a/libvo/bitmap_packer.c +++ b/libvo/bitmap_packer.c @@ -30,6 +30,24 @@ #include "sub/ass_mp.h" #include "sub/dec_sub.h" +void packer_reset(struct bitmap_packer *packer) +{ + struct bitmap_packer old = *packer; + *packer = (struct bitmap_packer) { + .w_max = old.w_max, + .h_max = old.h_max, + }; + talloc_free_children(packer); +} + +void packer_get_bb(struct bitmap_packer *packer, struct pos out_bb[2]) +{ + out_bb[0] = (struct pos) {0}; + out_bb[1] = (struct pos) { + FFMIN(packer->used_width + packer->padding, packer->w), + FFMIN(packer->used_height + packer->padding, packer->h), + }; +} #define HEIGHT_SORT_BITS 4 static int size_index(int s) @@ -171,36 +189,15 @@ void packer_set_size(struct bitmap_packer *packer, int size) packer->asize + 16); } -static int packer_pack_from_assimg(struct bitmap_packer *packer, - struct ass_image *imglist) -{ - int count = 0; - struct ass_image *img = imglist; - while (img) { - if (count >= packer->asize) - packer_set_size(packer, FFMAX(packer->asize * 2, 32)); - packer->in[count].x = img->w; - packer->in[count].y = img->h; - img = img->next; - count++; - } - packer->count = count; - return packer_pack(packer); -} - int packer_pack_from_subbitmaps(struct bitmap_packer *packer, - struct sub_bitmaps *b, int padding_pixels) + struct sub_bitmaps *b) { - packer->padding = 0; packer->count = 0; - if (b->type == SUBBITMAP_EMPTY) + if (b->format == SUBBITMAP_EMPTY) return 0; - if (b->type == SUBBITMAP_LIBASS) - return packer_pack_from_assimg(packer, b->imgs); - packer->padding = padding_pixels; - packer_set_size(packer, b->part_count); + packer_set_size(packer, b->num_parts); int a = packer->padding; - for (int i = 0; i < b->part_count; i++) + for (int i = 0; i < b->num_parts; i++) packer->in[i] = (struct pos){b->parts[i].w + a, b->parts[i].h + a}; return packer_pack(packer); } diff --git a/libvo/bitmap_packer.h b/libvo/bitmap_packer.h index c7c377cbd0..99c7b514b4 100644 --- a/libvo/bitmap_packer.h +++ b/libvo/bitmap_packer.h @@ -26,6 +26,13 @@ struct bitmap_packer { struct ass_image; struct sub_bitmaps; +// Clear all internal state. Leave the following fields: w_max, h_max +void packer_reset(struct bitmap_packer *packer); + +// Get the bounding box used for bitmap data (including padding). +// The bounding box doesn't exceed (0,0)-(packer->w,packer->h). +void packer_get_bb(struct bitmap_packer *packer, struct pos out_bb[2]); + /* Reallocate packer->in for at least to desired number of items. * Also sets packer->count to the same value. */ @@ -46,6 +53,6 @@ int packer_pack(struct bitmap_packer *packer); * given image list. */ int packer_pack_from_subbitmaps(struct bitmap_packer *packer, - struct sub_bitmaps *b, int padding_pixels); + struct sub_bitmaps *b); #endif diff --git a/libvo/vo_corevideo.m b/libvo/vo_corevideo.m index 1d10330bcb..fd667acb61 100644 --- a/libvo/vo_corevideo.m +++ b/libvo/vo_corevideo.m @@ -45,11 +45,10 @@ struct quad { }; #define CV_VERTICES_PER_QUAD 6 -#define CV_MAX_OSD_PARTS 20 struct osd_p { - GLuint tex[CV_MAX_OSD_PARTS]; - NSRect tex_rect[CV_MAX_OSD_PARTS]; + GLuint tex[MAX_OSD_PARTS]; + NSRect tex_rect[MAX_OSD_PARTS]; int tex_cnt; }; @@ -185,7 +184,7 @@ static void create_osd_texture(void *ctx, int x0, int y0, int w, int h, return; } - if (osd->tex_cnt >= CV_MAX_OSD_PARTS) { + if (osd->tex_cnt >= MAX_OSD_PARTS) { mp_msg(MSGT_VO, MSGL_ERR, "Too many OSD parts, contact the" " developers!\n"); return; diff --git a/libvo/vo_gl.c b/libvo/vo_gl.c index 5453943fe9..236471d537 100644 --- a/libvo/vo_gl.c +++ b/libvo/vo_gl.c @@ -44,9 +44,6 @@ #include "fastmemcpy.h" #include "sub/ass_mp.h" -//! How many parts the OSD may consist of at most -#define MAX_OSD_PARTS 20 - //for gl_priv.use_yuv #define MASK_ALL_YUV (~(1 << YUV_CONVERSION_NONE)) #define MASK_NOT_COMBINERS (~((1 << YUV_CONVERSION_NONE) | (1 << YUV_CONVERSION_COMBINERS))) diff --git a/libvo/vo_gl3.c b/libvo/vo_gl3.c index dea0c6637a..ebce32677b 100644 --- a/libvo/vo_gl3.c +++ b/libvo/vo_gl3.c @@ -59,9 +59,6 @@ static const char vo_gl3_shaders[] = #include "libvo/vo_gl3_shaders.h" ; -// How many parts the OSD may consist of at most. -#define MAX_OSD_PARTS 20 - // Pixel width of 1D lookup textures. #define LOOKUP_TEXTURE_SIZE 256 diff --git a/libvo/vo_vdpau.c b/libvo/vo_vdpau.c index 594829b394..d5856e2dfa 100644 --- a/libvo/vo_vdpau.c +++ b/libvo/vo_vdpau.c @@ -92,8 +92,6 @@ struct vdp_functions { #undef VDP_FUNCTION }; -#define MAX_OLD_OSD_BITMAPS 6 - struct vdpctx { struct vdp_functions *vdp; @@ -165,7 +163,7 @@ struct vdpctx { int x0, y0, w, h; unsigned char *src, *srca; int stride; - } old_osd_elements[MAX_OLD_OSD_BITMAPS]; + } old_osd_elements[MAX_OSD_PARTS]; int old_osd_count; unsigned char *osd_data_temp; int osd_data_size; @@ -184,7 +182,7 @@ struct vdpctx { VdpRect source; VdpRect dest; VdpColor color; - } *eosd_targets, osd_targets[MAX_OLD_OSD_BITMAPS][2]; + } *eosd_targets, osd_targets[MAX_OSD_PARTS][2]; int eosd_targets_size; int eosd_render_count; int bitmap_id; @@ -1008,7 +1006,7 @@ static void generate_eosd(struct vo *vo, mp_eosd_images_t *imgs) vc->eosd_render_count = 0; - if (imgs->type == SUBBITMAP_EMPTY) + if (imgs->format == SUBBITMAP_EMPTY) return; if (imgs->bitmap_id == vc->bitmap_id) @@ -1017,7 +1015,7 @@ static void generate_eosd(struct vo *vo, mp_eosd_images_t *imgs) need_upload = true; VdpRGBAFormat format; int format_size; - switch (imgs->type) { + switch (imgs->format) { case SUBBITMAP_LIBASS: format = VDP_RGBA_FORMAT_A8; format_size = 1; @@ -1036,7 +1034,8 @@ static void generate_eosd(struct vo *vo, mp_eosd_images_t *imgs) sfc->format = format; if (!sfc->packer) sfc->packer = make_packer(vo, format); - int r = packer_pack_from_subbitmaps(sfc->packer, imgs, imgs->scaled); + sfc->packer->padding = imgs->scaled; // assume 2x2 filter on scaling + int r = packer_pack_from_subbitmaps(sfc->packer, imgs); if (r < 0) { mp_msg(MSGT_VO, MSGL_ERR, "[vdpau] EOSD bitmaps do not fit on " "a surface with the maximum supported size\n"); @@ -1072,57 +1071,34 @@ eosd_skip_upload: vc->eosd_targets_size = sfc->packer->count; vc->eosd_targets = talloc_size(vc, vc->eosd_targets_size * sizeof(*vc->eosd_targets)); - } - - if (imgs->type == SUBBITMAP_LIBASS) { - int i = 0; - for (ASS_Image *p = imgs->imgs; p; p = p->next, i++) { - if (p->w == 0 || p->h == 0) - continue; - struct eosd_target *target = vc->eosd_targets + - vc->eosd_render_count; - int x = sfc->packer->result[i].x; - int y = sfc->packer->result[i].y; - target->source = (VdpRect){x, y, x + p->w, y + p->h}; - if (need_upload) { - vdp_st = vdp-> - bitmap_surface_put_bits_native(sfc->surface, - (const void *) &p->bitmap, - &p->stride, &target->source); - CHECK_ST_WARNING("EOSD: putbits failed"); - } - // Render dest, color, etc. - target->color.alpha = 1.0 - ((p->color >> 0) & 0xff) / 255.0; - target->color.blue = ((p->color >> 8) & 0xff) / 255.0; - target->color.green = ((p->color >> 16) & 0xff) / 255.0; - target->color.red = ((p->color >> 24) & 0xff) / 255.0; - target->dest.x0 = p->dst_x; - target->dest.y0 = p->dst_y; - target->dest.x1 = p->w + p->dst_x; - target->dest.y1 = p->h + p->dst_y; - vc->eosd_render_count++; - } - } else { - for (int i = 0 ;i < sfc->packer->count; i++) { - struct sub_bitmap *b = &imgs->parts[i]; - struct eosd_target *target = vc->eosd_targets + - vc->eosd_render_count; - int x = sfc->packer->result[i].x; - int y = sfc->packer->result[i].y; - target->source = (VdpRect){x, y, x + b->w, y + b->h}; - if (need_upload) { - vdp_st = vdp-> - bitmap_surface_put_bits_native(sfc->surface, - &(const void *){b->bitmap}, - &(uint32_t){b->w * 4}, - &target->source); - CHECK_ST_WARNING("EOSD: putbits failed"); - } - target->color = (VdpColor){1, 1, 1, 1}; - target->dest = (VdpRect){b->x, b->y, b->x + b->dw, b->y + b->dh}; - vc->eosd_render_count++; - } } + + for (int i = 0 ;i < sfc->packer->count; i++) { + struct sub_bitmap *b = &imgs->parts[i]; + struct eosd_target *target = vc->eosd_targets + vc->eosd_render_count; + int x = sfc->packer->result[i].x; + int y = sfc->packer->result[i].y; + target->source = (VdpRect){x, y, x + b->w, y + b->h}; + target->dest = (VdpRect){b->x, b->y, b->x + b->dw, b->y + b->dh}; + target->color = (VdpColor){1, 1, 1, 1}; + if (imgs->format == SUBBITMAP_LIBASS) { + uint32_t color = b->libass.color; + target->color.alpha = 1.0 - ((color >> 0) & 0xff) / 255.0; + target->color.blue = ((color >> 8) & 0xff) / 255.0; + target->color.green = ((color >> 16) & 0xff) / 255.0; + target->color.red = ((color >> 24) & 0xff) / 255.0; + } + if (need_upload) { + vdp_st = vdp-> + bitmap_surface_put_bits_native(sfc->surface, + &(const void *){b->bitmap}, + &(uint32_t){b->stride}, + &target->source); + CHECK_ST_WARNING("EOSD: putbits failed"); + } + vc->eosd_render_count++; + } + vc->bitmap_id = imgs->bitmap_id; vc->bitmap_pos_id = imgs->bitmap_pos_id; } @@ -1133,7 +1109,7 @@ static void record_osd(void *ctx, int x0, int y0, int w, int h, struct vo *vo = ctx; struct vdpctx *vc = vo->priv; - assert(vc->old_osd_count < MAX_OLD_OSD_BITMAPS); + assert(vc->old_osd_count < MAX_OSD_PARTS); if (!w || !h) return; vc->old_osd_elements[vc->old_osd_count++] = (struct old_osd){ diff --git a/mplayer.c b/mplayer.c index d17be7c357..5c08cdf330 100644 --- a/mplayer.c +++ b/mplayer.c @@ -2638,8 +2638,6 @@ static int redraw_osd(struct MPContext *mpctx) { struct sh_video *sh_video = mpctx->sh_video; struct vf_instance *vf = sh_video->vfilter; - if (sh_video->output_flags & VFCAP_OSD_FILTER) - return -1; if (vo_redraw_frame(mpctx->video_out) < 0) return -1; mpctx->osd->sub_pts = mpctx->video_pts; diff --git a/sub/dec_sub.c b/sub/dec_sub.c index 4a048b27a6..31b06b9b80 100644 --- a/sub/dec_sub.c +++ b/sub/dec_sub.c @@ -62,7 +62,8 @@ void sub_get_bitmaps(struct osd_state *osd, struct sub_bitmaps *res) { struct MPOpts *opts = osd->opts; - *res = (struct sub_bitmaps){ .type = SUBBITMAP_EMPTY, + *res = (struct sub_bitmaps){ .render_index = 0, + .format = SUBBITMAP_EMPTY, .bitmap_id = osd->bitmap_id, .bitmap_pos_id = osd->bitmap_pos_id }; if (!opts->sub_visibility || !osd->sh_sub || !osd->sh_sub->active) { diff --git a/sub/dec_sub.h b/sub/dec_sub.h index c71a2348aa..df6aaf9b91 100644 --- a/sub/dec_sub.h +++ b/sub/dec_sub.h @@ -1,14 +1,22 @@ #ifndef MPLAYER_DEC_SUB_H #define MPLAYER_DEC_SUB_H +#include +#include + +#define MAX_OSD_PARTS 8 + struct sh_sub; struct osd_state; struct ass_track; -enum sub_bitmap_type { +enum sub_bitmap_format { SUBBITMAP_EMPTY, - SUBBITMAP_LIBASS, - SUBBITMAP_RGBA, + SUBBITMAP_LIBASS, // A8, with a per-surface blend color (libass.color) + SUBBITMAP_RGBA, // B8G8R8A8 + SUBBITMAP_OLD, // I8A8 (monochrome), premultiplied alpha + + SUBBITMAP_COUNT }; typedef struct mp_eosd_res { @@ -16,21 +24,34 @@ typedef struct mp_eosd_res { int mt, mb, ml, mr; // borders (top, bottom, left, right) } mp_eosd_res_t; -typedef struct sub_bitmaps { - enum sub_bitmap_type type; +struct sub_bitmap { + void *bitmap; + int stride; + int w, h; + int x, y; + // Note: not clipped, going outside the screen area is allowed + int dw, dh; + union { + struct { + uint32_t color; + } libass; + }; +}; + +typedef struct sub_bitmaps { + int render_index; // for VO cache state (limited by MAX_OSD_PARTS) + + enum sub_bitmap_format format; + bool scaled; // if false, dw==w && dh==h + + struct sub_bitmap *parts; + int num_parts; + + // Provided for VOs with old code 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; + // Incremented on each change int bitmap_id, bitmap_pos_id; } mp_eosd_images_t; diff --git a/sub/sd_ass.c b/sub/sd_ass.c index 9295cab07d..aa190ee4ac 100644 --- a/sub/sd_ass.c +++ b/sub/sd_ass.c @@ -36,6 +36,7 @@ struct sd_ass_priv { struct ass_track *ass_track; bool vsfilter_aspect; bool incomplete_event; + struct sub_bitmap *parts; }; static void free_last_event(ASS_Track *track) @@ -147,7 +148,32 @@ static void get_bitmaps(struct sh_sub *sh, struct osd_state *osd, res->bitmap_id = ++res->bitmap_pos_id; else if (changed) res->bitmap_pos_id++; - res->type = SUBBITMAP_LIBASS; + 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; } static void reset(struct sh_sub *sh, struct osd_state *osd) diff --git a/sub/sd_lavc.c b/sub/sd_lavc.c index 1da33ffca1..39e4891fb1 100644 --- a/sub/sd_lavc.c +++ b/sub/sd_lavc.c @@ -175,6 +175,7 @@ static void decode(struct sh_sub *sh, struct osd_state *osd, void *data, uint32_t *outbmp = talloc_size(priv->inbitmaps, r->w * r->h * 4); b->bitmap = outbmp; + b->stride = r->w * 4; b->w = r->w; b->h = r->h; b->x = r->x; @@ -233,13 +234,13 @@ static void get_bitmaps(struct sh_sub *sh, struct osd_state *osd, SET(bo->dh, bi->h * yscale); } res->parts = priv->outbitmaps; - res->part_count = priv->count; + res->num_parts = priv->count; if (priv->bitmaps_changed) res->bitmap_id = ++res->bitmap_pos_id; else if (pos_changed) res->bitmap_pos_id++; priv->bitmaps_changed = false; - res->type = SUBBITMAP_RGBA; + res->format = SUBBITMAP_RGBA; res->scaled = xscale != 1 || yscale != 1; } From 3c9c1790fee177cc9c9661475746a92ab6ce9bea Mon Sep 17 00:00:00 2001 From: wm4 Date: Fri, 28 Sep 2012 21:25:26 +0200 Subject: [PATCH 02/83] vo_gl3: support RGBA EOSD This also adds support for multiple EOSD renderers. This capability is unused yet, but important for the following commits. --- libvo/fastmemcpy.h | 13 ++ libvo/gl_common.c | 26 ++++ libvo/gl_common.h | 3 + libvo/vo_gl3.c | 292 +++++++++++++++++++++++++------------- libvo/vo_gl3_shaders.glsl | 18 ++- 5 files changed, 252 insertions(+), 100 deletions(-) diff --git a/libvo/fastmemcpy.h b/libvo/fastmemcpy.h index 5d05d37043..36fada39fe 100644 --- a/libvo/fastmemcpy.h +++ b/libvo/fastmemcpy.h @@ -64,4 +64,17 @@ static inline void * memcpy_pic2(void * dst, const void * src, return retval; } +static inline void memset_pic(void *dst, int fill, int bytesPerLine, int height, + int stride) +{ + if (bytesPerLine == stride) { + memset(dst, fill, stride * height); + } else { + for (int i = 0; i < height; i++) { + memset(dst, fill, bytesPerLine); + dst = (uint8_t *)dst + stride; + } + } +} + #endif /* MPLAYER_FASTMEMCPY_H */ diff --git a/libvo/gl_common.c b/libvo/gl_common.c index 1ad7017e10..c56b0c8ffc 100644 --- a/libvo/gl_common.c +++ b/libvo/gl_common.c @@ -427,6 +427,7 @@ static const extfunc_desc_t extfuncs[] = { DEF_GL3_DESC(FramebufferTexture2D), DEF_GL3_DESC(Uniform1f), DEF_GL3_DESC(Uniform3f), + DEF_GL3_DESC(Uniform4f), DEF_GL3_DESC(Uniform1i), DEF_GL3_DESC(UniformMatrix3fv), DEF_GL3_DESC(UniformMatrix4x3fv), @@ -674,6 +675,31 @@ void glUploadTex(GL *gl, GLenum target, GLenum format, GLenum type, gl->TexSubImage2D(target, 0, x, y, w, y_max - y, format, type, data); } +// Like glUploadTex, but upload a byte array with all elements set to val. +// If scratch is not NULL, points to a resizeable talloc memory block than can +// be freely used by the function (for avoiding temporary memory allocations). +void glClearTex(GL *gl, GLenum target, GLenum format, GLenum type, + int x, int y, int w, int h, uint8_t val, void **scratch) +{ + int bpp = glFmt2bpp(format, type); + int stride = w * bpp; + int size = h * stride; + if (size < 1) + return; + void *data = scratch ? *scratch : NULL; + if (talloc_get_size(data) < size) + data = talloc_realloc(NULL, data, char *, size); + memset(data, val, size); + glAdjustAlignment(gl, stride); + gl->PixelStorei(GL_UNPACK_ROW_LENGTH, w); + gl->TexSubImage2D(target, 0, x, y, w, h, format, type, data); + if (scratch) { + *scratch = data; + } else { + talloc_free(data); + } +} + /** * \brief download a texture, handling things like stride and slices * \param target texture target, usually GL_TEXTURE_2D diff --git a/libvo/gl_common.h b/libvo/gl_common.h index f42caa8fd1..fa4b6dbf25 100644 --- a/libvo/gl_common.h +++ b/libvo/gl_common.h @@ -60,6 +60,8 @@ int glCreatePPMTex(GL *gl, GLenum target, GLenum fmt, GLint filter, void glUploadTex(GL *gl, GLenum target, GLenum format, GLenum type, const void *dataptr, int stride, int x, int y, int w, int h, int slice); +void glClearTex(GL *gl, GLenum target, GLenum format, GLenum type, + int x, int y, int w, int h, uint8_t val, void **scratch); void glDownloadTex(GL *gl, GLenum target, GLenum format, GLenum type, void *dataptr, int stride); void glDrawTex(GL *gl, GLfloat x, GLfloat y, GLfloat w, GLfloat h, @@ -351,6 +353,7 @@ struct GL { void (GLAPIENTRY *Uniform1f)(GLint, GLfloat); void (GLAPIENTRY *Uniform3f)(GLint, GLfloat, GLfloat, GLfloat); + void (GLAPIENTRY *Uniform4f)(GLint, GLfloat, GLfloat, GLfloat, GLfloat); void (GLAPIENTRY *Uniform1i)(GLint, GLint); void (GLAPIENTRY *UniformMatrix3fv)(GLint, GLsizei, GLboolean, const GLfloat *); diff --git a/libvo/vo_gl3.c b/libvo/vo_gl3.c index ebce32677b..e3d3b9af62 100644 --- a/libvo/vo_gl3.c +++ b/libvo/vo_gl3.c @@ -37,6 +37,7 @@ #endif #include "talloc.h" +#include "mpcommon.h" #include "bstr.h" #include "mp_msg.h" #include "subopt-helper.h" @@ -46,7 +47,7 @@ #include "geometry.h" #include "osd.h" #include "sub/sub.h" -#include "eosd_packer.h" +#include "bitmap_packer.h" #include "gl_common.h" #include "filter_kernels.h" @@ -111,7 +112,7 @@ struct vertex { #define VERTEX_ATTRIB_TEXCOORD 2 // 2 triangles primitives per quad = 6 vertices per quad -// (GL_QUAD is deprecated, strips can't be used with EOSD image lists) +// (GL_QUAD is deprecated, strips can't be used with OSD image lists) #define VERTICES_PER_QUAD 6 struct texplane { @@ -141,6 +142,17 @@ struct fbotex { int vp_w, vp_h; // viewport of fbo / used part of the texture }; +struct osd_render { + enum sub_bitmap_format format; + int bitmap_id, bitmap_pos_id; + GLuint texture; + int width, height; + GLuint buffer; + int num_vertices; + struct vertex *vertices; + struct bitmap_packer *packer; +}; + struct gl_priv { struct vo *vo; MPGLContext *glctx; @@ -171,18 +183,15 @@ struct gl_priv { GLuint vertex_buffer; GLuint vao; - GLuint osd_program, eosd_program; + GLuint osd_programs[SUBBITMAP_COUNT]; GLuint indirect_program, scale_sep_program, final_program; + // old OSD code - should go away GLuint osd_textures[MAX_OSD_PARTS]; int osd_textures_count; struct vertex osd_va[MAX_OSD_PARTS * VERTICES_PER_QUAD]; - GLuint eosd_texture; - int eosd_texture_width, eosd_texture_height; - GLuint eosd_buffer; - struct vertex *eosd_va; - struct eosd_packer *eosd; + struct osd_render *osd[MAX_OSD_PARTS]; GLuint lut_3d_texture; int lut_3d_w, lut_3d_h, lut_3d_d; @@ -231,6 +240,8 @@ struct gl_priv { struct vo_rect dst_rect; // video rectangle on output window int border_x, border_y; // OSD borders int vp_x, vp_y, vp_w, vp_h; // GL viewport + + void *scratch; }; struct fmt_entry { @@ -254,6 +265,25 @@ static const struct fmt_entry mp_to_gl_formats[] = { {0}, }; +struct osd_fmt_entry { + GLint internal_format; + GLint format; + int stride; // bytes per pixel + GLenum type; + const char *shader; // shader entry in the .glsl file +}; + +static const struct osd_fmt_entry osd_to_gl_formats[] = { + [SUBBITMAP_LIBASS] + = {GL_RED, GL_RED, 1, GL_UNSIGNED_BYTE, "frag_osd_libass"}, + [SUBBITMAP_RGBA] + = {GL_RGBA, GL_BGRA, 4, GL_UNSIGNED_BYTE, "frag_osd_rgba"}, + [SUBBITMAP_OLD] + = {GL_RG, GL_RG, 2, GL_UNSIGNED_BYTE, "frag_osd_old"}, + // Make array long enough to contain all formats + [SUBBITMAP_COUNT] = {0} +}; + static const char help_text[]; @@ -464,6 +494,15 @@ static void update_uniforms(struct gl_priv *p, GLuint program) gl->Uniform1f(gl->GetUniformLocation(program, "filter_param1"), isnan(sparam1) ? 0.5f : sparam1); + loc = gl->GetUniformLocation(program, "osd_color"); + if (loc >= 0) { + int r = (p->osd_color >> 16) & 0xff; + int g = (p->osd_color >> 8) & 0xff; + int b = p->osd_color & 0xff; + int a = 0xff - (p->osd_color >> 24); + gl->Uniform4f(loc, r / 255.0f, g / 255.0f, b / 255.0f, a / 255.0f); + } + gl->UseProgram(0); debug_check_gl(p, "update_uniforms()"); @@ -471,8 +510,8 @@ static void update_uniforms(struct gl_priv *p, GLuint program) static void update_all_uniforms(struct gl_priv *p) { - update_uniforms(p, p->osd_program); - update_uniforms(p, p->eosd_program); + for (int n = 0; n < SUBBITMAP_COUNT; n++) + update_uniforms(p, p->osd_programs[n]); update_uniforms(p, p->indirect_program); update_uniforms(p, p->scale_sep_program); update_uniforms(p, p->final_program); @@ -636,20 +675,21 @@ static void compile_shaders(struct gl_priv *p) char *vertex_shader = get_section(tmp, src, "vertex_all"); char *shader_prelude = get_section(tmp, src, "prelude"); char *s_video = get_section(tmp, src, "frag_video"); - char *s_eosd = get_section(tmp, src, "frag_eosd"); - char *s_osd = get_section(tmp, src, "frag_osd"); char *header = talloc_asprintf(tmp, "#version %s\n%s", p->shader_version, shader_prelude); - char *header_eosd = talloc_strdup(tmp, header); - shader_def_opt(&header_eosd, "USE_3DLUT", p->use_lut_3d); + char *header_osd = talloc_strdup(tmp, header); + shader_def_opt(&header_osd, "USE_3DLUT", p->use_lut_3d); - p->eosd_program = - create_program(gl, "eosd", header_eosd, vertex_shader, s_eosd); - - p->osd_program = - create_program(gl, "osd", header, vertex_shader, s_osd); + for (int n = 0; n < SUBBITMAP_COUNT; n++) { + struct osd_fmt_entry fmt = osd_to_gl_formats[n]; + if (fmt.shader) { + char *s_osd = get_section(tmp, src, fmt.shader); + p->osd_programs[n] = + create_program(gl, fmt.shader, header_osd, vertex_shader, s_osd); + } + } char *header_conv = talloc_strdup(tmp, ""); char *header_final = talloc_strdup(tmp, ""); @@ -750,8 +790,8 @@ static void delete_shaders(struct gl_priv *p) { GL *gl = p->gl; - delete_program(gl, &p->osd_program); - delete_program(gl, &p->eosd_program); + for (int n = 0; n < SUBBITMAP_COUNT; n++) + delete_program(gl, &p->osd_programs[n]); delete_program(gl, &p->indirect_program); delete_program(gl, &p->scale_sep_program); delete_program(gl, &p->final_program); @@ -1449,7 +1489,7 @@ static void draw_osd(struct vo *vo, struct osd_state *osd) // OSD bitmaps use premultiplied alpha. gl->BlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - gl->UseProgram(p->osd_program); + gl->UseProgram(p->osd_programs[SUBBITMAP_OLD]); for (int n = 0; n < p->osd_textures_count; n++) { gl->BindTexture(GL_TEXTURE_2D, p->osd_textures[n]); @@ -1464,80 +1504,111 @@ static void draw_osd(struct vo *vo, struct osd_state *osd) } } -static void gen_eosd(struct gl_priv *p, mp_eosd_images_t *imgs) +static void gen_eosd(struct gl_priv *p, struct osd_render *osd, + struct sub_bitmaps *imgs) { GL *gl = p->gl; - bool need_repos, need_upload, need_allocate; - eosd_packer_generate(p->eosd, imgs, &need_repos, &need_upload, - &need_allocate); - - if (!need_repos) + if (imgs->bitmap_pos_id == osd->bitmap_pos_id) return; - if (!p->eosd_texture) { - gl->GenTextures(1, &p->eosd_texture); - gl->GenBuffers(1, &p->eosd_buffer); + osd->num_vertices = 0; + + if (imgs->format == SUBBITMAP_EMPTY) + return; + + bool need_upload = imgs->bitmap_id != osd->bitmap_id; + bool need_allocate = false; + + if (imgs->format != osd->format) { + packer_reset(osd->packer); + osd->format = imgs->format; + need_allocate = true; } - gl->BindTexture(GL_TEXTURE_2D, p->eosd_texture); + osd->bitmap_id = imgs->bitmap_id; + osd->bitmap_pos_id = imgs->bitmap_pos_id; + + osd->packer->padding = imgs->scaled; // assume 2x2 filter on scaling + int r = packer_pack_from_subbitmaps(osd->packer, imgs); + if (r < 0) { + mp_msg(MSGT_VO, MSGL_ERR, "[gl] EOSD bitmaps do not fit on " + "a surface with the maximum supported size %dx%d.\n", + osd->packer->w_max, osd->packer->h_max); + return; + } else if (r > 0) { + need_allocate = true; + } + + struct osd_fmt_entry fmt = osd_to_gl_formats[imgs->format]; + assert(fmt.shader); + + if (!osd->texture) { + gl->GenTextures(1, &osd->texture); + gl->GenBuffers(1, &osd->buffer); + } + + gl->BindTexture(GL_TEXTURE_2D, osd->texture); if (need_allocate) { - tex_size(p, p->eosd->surface.w, p->eosd->surface.h, - &p->eosd_texture_width, &p->eosd_texture_height); - gl->TexImage2D(GL_TEXTURE_2D, 0, GL_RED, - p->eosd_texture_width, p->eosd_texture_height, 0, - GL_RED, GL_UNSIGNED_BYTE, NULL); - default_tex_params(gl, GL_TEXTURE_2D, GL_NEAREST); - gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, p->eosd_buffer); + tex_size(p, osd->packer->w, osd->packer->h, &osd->width, &osd->height); + gl->TexImage2D(GL_TEXTURE_2D, 0, fmt.internal_format, osd->width, + osd->height, 0, fmt.format, fmt.type, NULL); + default_tex_params(gl, GL_TEXTURE_2D, GL_LINEAR); + gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, osd->buffer); gl->BufferData(GL_PIXEL_UNPACK_BUFFER, - p->eosd->surface.w * p->eosd->surface.h, - NULL, - GL_DYNAMIC_COPY); + osd->width * osd->height * fmt.stride, + NULL, GL_DYNAMIC_COPY); gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); } - p->eosd_va = talloc_realloc_size(p->eosd, p->eosd_va, - p->eosd->targets_count - * sizeof(struct vertex) - * VERTICES_PER_QUAD); + struct pos bb[2]; + packer_get_bb(osd->packer, bb); if (need_upload && p->use_pbo) { - gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, p->eosd_buffer); + gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, osd->buffer); char *data = gl->MapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY); + size_t stride = osd->width * fmt.stride; if (!data) { mp_msg(MSGT_VO, MSGL_FATAL, "[gl] Error: can't upload subtitles! " - "Subtitles will look corrupted.\n"); + "Remove the 'pbo' suboption.\n"); } else { - for (int n = 0; n < p->eosd->targets_count; n++) { - struct eosd_target *target = &p->eosd->targets[n]; - ASS_Image *i = target->ass_img; + if (imgs->scaled) { + int w = bb[1].x - bb[0].x; + int h = bb[1].y - bb[0].y; + memset_pic(data, 0, w * fmt.stride, h, stride); + } + for (int n = 0; n < osd->packer->count; n++) { + struct sub_bitmap *b = &imgs->parts[n]; + struct pos p = osd->packer->result[n]; - void *pdata = data + target->source.y0 * p->eosd->surface.w - + target->source.x0; - - memcpy_pic(pdata, i->bitmap, i->w, i->h, - p->eosd->surface.w, i->stride); + void *pdata = data + p.y * stride + p.x * fmt.stride; + memcpy_pic(pdata, b->bitmap, b->w * fmt.stride, b->h, + stride, b->stride); } if (!gl->UnmapBuffer(GL_PIXEL_UNPACK_BUFFER)) mp_msg(MSGT_VO, MSGL_FATAL, "[gl] EOSD PBO upload failed. " "Remove the 'pbo' suboption.\n"); - struct eosd_rect rc; - eosd_packer_calculate_source_bb(p->eosd, &rc); - glUploadTex(gl, GL_TEXTURE_2D, GL_RED, GL_UNSIGNED_BYTE, NULL, - p->eosd->surface.w, rc.x0, rc.y0, - rc.x1 - rc.x0, rc.y1 - rc.y0, 0); + glUploadTex(gl, GL_TEXTURE_2D, fmt.format, fmt.type, NULL, stride, + bb[0].x, bb[0].y, bb[1].x - bb[0].x, bb[1].y - bb[0].y, + 0); + need_upload = false; } gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); - } else if (need_upload) { + } + if (need_upload) { // non-PBO upload - for (int n = 0; n < p->eosd->targets_count; n++) { - struct eosd_target *target = &p->eosd->targets[n]; - ASS_Image *i = target->ass_img; + if (imgs->scaled) { + glClearTex(gl, GL_TEXTURE_2D, fmt.format, fmt.type, + bb[0].x, bb[0].y, bb[1].x - bb[0].y, bb[1].y - bb[0].y, + 0, &p->scratch); + } + for (int n = 0; n < osd->packer->count; n++) { + struct sub_bitmap *b = &imgs->parts[n]; + struct pos p = osd->packer->result[n]; - glUploadTex(gl, GL_TEXTURE_2D, GL_RED, GL_UNSIGNED_BYTE, i->bitmap, - i->stride, target->source.x0, target->source.y0, - i->w, i->h, 0); + glUploadTex(gl, GL_TEXTURE_2D, fmt.format, fmt.type, + b->bitmap, b->stride, p.x, p.y, b->w, b->h, 0); } } @@ -1545,36 +1616,51 @@ static void gen_eosd(struct gl_priv *p, mp_eosd_images_t *imgs) debug_check_gl(p, "EOSD upload"); - for (int n = 0; n < p->eosd->targets_count; n++) { - struct eosd_target *target = &p->eosd->targets[n]; - ASS_Image *i = target->ass_img; - uint8_t color[4] = { i->color >> 24, (i->color >> 16) & 0xff, - (i->color >> 8) & 0xff, 255 - (i->color & 0xff) }; + osd->vertices = talloc_realloc_size(osd, osd->vertices, + osd->packer->count + * sizeof(struct vertex) + * VERTICES_PER_QUAD); - write_quad(&p->eosd_va[n * VERTICES_PER_QUAD], - target->dest.x0, target->dest.y0, - target->dest.x1, target->dest.y1, - target->source.x0, target->source.y0, - target->source.x1, target->source.y1, - p->eosd_texture_width, p->eosd_texture_height, - color, false); + for (int n = 0; n < osd->packer->count; n++) { + struct sub_bitmap *b = &imgs->parts[n]; + struct pos p = osd->packer->result[n]; + + // NOTE: the blend color is used with SUBBITMAP_LIBASS only, so it + // doesn't matter that we upload garbage for the other formats + uint32_t c = b->libass.color; + uint8_t color[4] = { c >> 24, (c >> 16) & 0xff, + (c >> 8) & 0xff, 255 - (c & 0xff) }; + + write_quad(&osd->vertices[osd->num_vertices], + b->x, b->y, b->x + b->dw, b->y + b->dh, + p.x, p.y, p.x + b->w, p.y + b->h, + osd->width, osd->height, color, false); + osd->num_vertices += VERTICES_PER_QUAD; } } -static void draw_eosd(struct gl_priv *p, mp_eosd_images_t *imgs) +static void draw_eosd(struct gl_priv *p, struct sub_bitmaps *imgs) { GL *gl = p->gl; - gen_eosd(p, imgs); + struct osd_render *osd = p->osd[imgs->render_index]; - if (p->eosd->targets_count == 0) + gen_eosd(p, osd, imgs); + + if (osd->num_vertices == 0) return; + assert(osd->format != SUBBITMAP_EMPTY); + gl->Enable(GL_BLEND); - gl->BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - gl->BindTexture(GL_TEXTURE_2D, p->eosd_texture); - gl->UseProgram(p->eosd_program); - draw_triangles(p, p->eosd_va, p->eosd->targets_count * VERTICES_PER_QUAD); + if (osd->format == SUBBITMAP_OLD) { + gl->BlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + } else { + gl->BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } + gl->BindTexture(GL_TEXTURE_2D, osd->texture); + gl->UseProgram(p->osd_programs[osd->format]); + draw_triangles(p, osd->vertices, osd->num_vertices); gl->UseProgram(0); gl->BindTexture(GL_TEXTURE_2D, 0); gl->Disable(GL_BLEND); @@ -1641,7 +1727,18 @@ static int init_gl(struct gl_priv *p) GLint max_texture_size; gl->GetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size); - eosd_packer_reinit(p->eosd, max_texture_size, max_texture_size); + + for (int n = 0; n < MAX_OSD_PARTS; n++) { + assert(!p->osd[n]); + struct osd_render *osd = talloc_ptrtype(p, osd); + *osd = (struct osd_render) { + .packer = talloc_struct(osd, struct bitmap_packer, { + .w_max = max_texture_size, + .h_max = max_texture_size, + }), + }; + p->osd[n] = osd; + } gl->ClearColor(0.0f, 0.0f, 0.0f, 0.0f); gl->Clear(GL_COLOR_BUFFER_BIT); @@ -1667,11 +1764,15 @@ static void uninit_gl(struct gl_priv *p) p->vertex_buffer = 0; clear_osd(p); - gl->DeleteTextures(1, &p->eosd_texture); - p->eosd_texture = 0; - gl->DeleteBuffers(1, &p->eosd_buffer); - p->eosd_buffer = 0; - eosd_packer_reinit(p->eosd, 0, 0); + for (int n = 0; n < MAX_OSD_PARTS; n++) { + struct osd_render *osd = p->osd[n]; + if (!osd) + continue; + gl->DeleteTextures(1, &osd->texture); + gl->DeleteBuffers(1, &osd->buffer); + talloc_free(osd); + p->osd[n] = NULL; + } gl->DeleteTextures(1, &p->lut_3d_texture); p->lut_3d_texture = 0; @@ -1753,7 +1854,7 @@ static int query_format(uint32_t format) { int caps = VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW | VFCAP_FLIP | VFCAP_HWSCALE_UP | VFCAP_HWSCALE_DOWN | VFCAP_ACCEPT_STRIDE | - VFCAP_OSD | VFCAP_EOSD | VFCAP_EOSD_UNSCALED; + VFCAP_OSD | VFCAP_EOSD | VFCAP_EOSD_UNSCALED | VFCAP_EOSD_RGBA; if (!init_format(format, NULL)) return 0; return caps; @@ -2244,6 +2345,7 @@ static int preinit(struct vo *vo, const char *arg) { .index = 1, .name = "bilinear" }, }, .scaler_params = {NAN, NAN}, + .scratch = talloc_zero_array(p, char *, 1), }; p->defaults = talloc(p, struct gl_priv); @@ -2323,8 +2425,6 @@ static int preinit(struct vo *vo, const char *arg) p->orig_cmdline = talloc(p, struct gl_priv); *p->orig_cmdline = *p; - p->eosd = eosd_packer_create(vo); - p->glctx = init_mpglcontext(backend, vo); if (!p->glctx) goto err_out; diff --git a/libvo/vo_gl3_shaders.glsl b/libvo/vo_gl3_shaders.glsl index f67e55e6f5..20f8c597ad 100644 --- a/libvo/vo_gl3_shaders.glsl +++ b/libvo/vo_gl3_shaders.glsl @@ -45,7 +45,7 @@ void main() { texcoord = vertex_texcoord; } -#!section frag_eosd +#!section frag_osd_libass uniform sampler2D texture1; in vec2 texcoord; @@ -56,15 +56,25 @@ void main() { out_color = vec4(color.rgb, color.a * texture(texture1, texcoord).r); } -#!section frag_osd +#!section frag_osd_rgba uniform sampler2D texture1; in vec2 texcoord; -in vec4 color; out vec4 out_color; void main() { - out_color = texture(texture1, texcoord).rrrg * color; + out_color = texture(texture1, texcoord); +} + +#!section frag_osd_old +uniform sampler2D texture1; +uniform vec4 osd_color; + +in vec2 texcoord; +out vec4 out_color; + +void main() { + out_color = texture(texture1, texcoord).rrrg * osd_color; } #!section frag_video From 2a5fcd2801ccaff48ad360613cef2d0edf80543c Mon Sep 17 00:00:00 2001 From: wm4 Date: Fri, 28 Sep 2012 21:33:26 +0200 Subject: [PATCH 03/83] sub: add preliminary emulation layer to draw OSD with EOSD This basically pushes the old OSD bitmaps via VOCTRL_DRAW_EOSD to the VO, instead of using the old callback-based interface. Future commits will change the code such that sub.c pushes images rendered by libass directly, rather than converting them to the old OSD format first. --- sub/sub.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ sub/sub.h | 9 +++++++ 2 files changed, 82 insertions(+) diff --git a/sub/sub.c b/sub/sub.c index c527503ef1..8b89ca497c 100644 --- a/sub/sub.c +++ b/sub/sub.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -253,6 +254,7 @@ struct osd_state *osd_create(struct MPOpts *opts, struct ass_library *asslib) .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); @@ -369,3 +371,74 @@ int vo_osd_check_range_update(int x1,int y1,int x2,int y2){ } return 0; } + +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) +{ + 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]; + } + } + + 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; + + 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); +} diff --git a/sub/sub.h b/sub/sub.h index fc0047bba6..74d2b5a37a 100644 --- a/sub/sub.h +++ b/sub/sub.h @@ -24,10 +24,13 @@ #include "subreader.h" #include "dec_sub.h" +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 @@ -78,6 +81,10 @@ struct osd_state { char *osd_text; int w, h; + struct sub_bitmaps eosd[MAX_OSD_PARTS]; + + void *scratch; + struct MPOpts *opts; }; @@ -153,6 +160,8 @@ 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); + 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); From 3099498154a06c6df0c365de2cc0af09686cd6e1 Mon Sep 17 00:00:00 2001 From: wm4 Date: Fri, 28 Sep 2012 21:36:36 +0200 Subject: [PATCH 04/83] vo_gl3: use old OSD using the emulation layer This still renders the OSD using essentially the same mechanisms, except that the EOSD code for texture handling and rendering is reused. --- libvo/vo_gl3.c | 98 +------------------------------------------------- 1 file changed, 1 insertion(+), 97 deletions(-) diff --git a/libvo/vo_gl3.c b/libvo/vo_gl3.c index e3d3b9af62..08f1514094 100644 --- a/libvo/vo_gl3.c +++ b/libvo/vo_gl3.c @@ -186,11 +186,6 @@ struct gl_priv { GLuint osd_programs[SUBBITMAP_COUNT]; GLuint indirect_program, scale_sep_program, final_program; - // old OSD code - should go away - GLuint osd_textures[MAX_OSD_PARTS]; - int osd_textures_count; - struct vertex osd_va[MAX_OSD_PARTS * VERTICES_PER_QUAD]; - struct osd_render *osd[MAX_OSD_PARTS]; GLuint lut_3d_texture; @@ -1414,96 +1409,6 @@ static mp_image_t *get_window_screenshot(struct gl_priv *p) return image; } -static void clear_osd(struct gl_priv *p) -{ - GL *gl = p->gl; - - if (!p->osd_textures_count) - return; - gl->DeleteTextures(p->osd_textures_count, p->osd_textures); - p->osd_textures_count = 0; -} - -static void create_osd_texture(void *ctx, int x0, int y0, int w, int h, - unsigned char *src, unsigned char *srca, - int stride) -{ - struct gl_priv *p = ctx; - GL *gl = p->gl; - - if (w <= 0 || h <= 0 || stride < w) { - mp_msg(MSGT_VO, MSGL_V, "Invalid dimensions OSD for part!\n"); - return; - } - - if (p->osd_textures_count >= MAX_OSD_PARTS) { - mp_msg(MSGT_VO, MSGL_ERR, "Too many OSD parts, contact the developers!\n"); - return; - } - - int sx, sy; - tex_size(p, w, h, &sx, &sy); - - gl->GenTextures(1, &p->osd_textures[p->osd_textures_count]); - gl->BindTexture(GL_TEXTURE_2D, p->osd_textures[p->osd_textures_count]); - gl->TexImage2D(GL_TEXTURE_2D, 0, GL_RG, sx, sy, 0, GL_RG, GL_UNSIGNED_BYTE, - NULL); - default_tex_params(gl, GL_TEXTURE_2D, GL_NEAREST); - unsigned char *tmp = malloc(stride * h * 2); - // Convert alpha from weird MPlayer scale. - for (int i = 0; i < h * stride; i++) { - tmp[i*2+0] = src[i]; - tmp[i*2+1] = -srca[i]; - } - glUploadTex(gl, GL_TEXTURE_2D, GL_RG, GL_UNSIGNED_BYTE, tmp, stride * 2, - 0, 0, w, h, 0); - free(tmp); - - gl->BindTexture(GL_TEXTURE_2D, 0); - - uint8_t color[4] = {(p->osd_color >> 16) & 0xff, (p->osd_color >> 8) & 0xff, - p->osd_color & 0xff, 0xff - (p->osd_color >> 24)}; - - write_quad(&p->osd_va[p->osd_textures_count * VERTICES_PER_QUAD], - x0, y0, x0 + w, y0 + h, 0, 0, w, h, - sx, sy, color, false); - - p->osd_textures_count++; -} - -static void draw_osd(struct vo *vo, struct osd_state *osd) -{ - struct gl_priv *p = vo->priv; - GL *gl = p->gl; - - if (vo_osd_has_changed(osd)) { - clear_osd(p); - osd_draw_text_ext(osd, vo->dwidth, vo->dheight, p->border_x, - p->border_y, p->border_x, - p->border_y, p->image_width, - p->image_height, create_osd_texture, p); - } - - if (p->osd_textures_count > 0) { - gl->Enable(GL_BLEND); - // OSD bitmaps use premultiplied alpha. - gl->BlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - - gl->UseProgram(p->osd_programs[SUBBITMAP_OLD]); - - for (int n = 0; n < p->osd_textures_count; n++) { - gl->BindTexture(GL_TEXTURE_2D, p->osd_textures[n]); - draw_triangles(p, &p->osd_va[n * VERTICES_PER_QUAD], - VERTICES_PER_QUAD); - } - - gl->UseProgram(0); - - gl->Disable(GL_BLEND); - gl->BindTexture(GL_TEXTURE_2D, 0); - } -} - static void gen_eosd(struct gl_priv *p, struct osd_render *osd, struct sub_bitmaps *imgs) { @@ -1763,7 +1668,6 @@ static void uninit_gl(struct gl_priv *p) gl->DeleteBuffers(1, &p->vertex_buffer); p->vertex_buffer = 0; - clear_osd(p); for (int n = 0; n < MAX_OSD_PARTS; n++) { struct osd_render *osd = p->osd[n]; if (!osd) @@ -2462,7 +2366,7 @@ const struct vo_driver video_out_gl3 = { .config = config, .control = control, .draw_slice = draw_slice, - .draw_osd = draw_osd, + .draw_osd = emulate_draw_osd, .flip_page = flip_page, .check_events = check_events, .uninit = uninit, From 3365514951e9c07ec3a21bb3898e5796c214f8b7 Mon Sep 17 00:00:00 2001 From: wm4 Date: Fri, 28 Sep 2012 21:38:52 +0200 Subject: [PATCH 05/83] sub: allow rendering OSD in ASS image format directly, simplify Before this commit, the OSD was drawn using libass, but the resulting bitmaps were converted to the internal mplayer OSD format. We want to get rid of the old OSD format, because it's monochrome, and can't even be rendered directly using modern video output methods (like with OpenGL/Direct3D/VDPAU). Change it so that VOs can get the ASS images directly, without additional conversions. (This also has the consequence that the OSD can render colors now.) Currently, this is vo_gl3 only. The other VOs still use the old method. Also, the old OSD format is still used for all VOs with DVD subtitles (spudec). Rewrite sub.c. Remove all the awkward flags and bounding boxes and change detection things. It turns out that much of that isn't needed. Move code related to converting subtitle images to img_convert.c. (It has to be noted that all of these conversions were already done before in some places, and that the new code actually makes less use of them.) --- Makefile | 1 + libvo/video_out.h | 1 + libvo/vo_gl3.c | 6 +- sub/ass_mp.c | 35 ++++ sub/ass_mp.h | 5 + sub/dec_sub.h | 13 +- sub/img_convert.c | 214 ++++++++++++++++++++++ sub/img_convert.h | 16 ++ sub/osd_dummy.c | 26 +-- sub/osd_libass.c | 195 ++++++-------------- sub/sd_ass.c | 36 +--- sub/spudec.c | 40 +++- sub/spudec.h | 3 + sub/sub.c | 455 +++++++++++++++++----------------------------- sub/sub.h | 77 ++++---- 15 files changed, 600 insertions(+), 523 deletions(-) create mode 100644 sub/img_convert.c create mode 100644 sub/img_convert.h 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 #include -#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 . + */ + +#include +#include + +#include +#include + +#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 + +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_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; - } + 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); -} - - 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 #include #include +#include #include #include @@ -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 +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 #include -#include #include #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->allocatedallocated = 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 struct osd_state *global_osd; -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; -} -void osd_free(struct osd_state *osd) +static void osd_update_ext(struct osd_state *osd, struct mp_eosd_res res) { - 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; + 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; } - 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) +void osd_update(struct osd_state *osd, int w, int h) { - 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<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; - } - return chg; -} - -int osd_update(struct osd_state *osd, int dxs, int dys) -{ - 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; -} - -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) +void vo_osd_resized(void) { - 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]; - } - } - - 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++; + // 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; } -// draw old-OSD using EOSD -void emulate_draw_osd(struct vo *vo, struct osd_state *osd) +bool sub_bitmaps_bb(struct sub_bitmaps *imgs, int *x1, int *y1, + int *x2, int *y2) { - mp_eosd_res_t res = {0}; - if (vo_control(vo, VOCTRL_GET_EOSD_RES, &res) != VO_TRUE) - return; + *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 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); + // avoid degenerate bounding box if empty + *x1 = FFMIN(*x1, *x2); + *y1 = FFMIN(*y1, *y2); + + 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_OSD_PARTS 5 -#define MAX_UCS 1600 -#define MAX_UCSLINES 16 +#define OSD_CONV_CACHE_MAX 2 -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; +struct osd_object { + int type; // OSDTYPE_* + bool force_redraw; - int allocated; - unsigned char *alpha_buffer; - unsigned char *bitmap_buffer; + // 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_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); +// defined in osd_libass.c and osd_dummy.c + +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); From 5fc5ae752bfaa6bddf76aa1912b4b9724578f5dd Mon Sep 17 00:00:00 2001 From: wm4 Date: Fri, 28 Sep 2012 21:48:30 +0200 Subject: [PATCH 06/83] sub: allow converting DVD subs to RGBA The mplayer DVD sub decoder is the only remaining OSD image producer that still requires the old mplayer OSD format (SUBBITMAP_OLD_PLANAR). To make supporting this format optional in VOs, add a step that allows converting these images to RGBA in case the VO doesn't have direct support for it. Note: the mplayer DVD sub decoder uses the old mplayer OSD format (SUBBITMAP_OLD_PLANAR), which is assumed to use premultiplied alpha. However, it seems DVDs allow only binary transparency, so the rendered result will be the same. --- sub/img_convert.c | 52 ++++++++++++++++++++++++++++++++++++++++++----- sub/img_convert.h | 1 + sub/sub.c | 4 ++++ sub/sub.h | 2 +- 4 files changed, 53 insertions(+), 6 deletions(-) diff --git a/sub/img_convert.c b/sub/img_convert.c index 38a367253c..6eef4a01a3 100644 --- a/sub/img_convert.c +++ b/sub/img_convert.c @@ -31,7 +31,7 @@ struct osd_conv_cache { // 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) + // for osd_conv_cache_alloc_bmp() (various other formats) unsigned char *packed; }; @@ -73,15 +73,16 @@ static void osd_conv_cache_alloc_old_p(struct osd_conv_cache *c, int w, int h) }; } -static void osd_conv_cache_alloc_old(struct osd_conv_cache *c, int w, int h) +static void osd_conv_cache_alloc_bmp(struct osd_conv_cache *c, int w, int h, + int bpp) { size_t size = talloc_get_size(c->packed); - size_t new_size = w * 2 * h; + size_t new_size = w * bpp * 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, + .stride = w * bpp, .w = w, .h = h, .dw = w, .dh = h, }; @@ -176,6 +177,47 @@ bool osd_conv_ass_to_old_p(struct osd_conv_cache *c, struct sub_bitmaps *imgs) return true; } +// SUBBITMAP_OLD_PLANAR -> SUBBITMAP_RGBA +bool osd_conv_old_p_to_rgba(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_RGBA; + 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_bmp(c, s->w, s->h, 4); + + 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 * 4; + for (int x = 0; x < s->w; x++) { + // This is incorrect, as input is premultiplied alpha, but output + // has to be non-premultiplied. However, this code is for + // compatibility with spudec.c only, and DVD subtitles have + // binary transparency only - the rendered result will be the same. + cur[x*4+0] = cur[x*4+1] = cur[x*4+2] = y_src[x]; + cur[x*4+3] = -y_srca[x]; + } + } + + c->part.x = s->x; + c->part.y = s->y; + + 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) { @@ -193,7 +235,7 @@ bool osd_conv_old_p_to_old(struct osd_conv_cache *c, struct sub_bitmaps *imgs) struct sub_bitmap *s = &src.parts[0]; struct old_osd_planar *p = s->bitmap; - osd_conv_cache_alloc_old(c, s->w, s->h); + osd_conv_cache_alloc_bmp(c, s->w, s->h, 2); for (int y = 0; y < s->h; y++) { unsigned char *y_src = p->bitmap + s->stride * y; diff --git a/sub/img_convert.h b/sub/img_convert.h index c40a8de2e4..b4201f606c 100644 --- a/sub/img_convert.h +++ b/sub/img_convert.h @@ -11,6 +11,7 @@ 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_old_p_to_rgba(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/sub.c b/sub/sub.c index 3f1b08c185..182215310f 100644 --- a/sub/sub.c +++ b/sub/sub.c @@ -210,6 +210,10 @@ static bool render_object(struct osd_state *osd, struct osd_object *obj, cached |= osd_conv_old_p_to_old(obj->cache[1], out_imgs); } + if (formats[SUBBITMAP_RGBA] && out_imgs->format == SUBBITMAP_OLD_PLANAR) { + cached |= osd_conv_old_p_to_rgba(obj->cache[2], out_imgs); + } + if (cached) obj->cached = *out_imgs; diff --git a/sub/sub.h b/sub/sub.h index 1dee0c8a8f..7deaf73b8e 100644 --- a/sub/sub.h +++ b/sub/sub.h @@ -34,7 +34,7 @@ struct vo; #define MAX_OSD_PARTS 5 -#define OSD_CONV_CACHE_MAX 2 +#define OSD_CONV_CACHE_MAX 3 struct osd_object { int type; // OSDTYPE_* From 18ab695a7296c4bceeb64bef0a898ed3807facd2 Mon Sep 17 00:00:00 2001 From: wm4 Date: Fri, 28 Sep 2012 21:49:09 +0200 Subject: [PATCH 07/83] vo_vdpau: allow multiple EOSD renderers Preparation for using new OSD rendering method. --- libvo/vo_vdpau.c | 79 +++++++++++++++++++++++++++--------------------- 1 file changed, 45 insertions(+), 34 deletions(-) diff --git a/libvo/vo_vdpau.c b/libvo/vo_vdpau.c index d5856e2dfa..8c0f78745f 100644 --- a/libvo/vo_vdpau.c +++ b/libvo/vo_vdpau.c @@ -175,18 +175,19 @@ struct vdpctx { uint32_t max_width; uint32_t max_height; struct bitmap_packer *packer; - } eosd_surface, osd_surface; + struct eosd_target *targets; + int targets_size; + int render_count; + int bitmap_id; + int bitmap_pos_id; + } eosd_surfaces[MAX_OSD_PARTS], osd_surface; // List of surfaces to be rendered struct eosd_target { VdpRect source; VdpRect dest; VdpColor color; - } *eosd_targets, osd_targets[MAX_OSD_PARTS][2]; - int eosd_targets_size; - int eosd_render_count; - int bitmap_id; - int bitmap_pos_id; + } osd_targets[MAX_OSD_PARTS][2]; // Video equalizer struct mp_csp_equalizer video_eq; @@ -812,13 +813,18 @@ static void mark_vdpau_objects_uninitialized(struct vo *vo) vc->output_surfaces[i] = VDP_INVALID_HANDLE; vc->vdp_device = VDP_INVALID_HANDLE; talloc_free(vc->osd_surface.packer); - talloc_free(vc->eosd_surface.packer); - vc->bitmap_id = vc->bitmap_pos_id = 0; - vc->osd_surface = vc->eosd_surface = (struct eosd_bitmap_surface){ + for (int i = 0; i < MAX_OSD_PARTS; i++) { + struct eosd_bitmap_surface *sfc = &vc->eosd_surfaces[i]; + talloc_free(sfc->packer); + sfc->bitmap_id = sfc->bitmap_pos_id = 0; + *sfc = (struct eosd_bitmap_surface){ + .surface = VDP_INVALID_HANDLE, + }; + } + vc->osd_surface = (struct eosd_bitmap_surface){ .surface = VDP_INVALID_HANDLE, }; vc->output_surface_width = vc->output_surface_height = -1; - vc->eosd_render_count = 0; } static int handle_preemption(struct vo *vo) @@ -958,11 +964,12 @@ static struct bitmap_packer *make_packer(struct vo *vo, VdpRGBAFormat format) return packer; } -static void draw_eosd(struct vo *vo) +static void draw_eosd(struct vo *vo, int index) { struct vdpctx *vc = vo->priv; struct vdp_functions *vdp = vc->vdp; VdpStatus vdp_st; + struct eosd_bitmap_surface *sfc = &vc->eosd_surfaces[index]; VdpOutputSurface output_surface = vc->output_surfaces[vc->surface_num]; int i; @@ -980,13 +987,13 @@ static void draw_eosd(struct vo *vo) .blend_equation_alpha = VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_ADD, }; - for (i = 0; i < vc->eosd_render_count; i++) { + for (i = 0; i < sfc->render_count; i++) { vdp_st = vdp-> output_surface_render_bitmap_surface(output_surface, - &vc->eosd_targets[i].dest, - vc->eosd_surface.surface, - &vc->eosd_targets[i].source, - &vc->eosd_targets[i].color, + &sfc->targets[i].dest, + sfc->surface, + &sfc->targets[i].source, + &sfc->targets[i].color, &blend_state, VDP_OUTPUT_SURFACE_RENDER_ROTATE_0); CHECK_ST_WARNING("EOSD: Error when rendering"); @@ -998,18 +1005,18 @@ static void generate_eosd(struct vo *vo, mp_eosd_images_t *imgs) struct vdpctx *vc = vo->priv; struct vdp_functions *vdp = vc->vdp; VdpStatus vdp_st; - struct eosd_bitmap_surface *sfc = &vc->eosd_surface; + struct eosd_bitmap_surface *sfc = &vc->eosd_surfaces[imgs->render_index]; bool need_upload = false; - if (imgs->bitmap_pos_id == vc->bitmap_pos_id) + if (imgs->bitmap_pos_id == sfc->bitmap_pos_id) return; // Nothing changed and we still have the old data - vc->eosd_render_count = 0; + sfc->render_count = 0; if (imgs->format == SUBBITMAP_EMPTY) return; - if (imgs->bitmap_id == vc->bitmap_id) + if (imgs->bitmap_id == sfc->bitmap_id) goto eosd_skip_upload; need_upload = true; @@ -1066,16 +1073,16 @@ static void generate_eosd(struct vo *vo, mp_eosd_images_t *imgs) eosd_skip_upload: if (sfc->surface == VDP_INVALID_HANDLE) return; - if (sfc->packer->count > vc->eosd_targets_size) { - talloc_free(vc->eosd_targets); - vc->eosd_targets_size = sfc->packer->count; - vc->eosd_targets = talloc_size(vc, vc->eosd_targets_size - * sizeof(*vc->eosd_targets)); + if (sfc->packer->count > sfc->targets_size) { + talloc_free(sfc->targets); + sfc->targets_size = sfc->packer->count; + sfc->targets = talloc_size(vc, sfc->targets_size + * sizeof(*sfc->targets)); } for (int i = 0 ;i < sfc->packer->count; i++) { struct sub_bitmap *b = &imgs->parts[i]; - struct eosd_target *target = vc->eosd_targets + vc->eosd_render_count; + struct eosd_target *target = sfc->targets + sfc->render_count; int x = sfc->packer->result[i].x; int y = sfc->packer->result[i].y; target->source = (VdpRect){x, y, x + b->w, y + b->h}; @@ -1096,11 +1103,11 @@ eosd_skip_upload: &target->source); CHECK_ST_WARNING("EOSD: putbits failed"); } - vc->eosd_render_count++; + sfc->render_count++; } - vc->bitmap_id = imgs->bitmap_id; - vc->bitmap_pos_id = imgs->bitmap_pos_id; + sfc->bitmap_id = imgs->bitmap_id; + sfc->bitmap_pos_id = imgs->bitmap_pos_id; } static void record_osd(void *ctx, int x0, int y0, int w, int h, @@ -1604,9 +1611,12 @@ static void destroy_vdpau_objects(struct vo *vo) CHECK_ST_WARNING("Error when calling vdp_output_surface_destroy"); } - if (vc->eosd_surface.surface != VDP_INVALID_HANDLE) { - vdp_st = vdp->bitmap_surface_destroy(vc->eosd_surface.surface); - CHECK_ST_WARNING("Error when calling vdp_bitmap_surface_destroy"); + for (int i = 0; i < MAX_OSD_PARTS; i++) { + struct eosd_bitmap_surface *sfc = &vc->eosd_surfaces[i]; + if (sfc->surface != VDP_INVALID_HANDLE) { + vdp_st = vdp->bitmap_surface_destroy(sfc->surface); + CHECK_ST_WARNING("Error when calling vdp_bitmap_surface_destroy"); + } } if (vc->osd_surface.surface != VDP_INVALID_HANDLE) { @@ -1779,8 +1789,9 @@ static int control(struct vo *vo, uint32_t request, void *data) if (!data) return VO_FALSE; if (status_ok(vo)) { - generate_eosd(vo, data); - draw_eosd(vo); + mp_eosd_images_t *imgs = data; + generate_eosd(vo, imgs); + draw_eosd(vo, imgs->render_index); } return VO_TRUE; case VOCTRL_GET_EOSD_RES: { From bef616ede902b2e75f4b3f75f64b68998f1fee48 Mon Sep 17 00:00:00 2001 From: wm4 Date: Fri, 28 Sep 2012 21:49:32 +0200 Subject: [PATCH 08/83] vo_vdpau: use new EOSD for OSD, remove support for old OSD format This allows vo_vdpau to render OSD directly, without the indirection through the old OSD API, and without the additional conversions. Remove support for the old OSD format. Only the mplayer DVD subtitle decoder still generates this format. Although the new OSD interface does support this format, remove it from vo_vdpau. It would be relatively hard to support it in the EOSD code, as it requires two surfaces. (These two surfaces are blended on top of each other to emulate the mplayer OSD format.) The correct way to implement direct support for DVD subs would consist of adding a paletted image format of some sort. But even sd_lavc converts paletted subtitle images to RGBA, so doing something special just for DVD subs is not worth it. This means the frontend (sub.c) converts the subtitles to RGBA if it detects that vo_vdpau does not support them natively. --- libvo/vo_vdpau.c | 193 ++++------------------------------------------- 1 file changed, 13 insertions(+), 180 deletions(-) diff --git a/libvo/vo_vdpau.c b/libvo/vo_vdpau.c index 8c0f78745f..41feaca7b6 100644 --- a/libvo/vo_vdpau.c +++ b/libvo/vo_vdpau.c @@ -158,16 +158,6 @@ struct vdpctx { VdpChromaType vdp_chroma_type; VdpYCbCrFormat vdp_pixel_format; - /* draw_osd */ - struct old_osd { - int x0, y0, w, h; - unsigned char *src, *srca; - int stride; - } old_osd_elements[MAX_OSD_PARTS]; - int old_osd_count; - unsigned char *osd_data_temp; - int osd_data_size; - // EOSD struct eosd_bitmap_surface { VdpRGBAFormat format; @@ -175,19 +165,17 @@ struct vdpctx { uint32_t max_width; uint32_t max_height; struct bitmap_packer *packer; - struct eosd_target *targets; + // List of surfaces to be rendered + struct eosd_target { + VdpRect source; + VdpRect dest; + VdpColor color; + } *targets; int targets_size; int render_count; int bitmap_id; int bitmap_pos_id; - } eosd_surfaces[MAX_OSD_PARTS], osd_surface; - - // List of surfaces to be rendered - struct eosd_target { - VdpRect source; - VdpRect dest; - VdpColor color; - } osd_targets[MAX_OSD_PARTS][2]; + } eosd_surfaces[MAX_OSD_PARTS]; // Video equalizer struct mp_csp_equalizer video_eq; @@ -812,7 +800,6 @@ static void mark_vdpau_objects_uninitialized(struct vo *vo) for (int i = 0; i < MAX_OUTPUT_SURFACES; i++) vc->output_surfaces[i] = VDP_INVALID_HANDLE; vc->vdp_device = VDP_INVALID_HANDLE; - talloc_free(vc->osd_surface.packer); for (int i = 0; i < MAX_OSD_PARTS; i++) { struct eosd_bitmap_surface *sfc = &vc->eosd_surfaces[i]; talloc_free(sfc->packer); @@ -821,9 +808,6 @@ static void mark_vdpau_objects_uninitialized(struct vo *vo) .surface = VDP_INVALID_HANDLE, }; } - vc->osd_surface = (struct eosd_bitmap_surface){ - .surface = VDP_INVALID_HANDLE, - }; vc->output_surface_width = vc->output_surface_height = -1; } @@ -1110,157 +1094,6 @@ eosd_skip_upload: sfc->bitmap_pos_id = imgs->bitmap_pos_id; } -static void record_osd(void *ctx, int x0, int y0, int w, int h, - unsigned char *src, unsigned char *srca, int stride) -{ - struct vo *vo = ctx; - struct vdpctx *vc = vo->priv; - - assert(vc->old_osd_count < MAX_OSD_PARTS); - if (!w || !h) - return; - vc->old_osd_elements[vc->old_osd_count++] = (struct old_osd){ - x0, y0, w, h, src, srca, stride}; -} - -static void render_old_osd(struct vo *vo) -{ - struct vdpctx *vc = vo->priv; - struct vdp_functions *vdp = vc->vdp; - VdpOutputSurface output_surface = vc->output_surfaces[vc->surface_num]; - VdpStatus vdp_st; - struct eosd_bitmap_surface *sfc = &vc->osd_surface; - - if (!sfc->packer) - sfc->packer = make_packer(vo, VDP_RGBA_FORMAT_A8); - - packer_set_size(sfc->packer, vc->old_osd_count * 2); - for (int i = 0; i < vc->old_osd_count; i++) { - struct old_osd *o = &vc->old_osd_elements[i]; - sfc->packer->in[i*2] = sfc->packer->in[i*2 + 1] = - (struct pos){o->w, o->h}; - }; - int r = packer_pack(sfc->packer); - if (r < 0) { - mp_msg(MSGT_VO, MSGL_ERR, "[vdpau] OSD bitmaps do not fit on " - "a surface with the maximum supported size\n"); - vc->old_osd_count = 0; - return; - } else if (r == 1) { - if (sfc->surface != VDP_INVALID_HANDLE) { - vdp_st = vdp->bitmap_surface_destroy(sfc->surface); - CHECK_ST_WARNING("Error when calling vdp_bitmap_surface_destroy"); - } - mp_msg(MSGT_VO, MSGL_V, "[vdpau] Allocating a %dx%d surface for " - "OSD bitmaps.\n", sfc->packer->w, sfc->packer->h); - vdp_st = vdp->bitmap_surface_create(vc->vdp_device, VDP_RGBA_FORMAT_A8, - sfc->packer->w, sfc->packer->h, - true, &sfc->surface); - if (vdp_st != VDP_STATUS_OK) - sfc->surface = VDP_INVALID_HANDLE; - CHECK_ST_WARNING("OSD: error when creating surface"); - } - - for (int i = 0; i < vc->old_osd_count; i++) { - struct old_osd *o = &vc->old_osd_elements[i]; - struct eosd_target *target1 = &vc->osd_targets[i][0]; - struct eosd_target *target2 = &vc->osd_targets[i][1]; - int w = o->w, h = o->h; - int sx = sfc->packer->result[i * 2].x; - int sy = sfc->packer->result[i * 2].y; - target1->source = (VdpRect){ sx, sy, sx + w, sy + h }; - target1->dest = (VdpRect){ o->x0, o->y0, o->x0 + w, o->y0 + h }; - sx = sfc->packer->result[i * 2 + 1].x; - sy = sfc->packer->result[i * 2 + 1].y; - target2->source = (VdpRect){ sx, sy, sx + w, sy + h }; - target2->dest = target1->dest; - vdp_st = vdp->bitmap_surface_put_bits_native(sfc->surface, - &(const void *){o->src}, - &(uint32_t){o->stride}, - &target1->source); - CHECK_ST_WARNING("OSD: putbits failed"); - int size_required = w * h; - if (vc->osd_data_size < size_required) { - talloc_free(vc->osd_data_temp); - vc->osd_data_temp = talloc_size(vc, size_required); - vc->osd_data_size = size_required; - } - for (int y = 0; y < h; y++) - for (int x = 0; x < w; x++) - vc->osd_data_temp[y * w + x] = -o->srca[y * o->stride + x]; - vdp_st = vdp->bitmap_surface_put_bits_native(sfc->surface, - &(const void *){vc->osd_data_temp}, - &(uint32_t){w}, - &target2->source); - CHECK_ST_WARNING("OSD: putbits failed"); - } - - VdpOutputSurfaceRenderBlendState blend_state_alpha = { - .struct_version = VDP_OUTPUT_SURFACE_RENDER_BLEND_STATE_VERSION, - .blend_factor_source_color = - VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ZERO, - .blend_factor_source_alpha = - VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ZERO, - .blend_factor_destination_color = - VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, - .blend_factor_destination_alpha = - VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, - .blend_equation_color = VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_ADD, - .blend_equation_alpha = VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_ADD, - }; - - VdpOutputSurfaceRenderBlendState blend_state_gray = { - .struct_version = VDP_OUTPUT_SURFACE_RENDER_BLEND_STATE_VERSION, - .blend_factor_source_color = - VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_SRC_ALPHA, - .blend_factor_source_alpha = - VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_SRC_ALPHA, - .blend_factor_destination_color = - VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE, - .blend_factor_destination_alpha = - VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE, - .blend_equation_color = VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_ADD, - .blend_equation_alpha = VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_ADD, - }; - - for (int i = 0; i < vc->old_osd_count; i++) { - struct eosd_target *target1 = &vc->osd_targets[i][0]; - struct eosd_target *target2 = &vc->osd_targets[i][1]; - vdp_st = vdp-> - output_surface_render_bitmap_surface(output_surface, - &target2->dest, - vc->osd_surface.surface, - &target2->source, - &(VdpColor){1, 1, 1, 1}, - &blend_state_alpha, - VDP_OUTPUT_SURFACE_RENDER_ROTATE_0); - CHECK_ST_WARNING("OSD: Error when rendering"); - vdp_st = vdp-> - output_surface_render_bitmap_surface(output_surface, - &target1->dest, - vc->osd_surface.surface, - &target1->source, - &(VdpColor){1, 1, 1, 1}, - &blend_state_gray, - VDP_OUTPUT_SURFACE_RENDER_ROTATE_0); - CHECK_ST_WARNING("OSD: Error when rendering"); - } -} - -static void draw_osd(struct vo *vo, struct osd_state *osd) -{ - struct vdpctx *vc = vo->priv; - - if (handle_preemption(vo) < 0) - return; - - vc->old_osd_count = 0; - osd_draw_text_ext(osd, vo->dwidth, vo->dheight, vc->border_x, vc->border_y, - vc->border_x, vc->border_y, vc->vid_width, - vc->vid_height, record_osd, vo); - render_old_osd(vo); -} - static int update_presentation_queue_status(struct vo *vo) { struct vdpctx *vc = vo->priv; @@ -1619,11 +1452,6 @@ static void destroy_vdpau_objects(struct vo *vo) } } - if (vc->osd_surface.surface != VDP_INVALID_HANDLE) { - vdp_st = vdp->bitmap_surface_destroy(vc->osd_surface.surface); - CHECK_ST_WARNING("Error when calling vdp_bitmap_surface_destroy"); - } - vdp_st = vdp->device_destroy(vc->vdp_device); CHECK_ST_WARNING("Error when calling vdp_device_destroy"); } @@ -1802,6 +1630,11 @@ static int control(struct vo *vo, uint32_t request, void *data) r->mt = r->mb = vc->border_y; return VO_TRUE; } + case VOCTRL_QUERY_EOSD_FORMAT: { + int format = *(int *)data; + return (format == SUBBITMAP_LIBASS || format == SUBBITMAP_RGBA) + ? VO_TRUE : VO_NOTIMPL; + } case VOCTRL_NEWFRAME: vc->deint_queue_pos = next_deint_queue_pos(vo, true); if (status_ok(vo)) @@ -1849,7 +1682,7 @@ const struct vo_driver video_out_vdpau = { .draw_image = draw_image, .get_buffered_frame = set_next_frame_info, .draw_slice = draw_slice, - .draw_osd = draw_osd, + .draw_osd = draw_osd_with_eosd, .flip_page_timed = flip_page_timed, .check_events = check_events, .uninit = uninit, From ef43d7701d2ae26227fad403e48a03cf2aea0ab0 Mon Sep 17 00:00:00 2001 From: wm4 Date: Sat, 29 Sep 2012 09:52:27 +0200 Subject: [PATCH 09/83] mplayer: reset subtitles handled by dec_sub.c on seek This was somehow lost when merging this. --- mplayer.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mplayer.c b/mplayer.c index 5c08cdf330..3d4e61c9e2 100644 --- a/mplayer.c +++ b/mplayer.c @@ -1758,6 +1758,8 @@ double playing_audio_pts(struct MPContext *mpctx) static void reset_subtitles(struct MPContext *mpctx) { + if (mpctx->sh_sub) + sub_reset(mpctx->sh_sub, mpctx->osd); sub_clear_text(&mpctx->subs, MP_NOPTS_VALUE); if (vo_sub) set_osd_subtitle(mpctx, NULL); From e62b3a175016eaf93ef5ead7ea3891bc85327a55 Mon Sep 17 00:00:00 2001 From: wm4 Date: Sat, 29 Sep 2012 09:53:28 +0200 Subject: [PATCH 10/83] sub: cosmetics: turn some defines into enums --- sub/osd_libass.c | 3 --- sub/sub.h | 55 ++++++++++++++++++++++++++++-------------------- 2 files changed, 32 insertions(+), 26 deletions(-) diff --git a/sub/osd_libass.c b/sub/osd_libass.c index 2d596a6516..6c325642c5 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}" diff --git a/sub/sub.h b/sub/sub.h index 7deaf73b8e..ceecce4017 100644 --- a/sub/sub.h +++ b/sub/sub.h @@ -26,13 +26,15 @@ struct vo; -#define OSDTYPE_ASS 0 -#define OSDTYPE_OSD 1 -#define OSDTYPE_SUBTITLE 2 -#define OSDTYPE_PROGBAR 3 -#define OSDTYPE_SPU 4 +enum mp_osdtype { + OSDTYPE_ASS, + OSDTYPE_OSD, + OSDTYPE_SUBTITLE, + OSDTYPE_PROGBAR, + OSDTYPE_SPU, -#define MAX_OSD_PARTS 5 + MAX_OSD_PARTS +}; #define OSD_CONV_CACHE_MAX 3 @@ -91,24 +93,31 @@ extern int vo_osd_progbar_value; // 0..255 extern void* vo_spudec; extern void* vo_vobsub; -#define OSD_PLAY 0x01 -#define OSD_PAUSE 0x02 -#define OSD_STOP 0x03 -#define OSD_REW 0x04 -#define OSD_FFW 0x05 -#define OSD_CLOCK 0x06 -#define OSD_CONTRAST 0x07 -#define OSD_SATURATION 0x08 -#define OSD_VOLUME 0x09 -#define OSD_BRIGHTNESS 0x0A -#define OSD_HUE 0x0B -#define OSD_BALANCE 0x0C -#define OSD_PANSCAN 0x50 +// Start of OSD symbols in osd_font.pfb +#define OSD_CODEPOINTS 0xE000 -#define OSD_PB_START 0x10 -#define OSD_PB_0 0x11 -#define OSD_PB_END 0x12 -#define OSD_PB_1 0x13 +// OSD symbols. osd_font.pfb has them starting from codepoint OSD_CODEPOINTS. +// Symbols with a value >= 32 are normal unicode codepoints. +enum mp_osd_font_codepoints { + OSD_PLAY = 0x01, + OSD_PAUSE = 0x02, + OSD_STOP = 0x03, + OSD_REW = 0x04, + OSD_FFW = 0x05, + OSD_CLOCK = 0x06, + OSD_CONTRAST = 0x07, + OSD_SATURATION = 0x08, + OSD_VOLUME = 0x09, + OSD_BRIGHTNESS = 0x0A, + OSD_HUE = 0x0B, + OSD_BALANCE = 0x0C, + OSD_PANSCAN = 0x50, + + OSD_PB_START = 0x10, + OSD_PB_0 = 0x11, + OSD_PB_END = 0x12, + OSD_PB_1 = 0x13, +}; /* now in textform */ extern char * const sub_osd_names[]; From 252ddcc014b7672a4434823fc6275be1b039bd79 Mon Sep 17 00:00:00 2001 From: wm4 Date: Sat, 29 Sep 2012 11:03:53 +0200 Subject: [PATCH 11/83] sub: cleanup: remove vo_osd_probar_type/value global variables --- libvo/vo_caca.c | 6 +++--- mplayer.c | 6 +++--- sub/osd_libass.c | 12 ++++++------ sub/sub.c | 5 ++--- sub/sub.h | 4 +--- 5 files changed, 15 insertions(+), 18 deletions(-) diff --git a/libvo/vo_caca.c b/libvo/vo_caca.c index 2dfaa2a90f..c2bc53138d 100644 --- a/libvo/vo_caca.c +++ b/libvo/vo_caca.c @@ -325,9 +325,9 @@ static void uninit(struct vo *vo) static void draw_osd(struct vo *vo, struct osd_state *osd) { - if (vo_osd_progbar_type != -1) - osdpercent(MESSAGE_DURATION, 0, 255, vo_osd_progbar_value, - sub_osd_names[vo_osd_progbar_type], ""); + if (osd->progbar_type != -1) + osdpercent(MESSAGE_DURATION, 0, 255, osd->progbar_value, + sub_osd_names[osd->progbar_type], ""); } static int preinit(struct vo *vo, const char *arg) diff --git a/mplayer.c b/mplayer.c index 3d4e61c9e2..6fe8c649c4 100644 --- a/mplayer.c +++ b/mplayer.c @@ -1430,7 +1430,7 @@ static mp_osd_msg_t *get_osd_msg(struct MPContext *mpctx) // the difference is greater assume it's wrapped around from below 0 if (mpctx->osd_visible - now > 36000000) { mpctx->osd_visible = 0; - vo_osd_progbar_type = -1; // disable + mpctx->osd->progbar_type = -1; // disable vo_osd_changed(OSDTYPE_PROGBAR); mpctx->osd_function = mpctx->paused ? OSD_PAUSE : OSD_PLAY; } @@ -1490,8 +1490,8 @@ void set_osd_bar(struct MPContext *mpctx, int type, const char *name, if (mpctx->sh_video && opts->term_osd != 1) { mpctx->osd_visible = (GetTimerMS() + 1000) | 1; - vo_osd_progbar_type = type; - vo_osd_progbar_value = 256 * (val - min) / (max - min); + mpctx->osd->progbar_type = type; + mpctx->osd->progbar_value = 256 * (val - min) / (max - min); vo_osd_changed(OSDTYPE_PROGBAR); return; } diff --git a/sub/osd_libass.c b/sub/osd_libass.c index 6c325642c5..dee60c7df7 100644 --- a/sub/osd_libass.c +++ b/sub/osd_libass.c @@ -176,7 +176,7 @@ static void update_osd(struct osd_state *osd, struct osd_object *obj) static void update_progbar(struct osd_state *osd, struct osd_object *obj) { - if (vo_osd_progbar_type < 0) { + if (osd->progbar_type < 0) { clear_obj(obj); return; } @@ -199,16 +199,16 @@ static void update_progbar(struct osd_state *osd, struct osd_object *obj) 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}"); } diff --git a/sub/sub.c b/sub/sub.c index 182215310f..8e80730b9a 100644 --- a/sub/sub.c +++ b/sub/sub.c @@ -66,8 +66,6 @@ int sub_bg_color=0; /* subtitles background color */ int sub_bg_alpha=0; int sub_justify=0; -int vo_osd_progbar_type=-1; -int vo_osd_progbar_value=100; // 0..256 subtitle* vo_sub=NULL; char *subtitle_font_encoding = NULL; float text_font_scale_factor = 3.5; @@ -113,6 +111,8 @@ struct osd_state *osd_create(struct MPOpts *opts, struct ass_library *asslib) *osd = (struct osd_state) { .opts = opts, .ass_library = asslib, + .osd_text = talloc_strdup(osd, ""), + .progbar_type = -1, }; for (int n = 0; n < MAX_OSD_PARTS; n++) { struct osd_object *obj = talloc_struct(osd, struct osd_object, { @@ -122,7 +122,6 @@ struct osd_state *osd_create(struct MPOpts *opts, struct ass_library *asslib) 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; diff --git a/sub/sub.h b/sub/sub.h index ceecce4017..5e1809bee1 100644 --- a/sub/sub.h +++ b/sub/sub.h @@ -73,6 +73,7 @@ struct osd_state { int w, h; char *osd_text; // OSDTYPE_OSD + int progbar_type, progbar_value; // OSDTYPE_PROGBAR // temporary for sub decoders int bitmap_id; @@ -87,9 +88,6 @@ struct osd_state { extern subtitle* vo_sub; -extern int vo_osd_progbar_type; -extern int vo_osd_progbar_value; // 0..255 - extern void* vo_spudec; extern void* vo_vobsub; From 42572fdcc0931f814147974a11bc2c531843d124 Mon Sep 17 00:00:00 2001 From: wm4 Date: Tue, 2 Oct 2012 00:25:06 +0200 Subject: [PATCH 12/83] sub, vo_gl3, vo_vdpau: exit early if there are no sub-images to draw libass may always return a full change if no subtitle images are rendered in some cases (empty tracks). Also, a full change despite empty sub-images list may be reported on initialization. Avoid invoking odd special cases in the VO code by always exiting early if the sub-image list is empty. Note that at least for OSD, the code in sub.c doesn't even send a request VOCTRL_DRAW_EOSD if the image list is empty. But the subtitle rendering code in vf_vo.c is independent from this (at least for now). --- libvo/vo_gl3.c | 2 +- libvo/vo_vdpau.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libvo/vo_gl3.c b/libvo/vo_gl3.c index 2af63700b4..03d04b7038 100644 --- a/libvo/vo_gl3.c +++ b/libvo/vo_gl3.c @@ -1419,7 +1419,7 @@ static void gen_eosd(struct gl_priv *p, struct osd_render *osd, osd->num_vertices = 0; - if (imgs->format == SUBBITMAP_EMPTY) + if (imgs->format == SUBBITMAP_EMPTY || imgs->num_parts == 0) return; bool need_upload = imgs->bitmap_id != osd->bitmap_id; diff --git a/libvo/vo_vdpau.c b/libvo/vo_vdpau.c index 41feaca7b6..14b9d0df63 100644 --- a/libvo/vo_vdpau.c +++ b/libvo/vo_vdpau.c @@ -997,7 +997,7 @@ static void generate_eosd(struct vo *vo, mp_eosd_images_t *imgs) sfc->render_count = 0; - if (imgs->format == SUBBITMAP_EMPTY) + if (imgs->format == SUBBITMAP_EMPTY || imgs->num_parts == 0) return; if (imgs->bitmap_id == sfc->bitmap_id) From 5357b38d40e28dda4032ddc8654f5877d4928860 Mon Sep 17 00:00:00 2001 From: wm4 Date: Tue, 2 Oct 2012 22:42:26 +0200 Subject: [PATCH 13/83] osd_libass: set RTL base direction to neutral We are using libass for OSD rendering. One problem with that is that libass has to be bug-compatible to VSFilter. This includes the setting for the default RTL base direction. Neutral would be most reasonable, but VSFilter assumes LTR. This commit forces the default to neutral. Unconfirmed whether this actually works as intended. See the following libass commits: 9dbd12d shaper: allow font encoding -1 for neutral base direction a80c45c shaper: always use LTR base direction by default --- sub/osd_libass.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/sub/osd_libass.c b/sub/osd_libass.c index dee60c7df7..811bc009f3 100644 --- a/sub/osd_libass.c +++ b/sub/osd_libass.c @@ -59,8 +59,11 @@ void osd_destroy_backend(struct osd_state *osd) osd->osd_ass_library = NULL; } -static void update_font_scale(ASS_Track *track, ASS_Style *style, double factor) +static void update_font_style(ASS_Track *track, ASS_Style *style, double factor) { + // Set to neutral base direction, as opposed to VSFilter LTR default + style->Encoding = -1; + // duplicated from ass_mp.c double fs = track->PlayResY * factor / 100.; /* The font size is always proportional to video height only; @@ -86,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; @@ -243,7 +246,7 @@ static void update_sub(struct osd_state *osd, struct osd_object *obj) ASS_Style *style = obj->osd_track->styles + obj->osd_track->default_style; style->MarginV = obj->osd_track->PlayResY * ((100 - sub_pos)/110.0); - update_font_scale(obj->osd_track, style, text_font_scale_factor); + update_font_style(obj->osd_track, style, text_font_scale_factor); char *text = talloc_strdup(NULL, ""); From 466fc6d4d18ac1751527ccfff8f3c39eb3ff1e4b Mon Sep 17 00:00:00 2001 From: wm4 Date: Tue, 2 Oct 2012 23:28:18 +0200 Subject: [PATCH 14/83] sub: make it easier to set DVD sub decoding with sd_lavc With this commit, the player will still use spudec.c (the "old" DVD sub decoder), rather than ffmpeg. But it brings the changes needed to enable this down to a single line change: --- a/mplayer.c +++ b/mplayer.c @@ -1988,7 +1988,7 @@ static void reinit_subs(struct MPContext *mpctx) #endif vo_osd_changed(OSDTYPE_SUBTITLE); } else if (track->stream) { - if (mpctx->sh_sub->type == 'v') + if (mpctx->sh_sub->type == 'v' && false) init_vo_spudec(mpctx); else sub_init(mpctx->sh_sub, mpctx->osd); Also, copy the DVD resolution heuristics from spudec.c (from the spudec_new_scaled() function). I'm not sure if this is correct or even needed, but the sd_lavc codd explicitly reverted back to spudec with code carrying this comment: // Assume resolution heuristics only work for PGS and DVB so it seems likely that the required heuristics were missing, and that the spudec heuristics may make the DVD compatibility situation at least as good as with spudec. Note that it's unlikely that we enable sd_lavc for DVD subs by default, as there are other problems in combination with direct DVD playback. --- mplayer.c | 4 +++- sub/dec_sub.c | 2 +- sub/sd_lavc.c | 29 ++++++++++++++++++++++------- 3 files changed, 26 insertions(+), 9 deletions(-) diff --git a/mplayer.c b/mplayer.c index 6fe8c649c4..a885fac8ca 100644 --- a/mplayer.c +++ b/mplayer.c @@ -1795,7 +1795,9 @@ static void update_subtitles(struct MPContext *mpctx, double refpts_tl) } // DVD sub: - if (track->vobsub_id_plus_one || type == 'v') { + if ((track->vobsub_id_plus_one || type == 'v') + && !(sh_sub && sh_sub->active)) + { int timestamp; // Get a sub packet from the demuxer (or the vobsub.c thing, which // should be a demuxer, but isn't). diff --git a/sub/dec_sub.c b/sub/dec_sub.c index 31b06b9b80..b5ffa81511 100644 --- a/sub/dec_sub.c +++ b/sub/dec_sub.c @@ -39,7 +39,7 @@ 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) diff --git a/sub/sd_lavc.c b/sub/sd_lavc.c index 39e4891fb1..b0dde50a00 100644 --- a/sub/sd_lavc.c +++ b/sub/sd_lavc.c @@ -77,6 +77,26 @@ static void old_avsub_to_spudec(AVSubtitleRect **rects, int num_rects, spudec_packet_send(vo_spudec, packet, pts, endpts); } +static void guess_resolution(char type, int *w, int *h) +{ + if (type == 'v') { + /* XXX Although the video frame is some size, the SPU frame is + always maximum size i.e. 720 wide and 576 or 480 high */ + // For HD files in MKV the VobSub resolution can be higher though, + // see largeres_vobsub.mkv + if (*w <= 720 && *h <= 576) { + *w = 720; + *h = (*h == 480 || *h == 240) ? 480 : 576; + } + } else { + // Hope that PGS subs set these and 720/576 works for dvb subs + if (!*w) + *w = 720; + if (!*h) + *h = 576; + } +} + static int init(struct sh_sub *sh, struct osd_state *osd) { if (sh->initialized) @@ -158,8 +178,7 @@ static void decode(struct sh_sub *sh, struct osd_state *osd, void *data, if (sub.num_rects > 0) { switch (sub.rects[0]->type) { case SUBTITLE_BITMAP: - // Assume resolution heuristics only work for PGS and DVB - if (!osd->support_rgba || sh->type != 'p' && sh->type != 'b') { + if (!osd->support_rgba) { if (!vo_spudec) vo_spudec = spudec_new_scaled(NULL, ctx->width, ctx->height, NULL, 0); @@ -214,13 +233,9 @@ static void get_bitmaps(struct sh_sub *sh, struct osd_state *osd, priv->outbitmaps = talloc_memdup(priv, priv->inbitmaps, talloc_get_size(priv->inbitmaps)); bool pos_changed = false; - // Hope that PGS subs set these and 720/576 works for dvb subs int inw = priv->avctx->width; - if (!inw) - inw = 720; int inh = priv->avctx->height; - if (!inh) - inh = 576; + guess_resolution(sh->type, &inw, &inh); struct mp_eosd_res *d = &osd->dim; double xscale = (double) (d->w - d->ml - d->mr) / inw; double yscale = (double) (d->h - d->mt - d->mb) / inh; From cf61928eecd87ba29324e501a3e4a0efde25d874 Mon Sep 17 00:00:00 2001 From: wm4 Date: Wed, 3 Oct 2012 16:50:13 +0200 Subject: [PATCH 15/83] vo_gl, options: remove doublebuffering option (--double) Useless. It complicated the code and caused flicker, and was useless otherwise. The manpage describes this option as "should not normally be used". One possibly useful effect from the point of view of the user was that vsync was disabled. You can do this with the --vsync option, or by changing X/driver settings directly. --- DOCS/man/en/options.rst | 4 ---- cfg-mplayer.h | 1 - libvo/gl_common.c | 2 +- libvo/video_out.c | 1 - libvo/video_out.h | 1 - libvo/vo_gl.c | 33 ++++++++++----------------------- 6 files changed, 11 insertions(+), 31 deletions(-) diff --git a/DOCS/man/en/options.rst b/DOCS/man/en/options.rst index c52c8b307e..bf297018a9 100644 --- a/DOCS/man/en/options.rst +++ b/DOCS/man/en/options.rst @@ -489,10 +489,6 @@ ``--display=xtest.localdomain:0`` ---double, --no-double - Double buffering. The option to disable this exists mostly for debugging - purposes and should not normally be used. - --doubleclick-time Time in milliseconds to recognize two consecutive button presses as a double-click (default: 300). diff --git a/cfg-mplayer.h b/cfg-mplayer.h index 775963a879..f84a2afb96 100644 --- a/cfg-mplayer.h +++ b/cfg-mplayer.h @@ -629,7 +629,6 @@ const m_option_t mplayer_opts[]={ OPT_INTRANGE("bpp", vo_dbpp, 0, 0, 32), {"colorkey", &vo_colorkey, CONF_TYPE_INT, 0, 0, 0, NULL}, {"no-colorkey", &vo_colorkey, CONF_TYPE_FLAG, 0, 0, 0x1000000, NULL}, - {"double", &vo_doublebuffering, CONF_TYPE_FLAG, 0, 0, 1, NULL}, // wait for v-sync (gl) {"vsync", &vo_vsync, CONF_TYPE_FLAG, 0, 0, 1, NULL}, {"panscan", &vo_panscan, CONF_TYPE_FLOAT, CONF_RANGE, -1.0, 1.0, NULL}, diff --git a/libvo/gl_common.c b/libvo/gl_common.c index c56b0c8ffc..8ae94f56f3 100644 --- a/libvo/gl_common.c +++ b/libvo/gl_common.c @@ -1649,7 +1649,7 @@ void glDisable3D(GL *gl, int type) gl->ColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); break; case GL_3D_QUADBUFFER: - gl->DrawBuffer(vo_doublebuffering ? GL_BACK : GL_FRONT); + gl->DrawBuffer(GL_BACK); gl->GetIntegerv(GL_DRAW_BUFFER, &buffer); switch (buffer) { case GL_FRONT: diff --git a/libvo/video_out.c b/libvo/video_out.c index 2be311f87c..f743d5b8bf 100644 --- a/libvo/video_out.c +++ b/libvo/video_out.c @@ -49,7 +49,6 @@ int xinerama_y; int vo_nomouse_input = 0; int vo_grabpointer = 1; -int vo_doublebuffering = 1; int vo_vsync = 1; int vo_fs = 0; int vo_fsmode = 0; diff --git a/libvo/video_out.h b/libvo/video_out.h index cdda6ec79f..e94c8186c5 100644 --- a/libvo/video_out.h +++ b/libvo/video_out.h @@ -310,7 +310,6 @@ extern int xinerama_x; extern int xinerama_y; extern int vo_grabpointer; -extern int vo_doublebuffering; extern int vo_vsync; extern int vo_fs; extern int vo_fsmode; diff --git a/libvo/vo_gl.c b/libvo/vo_gl.c index 236471d537..1fb788e780 100644 --- a/libvo/vo_gl.c +++ b/libvo/vo_gl.c @@ -523,7 +523,7 @@ static int initGl(struct vo *vo, uint32_t d_width, uint32_t d_height) gl->DepthMask(GL_FALSE); gl->Disable(GL_CULL_FACE); gl->Enable(p->target); - gl->DrawBuffer(vo_doublebuffering ? GL_BACK : GL_FRONT); + gl->DrawBuffer(GL_BACK); gl->TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); mp_msg(MSGT_VO, MSGL_V, "[gl] Creating %dx%d texture...\n", @@ -781,8 +781,7 @@ static void draw_osd(struct vo *vo, struct osd_state *osd) p->ass_border_y, p->image_width, p->image_height, create_osd_texture, vo); } - if (vo_doublebuffering) - do_render_osd(vo, RENDER_OSD); + do_render_osd(vo, RENDER_OSD); } static void do_render(struct vo *vo) @@ -826,20 +825,11 @@ static void flip_page(struct vo *vo) struct gl_priv *p = vo->priv; GL *gl = p->gl; - if (vo_doublebuffering) { - if (p->use_glFinish) - gl->Finish(); - p->glctx->swapGlBuffers(p->glctx); - if (aspect_scaling()) - gl->Clear(GL_COLOR_BUFFER_BIT); - } else { - do_render(vo); - do_render_osd(vo, RENDER_OSD | RENDER_EOSD); - if (p->use_glFinish) - gl->Finish(); - else - gl->Flush(); - } + if (p->use_glFinish) + gl->Finish(); + p->glctx->swapGlBuffers(p->glctx); + if (aspect_scaling()) + gl->Clear(GL_COLOR_BUFFER_BIT); } static int draw_slice(struct vo *vo, uint8_t *src[], int stride[], int w, int h, @@ -1063,8 +1053,7 @@ static uint32_t draw_image(struct vo *vo, mp_image_t *mpi) gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); } skip_upload: - if (vo_doublebuffering) - do_render(vo); + do_render(vo); return VO_TRUE; } @@ -1375,8 +1364,7 @@ static int control(struct vo *vo, uint32_t request, void *data) if (!data) return VO_FALSE; genEOSD(vo, data); - if (vo_doublebuffering) - do_render_osd(vo, RENDER_EOSD); + do_render_osd(vo, RENDER_EOSD); return VO_TRUE; case VOCTRL_GET_EOSD_RES: { mp_eosd_res_t *r = data; @@ -1447,8 +1435,7 @@ static int control(struct vo *vo, uint32_t request, void *data) p->glctx->update_xinerama_info(vo); return VO_TRUE; case VOCTRL_REDRAW_FRAME: - if (vo_doublebuffering) - do_render(vo); + do_render(vo); return true; case VOCTRL_SCREENSHOT: { struct voctrl_screenshot_args *args = data; From 8f8f6e6d9d27eef37640b363214a775647a0f2f4 Mon Sep 17 00:00:00 2001 From: wm4 Date: Wed, 3 Oct 2012 17:00:37 +0200 Subject: [PATCH 16/83] sub: remove logic for disabling hinting on scaled EOSD This was an extremely obscure setting, as it was used only with vo_gl if its scaled-osd suboption was used. If you really want this, you can set the desired ass-hinting value directly, and there will be literally no loss in functionality. Note that this didn't actually test whether the EOSD was scaled. Basically, it only checked whether vo_gl had the scaled-osd suboption set. --- DOCS/man/en/options.rst | 2 -- libmpcodecs/vf_vo.c | 1 - libmpcodecs/vfcap.h | 2 -- libvo/vo_direct3d.c | 2 +- libvo/vo_gl.c | 2 +- libvo/vo_gl3.c | 2 +- libvo/vo_vdpau.c | 2 +- sub/ass_mp.c | 7 ++----- sub/ass_mp.h | 2 +- sub/sd_ass.c | 2 +- sub/sub.h | 1 - 11 files changed, 8 insertions(+), 17 deletions(-) diff --git a/DOCS/man/en/options.rst b/DOCS/man/en/options.rst index bf297018a9..0b623859e5 100644 --- a/DOCS/man/en/options.rst +++ b/DOCS/man/en/options.rst @@ -163,8 +163,6 @@ :1: FreeType autohinter, light mode :2: FreeType autohinter, normal mode :3: font native hinter - :0-3 + 4: The same, but hinting will only be performed if the OSD is - rendered at screen resolution and will therefore not be scaled. The default value is 0 (no hinting). diff --git a/libmpcodecs/vf_vo.c b/libmpcodecs/vf_vo.c index 862cd63492..49668d4640 100644 --- a/libmpcodecs/vf_vo.c +++ b/libmpcodecs/vf_vo.c @@ -126,7 +126,6 @@ static int control(struct vf_instance *vf, int request, void *data) return CONTROL_FALSE; osd->normal_scale = 1; osd->vsfilter_scale = vf->priv->scale_ratio; - osd->unscaled = vf->default_caps & VFCAP_EOSD_UNSCALED; struct sub_bitmaps images; sub_get_bitmaps(osd, &images); return vo_control(video_out, VOCTRL_DRAW_EOSD, &images) == VO_TRUE; diff --git a/libmpcodecs/vfcap.h b/libmpcodecs/vfcap.h index 0bb255b3cd..0fb73f5a51 100644 --- a/libmpcodecs/vfcap.h +++ b/libmpcodecs/vfcap.h @@ -42,8 +42,6 @@ #define VFCAP_POSTPROC 0x800 // filter can draw EOSD #define VFCAP_EOSD 0x2000 -// filter will draw EOSD at screen resolution (without scaling) -#define VFCAP_EOSD_UNSCALED 0x4000 // used by libvo and vf_vo, indicates the VO does not support draw_slice for this format #define VOCAP_NOSLICES 0x8000 #define VFCAP_EOSD_FILTER 0x20000 // EOSD is drawn in filter chain diff --git a/libvo/vo_direct3d.c b/libvo/vo_direct3d.c index f8c9054b97..57bad61d02 100644 --- a/libvo/vo_direct3d.c +++ b/libvo/vo_direct3d.c @@ -1271,7 +1271,7 @@ static int query_format(d3d_priv *priv, uint32_t movie_fmt) int eosd_caps = VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW | VFCAP_OSD | VFCAP_HWSCALE_UP | VFCAP_HWSCALE_DOWN; if (priv->eosd) - eosd_caps |= VFCAP_EOSD | VFCAP_EOSD_UNSCALED; + eosd_caps |= VFCAP_EOSD; return eosd_caps; } diff --git a/libvo/vo_gl.c b/libvo/vo_gl.c index 1fb788e780..e71e482feb 100644 --- a/libvo/vo_gl.c +++ b/libvo/vo_gl.c @@ -1116,7 +1116,7 @@ static int query_format(struct vo *vo, uint32_t format) int caps = VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW | VFCAP_FLIP | VFCAP_HWSCALE_UP | VFCAP_HWSCALE_DOWN | VFCAP_ACCEPT_STRIDE; if (p->use_osd) - caps |= VFCAP_OSD | VFCAP_EOSD | (p->scaled_osd ? 0 : VFCAP_EOSD_UNSCALED); + caps |= VFCAP_OSD | VFCAP_EOSD; if (format == IMGFMT_RGB24 || format == IMGFMT_RGBA) return caps; if (p->use_yuv && mp_get_chroma_shift(format, NULL, NULL, &depth) && diff --git a/libvo/vo_gl3.c b/libvo/vo_gl3.c index 03d04b7038..5fd4f62af0 100644 --- a/libvo/vo_gl3.c +++ b/libvo/vo_gl3.c @@ -1758,7 +1758,7 @@ static int query_format(uint32_t format) { int caps = VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW | VFCAP_FLIP | VFCAP_HWSCALE_UP | VFCAP_HWSCALE_DOWN | VFCAP_ACCEPT_STRIDE | - VFCAP_OSD | VFCAP_EOSD | VFCAP_EOSD_UNSCALED | VFCAP_EOSD_RGBA; + VFCAP_OSD | VFCAP_EOSD | VFCAP_EOSD_RGBA; if (!init_format(format, NULL)) return 0; return caps; diff --git a/libvo/vo_vdpau.c b/libvo/vo_vdpau.c index 14b9d0df63..64378a9a0c 100644 --- a/libvo/vo_vdpau.c +++ b/libvo/vo_vdpau.c @@ -1396,7 +1396,7 @@ static int query_format(uint32_t format) { int default_flags = VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW | VFCAP_HWSCALE_UP | VFCAP_HWSCALE_DOWN | VFCAP_OSD | VFCAP_EOSD - | VFCAP_EOSD_UNSCALED | VFCAP_EOSD_RGBA | VFCAP_FLIP; + | VFCAP_EOSD_RGBA | VFCAP_FLIP; switch (format) { case IMGFMT_YV12: case IMGFMT_I420: diff --git a/sub/ass_mp.c b/sub/ass_mp.c index 5766a847f8..ba93c4c842 100644 --- a/sub/ass_mp.c +++ b/sub/ass_mp.c @@ -226,17 +226,14 @@ 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) { int hinting; ass_set_frame_size(priv, dim->w, dim->h); ass_set_margins(priv, dim->mt, dim->mb, dim->ml, dim->mr); ass_set_use_margins(priv, opts->ass_use_margins); ass_set_font_scale(priv, opts->ass_font_scale); - if (!unscaled && (opts->ass_hinting & 4)) - hinting = 0; - else - hinting = opts->ass_hinting & 3; + hinting = opts->ass_hinting & 3; // +4 was for no hinting if scaled ass_set_hinting(priv, hinting); ass_set_line_spacing(priv, opts->ass_line_spacing); } diff --git a/sub/ass_mp.h b/sub/ass_mp.h index 805e9d7310..4ca43dfb2e 100644 --- a/sub/ass_mp.h +++ b/sub/ass_mp.h @@ -42,7 +42,7 @@ 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); diff --git a/sub/sd_ass.c b/sub/sd_ass.c index 478b1c96a9..8b8ad6c0eb 100644 --- a/sub/sd_ass.c +++ b/sub/sd_ass.c @@ -139,7 +139,7 @@ static void get_bitmaps(struct sh_sub *sh, struct osd_state *osd, if (ctx->vsfilter_aspect && opts->ass_vsfilter_aspect_compat) scale = osd->vsfilter_scale; ASS_Renderer *renderer = osd->ass_renderer; - mp_ass_configure(renderer, opts, &osd->dim, osd->unscaled); + mp_ass_configure(renderer, opts, &osd->dim); ass_set_aspect_ratio(renderer, scale, 1); mp_ass_render_frame(renderer, ctx->ass_track, osd->sub_pts * 1000 + .5, &ctx->parts, res); diff --git a/sub/sub.h b/sub/sub.h index 5e1809bee1..92ac19eb52 100644 --- a/sub/sub.h +++ b/sub/sub.h @@ -67,7 +67,6 @@ struct osd_state { struct mp_eosd_res dim; double normal_scale; double vsfilter_scale; - bool unscaled; bool support_rgba; int w, h; From cadff3eec75bdd81fb0d18cd0ac029faa3c318d2 Mon Sep 17 00:00:00 2001 From: wm4 Date: Wed, 3 Oct 2012 18:25:41 +0200 Subject: [PATCH 17/83] vo_gl3: move OSD code to gl_osd.c Other OpenGL-using VOs can use this. gl_osd.c includes some code for vo_gl.c. The next commit actually makes use of it. --- Makefile | 2 +- libvo/bitmap_packer.c | 25 ++++ libvo/bitmap_packer.h | 10 ++ libvo/gl_common.c | 3 + libvo/gl_osd.c | 322 ++++++++++++++++++++++++++++++++++++++++++ libvo/gl_osd.h | 41 ++++++ libvo/vo_gl3.c | 261 +++++++--------------------------- 7 files changed, 456 insertions(+), 208 deletions(-) create mode 100644 libvo/gl_osd.c create mode 100644 libvo/gl_osd.h diff --git a/Makefile b/Makefile index 27aa1997dd..9c782e27fe 100644 --- a/Makefile +++ b/Makefile @@ -284,7 +284,7 @@ SRCS_MPLAYER-$(COREAUDIO) += libao2/ao_coreaudio.c SRCS_MPLAYER-$(COREVIDEO) += libvo/vo_corevideo.m SRCS_MPLAYER-$(DIRECT3D) += libvo/vo_direct3d.c libvo/w32_common.c SRCS_MPLAYER-$(GL) += libvo/gl_common.c libvo/vo_gl.c libvo/vo_gl3.c \ - pnm_loader.c + pnm_loader.c libvo/gl_osd.c SRCS_MPLAYER-$(ENCODING) += libvo/vo_lavc.c libao2/ao_lavc.c encode_lavc.c SRCS_MPLAYER-$(GL_WIN32) += libvo/w32_common.c SRCS_MPLAYER-$(GL_X11) += libvo/x11_common.c diff --git a/libvo/bitmap_packer.c b/libvo/bitmap_packer.c index 5e5bafea0c..9d3df70c34 100644 --- a/libvo/bitmap_packer.c +++ b/libvo/bitmap_packer.c @@ -20,6 +20,7 @@ */ #include +#include #include @@ -29,6 +30,9 @@ #include "mpcommon.h" #include "sub/ass_mp.h" #include "sub/dec_sub.h" +#include "fastmemcpy.h" + +#define IS_POWER_OF_2(x) (((x) > 0) && !(((x) - 1) & (x))) void packer_reset(struct bitmap_packer *packer) { @@ -160,6 +164,8 @@ int packer_pack(struct bitmap_packer *packer) // No padding at edges packer->used_width = FFMIN(used_width, packer->w); packer->used_height = FFMIN(y, packer->h); + assert(packer->w == 0 || IS_POWER_OF_2(packer->w)); + assert(packer->h == 0 || IS_POWER_OF_2(packer->h)); return packer->w != w_orig || packer->h != h_orig; } if (packer->w <= packer->h && packer->w != packer->w_max) @@ -201,3 +207,22 @@ int packer_pack_from_subbitmaps(struct bitmap_packer *packer, packer->in[i] = (struct pos){b->parts[i].w + a, b->parts[i].h + a}; return packer_pack(packer); } + +void packer_copy_subbitmaps(struct bitmap_packer *packer, struct sub_bitmaps *b, + void *data, int pixel_stride, int stride) +{ + assert(packer->count == b->num_parts); + if (packer->padding) { + struct pos bb[2]; + packer_get_bb(packer, bb); + memset_pic(data, 0, bb[1].x * pixel_stride, bb[1].y, stride); + } + for (int n = 0; n < packer->count; n++) { + struct sub_bitmap *s = &b->parts[n]; + struct pos p = packer->result[n]; + + void *pdata = (uint8_t *)data + p.y * stride + p.x * pixel_stride; + memcpy_pic(pdata, s->bitmap, s->w * pixel_stride, s->h, + stride, s->stride); + } +} diff --git a/libvo/bitmap_packer.h b/libvo/bitmap_packer.h index 99c7b514b4..b86c3ec4f9 100644 --- a/libvo/bitmap_packer.h +++ b/libvo/bitmap_packer.h @@ -43,6 +43,7 @@ void packer_set_size(struct bitmap_packer *packer, int size); * Write input sizes in packer->in. * Resulting packing will be written in packer->result. * w and h will be increased if necessary for successful packing. + * There is a strong guarantee that w and h will be powers of 2 (or set to 0). * Return value is -1 if packing failed because w and h were set to max * values but that wasn't enough, 1 if w or h was increased, and 0 otherwise. */ @@ -55,4 +56,13 @@ int packer_pack(struct bitmap_packer *packer); int packer_pack_from_subbitmaps(struct bitmap_packer *packer, struct sub_bitmaps *b); +// Copy the (already packed) sub-bitmaps from b to the image in data. +// data must point to an image that is at least (packer->w, packer->h) big. +// The image has the given stride (bytes between (x, y) to (x, y + 1)), and the +// pixel format used by both the sub-bitmaps and the image uses pixel_stride +// bytes per pixel (bytes between (x, y) to (x + 1, y)). +// If packer->padding is set, the padding borders are cleared with 0. +void packer_copy_subbitmaps(struct bitmap_packer *packer, struct sub_bitmaps *b, + void *data, int pixel_stride, int stride); + #endif diff --git a/libvo/gl_common.c b/libvo/gl_common.c index 8ae94f56f3..4bffc1521f 100644 --- a/libvo/gl_common.c +++ b/libvo/gl_common.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include "talloc.h" #include "gl_common.h" @@ -45,6 +46,8 @@ #include "aspect.h" #include "pnm_loader.h" #include "options.h" +#include "sub/sub.h" +#include "bitmap_packer.h" //! \defgroup glgeneral OpenGL general helper functions diff --git a/libvo/gl_osd.c b/libvo/gl_osd.c new file mode 100644 index 0000000000..0e99d13652 --- /dev/null +++ b/libvo/gl_osd.c @@ -0,0 +1,322 @@ +/* + * 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 . + */ + +#include +#include +#include + +#include "bitmap_packer.h" + +#include "gl_osd.h" + +struct osd_fmt_entry { + GLint internal_format; + GLint format; + GLenum type; +}; + +// glBlendFunc() arguments +static const int blend_factors[SUBBITMAP_COUNT][2] = { + [SUBBITMAP_LIBASS] = {GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA}, + [SUBBITMAP_RGBA] = {GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA}, + [SUBBITMAP_OLD] = {GL_ONE, GL_ONE_MINUS_SRC_ALPHA}, +}; + +static const struct osd_fmt_entry osd_to_gl3_formats[SUBBITMAP_COUNT] = { + [SUBBITMAP_LIBASS] = {GL_RED, GL_RED, GL_UNSIGNED_BYTE}, + [SUBBITMAP_RGBA] = {GL_RGBA, GL_BGRA, GL_UNSIGNED_BYTE}, + [SUBBITMAP_OLD] = {GL_RG, GL_RG, GL_UNSIGNED_BYTE}, +}; + +static const struct osd_fmt_entry osd_to_gl_legacy_formats[SUBBITMAP_COUNT] = { + [SUBBITMAP_LIBASS] = {GL_ALPHA, GL_ALPHA, GL_UNSIGNED_BYTE}, + [SUBBITMAP_RGBA] = {GL_RGBA, GL_BGRA, GL_UNSIGNED_BYTE}, + [SUBBITMAP_OLD] = + {GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE}, +}; + +struct mpgl_osd *mpgl_osd_init(GL *gl, bool legacy) +{ + GLint max_texture_size; + gl->GetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size); + + struct mpgl_osd *ctx = talloc_ptrtype(NULL, ctx); + *ctx = (struct mpgl_osd) { + .gl = gl, + .fmt_table = legacy ? osd_to_gl_legacy_formats : osd_to_gl3_formats, + .scratch = talloc_zero_size(ctx, 1), + }; + + for (int n = 0; n < MAX_OSD_PARTS; n++) { + struct mpgl_osd_part *p = talloc_ptrtype(ctx, p); + *p = (struct mpgl_osd_part) { + .packer = talloc_struct(p, struct bitmap_packer, { + .w_max = max_texture_size, + .h_max = max_texture_size, + }), + }; + ctx->parts[n] = p; + } + + return ctx; +} + +void mpgl_osd_destroy(struct mpgl_osd *ctx) +{ + GL *gl = ctx->gl; + + for (int n = 0; n < MAX_OSD_PARTS; n++) { + struct mpgl_osd_part *p = ctx->parts[n]; + gl->DeleteTextures(1, &p->texture); + if (gl->DeleteBuffers) + gl->DeleteBuffers(1, &p->buffer); + } + talloc_free(ctx); +} + +bool mpgl_osd_query_format(struct mpgl_osd *ctx, int osd_format) +{ + return ctx->fmt_table[osd_format].type != 0; +} + +static bool upload_pbo(struct mpgl_osd *ctx, struct mpgl_osd_part *osd, + struct sub_bitmaps *imgs) +{ + GL *gl = ctx->gl; + bool success = true; + struct osd_fmt_entry fmt = ctx->fmt_table[imgs->format]; + int pix_stride = glFmt2bpp(fmt.format, fmt.type); + + if (!osd->buffer) { + gl->GenBuffers(1, &osd->buffer); + gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, osd->buffer); + gl->BufferData(GL_PIXEL_UNPACK_BUFFER, osd->w * osd->h * pix_stride, + NULL, GL_DYNAMIC_COPY); + gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); + } + + gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, osd->buffer); + char *data = gl->MapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY); + if (!data) { + success = false; + } else { + struct pos bb[2]; + packer_get_bb(osd->packer, bb); + size_t stride = osd->w * pix_stride; + packer_copy_subbitmaps(osd->packer, imgs, data, pix_stride, stride); + if (!gl->UnmapBuffer(GL_PIXEL_UNPACK_BUFFER)) + success = false; + glUploadTex(gl, GL_TEXTURE_2D, fmt.format, fmt.type, NULL, stride, + bb[0].x, bb[0].y, bb[1].x - bb[0].x, bb[1].y - bb[0].y, + 0); + } + gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); + + if (!success) { + mp_msg(MSGT_VO, MSGL_FATAL, "[gl] Error: can't upload subtitles! " + "Remove the 'pbo' suboption.\n"); + } + + return success; +} + +static void upload_tex(struct mpgl_osd *ctx, struct mpgl_osd_part *osd, + struct sub_bitmaps *imgs) +{ + struct osd_fmt_entry fmt = ctx->fmt_table[imgs->format]; + if (osd->packer->padding) { + struct pos bb[2]; + packer_get_bb(osd->packer, bb); + glClearTex(ctx->gl, GL_TEXTURE_2D, fmt.format, fmt.type, + bb[0].x, bb[0].y, bb[1].x - bb[0].y, bb[1].y - bb[0].y, + 0, &ctx->scratch); + } + for (int n = 0; n < osd->packer->count; n++) { + struct sub_bitmap *s = &imgs->parts[n]; + struct pos p = osd->packer->result[n]; + + glUploadTex(ctx->gl, GL_TEXTURE_2D, fmt.format, fmt.type, + s->bitmap, s->stride, p.x, p.y, s->w, s->h, 0); + } +} + +static bool upload_osd(struct mpgl_osd *ctx, struct mpgl_osd_part *osd, + struct sub_bitmaps *imgs) +{ + GL *gl = ctx->gl; + + osd->packer->padding = imgs->scaled; // assume 2x2 filter on scaling + int r = packer_pack_from_subbitmaps(osd->packer, imgs); + if (r < 0) { + mp_msg(MSGT_VO, MSGL_ERR, "[gl] EOSD bitmaps do not fit on " + "a surface with the maximum supported size %dx%d.\n", + osd->packer->w_max, osd->packer->h_max); + return false; + } + + struct osd_fmt_entry fmt = ctx->fmt_table[imgs->format]; + assert(fmt.type != 0); + + if (!osd->texture) + gl->GenTextures(1, &osd->texture); + + gl->BindTexture(GL_TEXTURE_2D, osd->texture); + + if (osd->packer->w > osd->w || osd->packer->h > osd->h + || osd->format != imgs->format) + { + osd->format = imgs->format; + osd->w = FFMAX(32, osd->packer->w); + osd->h = FFMAX(32, osd->packer->h); + + gl->TexImage2D(GL_TEXTURE_2D, 0, fmt.internal_format, osd->w, osd->h, + 0, fmt.format, fmt.type, NULL); + + gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + if (gl->DeleteBuffers) + gl->DeleteBuffers(1, &osd->buffer); + osd->buffer = 0; + } + + bool uploaded = false; + if (ctx->use_pbo) + uploaded = upload_pbo(ctx, osd, imgs); + if (!uploaded) + upload_tex(ctx, osd, imgs); + + gl->BindTexture(GL_TEXTURE_2D, 0); + + return true; +} + +struct mpgl_osd_part *mpgl_osd_generate(struct mpgl_osd *ctx, + struct sub_bitmaps *imgs) +{ + if (imgs->num_parts == 0 || !mpgl_osd_query_format(ctx, imgs->format)) + return NULL; + + struct mpgl_osd_part *osd = ctx->parts[imgs->render_index]; + + if (imgs->bitmap_pos_id != osd->bitmap_pos_id) { + if (imgs->bitmap_id != osd->bitmap_id) { + if (!upload_osd(ctx, osd, imgs)) + osd->packer->count = 0; + } + + osd->bitmap_id = imgs->bitmap_id; + osd->bitmap_pos_id = imgs->bitmap_pos_id; + osd->num_vertices = 0; + } + + return osd->packer->count ? osd : NULL; +} + +void mpgl_osd_gl_set_state(struct mpgl_osd *ctx, struct mpgl_osd_part *p) +{ + GL *gl = ctx->gl; + + gl->BindTexture(GL_TEXTURE_2D, p->texture); + gl->Enable(GL_BLEND); + gl->BlendFunc(blend_factors[p->format][0], blend_factors[p->format][1]); +} + +void mpgl_osd_gl_unset_state(struct mpgl_osd *ctx, struct mpgl_osd_part *p) +{ + GL *gl = ctx->gl; + + gl->Disable(GL_BLEND); + gl->BindTexture(GL_TEXTURE_2D, 0); +} + +struct vertex { + float position[2]; + uint8_t color[4]; + float texcoord[2]; +}; + +void mpgl_osd_draw_legacy(struct mpgl_osd *ctx, struct sub_bitmaps *imgs) +{ + struct mpgl_osd_part *osd = mpgl_osd_generate(ctx, imgs); + if (!osd) + return; + + if (!osd->num_vertices) { + // 2 triangles primitives per quad = 6 vertices per quad + // not using GL_QUADS, as it is deprecated in OpenGL 3.x and later + osd->vertices = talloc_realloc(osd, osd->vertices, struct vertex, + osd->packer->count * 6); + + struct vertex *va = osd->vertices; + float tex_w = osd->w; + float tex_h = osd->h; + + for (int n = 0; n < osd->packer->count; n++) { + struct sub_bitmap *b = &imgs->parts[n]; + struct pos p = osd->packer->result[n]; + + uint32_t c = imgs->format == SUBBITMAP_LIBASS + ? b->libass.color : 0xFFFFFF00; + uint8_t color[4] = { c >> 24, (c >> 16) & 0xff, + (c >> 8) & 0xff, 255 - (c & 0xff) }; + + float x0 = b->x; + float y0 = b->y; + float x1 = b->x + b->dw; + float y1 = b->y + b->dh; + float tx0 = p.x / tex_w; + float ty0 = p.y / tex_h; + float tx1 = (p.x + b->w) / tex_w; + float ty1 = (p.y + b->h) / tex_h; + +#define COLOR_INIT {color[0], color[1], color[2], color[3]} + struct vertex *v = &va[osd->num_vertices]; + v[0] = (struct vertex) { {x0, y0}, COLOR_INIT, {tx0, ty0} }; + v[1] = (struct vertex) { {x0, y1}, COLOR_INIT, {tx0, ty1} }; + v[2] = (struct vertex) { {x1, y0}, COLOR_INIT, {tx1, ty0} }; + v[3] = (struct vertex) { {x1, y1}, COLOR_INIT, {tx1, ty1} }; + v[4] = v[2]; + v[5] = v[1]; +#undef COLOR_INIT + osd->num_vertices += 6; + } + } + + GL *gl = ctx->gl; + + struct vertex *va = osd->vertices; + size_t stride = sizeof(va[0]); + + gl->VertexPointer(2, GL_FLOAT, stride, &va[0].position[0]); + gl->ColorPointer(4, GL_UNSIGNED_BYTE, stride, &va[0].color[0]); + gl->TexCoordPointer(2, GL_FLOAT, stride, &va[0].texcoord[0]); + + gl->EnableClientState(GL_VERTEX_ARRAY); + gl->EnableClientState(GL_TEXTURE_COORD_ARRAY); + gl->EnableClientState(GL_COLOR_ARRAY); + + mpgl_osd_gl_set_state(ctx, osd); + gl->DrawArrays(GL_TRIANGLES, 0, osd->num_vertices); + mpgl_osd_gl_unset_state(ctx, osd); + + gl->DisableClientState(GL_VERTEX_ARRAY); + gl->DisableClientState(GL_TEXTURE_COORD_ARRAY); + gl->DisableClientState(GL_COLOR_ARRAY); +} diff --git a/libvo/gl_osd.h b/libvo/gl_osd.h new file mode 100644 index 0000000000..baebc3311c --- /dev/null +++ b/libvo/gl_osd.h @@ -0,0 +1,41 @@ +#ifndef MPLAYER_GL_OSD_H +#define MPLAYER_GL_OSD_H + +#include +#include + +#include "gl_common.h" +#include "sub/sub.h" + +struct mpgl_osd_part { + enum sub_bitmap_format format; + int bitmap_id, bitmap_pos_id; + GLuint texture; + int w, h; + GLuint buffer; + int num_vertices; + void *vertices; + struct bitmap_packer *packer; +}; + +struct mpgl_osd { + GL *gl; + bool use_pbo; + struct mpgl_osd_part *parts[MAX_OSD_PARTS]; + const struct osd_fmt_entry *fmt_table; + void *scratch; +}; + +struct mpgl_osd *mpgl_osd_init(GL *gl, bool legacy); +void mpgl_osd_destroy(struct mpgl_osd *ctx); + +bool mpgl_osd_query_format(struct mpgl_osd *ctx, int osd_format); + +void mpgl_osd_draw_legacy(struct mpgl_osd *ctx, struct sub_bitmaps *b); +struct mpgl_osd_part *mpgl_osd_generate(struct mpgl_osd *ctx, + struct sub_bitmaps *b); + +void mpgl_osd_gl_set_state(struct mpgl_osd *ctx, struct mpgl_osd_part *p); +void mpgl_osd_gl_unset_state(struct mpgl_osd *ctx, struct mpgl_osd_part *p); + +#endif diff --git a/libvo/vo_gl3.c b/libvo/vo_gl3.c index 5fd4f62af0..934d8f394d 100644 --- a/libvo/vo_gl3.c +++ b/libvo/vo_gl3.c @@ -50,6 +50,7 @@ #include "bitmap_packer.h" #include "gl_common.h" +#include "gl_osd.h" #include "filter_kernels.h" #include "aspect.h" #include "fastmemcpy.h" @@ -142,17 +143,6 @@ struct fbotex { int vp_w, vp_h; // viewport of fbo / used part of the texture }; -struct osd_render { - enum sub_bitmap_format format; - int bitmap_id, bitmap_pos_id; - GLuint texture; - int width, height; - GLuint buffer; - int num_vertices; - struct vertex *vertices; - struct bitmap_packer *packer; -}; - struct gl_priv { struct vo *vo; MPGLContext *glctx; @@ -186,7 +176,7 @@ struct gl_priv { GLuint osd_programs[SUBBITMAP_COUNT]; GLuint indirect_program, scale_sep_program, final_program; - struct osd_render *osd[MAX_OSD_PARTS]; + struct mpgl_osd *osd; GLuint lut_3d_texture; int lut_3d_w, lut_3d_h, lut_3d_d; @@ -260,23 +250,10 @@ static const struct fmt_entry mp_to_gl_formats[] = { {0}, }; -struct osd_fmt_entry { - GLint internal_format; - GLint format; - int stride; // bytes per pixel - GLenum type; - const char *shader; // shader entry in the .glsl file -}; - -static const struct osd_fmt_entry osd_to_gl_formats[] = { - [SUBBITMAP_LIBASS] - = {GL_RED, GL_RED, 1, GL_UNSIGNED_BYTE, "frag_osd_libass"}, - [SUBBITMAP_RGBA] - = {GL_RGBA, GL_BGRA, 4, GL_UNSIGNED_BYTE, "frag_osd_rgba"}, - [SUBBITMAP_OLD] - = {GL_RG, GL_RG, 2, GL_UNSIGNED_BYTE, "frag_osd_old"}, - // Make array long enough to contain all formats - [SUBBITMAP_COUNT] = {0} +static const char *osd_shaders[SUBBITMAP_COUNT] = { + [SUBBITMAP_LIBASS] = "frag_osd_libass", + [SUBBITMAP_RGBA] = "frag_osd_rgba", + [SUBBITMAP_OLD] = "frag_osd_old", }; @@ -678,11 +655,11 @@ static void compile_shaders(struct gl_priv *p) shader_def_opt(&header_osd, "USE_3DLUT", p->use_lut_3d); for (int n = 0; n < SUBBITMAP_COUNT; n++) { - struct osd_fmt_entry fmt = osd_to_gl_formats[n]; - if (fmt.shader) { - char *s_osd = get_section(tmp, src, fmt.shader); + const char *name = osd_shaders[n]; + if (name) { + char *s_osd = get_section(tmp, src, name); p->osd_programs[n] = - create_program(gl, fmt.shader, header_osd, vertex_shader, s_osd); + create_program(gl, name, header_osd, vertex_shader, s_osd); } } @@ -947,6 +924,11 @@ static void reinit_rendering(struct gl_priv *p) if (p->indirect_program && !p->indirect_fbo.fbo) fbotex_init(p, &p->indirect_fbo, p->texture_width, p->texture_height); + + if (!p->osd) { + p->osd = mpgl_osd_init(p->gl, false); + p->osd->use_pbo = p->use_pbo; + } } static void uninit_rendering(struct gl_priv *p) @@ -964,6 +946,10 @@ static void uninit_rendering(struct gl_priv *p) gl->DeleteTextures(1, &p->dither_texture); p->dither_texture = 0; + + if (p->osd) + mpgl_osd_destroy(p->osd); + p->osd = NULL; } static void init_lut_3d(struct gl_priv *p) @@ -1409,166 +1395,51 @@ static mp_image_t *get_window_screenshot(struct gl_priv *p) return image; } -static void gen_eosd(struct gl_priv *p, struct osd_render *osd, - struct sub_bitmaps *imgs) -{ - GL *gl = p->gl; - - if (imgs->bitmap_pos_id == osd->bitmap_pos_id) - return; - - osd->num_vertices = 0; - - if (imgs->format == SUBBITMAP_EMPTY || imgs->num_parts == 0) - return; - - bool need_upload = imgs->bitmap_id != osd->bitmap_id; - bool need_allocate = false; - - if (imgs->format != osd->format) { - packer_reset(osd->packer); - osd->format = imgs->format; - need_allocate = true; - } - - osd->bitmap_id = imgs->bitmap_id; - osd->bitmap_pos_id = imgs->bitmap_pos_id; - - osd->packer->padding = imgs->scaled; // assume 2x2 filter on scaling - int r = packer_pack_from_subbitmaps(osd->packer, imgs); - if (r < 0) { - mp_msg(MSGT_VO, MSGL_ERR, "[gl] EOSD bitmaps do not fit on " - "a surface with the maximum supported size %dx%d.\n", - osd->packer->w_max, osd->packer->h_max); - return; - } else if (r > 0) { - need_allocate = true; - } - - struct osd_fmt_entry fmt = osd_to_gl_formats[imgs->format]; - assert(fmt.shader); - - if (!osd->texture) { - gl->GenTextures(1, &osd->texture); - gl->GenBuffers(1, &osd->buffer); - } - - gl->BindTexture(GL_TEXTURE_2D, osd->texture); - - if (need_allocate) { - tex_size(p, osd->packer->w, osd->packer->h, &osd->width, &osd->height); - gl->TexImage2D(GL_TEXTURE_2D, 0, fmt.internal_format, osd->width, - osd->height, 0, fmt.format, fmt.type, NULL); - default_tex_params(gl, GL_TEXTURE_2D, GL_LINEAR); - gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, osd->buffer); - gl->BufferData(GL_PIXEL_UNPACK_BUFFER, - osd->width * osd->height * fmt.stride, - NULL, GL_DYNAMIC_COPY); - gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); - } - - struct pos bb[2]; - packer_get_bb(osd->packer, bb); - - if (need_upload && p->use_pbo) { - gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, osd->buffer); - char *data = gl->MapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY); - size_t stride = osd->width * fmt.stride; - if (!data) { - mp_msg(MSGT_VO, MSGL_FATAL, "[gl] Error: can't upload subtitles! " - "Remove the 'pbo' suboption.\n"); - } else { - if (imgs->scaled) { - int w = bb[1].x - bb[0].x; - int h = bb[1].y - bb[0].y; - memset_pic(data, 0, w * fmt.stride, h, stride); - } - for (int n = 0; n < osd->packer->count; n++) { - struct sub_bitmap *b = &imgs->parts[n]; - struct pos p = osd->packer->result[n]; - - void *pdata = data + p.y * stride + p.x * fmt.stride; - memcpy_pic(pdata, b->bitmap, b->w * fmt.stride, b->h, - stride, b->stride); - } - if (!gl->UnmapBuffer(GL_PIXEL_UNPACK_BUFFER)) - mp_msg(MSGT_VO, MSGL_FATAL, "[gl] EOSD PBO upload failed. " - "Remove the 'pbo' suboption.\n"); - glUploadTex(gl, GL_TEXTURE_2D, fmt.format, fmt.type, NULL, stride, - bb[0].x, bb[0].y, bb[1].x - bb[0].x, bb[1].y - bb[0].y, - 0); - need_upload = false; - } - gl->BindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); - } - if (need_upload) { - // non-PBO upload - if (imgs->scaled) { - glClearTex(gl, GL_TEXTURE_2D, fmt.format, fmt.type, - bb[0].x, bb[0].y, bb[1].x - bb[0].y, bb[1].y - bb[0].y, - 0, &p->scratch); - } - for (int n = 0; n < osd->packer->count; n++) { - struct sub_bitmap *b = &imgs->parts[n]; - struct pos p = osd->packer->result[n]; - - glUploadTex(gl, GL_TEXTURE_2D, fmt.format, fmt.type, - b->bitmap, b->stride, p.x, p.y, b->w, b->h, 0); - } - } - - gl->BindTexture(GL_TEXTURE_2D, 0); - - debug_check_gl(p, "EOSD upload"); - - osd->vertices = talloc_realloc_size(osd, osd->vertices, - osd->packer->count - * sizeof(struct vertex) - * VERTICES_PER_QUAD); - - for (int n = 0; n < osd->packer->count; n++) { - struct sub_bitmap *b = &imgs->parts[n]; - struct pos p = osd->packer->result[n]; - - // NOTE: the blend color is used with SUBBITMAP_LIBASS only, so it - // doesn't matter that we upload garbage for the other formats - uint32_t c = b->libass.color; - uint8_t color[4] = { c >> 24, (c >> 16) & 0xff, - (c >> 8) & 0xff, 255 - (c & 0xff) }; - - write_quad(&osd->vertices[osd->num_vertices], - b->x, b->y, b->x + b->dw, b->y + b->dh, - p.x, p.y, p.x + b->w, p.y + b->h, - osd->width, osd->height, color, false); - osd->num_vertices += VERTICES_PER_QUAD; - } -} - static void draw_eosd(struct gl_priv *p, struct sub_bitmaps *imgs) { GL *gl = p->gl; - struct osd_render *osd = p->osd[imgs->render_index]; + assert(p->osd); - gen_eosd(p, osd, imgs); - - if (osd->num_vertices == 0) + struct mpgl_osd_part *osd = mpgl_osd_generate(p->osd, imgs); + if (!osd) return; assert(osd->format != SUBBITMAP_EMPTY); - gl->Enable(GL_BLEND); - if (osd->format == SUBBITMAP_OLD) { - gl->BlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - } else { - gl->BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + if (!osd->num_vertices) { + osd->vertices = talloc_realloc(osd, osd->vertices, struct vertex, + osd->packer->count * VERTICES_PER_QUAD); + + struct vertex *va = osd->vertices; + + for (int n = 0; n < osd->packer->count; n++) { + struct sub_bitmap *b = &imgs->parts[n]; + struct pos p = osd->packer->result[n]; + + // NOTE: the blend color is used with SUBBITMAP_LIBASS only, so it + // doesn't matter that we upload garbage for the other formats + uint32_t c = b->libass.color; + uint8_t color[4] = { c >> 24, (c >> 16) & 0xff, + (c >> 8) & 0xff, 255 - (c & 0xff) }; + + write_quad(&va[osd->num_vertices], + b->x, b->y, b->x + b->dw, b->y + b->dh, + p.x, p.y, p.x + b->w, p.y + b->h, + osd->w, osd->h, color, false); + osd->num_vertices += VERTICES_PER_QUAD; + } } - gl->BindTexture(GL_TEXTURE_2D, osd->texture); + + debug_check_gl(p, "before drawing osd"); + gl->UseProgram(p->osd_programs[osd->format]); + mpgl_osd_gl_set_state(p->osd, osd); draw_triangles(p, osd->vertices, osd->num_vertices); + mpgl_osd_gl_unset_state(p->osd, osd); gl->UseProgram(0); - gl->BindTexture(GL_TEXTURE_2D, 0); - gl->Disable(GL_BLEND); + + debug_check_gl(p, "after drawing osd"); } static void setup_vertex_array(GL *gl) @@ -1630,21 +1501,6 @@ static int init_gl(struct gl_priv *p) gl->BindBuffer(GL_ARRAY_BUFFER, 0); gl->BindVertexArray(0); - GLint max_texture_size; - gl->GetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size); - - for (int n = 0; n < MAX_OSD_PARTS; n++) { - assert(!p->osd[n]); - struct osd_render *osd = talloc_ptrtype(p, osd); - *osd = (struct osd_render) { - .packer = talloc_struct(osd, struct bitmap_packer, { - .w_max = max_texture_size, - .h_max = max_texture_size, - }), - }; - p->osd[n] = osd; - } - gl->ClearColor(0.0f, 0.0f, 0.0f, 0.0f); gl->Clear(GL_COLOR_BUFFER_BIT); @@ -1668,16 +1524,6 @@ static void uninit_gl(struct gl_priv *p) gl->DeleteBuffers(1, &p->vertex_buffer); p->vertex_buffer = 0; - for (int n = 0; n < MAX_OSD_PARTS; n++) { - struct osd_render *osd = p->osd[n]; - if (!osd) - continue; - gl->DeleteTextures(1, &osd->texture); - gl->DeleteBuffers(1, &osd->buffer); - talloc_free(osd); - p->osd[n] = NULL; - } - gl->DeleteTextures(1, &p->lut_3d_texture); p->lut_3d_texture = 0; } @@ -1852,8 +1698,9 @@ static int control(struct vo *vo, uint32_t request, void *data) return VO_TRUE; } case VOCTRL_QUERY_EOSD_FORMAT: { - int *p = data; - return osd_to_gl_formats[*p].shader ? VO_TRUE : VO_NOTIMPL; + int f = *(int *)data; + return (mpgl_osd_query_format(p->osd, f) && osd_shaders[f]) + ? VO_TRUE : VO_NOTIMPL; } case VOCTRL_ONTOP: if (!p->glctx->ontop) From 637f1a4dc6ebcbff1b899da3dbc4b8fa2b12f47c Mon Sep 17 00:00:00 2001 From: wm4 Date: Thu, 4 Oct 2012 02:29:54 +0200 Subject: [PATCH 18/83] vo_gl: use gl_osd.c Side effect: no direct support for old OSD format anymore. Instead, sub.c converts sub-images in that format to the packed, alpha-inverted version. osd-color suboption is broken. --- libvo/gl_osd.c | 3 +- libvo/gl_osd.h | 1 + libvo/vo_gl.c | 318 ++++--------------------------------------------- 3 files changed, 27 insertions(+), 295 deletions(-) diff --git a/libvo/gl_osd.c b/libvo/gl_osd.c index 0e99d13652..ce4bee5c03 100644 --- a/libvo/gl_osd.c +++ b/libvo/gl_osd.c @@ -159,7 +159,8 @@ static bool upload_osd(struct mpgl_osd *ctx, struct mpgl_osd_part *osd, { GL *gl = ctx->gl; - osd->packer->padding = imgs->scaled; // assume 2x2 filter on scaling + // assume 2x2 filter on scaling + osd->packer->padding = ctx->scaled || imgs->scaled; int r = packer_pack_from_subbitmaps(osd->packer, imgs); if (r < 0) { mp_msg(MSGT_VO, MSGL_ERR, "[gl] EOSD bitmaps do not fit on " diff --git a/libvo/gl_osd.h b/libvo/gl_osd.h index baebc3311c..9bbf6ad785 100644 --- a/libvo/gl_osd.h +++ b/libvo/gl_osd.h @@ -21,6 +21,7 @@ struct mpgl_osd_part { struct mpgl_osd { GL *gl; bool use_pbo; + bool scaled; struct mpgl_osd_part *parts[MAX_OSD_PARTS]; const struct osd_fmt_entry *fmt_table; void *scratch; diff --git a/libvo/vo_gl.c b/libvo/vo_gl.c index e71e482feb..1608ea594e 100644 --- a/libvo/vo_gl.c +++ b/libvo/vo_gl.c @@ -37,9 +37,9 @@ #include "geometry.h" #include "osd.h" #include "sub/sub.h" -#include "eosd_packer.h" #include "gl_common.h" +#include "gl_osd.h" #include "aspect.h" #include "fastmemcpy.h" #include "sub/ass_mp.h" @@ -49,31 +49,13 @@ #define MASK_NOT_COMBINERS (~((1 << YUV_CONVERSION_NONE) | (1 << YUV_CONVERSION_COMBINERS))) #define MASK_GAMMA_SUPPORT (MASK_NOT_COMBINERS & ~(1 << YUV_CONVERSION_FRAGMENT)) -struct vertex_eosd { - float x, y; - uint8_t color[4]; - float u, v; -}; - struct gl_priv { MPGLContext *glctx; GL *gl; int use_osd; int scaled_osd; - //! Textures for OSD - GLuint osdtex[MAX_OSD_PARTS]; - //! Alpha textures for OSD - GLuint osdatex[MAX_OSD_PARTS]; - GLuint eosd_texture; - int eosd_texture_width, eosd_texture_height; - struct eosd_packer *eosd; - struct vertex_eosd *eosd_va; - //! Display lists that draw the OSD parts - GLuint osdDispList[MAX_OSD_PARTS]; - GLuint osdaDispList[MAX_OSD_PARTS]; - //! How many parts the OSD currently consists of - int osdtexCnt; + struct mpgl_osd *osd; int osd_color; int use_ycbcr; @@ -248,133 +230,23 @@ static void update_yuvconv(struct vo *vo) } } -/** - * \brief remove all OSD textures and display-lists, thus clearing it. - */ -static void clearOSD(struct vo *vo) -{ - struct gl_priv *p = vo->priv; - GL *gl = p->gl; - - int i; - if (!p->osdtexCnt) - return; - gl->DeleteTextures(p->osdtexCnt, p->osdtex); - gl->DeleteTextures(p->osdtexCnt, p->osdatex); - for (i = 0; i < p->osdtexCnt; i++) - gl->DeleteLists(p->osdaDispList[i], 1); - for (i = 0; i < p->osdtexCnt; i++) - gl->DeleteLists(p->osdDispList[i], 1); - p->osdtexCnt = 0; -} - -/** - * \brief construct display list from ass image list - * \param img image list to create OSD from. - */ -static void genEOSD(struct vo *vo, mp_eosd_images_t *imgs) -{ - struct gl_priv *p = vo->priv; - GL *gl = p->gl; - - bool need_repos, need_upload, need_allocate; - eosd_packer_generate(p->eosd, imgs, &need_repos, &need_upload, - &need_allocate); - - if (!need_repos) - return; - - if (!p->eosd_texture) - gl->GenTextures(1, &p->eosd_texture); - - gl->BindTexture(p->target, p->eosd_texture); - - if (need_allocate) { - texSize(vo, p->eosd->surface.w, p->eosd->surface.h, - &p->eosd_texture_width, &p->eosd_texture_height); - // xxx it doesn't need to be cleared, that's a waste of time - glCreateClearTex(gl, p->target, GL_ALPHA, GL_ALPHA, GL_UNSIGNED_BYTE, - GL_NEAREST, p->eosd_texture_width, - p->eosd_texture_height, 0); - } - - // 2 triangles primitives per quad = 6 vertices per quad - // not using GL_QUADS, as it is deprecated in OpenGL 3.x and later - p->eosd_va = talloc_realloc_size(p->eosd, p->eosd_va, - p->eosd->targets_count - * sizeof(struct vertex_eosd) * 6); - - float eosd_w = p->eosd_texture_width; - float eosd_h = p->eosd_texture_height; - - if (p->use_rectangle == 1) - eosd_w = eosd_h = 1.0f; - - for (int n = 0; n < p->eosd->targets_count; n++) { - struct eosd_target *target = &p->eosd->targets[n]; - ASS_Image *i = target->ass_img; - - if (need_upload) { - glUploadTex(gl, p->target, GL_ALPHA, GL_UNSIGNED_BYTE, i->bitmap, - i->stride, target->source.x0, target->source.y0, - i->w, i->h, 0); - } - - uint8_t color[4] = { i->color >> 24, (i->color >> 16) & 0xff, - (i->color >> 8) & 0xff, 255 - (i->color & 0xff) }; - - float x0 = target->dest.x0; - float y0 = target->dest.y0; - float x1 = target->dest.x1; - float y1 = target->dest.y1; - float tx0 = target->source.x0 / eosd_w; - float ty0 = target->source.y0 / eosd_h; - float tx1 = target->source.x1 / eosd_w; - float ty1 = target->source.y1 / eosd_h; - -#define COLOR_INIT {color[0], color[1], color[2], color[3]} - struct vertex_eosd *va = &p->eosd_va[n * 6]; - va[0] = (struct vertex_eosd) { x0, y0, COLOR_INIT, tx0, ty0 }; - va[1] = (struct vertex_eosd) { x0, y1, COLOR_INIT, tx0, ty1 }; - va[2] = (struct vertex_eosd) { x1, y0, COLOR_INIT, tx1, ty0 }; - va[3] = (struct vertex_eosd) { x1, y1, COLOR_INIT, tx1, ty1 }; - va[4] = va[2]; - va[5] = va[1]; -#undef COLOR_INIT - } - - gl->BindTexture(p->target, 0); -} - // Note: relies on state being setup, like projection matrix and blending -static void drawEOSD(struct vo *vo) +static void render_osd(struct vo *vo, struct sub_bitmaps *imgs) { struct gl_priv *p = vo->priv; GL *gl = p->gl; - if (p->eosd->targets_count == 0) - return; - - gl->BindTexture(p->target, p->eosd_texture); - - struct vertex_eosd *va = p->eosd_va; - size_t stride = sizeof(struct vertex_eosd); - - gl->VertexPointer(2, GL_FLOAT, stride, &va[0].x); - gl->ColorPointer(4, GL_UNSIGNED_BYTE, stride, &va[0].color[0]); - gl->TexCoordPointer(2, GL_FLOAT, stride, &va[0].u); - - gl->EnableClientState(GL_VERTEX_ARRAY); - gl->EnableClientState(GL_TEXTURE_COORD_ARRAY); - gl->EnableClientState(GL_COLOR_ARRAY); - - gl->DrawArrays(GL_TRIANGLES, 0, p->eosd->targets_count * 6); - - gl->DisableClientState(GL_VERTEX_ARRAY); - gl->DisableClientState(GL_TEXTURE_COORD_ARRAY); - gl->DisableClientState(GL_COLOR_ARRAY); - - gl->BindTexture(p->target, 0); + if (!p->scaled_osd) { + gl->MatrixMode(GL_PROJECTION); + gl->PushMatrix(); + gl->LoadIdentity(); + gl->Ortho(0, vo->dwidth, vo->dheight, 0, -1, 1); + } + gl->Color4ub((p->osd_color >> 16) & 0xff, (p->osd_color >> 8) & 0xff, + p->osd_color & 0xff, 0xff - (p->osd_color >> 24)); + mpgl_osd_draw_legacy(p->osd, imgs); + if (!p->scaled_osd) + gl->PopMatrix(); } /** @@ -394,13 +266,9 @@ static void uninitGl(struct vo *vo) if (i) gl->DeleteTextures(i, p->default_texs); p->default_texs[0] = 0; - clearOSD(vo); - if (p->eosd_texture) - gl->DeleteTextures(1, &p->eosd_texture); - eosd_packer_reinit(p->eosd, 0, 0); - p->eosd_texture = 0; - if (gl->DeleteBuffers && p->buffer) - gl->DeleteBuffers(1, &p->buffer); + if (p->osd) + mpgl_osd_destroy(p->osd); + p->osd = NULL; p->buffer = 0; p->buffersize = 0; p->bufferptr = NULL; @@ -580,9 +448,8 @@ static int initGl(struct vo *vo, uint32_t d_width, uint32_t d_height) update_yuvconv(vo); } - GLint max_texture_size; - gl->GetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size); - eosd_packer_reinit(p->eosd, max_texture_size, max_texture_size); + p->osd = mpgl_osd_init(gl, true); + p->osd->scaled = p->scaled_osd; resize(vo, d_width, d_height); @@ -650,140 +517,6 @@ static void check_events(struct vo *vo) vo->want_redraw = true; } -/** - * Creates the textures and the display list needed for displaying - * an OSD part. - * Callback function for osd_draw_text_ext(). - */ -static void create_osd_texture(void *ctx, int x0, int y0, int w, int h, - unsigned char *src, unsigned char *srca, - int stride) -{ - struct vo *vo = ctx; - struct gl_priv *p = vo->priv; - GL *gl = p->gl; - - // initialize to 8 to avoid special-casing on alignment - int sx = 8, sy = 8; - GLint scale_type = p->scaled_osd ? GL_LINEAR : GL_NEAREST; - - if (w <= 0 || h <= 0 || stride < w) { - mp_msg(MSGT_VO, MSGL_V, "Invalid dimensions OSD for part!\n"); - return; - } - texSize(vo, w, h, &sx, &sy); - - if (p->osdtexCnt >= MAX_OSD_PARTS) { - mp_msg(MSGT_VO, MSGL_ERR, "Too many OSD parts, contact the developers!\n"); - return; - } - - // create Textures for OSD part - gl->GenTextures(1, &p->osdtex[p->osdtexCnt]); - gl->BindTexture(p->target, p->osdtex[p->osdtexCnt]); - glCreateClearTex(gl, p->target, GL_LUMINANCE, GL_LUMINANCE, - GL_UNSIGNED_BYTE, scale_type, sx, sy, 0); - glUploadTex(gl, p->target, GL_LUMINANCE, GL_UNSIGNED_BYTE, src, stride, - 0, 0, w, h, 0); - - gl->GenTextures(1, &p->osdatex[p->osdtexCnt]); - gl->BindTexture(p->target, p->osdatex[p->osdtexCnt]); - glCreateClearTex(gl, p->target, GL_ALPHA, GL_ALPHA, GL_UNSIGNED_BYTE, - scale_type, sx, sy, 0); - { - int i; - char *tmp = malloc(stride * h); - // convert alpha from weird MPlayer scale. - // in-place is not possible since it is reused for future OSDs - for (i = h * stride - 1; i >= 0; i--) - tmp[i] = -srca[i]; - glUploadTex(gl, p->target, GL_ALPHA, GL_UNSIGNED_BYTE, tmp, stride, - 0, 0, w, h, 0); - free(tmp); - } - - gl->BindTexture(p->target, 0); - - // Create a list for rendering this OSD part - p->osdaDispList[p->osdtexCnt] = gl->GenLists(1); - gl->NewList(p->osdaDispList[p->osdtexCnt], GL_COMPILE); - // render alpha - gl->BindTexture(p->target, p->osdatex[p->osdtexCnt]); - glDrawTex(gl, x0, y0, w, h, 0, 0, w, h, sx, sy, p->use_rectangle == 1, 0, 0); - gl->EndList(); - - p->osdDispList[p->osdtexCnt] = gl->GenLists(1); - gl->NewList(p->osdDispList[p->osdtexCnt], GL_COMPILE); - // render OSD - gl->BindTexture(p->target, p->osdtex[p->osdtexCnt]); - glDrawTex(gl, x0, y0, w, h, 0, 0, w, h, sx, sy, p->use_rectangle == 1, 0, 0); - gl->EndList(); - - p->osdtexCnt++; -} - -#define RENDER_OSD 1 -#define RENDER_EOSD 2 - -/** - * \param type bit 0: render OSD, bit 1: render EOSD - */ -static void do_render_osd(struct vo *vo, int type) -{ - struct gl_priv *p = vo->priv; - GL *gl = p->gl; - - int draw_osd = (type & RENDER_OSD) && p->osdtexCnt > 0; - int draw_eosd = (type & RENDER_EOSD); - if (!draw_osd && !draw_eosd) - return; - // set special rendering parameters - if (!p->scaled_osd) { - gl->MatrixMode(GL_PROJECTION); - gl->PushMatrix(); - gl->LoadIdentity(); - gl->Ortho(0, vo->dwidth, vo->dheight, 0, -1, 1); - } - gl->Enable(GL_BLEND); - if (draw_eosd) { - gl->BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - drawEOSD(vo); - } - if (draw_osd) { - gl->Color4ub((p->osd_color >> 16) & 0xff, (p->osd_color >> 8) & 0xff, - p->osd_color & 0xff, 0xff - (p->osd_color >> 24)); - // draw OSD - gl->BlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_ALPHA); - gl->CallLists(p->osdtexCnt, GL_UNSIGNED_INT, p->osdaDispList); - gl->BlendFunc(GL_SRC_ALPHA, GL_ONE); - gl->CallLists(p->osdtexCnt, GL_UNSIGNED_INT, p->osdDispList); - } - // set rendering parameters back to defaults - gl->Disable(GL_BLEND); - if (!p->scaled_osd) - gl->PopMatrix(); - gl->BindTexture(p->target, 0); -} - -static void draw_osd(struct vo *vo, struct osd_state *osd) -{ - struct gl_priv *p = vo->priv; - - if (!p->use_osd) - return; - if (vo_osd_has_changed(osd)) { - int osd_h, osd_w; - clearOSD(vo); - osd_w = p->scaled_osd ? p->image_width : vo->dwidth; - osd_h = p->scaled_osd ? p->image_height : vo->dheight; - osd_draw_text_ext(osd, osd_w, osd_h, p->ass_border_x, - p->ass_border_y, p->ass_border_x, - p->ass_border_y, p->image_width, - p->image_height, create_osd_texture, vo); - } - do_render_osd(vo, RENDER_OSD); -} - static void do_render(struct vo *vo) { struct gl_priv *p = vo->priv; @@ -1176,8 +909,6 @@ static int preinit(struct vo *vo, const char *arg) .osd_color = 0xffffff, }; - p->eosd = eosd_packer_create(vo); - int allow_sw = 0; char *backend_arg = NULL; @@ -1361,11 +1092,10 @@ static int control(struct vo *vo, uint32_t request, void *data) case VOCTRL_DRAW_IMAGE: return draw_image(vo, data); case VOCTRL_DRAW_EOSD: - if (!data) - return VO_FALSE; - genEOSD(vo, data); - do_render_osd(vo, RENDER_EOSD); + render_osd(vo, data); return VO_TRUE; + case VOCTRL_QUERY_EOSD_FORMAT: + return mpgl_osd_query_format(p->osd, *(int *)data) ? VO_TRUE : VO_NOTIMPL; case VOCTRL_GET_EOSD_RES: { mp_eosd_res_t *r = data; r->w = vo->dwidth; @@ -1461,7 +1191,7 @@ const struct vo_driver video_out_gl = { .config = config, .control = control, .draw_slice = draw_slice, - .draw_osd = draw_osd, + .draw_osd = draw_osd_with_eosd, .flip_page = flip_page, .check_events = check_events, .uninit = uninit, @@ -1483,7 +1213,7 @@ const struct vo_driver video_out_gl_nosw = .config = config, .control = control, .draw_slice = draw_slice, - .draw_osd = draw_osd, + .draw_osd = draw_osd_with_eosd, .flip_page = flip_page, .check_events = check_events, .uninit = uninit, From 7463cff7470f47c9437db2890fcaddb83e6c832b Mon Sep 17 00:00:00 2001 From: wm4 Date: Thu, 4 Oct 2012 02:48:05 +0200 Subject: [PATCH 19/83] vo_corevideo: add EOSD Completely untested. --- libvo/vo_corevideo.m | 123 ++++++++----------------------------------- 1 file changed, 22 insertions(+), 101 deletions(-) diff --git a/libvo/vo_corevideo.m b/libvo/vo_corevideo.m index fd667acb61..1ac6369089 100644 --- a/libvo/vo_corevideo.m +++ b/libvo/vo_corevideo.m @@ -35,6 +35,7 @@ #import "osd.h" #import "gl_common.h" +#import "gl_osd.h" #import "cocoa_common.h" struct quad { @@ -44,14 +45,6 @@ struct quad { GLfloat upperLeft[2]; }; -#define CV_VERTICES_PER_QUAD 6 - -struct osd_p { - GLuint tex[MAX_OSD_PARTS]; - NSRect tex_rect[MAX_OSD_PARTS]; - int tex_cnt; -}; - struct priv { MPGLContext *mpglctx; OSType pixelFormat; @@ -64,7 +57,7 @@ struct priv { CVOpenGLTextureRef texture; struct quad *quad; - struct osd_p *osd; + struct mpgl_osd *osd; }; static void resize(struct vo *vo, int width, int height) @@ -124,6 +117,9 @@ static int init_gl(struct vo *vo, uint32_t d_width, uint32_t d_height) gl->DrawBuffer(GL_BACK); gl->TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + if (!p->osd) + p->osd = mpgl_osd_init(gl, true); + resize(vo, d_width, d_height); gl->ClearColor(0.0f, 0.0f, 0.0f, 0.0f); @@ -141,7 +137,6 @@ static void release_cv_entities(struct vo *vo) { p->texture = NULL; CVOpenGLTextureCacheRelease(p->textureCache); p->textureCache = NULL; - } static int config(struct vo *vo, uint32_t width, uint32_t height, @@ -171,90 +166,6 @@ static void check_events(struct vo *vo) resize(vo, vo->dwidth, vo->dheight); } -static void create_osd_texture(void *ctx, int x0, int y0, int w, int h, - unsigned char *src, unsigned char *srca, - int stride) -{ - struct priv *p = ((struct vo *) ctx)->priv; - struct osd_p *osd = p->osd; - GL *gl = p->mpglctx->gl; - - if (w <= 0 || h <= 0 || stride < w) { - mp_msg(MSGT_VO, MSGL_V, "Invalid dimensions OSD for part!\n"); - return; - } - - if (osd->tex_cnt >= MAX_OSD_PARTS) { - mp_msg(MSGT_VO, MSGL_ERR, "Too many OSD parts, contact the" - " developers!\n"); - return; - } - - gl->GenTextures(1, &osd->tex[osd->tex_cnt]); - gl->BindTexture(GL_TEXTURE_2D, osd->tex[osd->tex_cnt]); - glCreateClearTex(gl, GL_TEXTURE_2D, GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, - GL_UNSIGNED_BYTE, GL_LINEAR, w, h, 0); - { - int i; - unsigned char *tmp = malloc(stride * h * 2); - // convert alpha from weird MPlayer scale. - for (i = 0; i < h * stride; i++) { - tmp[i*2+0] = src[i]; - tmp[i*2+1] = -srca[i]; - } - glUploadTex(gl, GL_TEXTURE_2D, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, - tmp, stride * 2, 0, 0, w, h, 0); - free(tmp); - } - - osd->tex_rect[osd->tex_cnt] = NSMakeRect(x0, y0, w, h); - - gl->BindTexture(GL_TEXTURE_2D, 0); - osd->tex_cnt++; -} - -static void clearOSD(struct vo *vo) -{ - struct priv *p = vo->priv; - struct osd_p *osd = p->osd; - GL *gl = p->mpglctx->gl; - - if (!osd->tex_cnt) - return; - gl->DeleteTextures(osd->tex_cnt, osd->tex); - osd->tex_cnt = 0; -} - -static void draw_osd(struct vo *vo, struct osd_state *osd_s) -{ - struct priv *p = vo->priv; - struct osd_p *osd = p->osd; - GL *gl = p->mpglctx->gl; - - if (vo_osd_has_changed(osd_s)) { - clearOSD(vo); - osd_draw_text_ext(osd_s, vo->dwidth, vo->dheight, 0, 0, 0, 0, - p->image_width, p->image_height, create_osd_texture, - vo); - } - - if (osd->tex_cnt > 0) { - gl->Enable(GL_BLEND); - gl->BlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - - for (int n = 0; n < osd->tex_cnt; n++) { - NSRect tr = osd->tex_rect[n]; - gl->BindTexture(GL_TEXTURE_2D, osd->tex[n]); - glDrawTex(gl, tr.origin.x, tr.origin.y, - tr.size.width, tr.size.height, - 0, 0, 1.0, 1.0, 1, 1, 0, 0, 0); - } - - gl->Disable(GL_BLEND); - gl->BindTexture(GL_TEXTURE_2D, 0); - } -} - static void prepare_texture(struct vo *vo) { struct priv *p = vo->priv; @@ -342,7 +253,7 @@ static int query_format(struct vo *vo, uint32_t format) struct priv *p = vo->priv; const int flags = VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW | VFCAP_OSD | VFCAP_HWSCALE_UP | VFCAP_HWSCALE_DOWN | - VOCAP_NOSLICES; + VOCAP_NOSLICES | VFCAP_EOSD; switch (format) { case IMGFMT_YUY2: p->pixelFormat = kYUVSPixelFormat; @@ -366,6 +277,8 @@ static int query_format(struct vo *vo, uint32_t format) static void uninit(struct vo *vo) { struct priv *p = vo->priv; + if (p->osd) + mpgl_osd_destroy(p->osd); uninit_mpglcontext(p->mpglctx); release_cv_entities(vo); } @@ -379,11 +292,6 @@ static int preinit(struct vo *vo, const char *arg) .mpglctx = init_mpglcontext(GLTYPE_COCOA, vo), .colorspace = MP_CSP_DETAILS_DEFAULTS, .quad = talloc_ptrtype(p, p->quad), - .osd = talloc_ptrtype(p, p->osd), - }; - - *p->osd = (struct osd_p) { - .tex_cnt = 0, }; return 0; @@ -420,6 +328,19 @@ static int control(struct vo *vo, uint32_t request, void *data) return draw_image(vo, data); case VOCTRL_QUERY_FORMAT: return query_format(vo, *(uint32_t*)data); + case VOCTRL_DRAW_EOSD: + mpgl_osd_draw_legacy(p->osd, data); + return VO_TRUE; + case VOCTRL_QUERY_EOSD_FORMAT: + return mpgl_osd_query_format(p->osd, *(int *)data) + ? VO_TRUE : VO_NOTIMPL; + case VOCTRL_GET_EOSD_RES: { + mp_eosd_res_t *r = data; + r->w = vo->dwidth; + r->h = vo->dheight; + r->mt = r->mb = r->ml = r->mr = 0; + return VO_TRUE; + } case VOCTRL_ONTOP: p->mpglctx->ontop(vo); return VO_TRUE; @@ -460,7 +381,7 @@ const struct vo_driver video_out_corevideo = { .preinit = preinit, .config = config, .control = control, - .draw_osd = draw_osd, + .draw_osd = draw_osd_with_eosd, .flip_page = flip_page, .check_events = check_events, .uninit = uninit, From ffd6219ecdc12dc77b29cb95dea93bbb73258742 Mon Sep 17 00:00:00 2001 From: wm4 Date: Thu, 4 Oct 2012 17:16:21 +0200 Subject: [PATCH 20/83] vo_direct3d: use new OSD API --- libvo/vo_direct3d.c | 438 +++++++++++++++----------------------------- 1 file changed, 148 insertions(+), 290 deletions(-) diff --git a/libvo/vo_direct3d.c b/libvo/vo_direct3d.c index 57bad61d02..a9bac67e6c 100644 --- a/libvo/vo_direct3d.c +++ b/libvo/vo_direct3d.c @@ -41,7 +41,7 @@ #include "w32_common.h" #include "libavutil/common.h" #include "sub/sub.h" -#include "eosd_packer.h" +#include "bitmap_packer.h" // shaders generated by fxc.exe from d3d_shader_yuv.hlsl #include "d3d_shader_yuv.h" @@ -59,14 +59,6 @@ #define DEVTYPE D3DDEVTYPE_HAL //#define DEVTYPE D3DDEVTYPE_REF - -#define D3DFVF_OSD_VERTEX (D3DFVF_XYZ | D3DFVF_TEX1) - -typedef struct { - float x, y, z; /* Position of vertex in 3D space */ - float tu, tv; /* Texture coordinates */ -} vertex_osd; - #define D3DFVF_EOSD_VERTEX (D3DFVF_XYZ | D3DFVF_TEX1 | D3DFVF_DIFFUSE) typedef struct { @@ -116,6 +108,15 @@ struct texplane { uint8_t clearval; }; +struct osdpart { + enum sub_bitmap_format format; + int bitmap_id, bitmap_pos_id; + struct d3dtex texture; + int num_vertices; + vertex_eosd *vertices; + struct bitmap_packer *packer; +}; + /* Global variables "priv" structure. I try to keep their count low. */ typedef struct d3d_priv { @@ -175,14 +176,10 @@ typedef struct d3d_priv { IDirect3DSurface9 *d3d_surface; /**< Offscreen Direct3D Surface. MPlayer renders inside it. Uses colorspace priv->movie_src_fmt */ - struct d3dtex texture_osd; /**< RGBA */ IDirect3DSurface9 *d3d_backbuf; /**< Video card's back buffer (used to display next frame) */ - struct d3dtex texture_eosd; /**< A8 */ int cur_backbuf_width; /**< Current backbuffer width */ int cur_backbuf_height; /**< Current backbuffer height */ - int is_osd_populated; /**< 1 = OSD texture has something to display, - 0 = OSD texture is clear */ int device_caps_power2_only; /**< 1 = texture sizes have to be power 2 0 = texture sizes can be anything */ int device_caps_square_only; /**< 1 = textures have to be square @@ -197,8 +194,7 @@ typedef struct d3d_priv { struct mp_csp_details colorspace; struct mp_csp_equalizer video_eq; - struct eosd_packer *eosd; /**< EOSD packer (image positions etc.) */ - vertex_eosd *eosd_vb; /**< temporary memory for D3D when rendering EOSD */ + struct osdpart *osd[MAX_OSD_PARTS]; } d3d_priv; struct fmt_entry { @@ -232,9 +228,12 @@ static const struct fmt_entry fmt_table[] = { {0}, }; +static const D3DFORMAT osd_fmt_table[SUBBITMAP_COUNT] = { + [SUBBITMAP_LIBASS] = D3DFMT_A8, + [SUBBITMAP_RGBA] = D3DFMT_A8R8G8B8, +}; + -static void generate_eosd(d3d_priv *priv, mp_eosd_images_t *); -static void draw_eosd(d3d_priv *priv); static void update_colorspace(d3d_priv *priv); static void d3d_clear_video_textures(d3d_priv *priv); static bool resize_d3d(d3d_priv *priv); @@ -242,7 +241,7 @@ static uint32_t d3d_draw_frame(d3d_priv *priv); static int draw_slice(struct vo *vo, uint8_t *src[], int stride[], int w, int h, int x, int y); static void uninit(struct vo *vo); -static void draw_osd(struct vo *vo, struct osd_state *osd); +static void draw_osd(d3d_priv *priv, struct sub_bitmaps *imgs); static void flip_page(struct vo *vo); static mp_image_t *get_screenshot(d3d_priv *priv); static mp_image_t *get_window_screenshot(d3d_priv *priv); @@ -480,17 +479,16 @@ static void destroy_d3d_surfaces(d3d_priv *priv) d3d_destroy_video_objects(priv); - d3dtex_release(priv, &priv->texture_osd); + for (int n = 0; n < MAX_OSD_PARTS; n++) { + struct osdpart *osd = priv->osd[n]; + d3dtex_release(priv, &osd->texture); + osd->bitmap_id = osd->bitmap_pos_id = -1; + } if (priv->d3d_backbuf) IDirect3DSurface9_Release(priv->d3d_backbuf); priv->d3d_backbuf = NULL; - d3dtex_release(priv, &priv->texture_eosd); - - if (priv->eosd) - eosd_packer_reinit(priv->eosd, 0, 0); - priv->d3d_in_scene = false; } @@ -598,8 +596,6 @@ static void d3d_clear_video_textures(d3d_priv *priv) // done. static bool create_d3d_surfaces(d3d_priv *priv) { - int osd_width = priv->vo->dwidth, osd_height = priv->vo->dheight; - int tex_width = osd_width, tex_height = osd_height; mp_msg(MSGT_VO, MSGL_V, "create_d3d_surfaces called.\n"); if (!priv->d3d_backbuf && @@ -613,40 +609,6 @@ static bool create_d3d_surfaces(d3d_priv *priv) if (!d3d_configure_video_objects(priv)) return 0; - /* create OSD */ - - d3d_fix_texture_size(priv, &tex_width, &tex_height); - - while (tex_width > priv->max_texture_width - || tex_height > priv->max_texture_height) - { - osd_width >>= 1; - osd_height >>= 1; - tex_width >>= 1; - tex_height >>= 1; - } - - if (priv->texture_osd.tex_w < tex_width - || priv->texture_osd.tex_h < tex_height) - { - d3dtex_release(priv, &priv->texture_osd); - - mp_msg(MSGT_VO, MSGL_V, "OSD texture size (%dx%d)," - " requested (%dx%d).\n", osd_width, osd_height, tex_width, - tex_height); - - if (!d3dtex_allocate(priv, &priv->texture_osd, D3DFMT_A8L8, tex_width, - tex_height)) - { - mp_msg(MSGT_VO, MSGL_ERR, - "Allocating OSD texture failed.\n"); - return 0; - } - } - - priv->texture_osd.w = osd_width; - priv->texture_osd.h = osd_height; - /* setup default renderstate */ IDirect3DDevice9_SetRenderState(priv->d3d_device, D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); @@ -671,10 +633,6 @@ static bool create_d3d_surfaces(d3d_priv *priv) D3DTADDRESS_CLAMP); } - if (priv->eosd && !priv->texture_eosd.system) - eosd_packer_reinit(priv->eosd, priv->max_texture_width, - priv->max_texture_height); - return 1; } @@ -1270,8 +1228,8 @@ static int query_format(d3d_priv *priv, uint32_t movie_fmt) int eosd_caps = VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW | VFCAP_OSD | VFCAP_HWSCALE_UP | VFCAP_HWSCALE_DOWN; - if (priv->eosd) - eosd_caps |= VFCAP_EOSD; + if (!priv->opt_disable_eosd) + eosd_caps |= VFCAP_EOSD | VFCAP_EOSD_RGBA; return eosd_caps; } @@ -1412,6 +1370,14 @@ static int preinit_internal(struct vo *vo, const char *arg, bool allow_shaders) .video_eq = { MP_CSP_EQ_CAPS_COLORMATRIX }, }; + for (int n = 0; n < MAX_OSD_PARTS; n++) { + struct osdpart *osd = talloc_ptrtype(priv, osd); + *osd = (struct osdpart) { + .packer = talloc_zero(osd, struct bitmap_packer), + }; + priv->osd[n] = osd; + } + if (!allow_shaders) { priv->opt_disable_shaders = priv->opt_disable_textures = true; } @@ -1436,9 +1402,6 @@ static int preinit_internal(struct vo *vo, const char *arg, bool allow_shaders) return -1; } - if (!priv->opt_disable_eosd) - priv->eosd = eosd_packer_create(priv); - priv->d3d9_dll = LoadLibraryA("d3d9.dll"); if (!priv->d3d9_dll) { mp_msg(MSGT_VO, MSGL_ERR, @@ -1549,12 +1512,11 @@ static int control(struct vo *vo, uint32_t request, void *data) case VOCTRL_DRAW_EOSD: if (!data) return VO_FALSE; - assert(priv->eosd); - generate_eosd(priv, data); - draw_eosd(priv); + draw_osd(priv, data); return VO_TRUE; + case VOCTRL_QUERY_EOSD_FORMAT: + return osd_fmt_table[*(int *)data] ? VO_TRUE : VO_NOTIMPL; case VOCTRL_GET_EOSD_RES: { - assert(priv->eosd); struct mp_eosd_res *r = data; r->w = vo->dwidth; r->h = vo->dheight; @@ -1934,142 +1896,86 @@ error_exit: return NULL; } -/** @brief Maps MPlayer alpha to D3D - * 0x0 -> transparent and discarded by alpha test - * 0x1 -> 0xFF to become opaque - * other alpha values are inverted +1 (2 = -2) - * These values are then inverted again with - the texture filter D3DBLEND_INVSRCALPHA - */ -static void vo_draw_alpha_l8a8(int w, int h, unsigned char* src, - unsigned char *srca, int srcstride, - unsigned char* dstbase, int dststride) +static bool upload_osd(d3d_priv *priv, struct osdpart *osd, + struct sub_bitmaps *imgs) { - int y; - for (y = 0; y < h; y++) { - unsigned short *dst = (unsigned short*)dstbase; - int x; - for (x = 0; x < w; x++) { - dst[x] = (-srca[x] << 8) | src[x]; - } - src += srcstride; - srca += srcstride; - dstbase += dststride; - } -} + D3DFORMAT fmt = osd_fmt_table[imgs->format]; + + osd->packer->w_max = priv->max_texture_width; + osd->packer->h_max = priv->max_texture_height; + + osd->packer->padding = imgs->scaled; // assume 2x2 filter on scaling + int r = packer_pack_from_subbitmaps(osd->packer, imgs); + if (r < 0) { + mp_msg(MSGT_VO, MSGL_ERR, "EOSD bitmaps do not fit on " + "a surface with the maximum supported size %dx%d.\n", + osd->packer->w_max, osd->packer->h_max); + return false; + } + + if (osd->packer->w > osd->texture.tex_w + || osd->packer->h > osd->texture.tex_h + || osd->format != imgs->format) + { + osd->format = imgs->format; + + int new_w = osd->packer->w; + int new_h = osd->packer->h; + d3d_fix_texture_size(priv, &new_w, &new_h); + + mp_msg(MSGT_VO, MSGL_DBG2, "reallocate OSD surface.\n"); + + d3dtex_release(priv, &osd->texture); + d3dtex_allocate(priv, &osd->texture, fmt, new_w, new_h); + + if (!osd->texture.system) + return false; // failed to allocate + } + + struct pos bb[2]; + packer_get_bb(osd->packer, bb); + RECT dirty_rc = { bb[0].x, bb[0].y, bb[1].x, bb[1].y }; -struct draw_osd_closure { - d3d_priv *priv; D3DLOCKED_RECT locked_rect; -}; -/** @brief Callback function to render the OSD to the texture - */ -static void draw_alpha(void *pctx, int x0, int y0, int w, int h, - unsigned char *src, unsigned char *srca, int stride) -{ - struct draw_osd_closure *ctx = pctx; - D3DLOCKED_RECT locked_rect = ctx->locked_rect; - - vo_draw_alpha_l8a8(w, h, src, srca, stride, - (unsigned char *)locked_rect.pBits + locked_rect.Pitch * y0 + 2 * x0, - locked_rect.Pitch); - - ctx->priv->is_osd_populated = 1; -} - -/** @brief libvo Callback: Draw OSD/Subtitles, - */ -static void draw_osd(struct vo *vo, struct osd_state *osd) -{ - d3d_priv *priv = vo->priv; - - if (!priv->d3d_device) - return; - - if (vo_osd_has_changed(osd)) { - struct draw_osd_closure ctx = { priv }; - - /* clear the OSD */ - if (FAILED(IDirect3DTexture9_LockRect(priv->texture_osd.system, 0, - &ctx.locked_rect, NULL, 0))) { - mp_msg(MSGT_VO,MSGL_ERR, "OSD texture lock failed.\n"); - return; - } - - /* clear the whole texture to avoid issues due to interpolation */ - memset(ctx.locked_rect.pBits, 0, - ctx.locked_rect.Pitch * priv->texture_osd.tex_h); - - priv->is_osd_populated = 0; - /* required for if subs are in the boarder region */ - priv->is_clear_needed = 1; - - osd_draw_text_ext(osd, priv->texture_osd.w, priv->texture_osd.h, - priv->border_x, priv->border_y, - priv->border_x, priv->border_y, - priv->src_width, priv->src_height, draw_alpha, &ctx); - - if (FAILED(IDirect3DTexture9_UnlockRect(priv->texture_osd.system, 0))) { - mp_msg(MSGT_VO,MSGL_ERR, - "OSD texture unlock failed.\n"); - return; - } - - d3dtex_update(priv, &priv->texture_osd); + if (FAILED(IDirect3DTexture9_LockRect(osd->texture.system, 0, &locked_rect, + &dirty_rc, 0))) + { + mp_msg(MSGT_VO,MSGL_ERR, "EOSD texture lock failed.\n"); + return false; } - if (priv->is_osd_populated) { - float tw = (float)priv->texture_osd.w / priv->texture_osd.tex_w; - float th = (float)priv->texture_osd.h / priv->texture_osd.tex_h; + int ps = fmt == D3DFMT_A8 ? 1 : 4; + packer_copy_subbitmaps(osd->packer, imgs, locked_rect.pBits, ps, + locked_rect.Pitch); - vertex_osd osd_quad_vb[] = { - { 0, 0, 0.0f, 0, 0 }, - { vo->dwidth, 0, 0.0f, tw, 0 }, - { 0, vo->dheight, 0.0f, 0, th }, - { vo->dwidth, vo->dheight, 0.0f, tw, th } - }; - - d3d_begin_scene(priv); - - IDirect3DDevice9_SetRenderState(priv->d3d_device, - D3DRS_ALPHABLENDENABLE, TRUE); - IDirect3DDevice9_SetRenderState(priv->d3d_device, - D3DRS_ALPHATESTENABLE, TRUE); - - IDirect3DDevice9_SetTexture(priv->d3d_device, 0, - d3dtex_get_render_texture(priv, &priv->texture_osd)); - - IDirect3DDevice9_SetFVF(priv->d3d_device, D3DFVF_OSD_VERTEX); - IDirect3DDevice9_DrawPrimitiveUP(priv->d3d_device, D3DPT_TRIANGLESTRIP, - 2, osd_quad_vb, sizeof(vertex_osd)); - - IDirect3DDevice9_SetTexture(priv->d3d_device, 0, NULL); - - IDirect3DDevice9_SetRenderState(priv->d3d_device, - D3DRS_ALPHATESTENABLE, FALSE); - IDirect3DDevice9_SetRenderState(priv->d3d_device, - D3DRS_ALPHABLENDENABLE, FALSE); + if (FAILED(IDirect3DTexture9_UnlockRect(osd->texture.system, 0))) { + mp_msg(MSGT_VO,MSGL_ERR, "EOSD texture unlock failed.\n"); + return false; } + + return d3dtex_update(priv, &osd->texture); } -static void d3d_realloc_eosd_texture(d3d_priv *priv) +static struct osdpart *generate_osd(d3d_priv *priv, struct sub_bitmaps *imgs) { - int new_w = priv->eosd->surface.w; - int new_h = priv->eosd->surface.h; + if (imgs->num_parts == 0 || !osd_fmt_table[imgs->format]) + return NULL; - d3d_fix_texture_size(priv, &new_w, &new_h); + struct osdpart *osd = priv->osd[imgs->render_index]; - if (new_w == priv->texture_eosd.tex_w && new_h == priv->texture_eosd.tex_h) - return; + if (imgs->bitmap_pos_id != osd->bitmap_pos_id) { + if (imgs->bitmap_id != osd->bitmap_id) { + if (!upload_osd(priv, osd, imgs)) + osd->packer->count = 0; + } - mp_msg(MSGT_VO, MSGL_DBG2, "reallocate EOSD surface.\n"); + osd->bitmap_id = imgs->bitmap_id; + osd->bitmap_pos_id = imgs->bitmap_pos_id; + osd->num_vertices = 0; + } - // fortunately, we don't need to keep the old image data - // we can always free it - d3dtex_release(priv, &priv->texture_eosd); - - d3dtex_allocate(priv, &priv->texture_eosd, D3DFMT_A8, new_w, new_h); + return osd->packer->count ? osd : NULL; } static D3DCOLOR ass_to_d3d_color(uint32_t color) @@ -2081,124 +1987,76 @@ static D3DCOLOR ass_to_d3d_color(uint32_t color) return D3DCOLOR_ARGB(a, r, g, b); } -static void generate_eosd(d3d_priv *priv, mp_eosd_images_t *imgs) +static void draw_osd(d3d_priv *priv, struct sub_bitmaps *imgs) { if (!priv->d3d_device) return; - bool need_reposition, need_upload, need_resize; - eosd_packer_generate(priv->eosd, imgs, &need_reposition, &need_upload, - &need_resize); - - if (!need_reposition) + struct osdpart *osd = generate_osd(priv, imgs); + if (!osd) return; - // even if the texture size is unchanged, the texture might have been free'd - d3d_realloc_eosd_texture(priv); - if (!priv->texture_eosd.system) - return; // failed to allocate - // reupload all EOSD images + if (osd->packer->count && !osd->num_vertices) { + // We need 2 primitives per quad which makes 6 vertices (we could reduce + // the number of vertices by using an indexed vertex array, but it's + // probably not worth doing) + osd->num_vertices = osd->packer->count * 6; + osd->vertices = talloc_realloc(osd, osd->vertices, vertex_eosd, + osd->num_vertices); - // we need 2 primitives per quad which makes 6 vertices (we could reduce the - // number of vertices by using an indexed vertex array, but it's probably - // not worth doing) - priv->eosd_vb = talloc_realloc_size(priv->eosd, priv->eosd_vb, - priv->eosd->targets_count - * sizeof(vertex_eosd) * 6); + float tex_w = osd->texture.tex_w; + float tex_h = osd->texture.tex_h; - if (need_upload) { - struct eosd_rect rc; - eosd_packer_calculate_source_bb(priv->eosd, &rc); - RECT dirty_rc = { rc.x0, rc.y0, rc.x1, rc.y1 }; + for (int n = 0; n < osd->packer->count; n++) { + struct sub_bitmap *b = &imgs->parts[n]; + struct pos p = osd->packer->result[n]; - D3DLOCKED_RECT locked_rect; + D3DCOLOR color = imgs->format == SUBBITMAP_LIBASS + ? ass_to_d3d_color(b->libass.color) + : D3DCOLOR_ARGB(255, 255, 255, 255); - if (FAILED(IDirect3DTexture9_LockRect(priv->texture_eosd.system, 0, - &locked_rect, &dirty_rc, 0))) - { - mp_msg(MSGT_VO,MSGL_ERR, "EOSD texture lock failed.\n"); - return; + float x0 = b->x; + float y0 = b->y; + float x1 = b->x + b->dw; + float y1 = b->y + b->dh; + float tx0 = p.x / tex_w; + float ty0 = p.y / tex_h; + float tx1 = (p.x + b->w) / tex_w; + float ty1 = (p.y + b->h) / tex_h; + + vertex_eosd *v = &osd->vertices[n * 6]; + v[0] = (vertex_eosd) { x0, y0, 0, color, tx0, ty0 }; + v[1] = (vertex_eosd) { x1, y0, 0, color, tx1, ty0 }; + v[2] = (vertex_eosd) { x0, y1, 0, color, tx0, ty1 }; + v[3] = (vertex_eosd) { x1, y1, 0, color, tx1, ty1 }; + v[4] = v[2]; + v[5] = v[1]; } - - //memset(locked_rect.pBits, 0, locked_rect.Pitch * priv->texture_eosd.tex_h); - - for (int i = 0; i < priv->eosd->targets_count; i++) { - struct eosd_target *target = &priv->eosd->targets[i]; - ASS_Image *img = target->ass_img; - char *src = img->bitmap; - char *dst = (char*)locked_rect.pBits + target->source.x0 - + locked_rect.Pitch * target->source.y0; - for (int y = 0; y < img->h; y++) { - memcpy(dst, src, img->w); - src += img->stride; - dst += locked_rect.Pitch; - } - } - - if (FAILED(IDirect3DTexture9_UnlockRect(priv->texture_eosd.system, 0))) { - mp_msg(MSGT_VO,MSGL_ERR, "EOSD texture unlock failed.\n"); - return; - } - - d3dtex_update(priv, &priv->texture_eosd); } - float eosd_w = priv->texture_eosd.tex_w; - float eosd_h = priv->texture_eosd.tex_h; - - for (int i = 0; i < priv->eosd->targets_count; i++) { - struct eosd_target *target = &priv->eosd->targets[i]; - - D3DCOLOR color = ass_to_d3d_color(target->ass_img->color); - - float x0 = target->dest.x0; - float y0 = target->dest.y0; - float x1 = target->dest.x1; - float y1 = target->dest.y1; - float tx0 = target->source.x0 / eosd_w; - float ty0 = target->source.y0 / eosd_h; - float tx1 = target->source.x1 / eosd_w; - float ty1 = target->source.y1 / eosd_h; - - vertex_eosd *v = &priv->eosd_vb[i*6]; - v[0] = (vertex_eosd) { x0, y0, 0, color, tx0, ty0 }; - v[1] = (vertex_eosd) { x1, y0, 0, color, tx1, ty0 }; - v[2] = (vertex_eosd) { x0, y1, 0, color, tx0, ty1 }; - v[3] = (vertex_eosd) { x1, y1, 0, color, tx1, ty1 }; - v[4] = v[2]; - v[5] = v[1]; - } -} - -static void draw_eosd(d3d_priv *priv) -{ - if (!priv->d3d_device) - return; - - if (!priv->eosd->targets_count) - return; - d3d_begin_scene(priv); IDirect3DDevice9_SetRenderState(priv->d3d_device, D3DRS_ALPHABLENDENABLE, TRUE); IDirect3DDevice9_SetTexture(priv->d3d_device, 0, - d3dtex_get_render_texture(priv, &priv->texture_eosd)); + d3dtex_get_render_texture(priv, &osd->texture)); - // do not use the color value from the A8 texture, because that is black - IDirect3DDevice9_SetRenderState(priv->d3d_device,D3DRS_TEXTUREFACTOR, - 0xFFFFFFFF); - IDirect3DDevice9_SetTextureStageState(priv->d3d_device,0, - D3DTSS_COLORARG1, D3DTA_TFACTOR); + if (imgs->format == SUBBITMAP_LIBASS) { + // do not use the color value from the A8 texture, because that is black + IDirect3DDevice9_SetRenderState(priv->d3d_device,D3DRS_TEXTUREFACTOR, + 0xFFFFFFFF); + IDirect3DDevice9_SetTextureStageState(priv->d3d_device,0, + D3DTSS_COLORARG1, D3DTA_TFACTOR); - IDirect3DDevice9_SetTextureStageState(priv->d3d_device, 0, - D3DTSS_ALPHAOP, D3DTOP_MODULATE); + IDirect3DDevice9_SetTextureStageState(priv->d3d_device, 0, + D3DTSS_ALPHAOP, D3DTOP_MODULATE); + } IDirect3DDevice9_SetFVF(priv->d3d_device, D3DFVF_EOSD_VERTEX); IDirect3DDevice9_DrawPrimitiveUP(priv->d3d_device, D3DPT_TRIANGLELIST, - priv->eosd->targets_count * 2, - priv->eosd_vb, sizeof(vertex_eosd)); + osd->num_vertices / 3, + osd->vertices, sizeof(vertex_eosd)); IDirect3DDevice9_SetTextureStageState(priv->d3d_device,0, D3DTSS_COLORARG1, D3DTA_TEXTURE); @@ -2225,7 +2083,7 @@ const struct vo_driver video_out_direct3d = { .config = config, .control = control, .draw_slice = draw_slice, - .draw_osd = draw_osd, + .draw_osd = draw_osd_with_eosd, .flip_page = flip_page, .check_events = check_events, .uninit = uninit, @@ -2243,7 +2101,7 @@ const struct vo_driver video_out_direct3d_shaders = { .config = config, .control = control, .draw_slice = draw_slice, - .draw_osd = draw_osd, + .draw_osd = draw_osd_with_eosd, .flip_page = flip_page, .check_events = check_events, .uninit = uninit, From 2db0d229efc1ba53e33bb3c110ec591246f0c83a Mon Sep 17 00:00:00 2001 From: wm4 Date: Thu, 4 Oct 2012 17:16:24 +0200 Subject: [PATCH 21/83] libvo: remove eosd_packer.c This contains about the same code as bitmap_packer.c. eosd_packer.c was added first, and then not merged for a year - then it was added as bitmap_packer.c with slightly different and incompatible interface. Now replacing eosd_packer.c with bitmap_packer.c is finally done. So much wasted work... --- Makefile | 1 - libvo/eosd_packer.c | 255 -------------------------------------------- libvo/eosd_packer.h | 74 ------------- 3 files changed, 330 deletions(-) delete mode 100644 libvo/eosd_packer.c delete mode 100644 libvo/eosd_packer.h diff --git a/Makefile b/Makefile index 9c782e27fe..1bfccf04ea 100644 --- a/Makefile +++ b/Makefile @@ -247,7 +247,6 @@ SRCS_COMMON = asxparser.c \ libmpdemux/mp_taglists.c \ libmpdemux/video.c \ libvo/osd.c \ - libvo/eosd_packer.c \ libvo/bitmap_packer.c \ osdep/numcores.c \ osdep/io.c \ diff --git a/libvo/eosd_packer.c b/libvo/eosd_packer.c deleted file mode 100644 index 8f831d512e..0000000000 --- a/libvo/eosd_packer.c +++ /dev/null @@ -1,255 +0,0 @@ -/* - * Common code for packing EOSD images into larger surfaces. - * - * This file is part of mplayer2. - * - * mplayer2 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. - * - * mplayer2 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 mplayer2; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include -#include "talloc.h" -#include "mp_msg.h" -#include "eosd_packer.h" - -// Initial size of EOSD surface in pixels (x*x) -#define EOSD_SURFACE_INITIAL_SIZE 256 - -// Allocate an eosd_packer, which can be used to layout and cache the list of -// EOSD images contained in a mp_eosd_images_t into a flat surface. -// It can be free'd with talloc_free(). -// Don't forget to call eosd_init() before using it. -struct eosd_packer *eosd_packer_create(void *talloc_ctx) { - return talloc_zero(talloc_ctx, struct eosd_packer); -} - -// Call this when you need to completely reinitialize the EOSD state, e.g. when -// when your EOSD surface was deleted. -// max_width and max_height are the maximum surface sizes that should be -// allowed. -void eosd_packer_reinit(struct eosd_packer *state, uint32_t max_width, - uint32_t max_height) -{ - state->max_surface_width = max_width; - state->max_surface_height = max_height; - state->surface.w = 0; - state->surface.h = 0; - state->targets_count = 0; -} - -#define HEIGHT_SORT_BITS 4 -static int size_index(struct eosd_target *r) -{ - unsigned int h = r->source.y1; - int n = av_log2_16bit(h); - return (n << HEIGHT_SORT_BITS) - + (- 1 - (h << HEIGHT_SORT_BITS >> n) & (1 << HEIGHT_SORT_BITS) - 1); -} - -/* Pack the given rectangles into an area of size w * h. - * The size of each rectangle is read from .source.x1/.source.y1. - * The height of each rectangle must be at least 1 and less than 65536. - * The .source rectangle is then set corresponding to the packed position. - * 'scratch' must point to work memory for num_rects+16 ints. - * Return 0 on success, -1 if the rectangles did not fit in w*h. - * - * The rectangles are placed in rows in order approximately sorted by - * height (the approximate sorting is simpler than a full one would be, - * and allows the algorithm to work in linear time). Additionally, to - * reduce wasted space when there are a few tall rectangles, empty - * lower-right parts of rows are filled recursively when the size of - * rectangles in the row drops past a power-of-two threshold. So if a - * row starts with rectangles of size 3x50, 10x40 and 5x20 then the - * free rectangle with corners (13, 20)-(w, 50) is filled recursively. - */ -static int pack_rectangles(struct eosd_target *rects, int num_rects, - int w, int h, int *scratch) -{ - int bins[16 << HEIGHT_SORT_BITS]; - int sizes[16 << HEIGHT_SORT_BITS] = {}; - for (int i = 0; i < num_rects; i++) - sizes[size_index(rects + i)]++; - int idx = 0; - for (int i = 0; i < 16 << HEIGHT_SORT_BITS; i += 1 << HEIGHT_SORT_BITS) { - for (int j = 0; j < 1 << HEIGHT_SORT_BITS; j++) { - bins[i + j] = idx; - idx += sizes[i + j]; - } - scratch[idx++] = -1; - } - for (int i = 0; i < num_rects; i++) - scratch[bins[size_index(rects + i)]++] = i; - for (int i = 0; i < 16; i++) - bins[i] = bins[i << HEIGHT_SORT_BITS] - sizes[i << HEIGHT_SORT_BITS]; - struct { - int size, x, bottom; - } stack[16] = {{15, 0, h}}, s = {}; - int stackpos = 1; - int y; - while (stackpos) { - y = s.bottom; - s = stack[--stackpos]; - s.size++; - while (s.size--) { - int maxy = -1; - int obj; - while ((obj = scratch[bins[s.size]]) >= 0) { - int bottom = y + rects[obj].source.y1; - if (bottom > s.bottom) - break; - int right = s.x + rects[obj].source.x1; - if (right > w) - break; - bins[s.size]++; - rects[obj].source.x0 = s.x; - rects[obj].source.x1 += s.x; - rects[obj].source.y0 = y; - rects[obj].source.y1 += y; - num_rects--; - if (maxy <= 0) - stack[stackpos++] = s; - s.x = right; - maxy = FFMAX(maxy, bottom); - } - if (maxy > 0) - s.bottom = maxy; - } - } - return num_rects ? -1 : 0; -} - -// padding to reduce interpolation artifacts when doing scaling & filtering -#define EOSD_PADDING 0 - -// Release all previous images, and packs the images in imgs into state. The -// caller must check the change variables: -// *out_need_reposition == true: sub-image positions changed -// *out_need_upload == true: upload all sub-images again -// *out_need_reallocate == true: resize the EOSD texture to state->surface.w/h -// Logical implications: need_reallocate => need_upload => need_reposition -void eosd_packer_generate(struct eosd_packer *state, mp_eosd_images_t *imgs, - bool *out_need_reposition, bool *out_need_upload, - bool *out_need_reallocate) -{ - int i; - ASS_Image *img = imgs->imgs; - ASS_Image *p; - struct eosd_surface *sfc = &state->surface; - - *out_need_reposition = imgs->bitmap_pos_id != state->last_bitmap_pos_id; - *out_need_upload = imgs->bitmap_id != state->last_bitmap_id; - *out_need_reallocate = false; - - state->last_bitmap_pos_id = imgs->bitmap_pos_id; - state->last_bitmap_id = imgs->bitmap_id; - - // eosd_reinit() was probably called, force full reupload. - if (state->targets_count == 0 && img) - *out_need_upload = true; - - if (!(*out_need_reposition) && !(*out_need_upload)) - return; // Nothing changed, no need to redraw - - state->targets_count = 0; - - *out_need_reposition = true; - - if (!img) - return; // There's nothing to render! - - if (!(*out_need_upload)) - goto eosd_skip_upload; - - *out_need_upload = true; - while (1) { - for (p = img, i = 0; p; p = p->next) { - if (p->w <= 0 || p->h <= 0) - continue; - // Allocate new space for surface/target arrays - if (i >= state->targets_size) { - state->targets_size = FFMAX(state->targets_size * 2, 512); - state->targets = - talloc_realloc_size(state, state->targets, - state->targets_size - * sizeof(*state->targets)); - state->scratch = - talloc_realloc_size(state, state->scratch, - (state->targets_size + 16) - * sizeof(*state->scratch)); - } - state->targets[i].source.x1 = p->w + EOSD_PADDING; - state->targets[i].source.y1 = p->h + EOSD_PADDING; - i++; - } - if (pack_rectangles(state->targets, i, sfc->w, sfc->h, - state->scratch) >= 0) - break; - int w = FFMIN(FFMAX(sfc->w * 2, EOSD_SURFACE_INITIAL_SIZE), - state->max_surface_width); - int h = FFMIN(FFMAX(sfc->h * 2, EOSD_SURFACE_INITIAL_SIZE), - state->max_surface_height); - if (w == sfc->w && h == sfc->h) { - mp_msg(MSGT_VO, MSGL_ERR, "[eosd] EOSD bitmaps do not fit on " - "a surface with the maximum supported size\n"); - return; - } - sfc->w = w; - sfc->h = h; - *out_need_reallocate = true; - } - if (*out_need_reallocate) { - mp_msg(MSGT_VO, MSGL_V, "[eosd] Allocate a %dx%d surface for " - "EOSD bitmaps.\n", sfc->w, sfc->h); - } - -eosd_skip_upload: - for (p = img; p; p = p->next) { - if (p->w <= 0 || p->h <= 0) - continue; - struct eosd_target *target = &state->targets[state->targets_count]; - target->source.x1 -= EOSD_PADDING; - target->source.y1 -= EOSD_PADDING; - target->dest.x0 = p->dst_x; - target->dest.y0 = p->dst_y; - target->dest.x1 = p->w + p->dst_x; - target->dest.y1 = p->h + p->dst_y; - target->color = p->color; - target->ass_img = p; - state->targets_count++; - } -} - -// Calculate the bounding box of all sub-rectangles in the EOSD surface that -// will be used for EOSD rendering. -// If the bounding box is empty, return false. -bool eosd_packer_calculate_source_bb(struct eosd_packer *state, - struct eosd_rect *out_bb) -{ - struct eosd_rect bb = { state->surface.w, state->surface.h, 0, 0 }; - - for (int n = 0; n < state->targets_count; n++) { - struct eosd_rect s = state->targets[n].source; - bb.x0 = FFMIN(bb.x0, s.x0); - bb.y0 = FFMIN(bb.y0, s.y0); - bb.x1 = FFMAX(bb.x1, s.x1); - bb.y1 = FFMAX(bb.y1, s.y1); - } - - // avoid degenerate bounding box if empty - bb.x0 = FFMIN(bb.x0, bb.x1); - bb.y0 = FFMIN(bb.y0, bb.y1); - - *out_bb = bb; - return state->targets_count > 0; -} diff --git a/libvo/eosd_packer.h b/libvo/eosd_packer.h deleted file mode 100644 index 228057d3c4..0000000000 --- a/libvo/eosd_packer.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * This file is part of mplayer2. - * - * mplayer2 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. - * - * mplayer2 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 mplayer2; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef MPLAYER_EOSD_PACKER_H -#define MPLAYER_EOSD_PACKER_H - -#include -#include - -#include "sub/ass_mp.h" -#include "sub/dec_sub.h" - -// Pool of surfaces -struct eosd_surface { - //void *native_surface; - int w; - int h; -}; - -struct eosd_rect { - int x0, y0, x1, y1; -}; - -// List of surfaces to be rendered -struct eosd_target { - struct eosd_rect source; // position in EOSD surface - struct eosd_rect dest; // position on screen - uint32_t color; // libass-style color of the image - // NOTE: This must not be accessed after you return from your VO's - // VOCTRL_DRAW_EOSD call - libass will free or reuse the associated - // memory. Feel free to set this to NULL to make erroneous accesses to - // this member fail early. - ASS_Image *ass_img; -}; - -struct eosd_packer { - struct eosd_surface surface; - struct eosd_target *targets; - int targets_count; // number of valid elements in targets - int targets_size; // number of allocated elements in targets - - uint32_t max_surface_width; - uint32_t max_surface_height; - - int *scratch; - int last_bitmap_id; - int last_bitmap_pos_id; -}; - -struct eosd_packer *eosd_packer_create(void *talloc_ctx); -void eosd_packer_reinit(struct eosd_packer *state, uint32_t max_width, - uint32_t max_height); -void eosd_packer_generate(struct eosd_packer *state, mp_eosd_images_t *imgs, - bool *out_need_reposition, bool *out_need_upload, - bool *out_need_reallocate); -bool eosd_packer_calculate_source_bb(struct eosd_packer *state, - struct eosd_rect *out_bb); - -#endif /* MPLAYER_EOSD_PACKER_H */ From 34b3a9c5e97dfae87afab64915dec624439eafa6 Mon Sep 17 00:00:00 2001 From: wm4 Date: Thu, 4 Oct 2012 17:16:28 +0200 Subject: [PATCH 22/83] sub, VO: remove vo_osd_resized() function VOs which could render the OSD in window size (as opposed to video size, like vo_xv) and which could cache the OSD called this when the window size changed. This was needed, because VOs used another OSD function to check whether the OSD changed before passing the new window size to the OSD code. This was really just an artifact of OSD change detection, and now that the affected VOs use the new OSD rendering API, it's done automatically. --- command.c | 6 ++++-- libvo/vo_corevideo.m | 2 -- libvo/vo_direct3d.c | 2 -- libvo/vo_gl.c | 1 - libvo/vo_gl3.c | 1 - libvo/vo_vdpau.c | 2 +- sub/sub.c | 8 -------- sub/sub.h | 1 - 8 files changed, 5 insertions(+), 18 deletions(-) diff --git a/command.c b/command.c index 1cffedfd13..5f15cecf62 100644 --- a/command.c +++ b/command.c @@ -1598,7 +1598,8 @@ static int mp_property_sub_scale(m_option_t *prop, int action, void *arg, if (opts->ass_enabled) opts->ass_font_scale = *(float *) arg; text_font_scale_factor = *(float *) arg; - vo_osd_resized(); + vo_osd_changed(OSDTYPE_SUBTITLE); + vo_osd_changed(OSDTYPE_OSD); return M_PROPERTY_OK; case M_PROPERTY_STEP_UP: case M_PROPERTY_STEP_DOWN: @@ -1610,7 +1611,8 @@ static int mp_property_sub_scale(m_option_t *prop, int action, void *arg, text_font_scale_factor += (arg ? *(float *) arg : 0.1) * (action == M_PROPERTY_STEP_UP ? 1.0 : -1.0); M_PROPERTY_CLAMP(prop, text_font_scale_factor); - vo_osd_resized(); + vo_osd_changed(OSDTYPE_SUBTITLE); + vo_osd_changed(OSDTYPE_OSD); return M_PROPERTY_OK; default: if (opts->ass_enabled) diff --git a/libvo/vo_corevideo.m b/libvo/vo_corevideo.m index 1ac6369089..37a16fec5e 100644 --- a/libvo/vo_corevideo.m +++ b/libvo/vo_corevideo.m @@ -91,8 +91,6 @@ static void resize(struct vo *vo, int width, int height) gl->MatrixMode(GL_MODELVIEW); gl->LoadIdentity(); - vo_osd_resized(); - gl->Clear(GL_COLOR_BUFFER_BIT); vo->want_redraw = true; } diff --git a/libvo/vo_direct3d.c b/libvo/vo_direct3d.c index a9bac67e6c..4f16c6a6b1 100644 --- a/libvo/vo_direct3d.c +++ b/libvo/vo_direct3d.c @@ -850,8 +850,6 @@ static bool resize_d3d(d3d_priv *priv) calc_fs_rect(priv); - vo_osd_resized(); - priv->vo->want_redraw = true; return 1; diff --git a/libvo/vo_gl.c b/libvo/vo_gl.c index 1608ea594e..7ad5fe31e3 100644 --- a/libvo/vo_gl.c +++ b/libvo/vo_gl.c @@ -145,7 +145,6 @@ static void resize(struct vo *vo, int x, int y) gl->MatrixMode(GL_MODELVIEW); gl->LoadIdentity(); - vo_osd_resized(); gl->Clear(GL_COLOR_BUFFER_BIT); vo->want_redraw = true; } diff --git a/libvo/vo_gl3.c b/libvo/vo_gl3.c index 934d8f394d..66324281ba 100644 --- a/libvo/vo_gl3.c +++ b/libvo/vo_gl3.c @@ -1210,7 +1210,6 @@ static void resize(struct gl_priv *p) update_window_sized_objects(p); update_all_uniforms(p); - vo_osd_resized(); gl->Clear(GL_COLOR_BUFFER_BIT); vo->want_redraw = true; } diff --git a/libvo/vo_vdpau.c b/libvo/vo_vdpau.c index 64378a9a0c..1e587810ac 100644 --- a/libvo/vo_vdpau.c +++ b/libvo/vo_vdpau.c @@ -385,7 +385,7 @@ static void resize(struct vo *vo) vc->src_rect_vid.y1 = vc->flip ? src_rect.top : src_rect.bottom; vc->border_x = borders.left; vc->border_y = borders.top; - vo_osd_resized(); + int flip_offset_ms = vo_fs ? vc->flip_offset_fs : vc->flip_offset_window; vo->flip_queue_offset = flip_offset_ms / 1000.; diff --git a/sub/sub.c b/sub/sub.c index 8e80730b9a..fb1c76c91d 100644 --- a/sub/sub.c +++ b/sub/sub.c @@ -301,14 +301,6 @@ void vo_osd_reset_changed(void) osd->objs[n]->force_redraw = false; } -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; -} - bool sub_bitmaps_bb(struct sub_bitmaps *imgs, int *x1, int *y1, int *x2, int *y2) { diff --git a/sub/sub.h b/sub/sub.h index 92ac19eb52..badc21d7a6 100644 --- a/sub/sub.h +++ b/sub/sub.h @@ -169,7 +169,6 @@ 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); void osd_free(struct osd_state *osd); bool sub_bitmaps_bb(struct sub_bitmaps *imgs, int *x1, int *y1, From 17f5019b468d5269408b7dae53a24e17426de7d5 Mon Sep 17 00:00:00 2001 From: wm4 Date: Thu, 4 Oct 2012 17:16:32 +0200 Subject: [PATCH 23/83] sub: always go through sub.c for OSD rendering Before this commit, vf_vo.c and vf_ass.c were manually calling the subtitle decoder to retrieve images to render. In particular, this circumvented the sub-bitmap conversion & caching layer in sub.c. Change this so that subtitle decoding isn't special anymore, and draws all subtitles with the normal OSD drawing API. This is also a step towards removing the need for vf_ass auto-insertion. In fact, if auto-insertion would be disabled now, VOs with "old" OSD rendering could still render ASS subtitles in monochrome, because there is still ASS -> old-OSD bitmap conversion in the sub.c mechanism. The code is written with the assumption that the subtitle rendering filter (vf_ass) can render all subtitle formats. Since vf_ass knows the ASS format only, rendering image subs (i.e. RGBA subs) with it simply fails. This means that with vo_xv (vf_ass auto-inserted), image subs wouldn't be rendered. Use a dumb hack to disable rendering subs with a filter, if we detect that the subs are not in ASS format. (Trying to render the subs first would probably result in purging the conversion cache on every frame.) --- libmpcodecs/vf.h | 3 +- libmpcodecs/vf_ass.c | 30 +++++++-------- libmpcodecs/vf_vo.c | 16 -------- mplayer.c | 19 ++++------ sub/dec_sub.h | 9 +++++ sub/sub.c | 89 ++++++++++++++++++++++++++++++++++++++++---- sub/sub.h | 14 ++++++- 7 files changed, 124 insertions(+), 56 deletions(-) diff --git a/libmpcodecs/vf.h b/libmpcodecs/vf.h index ec8144b22f..8b18470e62 100644 --- a/libmpcodecs/vf.h +++ b/libmpcodecs/vf.h @@ -104,8 +104,7 @@ struct vf_ctrl_screenshot { #define VFCTRL_SKIP_NEXT_FRAME 12 // For encoding - drop the next frame that passes thru #define VFCTRL_FLUSH_FRAMES 13 // For encoding - flush delayed frames #define VFCTRL_SCREENSHOT 14 // Take screenshot, arg is vf_ctrl_screenshot -#define VFCTRL_INIT_EOSD 15 // Select EOSD renderer -#define VFCTRL_DRAW_EOSD 16 // Render EOSD */ +#define VFCTRL_INIT_OSD 15 // Filter OSD renderer present? #define VFCTRL_SET_DEINTERLACE 18 // Set deinterlacing status #define VFCTRL_GET_DEINTERLACE 19 // Get deinterlacing status /* Hack to make the OSD state object available to vf_expand and vf_ass which diff --git a/libmpcodecs/vf_ass.c b/libmpcodecs/vf_ass.c index f0b2e6ab77..937912313b 100644 --- a/libmpcodecs/vf_ass.c +++ b/libmpcodecs/vf_ass.c @@ -355,23 +355,23 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts) struct vf_priv_s *priv = vf->priv; struct MPOpts *opts = vf->opts; struct osd_state *osd = priv->osd; - ASS_Image *images = 0; + struct sub_bitmaps imgs = (struct sub_bitmaps) {0}; if (pts != MP_NOPTS_VALUE) { - osd->dim = (struct mp_eosd_res){ .w = vf->priv->outw, - .h = vf->priv->outh, - .mt = opts->ass_top_margin, - .mb = opts->ass_bottom_margin }; - osd->normal_scale = vf->priv->aspect_correction; - osd->vsfilter_scale = 1; - osd->sub_pts = pts - osd->sub_offset; - osd->support_rgba = false; - struct sub_bitmaps b; - sub_get_bitmaps(osd, &b); - images = b.imgs; + struct sub_render_params subparams = { + .pts = pts, + .dim = { .w = vf->priv->outw, + .h = vf->priv->outh, + .mt = opts->ass_top_margin, + .mb = opts->ass_bottom_margin }, + .normal_scale = vf->priv->aspect_correction, + .vsfilter_scale = 1, + }; + bool formats[SUBBITMAP_COUNT] = {[SUBBITMAP_LIBASS] = true}; + osd_draw_sub(osd, &imgs, &subparams, formats); } prepare_image(vf, mpi); - render_frame(vf, mpi, images); + render_frame(vf, mpi, imgs.imgs); return vf_next_put_image(vf, vf->dmpi, pts); } @@ -393,9 +393,7 @@ static int control(vf_instance_t *vf, int request, void *data) case VFCTRL_SET_OSD_OBJ: vf->priv->osd = data; break; - case VFCTRL_INIT_EOSD: - return CONTROL_TRUE; - case VFCTRL_DRAW_EOSD: + case VFCTRL_INIT_OSD: return CONTROL_TRUE; } return vf_next_control(vf, request, data); diff --git a/libmpcodecs/vf_vo.c b/libmpcodecs/vf_vo.c index 49668d4640..998b4b6dfa 100644 --- a/libmpcodecs/vf_vo.c +++ b/libmpcodecs/vf_vo.c @@ -34,7 +34,6 @@ struct vf_priv_s { struct vo *vo; - double scale_ratio; }; #define video_out (vf->priv->vo) @@ -74,8 +73,6 @@ static int config(struct vf_instance *vf, if (vo_config(video_out, width, height, d_width, d_height, flags, outfmt)) return 0; - vf->priv->scale_ratio = (double) d_width / d_height * height / width; - return 1; } @@ -117,19 +114,6 @@ static int control(struct vf_instance *vf, int request, void *data) }; return vo_control(video_out, VOCTRL_GET_EQUALIZER, ¶m) == VO_TRUE; } - case VFCTRL_DRAW_EOSD: { - struct osd_state *osd = data; - osd->support_rgba = vf->default_caps & VFCAP_EOSD_RGBA; - osd->dim = (struct mp_eosd_res){0}; - if (!video_out->config_ok || - vo_control(video_out, VOCTRL_GET_EOSD_RES, &osd->dim) != true) - return CONTROL_FALSE; - osd->normal_scale = 1; - osd->vsfilter_scale = vf->priv->scale_ratio; - struct sub_bitmaps images; - sub_get_bitmaps(osd, &images); - return vo_control(video_out, VOCTRL_DRAW_EOSD, &images) == VO_TRUE; - } } return CONTROL_UNKNOWN; } diff --git a/mplayer.c b/mplayer.c index a885fac8ca..ebf911cb54 100644 --- a/mplayer.c +++ b/mplayer.c @@ -2397,9 +2397,9 @@ int reinit_video_chain(struct MPContext *mpctx) sh_video->vfilter = append_filters(sh_video->vfilter, opts->vf_settings); - if (opts->ass_enabled) - sh_video->vfilter->control(sh_video->vfilter, VFCTRL_INIT_EOSD, - mpctx->ass_library); + struct vf_instance *vf = sh_video->vfilter; + mpctx->osd->render_subs_in_filter + = vf->control(vf, VFCTRL_INIT_OSD, NULL) == VO_TRUE; init_best_video_codec(sh_video, video_codec_list, video_fm_list); @@ -2644,12 +2644,10 @@ static int redraw_osd(struct MPContext *mpctx) struct vf_instance *vf = sh_video->vfilter; if (vo_redraw_frame(mpctx->video_out) < 0) return -1; - mpctx->osd->sub_pts = mpctx->video_pts; - if (mpctx->osd->sub_pts != MP_NOPTS_VALUE) - mpctx->osd->sub_pts += sub_delay - mpctx->osd->sub_offset; + mpctx->osd->vo_sub_pts = mpctx->video_pts; - if (!(sh_video->output_flags & VFCAP_EOSD_FILTER)) - vf->control(vf, VFCTRL_DRAW_EOSD, mpctx->osd); + // NOTE: probably should use VO ctrl directly, and/or check if a filter does + // OSD rendering (a filter can't redraw anything here) vf->control(vf, VFCTRL_DRAW_OSD, mpctx->osd); vo_osd_reset_changed(); vo_flip_page(mpctx->video_out, 0, -1); @@ -3257,10 +3255,7 @@ static void run_playloop(struct MPContext *mpctx) update_subtitles(mpctx, sh_video->pts); update_osd_msg(mpctx); struct vf_instance *vf = sh_video->vfilter; - mpctx->osd->sub_pts = mpctx->video_pts; - if (mpctx->osd->sub_pts != MP_NOPTS_VALUE) - mpctx->osd->sub_pts += sub_delay - mpctx->osd->sub_offset; - vf->control(vf, VFCTRL_DRAW_EOSD, mpctx->osd); + mpctx->osd->vo_sub_pts = mpctx->video_pts; vf->control(vf, VFCTRL_DRAW_OSD, mpctx->osd); vo_osd_reset_changed(); diff --git a/sub/dec_sub.h b/sub/dec_sub.h index 9c75506c4c..7ccf513438 100644 --- a/sub/dec_sub.h +++ b/sub/dec_sub.h @@ -60,6 +60,15 @@ typedef struct sub_bitmaps { int bitmap_id, bitmap_pos_id; } mp_eosd_images_t; +struct sub_render_params { + double pts; + struct mp_eosd_res dim; + double normal_scale; + double vsfilter_scale; + + bool support_rgba; +}; + static inline bool is_text_sub(int type) { return type == 't' || type == 'm' || type == 'a'; diff --git a/sub/sub.c b/sub/sub.c index fb1c76c91d..64dba7df20 100644 --- a/sub/sub.c +++ b/sub/sub.c @@ -114,6 +114,7 @@ struct osd_state *osd_create(struct MPOpts *opts, struct ass_library *asslib) .osd_text = talloc_strdup(osd, ""), .progbar_type = -1, }; + for (int n = 0; n < MAX_OSD_PARTS; n++) { struct osd_object *obj = talloc_struct(osd, struct osd_object, { .type = n, @@ -122,6 +123,11 @@ struct osd_state *osd_create(struct MPOpts *opts, struct ass_library *asslib) obj->cache[i] = talloc_steal(obj, osd_conv_cache_new()); osd->objs[n] = obj; } + + // OSDTYPE_SPU is an odd case, because vf_ass.c can't render it. + osd->objs[OSDTYPE_SUB]->is_sub = true; // dec_sub.c + osd->objs[OSDTYPE_SUBTITLE]->is_sub = true; // osd_libass.c + osd_init_backend(osd); global_osd = osd; return osd; @@ -157,6 +163,7 @@ static bool spu_visible(struct osd_state *osd, struct osd_object *obj) // 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, + struct sub_render_params *sub_params, const bool formats[SUBBITMAP_COUNT]) { memset(out_imgs, 0x55, sizeof(*out_imgs)); @@ -170,6 +177,19 @@ static bool render_object(struct osd_state *osd, struct osd_object *obj, out_imgs->bitmap_id++; out_imgs->bitmap_pos_id++; } + } else if (obj->type == OSDTYPE_SUB) { + double pts = sub_params->pts; + if (pts != MP_NOPTS_VALUE) + pts += sub_delay - osd->sub_offset; + + // passing the parameters is a big temporary hack + osd->sub_pts = pts; + osd->dim = sub_params->dim; + osd->normal_scale = sub_params->normal_scale; + osd->vsfilter_scale = sub_params->vsfilter_scale; + osd->support_rgba = formats[SUBBITMAP_RGBA]; + + sub_get_bitmaps(osd, out_imgs); } else { osd_object_get_bitmaps(osd, obj, out_imgs); } @@ -216,13 +236,46 @@ static bool render_object(struct osd_state *osd, struct osd_object *obj, if (cached) obj->cached = *out_imgs; - return formats[out_imgs->format]; + if (!formats[out_imgs->format]) { + mp_msg(MSGT_OSD, MSGL_ERR, "Can't render OSD part %d (format %d).\n", + obj->type, out_imgs->format); + return false; + } + return true; +} + +// This is a hack to render the first subtitle OSD object, which is not empty. +// It's a hack because it's really only useful for subtitles: normal OSD can +// have multiple objects, and rendering one object may invalidate data of a +// previously rendered, different object (that's how osd_libass.c works). +// Also, it assumes this is called from a filter: it disables VO rendering of +// subtitles, because we don't want to render both. +bool osd_draw_sub(struct osd_state *osd, struct sub_bitmaps *out_imgs, + struct sub_render_params *sub_params, + const bool formats[SUBBITMAP_COUNT]) +{ + *out_imgs = (struct sub_bitmaps) {0}; + for (int n = 0; n < MAX_OSD_PARTS; n++) { + struct osd_object *obj = osd->objs[n]; + if (obj->is_sub) { + // hack to allow rendering non-ASS subs with vf_ass inserted + // (vf_ass is auto-inserted if VOs don't support EOSD) +#ifdef CONFIG_ASS + osd->render_subs_in_filter = !!sub_get_ass_track(osd); + if (!osd->render_subs_in_filter) + return false; +#endif + if (render_object(osd, obj, out_imgs, sub_params, formats)) + return true; + } + } + return false; } 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) + mp_eosd_res_t dim = {0}; + if (vo_control(vo, VOCTRL_GET_EOSD_RES, &dim) != VO_TRUE) return; bool formats[SUBBITMAP_COUNT]; @@ -231,12 +284,24 @@ void draw_osd_with_eosd(struct vo *vo, struct osd_state *osd) formats[n] = vo_control(vo, VOCTRL_QUERY_EOSD_FORMAT, &data) == VO_TRUE; } - osd_update_ext(osd, res); + osd_update_ext(osd, dim); + + struct aspect_data asp = vo->aspdat; + + struct sub_render_params subparams = { + .pts = osd->vo_sub_pts, + .dim = dim, + .normal_scale = 1, + .vsfilter_scale = (double) asp.prew / asp.preh * asp.orgh / asp.orgw, + .support_rgba = formats[SUBBITMAP_RGBA], + }; for (int n = 0; n < MAX_OSD_PARTS; n++) { struct osd_object *obj = osd->objs[n]; + if (obj->is_sub && osd->render_subs_in_filter) + continue; struct sub_bitmaps imgs; - if (render_object(osd, obj, &imgs, formats)) + if (render_object(osd, obj, &imgs, &subparams, formats)) vo_control(vo, VOCTRL_DRAW_EOSD, &imgs); } } @@ -249,14 +314,22 @@ void osd_draw_text_ext(struct osd_state *osd, int w, int h, int stride), void *ctx) { - struct mp_eosd_res res = + struct mp_eosd_res dim = {.w = w, .h = h, .ml = ml, .mt = mt, .mr = mr, .mb = mb}; - osd_update_ext(osd, res); + osd_update_ext(osd, dim); + struct sub_render_params subparams = { + .pts = osd->vo_sub_pts, + .dim = dim, + .normal_scale = 1, + .vsfilter_scale = 1, // unknown + }; for (int n = 0; n < MAX_OSD_PARTS; n++) { struct osd_object *obj = osd->objs[n]; + if (obj->is_sub && osd->render_subs_in_filter) + continue; struct sub_bitmaps imgs; bool formats[SUBBITMAP_COUNT] = {[SUBBITMAP_OLD_PLANAR] = true}; - if (render_object(osd, obj, &imgs, formats)) { + if (render_object(osd, obj, &imgs, &subparams, formats)) { assert(imgs.num_parts == 1); struct sub_bitmap *part = &imgs.parts[0]; struct old_osd_planar *bmp = part->bitmap; diff --git a/sub/sub.h b/sub/sub.h index badc21d7a6..4f055558e9 100644 --- a/sub/sub.h +++ b/sub/sub.h @@ -27,7 +27,7 @@ struct vo; enum mp_osdtype { - OSDTYPE_ASS, + OSDTYPE_SUB, OSDTYPE_OSD, OSDTYPE_SUBTITLE, OSDTYPE_PROGBAR, @@ -40,6 +40,8 @@ enum mp_osdtype { struct osd_object { int type; // OSDTYPE_* + bool is_sub; + bool force_redraw; // caches for OSD conversion (internal to render_object()) @@ -62,13 +64,17 @@ struct osd_state { struct ass_library *ass_library; struct ass_renderer *ass_renderer; struct sh_sub *sh_sub; - double sub_pts; double sub_offset; + double vo_sub_pts; + + double sub_pts; struct mp_eosd_res dim; double normal_scale; double vsfilter_scale; bool support_rgba; + bool render_subs_in_filter; + int w, h; char *osd_text; // OSDTYPE_OSD @@ -171,6 +177,10 @@ void vo_osd_reset_changed(void); bool vo_osd_has_changed(struct osd_state *osd); void osd_free(struct osd_state *osd); +bool osd_draw_sub(struct osd_state *osd, struct sub_bitmaps *out_imgs, + struct sub_render_params *sub_params, + const bool formats[SUBBITMAP_COUNT]); + bool sub_bitmaps_bb(struct sub_bitmaps *imgs, int *x1, int *y1, int *x2, int *y2); From 05f4f00e24caf23646a2b551b8e1a1a1abe76de7 Mon Sep 17 00:00:00 2001 From: wm4 Date: Thu, 4 Oct 2012 17:16:36 +0200 Subject: [PATCH 24/83] sub: cleanup: don't pass parameters via global variables Passing parameters from caller to subtitle renderer was done by temporarily setting certain members in the osd_state struct (which for all practical purposes are as good as global variables). This was the only purpose of these members. Rather than using such a messy way to pass parameter, put these into a struct sub_render_params. The struct was already introduced in earlier commits, and this commit just removes the parameter passing hack. --- sub/dec_sub.c | 28 +++++++++++++++------------- sub/dec_sub.h | 3 ++- sub/sd.h | 2 ++ sub/sd_ass.c | 11 ++++++----- sub/sd_lavc.c | 9 +++++---- sub/sub.c | 15 +++++---------- sub/sub.h | 8 +------- 7 files changed, 36 insertions(+), 40 deletions(-) diff --git a/sub/dec_sub.c b/sub/dec_sub.c index b5ffa81511..87cb9870cb 100644 --- a/sub/dec_sub.c +++ b/sub/dec_sub.c @@ -45,7 +45,7 @@ void sub_init(struct sh_sub *sh, struct osd_state *osd) 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,14 +58,15 @@ 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){ .render_index = 0, - .format = SUBBITMAP_EMPTY, - .bitmap_id = osd->bitmap_id, - .bitmap_pos_id = osd->bitmap_pos_id }; + // temporary hack + osd->support_rgba = params->support_rgba; + + *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 @@ -73,14 +74,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 7ccf513438..442cd870d8 100644 --- a/sub/dec_sub.h +++ b/sub/dec_sub.h @@ -76,7 +76,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/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 8b8ad6c0eb..fca47c557b 100644 --- a/sub/sd_ass.c +++ b/sub/sd_ass.c @@ -127,21 +127,22 @@ static void decode(struct sh_sub *sh, struct osd_state *osd, void *data, } static void get_bitmaps(struct sh_sub *sh, struct osd_state *osd, + struct sub_render_params *params, struct sub_bitmaps *res) { struct sd_ass_priv *ctx = sh->context; struct MPOpts *opts = osd->opts; - if (osd->sub_pts == MP_NOPTS_VALUE) + if (params->pts == MP_NOPTS_VALUE) return; - double scale = osd->normal_scale; + double scale = params->normal_scale; if (ctx->vsfilter_aspect && opts->ass_vsfilter_aspect_compat) - scale = osd->vsfilter_scale; + scale = params->vsfilter_scale; ASS_Renderer *renderer = osd->ass_renderer; - mp_ass_configure(renderer, opts, &osd->dim); + mp_ass_configure(renderer, opts, ¶ms->dim); ass_set_aspect_ratio(renderer, scale, 1); - mp_ass_render_frame(renderer, ctx->ass_track, osd->sub_pts * 1000 + .5, + mp_ass_render_frame(renderer, ctx->ass_track, params->pts * 1000 + .5, &ctx->parts, res); talloc_steal(ctx, ctx->parts); } diff --git a/sub/sd_lavc.c b/sub/sd_lavc.c index b0dde50a00..7f327957dd 100644 --- a/sub/sd_lavc.c +++ b/sub/sd_lavc.c @@ -220,14 +220,15 @@ static void decode(struct sh_sub *sh, struct osd_state *osd, void *data, } static void get_bitmaps(struct sh_sub *sh, struct osd_state *osd, + struct sub_render_params *params, struct sub_bitmaps *res) { struct sd_lavc_priv *priv = sh->context; - if (priv->endpts != MP_NOPTS_VALUE && (osd->sub_pts >= priv->endpts || - osd->sub_pts < priv->endpts - 300)) + if (priv->endpts != MP_NOPTS_VALUE && (params->pts >= priv->endpts || + params->pts < priv->endpts - 300)) clear(priv); - if (!osd->support_rgba) + if (!params->support_rgba) return; if (priv->bitmaps_changed && priv->count > 0) priv->outbitmaps = talloc_memdup(priv, priv->inbitmaps, @@ -236,7 +237,7 @@ static void get_bitmaps(struct sh_sub *sh, struct osd_state *osd, int inw = priv->avctx->width; int inh = priv->avctx->height; guess_resolution(sh->type, &inw, &inh); - struct mp_eosd_res *d = &osd->dim; + struct mp_eosd_res *d = ¶ms->dim; double xscale = (double) (d->w - d->ml - d->mr) / inw; double yscale = (double) (d->h - d->mt - d->mb) / inh; for (int i = 0; i < priv->count; i++) { diff --git a/sub/sub.c b/sub/sub.c index 64dba7df20..600ef6fae1 100644 --- a/sub/sub.c +++ b/sub/sub.c @@ -178,18 +178,13 @@ static bool render_object(struct osd_state *osd, struct osd_object *obj, out_imgs->bitmap_pos_id++; } } else if (obj->type == OSDTYPE_SUB) { - double pts = sub_params->pts; - if (pts != MP_NOPTS_VALUE) - pts += sub_delay - osd->sub_offset; + struct sub_render_params p = *sub_params; + if (p.pts != MP_NOPTS_VALUE) + p.pts += sub_delay - osd->sub_offset; - // passing the parameters is a big temporary hack - osd->sub_pts = pts; - osd->dim = sub_params->dim; - osd->normal_scale = sub_params->normal_scale; - osd->vsfilter_scale = sub_params->vsfilter_scale; - osd->support_rgba = formats[SUBBITMAP_RGBA]; + p.support_rgba = formats[SUBBITMAP_RGBA]; - sub_get_bitmaps(osd, out_imgs); + sub_get_bitmaps(osd, &p, out_imgs); } else { osd_object_get_bitmaps(osd, obj, out_imgs); } diff --git a/sub/sub.h b/sub/sub.h index 4f055558e9..ed3010c1af 100644 --- a/sub/sub.h +++ b/sub/sub.h @@ -67,10 +67,6 @@ struct osd_state { double sub_offset; double vo_sub_pts; - double sub_pts; - struct mp_eosd_res dim; - double normal_scale; - double vsfilter_scale; bool support_rgba; bool render_subs_in_filter; @@ -80,9 +76,7 @@ struct osd_state { char *osd_text; // OSDTYPE_OSD int progbar_type, progbar_value; // OSDTYPE_PROGBAR - // temporary for sub decoders - int bitmap_id; - int bitmap_pos_id; + int switch_sub_id; struct MPOpts *opts; From cc05910f16a5ccd8e3dca26a89e9c3835cbdb645 Mon Sep 17 00:00:00 2001 From: wm4 Date: Thu, 4 Oct 2012 17:16:40 +0200 Subject: [PATCH 25/83] sub: cosmetics: move things around Move sub-bitmap definitions from dec_sub.h to sub.h. While it's a bit odd that OSD data structures are in a file named sub.h, it's definitely way too strange to have them in a file about subtitle decoding. (Maybe sub.h/.c and the sub/ directory should be split out and renamed "osd" at a later point.) Remove including ass_mp.h (and the libass headers) where possible. Remove typedefs for mp_eosd_res and sub_bitmaps structs. Store a mp_eosd_res struct in osd_state instead of just w/h. Note that sbtitles might be rendered using different sizes/margins when filters are involved (the subtitle renderer is not supposed to use the OSD res directly, and the "dim" member removed in the previous commit is something different). --- libmpcodecs/vf_ass.c | 1 + libvo/bitmap_packer.c | 1 - libvo/vo_corevideo.m | 2 +- libvo/vo_gl.c | 3 +-- libvo/vo_gl3.c | 3 +-- libvo/vo_vdpau.c | 5 ++-- sub/dec_sub.h | 56 +++--------------------------------------- sub/osd_libass.c | 4 +-- sub/sd_ass.c | 1 + sub/sd_lavc.c | 1 + sub/sub.c | 14 ++++++----- sub/sub.h | 57 +++++++++++++++++++++++++++++++++++++++++-- 12 files changed, 76 insertions(+), 72 deletions(-) diff --git a/libmpcodecs/vf_ass.c b/libmpcodecs/vf_ass.c index 937912313b..77248b49c0 100644 --- a/libmpcodecs/vf_ass.c +++ b/libmpcodecs/vf_ass.c @@ -35,6 +35,7 @@ #include "mp_image.h" #include "vf.h" #include "sub/sub.h" +#include "sub/dec_sub.h" #include "libvo/fastmemcpy.h" diff --git a/libvo/bitmap_packer.c b/libvo/bitmap_packer.c index 9d3df70c34..603a6ce410 100644 --- a/libvo/bitmap_packer.c +++ b/libvo/bitmap_packer.c @@ -28,7 +28,6 @@ #include "bitmap_packer.h" #include "mp_msg.h" #include "mpcommon.h" -#include "sub/ass_mp.h" #include "sub/dec_sub.h" #include "fastmemcpy.h" diff --git a/libvo/vo_corevideo.m b/libvo/vo_corevideo.m index 37a16fec5e..e5c74f6cc8 100644 --- a/libvo/vo_corevideo.m +++ b/libvo/vo_corevideo.m @@ -333,7 +333,7 @@ static int control(struct vo *vo, uint32_t request, void *data) return mpgl_osd_query_format(p->osd, *(int *)data) ? VO_TRUE : VO_NOTIMPL; case VOCTRL_GET_EOSD_RES: { - mp_eosd_res_t *r = data; + struct mp_eosd_res *r = data; r->w = vo->dwidth; r->h = vo->dheight; r->mt = r->mb = r->ml = r->mr = 0; diff --git a/libvo/vo_gl.c b/libvo/vo_gl.c index 7ad5fe31e3..d41adad6bc 100644 --- a/libvo/vo_gl.c +++ b/libvo/vo_gl.c @@ -42,7 +42,6 @@ #include "gl_osd.h" #include "aspect.h" #include "fastmemcpy.h" -#include "sub/ass_mp.h" //for gl_priv.use_yuv #define MASK_ALL_YUV (~(1 << YUV_CONVERSION_NONE)) @@ -1096,7 +1095,7 @@ static int control(struct vo *vo, uint32_t request, void *data) case VOCTRL_QUERY_EOSD_FORMAT: return mpgl_osd_query_format(p->osd, *(int *)data) ? VO_TRUE : VO_NOTIMPL; case VOCTRL_GET_EOSD_RES: { - mp_eosd_res_t *r = data; + struct mp_eosd_res *r = data; r->w = vo->dwidth; r->h = vo->dheight; r->mt = r->mb = r->ml = r->mr = 0; diff --git a/libvo/vo_gl3.c b/libvo/vo_gl3.c index 66324281ba..f3c1767b78 100644 --- a/libvo/vo_gl3.c +++ b/libvo/vo_gl3.c @@ -54,7 +54,6 @@ #include "filter_kernels.h" #include "aspect.h" #include "fastmemcpy.h" -#include "sub/ass_mp.h" static const char vo_gl3_shaders[] = // Generated from libvo/vo_gl3_shaders.glsl @@ -1689,7 +1688,7 @@ static int control(struct vo *vo, uint32_t request, void *data) draw_eosd(p, data); return VO_TRUE; case VOCTRL_GET_EOSD_RES: { - mp_eosd_res_t *r = data; + struct mp_eosd_res *r = data; r->w = vo->dwidth; r->h = vo->dheight; r->ml = r->mr = p->border_x; diff --git a/libvo/vo_vdpau.c b/libvo/vo_vdpau.c index 1e587810ac..34aa9824dc 100644 --- a/libvo/vo_vdpau.c +++ b/libvo/vo_vdpau.c @@ -51,7 +51,6 @@ #include "libmpcodecs/vfcap.h" #include "libmpcodecs/mp_image.h" #include "osdep/timer.h" -#include "sub/ass_mp.h" #include "bitmap_packer.h" #define WRAP_ADD(x, a, m) ((a) < 0 \ @@ -984,7 +983,7 @@ static void draw_eosd(struct vo *vo, int index) } } -static void generate_eosd(struct vo *vo, mp_eosd_images_t *imgs) +static void generate_eosd(struct vo *vo, struct sub_bitmaps *imgs) { struct vdpctx *vc = vo->priv; struct vdp_functions *vdp = vc->vdp; @@ -1617,7 +1616,7 @@ static int control(struct vo *vo, uint32_t request, void *data) if (!data) return VO_FALSE; if (status_ok(vo)) { - mp_eosd_images_t *imgs = data; + struct sub_bitmaps *imgs = data; generate_eosd(vo, imgs); draw_eosd(vo, imgs->render_index); } diff --git a/sub/dec_sub.h b/sub/dec_sub.h index 442cd870d8..9cfe8d964c 100644 --- a/sub/dec_sub.h +++ b/sub/dec_sub.h @@ -4,61 +4,11 @@ #include #include +#include "sub.h" + struct sh_sub; -struct osd_state; struct ass_track; - -enum sub_bitmap_format { - SUBBITMAP_EMPTY = 0,// no bitmaps; always has num_parts==0 - SUBBITMAP_LIBASS, // A8, with a per-surface blend color (libass.color) - 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) -} mp_eosd_res_t; - -struct sub_bitmap { - void *bitmap; - int stride; - int w, h; - int x, y; - // Note: not clipped, going outside the screen area is allowed - int dw, dh; - - union { - struct { - uint32_t color; - } libass; - }; -}; - -typedef struct sub_bitmaps { - int render_index; // for VO cache state (limited by MAX_OSD_PARTS) - - enum sub_bitmap_format format; - bool scaled; // if false, dw==w && dh==h - - struct sub_bitmap *parts; - int num_parts; - - // Provided for VOs with old code - struct ass_image *imgs; - - // Incremented on each change - int bitmap_id, bitmap_pos_id; -} mp_eosd_images_t; +struct MPOpts *opts; struct sub_render_params { double pts; diff --git a/sub/osd_libass.c b/sub/osd_libass.c index 811bc009f3..f3296c6091 100644 --- a/sub/osd_libass.c +++ b/sub/osd_libass.c @@ -196,7 +196,7 @@ static void update_progbar(struct osd_state *osd, struct osd_object *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; @@ -285,7 +285,7 @@ void osd_object_get_bitmaps(struct osd_state *osd, struct osd_object *obj, if (!obj->osd_track) return; - ass_set_frame_size(osd->osd_render, osd->w, osd->h); + 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_ass.c b/sub/sd_ass.c index fca47c557b..44c91c6fdc 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" diff --git a/sub/sd_lavc.c b/sub/sd_lavc.c index 7f327957dd..a10ac5e18e 100644 --- a/sub/sd_lavc.c +++ b/sub/sd_lavc.c @@ -25,6 +25,7 @@ #include "sd.h" #include "spudec.h" // Current code still pushes subs directly to global spudec +#include "dec_sub.h" #include "sub.h" struct sd_lavc_priv { diff --git a/sub/sub.c b/sub/sub.c index 600ef6fae1..b2d9eb82fc 100644 --- a/sub/sub.c +++ b/sub/sub.c @@ -35,7 +35,7 @@ #include "mp_msg.h" #include "libvo/video_out.h" #include "sub.h" -#include "sub/ass_mp.h" +#include "dec_sub.h" #include "img_convert.h" #include "spudec.h" @@ -92,9 +92,11 @@ static struct osd_state *global_osd; static void osd_update_ext(struct osd_state *osd, struct mp_eosd_res res) { - if (osd->w != res.w || osd->h != res.h) { - osd->w = res.w; - osd->h = res.h; + struct mp_eosd_res old = osd->res; + if (old.w != res.w || old.h != res.h || old.ml != res.ml || old.mt != res.mt + || old.mr != res.mr || old.mb != res.mb) + { + osd->res = res; for (int n = 0; n < MAX_OSD_PARTS; n++) osd->objs[n]->force_redraw = true; } @@ -171,7 +173,7 @@ static bool render_object(struct osd_state *osd, struct osd_object *obj, 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); + spudec_get_bitmap(vo_spudec, osd->res.w, osd->res.h, out_imgs); // Normal change-detection (sub. dec. calls vo_osd_changed(OSDTYPE_SPU)) if (obj->force_redraw) { out_imgs->bitmap_id++; @@ -269,7 +271,7 @@ bool osd_draw_sub(struct osd_state *osd, struct sub_bitmaps *out_imgs, void draw_osd_with_eosd(struct vo *vo, struct osd_state *osd) { - mp_eosd_res_t dim = {0}; + struct mp_eosd_res dim = {0}; if (vo_control(vo, VOCTRL_GET_EOSD_RES, &dim) != VO_TRUE) return; diff --git a/sub/sub.h b/sub/sub.h index ed3010c1af..6a83036460 100644 --- a/sub/sub.h +++ b/sub/sub.h @@ -20,11 +20,64 @@ #define MPLAYER_SUB_H #include +#include #include "subreader.h" -#include "dec_sub.h" struct vo; +struct sub_render_params; + +enum sub_bitmap_format { + SUBBITMAP_EMPTY = 0,// no bitmaps; always has num_parts==0 + SUBBITMAP_LIBASS, // A8, with a per-surface blend color (libass.color) + 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; +}; + +struct sub_bitmap { + void *bitmap; + int stride; + int w, h; + int x, y; + // Note: not clipped, going outside the screen area is allowed + int dw, dh; + + union { + struct { + uint32_t color; + } libass; + }; +}; + +struct sub_bitmaps { + int render_index; // for VO cache state (limited by MAX_OSD_PARTS) + + enum sub_bitmap_format format; + bool scaled; // if false, dw==w && dh==h + + struct sub_bitmap *parts; + int num_parts; + + // Provided for VOs with old code + struct ass_image *imgs; + + // Incremented on each change + int bitmap_id, bitmap_pos_id; +}; + +struct mp_eosd_res { + int w, h; // screen dimensions, including black borders + int mt, mb, ml, mr; // borders (top, bottom, left, right) +}; enum mp_osdtype { OSDTYPE_SUB, @@ -71,7 +124,7 @@ struct osd_state { bool render_subs_in_filter; - int w, h; + struct mp_eosd_res res; char *osd_text; // OSDTYPE_OSD int progbar_type, progbar_value; // OSDTYPE_PROGBAR From 3ad918bbc62449759bbf97f6a809ebdde27ad59e Mon Sep 17 00:00:00 2001 From: wm4 Date: Thu, 4 Oct 2012 17:16:47 +0200 Subject: [PATCH 26/83] sub: never decode subs to old OSD format Instead, sd_lavc.c and spudec.c (the two image sub decoders) always output indexed/paletted images. For this purpose, add SUBBITMAP_INDEXED, and convert the subs to RGBA in img_convert.c instead. If a VO is used that supports the old OSD format only, the indexed bitmaps are converted to the old OSD format by abusing spudec.c in a similar way sd_lavc.c used to do. The main reason why spudec.c is used is because the images must not only be converted to the old format, but also properly scaled, cropped, and aligned (the asm code in libvo/osd.c requires this alignment). Remove support for the old format (packed variant) from the OpenGL VOs. (The packed formats were how the actual OSD format was handled in some GPU-driven VOs for a while.) Remove all conversions from old to new formats. Now all subtitle decoders and OSD renderers produce the new formats only. Add an evil hack to convert the new format (scaled+indexed bitmaps) to the old format. It creates a new spudec instance to convert images to grayscale and to scale them. This is temporary for VOs which don't support new OSD formats yet (vo_xv, vo_x11, vo_lavc). --- libvo/gl_osd.c | 4 -- libvo/vo_gl3.c | 1 - libvo/vo_gl3_shaders.glsl | 11 --- sub/dec_sub.c | 3 - sub/dec_sub.h | 2 - sub/img_convert.c | 138 ++++++++++++++++++++------------------ sub/img_convert.h | 5 +- sub/sd_lavc.c | 90 ++++++------------------- sub/spudec.c | 53 +++++++++++++++ sub/spudec.h | 3 + sub/sub.c | 34 +++++----- sub/sub.h | 24 +++++-- 12 files changed, 187 insertions(+), 181 deletions(-) diff --git a/libvo/gl_osd.c b/libvo/gl_osd.c index ce4bee5c03..74053afd4a 100644 --- a/libvo/gl_osd.c +++ b/libvo/gl_osd.c @@ -33,20 +33,16 @@ struct osd_fmt_entry { static const int blend_factors[SUBBITMAP_COUNT][2] = { [SUBBITMAP_LIBASS] = {GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA}, [SUBBITMAP_RGBA] = {GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA}, - [SUBBITMAP_OLD] = {GL_ONE, GL_ONE_MINUS_SRC_ALPHA}, }; static const struct osd_fmt_entry osd_to_gl3_formats[SUBBITMAP_COUNT] = { [SUBBITMAP_LIBASS] = {GL_RED, GL_RED, GL_UNSIGNED_BYTE}, [SUBBITMAP_RGBA] = {GL_RGBA, GL_BGRA, GL_UNSIGNED_BYTE}, - [SUBBITMAP_OLD] = {GL_RG, GL_RG, GL_UNSIGNED_BYTE}, }; static const struct osd_fmt_entry osd_to_gl_legacy_formats[SUBBITMAP_COUNT] = { [SUBBITMAP_LIBASS] = {GL_ALPHA, GL_ALPHA, GL_UNSIGNED_BYTE}, [SUBBITMAP_RGBA] = {GL_RGBA, GL_BGRA, GL_UNSIGNED_BYTE}, - [SUBBITMAP_OLD] = - {GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE}, }; struct mpgl_osd *mpgl_osd_init(GL *gl, bool legacy) diff --git a/libvo/vo_gl3.c b/libvo/vo_gl3.c index f3c1767b78..f5df6a1ae4 100644 --- a/libvo/vo_gl3.c +++ b/libvo/vo_gl3.c @@ -252,7 +252,6 @@ static const struct fmt_entry mp_to_gl_formats[] = { static const char *osd_shaders[SUBBITMAP_COUNT] = { [SUBBITMAP_LIBASS] = "frag_osd_libass", [SUBBITMAP_RGBA] = "frag_osd_rgba", - [SUBBITMAP_OLD] = "frag_osd_old", }; diff --git a/libvo/vo_gl3_shaders.glsl b/libvo/vo_gl3_shaders.glsl index 20f8c597ad..04d886f9c0 100644 --- a/libvo/vo_gl3_shaders.glsl +++ b/libvo/vo_gl3_shaders.glsl @@ -66,17 +66,6 @@ void main() { out_color = texture(texture1, texcoord); } -#!section frag_osd_old -uniform sampler2D texture1; -uniform vec4 osd_color; - -in vec2 texcoord; -out vec4 out_color; - -void main() { - out_color = texture(texture1, texcoord).rrrg * osd_color; -} - #!section frag_video uniform sampler2D texture1; uniform sampler2D texture2; diff --git a/sub/dec_sub.c b/sub/dec_sub.c index 87cb9870cb..09d9989494 100644 --- a/sub/dec_sub.c +++ b/sub/dec_sub.c @@ -63,9 +63,6 @@ void sub_get_bitmaps(struct osd_state *osd, struct sub_render_params *params, { struct MPOpts *opts = osd->opts; - // temporary hack - osd->support_rgba = params->support_rgba; - *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 diff --git a/sub/dec_sub.h b/sub/dec_sub.h index 9cfe8d964c..0c5c1ab7ee 100644 --- a/sub/dec_sub.h +++ b/sub/dec_sub.h @@ -15,8 +15,6 @@ struct sub_render_params { struct mp_eosd_res dim; double normal_scale; double vsfilter_scale; - - bool support_rgba; }; static inline bool is_text_sub(int type) diff --git a/sub/img_convert.c b/sub/img_convert.c index 6eef4a01a3..b8a769f052 100644 --- a/sub/img_convert.c +++ b/sub/img_convert.c @@ -25,14 +25,16 @@ #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_cache_alloc_bmp() (various other formats) - unsigned char *packed; + // for osd_conv_idx_to_old_p(), a spudec.c handle + void *spudec; }; static int osd_conv_cache_destroy(void *p) @@ -40,6 +42,8 @@ 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; } @@ -73,21 +77,6 @@ static void osd_conv_cache_alloc_old_p(struct osd_conv_cache *c, int w, int h) }; } -static void osd_conv_cache_alloc_bmp(struct osd_conv_cache *c, int w, int h, - int bpp) -{ - size_t size = talloc_get_size(c->packed); - size_t new_size = w * bpp * 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 * bpp, - .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, @@ -177,80 +166,99 @@ bool osd_conv_ass_to_old_p(struct osd_conv_cache *c, struct sub_bitmaps *imgs) return true; } -// SUBBITMAP_OLD_PLANAR -> SUBBITMAP_RGBA -bool osd_conv_old_p_to_rgba(struct osd_conv_cache *c, struct sub_bitmaps *imgs) +bool osd_conv_idx_to_rgba(struct osd_conv_cache *c, struct sub_bitmaps *imgs) { struct sub_bitmaps src = *imgs; - if (src.format != SUBBITMAP_OLD_PLANAR || src.num_parts > 1) + if (src.format != SUBBITMAP_INDEXED) return false; imgs->format = SUBBITMAP_RGBA; - imgs->num_parts = 0; - imgs->parts = NULL; + talloc_free(c->parts); + imgs->parts = c->parts = talloc_array(c, struct sub_bitmap, src.num_parts); - if (src.num_parts == 0) - return true; + 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 = s->bitmap; - struct sub_bitmap *s = &src.parts[0]; - struct old_osd_planar *p = s->bitmap; + *d = *s; + d->stride = s->w * 4; + d->bitmap = talloc_size(c->parts, s->h * d->stride); - osd_conv_cache_alloc_bmp(c, s->w, s->h, 4); - - 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 * 4; - for (int x = 0; x < s->w; x++) { - // This is incorrect, as input is premultiplied alpha, but output - // has to be non-premultiplied. However, this code is for - // compatibility with spudec.c only, and DVD subtitles have - // binary transparency only - the rendered result will be the same. - cur[x*4+0] = cur[x*4+1] = cur[x*4+2] = y_src[x]; - cur[x*4+3] = -y_srca[x]; + uint32_t *palette = sb->palette; + 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++ = palette[*inbmp++]; } } - - c->part.x = s->x; - c->part.y = s->y; - - 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) +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_OLD_PLANAR || src.num_parts > 1) + if (src.format != SUBBITMAP_INDEXED) return false; - imgs->format = SUBBITMAP_OLD; + imgs->format = SUBBITMAP_OLD_PLANAR; 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; + // 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); - osd_conv_cache_alloc_bmp(c, s->w, s->h, 2); + int xmin, ymin, xmax, ymax; - 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]; - } + 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); } - c->part.x = s->x; - c->part.y = s->y; + int w = xmax - xmin; + int h = ymax - ymin; - imgs->parts = &c->part; - imgs->num_parts = 1; + 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 index b4201f606c..ac766fb0ed 100644 --- a/sub/img_convert.h +++ b/sub/img_convert.h @@ -10,8 +10,9 @@ 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_old_p_to_rgba(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); +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/sd_lavc.c b/sub/sd_lavc.c index a10ac5e18e..a5fe23721a 100644 --- a/sub/sd_lavc.c +++ b/sub/sd_lavc.c @@ -16,6 +16,7 @@ */ #include +#include #include @@ -23,61 +24,21 @@ #include "mp_msg.h" #include "libmpdemux/stheader.h" #include "sd.h" -#include "spudec.h" -// Current code still pushes subs directly to global spudec #include "dec_sub.h" #include "sub.h" struct sd_lavc_priv { AVCodecContext *avctx; + AVSubtitle sub; + bool have_sub; int count; struct sub_bitmap *inbitmaps; struct sub_bitmap *outbitmaps; + struct osd_bmp_indexed *imgs; bool bitmaps_changed; double endpts; }; -static void old_avsub_to_spudec(AVSubtitleRect **rects, int num_rects, - double pts, double endpts) -{ - int i, xmin = INT_MAX, ymin = INT_MAX, xmax = INT_MIN, ymax = INT_MIN; - struct spu_packet_t *packet; - - if (num_rects == 1) { - spudec_set_paletted(vo_spudec, - rects[0]->pict.data[0], - rects[0]->pict.linesize[0], - rects[0]->pict.data[1], - rects[0]->x, - rects[0]->y, - rects[0]->w, - rects[0]->h, - pts, - endpts); - return; - } - for (i = 0; i < num_rects; i++) { - xmin = FFMIN(xmin, rects[i]->x); - ymin = FFMIN(ymin, rects[i]->y); - xmax = FFMAX(xmax, rects[i]->x + rects[i]->w); - ymax = FFMAX(ymax, rects[i]->y + rects[i]->h); - } - packet = spudec_packet_create(xmin, ymin, xmax - xmin, ymax - ymin); - if (!packet) - return; - spudec_packet_clear(packet); - for (i = 0; i < num_rects; i++) - spudec_packet_fill(packet, - rects[i]->pict.data[0], - rects[i]->pict.linesize[0], - rects[i]->pict.data[1], - rects[i]->x - xmin, - rects[i]->y - ymin, - rects[i]->w, - rects[i]->h); - spudec_packet_send(vo_spudec, packet, pts, endpts); -} - static void guess_resolution(char type, int *w, int *h) { if (type == 'v') { @@ -143,8 +104,13 @@ static void clear(struct sd_lavc_priv *priv) talloc_free(priv->inbitmaps); talloc_free(priv->outbitmaps); priv->inbitmaps = priv->outbitmaps = NULL; + talloc_free(priv->imgs); + priv->imgs = NULL; priv->bitmaps_changed = true; priv->endpts = MP_NOPTS_VALUE; + if (priv->have_sub) + avsubtitle_free(&priv->sub); + priv->have_sub = false; } static void decode(struct sh_sub *sh, struct osd_state *osd, void *data, @@ -166,6 +132,8 @@ static void decode(struct sh_sub *sh, struct osd_state *osd, void *data, int res = avcodec_decode_subtitle2(ctx, &sub, &got_sub, &pkt); if (res < 0 || !got_sub) return; + priv->sub = sub; + priv->have_sub = true; if (pts != MP_NOPTS_VALUE) { if (sub.end_display_time > sub.start_display_time) duration = (sub.end_display_time - sub.start_display_time) / 1000.0; @@ -174,39 +142,27 @@ static void decode(struct sh_sub *sh, struct osd_state *osd, void *data, double endpts = MP_NOPTS_VALUE; if (pts != MP_NOPTS_VALUE && duration >= 0) endpts = pts + duration; - if (vo_spudec && sub.num_rects == 0) - spudec_set_paletted(vo_spudec, NULL, 0, NULL, 0, 0, 0, 0, pts, endpts); if (sub.num_rects > 0) { switch (sub.rects[0]->type) { case SUBTITLE_BITMAP: - if (!osd->support_rgba) { - if (!vo_spudec) - vo_spudec = spudec_new_scaled(NULL, ctx->width, ctx->height, - NULL, 0); - old_avsub_to_spudec(sub.rects, sub.num_rects, pts, endpts); - vo_osd_changed(OSDTYPE_SPU); - break; - } priv->inbitmaps = talloc_array(priv, struct sub_bitmap, sub.num_rects); + priv->imgs = talloc_array(priv, struct osd_bmp_indexed, + sub.num_rects); for (int i = 0; i < sub.num_rects; i++) { struct AVSubtitleRect *r = sub.rects[i]; struct sub_bitmap *b = &priv->inbitmaps[i]; - uint32_t *outbmp = talloc_size(priv->inbitmaps, - r->w * r->h * 4); - b->bitmap = outbmp; - b->stride = r->w * 4; + struct osd_bmp_indexed *img = &priv->imgs[i]; + img->bitmap = r->pict.data[0]; + assert(r->nb_colors > 0); + assert(r->nb_colors * 4 <= sizeof(img->palette)); + memcpy(img->palette, r->pict.data[1], r->nb_colors * 4); + b->bitmap = img; + b->stride = r->pict.linesize[0]; b->w = r->w; b->h = r->h; b->x = r->x; b->y = r->y; - uint8_t *inbmp = r->pict.data[0]; - uint32_t *palette = (uint32_t *) r->pict.data[1]; - for (int y = 0; y < r->h; y++) { - for (int x = 0; x < r->w; x++) - *outbmp++ = palette[*inbmp++]; - inbmp += r->pict.linesize[0] - r->w; - }; } priv->count = sub.num_rects; priv->endpts = endpts; @@ -217,7 +173,6 @@ static void decode(struct sh_sub *sh, struct osd_state *osd, void *data, break; } } - avsubtitle_free(&sub); } static void get_bitmaps(struct sh_sub *sh, struct osd_state *osd, @@ -229,8 +184,6 @@ static void get_bitmaps(struct sh_sub *sh, struct osd_state *osd, if (priv->endpts != MP_NOPTS_VALUE && (params->pts >= priv->endpts || params->pts < priv->endpts - 300)) clear(priv); - if (!params->support_rgba) - return; if (priv->bitmaps_changed && priv->count > 0) priv->outbitmaps = talloc_memdup(priv, priv->inbitmaps, talloc_get_size(priv->inbitmaps)); @@ -257,7 +210,7 @@ static void get_bitmaps(struct sh_sub *sh, struct osd_state *osd, else if (pos_changed) res->bitmap_pos_id++; priv->bitmaps_changed = false; - res->format = SUBBITMAP_RGBA; + res->format = SUBBITMAP_INDEXED; res->scaled = xscale != 1 || yscale != 1; } @@ -274,6 +227,7 @@ static void uninit(struct sh_sub *sh) { struct sd_lavc_priv *priv = sh->context; + clear(priv); avcodec_close(priv->avctx); av_free(priv->avctx); talloc_free(priv); diff --git a/sub/spudec.c b/sub/spudec.c index a58df60b17..8ee22a5267 100644 --- a/sub/spudec.c +++ b/sub/spudec.c @@ -127,6 +127,7 @@ typedef struct { struct sub_bitmap borrowed_sub_part; struct old_osd_planar borrowed_sub_image; + struct osd_bmp_indexed borrowed_bmp; } spudec_handle_t; static void spudec_queue_packet(spudec_handle_t *this, packet_t *packet) @@ -760,6 +761,50 @@ void spudec_get_bitmap(void *this, int w, int h, struct sub_bitmaps *res) } } +void spudec_get_indexed(void *this, struct mp_eosd_res *dim, + struct sub_bitmaps *res) +{ + spudec_handle_t *spu = this; + *res = (struct sub_bitmaps) { .format = SUBBITMAP_INDEXED }; + struct sub_bitmap *part = &spu->borrowed_sub_part; + res->parts = part; + if (spudec_visible(spu)) { + struct osd_bmp_indexed *bmp = &spu->borrowed_bmp; + part->bitmap = bmp; + bmp->bitmap = spu->pal_image; + part->stride = spu->pal_width; + part->w = spu->pal_width; + part->h = spu->pal_height; + double xscale = (double) (dim->w - dim->ml - dim->mr) / spu->orig_frame_width; + double yscale = (double) (dim->h - dim->mt - dim->mb) / spu->orig_frame_height; + part->x = spu->pal_start_col * xscale + dim->ml; + part->y = spu->pal_start_row * yscale + dim->mt; + part->dw = part->w * xscale; + part->dh = part->h * yscale; + res->num_parts = 1; + memset(bmp->palette, 0, sizeof(bmp->palette)); + for (int i = 0; i < 4; ++i) { + int alpha = spu->alpha[i]; + // extend 4 -> 8 bit + alpha |= alpha << 4; + if (spu->custom && (spu->cuspal[i] >> 31) != 0) + alpha = 0; + int color = spu->custom ? spu->cuspal[i] : + spu->global_palette[spu->palette[i]]; + int y = (color >> 16) & 0xff; + int u = (color >> 8) & 0xff; + int v = color & 0xff; + // stolen from some site, likely incorrect + int b = 1.164 * (y - 16) + 2.018 * (u - 128); + int g = 1.164 * (y - 16) - 0.813 * (v - 128) - 0.391 * (u - 128); + int r = 1.164 * (y - 16) + 1.596 * (v - 128); +#define CL(x) FFMAX(FFMIN((x), 255), 0) + bmp->palette[i] = (alpha << 24) | CL(r) | (CL(g) << 8) | (CL(b) << 16); +#undef CL + } + } +} + 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; @@ -1325,6 +1370,14 @@ void *spudec_new_scaled(unsigned int *palette, unsigned int frame_width, unsigne return this; } +void spudec_set_res(void *this, unsigned int frame_width, unsigned int frame_height) +{ + spudec_handle_t *spu = this; + // intentionally do not apply resolution heuristics + spu->orig_frame_width = frame_width; + spu->orig_frame_height = frame_height; +} + void *spudec_new(unsigned int *palette) { return spudec_new_scaled(palette, 0, 0, NULL, 0); diff --git a/sub/spudec.h b/sub/spudec.h index 2e2542128a..411aafeb19 100644 --- a/sub/spudec.h +++ b/sub/spudec.h @@ -22,14 +22,17 @@ #include struct sub_bitmaps; +struct mp_eosd_res; 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); +void spudec_get_indexed(void *this, struct mp_eosd_res *dim, 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_set_res(void *this, unsigned int frame_width, unsigned int frame_height); void *spudec_new(unsigned int *palette); void spudec_free(void *this); void spudec_reset(void *this); // called after seek diff --git a/sub/sub.c b/sub/sub.c index b2d9eb82fc..39cb32e488 100644 --- a/sub/sub.c +++ b/sub/sub.c @@ -172,8 +172,10 @@ static bool render_object(struct osd_state *osd, struct osd_object *obj, if (obj->type == OSDTYPE_SPU) { *out_imgs = (struct sub_bitmaps) {0}; - if (spu_visible(osd, obj)) - spudec_get_bitmap(vo_spudec, osd->res.w, osd->res.h, out_imgs); + if (spu_visible(osd, obj)) { + //spudec_get_bitmap(vo_spudec, osd->res.w, osd->res.h, out_imgs); + spudec_get_indexed(vo_spudec, &osd->res, out_imgs); + } // Normal change-detection (sub. dec. calls vo_osd_changed(OSDTYPE_SPU)) if (obj->force_redraw) { out_imgs->bitmap_id++; @@ -183,9 +185,6 @@ static bool render_object(struct osd_state *osd, struct osd_object *obj, struct sub_render_params p = *sub_params; if (p.pts != MP_NOPTS_VALUE) p.pts += sub_delay - osd->sub_offset; - - p.support_rgba = formats[SUBBITMAP_RGBA]; - sub_get_bitmaps(osd, &p, out_imgs); } else { osd_object_get_bitmaps(osd, obj, out_imgs); @@ -204,7 +203,7 @@ static bool render_object(struct osd_state *osd, struct osd_object *obj, && formats[obj->cached.format]) { *out_imgs = obj->cached; - return true; + return out_imgs->num_parts > 0; } out_imgs->render_index = obj->type; @@ -212,22 +211,22 @@ static bool render_object(struct osd_state *osd, struct osd_object *obj, out_imgs->bitmap_pos_id = obj->vo_bitmap_pos_id; if (formats[out_imgs->format]) - return true; + return out_imgs->num_parts > 0; 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) + if (formats[SUBBITMAP_RGBA] && out_imgs->format == SUBBITMAP_INDEXED) { + cached |= osd_conv_idx_to_rgba(obj->cache[0], out_imgs); + } + + if (formats[SUBBITMAP_OLD_PLANAR] && out_imgs->format == SUBBITMAP_INDEXED) { - cached |= osd_conv_ass_to_old_p(obj->cache[0], out_imgs); + cached |= osd_conv_idx_to_old_p(obj->cache[1], out_imgs, + osd->res.w, osd->res.h); } - if (formats[SUBBITMAP_OLD] && out_imgs->format == SUBBITMAP_OLD_PLANAR) { - cached |= osd_conv_old_p_to_old(obj->cache[1], out_imgs); - } - - if (formats[SUBBITMAP_RGBA] && out_imgs->format == SUBBITMAP_OLD_PLANAR) { - cached |= osd_conv_old_p_to_rgba(obj->cache[2], out_imgs); + if (formats[SUBBITMAP_OLD_PLANAR] && out_imgs->format == SUBBITMAP_LIBASS) { + cached |= osd_conv_ass_to_old_p(obj->cache[2], out_imgs); } if (cached) @@ -238,7 +237,7 @@ static bool render_object(struct osd_state *osd, struct osd_object *obj, obj->type, out_imgs->format); return false; } - return true; + return out_imgs->num_parts > 0; } // This is a hack to render the first subtitle OSD object, which is not empty. @@ -290,7 +289,6 @@ void draw_osd_with_eosd(struct vo *vo, struct osd_state *osd) .dim = dim, .normal_scale = 1, .vsfilter_scale = (double) asp.prew / asp.preh * asp.orgh / asp.orgw, - .support_rgba = formats[SUBBITMAP_RGBA], }; for (int n = 0; n < MAX_OSD_PARTS; n++) { diff --git a/sub/sub.h b/sub/sub.h index 6a83036460..8649018029 100644 --- a/sub/sub.h +++ b/sub/sub.h @@ -30,13 +30,20 @@ struct sub_render_params; enum sub_bitmap_format { SUBBITMAP_EMPTY = 0,// no bitmaps; always has num_parts==0 SUBBITMAP_LIBASS, // A8, with a per-surface blend color (libass.color) - SUBBITMAP_RGBA, // B8G8R8A8, can be scaled - SUBBITMAP_OLD, // I8A8 (monochrome), premultiplied alpha + SUBBITMAP_RGBA, // B8G8R8A8 (MSB=A, LSB=B), can be scaled + SUBBITMAP_INDEXED, // scaled, bitmap points to osd_bmp_indexed SUBBITMAP_OLD_PLANAR, // like previous, but bitmap points to old_osd_planar SUBBITMAP_COUNT }; +// For SUBBITMAP_INDEXED +struct osd_bmp_indexed { + uint8_t *bitmap; + // Each entry is like a pixel in SUBBITMAP_RGBA format + uint32_t palette[256]; +}; + // For SUBBITMAP_OLD_PANAR struct old_osd_planar { unsigned char *bitmap; @@ -46,9 +53,10 @@ struct old_osd_planar { struct sub_bitmap { void *bitmap; int stride; + // Note: not clipped, going outside the screen area is allowed + // (except for SUBBITMAP_LIBASS, which is always clipped) int w, h; int x, y; - // Note: not clipped, going outside the screen area is allowed int dw, dh; union { @@ -59,10 +67,14 @@ struct sub_bitmap { }; struct sub_bitmaps { - int render_index; // for VO cache state (limited by MAX_OSD_PARTS) + // For VO cache state (limited by MAX_OSD_PARTS) + int render_index; enum sub_bitmap_format format; - bool scaled; // if false, dw==w && dh==h + + // If false, dw==w && dh==h. + // SUBBITMAP_LIBASS is never scaled. + bool scaled; struct sub_bitmap *parts; int num_parts; @@ -120,8 +132,6 @@ struct osd_state { double sub_offset; double vo_sub_pts; - bool support_rgba; - bool render_subs_in_filter; struct mp_eosd_res res; From 44c62a685222f2b018a480246c2946d3e3e7529c Mon Sep 17 00:00:00 2001 From: wm4 Date: Fri, 5 Oct 2012 20:37:16 +0200 Subject: [PATCH 27/83] sub: switch to premultiplied alpha Fixes problems with ugly borders. Note that at least in the DVD sub case, we could have just set all transparent pixels to black to solve this. vo_direct3d.c change untested, because mingw is a miserable pile of crap. --- libvo/gl_osd.c | 2 +- libvo/vo_direct3d.c | 5 +++++ libvo/vo_vdpau.c | 9 ++++++++- sub/img_convert.c | 24 ++++++++++++++++++++---- sub/sub.h | 2 +- 5 files changed, 35 insertions(+), 7 deletions(-) diff --git a/libvo/gl_osd.c b/libvo/gl_osd.c index 74053afd4a..5266dca4ac 100644 --- a/libvo/gl_osd.c +++ b/libvo/gl_osd.c @@ -32,7 +32,7 @@ struct osd_fmt_entry { // glBlendFunc() arguments static const int blend_factors[SUBBITMAP_COUNT][2] = { [SUBBITMAP_LIBASS] = {GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA}, - [SUBBITMAP_RGBA] = {GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA}, + [SUBBITMAP_RGBA] = {GL_ONE, GL_ONE_MINUS_SRC_ALPHA}, }; static const struct osd_fmt_entry osd_to_gl3_formats[SUBBITMAP_COUNT] = { diff --git a/libvo/vo_direct3d.c b/libvo/vo_direct3d.c index 4f16c6a6b1..2b8f3429e4 100644 --- a/libvo/vo_direct3d.c +++ b/libvo/vo_direct3d.c @@ -2049,6 +2049,9 @@ static void draw_osd(d3d_priv *priv, struct sub_bitmaps *imgs) IDirect3DDevice9_SetTextureStageState(priv->d3d_device, 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE); + } else { + IDirect3DDevice9_SetRenderState(priv->d3d_device, D3DRS_SRCBLEND, + D3DBLEND_ONE); } IDirect3DDevice9_SetFVF(priv->d3d_device, D3DFVF_EOSD_VERTEX); @@ -2060,6 +2063,8 @@ static void draw_osd(d3d_priv *priv, struct sub_bitmaps *imgs) D3DTSS_COLORARG1, D3DTA_TEXTURE); IDirect3DDevice9_SetTextureStageState(priv->d3d_device, 0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1); + IDirect3DDevice9_SetRenderState(priv->d3d_device, + D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); IDirect3DDevice9_SetTexture(priv->d3d_device, 0, NULL); diff --git a/libvo/vo_vdpau.c b/libvo/vo_vdpau.c index 34aa9824dc..94d37e3018 100644 --- a/libvo/vo_vdpau.c +++ b/libvo/vo_vdpau.c @@ -970,14 +970,21 @@ static void draw_eosd(struct vo *vo, int index) .blend_equation_alpha = VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_ADD, }; + VdpOutputSurfaceRenderBlendState blend_state_premultiplied = blend_state; + blend_state_premultiplied.blend_factor_source_color = + VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE; + for (i = 0; i < sfc->render_count; i++) { + VdpOutputSurfaceRenderBlendState *blend = &blend_state; + if (sfc->format == VDP_RGBA_FORMAT_B8G8R8A8) + blend = &blend_state_premultiplied; vdp_st = vdp-> output_surface_render_bitmap_surface(output_surface, &sfc->targets[i].dest, sfc->surface, &sfc->targets[i].source, &sfc->targets[i].color, - &blend_state, + blend, VDP_OUTPUT_SURFACE_RENDER_ROTATE_0); CHECK_ST_WARNING("EOSD: Error when rendering"); } diff --git a/sub/img_convert.c b/sub/img_convert.c index b8a769f052..888380cf70 100644 --- a/sub/img_convert.c +++ b/sub/img_convert.c @@ -166,6 +166,21 @@ bool osd_conv_ass_to_old_p(struct osd_conv_cache *c, struct sub_bitmaps *imgs) 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; @@ -179,18 +194,19 @@ bool osd_conv_idx_to_rgba(struct osd_conv_cache *c, struct sub_bitmaps *imgs) 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 = s->bitmap; + 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 *palette = sb->palette; uint32_t *outbmp = d->bitmap; for (int y = 0; y < s->h; y++) { - uint8_t *inbmp = sb->bitmap + y * s->stride; + uint8_t *inbmp = sb.bitmap + y * s->stride; for (int x = 0; x < s->w; x++) - *outbmp++ = palette[*inbmp++]; + *outbmp++ = sb.palette[*inbmp++]; } } return true; diff --git a/sub/sub.h b/sub/sub.h index 8649018029..649f196414 100644 --- a/sub/sub.h +++ b/sub/sub.h @@ -30,7 +30,7 @@ struct sub_render_params; enum sub_bitmap_format { SUBBITMAP_EMPTY = 0,// no bitmaps; always has num_parts==0 SUBBITMAP_LIBASS, // A8, with a per-surface blend color (libass.color) - SUBBITMAP_RGBA, // B8G8R8A8 (MSB=A, LSB=B), can be scaled + SUBBITMAP_RGBA, // B8G8R8A8 (MSB=A, LSB=B), scaled, premultiplied alpha SUBBITMAP_INDEXED, // scaled, bitmap points to osd_bmp_indexed SUBBITMAP_OLD_PLANAR, // like previous, but bitmap points to old_osd_planar From 84c34806864d0e44855d87e9fb47c70297f260ef Mon Sep 17 00:00:00 2001 From: wm4 Date: Mon, 8 Oct 2012 02:05:59 +0200 Subject: [PATCH 28/83] spudec.c: crop subs, set scaled flag Crop subtitle images produced by spudec.c: instead of returning a frame- sized bitmap (with possibly large transparent regions), return a cropped down rectangle of the visible part only. The old spudec scaler code had this as spudec_cut_image(), but it worked on the data converted to the old OSD format only. Move most code to setup the sub-bitmap from spudec_get_indexed() to spudec_process_data(), so that cropping can be done every time a new subtitle is decoded, instead of every frame. Set the sub_bitmaps->scaled flag. Without it, vo_gl and vo_vdpau produced ugly artifacts on the borders. --- sub/spudec.c | 114 +++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 84 insertions(+), 30 deletions(-) diff --git a/sub/spudec.c b/sub/spudec.c index 8ee22a5267..e9084dcb32 100644 --- a/sub/spudec.c +++ b/sub/spudec.c @@ -125,8 +125,8 @@ typedef struct { struct palette_crop_cache palette_crop_cache; - struct sub_bitmap borrowed_sub_part; struct old_osd_planar borrowed_sub_image; + struct sub_bitmap sub_part, borrowed_sub_part; struct osd_bmp_indexed borrowed_bmp; } spudec_handle_t; @@ -344,6 +344,70 @@ int spudec_apply_palette_crop(void *this, uint32_t palette, return c->result; } +static void setup_palette(spudec_handle_t *spu, uint32_t palette[256]) +{ + memset(palette, 0, sizeof(palette)); + for (int i = 0; i < 4; ++i) { + int alpha = spu->alpha[i]; + // extend 4 -> 8 bit + alpha |= alpha << 4; + if (spu->custom && (spu->cuspal[i] >> 31) != 0) + alpha = 0; + int color = spu->custom ? spu->cuspal[i] : + spu->global_palette[spu->palette[i]]; + int y = (color >> 16) & 0xff; + int u = (color >> 8) & 0xff; + int v = color & 0xff; + // stolen from some site, likely incorrect + int b = 1.164 * (y - 16) + 2.018 * (u - 128); + int g = 1.164 * (y - 16) - 0.813 * (v - 128) - 0.391 * (u - 128); + int r = 1.164 * (y - 16) + 1.596 * (v - 128); +#define CL(x) FFMAX(FFMIN((x), 255), 0) + palette[i] = (alpha << 24) | CL(r) | (CL(g) << 8) | (CL(b) << 16); +#undef CL + } +} + +static void crop_image(struct sub_bitmap *part) +{ + if (part->w < 1 || part->h < 1) + return; + struct osd_bmp_indexed *bmp = part->bitmap; + bool invisible[256]; + for (int n = 0; n < 256; n++) + invisible[n] = !(bmp->palette[n] >> 24); + int y0 = 0, y1 = part->h, x0 = part->w, x1 = 0; + bool y_all_invisible = true; + for (int y = 0; y < part->h; y++) { + uint8_t *pixels = bmp->bitmap + part->stride * y; + int cur = 0; + while (cur < part->w && invisible[pixels[cur]]) + cur++; + int start_visible = cur; + int last_visible = -1; + while (cur < part->w) { + if (!invisible[pixels[cur]]) + last_visible = cur; + cur++; + } + x0 = FFMIN(x0, start_visible); + x1 = FFMAX(x1, last_visible); + bool all_invisible = last_visible == -1; + if (all_invisible) { + if (y_all_invisible) + y0 = y; + } else { + y_all_invisible = false; + y1 = y + 1; + } + } + bmp->bitmap += x0 + y0 * part->stride; + part->w = FFMAX(x1 - x0, 0); + part->h = FFMAX(y1 - y0, 0); + part->x += x0; + part->y += y0; +} + static void spudec_process_data(spudec_handle_t *this, packet_t *packet) { unsigned int i, x, y; @@ -391,6 +455,18 @@ static void spudec_process_data(spudec_handle_t *this, packet_t *packet) dst += len; } apply_palette_crop(this, 0, 0, this->pal_width, this->pal_height); + + struct sub_bitmap *sub_part = &this->sub_part; + struct osd_bmp_indexed *bmp = &this->borrowed_bmp; + bmp->bitmap = this->pal_image; + setup_palette(this, bmp->palette); + sub_part->bitmap = bmp; + sub_part->stride = this->pal_width; + sub_part->w = this->pal_width; + sub_part->h = this->pal_height; + sub_part->x = this->pal_start_col; + sub_part->y = this->pal_start_row; + crop_image(sub_part); } @@ -768,40 +844,18 @@ void spudec_get_indexed(void *this, struct mp_eosd_res *dim, *res = (struct sub_bitmaps) { .format = SUBBITMAP_INDEXED }; struct sub_bitmap *part = &spu->borrowed_sub_part; res->parts = part; - if (spudec_visible(spu)) { - struct osd_bmp_indexed *bmp = &spu->borrowed_bmp; - part->bitmap = bmp; - bmp->bitmap = spu->pal_image; - part->stride = spu->pal_width; - part->w = spu->pal_width; - part->h = spu->pal_height; + *part = spu->sub_part; + // Empty subs do happen when cropping + bool empty = part->w < 1 || part->h < 1; + if (spudec_visible(spu) && !empty) { double xscale = (double) (dim->w - dim->ml - dim->mr) / spu->orig_frame_width; double yscale = (double) (dim->h - dim->mt - dim->mb) / spu->orig_frame_height; - part->x = spu->pal_start_col * xscale + dim->ml; - part->y = spu->pal_start_row * yscale + dim->mt; + part->x = part->x * xscale + dim->ml; + part->y = part->y * yscale + dim->mt; part->dw = part->w * xscale; part->dh = part->h * yscale; res->num_parts = 1; - memset(bmp->palette, 0, sizeof(bmp->palette)); - for (int i = 0; i < 4; ++i) { - int alpha = spu->alpha[i]; - // extend 4 -> 8 bit - alpha |= alpha << 4; - if (spu->custom && (spu->cuspal[i] >> 31) != 0) - alpha = 0; - int color = spu->custom ? spu->cuspal[i] : - spu->global_palette[spu->palette[i]]; - int y = (color >> 16) & 0xff; - int u = (color >> 8) & 0xff; - int v = color & 0xff; - // stolen from some site, likely incorrect - int b = 1.164 * (y - 16) + 2.018 * (u - 128); - int g = 1.164 * (y - 16) - 0.813 * (v - 128) - 0.391 * (u - 128); - int r = 1.164 * (y - 16) + 1.596 * (v - 128); -#define CL(x) FFMAX(FFMIN((x), 255), 0) - bmp->palette[i] = (alpha << 24) | CL(r) | (CL(g) << 8) | (CL(b) << 16); -#undef CL - } + res->scaled = true; } } From f45eab6faea05834c1337175dbe51437707b8d7e Mon Sep 17 00:00:00 2001 From: wm4 Date: Tue, 16 Oct 2012 07:26:45 +0200 Subject: [PATCH 29/83] sub: fix and simplify some change detection details Fix spudec change detection. The internal changed-flag was not reset when retrieving indexed bitmaps, and subtitles were rescaled every frame, even if they were not changing. Simplify subtitle decoders by not requiring them to check whether the passed-in screen size has changed. sd_lavc did this, and spudec would have needed to do the same. Instead, leave this to the osd_object force_redraw flag. Subtitle decoders (such as libass) can still signal that only the positions of subtitles have changed, but making _all_ subtitle decoders do this just to deal with screen size changes is worthless. --- sub/sd_lavc.c | 12 ++++-------- sub/spudec.c | 4 ++++ sub/sub.c | 13 ++++++------- 3 files changed, 14 insertions(+), 15 deletions(-) diff --git a/sub/sd_lavc.c b/sub/sd_lavc.c index a5fe23721a..4311db7dc5 100644 --- a/sub/sd_lavc.c +++ b/sub/sd_lavc.c @@ -187,7 +187,6 @@ static void get_bitmaps(struct sh_sub *sh, struct osd_state *osd, if (priv->bitmaps_changed && priv->count > 0) priv->outbitmaps = talloc_memdup(priv, priv->inbitmaps, talloc_get_size(priv->inbitmaps)); - bool pos_changed = false; int inw = priv->avctx->width; int inh = priv->avctx->height; guess_resolution(sh->type, &inw, &inh); @@ -197,18 +196,15 @@ static void get_bitmaps(struct sh_sub *sh, struct osd_state *osd, for (int i = 0; i < priv->count; i++) { struct sub_bitmap *bi = &priv->inbitmaps[i]; struct sub_bitmap *bo = &priv->outbitmaps[i]; -#define SET(var, val) pos_changed |= var != (int)(val); var = (val) - SET(bo->x, bi->x * xscale + d->ml); - SET(bo->y, bi->y * yscale + d->mt); - SET(bo->dw, bi->w * xscale); - SET(bo->dh, bi->h * yscale); + bo->x = bi->x * xscale + d->ml; + bo->y = bi->y * yscale + d->mt; + bo->dw = bi->w * xscale; + bo->dh = bi->h * yscale; } res->parts = priv->outbitmaps; res->num_parts = priv->count; if (priv->bitmaps_changed) res->bitmap_id = ++res->bitmap_pos_id; - else if (pos_changed) - res->bitmap_pos_id++; priv->bitmaps_changed = false; res->format = SUBBITMAP_INDEXED; res->scaled = xscale != 1 || yscale != 1; diff --git a/sub/spudec.c b/sub/spudec.c index e9084dcb32..4eea10ed8f 100644 --- a/sub/spudec.c +++ b/sub/spudec.c @@ -857,6 +857,10 @@ void spudec_get_indexed(void *this, struct mp_eosd_res *dim, res->num_parts = 1; res->scaled = true; } + if (spu->spu_changed) { + res->bitmap_id = res->bitmap_pos_id = 1; + spu->spu_changed = 0; + } } 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) diff --git a/sub/sub.c b/sub/sub.c index 39cb32e488..b37ec07747 100644 --- a/sub/sub.c +++ b/sub/sub.c @@ -176,11 +176,6 @@ static bool render_object(struct osd_state *osd, struct osd_object *obj, //spudec_get_bitmap(vo_spudec, osd->res.w, osd->res.h, out_imgs); spudec_get_indexed(vo_spudec, &osd->res, 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 if (obj->type == OSDTYPE_SUB) { struct sub_render_params p = *sub_params; if (p.pts != MP_NOPTS_VALUE) @@ -190,6 +185,11 @@ static bool render_object(struct osd_state *osd, struct osd_object *obj, osd_object_get_bitmaps(osd, obj, out_imgs); } + if (obj->force_redraw) { + out_imgs->bitmap_id++; + out_imgs->bitmap_pos_id++; + } + obj->force_redraw = false; obj->vo_bitmap_id += out_imgs->bitmap_id; obj->vo_bitmap_pos_id += out_imgs->bitmap_pos_id; @@ -197,8 +197,7 @@ static bool render_object(struct osd_state *osd, struct osd_object *obj, 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 + if (obj->cached.bitmap_id == obj->vo_bitmap_id && obj->cached.bitmap_pos_id == obj->vo_bitmap_pos_id && formats[obj->cached.format]) { From 64ac38c4d30e30783032a4b65f34f4fb50761c7b Mon Sep 17 00:00:00 2001 From: Rudolf Polzer Date: Wed, 24 Oct 2012 19:00:49 +0200 Subject: [PATCH 30/83] libmpcodecs: move vf_scale.c swscale helper functions to sws_utils.c Extracted/rebased by wm4 from commits 93978f17b76d..13211ef5fc20. Actual mp_image_swscale is added in a later commit. --- Makefile | 1 + image_writer.c | 2 +- libmpcodecs/sws_utils.c | 134 ++++++++++++++++++++++++++++++++++++ libmpcodecs/sws_utils.h | 27 ++++++++ libmpcodecs/vf_scale.c | 83 +--------------------- libmpcodecs/vf_scale.h | 28 -------- libmpcodecs/vf_screenshot.c | 2 +- libvo/vo_x11.c | 3 +- 8 files changed, 166 insertions(+), 114 deletions(-) create mode 100644 libmpcodecs/sws_utils.c create mode 100644 libmpcodecs/sws_utils.h delete mode 100644 libmpcodecs/vf_scale.h diff --git a/Makefile b/Makefile index ce1a369f77..839b4d0977 100644 --- a/Makefile +++ b/Makefile @@ -144,6 +144,7 @@ SRCS_COMMON = asxparser.c \ libmpcodecs/img_format.c \ libmpcodecs/mp_image.c \ libmpcodecs/pullup.c \ + libmpcodecs/sws_utils.c \ libmpcodecs/vd.c \ libmpcodecs/vd_ffmpeg.c \ libmpcodecs/vf.c \ diff --git a/image_writer.c b/image_writer.c index ded114f140..f4851a9176 100644 --- a/image_writer.c +++ b/image_writer.c @@ -40,7 +40,7 @@ #include "fmt-conversion.h" //for sws_getContextFromCmdLine_hq and mp_sws_set_colorspace -#include "libmpcodecs/vf_scale.h" +#include "libmpcodecs/sws_utils.h" #include "libvo/csputils.h" #include "m_option.h" diff --git a/libmpcodecs/sws_utils.c b/libmpcodecs/sws_utils.c new file mode 100644 index 0000000000..438db4a13a --- /dev/null +++ b/libmpcodecs/sws_utils.c @@ -0,0 +1,134 @@ +/* + * 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, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include + +#include "libmpcodecs/sws_utils.h" + +#include "libmpcodecs/mp_image.h" +#include "libmpcodecs/img_format.h" +#include "fmt-conversion.h" +#include "libvo/csputils.h" +#include "mp_msg.h" + +//global sws_flags from the command line +int sws_flags = 2; + +float sws_lum_gblur = 0.0; +float sws_chr_gblur = 0.0; +int sws_chr_vshift = 0; +int sws_chr_hshift = 0; +float sws_chr_sharpen = 0.0; +float sws_lum_sharpen = 0.0; + +//global srcFilter +static SwsFilter *src_filter = NULL; + +void sws_getFlagsAndFilterFromCmdLine(int *flags, SwsFilter **srcFilterParam, + SwsFilter **dstFilterParam) +{ + static int firstTime = 1; + *flags = 0; + + if (firstTime) { + firstTime = 0; + *flags = SWS_PRINT_INFO; + } else if (mp_msg_test(MSGT_VFILTER, MSGL_DBG2)) + *flags = SWS_PRINT_INFO; + + if (src_filter) + sws_freeFilter(src_filter); + + src_filter = sws_getDefaultFilter( + sws_lum_gblur, sws_chr_gblur, + sws_lum_sharpen, sws_chr_sharpen, + sws_chr_hshift, sws_chr_vshift, verbose > 1); + + switch (sws_flags) { + case 0: *flags |= SWS_FAST_BILINEAR; + break; + case 1: *flags |= SWS_BILINEAR; + break; + case 2: *flags |= SWS_BICUBIC; + break; + case 3: *flags |= SWS_X; + break; + case 4: *flags |= SWS_POINT; + break; + case 5: *flags |= SWS_AREA; + break; + case 6: *flags |= SWS_BICUBLIN; + break; + case 7: *flags |= SWS_GAUSS; + break; + case 8: *flags |= SWS_SINC; + break; + case 9: *flags |= SWS_LANCZOS; + break; + case 10: *flags |= SWS_SPLINE; + break; + default: *flags |= SWS_BILINEAR; + break; + } + + *srcFilterParam = src_filter; + *dstFilterParam = NULL; +} + +// will use sws_flags & src_filter (from cmd line) +static struct SwsContext *sws_getContextFromCmdLine2(int srcW, int srcH, + int srcFormat, int dstW, + int dstH, int dstFormat, + int extraflags) +{ + int flags; + SwsFilter *dstFilterParam, *srcFilterParam; + enum PixelFormat dfmt, sfmt; + + dfmt = imgfmt2pixfmt(dstFormat); + sfmt = imgfmt2pixfmt(srcFormat); + if (srcFormat == IMGFMT_RGB8 || srcFormat == IMGFMT_BGR8) + sfmt = PIX_FMT_PAL8; + sws_getFlagsAndFilterFromCmdLine(&flags, &srcFilterParam, &dstFilterParam); + + return sws_getContext(srcW, srcH, sfmt, dstW, dstH, dfmt, flags | + extraflags, srcFilterParam, dstFilterParam, + NULL); +} + +struct SwsContext *sws_getContextFromCmdLine(int srcW, int srcH, int srcFormat, + int dstW, int dstH, + int dstFormat) +{ + return sws_getContextFromCmdLine2(srcW, srcH, srcFormat, dstW, dstH, + dstFormat, + 0); +} + +struct SwsContext *sws_getContextFromCmdLine_hq(int srcW, int srcH, + int srcFormat, int dstW, + int dstH, + int dstFormat) +{ + return sws_getContextFromCmdLine2( + srcW, srcH, srcFormat, dstW, dstH, dstFormat, + SWS_FULL_CHR_H_INT | SWS_FULL_CHR_H_INP | + SWS_ACCURATE_RND | SWS_BITEXACT); +} + +// vim: ts=4 sw=4 et tw=80 diff --git a/libmpcodecs/sws_utils.h b/libmpcodecs/sws_utils.h new file mode 100644 index 0000000000..a8dc970d08 --- /dev/null +++ b/libmpcodecs/sws_utils.h @@ -0,0 +1,27 @@ +#ifndef MPLAYER_SWS_UTILS_H +#define MPLAYER_SWS_UTILS_H + +#include + +struct mp_image; +struct mp_csp_details; + +// libswscale currently requires 16 bytes alignment for row pointers and +// strides. Otherwise, it will print warnings and use slow codepaths. +// Guaranteed to be a power of 2 and > 1. +#define SWS_MIN_BYTE_ALIGN 16 + +void sws_getFlagsAndFilterFromCmdLine(int *flags, SwsFilter **srcFilterParam, + SwsFilter **dstFilterParam); +struct SwsContext *sws_getContextFromCmdLine(int srcW, int srcH, int srcFormat, + int dstW, int dstH, + int dstFormat); +struct SwsContext *sws_getContextFromCmdLine_hq(int srcW, int srcH, + int srcFormat, int dstW, + int dstH, + int dstFormat); +int mp_sws_set_colorspace(struct SwsContext *sws, struct mp_csp_details *csp); + +#endif /* MP_SWS_UTILS_H */ + +// vim: ts=4 sw=4 et tw=80 diff --git a/libmpcodecs/vf_scale.c b/libmpcodecs/vf_scale.c index 71428685ac..5ea62bacbd 100644 --- a/libmpcodecs/vf_scale.c +++ b/libmpcodecs/vf_scale.c @@ -32,8 +32,7 @@ #include "fmt-conversion.h" #include "mpbswap.h" -#include "libswscale/swscale.h" -#include "vf_scale.h" +#include "libmpcodecs/sws_utils.h" #include "libvo/csputils.h" // VOFLAG_SWSCALE @@ -68,8 +67,6 @@ static struct vf_priv_s { //===========================================================================// -void sws_getFlagsAndFilterFromCmdLine(int *flags, SwsFilter **srcFilterParam, SwsFilter **dstFilterParam); - static const unsigned int outfmt_list[]={ // YUV: IMGFMT_444P, @@ -647,84 +644,6 @@ static int vf_open(vf_instance_t *vf, char *args){ return 1; } -//global sws_flags from the command line -int sws_flags=2; - -//global srcFilter -static SwsFilter *src_filter= NULL; - -float sws_lum_gblur= 0.0; -float sws_chr_gblur= 0.0; -int sws_chr_vshift= 0; -int sws_chr_hshift= 0; -float sws_chr_sharpen= 0.0; -float sws_lum_sharpen= 0.0; - -void sws_getFlagsAndFilterFromCmdLine(int *flags, SwsFilter **srcFilterParam, SwsFilter **dstFilterParam) -{ - static int firstTime=1; - *flags=0; - - if(firstTime) - { - firstTime=0; - *flags= SWS_PRINT_INFO; - } - else if( mp_msg_test(MSGT_VFILTER,MSGL_DBG2) ) *flags= SWS_PRINT_INFO; - - if(src_filter) sws_freeFilter(src_filter); - - src_filter= sws_getDefaultFilter( - sws_lum_gblur, sws_chr_gblur, - sws_lum_sharpen, sws_chr_sharpen, - sws_chr_hshift, sws_chr_vshift, verbose>1); - - switch(sws_flags) - { - case 0: *flags|= SWS_FAST_BILINEAR; break; - case 1: *flags|= SWS_BILINEAR; break; - case 2: *flags|= SWS_BICUBIC; break; - case 3: *flags|= SWS_X; break; - case 4: *flags|= SWS_POINT; break; - case 5: *flags|= SWS_AREA; break; - case 6: *flags|= SWS_BICUBLIN; break; - case 7: *flags|= SWS_GAUSS; break; - case 8: *flags|= SWS_SINC; break; - case 9: *flags|= SWS_LANCZOS; break; - case 10:*flags|= SWS_SPLINE; break; - default:*flags|= SWS_BILINEAR; break; - } - - *srcFilterParam= src_filter; - *dstFilterParam= NULL; -} - -// will use sws_flags & src_filter (from cmd line) -static struct SwsContext *sws_getContextFromCmdLine2(int srcW, int srcH, int srcFormat, int dstW, int dstH, int dstFormat, int extraflags) -{ - int flags; - SwsFilter *dstFilterParam, *srcFilterParam; - enum PixelFormat dfmt, sfmt; - - dfmt = imgfmt2pixfmt(dstFormat); - sfmt = imgfmt2pixfmt(srcFormat); - if (srcFormat == IMGFMT_RGB8 || srcFormat == IMGFMT_BGR8) sfmt = PIX_FMT_PAL8; - sws_getFlagsAndFilterFromCmdLine(&flags, &srcFilterParam, &dstFilterParam); - - return sws_getContext(srcW, srcH, sfmt, dstW, dstH, dfmt, flags | extraflags, srcFilterParam, dstFilterParam, NULL); -} - -struct SwsContext *sws_getContextFromCmdLine(int srcW, int srcH, int srcFormat, int dstW, int dstH, int dstFormat) -{ - return sws_getContextFromCmdLine2(srcW, srcH, srcFormat, dstW, dstH, dstFormat, 0); -} - -struct SwsContext *sws_getContextFromCmdLine_hq(int srcW, int srcH, int srcFormat, int dstW, int dstH, int dstFormat) -{ - return sws_getContextFromCmdLine2(srcW, srcH, srcFormat, dstW, dstH, dstFormat, - SWS_FULL_CHR_H_INT | SWS_FULL_CHR_H_INP | SWS_ACCURATE_RND | SWS_BITEXACT); -} - /// An example of presets usage static const struct size_preset { char* name; diff --git a/libmpcodecs/vf_scale.h b/libmpcodecs/vf_scale.h deleted file mode 100644 index 575d4f3640..0000000000 --- a/libmpcodecs/vf_scale.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef MPLAYER_VF_SCALE_H -#define MPLAYER_VF_SCALE_H - -struct SwsContext *sws_getContextFromCmdLine(int srcW, int srcH, int srcFormat, int dstW, int dstH, int dstFormat); -struct SwsContext *sws_getContextFromCmdLine_hq(int srcW, int srcH, int srcFormat, int dstW, int dstH, int dstFormat); - -struct mp_csp_details; -int mp_sws_set_colorspace(struct SwsContext *sws, struct mp_csp_details *csp); - -#endif /* MPLAYER_VF_SCALE_H */ diff --git a/libmpcodecs/vf_screenshot.c b/libmpcodecs/vf_screenshot.c index eb961d8118..013525694a 100644 --- a/libmpcodecs/vf_screenshot.c +++ b/libmpcodecs/vf_screenshot.c @@ -27,7 +27,7 @@ #include "img_format.h" #include "mp_image.h" #include "vf.h" -#include "vf_scale.h" +#include "libmpcodecs/sws_utils.h" #include "fmt-conversion.h" #include "libvo/fastmemcpy.h" diff --git a/libvo/vo_x11.c b/libvo/vo_x11.c index 8090821fa8..d43601f7c2 100644 --- a/libvo/vo_x11.c +++ b/libvo/vo_x11.c @@ -43,8 +43,7 @@ #include "sub/sub.h" -#include "libswscale/swscale.h" -#include "libmpcodecs/vf_scale.h" +#include "libmpcodecs/sws_utils.h" #define MODE_RGB 0x1 #define MODE_BGR 0x2 From 1282f9d79e09160af67ec13c05c0eed1ae02bd46 Mon Sep 17 00:00:00 2001 From: Rudolf Polzer Date: Wed, 24 Oct 2012 19:05:49 +0200 Subject: [PATCH 31/83] mp_image: fix copy_mpi() with 16 bit formats, add helper macros Merged by wm4. copy_mpi() assumed that planar YUV formats always used 1 byte per component, which is not true for 9/10/16 bit YUV formats. --- libmpcodecs/mp_image.c | 12 +++++++----- libmpcodecs/mp_image.h | 10 ++++++++++ 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/libmpcodecs/mp_image.c b/libmpcodecs/mp_image.c index 006b0bf4f3..28472d092c 100644 --- a/libmpcodecs/mp_image.c +++ b/libmpcodecs/mp_image.c @@ -40,7 +40,9 @@ void mp_image_alloc_planes(mp_image_t *mpi) { if (!mpi->planes[0]) abort(); //out of memory if (mpi->flags&MP_IMGFLAG_PLANAR) { - int bpp = IMGFMT_IS_YUVP16(mpi->imgfmt)? 2 : 1; + // FIXME this code only supports same bpp for all planes, and bpp divisible + // by 8. Currently the case for all planar formats. + int bpp = MP_IMAGE_PLANAR_BITS_PER_PIXEL_ON_PLANE(mpi, 0) / 8; // YV12/I420/YVU9/IF09. feel free to add other planar formats here... mpi->stride[0]=mpi->stride[3]=bpp*mpi->width; if(mpi->num_planes > 2){ @@ -82,15 +84,15 @@ mp_image_t* alloc_mpi(int w, int h, unsigned long int fmt) { void copy_mpi(mp_image_t *dmpi, mp_image_t *mpi) { if(mpi->flags&MP_IMGFLAG_PLANAR){ - memcpy_pic(dmpi->planes[0],mpi->planes[0], mpi->w, mpi->h, + memcpy_pic(dmpi->planes[0],mpi->planes[0], MP_IMAGE_BYTES_PER_ROW_ON_PLANE(mpi, 0), mpi->h, dmpi->stride[0],mpi->stride[0]); - memcpy_pic(dmpi->planes[1],mpi->planes[1], mpi->chroma_width, mpi->chroma_height, + memcpy_pic(dmpi->planes[1],mpi->planes[1], MP_IMAGE_BYTES_PER_ROW_ON_PLANE(mpi, 1), mpi->chroma_height, dmpi->stride[1],mpi->stride[1]); - memcpy_pic(dmpi->planes[2], mpi->planes[2], mpi->chroma_width, mpi->chroma_height, + memcpy_pic(dmpi->planes[2], mpi->planes[2], MP_IMAGE_BYTES_PER_ROW_ON_PLANE(mpi, 2), mpi->chroma_height, dmpi->stride[2],mpi->stride[2]); } else { memcpy_pic(dmpi->planes[0],mpi->planes[0], - mpi->w*(dmpi->bpp/8), mpi->h, + MP_IMAGE_BYTES_PER_ROW_ON_PLANE(mpi, 0), mpi->h, dmpi->stride[0],mpi->stride[0]); } } diff --git a/libmpcodecs/mp_image.h b/libmpcodecs/mp_image.h index 6dbe3bfe02..e1cbe7d2cf 100644 --- a/libmpcodecs/mp_image.h +++ b/libmpcodecs/mp_image.h @@ -130,4 +130,14 @@ mp_image_t* alloc_mpi(int w, int h, unsigned long int fmt); void mp_image_alloc_planes(mp_image_t *mpi); void copy_mpi(mp_image_t *dmpi, mp_image_t *mpi); +// this macro requires img_format.h to be included too: +#define MP_IMAGE_PLANAR_BITS_PER_PIXEL_ON_PLANE(mpi, p) \ + (IMGFMT_IS_YUVP16((mpi)->imgfmt) ? 16 : 8) +#define MP_IMAGE_BITS_PER_PIXEL_ON_PLANE(mpi, p) \ + (((mpi)->flags & MP_IMGFLAG_PLANAR) \ + ? MP_IMAGE_PLANAR_BITS_PER_PIXEL_ON_PLANE(mpi, p) \ + : (mpi)->bpp) +#define MP_IMAGE_BYTES_PER_ROW_ON_PLANE(mpi, p) \ + ((MP_IMAGE_BITS_PER_PIXEL_ON_PLANE(mpi, p) * ((mpi)->w >> (p ? mpi->chroma_x_shift : 0)) + 7) / 8) + #endif /* MPLAYER_MP_IMAGE_H */ From aa1047a35a98606c972cc35e566178703b1f2bff Mon Sep 17 00:00:00 2001 From: Rudolf Polzer Date: Wed, 24 Oct 2012 19:11:42 +0200 Subject: [PATCH 32/83] sub: add helper to draw sub-bitmaps into an image Merged by wm4 from commits 93978f17b76d..13211ef5fc20. Changed copyright header in draw_bmp.c to "mpv", and removed the one in draw_bmp.h. --- Makefile | 1 + libmpcodecs/sws_utils.c | 24 ++ libmpcodecs/sws_utils.h | 3 + libvo/csputils.c | 54 ++++ libvo/csputils.h | 10 + sub/draw_bmp.c | 580 ++++++++++++++++++++++++++++++++++++++++ sub/draw_bmp.h | 12 + 7 files changed, 684 insertions(+) create mode 100644 sub/draw_bmp.c create mode 100644 sub/draw_bmp.h diff --git a/Makefile b/Makefile index 839b4d0977..ecd33359c2 100644 --- a/Makefile +++ b/Makefile @@ -217,6 +217,7 @@ SRCS_COMMON = asxparser.c \ sub/spudec.c \ sub/sub.c \ sub/img_convert.c \ + sub/draw_bmp.c \ sub/subassconvert.c \ sub/subreader.c \ sub/vobsub.c \ diff --git a/libmpcodecs/sws_utils.c b/libmpcodecs/sws_utils.c index 438db4a13a..65b079dd84 100644 --- a/libmpcodecs/sws_utils.c +++ b/libmpcodecs/sws_utils.c @@ -131,4 +131,28 @@ struct SwsContext *sws_getContextFromCmdLine_hq(int srcW, int srcH, SWS_ACCURATE_RND | SWS_BITEXACT); } +void mp_image_swscale(struct mp_image *dst, + const struct mp_image *src, + struct mp_csp_details *csp, + int my_sws_flags) +{ + enum PixelFormat dfmt, sfmt; + dfmt = imgfmt2pixfmt(dst->imgfmt); + sfmt = imgfmt2pixfmt(src->imgfmt); + if (src->imgfmt == IMGFMT_RGB8 || src->imgfmt == IMGFMT_BGR8) + sfmt = PIX_FMT_PAL8; + + struct SwsContext *sws = + sws_getContext(src->w, src->h, sfmt, dst->w, dst->h, dfmt, + my_sws_flags, NULL, NULL, NULL); + struct mp_csp_details mycsp = MP_CSP_DETAILS_DEFAULTS; + if (csp) + mycsp = *csp; + mp_sws_set_colorspace(sws, &mycsp); + sws_scale(sws, (const unsigned char *const *) src->planes, src->stride, + 0, src->h, + dst->planes, dst->stride); + sws_freeContext(sws); +} + // vim: ts=4 sw=4 et tw=80 diff --git a/libmpcodecs/sws_utils.h b/libmpcodecs/sws_utils.h index a8dc970d08..b2c55eb407 100644 --- a/libmpcodecs/sws_utils.h +++ b/libmpcodecs/sws_utils.h @@ -22,6 +22,9 @@ struct SwsContext *sws_getContextFromCmdLine_hq(int srcW, int srcH, int dstFormat); int mp_sws_set_colorspace(struct SwsContext *sws, struct mp_csp_details *csp); +void mp_image_swscale(struct mp_image *dst, const struct mp_image *src, + struct mp_csp_details *csp, int my_sws_flags); + #endif /* MP_SWS_UTILS_H */ // vim: ts=4 sw=4 et tw=80 diff --git a/libvo/csputils.c b/libvo/csputils.c index ed74b9ae74..58b29bfeaa 100644 --- a/libvo/csputils.c +++ b/libvo/csputils.c @@ -29,6 +29,7 @@ #include #include #include +#include "mp_msg.h" #include "csputils.h" @@ -317,3 +318,56 @@ int mp_csp_equalizer_set(struct mp_csp_equalizer *eq, const char *property, return 1; } + +void mp_invert_yuv2rgb(float out[3][4], float in[3][4]) +{ + // this is from the DarkPlaces engine, reduces to 3x3. Original code + // released under GPL2 or any later version. + float det; + + // this seems to help gcc's common subexpression elimination, and also makes the code look nicer + float m00 = in[0][0], m01 = in[0][1], m02 = in[0][2], m03 = in[0][3], + m10 = in[1][0], m11 = in[1][1], m12 = in[1][2], m13 = in[1][3], + m20 = in[2][0], m21 = in[2][1], m22 = in[2][2], m23 = in[2][3]; + + // calculate the adjoint + out[0][0] = (m11 * m22 - m21 * m12); + out[0][1] = -(m01 * m22 - m21 * m02); + out[0][2] = (m01 * m12 - m11 * m02); + out[1][0] = -(m10 * m22 - m20 * m12); + out[1][1] = (m00 * m22 - m20 * m02); + out[1][2] = -(m00 * m12 - m10 * m02); + out[2][0] = (m10 * m21 - m20 * m11); + out[2][1] = -(m00 * m21 - m20 * m01); + out[2][2] = (m00 * m11 - m10 * m01); + + // calculate the determinant (as inverse == 1/det * adjoint, adjoint * m == identity * det, so this calculates the det) + det = m00 * out[0][0] + m10 * out[0][1] + m20 * out[0][2]; + if (det == 0.0f) { + //mp_msg(MSGT_VO, MSGL_ERR, "cannot invert yuv2rgb matrix\n"); + return; + } + + // multiplications are faster than divisions, usually + det = 1.0f / det; + + // manually unrolled loop to multiply all matrix elements by 1/det + out[0][0] *= det; + out[0][1] *= det; + out[0][2] *= det; + out[1][0] *= det; + out[1][1] *= det; + out[1][2] *= det; + out[2][0] *= det; + out[2][1] *= det; + out[2][2] *= det; + + // fix the constant coefficient + // rgb = M * yuv + C + // M^-1 * rgb = yuv + M^-1 * C + // yuv = M^-1 * rgb - M^-1 * C + // ^^^^^^^^^^ + out[0][3] = -(out[0][0] * m03 + out[0][1] * m13 + out[0][2] * m23); + out[1][3] = -(out[1][0] * m03 + out[1][1] * m13 + out[1][2] * m23); + out[2][3] = -(out[2][0] * m03 + out[2][1] * m13 + out[2][2] * m23); +} diff --git a/libvo/csputils.h b/libvo/csputils.h index 4ec0f14ba2..0dd75b0549 100644 --- a/libvo/csputils.h +++ b/libvo/csputils.h @@ -133,4 +133,14 @@ void mp_gen_gamma_map(unsigned char *map, int size, float gamma); void mp_get_yuv2rgb_coeffs(struct mp_csp_params *params, float yuv2rgb[3][4]); void mp_gen_yuv2rgb_map(struct mp_csp_params *params, uint8_t *map, int size); +#define MP_MAP_YUV2RGB_COLOR(m, y, u, v, scale, c) ((m)[c][0] * (y) + \ + (m)[c][1] * (u) + \ + (m)[c][2] * (v) + \ + (m)[c][3] * (scale)) +#define MP_MAP_RGB2YUV_COLOR(minv, r, g, b, scale, c) ((minv)[c][0] * (r) + \ + (minv)[c][1] * (g) + \ + (minv)[c][2] * (b) + \ + (minv)[c][3] * (scale)) +void mp_invert_yuv2rgb(float out[3][4], float in[3][4]); + #endif /* MPLAYER_CSPUTILS_H */ diff --git a/sub/draw_bmp.c b/sub/draw_bmp.c new file mode 100644 index 0000000000..8612336dfa --- /dev/null +++ b/sub/draw_bmp.c @@ -0,0 +1,580 @@ +/* + * This file is part of mpv. + * + * mpv is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * mpv is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with mpv; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "sub/draw_bmp.h" + +#include +#include + +#include "sub/sub.h" +#include "libmpcodecs/mp_image.h" +#include "libmpcodecs/sws_utils.h" +#include "libmpcodecs/img_format.h" +#include "libvo/csputils.h" + +#define ACCURATE +#define CONDITIONAL +#define CONDITIONAL2 + +static void blend_const16_alpha(uint8_t *dst, + ssize_t dstRowStride, + uint16_t srcp, + const uint8_t *srca, + ssize_t srcaRowStride, + uint8_t srcamul, int rows, + int cols) +{ + int i, j; +#ifdef CONDITIONAL + if (!srcamul) + return; +#endif + for (i = 0; i < rows; ++i) { + uint16_t *dstr = (uint16_t *) (dst + dstRowStride * i); + const uint8_t *srcar = srca + srcaRowStride * i; + for (j = 0; j < cols; ++j) { + uint32_t srcap = srcar[j]; + // 32bit to force the math ops to operate on 32 bit +#ifdef CONDITIONAL + if (!srcap) + continue; +#endif +#ifdef CONDITIONAL2 + if (srcap == 255 && srcamul == 255) { + dstr[j] = srcp; + continue; + } +#endif + uint16_t dstp = dstr[j]; + srcap *= srcamul; // now 0..65025 + uint16_t outp = + (srcp * srcap + dstp * (65025 - srcap) + 32512) / 65025; + dstr[j] = outp; + } + } +} + +static void blend_src16_alpha(uint8_t *dst, + ssize_t dstRowStride, + const uint8_t *src, + ssize_t srcRowStride, + const uint8_t *srca, + ssize_t srcaRowStride, + int rows, + int cols) +{ + int i, j; + for (i = 0; i < rows; ++i) { + uint16_t *dstr = (uint16_t *) (dst + dstRowStride * i); + const uint16_t *srcr = (const uint16_t *) (src + srcRowStride * i); + const uint8_t *srcar = srca + srcaRowStride * i; + for (j = 0; j < cols; ++j) { + uint32_t srcap = srcar[j]; + // 32bit to force the math ops to operate on 32 bit +#ifdef CONDITIONAL + if (!srcap) + continue; +#endif + uint16_t srcp = srcr[j]; +#ifdef CONDITIONAL2 + if (srcap == 255) { + dstr[j] = srcp; + continue; + } +#endif + uint16_t dstp = dstr[j]; + uint16_t outp = + (srcp * srcap + dstp * (255 - srcap) + 127) / 255; + dstr[j] = outp; + } + } +} + +static void blend_const8_alpha(uint8_t *dst, + ssize_t dstRowStride, + uint16_t srcp, + const uint8_t *srca, + ssize_t srcaRowStride, + uint8_t srcamul, int rows, + int cols) +{ + int i, j; +#ifdef CONDITIONAL + if (!srcamul) + return; +#endif + for (i = 0; i < rows; ++i) { + uint8_t *dstr = dst + dstRowStride * i; + const uint8_t *srcar = srca + srcaRowStride * i; + for (j = 0; j < cols; ++j) { + uint32_t srcap = srcar[j]; + // 32bit to force the math ops to operate on 32 bit +#ifdef CONDITIONAL + if (!srcap) + continue; +#endif +#ifdef CONDITIONAL2 + if (srcap == 255 && srcamul == 255) { + dstr[j] = srcp; + continue; + } +#endif + uint8_t dstp = dstr[j]; +#ifdef ACCURATE + srcap *= srcamul; // now 0..65025 + uint8_t outp = + (srcp * srcap + dstp * (65025 - srcap) + 32512) / 65025; + dstr[j] = outp; +#else + srcap = (srcap * srcamul + 255) >> 8; + uint8_t outp = + (srcp * srcap + dstp * (255 - srcap) + 255) >> 8; + dstr[j] = outp; +#endif + } + } +} + +static void blend_src8_alpha(uint8_t *dst, + ssize_t dstRowStride, + const uint8_t *src, + ssize_t srcRowStride, + const uint8_t *srca, + ssize_t srcaRowStride, + int rows, + int cols) +{ + int i, j; + for (i = 0; i < rows; ++i) { + uint8_t *dstr = dst + dstRowStride * i; + const uint8_t *srcr = src + srcRowStride * i; + const uint8_t *srcar = srca + srcaRowStride * i; + for (j = 0; j < cols; ++j) { + uint16_t srcap = srcar[j]; + // 16bit to force the math ops to operate on 16 bit +#ifdef CONDITIONAL + if (!srcap) + continue; +#endif + uint8_t srcp = srcr[j]; +#ifdef CONDITIONAL2 + if (srcap == 255) { + dstr[j] = srcp; + continue; + } +#endif + uint8_t dstp = dstr[j]; +#ifdef ACCURATE + uint8_t outp = + (srcp * srcap + dstp * (255 - srcap) + 127) / 255; +#else + uint8_t outp = + (srcp * srcap + dstp * (255 - srcap) + 255) >> 8; +#endif + dstr[j] = outp; + } + } +} + +static void blend_src_alpha(uint8_t *dst, ssize_t dstRowStride, + const uint8_t *src, ssize_t srcRowStride, + const uint8_t *srca, ssize_t srcaRowStride, + int rows, int cols, int bytes) +{ + if (bytes == 2) { + blend_src16_alpha(dst, dstRowStride, src, + srcRowStride, srca, + srcaRowStride, rows, cols); + } else if (bytes == 1) { + blend_src8_alpha(dst, dstRowStride, src, + srcRowStride, srca, + srcaRowStride, rows, cols); + } +} + +static void blend_const_alpha(uint8_t *dst, ssize_t dstRowStride, + uint16_t srcp, + const uint8_t *srca, ssize_t srcaRowStride, + uint8_t srcamul, + int rows, int cols, int bytes) +{ + if (bytes == 2) { + blend_const16_alpha(dst, dstRowStride, srcp, + srca, srcaRowStride, + srcamul, rows, + cols); + } else if (bytes == 1) { + blend_const8_alpha(dst, dstRowStride, srcp, + srca, srcaRowStride, srcamul, + rows, + cols); + } +} + +static inline int min(int x, int y) +{ + if (x < y) + return x; + else + return y; +} + +static void unpremultiply_and_split_bgra(mp_image_t *img, mp_image_t *alpha) +{ + int x, y; + for (y = 0; y < img->h; ++y) { + unsigned char *irow = &img->planes[0][img->stride[0] * y]; + unsigned char *arow = &alpha->planes[0][alpha->stride[0] * y]; + for (x = 0; x < img->w; ++x) { + unsigned char aval = irow[4 * x + 3]; + // multiplied = separate * alpha / 255 + // separate = rint(multiplied * 255 / alpha) + // = floor(multiplied * 255 / alpha + 0.5) + // = floor((multiplied * 255 + 0.5 * alpha) / alpha) + // = floor((multiplied * 255 + floor(0.5 * alpha)) / alpha) + int div = (int) aval; + int add = div / 2; + if (aval) { + irow[4 * x + 0] = min(255, (irow[4 * x + 0] * 255 + add) / div); + irow[4 * x + 1] = min(255, (irow[4 * x + 1] * 255 + add) / div); + irow[4 * x + 2] = min(255, (irow[4 * x + 2] * 255 + add) / div); + } + arow[x] = aval; + } + } +} + +static bool sub_bitmap_to_mp_images(struct mp_image **sbi, int *color_yuv, + int *color_a, struct mp_image **sba, + struct sub_bitmap *sb, + int format, struct mp_csp_details *csp, + float rgb2yuv[3][4], int imgfmt, int bits) +{ + *sbi = NULL; + *sba = NULL; + if (format == SUBBITMAP_RGBA && sb->w >= 8) { + // >= 8 because of libswscale madness + // swscale the bitmap from w*h to dw*dh, changing BGRA8 into YUV444P16 + // and make a scaled copy of A8 + mp_image_t *sbisrc = new_mp_image(sb->w, sb->h); + mp_image_setfmt(sbisrc, IMGFMT_BGRA); + sbisrc->planes[0] = sb->bitmap; + sbisrc->stride[0] = sb->stride; + mp_image_t *sbisrc2 = alloc_mpi(sb->dw, sb->dh, IMGFMT_BGRA); + mp_image_swscale(sbisrc2, sbisrc, csp, SWS_BILINEAR); + + // sbisrc2 now is the original image in premultiplied alpha, but + // properly scaled... + // now, un-premultiply so we can work in YUV color space, also extract + // alpha + *sba = alloc_mpi(sb->dw, sb->dh, IMGFMT_Y8); + unpremultiply_and_split_bgra(sbisrc2, *sba); + + // convert to the output format + *sbi = alloc_mpi(sb->dw, sb->dh, imgfmt); + mp_image_swscale(*sbi, sbisrc2, csp, SWS_BILINEAR); + + free_mp_image(sbisrc); + free_mp_image(sbisrc2); + + color_yuv[0] = 255; + color_yuv[1] = 128; + color_yuv[2] = 128; + *color_a = 255; + return true; + } else if (format == SUBBITMAP_LIBASS && + sb->w == sb->dw && sb->h == sb->dh) { + // swscale alpha only + *sba = new_mp_image(sb->w, sb->h); + mp_image_setfmt(*sba, IMGFMT_Y8); + (*sba)->planes[0] = sb->bitmap; + (*sba)->stride[0] = sb->stride; + int r = (sb->libass.color >> 24) & 0xFF; + int g = (sb->libass.color >> 16) & 0xFF; + int b = (sb->libass.color >> 8) & 0xFF; + int a = sb->libass.color & 0xFF; + color_yuv[0] = + rint(MP_MAP_RGB2YUV_COLOR(rgb2yuv, r, g, b, 255, 0) + * (1 << (bits - 8))); + color_yuv[1] = + rint(MP_MAP_RGB2YUV_COLOR(rgb2yuv, r, g, b, 255, 1) + * (1 << (bits - 8))); + color_yuv[2] = + rint(MP_MAP_RGB2YUV_COLOR(rgb2yuv, r, g, b, 255, 2) + * (1 << (bits - 8))); + *color_a = 255 - a; + // NOTE: these overflows can actually happen (when subtitles use color + // 0,0,0 while output levels only allows 16,16,16 upwards...) + if (color_yuv[0] < 0) + color_yuv[0] = 0; + if (color_yuv[1] < 0) + color_yuv[1] = 0; + if (color_yuv[2] < 0) + color_yuv[2] = 0; + if (*color_a < 0) + *color_a = 0; + if (color_yuv[0] > ((1 << bits) - 1)) + color_yuv[0] = ((1 << bits) - 1); + if (color_yuv[1] > ((1 << bits) - 1)) + color_yuv[1] = ((1 << bits) - 1); + if (color_yuv[2] > ((1 << bits) - 1)) + color_yuv[2] = ((1 << bits) - 1); + if (*color_a > 255) + *color_a = 255; + return true; + } else + return false; +} + +static void mp_image_crop(struct mp_image *img, int x, int y, int w, int h) +{ + int p; + for (p = 0; p < img->num_planes; ++p) { + int bits = MP_IMAGE_BITS_PER_PIXEL_ON_PLANE(img, p); + img->planes[p] += + (y >> (p ? img->chroma_y_shift : 0)) * img->stride[p] + + ((x >> (p ? img->chroma_x_shift : 0)) * bits) / 8; + } + img->w = w; + img->h = h; +} + +static bool clip_to_bounds(int *x, int *y, int *w, int *h, + int bx, int by, int bw, int bh) +{ + if (*x < bx) { + *w += *x - bx; + *x = bx; + } + if (*y < 0) { + *h += *y - by; + *y = by; + } + if (*x + *w > bx + bw) + *w = bx + bw - *x; + if (*y + *h > by + bh) + *h = by + bh - *y; + + if (*w <= 0 || *h <= 0) + return false; // nothing left + + return true; +} + +static void get_swscale_requirements(int *sx, int *sy, + const struct mp_image *img) +{ + int p; + + if (img->chroma_x_shift == 31) + *sx = 1; + else + *sx = (1 << img->chroma_x_shift); + + if (img->chroma_y_shift == 31) + *sy = 1; + else + *sy = (1 << img->chroma_y_shift); + + for (p = 0; p < img->num_planes; ++p) { + int bits = MP_IMAGE_BITS_PER_PIXEL_ON_PLANE(img, p); + while (((*sx >> img->chroma_x_shift) * bits) % (SWS_MIN_BYTE_ALIGN * 8)) + *sx *= 2; + } +} + +static void align_bbox(int *x1, int *y1, int *x2, int *y2, int xstep, int ystep) +{ + *x1 -= (*x1 % xstep); + *y1 -= (*y1 % ystep); + + *x2 += xstep - 1; + *y2 += ystep - 1; + *x2 -= (*x2 % xstep); + *y2 -= (*y2 % ystep); +} + +static bool align_bbox_to_swscale_requirements(int *x1, int *y1, + int *x2, int *y2, + struct mp_image *img) +{ + int xstep, ystep; + get_swscale_requirements(&xstep, &ystep, img); + align_bbox(x1, y1, x2, y2, xstep, ystep); + + if (*x1 < 0) + *x1 = 0; + if (*y1 < 0) + *y1 = 0; + if (*x2 > img->w) + *x2 = img->w; + if (*y2 > img->h) + *y2 = img->h; + + return (*x2 > *x1) && (*y2 > *y1); +} + +void mp_draw_sub_bitmaps(struct mp_image *dst, struct sub_bitmaps *sbs, + struct mp_csp_details *csp) +{ + int i; + int x1, y1, x2, y2; + int color_yuv[3]; + int color_a; + float yuv2rgb[3][4]; + float rgb2yuv[3][4]; + +#ifdef ACCURATE + int format = IMGFMT_444P16; + int bits = 16; + // however, we can try matching 8bit, 9bit, 10bit yuv formats! + if (dst->flags & MP_IMGFLAG_YUV) { + if (mp_get_chroma_shift(dst->imgfmt, NULL, NULL, &bits)) { + switch (bits) { + case 8: + format = IMGFMT_444P; + break; + case 9: + format = IMGFMT_444P9; + break; + case 10: + format = IMGFMT_444P10; + break; + default: + // revert back + bits = 16; + break; + } + } + } +#else + int format = IMGFMT_444P; + int bits = 8; +#endif + int bytes = (bits + 7) / 8; + + struct mp_csp_params cspar = { + .colorspace = *csp, + .brightness = 0, .contrast = 1, + .hue = 0, .saturation = 1, + .rgamma = 1, .ggamma = 1, .bgamma = 1, + .texture_bits = 8, .input_bits = 8 + }; + + // prepare YUV/RGB conversion values + mp_get_yuv2rgb_coeffs(&cspar, yuv2rgb); + mp_invert_yuv2rgb(rgb2yuv, yuv2rgb); + + //mp_msg(MSGT_VO, MSGL_ERR, "%f %f %f %f // %f %f %f %f // %f %f %f %f\n", + // rgb2yuv[0][0], + // rgb2yuv[0][1], + // rgb2yuv[0][2], + // rgb2yuv[0][3], + // rgb2yuv[1][0], + // rgb2yuv[1][1], + // rgb2yuv[1][2], + // rgb2yuv[1][3], + // rgb2yuv[2][0], + // rgb2yuv[2][1], + // rgb2yuv[2][2], + // rgb2yuv[2][3]); + + // calculate bounding range + if (!sub_bitmaps_bb(sbs, &x1, &y1, &x2, &y2)) + return; + + if (!align_bbox_to_swscale_requirements(&x1, &y1, &x2, &y2, dst)) + return; // nothing to do + + // convert to a temp image + mp_image_t *temp; + mp_image_t dst_region = *dst; + if (dst->imgfmt == format) { + mp_image_crop(&dst_region, x1, y1, x2 - x1, y2 - y1); + temp = &dst_region; + } else { + mp_image_crop(&dst_region, x1, y1, x2 - x1, y2 - y1); + temp = alloc_mpi(x2 - x1, y2 - y1, format); + mp_image_swscale(temp, &dst_region, csp, SWS_POINT); // chroma up + } + + for (i = 0; i < sbs->num_parts; ++i) { + struct sub_bitmap *sb = &sbs->parts[i]; + mp_image_t *sbi = NULL; + mp_image_t *sba = NULL; + + // cut off areas outside the image + int dst_x = sb->x - x1; // coordinates are relative to the bbox + int dst_y = sb->y - y1; // coordinates are relative to the bbox + int dst_w = sb->dw; + int dst_h = sb->dh; + if (!clip_to_bounds(&dst_x, &dst_y, &dst_w, &dst_h, + 0, 0, temp->w, temp->h)) + continue; + + if (!sub_bitmap_to_mp_images(&sbi, color_yuv, &color_a, &sba, sb, + sbs->format, csp, rgb2yuv, format, bits)) { + mp_msg(MSGT_VO, MSGL_ERR, + "render_sub_bitmap: invalid sub bitmap type\n"); + continue; + } + + // call blend_alpha 3 times + int p; + int src_x = (dst_x + x1) - sb->x; + int src_y = (dst_y + y1) - sb->y; + unsigned char *alpha_p = + sba->planes[0] + src_y * sba->stride[0] + src_x; + for (p = 0; p < 3; ++p) { + unsigned char *dst_p = + temp->planes[p] + dst_y * temp->stride[p] + dst_x * bytes; + if (sbi) { + unsigned char *src_p = + sbi->planes[p] + src_y * sbi->stride[p] + src_x * bytes; + blend_src_alpha( + dst_p, temp->stride[p], + src_p, sbi->stride[p], + alpha_p, sba->stride[0], + dst_h, dst_w, bytes + ); + } else { + blend_const_alpha( + dst_p, temp->stride[p], + color_yuv[p], + alpha_p, sba->stride[0], color_a, + dst_h, dst_w, bytes + ); + } + } + + if (sbi) + free_mp_image(sbi); + if (sba) + free_mp_image(sba); + } + + if (temp != &dst_region) { + // convert back + mp_image_swscale(&dst_region, temp, csp, SWS_AREA); // chroma down + + // clean up + free_mp_image(temp); + } +} + +// vim: ts=4 sw=4 et tw=80 diff --git a/sub/draw_bmp.h b/sub/draw_bmp.h new file mode 100644 index 0000000000..478965af15 --- /dev/null +++ b/sub/draw_bmp.h @@ -0,0 +1,12 @@ +#ifndef MPLAYER_DRAW_BMP_H +#define MPLAYER_DRAW_BMP_H + +struct mp_image; +struct sub_bitmaps; +struct mp_csp_details; +void mp_draw_sub_bitmaps(struct mp_image *dst, struct sub_bitmaps *sbs, + struct mp_csp_details *csp); + +#endif /* MPLAYER_DRAW_BMP_H */ + +// vim: ts=4 sw=4 et tw=80 From 34d974032b45131331794364fe408008c96d96e9 Mon Sep 17 00:00:00 2001 From: wm4 Date: Wed, 24 Oct 2012 20:20:13 +0200 Subject: [PATCH 33/83] csputils: cosmetic changes --- libvo/csputils.c | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/libvo/csputils.c b/libvo/csputils.c index 58b29bfeaa..b894a2f869 100644 --- a/libvo/csputils.c +++ b/libvo/csputils.c @@ -3,6 +3,8 @@ * * Copyleft (C) 2009 Reimar Döffinger * + * mp_invert_yuv2rgb based on DarkPlaces engine, original code (GPL2 or later) + * * This file is part of MPlayer. * * MPlayer is free software; you can redistribute it and/or modify @@ -29,7 +31,6 @@ #include #include #include -#include "mp_msg.h" #include "csputils.h" @@ -321,11 +322,6 @@ int mp_csp_equalizer_set(struct mp_csp_equalizer *eq, const char *property, void mp_invert_yuv2rgb(float out[3][4], float in[3][4]) { - // this is from the DarkPlaces engine, reduces to 3x3. Original code - // released under GPL2 or any later version. - float det; - - // this seems to help gcc's common subexpression elimination, and also makes the code look nicer float m00 = in[0][0], m01 = in[0][1], m02 = in[0][2], m03 = in[0][3], m10 = in[1][0], m11 = in[1][1], m12 = in[1][2], m13 = in[1][3], m20 = in[2][0], m21 = in[2][1], m22 = in[2][2], m23 = in[2][3]; @@ -341,17 +337,11 @@ void mp_invert_yuv2rgb(float out[3][4], float in[3][4]) out[2][1] = -(m00 * m21 - m20 * m01); out[2][2] = (m00 * m11 - m10 * m01); - // calculate the determinant (as inverse == 1/det * adjoint, adjoint * m == identity * det, so this calculates the det) - det = m00 * out[0][0] + m10 * out[0][1] + m20 * out[0][2]; - if (det == 0.0f) { - //mp_msg(MSGT_VO, MSGL_ERR, "cannot invert yuv2rgb matrix\n"); - return; - } - - // multiplications are faster than divisions, usually + // calculate the determinant (as inverse == 1/det * adjoint, + // adjoint * m == identity * det, so this calculates the det) + float det = m00 * out[0][0] + m10 * out[0][1] + m20 * out[0][2]; det = 1.0f / det; - // manually unrolled loop to multiply all matrix elements by 1/det out[0][0] *= det; out[0][1] *= det; out[0][2] *= det; From 0e72b0d5d3aeae5c4a04ca1baceda3ceb2d63ce3 Mon Sep 17 00:00:00 2001 From: wm4 Date: Wed, 17 Oct 2012 14:06:03 +0200 Subject: [PATCH 34/83] draw_bmp: compensate for libswscale writing past image bounds libswscale tends to overwrite the area between (w,y)-(0,y+1). It tries to process multiple pixels at once, and if the memory past the last x pixel is inside a SIMD operation, but still below the image stride, it overwrites that data with black. This happens with vo_x11 and 32 bit RGBA formats. The bug is visible as black bar right of the subtitle bounding box. Fix by giving libswscale more alignment. Then the "outside" pixels are inside, and are processed normally instead of overwritten with black. NOTE: we do not increase the alignment constant, because this is a separate issue from pointer alignment. libavutil's av_malloc() wouldn't actually satisfy the increased alignment either. --- sub/draw_bmp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sub/draw_bmp.c b/sub/draw_bmp.c index 8612336dfa..fba3513ee4 100644 --- a/sub/draw_bmp.c +++ b/sub/draw_bmp.c @@ -393,7 +393,8 @@ static void get_swscale_requirements(int *sx, int *sy, for (p = 0; p < img->num_planes; ++p) { int bits = MP_IMAGE_BITS_PER_PIXEL_ON_PLANE(img, p); - while (((*sx >> img->chroma_x_shift) * bits) % (SWS_MIN_BYTE_ALIGN * 8)) + // the * 2 fixes problems with writing past the destination width + while (((*sx >> img->chroma_x_shift) * bits) % (SWS_MIN_BYTE_ALIGN * 8 * 2)) *sx *= 2; } } From c139cd2b936a6824238264aa974aa5cfa55caa25 Mon Sep 17 00:00:00 2001 From: wm4 Date: Sun, 7 Oct 2012 03:26:46 +0200 Subject: [PATCH 35/83] sub: add function to draw OSD into an image The osd_draw_on_image() function renders the full OSD into the provided image. It uses the mp_draw_sub_bitmaps() function added in the previous commit to do the actual work. --- sub/sub.c | 25 +++++++++++++++++++++++++ sub/sub.h | 6 ++++++ 2 files changed, 31 insertions(+) diff --git a/sub/sub.c b/sub/sub.c index b37ec07747..f175563974 100644 --- a/sub/sub.c +++ b/sub/sub.c @@ -37,6 +37,7 @@ #include "sub.h" #include "dec_sub.h" #include "img_convert.h" +#include "draw_bmp.h" #include "spudec.h" @@ -300,6 +301,30 @@ void draw_osd_with_eosd(struct vo *vo, struct osd_state *osd) } } +// Returns whether anything was drawn. +bool osd_draw_on_image(struct osd_state *osd, struct mp_image *dest, + struct mp_csp_details *dest_csp, + struct sub_render_params *sub_params) +{ + static const bool formats[SUBBITMAP_COUNT] = { + [SUBBITMAP_LIBASS] = true, + [SUBBITMAP_RGBA] = true, + }; + bool changed = false; + osd_update_ext(osd, sub_params->dim); + for (int n = 0; n < MAX_OSD_PARTS; n++) { + struct osd_object *obj = osd->objs[n]; + if (obj->is_sub && osd->render_subs_in_filter) + continue; + struct sub_bitmaps imgs; + if (render_object(osd, obj, &imgs, sub_params, formats)) { + mp_draw_sub_bitmaps(dest, &imgs, dest_csp); + changed = true; + } + } + return changed; +} + 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, diff --git a/sub/sub.h b/sub/sub.h index 649f196414..cc59077011 100644 --- a/sub/sub.h +++ b/sub/sub.h @@ -238,6 +238,12 @@ bool osd_draw_sub(struct osd_state *osd, struct sub_bitmaps *out_imgs, struct sub_render_params *sub_params, const bool formats[SUBBITMAP_COUNT]); +struct mp_image; +struct mp_csp_details; +bool osd_draw_on_image(struct osd_state *osd, struct mp_image *dest, + struct mp_csp_details *dest_csp, + struct sub_render_params *sub_params); + bool sub_bitmaps_bb(struct sub_bitmaps *imgs, int *x1, int *y1, int *x2, int *y2); From fef1871d3f1f0a1477fc764e8d83a008337045f8 Mon Sep 17 00:00:00 2001 From: Rudolf Polzer Date: Wed, 24 Oct 2012 19:25:24 +0200 Subject: [PATCH 36/83] vo_lavc: use new OSD API Merged by wm4 from commits c93978f17b76 and following. --- libvo/vo_lavc.c | 133 ++++++++++++++++++------------------------------ 1 file changed, 50 insertions(+), 83 deletions(-) diff --git a/libvo/vo_lavc.c b/libvo/vo_lavc.c index 5b467f1f6a..4cf4003031 100644 --- a/libvo/vo_lavc.c +++ b/libvo/vo_lavc.c @@ -34,6 +34,7 @@ #include "encode_lavc.h" #include "sub/sub.h" +#include "sub/draw_bmp.h" #include "libvo/osd.h" struct priv { @@ -49,13 +50,12 @@ struct priv { int64_t lastframeipts; double expected_next_pts; mp_image_t *lastimg; + int lastimg_wants_osd; int lastdisplaycount; AVRational worst_time_base; int worst_time_base_is_stream; - struct osd_state *osd; - struct mp_csp_details colorspace; }; @@ -156,12 +156,13 @@ static int config(struct vo *vo, uint32_t width, uint32_t height, encode_lavc_set_csp(vo->encode_lavc_ctx, vc->stream, vc->colorspace.format); encode_lavc_set_csp_levels(vo->encode_lavc_ctx, vc->stream, vc->colorspace.levels_out); - vc->colorspace.format = encode_lavc_get_csp(vo->encode_lavc_ctx, vc->stream); - vc->colorspace.levels_out = encode_lavc_get_csp_levels(vo->encode_lavc_ctx, vc->stream); if (encode_lavc_open_codec(vo->encode_lavc_ctx, vc->stream) < 0) goto error; + vc->colorspace.format = encode_lavc_get_csp(vo->encode_lavc_ctx, vc->stream); + vc->colorspace.levels_out = encode_lavc_get_csp_levels(vo->encode_lavc_ctx, vc->stream); + vc->buffer_size = 6 * width * height + 200; if (vc->buffer_size < FF_MIN_BUFFER_SIZE) vc->buffer_size = FF_MIN_BUFFER_SIZE; @@ -191,8 +192,18 @@ static int query_format(struct vo *vo, uint32_t format) if (!vo->encode_lavc_ctx) return 0; - return encode_lavc_supports_pixfmt(vo->encode_lavc_ctx, pix_fmt) ? - VFCAP_CSP_SUPPORTED : 0; + if (!encode_lavc_supports_pixfmt(vo->encode_lavc_ctx, pix_fmt)) + return 0; + + return + VFCAP_CSP_SUPPORTED | + // we can do it + VFCAP_CSP_SUPPORTED_BY_HW | + // we don't convert colorspaces here (TODO: if we add EOSD rendering, only set this flag if EOSD can be rendered without extra conversions) + VFCAP_OSD | VFCAP_EOSD | + // we have OSD + VOCAP_NOSLICES; + // we don't use slices } static void write_packet(struct vo *vo, int size, AVPacket *packet) @@ -275,63 +286,6 @@ static int encode_video(struct vo *vo, AVFrame *frame, AVPacket *packet) } } -static void add_osd_to_lastimg_draw_func(void *ctx, int x0,int y0, int w,int h,unsigned char* src, unsigned char *srca, int stride){ - struct priv *vc = ctx; - unsigned char* dst; - if(w<=0 || h<=0) return; // nothing to do... - // printf("OSD redraw: %d;%d %dx%d \n",x0,y0,w,h); - dst=vc->lastimg->planes[0]+ - vc->lastimg->stride[0]*y0+ - (vc->lastimg->bpp>>3)*x0; - switch(vc->lastimg->imgfmt){ - case IMGFMT_BGR12: - case IMGFMT_RGB12: - vo_draw_alpha_rgb12(w, h, src, srca, stride, dst, vc->lastimg->stride[0]); - break; - case IMGFMT_BGR15: - case IMGFMT_RGB15: - vo_draw_alpha_rgb15(w,h,src,srca,stride,dst,vc->lastimg->stride[0]); - break; - case IMGFMT_BGR16: - case IMGFMT_RGB16: - vo_draw_alpha_rgb16(w,h,src,srca,stride,dst,vc->lastimg->stride[0]); - break; - case IMGFMT_BGR24: - case IMGFMT_RGB24: - vo_draw_alpha_rgb24(w,h,src,srca,stride,dst,vc->lastimg->stride[0]); - break; - case IMGFMT_BGR32: - case IMGFMT_RGB32: - vo_draw_alpha_rgb32(w,h,src,srca,stride,dst,vc->lastimg->stride[0]); - break; - case IMGFMT_YV12: - case IMGFMT_I420: - case IMGFMT_IYUV: - case IMGFMT_YVU9: - case IMGFMT_IF09: - case IMGFMT_Y800: - case IMGFMT_Y8: - vo_draw_alpha_yv12(w,h,src,srca,stride,dst,vc->lastimg->stride[0]); - break; - case IMGFMT_YUY2: - vo_draw_alpha_yuy2(w,h,src,srca,stride,dst,vc->lastimg->stride[0]); - break; - case IMGFMT_UYVY: - vo_draw_alpha_yuy2(w,h,src,srca,stride,dst+1,vc->lastimg->stride[0]); - break; - default: - mp_msg(MSGT_ENCODE, MSGL_WARN, "vo-lavc: tried to draw OSD on an usnupported pixel format\n"); - } -} - -static void add_osd_to_lastimg(struct vo *vo) -{ - struct priv *vc = vo->priv; - if(vc->osd) { - osd_draw_text(vc->osd, vc->lastimg->w, vc->lastimg->h, add_osd_to_lastimg_draw_func, vc); - } -} - static void draw_image(struct vo *vo, mp_image_t *mpi, double pts) { struct priv *vc = vo->priv; @@ -503,7 +457,7 @@ static void draw_image(struct vo *vo, mp_image_t *mpi, double pts) "vo-lavc: Frame at pts %d got displayed %d times\n", (int) vc->lastframeipts, vc->lastdisplaycount); copy_mpi(vc->lastimg, mpi); - add_osd_to_lastimg(vo); + vc->lastimg_wants_osd = true; // palette hack if (vc->lastimg->imgfmt == IMGFMT_RGB8 || @@ -516,12 +470,22 @@ static void draw_image(struct vo *vo, mp_image_t *mpi, double pts) vc->lastipts = -1; } vc->lastdisplaycount = 0; - } else + } else { mp_msg(MSGT_ENCODE, MSGL_INFO, "vo-lavc: Frame at pts %d got dropped " "entirely because pts went backwards\n", (int) frameipts); + vc->lastimg_wants_osd = false; + } } } +static void flip_page_timed(struct vo *vo, unsigned int pts_us, int duration) +{ +} + +static void check_events(struct vo *vo) +{ +} + static int control(struct vo *vo, uint32_t request, void *data) { struct priv *vc = vo->priv; @@ -543,26 +507,29 @@ static int control(struct vo *vo, uint32_t request, void *data) case VOCTRL_GET_YUV_COLORSPACE: *(struct mp_csp_details *)data = vc->colorspace; return 1; + case VOCTRL_DRAW_EOSD: + if (vc->lastimg && vc->lastimg_wants_osd) { + struct sub_bitmaps *imgs = data; + mp_draw_sub_bitmaps(vc->lastimg, imgs, &vc->colorspace); + } + return VO_TRUE; + case VOCTRL_GET_EOSD_RES: { + struct mp_eosd_res *r = data; + r->w = vc->stream->codec->width; + r->h = vc->stream->codec->height; + r->ml = r->mr = 0; + r->mt = r->mb = 0; + return VO_TRUE; + } + case VOCTRL_QUERY_EOSD_FORMAT: { + int format = *(int *)data; + return (format == SUBBITMAP_LIBASS || format == SUBBITMAP_RGBA) + ? VO_TRUE : VO_NOTIMPL; + } } return VO_NOTIMPL; } -static void draw_osd(struct vo *vo, struct osd_state *osd) -{ - struct priv *vc = vo->priv; - vc->osd = osd; - if(vc->lastimg) - osd_update(vc->osd, vc->lastimg->w, vc->lastimg->h); -} - -static void flip_page_timed(struct vo *vo, unsigned int pts_us, int duration) -{ -} - -static void check_events(struct vo *vo) -{ -} - const struct vo_driver video_out_lavc = { .is_new = true, .buffer_frames = false, @@ -577,8 +544,8 @@ const struct vo_driver video_out_lavc = { .control = control, .uninit = uninit, .check_events = check_events, - .draw_osd = draw_osd, + .draw_osd = draw_osd_with_eosd, .flip_page_timed = flip_page_timed, }; -// vim: sw=4 ts=4 et +// vim: sw=4 ts=4 et tw=80 From b03e357c69034807c455617cdd2a5700382f4670 Mon Sep 17 00:00:00 2001 From: wm4 Date: Sun, 7 Oct 2012 03:28:40 +0200 Subject: [PATCH 37/83] vo_xv: use new OSD API Aspect ratio stuff needs to be fixed later. "Fixing" the position of OSD elements outside of the screen due to panscan needs to be added back as well (what the removed fixup_osd_position() function did). The amount of data needed to "backup" an image when OSD is rendered increases. This is because we support color OSD/subtitles now. The old code rendered into the Y plane only, while the new code touches all 3 planes. For YV12, which is probably the only format supported not considering chroma-swapped and packed formats, 0.5 times more memory is copied when the OSD is used in pause mode. --- libvo/vo_xv.c | 139 ++++++++++++++------------------------------------ 1 file changed, 38 insertions(+), 101 deletions(-) diff --git a/libvo/vo_xv.c b/libvo/vo_xv.c index 42ddde890a..7c2d3816c4 100644 --- a/libvo/vo_xv.c +++ b/libvo/vo_xv.c @@ -51,6 +51,7 @@ #include "x11_common.h" #include "fastmemcpy.h" #include "sub/sub.h" +#include "sub/dec_sub.h" #include "aspect.h" #include "csputils.h" #include "subopt-helper.h" @@ -84,10 +85,6 @@ struct xvctx { struct vo_rect dst_rect; uint32_t max_width, max_height; // zero means: not set int mode_switched; - int osd_objects_drawn; - void (*draw_alpha_fnc)(void *ctx, int x0, int y0, int w, int h, - unsigned char *src, unsigned char *srca, - int stride); #ifdef HAVE_SHM XShmSegmentInfo Shminfo[2 + 1]; int Shmem_Flag; @@ -95,71 +92,6 @@ struct xvctx { }; static void allocate_xvimage(struct vo *, int); - - -static void fixup_osd_position(struct vo *vo, int *x0, int *y0, int *w, int *h) -{ - struct xvctx *ctx = vo->priv; - *x0 += ctx->image_width * (vo->panscan_x >> 1) - / (vo->dwidth + vo->panscan_x); - *w = av_clip(*w, 0, ctx->image_width); - *h = av_clip(*h, 0, ctx->image_height); - *x0 = FFMIN(*x0, ctx->image_width - *w); - *y0 = FFMIN(*y0, ctx->image_height - *h); -} - -static void draw_alpha_yv12(void *p, int x0, int y0, int w, int h, - unsigned char *src, unsigned char *srca, - int stride) -{ - struct vo *vo = p; - struct xvctx *ctx = vo->priv; - fixup_osd_position(vo, &x0, &y0, &w, &h); - vo_draw_alpha_yv12(w, h, src, srca, stride, - ctx->xvimage[ctx->current_buf]->data + - ctx->xvimage[ctx->current_buf]->offsets[0] + - ctx->xvimage[ctx->current_buf]->pitches[0] * y0 + x0, - ctx->xvimage[ctx->current_buf]->pitches[0]); - ctx->osd_objects_drawn++; -} - -static void draw_alpha_yuy2(void *p, int x0, int y0, int w, int h, - unsigned char *src, unsigned char *srca, - int stride) -{ - struct vo *vo = p; - struct xvctx *ctx = vo->priv; - fixup_osd_position(vo, &x0, &y0, &w, &h); - vo_draw_alpha_yuy2(w, h, src, srca, stride, - ctx->xvimage[ctx->current_buf]->data + - ctx->xvimage[ctx->current_buf]->offsets[0] + - ctx->xvimage[ctx->current_buf]->pitches[0] * y0 + 2 * x0, - ctx->xvimage[ctx->current_buf]->pitches[0]); - ctx->osd_objects_drawn++; -} - -static void draw_alpha_uyvy(void *p, int x0, int y0, int w, int h, - unsigned char *src, unsigned char *srca, - int stride) -{ - struct vo *vo = p; - struct xvctx *ctx = vo->priv; - fixup_osd_position(vo, &x0, &y0, &w, &h); - vo_draw_alpha_yuy2(w, h, src, srca, stride, - ctx->xvimage[ctx->current_buf]->data + - ctx->xvimage[ctx->current_buf]->offsets[0] + - ctx->xvimage[ctx->current_buf]->pitches[0] * y0 + 2 * x0 + 1, - ctx->xvimage[ctx->current_buf]->pitches[0]); - ctx->osd_objects_drawn++; -} - -static void draw_alpha_null(void *p, int x0, int y0, int w, int h, - unsigned char *src, unsigned char *srca, - int stride) -{ -} - - static void deallocate_xvimage(struct vo *vo, int foo); static void resize(struct vo *vo) @@ -261,23 +193,6 @@ static int config(struct vo *vo, uint32_t width, uint32_t height, mp_msg(MSGT_VO, MSGL_V, "using Xvideo port %d for hw scaling\n", x11->xv_port); - switch (ctx->xv_format) { - case IMGFMT_YV12: - case IMGFMT_I420: - case IMGFMT_IYUV: - ctx->draw_alpha_fnc = draw_alpha_yv12; - break; - case IMGFMT_YUY2: - case IMGFMT_YVYU: - ctx->draw_alpha_fnc = draw_alpha_yuy2; - break; - case IMGFMT_UYVY: - ctx->draw_alpha_fnc = draw_alpha_uyvy; - break; - default: - ctx->draw_alpha_fnc = draw_alpha_null; - } - // In case config has been called before for (i = 0; i < ctx->total_buffers; i++) deallocate_xvimage(vo, i); @@ -383,16 +298,32 @@ static inline void put_xvimage(struct vo *vo, XvImage *xvi) } } -// Only copies luma for planar formats as draw_alpha doesn't change others */ -static void copy_backup_image(struct vo *vo, int dest, int src) +static struct mp_image get_xv_buffer(struct vo *vo, int buf_index) { struct xvctx *ctx = vo->priv; + XvImage *xv_image = ctx->xvimage[buf_index]; - XvImage *vb = ctx->xvimage[dest]; - XvImage *cp = ctx->xvimage[src]; - memcpy_pic(vb->data + vb->offsets[0], cp->data + cp->offsets[0], - vb->width, vb->height, - vb->pitches[0], cp->pitches[0]); + struct mp_image img = {0}; + img.w = img.width = xv_image->width; + img.h = img.height = xv_image->height; + mp_image_setfmt(&img, ctx->image_format); + + bool swapuv = ctx->image_format == IMGFMT_YV12; + for (int n = 0; n < img.num_planes; n++) { + int sn = n > 0 && swapuv ? (n == 1 ? 2 : 1) : n; + img.planes[n] = xv_image->data + xv_image->offsets[sn]; + img.stride[n] = xv_image->pitches[sn]; + } + + return img; +} + +static void copy_backup_image(struct vo *vo, int dest, int src) +{ + struct mp_image img_dest = get_xv_buffer(vo, dest); + struct mp_image img_src = get_xv_buffer(vo, src); + + copy_mpi(&img_dest, &img_src); } static void check_events(struct vo *vo) @@ -409,13 +340,19 @@ static void draw_osd(struct vo *vo, struct osd_state *osd) { struct xvctx *ctx = vo->priv; - ctx->osd_objects_drawn = 0; - osd_draw_text(osd, - ctx->image_width - - ctx->image_width * vo->panscan_x / (vo->dwidth + - vo->panscan_x), - ctx->image_height, ctx->draw_alpha_fnc, vo); - if (ctx->osd_objects_drawn) + struct mp_image img = get_xv_buffer(vo, ctx->current_buf); + + struct mp_csp_details csp = {0}; + vo_control(vo, VOCTRL_GET_YUV_COLORSPACE, &csp); + + struct sub_render_params subparams = { + .pts = osd->vo_sub_pts, + .dim = {.w = ctx->image_width, .h = ctx->image_height}, + .normal_scale = 1, + .vsfilter_scale = 1, + }; + + if (osd_draw_on_image(osd, &img, &csp, &subparams)) ctx->unchanged_image = false; } @@ -553,7 +490,7 @@ static uint32_t draw_image(struct vo *vo, mp_image_t *mpi) static int query_format(struct xvctx *ctx, uint32_t format) { uint32_t i; - int flag = VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW | VFCAP_HWSCALE_UP | VFCAP_HWSCALE_DOWN | VFCAP_OSD | VFCAP_ACCEPT_STRIDE; // FIXME! check for DOWN + int flag = VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW | VFCAP_HWSCALE_UP | VFCAP_HWSCALE_DOWN | VFCAP_OSD | VFCAP_EOSD | VFCAP_ACCEPT_STRIDE; // FIXME! check for DOWN /* check image formats */ for (i = 0; i < ctx->formats; i++) { From a45ad346e4158708b1ede75fcd6e8ec3c05d1d9e Mon Sep 17 00:00:00 2001 From: wm4 Date: Sun, 7 Oct 2012 04:33:46 +0200 Subject: [PATCH 38/83] vo_xv: simplify screenshot code We now have a simple function to get a XvImage buffer as mp_image. Return that as screenshot. We don't even need to copy the image (we allocate a mp_image struct only, no image data). --- libvo/vo_xv.c | 40 +++++----------------------------------- 1 file changed, 5 insertions(+), 35 deletions(-) diff --git a/libvo/vo_xv.c b/libvo/vo_xv.c index 7c2d3816c4..e12f8cbaf8 100644 --- a/libvo/vo_xv.c +++ b/libvo/vo_xv.c @@ -422,42 +422,12 @@ static mp_image_t *get_screenshot(struct vo *vo) struct xvctx *ctx = vo->priv; // try to get an image without OSD - if (ctx->have_image_copy) - copy_backup_image(vo, ctx->visible_buf, ctx->num_buffers); + int id = ctx->have_image_copy ? ctx->num_buffers : ctx->visible_buf; + struct mp_image img = get_xv_buffer(vo, id); + img.w = ctx->image_d_width; + img.h = ctx->image_d_height; - XvImage *xv_image = ctx->xvimage[ctx->visible_buf]; - - int w = xv_image->width; - int h = xv_image->height; - - mp_image_t *image = alloc_mpi(w, h, ctx->image_format); - - int bytes = 1; - if (!(image->flags & MP_IMGFLAG_PLANAR) && (image->flags & MP_IMGFLAG_YUV)) - // packed YUV - bytes = image->bpp / 8; - - memcpy_pic(image->planes[0], xv_image->data + xv_image->offsets[0], - bytes * w, h, image->stride[0], xv_image->pitches[0]); - - if (image->flags & MP_IMGFLAG_PLANAR) { - int swap = ctx->image_format == IMGFMT_YV12; - int p1 = swap ? 2 : 1; - int p2 = swap ? 1 : 2; - - w /= 2; - h /= 2; - - memcpy_pic(image->planes[p1], xv_image->data + xv_image->offsets[1], - w, h, image->stride[p1], xv_image->pitches[1]); - memcpy_pic(image->planes[p2], xv_image->data + xv_image->offsets[2], - w, h, image->stride[p2], xv_image->pitches[2]); - } - - image->w = ctx->image_d_width; - image->h = ctx->image_d_height; - - return image; + return talloc_memdup(NULL, &img, sizeof(img)); } static uint32_t draw_image(struct vo *vo, mp_image_t *mpi) From d5e47632430b93a03748007748ee1fc122932712 Mon Sep 17 00:00:00 2001 From: wm4 Date: Sun, 7 Oct 2012 21:24:22 +0200 Subject: [PATCH 39/83] vo_x11: use new OSD API --- libvo/vo_x11.c | 84 +++++++++++++++----------------------------------- 1 file changed, 25 insertions(+), 59 deletions(-) diff --git a/libvo/vo_x11.c b/libvo/vo_x11.c index d43601f7c2..c23dd47fd2 100644 --- a/libvo/vo_x11.c +++ b/libvo/vo_x11.c @@ -24,6 +24,7 @@ #include "config.h" #include "video_out.h" #include "aspect.h" +#include "csputils.h" #include "osd.h" #include "libmpcodecs/mp_image.h" #include "libmpcodecs/vfcap.h" @@ -42,6 +43,8 @@ #endif #include "sub/sub.h" +#include "sub/dec_sub.h" +#include "sub/draw_bmp.h" #include "libmpcodecs/sws_utils.h" #define MODE_RGB 0x1 @@ -113,42 +116,6 @@ static void check_events(struct vo *vo) flip_page(vo); } -static void draw_alpha_32(int x0, int y0, int w, int h, unsigned char *src, - unsigned char *srca, int stride, - unsigned char *dst, uint32_t dst_width) -{ - vo_draw_alpha_rgb32(w, h, src, srca, stride, - dst + 4 * (y0 * dst_width + x0), - 4 * dst_width); -} - -static void draw_alpha_24(int x0, int y0, int w, int h, unsigned char *src, - unsigned char *srca, int stride, - unsigned char *dst, uint32_t dst_width) -{ - vo_draw_alpha_rgb24(w, h, src, srca, stride, - dst + 3 * (y0 * dst_width + x0), - 3 * dst_width); -} - -static void draw_alpha_16(int x0, int y0, int w, int h, unsigned char *src, - unsigned char *srca, int stride, - unsigned char *dst, uint32_t dst_width) -{ - vo_draw_alpha_rgb16(w, h, src, srca, stride, - dst + 2 * (y0 * dst_width + x0), - 2 * dst_width); -} - -static void draw_alpha_15(int x0, int y0, int w, int h, unsigned char *src, - unsigned char *srca, int stride, - unsigned char *dst, uint32_t dst_width) -{ - vo_draw_alpha_rgb15(w, h, src, srca, stride, - dst + 2 * (y0 * dst_width + x0), - 2 * dst_width); -} - static void getMyXImage(struct priv *p) { struct vo *vo = p->vo; @@ -457,36 +424,35 @@ static void Display_Image(struct priv *p, XImage *myximage, uint8_t *ImageData) p->myximage->data -= p->out_offset; } -static void draw_osd_elem(void *ctx, int x0, int y0, int w, int h, - unsigned char *src, unsigned char *srca, int stride) +static struct mp_image get_x_buffer(struct priv *p) { - struct priv *p = ctx; + struct mp_image img = {0}; + img.w = img.width = p->image_width; + img.h = img.height = p->image_height; + mp_image_setfmt(&img, p->out_format); - switch (p->myximage->bits_per_pixel) { - case 24: - draw_alpha_24(x0, y0, w, h, src, srca, stride, p->ImageData, - p->image_width); - break; - case 32: - draw_alpha_32(x0, y0, w, h, src, srca, stride, p->ImageData, - p->image_width); - break; - case 15: - draw_alpha_15(x0, y0, w, h, src, srca, stride, p->ImageData, - p->image_width); - break; - case 16: - draw_alpha_16(x0, y0, w, h, src, srca, stride, p->ImageData, - p->image_width); - break; - default:; - } + img.planes[0] = p->ImageData; + img.stride[0] = p->image_width * ((p->bpp + 7) / 8); + + return img; } static void draw_osd(struct vo *vo, struct osd_state *osd) { struct priv *p = vo->priv; - osd_draw_text(osd, p->image_width, p->image_height, draw_osd_elem, p); + + struct mp_image img = get_x_buffer(p); + + struct mp_csp_details csp = MP_CSP_DETAILS_DEFAULTS; + + struct sub_render_params subparams = { + .pts = osd->vo_sub_pts, + .dim = {.w = img.w, .h = img.h}, + .normal_scale = 1, + .vsfilter_scale = 1, + }; + + osd_draw_on_image(osd, &img, &csp, &subparams); } static void flip_page(struct vo *vo) From 7b203b5e05d9873e279f8432d4ffb3d9facc5e23 Mon Sep 17 00:00:00 2001 From: wm4 Date: Sun, 7 Oct 2012 01:21:29 +0200 Subject: [PATCH 40/83] img_convert: fix alignment for RGBA images draw_bmp.c uses libswscale, which has strict alignment requirements on input images. Since imp_convert.c is currently the only producer of RGBA sub-bitmaps, the overall code becomes easier if the alignment is done on image allocation, rather than forcing draw_bmp.c to create an aligned copy. talloc doesn't align to 16 bytes, as required by libswscale. Apparently, system malloc (glibc/Linux/32 bit) aligns to 8 bytes only, so talloc's own code to align to 16 bytes is ineffective. Work around by using mp_image to allocate the image. --- sub/img_convert.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/sub/img_convert.c b/sub/img_convert.c index 888380cf70..9437226c64 100644 --- a/sub/img_convert.c +++ b/sub/img_convert.c @@ -26,6 +26,9 @@ #include "img_convert.h" #include "sub.h" #include "spudec.h" +#include "libmpcodecs/img_format.h" +#include "libmpcodecs/mp_image.h" +#include "libmpcodecs/sws_utils.h" struct osd_conv_cache { struct sub_bitmap part; @@ -199,12 +202,14 @@ bool osd_conv_idx_to_rgba(struct osd_conv_cache *c, struct sub_bitmaps *imgs) rgba_to_premultiplied_rgba(sb.palette, 256); *d = *s; - d->stride = s->w * 4; - d->bitmap = talloc_size(c->parts, s->h * d->stride); + struct mp_image *image = alloc_mpi(s->w, s->h, IMGFMT_BGRA); + talloc_steal(c->parts, image); + d->stride = image->stride[0]; + d->bitmap = image->planes[0]; - uint32_t *outbmp = d->bitmap; for (int y = 0; y < s->h; y++) { uint8_t *inbmp = sb.bitmap + y * s->stride; + uint32_t *outbmp = (uint32_t*)((uint8_t*)d->bitmap + y * d->stride); for (int x = 0; x < s->w; x++) *outbmp++ = sb.palette[*inbmp++]; } From fd5c4a19849b768986a0e652bb2f398c922f42dd Mon Sep 17 00:00:00 2001 From: wm4 Date: Sun, 7 Oct 2012 22:02:03 +0200 Subject: [PATCH 41/83] Remove things related to old OSD To ease changing all the VOs to the new OSD rendering, fallbacks, conversions, support code etc. was left all over the code. Now that all VOs have been changed, all that code is inactive. Remove it. Strip down spudec.c. We don't need the old grayscale and scaling stuff anymore. (Not removing spudec itself yet - I'm not confident that the libavcodec DVD sub decoder is sufficient, and it would also require some hacks to get DVD palette and resolution information from libdvdread to libavcodec.) The option --spuaa, --spualign, --spugauss were used with the old sub scaling code, and don't do anything anymore. --- DOCS/man/en/options.rst | 24 -- Makefile | 1 - cfg-mplayer.h | 3 - libvo/osd.c | 224 ------------ libvo/osd.h | 34 -- libvo/osd_template.c | 383 -------------------- libvo/vo_corevideo.m | 1 - libvo/vo_lavc.c | 1 - libvo/vo_opengl.c | 1 - libvo/vo_opengl_old.c | 1 - libvo/vo_x11.c | 1 - libvo/vo_xv.c | 1 - sub/img_convert.c | 198 +---------- sub/img_convert.h | 3 - sub/spudec.c | 772 ---------------------------------------- sub/spudec.h | 18 - sub/sub.c | 52 --- sub/sub.h | 24 -- 18 files changed, 1 insertion(+), 1741 deletions(-) delete mode 100644 libvo/osd.c delete mode 100644 libvo/osd.h delete mode 100644 libvo/osd_template.c diff --git a/DOCS/man/en/options.rst b/DOCS/man/en/options.rst index ca245f6d32..3be707bfad 100644 --- a/DOCS/man/en/options.rst +++ b/DOCS/man/en/options.rst @@ -1781,30 +1781,6 @@ --speed=<0.01-100> Slow down or speed up playback by the factor given as parameter. ---spuaa= - Antialiasing/scaling mode for DVD/VOBsub. A value of 16 may be added to - in order to force scaling even when original and scaled frame size - already match. This can be employed to e.g. smooth subtitles with gaussian - blur. Available modes are: - - :0: none (fastest, very ugly) - :1: approximate (broken?) - :2: full (slow) - :3: bilinear (default, fast and not too bad) - :4: uses swscaler gaussian blur (looks very good) - ---spualign=<-1-2> - Specify how SPU (DVD/VOBsub) subtitles should be aligned. - - :-1: Original position - :0: Align at top (original behavior, default). - :1: Align at center. - :2: Align at bottom. - ---spugauss=<0.0-3.0> - Variance parameter of gaussian used by ``--spuaa=4``. Higher means more - blur (default: 1.0). - --srate= Select the output sample rate to be used (of course sound cards have limits on this). If the sample frequency selected is different from that diff --git a/Makefile b/Makefile index ecd33359c2..dd476d2a28 100644 --- a/Makefile +++ b/Makefile @@ -198,7 +198,6 @@ SRCS_COMMON = asxparser.c \ libmpdemux/mf.c \ libmpdemux/mp_taglists.c \ libmpdemux/video.c \ - libvo/osd.c \ libvo/bitmap_packer.c \ osdep/numcores.c \ osdep/io.c \ diff --git a/cfg-mplayer.h b/cfg-mplayer.h index 581f363148..975c11b9ff 100644 --- a/cfg-mplayer.h +++ b/cfg-mplayer.h @@ -532,9 +532,6 @@ const m_option_t common_opts[] = { {"ffactor", &font_factor, CONF_TYPE_FLOAT, CONF_RANGE, 0.0, 10.0, NULL}, {"sub-pos", &sub_pos, CONF_TYPE_INT, CONF_RANGE, 0, 100, NULL}, {"subwidth", &sub_width_p, CONF_TYPE_INT, CONF_RANGE, 10, 100, NULL}, - {"spualign", &spu_alignment, CONF_TYPE_INT, CONF_RANGE, -1, 2, NULL}, - {"spuaa", &spu_aamode, CONF_TYPE_INT, CONF_RANGE, 0, 31, NULL}, - {"spugauss", &spu_gaussvar, CONF_TYPE_FLOAT, CONF_RANGE, 0.0, 3.0, NULL}, {"subfont-encoding", &subtitle_font_encoding, CONF_TYPE_STRING, 0, 0, 0, NULL}, {"subfont-text-scale", &text_font_scale_factor, CONF_TYPE_FLOAT, CONF_RANGE, 0, 100, NULL}, {"subfont-osd-scale", &osd_font_scale_factor, CONF_TYPE_FLOAT, CONF_RANGE, 0, 100, NULL}, diff --git a/libvo/osd.c b/libvo/osd.c deleted file mode 100644 index 2fd294a13a..0000000000 --- a/libvo/osd.c +++ /dev/null @@ -1,224 +0,0 @@ -/* - * generic alpha renderers for all YUV modes and RGB depths - * These are "reference implementations", should be optimized later (MMX, etc). - * templating code by Michael Niedermayer (michaelni@gmx.at) - * - * 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, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include "config.h" -#include "osd.h" -#include "mp_msg.h" -#include -#include -#include "cpudetect.h" - -#if ARCH_X86 -static const uint64_t bFF __attribute__((aligned(8))) = 0xFFFFFFFFFFFFFFFFULL; -static const unsigned long long mask24lh __attribute__((aligned(8))) = 0xFFFF000000000000ULL; -static const unsigned long long mask24hl __attribute__((aligned(8))) = 0x0000FFFFFFFFFFFFULL; -#endif - -//Note: we have C, X86-nommx, MMX, MMX2 -//Plain C versions -#define COMPILE_C - -#if ARCH_X86 - -#define COMPILE_MMX -#define COMPILE_MMX2 - -#endif /* ARCH_X86 */ - -#undef HAVE_MMX -#undef HAVE_MMX2 -#define HAVE_MMX 0 -#define HAVE_MMX2 0 - -#if ! ARCH_X86 - -#ifdef COMPILE_C -#undef HAVE_MMX -#undef HAVE_MMX2 -#define HAVE_MMX 0 -#define HAVE_MMX2 0 -#define RENAME(a) a ## _C -#include "osd_template.c" -#endif - -#else - -//X86 noMMX versions -#ifdef COMPILE_C -#undef RENAME -#undef HAVE_MMX -#undef HAVE_MMX2 -#define HAVE_MMX 0 -#define HAVE_MMX2 0 -#define RENAME(a) a ## _X86 -#include "osd_template.c" -#endif - -//MMX versions -#ifdef COMPILE_MMX -#undef RENAME -#undef HAVE_MMX -#undef HAVE_MMX2 -#define HAVE_MMX 1 -#define HAVE_MMX2 0 -#define RENAME(a) a ## _MMX -#include "osd_template.c" -#endif - -//MMX2 versions -#ifdef COMPILE_MMX2 -#undef RENAME -#undef HAVE_MMX -#undef HAVE_MMX2 -#define HAVE_MMX 1 -#define HAVE_MMX2 1 -#define RENAME(a) a ## _MMX2 -#include "osd_template.c" -#endif - -#endif /* ARCH_X86 */ - -void vo_draw_alpha_yv12(int w,int h, unsigned char* src, unsigned char *srca, int srcstride, unsigned char* dstbase,int dststride){ -#if ARCH_X86 - // ordered by speed / fastest first - if(gCpuCaps.hasMMX2) - vo_draw_alpha_yv12_MMX2(w, h, src, srca, srcstride, dstbase, dststride); - else if(gCpuCaps.hasMMX) - vo_draw_alpha_yv12_MMX(w, h, src, srca, srcstride, dstbase, dststride); - else - vo_draw_alpha_yv12_X86(w, h, src, srca, srcstride, dstbase, dststride); -#else - vo_draw_alpha_yv12_C(w, h, src, srca, srcstride, dstbase, dststride); -#endif -} - -void vo_draw_alpha_yuy2(int w,int h, unsigned char* src, unsigned char *srca, int srcstride, unsigned char* dstbase,int dststride){ -#if ARCH_X86 - // ordered by speed / fastest first - if(gCpuCaps.hasMMX2) - vo_draw_alpha_yuy2_MMX2(w, h, src, srca, srcstride, dstbase, dststride); - else if(gCpuCaps.hasMMX) - vo_draw_alpha_yuy2_MMX(w, h, src, srca, srcstride, dstbase, dststride); - else - vo_draw_alpha_yuy2_X86(w, h, src, srca, srcstride, dstbase, dststride); -#else - vo_draw_alpha_yuy2_C(w, h, src, srca, srcstride, dstbase, dststride); -#endif -} - -void vo_draw_alpha_rgb24(int w,int h, unsigned char* src, unsigned char *srca, int srcstride, unsigned char* dstbase,int dststride){ -#if ARCH_X86 - // ordered by speed / fastest first - if(gCpuCaps.hasMMX2) - vo_draw_alpha_rgb24_MMX2(w, h, src, srca, srcstride, dstbase, dststride); - else if(gCpuCaps.hasMMX) - vo_draw_alpha_rgb24_MMX(w, h, src, srca, srcstride, dstbase, dststride); - else - vo_draw_alpha_rgb24_X86(w, h, src, srca, srcstride, dstbase, dststride); -#else - vo_draw_alpha_rgb24_C(w, h, src, srca, srcstride, dstbase, dststride); -#endif -} - -void vo_draw_alpha_rgb32(int w,int h, unsigned char* src, unsigned char *srca, int srcstride, unsigned char* dstbase,int dststride){ -#if ARCH_X86 - // ordered by speed / fastest first - if(gCpuCaps.hasMMX2) - vo_draw_alpha_rgb32_MMX2(w, h, src, srca, srcstride, dstbase, dststride); - else if(gCpuCaps.hasMMX) - vo_draw_alpha_rgb32_MMX(w, h, src, srca, srcstride, dstbase, dststride); - else - vo_draw_alpha_rgb32_X86(w, h, src, srca, srcstride, dstbase, dststride); -#else - vo_draw_alpha_rgb32_C(w, h, src, srca, srcstride, dstbase, dststride); -#endif -} - -void vo_draw_alpha_rgb12(int w, int h, unsigned char* src, unsigned char *srca, - int srcstride, unsigned char* dstbase, int dststride) { - int y; - for (y = 0; y < h; y++) { - register unsigned short *dst = (unsigned short*) dstbase; - register int x; - for (x = 0; x < w; x++) { - if(srca[x]){ - unsigned char r = dst[x] & 0x0F; - unsigned char g = (dst[x] >> 4) & 0x0F; - unsigned char b = (dst[x] >> 8) & 0x0F; - r = (((r*srca[x]) >> 4) + src[x]) >> 4; - g = (((g*srca[x]) >> 4) + src[x]) >> 4; - b = (((b*srca[x]) >> 4) + src[x]) >> 4; - dst[x] = (b << 8) | (g << 4) | r; - } - } - src += srcstride; - srca += srcstride; - dstbase += dststride; - } - return; -} - -void vo_draw_alpha_rgb15(int w,int h, unsigned char* src, unsigned char *srca, int srcstride, unsigned char* dstbase,int dststride){ - int y; - for(y=0;y>5)&0x1F; - unsigned char b=(dst[x]>>10)&0x1F; - r=(((r*srca[x])>>5)+src[x])>>3; - g=(((g*srca[x])>>5)+src[x])>>3; - b=(((b*srca[x])>>5)+src[x])>>3; - dst[x]=(b<<10)|(g<<5)|r; - } - } - src+=srcstride; - srca+=srcstride; - dstbase+=dststride; - } - return; -} - -void vo_draw_alpha_rgb16(int w,int h, unsigned char* src, unsigned char *srca, int srcstride, unsigned char* dstbase,int dststride){ - int y; - for(y=0;y>5)&0x3F; - unsigned char b=(dst[x]>>11)&0x1F; - r=(((r*srca[x])>>5)+src[x])>>3; - g=(((g*srca[x])>>6)+src[x])>>2; - b=(((b*srca[x])>>5)+src[x])>>3; - dst[x]=(b<<11)|(g<<5)|r; - } - } - src+=srcstride; - srca+=srcstride; - dstbase+=dststride; - } - return; -} diff --git a/libvo/osd.h b/libvo/osd.h deleted file mode 100644 index 4e8064a93f..0000000000 --- a/libvo/osd.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * generic alpha renderers for all YUV modes and RGB depths - * These are "reference implementations", should be optimized later (MMX, etc). - * - * 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, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef MPLAYER_OSD_H -#define MPLAYER_OSD_H - -void vo_draw_alpha_yv12(int w, int h, unsigned char* src, unsigned char *srca, int srcstride, unsigned char* dstbase, int dststride); -void vo_draw_alpha_yuy2(int w, int h, unsigned char* src, unsigned char *srca, int srcstride, unsigned char* dstbase, int dststride); -void vo_draw_alpha_rgb24(int w, int h, unsigned char* src, unsigned char *srca, int srcstride, unsigned char* dstbase, int dststride); -void vo_draw_alpha_rgb32(int w, int h, unsigned char* src, unsigned char *srca, int srcstride, unsigned char* dstbase, int dststride); -void vo_draw_alpha_rgb12(int w, int h, unsigned char* src, unsigned char *srca, - int srcstride, unsigned char* dstbase, int dststride); -void vo_draw_alpha_rgb15(int w, int h, unsigned char* src, unsigned char *srca, int srcstride, unsigned char* dstbase, int dststride); -void vo_draw_alpha_rgb16(int w, int h, unsigned char* src, unsigned char *srca, int srcstride, unsigned char* dstbase, int dststride); - -#endif /* MPLAYER_OSD_H */ diff --git a/libvo/osd_template.c b/libvo/osd_template.c deleted file mode 100644 index 40a335e30e..0000000000 --- a/libvo/osd_template.c +++ /dev/null @@ -1,383 +0,0 @@ -/* - * generic alpha renderers for all YUV modes and RGB depths - * Optimized by Nick and Michael. - * - * 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, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#undef PREFETCH -#undef EMMS -#undef PREFETCHW -#undef PAVGB - -#if HAVE_MMX2 -#define PREFETCH "prefetchnta" -#define PREFETCHW "prefetcht0" -#define PAVGB "pavgb" -#else -#define PREFETCH " # nop" -#define PREFETCHW " # nop" -#endif - -#define EMMS "emms" - -static inline void RENAME(vo_draw_alpha_yv12)(int w,int h, unsigned char* src, unsigned char *srca, int srcstride, unsigned char* dstbase,int dststride){ - int y; -#if HAVE_MMX - __asm__ volatile( - "pcmpeqb %%mm5, %%mm5\n\t" // F..F - "movq %%mm5, %%mm4\n\t" - "movq %%mm5, %%mm7\n\t" - "psllw $8, %%mm5\n\t" //FF00FF00FF00 - "psrlw $8, %%mm4\n\t" //00FF00FF00FF - ::); -#endif - for(y=0;y>8)+src[x]; - } -#endif - src+=srcstride; - srca+=srcstride; - dstbase+=dststride; - } -#if HAVE_MMX - __asm__ volatile(EMMS:::"memory"); -#endif - return; -} - -static inline void RENAME(vo_draw_alpha_yuy2)(int w,int h, unsigned char* src, unsigned char *srca, int srcstride, unsigned char* dstbase,int dststride){ - int y; -#if HAVE_MMX - __asm__ volatile( - "pxor %%mm7, %%mm7\n\t" - "pcmpeqb %%mm5, %%mm5\n\t" // F..F - "movq %%mm5, %%mm6\n\t" - "movq %%mm5, %%mm4\n\t" - "psllw $8, %%mm5\n\t" //FF00FF00FF00 - "psrlw $8, %%mm4\n\t" //00FF00FF00FF - ::); -#endif - for(y=0;y>8)+src[x]; - dstbase[2*x+1]=((((signed)dstbase[2*x+1]-128)*srca[x])>>8)+128; - } - } -#endif - src+=srcstride; - srca+=srcstride; - dstbase+=dststride; - } -#if HAVE_MMX - __asm__ volatile(EMMS:::"memory"); -#endif - return; -} - -static inline void RENAME(vo_draw_alpha_rgb24)(int w,int h, unsigned char* src, unsigned char *srca, int srcstride, unsigned char* dstbase,int dststride){ - int y; -#if HAVE_MMX - __asm__ volatile( - "pxor %%mm7, %%mm7\n\t" - "pcmpeqb %%mm6, %%mm6\n\t" // F..F - ::); -#endif - for(y=0;y>8)+src[x]; - dst[1]=((dst[1]*srca[x])>>8)+src[x]; - dst[2]=((dst[2]*srca[x])>>8)+src[x]; - } - dst+=3; // 24bpp - } -#endif /* arch_x86 */ - src+=srcstride; - srca+=srcstride; - dstbase+=dststride; - } -#if HAVE_MMX - __asm__ volatile(EMMS:::"memory"); -#endif - return; -} - -static inline void RENAME(vo_draw_alpha_rgb32)(int w,int h, unsigned char* src, unsigned char *srca, int srcstride, unsigned char* dstbase,int dststride){ - int y; -#if BYTE_ORDER == BIG_ENDIAN - dstbase++; -#endif -#if HAVE_MMX - __asm__ volatile( - "pxor %%mm7, %%mm7\n\t" - "pcmpeqb %%mm5, %%mm5\n\t" // F..F - "movq %%mm5, %%mm4\n\t" - "psllw $8, %%mm5\n\t" //FF00FF00FF00 - "psrlw $8, %%mm4\n\t" //00FF00FF00FF - ::); -#endif /* HAVE_MMX */ - for(y=0;y>8)+src[x]; - dstbase[4*x+1]=((dstbase[4*x+1]*srca[x])>>8)+src[x]; - dstbase[4*x+2]=((dstbase[4*x+2]*srca[x])>>8)+src[x]; - } - } -#endif /* arch_x86 */ - src+=srcstride; - srca+=srcstride; - dstbase+=dststride; - } -#if HAVE_MMX - __asm__ volatile(EMMS:::"memory"); -#endif - return; -} diff --git a/libvo/vo_corevideo.m b/libvo/vo_corevideo.m index 6775762787..c3d832d589 100644 --- a/libvo/vo_corevideo.m +++ b/libvo/vo_corevideo.m @@ -32,7 +32,6 @@ #import "csputils.h" #import "libmpcodecs/vfcap.h" #import "libmpcodecs/mp_image.h" -#import "osd.h" #import "gl_common.h" #import "gl_osd.h" diff --git a/libvo/vo_lavc.c b/libvo/vo_lavc.c index 4cf4003031..5ba548926e 100644 --- a/libvo/vo_lavc.c +++ b/libvo/vo_lavc.c @@ -35,7 +35,6 @@ #include "sub/sub.h" #include "sub/draw_bmp.h" -#include "libvo/osd.h" struct priv { uint8_t *buffer; diff --git a/libvo/vo_opengl.c b/libvo/vo_opengl.c index cbf1b46f8b..413ca78710 100644 --- a/libvo/vo_opengl.c +++ b/libvo/vo_opengl.c @@ -45,7 +45,6 @@ #include "libmpcodecs/vfcap.h" #include "libmpcodecs/mp_image.h" #include "geometry.h" -#include "osd.h" #include "sub/sub.h" #include "bitmap_packer.h" diff --git a/libvo/vo_opengl_old.c b/libvo/vo_opengl_old.c index 6dfe90c17d..98a111b454 100644 --- a/libvo/vo_opengl_old.c +++ b/libvo/vo_opengl_old.c @@ -35,7 +35,6 @@ #include "libmpcodecs/vfcap.h" #include "libmpcodecs/mp_image.h" #include "geometry.h" -#include "osd.h" #include "sub/sub.h" #include "gl_common.h" diff --git a/libvo/vo_x11.c b/libvo/vo_x11.c index c23dd47fd2..8725279bb8 100644 --- a/libvo/vo_x11.c +++ b/libvo/vo_x11.c @@ -25,7 +25,6 @@ #include "video_out.h" #include "aspect.h" #include "csputils.h" -#include "osd.h" #include "libmpcodecs/mp_image.h" #include "libmpcodecs/vfcap.h" diff --git a/libvo/vo_xv.c b/libvo/vo_xv.c index e12f8cbaf8..b62eaf18d7 100644 --- a/libvo/vo_xv.c +++ b/libvo/vo_xv.c @@ -47,7 +47,6 @@ #include "video_out.h" #include "libmpcodecs/vfcap.h" #include "libmpcodecs/mp_image.h" -#include "osd.h" #include "x11_common.h" #include "fastmemcpy.h" #include "sub/sub.h" diff --git a/sub/img_convert.c b/sub/img_convert.c index 9437226c64..aa5c89401a 100644 --- a/sub/img_convert.c +++ b/sub/img_convert.c @@ -33,140 +33,11 @@ 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; + return talloc_zero(NULL, struct osd_conv_cache); } static void rgba_to_premultiplied_rgba(uint32_t *colors, size_t count) @@ -216,70 +87,3 @@ bool osd_conv_idx_to_rgba(struct osd_conv_cache *c, struct sub_bitmaps *imgs) } 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 index ac766fb0ed..c947c44f01 100644 --- a/sub/img_convert.h +++ b/sub/img_convert.h @@ -10,9 +10,6 @@ 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/spudec.c b/sub/spudec.c index 4eea10ed8f..734b8f1846 100644 --- a/sub/spudec.c +++ b/sub/spudec.c @@ -38,7 +38,6 @@ #include #include -#include #include "config.h" #include "mp_msg.h" @@ -48,18 +47,6 @@ #include "sub.h" #include "mpcommon.h" -/* Valid values for spu_aamode: - 0: none (fastest, most ugly) - 1: approximate - 2: full (slowest) - 3: bilinear (similiar to vobsub, fast and not too bad) - 4: uses swscaler gaussian (this is the only one that looks good) - */ - -int spu_aamode = 3; -int spu_alignment = -1; -float spu_gaussvar = 1.0; - typedef struct spu_packet_t packet_t; struct spu_packet_t { int is_decoded; @@ -79,13 +66,6 @@ struct spu_packet_t { packet_t *next; }; -struct palette_crop_cache { - int valid; - uint32_t palette; - int sx, sy, ex, ey; - int result; -}; - typedef struct { packet_t *queue_head; packet_t *queue_tail; @@ -107,25 +87,15 @@ typedef struct { unsigned int width, height, stride; size_t image_size; /* Size of the image buffer */ unsigned char *image; /* Grayscale value */ - unsigned char *aimage; /* Alpha value */ unsigned int pal_start_col, pal_start_row; unsigned int pal_width, pal_height; unsigned char *pal_image; /* palette entry value */ - unsigned int scaled_frame_width, scaled_frame_height; - unsigned int scaled_start_col, scaled_start_row; - unsigned int scaled_width, scaled_height, scaled_stride; - size_t scaled_image_size; - unsigned char *scaled_image; - unsigned char *scaled_aimage; int auto_palette; /* 1 if we lack a palette and must use an heuristic. */ int font_start_level; /* Darkest value used for the computed font */ int spu_changed; unsigned int forced_subs_only; /* flag: 0=display all subtitle, !0 display only forced subtitles */ unsigned int is_forced_sub; /* true if current subtitle is a forced subtitle */ - struct palette_crop_cache palette_crop_cache; - - struct old_osd_planar borrowed_sub_image; struct sub_bitmap sub_part, borrowed_sub_part; struct osd_bmp_indexed borrowed_bmp; } spudec_handle_t; @@ -190,40 +160,6 @@ static inline unsigned char get_nibble(packet_t *packet) return nib; } -/* Cut the sub to visible part */ -static inline void spudec_cut_image(spudec_handle_t *this) -{ - unsigned int fy, ly; - unsigned int first_y, last_y; - - if (this->stride == 0 || this->height == 0) { - return; - } - - for (fy = 0; fy < this->image_size && !this->aimage[fy]; fy++); - for (ly = this->stride * this->height-1; ly && !this->aimage[ly]; ly--); - first_y = fy / this->stride; - last_y = ly / this->stride; - //printf("first_y: %d, last_y: %d\n", first_y, last_y); - this->start_row += first_y; - - // Some subtitles trigger this condition - if (last_y + 1 > first_y ) { - this->height = last_y - first_y +1; - } else { - this->height = 0; - return; - } - -// printf("new h %d new start %d (sz %d st %d)---\n\n", this->height, this->start_row, this->image_size, this->stride); - - if (first_y > 0) { - memmove(this->image, this->image + this->stride * first_y, this->stride * this->height); - memmove(this->aimage, this->aimage + this->stride * first_y, this->stride * this->height); - } -} - - static int spudec_alloc_image(spudec_handle_t *this, int stride, int height) { if (this->width > stride) // just a safeguard @@ -240,7 +176,6 @@ static int spudec_alloc_image(spudec_handle_t *this, int stride, int height) this->image = malloc(2 * this->stride * this->height); if (this->image) { this->image_size = this->stride * this->height; - this->aimage = this->image + this->image_size; // use stride here as well to simplify reallocation checks this->pal_image = malloc(this->stride * this->height); } @@ -248,102 +183,6 @@ static int spudec_alloc_image(spudec_handle_t *this, int stride, int height) return this->image != NULL; } -/** - * \param pal palette in MPlayer-style gray-alpha values, i.e. - * alpha == 0 means transparent, 1 fully opaque, - * gray value <= 256 - alpha. - */ -static void pal2gray_alpha(const uint16_t *pal, - const uint8_t *src, int src_stride, - uint8_t *dst, uint8_t *dsta, - int dst_stride, int w, int h) -{ - int x, y; - for (y = 0; y < h; y++) { - for (x = 0; x < w; x++) { - uint16_t pixel = pal[src[x]]; - *dst++ = pixel; - *dsta++ = pixel >> 8; - } - for (; x < dst_stride; x++) - *dsta++ = *dst++ = 0; - src += src_stride; - } -} - -static int apply_palette_crop(spudec_handle_t *this, - unsigned crop_x, unsigned crop_y, - unsigned crop_w, unsigned crop_h) -{ - int i; - uint8_t *src; - uint16_t pal[4]; - unsigned stride = (crop_w + 7) & ~7; - if (crop_x > this->pal_width || crop_y > this->pal_height || - crop_w > this->pal_width - crop_x || crop_h > this->pal_width - crop_y || - crop_w > 0x8000 || crop_h > 0x8000 || - stride * crop_h > this->image_size) { - return 0; - } - for (i = 0; i < 4; ++i) { - int color; - int alpha = this->alpha[i]; - // extend 4 -> 8 bit - alpha |= alpha << 4; - if (this->custom && (this->cuspal[i] >> 31) != 0) - alpha = 0; - color = this->custom ? this->cuspal[i] : - this->global_palette[this->palette[i]]; - color = (color >> 16) & 0xff; - // convert to MPlayer-style gray/alpha palette - color = FFMIN(color, alpha); - pal[i] = (-alpha << 8) | color; - } - src = this->pal_image + crop_y * this->pal_width + crop_x; - pal2gray_alpha(pal, src, this->pal_width, - this->image, this->aimage, stride, - crop_w, crop_h); - this->width = crop_w; - this->height = crop_h; - this->stride = stride; - this->start_col = this->pal_start_col + crop_x; - this->start_row = this->pal_start_row + crop_y; - spudec_cut_image(this); - - // reset scaled image - this->scaled_frame_width = 0; - this->scaled_frame_height = 0; - this->palette_crop_cache.valid = 0; - return 1; -} - -int spudec_apply_palette_crop(void *this, uint32_t palette, - int sx, int sy, int ex, int ey) -{ - spudec_handle_t *spu = this; - struct palette_crop_cache *c = &spu->palette_crop_cache; - if (c->valid && c->palette == palette && - c->sx == sx && c->sy == sy && c->ex == ex && c->ey == ey) - return c->result; - spu->palette[0] = (palette >> 28) & 0xf; - spu->palette[1] = (palette >> 24) & 0xf; - spu->palette[2] = (palette >> 20) & 0xf; - spu->palette[3] = (palette >> 16) & 0xf; - spu->alpha[0] = (palette >> 12) & 0xf; - spu->alpha[1] = (palette >> 8) & 0xf; - spu->alpha[2] = (palette >> 4) & 0xf; - spu->alpha[3] = palette & 0xf; - spu->spu_changed = 1; - c->result = apply_palette_crop(spu, - sx - spu->pal_start_col, sy - spu->pal_start_row, - ex - sx, ey - sy); - c->palette = palette; - c->sx = sx; c->sy = sy; - c->ex = ex; c->ey = ey; - c->valid = 1; - return c->result; -} - static void setup_palette(spudec_handle_t *spu, uint32_t palette[256]) { memset(palette, 0, sizeof(palette)); @@ -454,7 +293,6 @@ static void spudec_process_data(spudec_handle_t *this, packet_t *packet) memset(dst, color, len); dst += len; } - apply_palette_crop(this, 0, 0, this->pal_width, this->pal_height); struct sub_bitmap *sub_part = &this->sub_part; struct osd_bmp_indexed *bmp = &this->borrowed_bmp; @@ -765,17 +603,12 @@ void spudec_heartbeat(void *this, unsigned int pts100) free(spu->image); spu->image_size = packet->data_len; spu->image = packet->packet; - spu->aimage = packet->packet + packet->stride * packet->height; packet->packet = NULL; spu->width = packet->width; spu->height = packet->height; spu->stride = packet->stride; spu->start_col = packet->start_col; spu->start_row = packet->start_row; - - // reset scaled image - spu->scaled_frame_width = 0; - spu->scaled_frame_height = 0; } else { if (spu->auto_palette) compute_palette(spu, packet); @@ -803,40 +636,6 @@ 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_get_indexed(void *this, struct mp_eosd_res *dim, struct sub_bitmaps *res) { @@ -863,482 +662,6 @@ void spudec_get_indexed(void *this, struct mp_eosd_res *dim, } } -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; - if (spudec_visible(spu)) - { - draw_alpha(ctx, spu->start_col, spu->start_row, spu->width, spu->height, - spu->image, spu->aimage, spu->stride); - spu->spu_changed = 0; - } -} - -/* calc the bbox for spudec subs */ -void spudec_calc_bbox(void *me, unsigned int dxs, unsigned int dys, unsigned int* bbox) -{ - spudec_handle_t *spu = me; - if (spu->orig_frame_width == 0 || spu->orig_frame_height == 0 - || (spu->orig_frame_width == dxs && spu->orig_frame_height == dys)) { - // unscaled - bbox[0] = spu->start_col; - bbox[1] = spu->start_col + spu->width; - bbox[2] = spu->start_row; - bbox[3] = spu->start_row + spu->height; - } - else { - // scaled - unsigned int scalex = 0x100 * dxs / spu->orig_frame_width; - unsigned int scaley = 0x100 * dys / spu->orig_frame_height; - bbox[0] = spu->start_col * scalex / 0x100; - bbox[1] = spu->start_col * scalex / 0x100 + spu->width * scalex / 0x100; - switch (spu_alignment) { - case 0: - bbox[3] = dys*sub_pos/100 + spu->height * scaley / 0x100; - if (bbox[3] > dys) bbox[3] = dys; - bbox[2] = bbox[3] - spu->height * scaley / 0x100; - break; - case 1: - if (sub_pos < 50) { - bbox[2] = dys*sub_pos/100 - spu->height * scaley / 0x200; - bbox[3] = bbox[2] + spu->height; - } else { - bbox[3] = dys*sub_pos/100 + spu->height * scaley / 0x200; - if (bbox[3] > dys) bbox[3] = dys; - bbox[2] = bbox[3] - spu->height * scaley / 0x100; - } - break; - case 2: - bbox[2] = dys*sub_pos/100 - spu->height * scaley / 0x100; - bbox[3] = bbox[2] + spu->height; - break; - default: /* -1 */ - bbox[2] = spu->start_row * scaley / 0x100; - bbox[3] = spu->start_row * scaley / 0x100 + spu->height * scaley / 0x100; - break; - } - } -} -/* transform mplayer's alpha value into an opacity value that is linear */ -static inline int canon_alpha(int alpha) -{ - return (uint8_t)-alpha; -} - -typedef struct { - unsigned position; - unsigned left_up; - unsigned right_down; -}scale_pixel; - - -static void scale_table(unsigned int start_src, unsigned int start_tar, unsigned int end_src, unsigned int end_tar, scale_pixel * table) -{ - unsigned int t; - unsigned int delta_src = end_src - start_src; - unsigned int delta_tar = end_tar - start_tar; - int src = 0; - int src_step; - if (delta_src == 0 || delta_tar == 0) { - return; - } - src_step = (delta_src << 16) / delta_tar >>1; - for (t = 0; t<=delta_tar; src += (src_step << 1), t++){ - table[t].position= FFMIN(src >> 16, end_src - 1); - table[t].right_down = src & 0xffff; - table[t].left_up = 0x10000 - table[t].right_down; - } -} - -/* bilinear scale, similar to vobsub's code */ -static void scale_image(int x, int y, scale_pixel* table_x, scale_pixel* table_y, spudec_handle_t * spu) -{ - int alpha[4]; - int color[4]; - unsigned int scale[4]; - int base = table_y[y].position * spu->stride + table_x[x].position; - int scaled = y * spu->scaled_stride + x; - alpha[0] = canon_alpha(spu->aimage[base]); - alpha[1] = canon_alpha(spu->aimage[base + 1]); - alpha[2] = canon_alpha(spu->aimage[base + spu->stride]); - alpha[3] = canon_alpha(spu->aimage[base + spu->stride + 1]); - color[0] = spu->image[base]; - color[1] = spu->image[base + 1]; - color[2] = spu->image[base + spu->stride]; - color[3] = spu->image[base + spu->stride + 1]; - scale[0] = (table_x[x].left_up * table_y[y].left_up >> 16) * alpha[0]; - if (table_y[y].left_up == 0x10000) // necessary to avoid overflow-case - scale[0] = table_x[x].left_up * alpha[0]; - scale[1] = (table_x[x].right_down * table_y[y].left_up >>16) * alpha[1]; - scale[2] = (table_x[x].left_up * table_y[y].right_down >> 16) * alpha[2]; - scale[3] = (table_x[x].right_down * table_y[y].right_down >> 16) * alpha[3]; - spu->scaled_image[scaled] = (color[0] * scale[0] + color[1] * scale[1] + color[2] * scale[2] + color[3] * scale[3])>>24; - spu->scaled_aimage[scaled] = (scale[0] + scale[1] + scale[2] + scale[3]) >> 16; - if (spu->scaled_aimage[scaled]){ - // ensure that MPlayer's simplified alpha-blending can not overflow - spu->scaled_image[scaled] = FFMIN(spu->scaled_image[scaled], spu->scaled_aimage[scaled]); - // convert to MPlayer-style alpha - spu->scaled_aimage[scaled] = -spu->scaled_aimage[scaled]; - } -} - -static void sws_spu_image(unsigned char *d1, unsigned char *d2, int dw, int dh, - int ds, const unsigned char* s1, unsigned char* s2, - int sw, int sh, int ss) -{ - struct SwsContext *ctx; - static SwsFilter filter; - static int firsttime = 1; - static float oldvar; - int i; - - if (!firsttime && oldvar != spu_gaussvar) sws_freeVec(filter.lumH); - if (firsttime) { - filter.lumH = filter.lumV = - filter.chrH = filter.chrV = sws_getGaussianVec(spu_gaussvar, 3.0); - sws_normalizeVec(filter.lumH, 1.0); - firsttime = 0; - oldvar = spu_gaussvar; - } - - ctx=sws_getContext(sw, sh, PIX_FMT_GRAY8, dw, dh, PIX_FMT_GRAY8, SWS_GAUSS, &filter, NULL, NULL); - sws_scale(ctx,&s1,&ss,0,sh,&d1,&ds); - for (i=ss*sh-1; i>=0; i--) s2[i] = -s2[i]; - sws_scale(ctx,(const uint8_t **)&s2,&ss,0,sh,&d2,&ds); - for (i=ds*dh-1; i>=0; i--) d2[i] = -d2[i]; - sws_freeContext(ctx); -} - -void spudec_draw_scaled(void *me, 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) -{ - spudec_handle_t *spu = me; - scale_pixel *table_x; - scale_pixel *table_y; - - if (spudec_visible(spu)) { - - // check if only forced subtitles are requested - if( (spu->forced_subs_only) && !(spu->is_forced_sub) ){ - return; - } - - if (!(spu_aamode&16) && (spu->orig_frame_width == 0 || spu->orig_frame_height == 0 - || (spu->orig_frame_width == dxs && spu->orig_frame_height == dys))) { - spudec_draw(spu, draw_alpha, ctx); - } - else { - if (spu->scaled_frame_width != dxs || spu->scaled_frame_height != dys) { /* Resizing is needed */ - /* scaled_x = scalex * x / 0x100 - scaled_y = scaley * y / 0x100 - order of operations is important because of rounding. */ - unsigned int scalex = 0x100 * dxs / spu->orig_frame_width; - unsigned int scaley = 0x100 * dys / spu->orig_frame_height; - spu->scaled_start_col = spu->start_col * scalex / 0x100; - spu->scaled_start_row = spu->start_row * scaley / 0x100; - spu->scaled_width = spu->width * scalex / 0x100; - spu->scaled_height = spu->height * scaley / 0x100; - /* Kludge: draw_alpha needs width multiple of 8 */ - spu->scaled_stride = (spu->scaled_width + 7) & ~7; - if (spu->scaled_image_size < spu->scaled_stride * spu->scaled_height) { - if (spu->scaled_image) { - free(spu->scaled_image); - spu->scaled_image_size = 0; - } - spu->scaled_image = malloc(2 * spu->scaled_stride * spu->scaled_height); - if (spu->scaled_image) { - spu->scaled_image_size = spu->scaled_stride * spu->scaled_height; - spu->scaled_aimage = spu->scaled_image + spu->scaled_image_size; - } - } - if (spu->scaled_image) { - unsigned int x, y; - // needs to be 0-initialized because draw_alpha draws always a - // multiple of 8 pixels. TODO: optimize - if (spu->scaled_width & 7) - memset(spu->scaled_image, 0, 2 * spu->scaled_image_size); - if (spu->scaled_width <= 1 || spu->scaled_height <= 1) { - goto nothing_to_do; - } - switch(spu_aamode&15) { - case 4: - sws_spu_image(spu->scaled_image, spu->scaled_aimage, - spu->scaled_width, spu->scaled_height, spu->scaled_stride, - spu->image, spu->aimage, spu->width, spu->height, spu->stride); - break; - case 3: - table_x = calloc(spu->scaled_width, sizeof(scale_pixel)); - table_y = calloc(spu->scaled_height, sizeof(scale_pixel)); - if (!table_x || !table_y) { - mp_msg(MSGT_SPUDEC, MSGL_FATAL, "Fatal: spudec_draw_scaled: calloc failed\n"); - } - scale_table(0, 0, spu->width - 1, spu->scaled_width - 1, table_x); - scale_table(0, 0, spu->height - 1, spu->scaled_height - 1, table_y); - for (y = 0; y < spu->scaled_height; y++) - for (x = 0; x < spu->scaled_width; x++) - scale_image(x, y, table_x, table_y, spu); - free(table_x); - free(table_y); - break; - case 0: - /* no antialiasing */ - for (y = 0; y < spu->scaled_height; ++y) { - int unscaled_y = y * 0x100 / scaley; - int strides = spu->stride * unscaled_y; - int scaled_strides = spu->scaled_stride * y; - for (x = 0; x < spu->scaled_width; ++x) { - int unscaled_x = x * 0x100 / scalex; - spu->scaled_image[scaled_strides + x] = spu->image[strides + unscaled_x]; - spu->scaled_aimage[scaled_strides + x] = spu->aimage[strides + unscaled_x]; - } - } - break; - case 1: - { - /* Intermediate antialiasing. */ - for (y = 0; y < spu->scaled_height; ++y) { - const unsigned int unscaled_top = y * spu->orig_frame_height / dys; - unsigned int unscaled_bottom = (y + 1) * spu->orig_frame_height / dys; - if (unscaled_bottom >= spu->height) - unscaled_bottom = spu->height - 1; - for (x = 0; x < spu->scaled_width; ++x) { - const unsigned int unscaled_left = x * spu->orig_frame_width / dxs; - unsigned int unscaled_right = (x + 1) * spu->orig_frame_width / dxs; - unsigned int color = 0; - unsigned int alpha = 0; - unsigned int walkx, walky; - unsigned int base, tmp; - if (unscaled_right >= spu->width) - unscaled_right = spu->width - 1; - for (walky = unscaled_top; walky <= unscaled_bottom; ++walky) - for (walkx = unscaled_left; walkx <= unscaled_right; ++walkx) { - base = walky * spu->stride + walkx; - tmp = canon_alpha(spu->aimage[base]); - alpha += tmp; - color += tmp * spu->image[base]; - } - base = y * spu->scaled_stride + x; - spu->scaled_image[base] = alpha ? color / alpha : 0; - spu->scaled_aimage[base] = - alpha * (1 + unscaled_bottom - unscaled_top) * (1 + unscaled_right - unscaled_left); - /* spu->scaled_aimage[base] = - alpha * dxs * dys / spu->orig_frame_width / spu->orig_frame_height; */ - if (spu->scaled_aimage[base]) { - spu->scaled_aimage[base] = 256 - spu->scaled_aimage[base]; - if (spu->scaled_aimage[base] + spu->scaled_image[base] > 255) - spu->scaled_image[base] = 256 - spu->scaled_aimage[base]; - } - } - } - } - break; - case 2: - { - /* Best antialiasing. Very slow. */ - /* Any pixel (x, y) represents pixels from the original - rectangular region comprised between the columns - unscaled_y and unscaled_y + 0x100 / scaley and the rows - unscaled_x and unscaled_x + 0x100 / scalex - - The original rectangular region that the scaled pixel - represents is cut in 9 rectangular areas like this: - - +---+-----------------+---+ - | 1 | 2 | 3 | - +---+-----------------+---+ - | | | | - | 4 | 5 | 6 | - | | | | - +---+-----------------+---+ - | 7 | 8 | 9 | - +---+-----------------+---+ - - The width of the left column is at most one pixel and - it is never null and its right column is at a pixel - boundary. The height of the top row is at most one - pixel it is never null and its bottom row is at a - pixel boundary. The width and height of region 5 are - integral values. The width of the right column is - what remains and is less than one pixel. The height - of the bottom row is what remains and is less than - one pixel. - - The row above 1, 2, 3 is unscaled_y. The row between - 1, 2, 3 and 4, 5, 6 is top_low_row. The row between 4, - 5, 6 and 7, 8, 9 is (unsigned int)unscaled_y_bottom. - The row beneath 7, 8, 9 is unscaled_y_bottom. - - The column left of 1, 4, 7 is unscaled_x. The column - between 1, 4, 7 and 2, 5, 8 is left_right_column. The - column between 2, 5, 8 and 3, 6, 9 is (unsigned - int)unscaled_x_right. The column right of 3, 6, 9 is - unscaled_x_right. */ - const double inv_scalex = (double) 0x100 / scalex; - const double inv_scaley = (double) 0x100 / scaley; - for (y = 0; y < spu->scaled_height; ++y) { - const double unscaled_y = y * inv_scaley; - const double unscaled_y_bottom = unscaled_y + inv_scaley; - const unsigned int top_low_row = FFMIN(unscaled_y_bottom, unscaled_y + 1.0); - const double top = top_low_row - unscaled_y; - const unsigned int height = unscaled_y_bottom > top_low_row - ? (unsigned int) unscaled_y_bottom - top_low_row - : 0; - const double bottom = unscaled_y_bottom > top_low_row - ? unscaled_y_bottom - floor(unscaled_y_bottom) - : 0.0; - for (x = 0; x < spu->scaled_width; ++x) { - const double unscaled_x = x * inv_scalex; - const double unscaled_x_right = unscaled_x + inv_scalex; - const unsigned int left_right_column = FFMIN(unscaled_x_right, unscaled_x + 1.0); - const double left = left_right_column - unscaled_x; - const unsigned int width = unscaled_x_right > left_right_column - ? (unsigned int) unscaled_x_right - left_right_column - : 0; - const double right = unscaled_x_right > left_right_column - ? unscaled_x_right - floor(unscaled_x_right) - : 0.0; - double color = 0.0; - double alpha = 0.0; - double tmp; - unsigned int base; - /* Now use these informations to compute a good alpha, - and lightness. The sum is on each of the 9 - region's surface and alpha and lightness. - - transformed alpha = sum(surface * alpha) / sum(surface) - transformed color = sum(surface * alpha * color) / sum(surface * alpha) - */ - /* 1: top left part */ - base = spu->stride * (unsigned int) unscaled_y; - tmp = left * top * canon_alpha(spu->aimage[base + (unsigned int) unscaled_x]); - alpha += tmp; - color += tmp * spu->image[base + (unsigned int) unscaled_x]; - /* 2: top center part */ - if (width > 0) { - unsigned int walkx; - for (walkx = left_right_column; walkx < (unsigned int) unscaled_x_right; ++walkx) { - base = spu->stride * (unsigned int) unscaled_y + walkx; - tmp = /* 1.0 * */ top * canon_alpha(spu->aimage[base]); - alpha += tmp; - color += tmp * spu->image[base]; - } - } - /* 3: top right part */ - if (right > 0.0) { - base = spu->stride * (unsigned int) unscaled_y + (unsigned int) unscaled_x_right; - tmp = right * top * canon_alpha(spu->aimage[base]); - alpha += tmp; - color += tmp * spu->image[base]; - } - /* 4: center left part */ - if (height > 0) { - unsigned int walky; - for (walky = top_low_row; walky < (unsigned int) unscaled_y_bottom; ++walky) { - base = spu->stride * walky + (unsigned int) unscaled_x; - tmp = left /* * 1.0 */ * canon_alpha(spu->aimage[base]); - alpha += tmp; - color += tmp * spu->image[base]; - } - } - /* 5: center part */ - if (width > 0 && height > 0) { - unsigned int walky; - for (walky = top_low_row; walky < (unsigned int) unscaled_y_bottom; ++walky) { - unsigned int walkx; - base = spu->stride * walky; - for (walkx = left_right_column; walkx < (unsigned int) unscaled_x_right; ++walkx) { - tmp = /* 1.0 * 1.0 * */ canon_alpha(spu->aimage[base + walkx]); - alpha += tmp; - color += tmp * spu->image[base + walkx]; - } - } - } - /* 6: center right part */ - if (right > 0.0 && height > 0) { - unsigned int walky; - for (walky = top_low_row; walky < (unsigned int) unscaled_y_bottom; ++walky) { - base = spu->stride * walky + (unsigned int) unscaled_x_right; - tmp = right /* * 1.0 */ * canon_alpha(spu->aimage[base]); - alpha += tmp; - color += tmp * spu->image[base]; - } - } - /* 7: bottom left part */ - if (bottom > 0.0) { - base = spu->stride * (unsigned int) unscaled_y_bottom + (unsigned int) unscaled_x; - tmp = left * bottom * canon_alpha(spu->aimage[base]); - alpha += tmp; - color += tmp * spu->image[base]; - } - /* 8: bottom center part */ - if (width > 0 && bottom > 0.0) { - unsigned int walkx; - base = spu->stride * (unsigned int) unscaled_y_bottom; - for (walkx = left_right_column; walkx < (unsigned int) unscaled_x_right; ++walkx) { - tmp = /* 1.0 * */ bottom * canon_alpha(spu->aimage[base + walkx]); - alpha += tmp; - color += tmp * spu->image[base + walkx]; - } - } - /* 9: bottom right part */ - if (right > 0.0 && bottom > 0.0) { - base = spu->stride * (unsigned int) unscaled_y_bottom + (unsigned int) unscaled_x_right; - tmp = right * bottom * canon_alpha(spu->aimage[base]); - alpha += tmp; - color += tmp * spu->image[base]; - } - /* Finally mix these transparency and brightness information suitably */ - base = spu->scaled_stride * y + x; - spu->scaled_image[base] = alpha > 0 ? color / alpha : 0; - spu->scaled_aimage[base] = alpha * scalex * scaley / 0x10000; - if (spu->scaled_aimage[base]) { - spu->scaled_aimage[base] = 256 - spu->scaled_aimage[base]; - if (spu->scaled_aimage[base] + spu->scaled_image[base] > 255) - spu->scaled_image[base] = 256 - spu->scaled_aimage[base]; - } - } - } - } - } -nothing_to_do: - /* Kludge: draw_alpha needs width multiple of 8. */ - if (spu->scaled_width < spu->scaled_stride) - for (y = 0; y < spu->scaled_height; ++y) { - memset(spu->scaled_aimage + y * spu->scaled_stride + spu->scaled_width, 0, - spu->scaled_stride - spu->scaled_width); - } - spu->scaled_frame_width = dxs; - spu->scaled_frame_height = dys; - } - } - if (spu->scaled_image){ - switch (spu_alignment) { - case 0: - spu->scaled_start_row = dys*sub_pos/100; - if (spu->scaled_start_row + spu->scaled_height > dys) - spu->scaled_start_row = dys - spu->scaled_height; - break; - case 1: - spu->scaled_start_row = dys*sub_pos/100 - spu->scaled_height/2; - if (sub_pos >= 50 && spu->scaled_start_row + spu->scaled_height > dys) - spu->scaled_start_row = dys - spu->scaled_height; - break; - case 2: - spu->scaled_start_row = dys*sub_pos/100 - spu->scaled_height; - break; - } - draw_alpha(ctx, spu->scaled_start_col, spu->scaled_start_row, spu->scaled_width, spu->scaled_height, - spu->scaled_image, spu->scaled_aimage, spu->scaled_stride); - spu->spu_changed = 0; - } - } - } - else - { - mp_msg(MSGT_SPUDEC,MSGL_DBG2,"SPU not displayed: start_pts=%d end_pts=%d now_pts=%d\n", - spu->start_pts, spu->end_pts, spu->now_pts); - } -} - void spudec_set_font_factor(void * this, double factor) { spudec_handle_t *spu = this; @@ -1428,14 +751,6 @@ void *spudec_new_scaled(unsigned int *palette, unsigned int frame_width, unsigne return this; } -void spudec_set_res(void *this, unsigned int frame_width, unsigned int frame_height) -{ - spudec_handle_t *spu = this; - // intentionally do not apply resolution heuristics - spu->orig_frame_width = frame_width; - spu->orig_frame_height = frame_height; -} - void *spudec_new(unsigned int *palette) { return spudec_new_scaled(palette, 0, 0, NULL, 0); @@ -1449,11 +764,8 @@ void spudec_free(void *this) spudec_free_packet(spudec_dequeue_packet(spu)); free(spu->packet); spu->packet = NULL; - free(spu->scaled_image); - spu->scaled_image = NULL; free(spu->image); spu->image = NULL; - spu->aimage = NULL; free(spu->pal_image); spu->pal_image = NULL; spu->image_size = 0; @@ -1461,87 +773,3 @@ void spudec_free(void *this) free(spu); } } - -#define MP_NOPTS_VALUE (-1LL<<63) //both int64_t and double should be able to represent this exactly - -packet_t *spudec_packet_create(int x, int y, int w, int h) -{ - packet_t *packet; - int stride = (w + 7) & ~7; - if ((unsigned)w >= 0x8000 || (unsigned)h > 0x4000) - return NULL; - packet = calloc(1, sizeof(packet_t)); - packet->is_decoded = 1; - packet->width = w; - packet->height = h; - packet->stride = stride; - packet->start_col = x; - packet->start_row = y; - packet->data_len = 2 * stride * h; - if (packet->data_len) { // size 0 is a special "clear" packet - packet->packet = malloc(packet->data_len); - if (!packet->packet) { - free(packet); - packet = NULL; - } - } - return packet; -} - -void spudec_packet_clear(packet_t *packet) -{ - /* clear alpha and value, as value is premultiplied */ - memset(packet->packet, 0, packet->data_len); -} - -void spudec_packet_fill(packet_t *packet, - const uint8_t *pal_img, int pal_stride, - const void *palette, - int x, int y, int w, int h) -{ - const uint32_t *pal = palette; - uint8_t *img = packet->packet + x + y * packet->stride; - uint8_t *aimg = img + packet->stride * packet->height; - int i; - uint16_t g8a8_pal[256]; - - for (i = 0; i < 256; i++) { - uint32_t pixel = pal[i]; - int alpha = pixel >> 24; - int gray = (((pixel & 0x000000ff) >> 0) + - ((pixel & 0x0000ff00) >> 7) + - ((pixel & 0x00ff0000) >> 16)) >> 2; - gray = FFMIN(gray, alpha); - g8a8_pal[i] = (-alpha << 8) | gray; - } - pal2gray_alpha(g8a8_pal, pal_img, pal_stride, - img, aimg, packet->stride, w, h); -} - -void spudec_packet_send(void *spu, packet_t *packet, double pts, double endpts) -{ - packet->start_pts = 0; - packet->end_pts = 0x7fffffff; - if (pts != MP_NOPTS_VALUE) - packet->start_pts = pts * 90000; - if (endpts != MP_NOPTS_VALUE) - packet->end_pts = endpts * 90000; - spudec_queue_packet(spu, packet); -} - -/** - * palette must contain at least 256 32-bit entries, otherwise crashes - * are possible - */ -void spudec_set_paletted(void *spu, const uint8_t *pal_img, int pal_stride, - const void *palette, - int x, int y, int w, int h, - double pts, double endpts) -{ - packet_t *packet = spudec_packet_create(x, y, w, h); - if (!packet) - return; - if (packet->data_len) // size 0 is a special "clear" packet - spudec_packet_fill(packet, pal_img, pal_stride, palette, 0, 0, w, h); - spudec_packet_send(spu, packet, pts, endpts); -} diff --git a/sub/spudec.h b/sub/spudec.h index 411aafeb19..6611a28327 100644 --- a/sub/spudec.h +++ b/sub/spudec.h @@ -26,32 +26,14 @@ struct mp_eosd_res; 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); void spudec_get_indexed(void *this, struct mp_eosd_res *dim, 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_set_res(void *this, unsigned int frame_width, unsigned int frame_height); void *spudec_new(unsigned int *palette); void spudec_free(void *this); void spudec_reset(void *this); // called after seek int spudec_visible(void *this); // check if spu is visible void spudec_set_font_factor(void * this, double factor); // sets the equivalent to ffactor int spudec_changed(void *this); -void spudec_calc_bbox(void *me, unsigned int dxs, unsigned int dys, unsigned int* bbox); void spudec_set_forced_subs_only(void * const this, const unsigned int flag); -void spudec_set_paletted(void *this, const uint8_t *pal_img, int stride, - const void *palette, - int x, int y, int w, int h, - double pts, double endpts); -struct spu_packet_t *spudec_packet_create(int x, int y, int w, int h); -void spudec_packet_fill(struct spu_packet_t *packet, - const uint8_t *pal_img, int pal_stride, - const void *palette, - int x, int y, int w, int h); -void spudec_packet_send(void *spu, struct spu_packet_t *packet, - double pts, double endpts); -void spudec_packet_clear(struct spu_packet_t *packet); #endif /* MPLAYER_SPUDEC_H */ diff --git a/sub/sub.c b/sub/sub.c index f175563974..862f5d1f6e 100644 --- a/sub/sub.c +++ b/sub/sub.c @@ -219,16 +219,6 @@ static bool render_object(struct osd_state *osd, struct osd_object *obj, cached |= osd_conv_idx_to_rgba(obj->cache[0], out_imgs); } - if (formats[SUBBITMAP_OLD_PLANAR] && out_imgs->format == SUBBITMAP_INDEXED) - { - cached |= osd_conv_idx_to_old_p(obj->cache[1], out_imgs, - osd->res.w, osd->res.h); - } - - if (formats[SUBBITMAP_OLD_PLANAR] && out_imgs->format == SUBBITMAP_LIBASS) { - cached |= osd_conv_ass_to_old_p(obj->cache[2], out_imgs); - } - if (cached) obj->cached = *out_imgs; @@ -325,48 +315,6 @@ bool osd_draw_on_image(struct osd_state *osd, struct mp_image *dest, return changed; } -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) -{ - struct mp_eosd_res dim = - {.w = w, .h = h, .ml = ml, .mt = mt, .mr = mr, .mb = mb}; - osd_update_ext(osd, dim); - struct sub_render_params subparams = { - .pts = osd->vo_sub_pts, - .dim = dim, - .normal_scale = 1, - .vsfilter_scale = 1, // unknown - }; - for (int n = 0; n < MAX_OSD_PARTS; n++) { - struct osd_object *obj = osd->objs[n]; - if (obj->is_sub && osd->render_subs_in_filter) - continue; - struct sub_bitmaps imgs; - bool formats[SUBBITMAP_COUNT] = {[SUBBITMAP_OLD_PLANAR] = true}; - if (render_object(osd, obj, &imgs, &subparams, 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 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, w, h, 0, 0, 0, 0, 0, 0, draw_alpha, ctx); -} - void vo_osd_changed(int new_value) { struct osd_state *osd = global_osd; diff --git a/sub/sub.h b/sub/sub.h index cc59077011..4f3ca905b6 100644 --- a/sub/sub.h +++ b/sub/sub.h @@ -32,7 +32,6 @@ enum sub_bitmap_format { SUBBITMAP_LIBASS, // A8, with a per-surface blend color (libass.color) SUBBITMAP_RGBA, // B8G8R8A8 (MSB=A, LSB=B), scaled, premultiplied alpha SUBBITMAP_INDEXED, // scaled, bitmap points to osd_bmp_indexed - SUBBITMAP_OLD_PLANAR, // like previous, but bitmap points to old_osd_planar SUBBITMAP_COUNT }; @@ -44,12 +43,6 @@ struct osd_bmp_indexed { uint32_t palette[256]; }; -// For SUBBITMAP_OLD_PANAR -struct old_osd_planar { - unsigned char *bitmap; - unsigned char *alpha; -}; - struct sub_bitmap { void *bitmap; int stride; @@ -191,9 +184,6 @@ extern int sub_pos; extern int sub_width_p; extern int sub_bg_color; /* subtitles background color */ extern int sub_bg_alpha; -extern int spu_alignment; -extern int spu_aamode; -extern float spu_gaussvar; extern char *subtitle_font_encoding; extern float text_font_scale_factor; @@ -210,20 +200,6 @@ extern float sub_fps; extern int sub_justify; -void osd_draw_text(struct osd_state *osd, int dxs, 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 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, - void (*draw_alpha)(void *ctx, int x0, int y0, int w, - int h, unsigned char* src, - unsigned char *srca, - int stride), - void *ctx); - void draw_osd_with_eosd(struct vo *vo, struct osd_state *osd); struct osd_state *osd_create(struct MPOpts *opts, struct ass_library *asslib); From f6197249a783f00ae583e67d113ed737d677f12c Mon Sep 17 00:00:00 2001 From: wm4 Date: Mon, 8 Oct 2012 00:14:51 +0200 Subject: [PATCH 42/83] spudec: use csputils for color conversion Just to get rid of that conversion copy&pasted from the internet. R and G are swapped for unknown reasons. Testing various subtitles seem to yield the same results as VLC. The sub-bitmap renderers output the correct colors. The colorspace conversion is used without problems for vo_gl, vo_gl3 and vo_vdpau. The problem is most likely that apparently, the DVD palette read from the subtitle track extradata is converted to YUV using vobsub_palette_to_yuv(), and swapped in the process. Or in other words, the YUV colors spu->global_palette are encoded with R and G swapped. Add some utility definition to csputils.c/h to make converting single color values easier. --- libvo/csputils.c | 14 ++++++++++++++ libvo/csputils.h | 8 ++++++++ sub/spudec.c | 18 ++++++++---------- 3 files changed, 30 insertions(+), 10 deletions(-) diff --git a/libvo/csputils.c b/libvo/csputils.c index b894a2f869..b0255a00dc 100644 --- a/libvo/csputils.c +++ b/libvo/csputils.c @@ -361,3 +361,17 @@ void mp_invert_yuv2rgb(float out[3][4], float in[3][4]) out[1][3] = -(out[1][0] * m03 + out[1][1] * m13 + out[1][2] * m23); out[2][3] = -(out[2][0] * m03 + out[2][1] * m13 + out[2][2] * m23); } + +// Multiply the color in c with the given matrix. +// c is {R, G, B} or {Y, U, V} (depending on input/output and matrix). +void mp_map_color(float matrix[3][4], uint8_t c[3]) +{ + uint8_t in[3] = {c[0], c[1], c[2]}; + for (int i = 0; i < 3; i++) { + double val = matrix[i][3] * 255; + for (int x = 0; x < 3; x++) + val += matrix[i][x] * in[x]; + int ival = lrint(val); + c[i] = FFMIN(FFMAX(ival, 0), 255); + } +} diff --git a/libvo/csputils.h b/libvo/csputils.h index 0dd75b0549..e4fb32e156 100644 --- a/libvo/csputils.h +++ b/libvo/csputils.h @@ -73,6 +73,12 @@ struct mp_csp_params { int input_bits; }; +#define MP_CSP_PARAMS_DEFAULTS { \ + .colorspace = MP_CSP_DETAILS_DEFAULTS, \ + .brightness = 0, .contrast = 1, .hue = 0, .saturation = 1, \ + .rgamma = 1, .ggamma = 1, .bgamma = 1, \ + .texture_bits = 8, .input_bits = 8} + enum mp_csp_equalizer_param { MP_CSP_EQ_BRIGHTNESS, MP_CSP_EQ_CONTRAST, @@ -143,4 +149,6 @@ void mp_gen_yuv2rgb_map(struct mp_csp_params *params, uint8_t *map, int size); (minv)[c][3] * (scale)) void mp_invert_yuv2rgb(float out[3][4], float in[3][4]); +void mp_map_color(float matrix[3][4], uint8_t c[3]); + #endif /* MPLAYER_CSPUTILS_H */ diff --git a/sub/spudec.c b/sub/spudec.c index 734b8f1846..353f72de7a 100644 --- a/sub/spudec.c +++ b/sub/spudec.c @@ -46,6 +46,7 @@ #include "vobsub.h" #include "sub.h" #include "mpcommon.h" +#include "libvo/csputils.h" typedef struct spu_packet_t packet_t; struct spu_packet_t { @@ -186,6 +187,9 @@ static int spudec_alloc_image(spudec_handle_t *this, int stride, int height) static void setup_palette(spudec_handle_t *spu, uint32_t palette[256]) { memset(palette, 0, sizeof(palette)); + struct mp_csp_params csp = MP_CSP_PARAMS_DEFAULTS; + float cmatrix[3][4]; + mp_get_yuv2rgb_coeffs(&csp, cmatrix); for (int i = 0; i < 4; ++i) { int alpha = spu->alpha[i]; // extend 4 -> 8 bit @@ -194,16 +198,10 @@ static void setup_palette(spudec_handle_t *spu, uint32_t palette[256]) alpha = 0; int color = spu->custom ? spu->cuspal[i] : spu->global_palette[spu->palette[i]]; - int y = (color >> 16) & 0xff; - int u = (color >> 8) & 0xff; - int v = color & 0xff; - // stolen from some site, likely incorrect - int b = 1.164 * (y - 16) + 2.018 * (u - 128); - int g = 1.164 * (y - 16) - 0.813 * (v - 128) - 0.391 * (u - 128); - int r = 1.164 * (y - 16) + 1.596 * (v - 128); -#define CL(x) FFMAX(FFMIN((x), 255), 0) - palette[i] = (alpha << 24) | CL(r) | (CL(g) << 8) | (CL(b) << 16); -#undef CL + uint8_t c[3] = {(color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff}; + mp_map_color(cmatrix, c); + // R and G swapped, possibly due to vobsub_palette_to_yuv() + palette[i] = (alpha << 24) | (c[2] << 16) | (c[1] << 8) | c[0]; } } From 73f18ace91fb040f7016df28e66ebe5ce7177e66 Mon Sep 17 00:00:00 2001 From: wm4 Date: Wed, 17 Oct 2012 13:46:46 +0200 Subject: [PATCH 43/83] mp_image: hack to fix alignment for certain image formats This is to get rid of swscale alignment warnings with the new OSD code. Only image formats used by it are fixed. Solving this generally would require some more effort. (Possibly by using libav's allocation functions plus lots of testing.) --- libmpcodecs/mp_image.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/libmpcodecs/mp_image.c b/libmpcodecs/mp_image.c index 28472d092c..1ba9e8e753 100644 --- a/libmpcodecs/mp_image.c +++ b/libmpcodecs/mp_image.c @@ -26,11 +26,30 @@ #include "libmpcodecs/img_format.h" #include "libmpcodecs/mp_image.h" +#include "libmpcodecs/sws_utils.h" #include "libvo/fastmemcpy.h" #include "libavutil/mem.h" +#include "libavutil/common.h" void mp_image_alloc_planes(mp_image_t *mpi) { + if (mpi->imgfmt == IMGFMT_BGRA) { + mpi->stride[0]=FFALIGN(mpi->width*4,SWS_MIN_BYTE_ALIGN); + mpi->planes[0]=av_malloc(mpi->stride[0]*mpi->height); + mpi->flags|=MP_IMGFLAG_ALLOCATED; + return; + } + if (mpi->imgfmt == IMGFMT_444P16 || mpi->imgfmt == IMGFMT_444P) { + int bp = mpi->imgfmt == IMGFMT_444P16 ? 2 : 1; + mpi->stride[0]=FFALIGN(mpi->width*bp,SWS_MIN_BYTE_ALIGN); + mpi->stride[1]=mpi->stride[2]=mpi->stride[0]; + int imgsize = mpi->stride[0] * mpi->height; + mpi->planes[0]=av_malloc(imgsize*3); + mpi->planes[1]=mpi->planes[0]+imgsize; + mpi->planes[2]=mpi->planes[1]+imgsize; + mpi->flags|=MP_IMGFLAG_ALLOCATED; + return; + } // IF09 - allocate space for 4. plane delta info - unused if (mpi->imgfmt == IMGFMT_IF09) { mpi->planes[0]=av_malloc(mpi->bpp*mpi->width*(mpi->height+2)/8+ From d5def80afbdc7d20a22f2f630cdd34c60a0b99a9 Mon Sep 17 00:00:00 2001 From: wm4 Date: Wed, 17 Oct 2012 14:06:52 +0200 Subject: [PATCH 44/83] core: fix -subfile When demux_demuxers was removed, and -subfile was moved to the frontend, setting the non_interleaved for -subfile was forgotten. --- libmpdemux/demuxer.h | 2 -- mplayer.c | 9 ++++++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/libmpdemux/demuxer.h b/libmpdemux/demuxer.h index 8c04c9dad6..62316c0ef0 100644 --- a/libmpdemux/demuxer.h +++ b/libmpdemux/demuxer.h @@ -120,8 +120,6 @@ typedef struct demux_stream { off_t dpos; // position in the demuxed stream int pack_no; // serial number of packet bool keyframe; // keyframe flag of current packet - int non_interleaved; // 1 if this stream is not properly interleaved, - // so e.g. subtitle handling must do explicit reads. //--------------- int packs; // number of packets in buffer int bytes; // total bytes of packets in buffer diff --git a/mplayer.c b/mplayer.c index 08ba04a0f5..450beb58f9 100644 --- a/mplayer.c +++ b/mplayer.c @@ -1752,7 +1752,8 @@ static void update_subtitles(struct MPContext *mpctx, double refpts_tl) spudec_assemble(vo_spudec, packet, len, timestamp); } } else if (d_sub && (is_text_sub(type) || (sh_sub && sh_sub->active))) { - if (d_sub->non_interleaved) + bool non_interleaved = track->is_external; // if demuxing subs only + if (non_interleaved) ds_get_next_pts(d_sub); while (d_sub->first) { @@ -1762,7 +1763,7 @@ static void update_subtitles(struct MPContext *mpctx, double refpts_tl) if (!opts->ass_enabled || !is_text_sub(type)) break; // Try to avoid demuxing whole file at once - if (d_sub->non_interleaved && subpts_s > curpts_s + 1) + if (non_interleaved && subpts_s > curpts_s + 1) break; } double duration = d_sub->first->duration; @@ -1798,7 +1799,7 @@ static void update_subtitles(struct MPContext *mpctx, double refpts_tl) sub_add_text(&mpctx->subs, packet, len, endpts_s); set_osd_subtitle(mpctx, &mpctx->subs); } - if (d_sub->non_interleaved) + if (non_interleaved) ds_get_next_pts(d_sub); } if (!opts->ass_enabled) @@ -3589,6 +3590,8 @@ static void open_external_file(struct MPContext *mpctx, char *filename, if (stream->type == filter) { struct track *t = add_stream_track(mpctx, stream, false); t->is_external = true; + t->title = talloc_strdup(t, filename); + num_added++; } } if (num_added == 0) { From 98f74335d509320f19db2da8786273f95cad2a69 Mon Sep 17 00:00:00 2001 From: wm4 Date: Thu, 18 Oct 2012 17:31:00 +0200 Subject: [PATCH 45/83] sub: fix text subtitle aspect ratio with vo_xv and vo_lavc, refactor This fixes that vo_xv didn't display text subtitles correctly when using anamorphic video. It didn't pass the aspect information to the subtitle renderer. Also, try to render OSD correctly with respect to aspect ratio settings: on vo_xv, the OSD is rendered into the video, and needs to be "stretched" too when playing anamorphic video. When the -monitorpixelaspect option is used, even with VOs such as vo_opengl the OSD has to be rendered with that aspect ratio. As preparation for future commits, replace the weird vsfilter_scale value with a somewhat more sensible video_par member. Also, struct mp_eosd_res is a better place for the aspect ratio parameters, as OSD needs this too. Use osd_draw_on_image() directly in vo_lavc, which fixes aspect ratio issues as well. --- libmpcodecs/vf_ass.c | 22 ++++++++++++--------- libvo/aspect.c | 31 +++++++++++++---------------- libvo/aspect.h | 5 +---- libvo/video_out.c | 3 +-- libvo/video_out.h | 3 ++- libvo/vo_lavc.c | 46 ++++++++++++++++++++++++-------------------- libvo/vo_x11.c | 10 ++++++---- libvo/vo_xv.c | 13 ++++++++++--- sub/dec_sub.h | 2 -- sub/osd_libass.c | 1 + sub/sd_ass.c | 4 ++-- sub/sub.c | 7 +++---- sub/sub.h | 2 ++ 13 files changed, 79 insertions(+), 70 deletions(-) diff --git a/libmpcodecs/vf_ass.c b/libmpcodecs/vf_ass.c index 77248b49c0..167ebd6e15 100644 --- a/libmpcodecs/vf_ass.c +++ b/libmpcodecs/vf_ass.c @@ -63,7 +63,7 @@ static const struct vf_priv_s { int auto_insert; struct osd_state *osd; - double aspect_correction; + struct mp_eosd_res dim; unsigned char *planes[3]; struct line_limits { @@ -92,7 +92,17 @@ static int config(struct vf_instance *vf, vf->priv->planes[2] = malloc(vf->priv->outw * vf->priv->outh); vf->priv->line_limits = malloc((vf->priv->outh + 1) / 2 * sizeof(*vf->priv->line_limits)); - vf->priv->aspect_correction = (double)width / height * d_height / d_width; + double dar = (double)d_width / d_height; + double sar = (double)width / height; + + vf->priv->dim = (struct mp_eosd_res) { + .w = vf->priv->outw, + .h = vf->priv->outh, + .mt = opts->ass_top_margin, + .mb = opts->ass_bottom_margin, + .display_par = sar / dar, + .video_par = dar / sar, + }; return vf_next_config(vf, vf->priv->outw, vf->priv->outh, d_width, d_height, flags, outfmt); @@ -354,18 +364,12 @@ static int render_frame(struct vf_instance *vf, mp_image_t *mpi, static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts) { struct vf_priv_s *priv = vf->priv; - struct MPOpts *opts = vf->opts; struct osd_state *osd = priv->osd; struct sub_bitmaps imgs = (struct sub_bitmaps) {0}; if (pts != MP_NOPTS_VALUE) { struct sub_render_params subparams = { .pts = pts, - .dim = { .w = vf->priv->outw, - .h = vf->priv->outh, - .mt = opts->ass_top_margin, - .mb = opts->ass_bottom_margin }, - .normal_scale = vf->priv->aspect_correction, - .vsfilter_scale = 1, + .dim = priv->dim, }; bool formats[SUBBITMAP_COUNT] = {[SUBBITMAP_LIBASS] = true}; osd_draw_sub(osd, &imgs, &subparams, formats); diff --git a/libvo/aspect.c b/libvo/aspect.c index 8a26a5ac00..f3cd00a5e5 100644 --- a/libvo/aspect.c +++ b/libvo/aspect.c @@ -25,18 +25,13 @@ #include "video_out.h" -void aspect_save_orig(struct vo *vo, int orgw, int orgh) +void aspect_save_videores(struct vo *vo, int w, int h, int d_w, int d_h) { - mp_msg(MSGT_VO, MSGL_DBG2, "aspect_save_orig %dx%d\n", orgw, orgh); - vo->aspdat.orgw = orgw; - vo->aspdat.orgh = orgh; -} - -void aspect_save_prescale(struct vo *vo, int prew, int preh) -{ - mp_msg(MSGT_VO, MSGL_DBG2, "aspect_save_prescale %dx%d\n", prew, preh); - vo->aspdat.prew = prew; - vo->aspdat.preh = preh; + vo->aspdat.orgw = w; + vo->aspdat.orgh = h; + vo->aspdat.prew = d_w; + vo->aspdat.preh = d_h; + vo->aspdat.par = (double)d_w / d_h * h / w; } void aspect_save_screenres(struct vo *vo, int scrw, int scrh) @@ -52,9 +47,9 @@ void aspect_save_screenres(struct vo *vo, int scrw, int scrh) vo->aspdat.scrw = scrw; vo->aspdat.scrh = scrh; if (opts->force_monitor_aspect) - vo->monitor_aspect = opts->force_monitor_aspect; + vo->monitor_par = opts->force_monitor_aspect * scrh / scrw; else - vo->monitor_aspect = opts->monitor_pixel_aspect * scrw / scrh; + vo->monitor_par = 1.0 / opts->monitor_pixel_aspect; } /* aspect is called with the source resolution and the @@ -64,17 +59,17 @@ void aspect_save_screenres(struct vo *vo, int scrw, int scrh) void aspect_fit(struct vo *vo, int *srcw, int *srch, int fitw, int fith) { struct aspect_data *aspdat = &vo->aspdat; - float pixelaspect = vo->monitor_aspect * aspdat->scrh / aspdat->scrw; + float pixelaspect = vo->monitor_par; - mp_msg(MSGT_VO, MSGL_DBG2, "aspect(0) fitin: %dx%d screenaspect: %.2f\n", - fitw, fith, vo->monitor_aspect); + mp_msg(MSGT_VO, MSGL_DBG2, "aspect(0) fitin: %dx%d monitor_par: %.2f\n", + fitw, fith, vo->monitor_par); *srcw = fitw; - *srch = (float)fitw / aspdat->prew * aspdat->preh * pixelaspect; + *srch = (float)fitw / aspdat->prew * aspdat->preh / pixelaspect; *srch += *srch % 2; // round mp_msg(MSGT_VO, MSGL_DBG2, "aspect(1) wh: %dx%d (org: %dx%d)\n", *srcw, *srch, aspdat->prew, aspdat->preh); if (*srch > fith || *srch < aspdat->orgh) { - int tmpw = (float)fith / aspdat->preh * aspdat->prew / pixelaspect; + int tmpw = (float)fith / aspdat->preh * aspdat->prew * pixelaspect; tmpw += tmpw % 2; // round if (tmpw <= fitw) { *srch = fith; diff --git a/libvo/aspect.h b/libvo/aspect.h index aa117833f3..c5247421d2 100644 --- a/libvo/aspect.h +++ b/libvo/aspect.h @@ -24,10 +24,7 @@ struct vo; void panscan_init(struct vo *vo); void panscan_calc_windowed(struct vo *vo); -void aspect_save_orig(struct vo *vo, int orgw, int orgh); - -void aspect_save_prescale(struct vo *vo, int prew, int preh); - +void aspect_save_videores(struct vo *vo, int w, int h, int d_w, int d_h); void aspect_save_screenres(struct vo *vo, int scrw, int scrh); #define A_WINZOOM 2 ///< zoom to fill window size diff --git a/libvo/video_out.c b/libvo/video_out.c index 18a8482c18..2503fa93e3 100644 --- a/libvo/video_out.c +++ b/libvo/video_out.c @@ -370,8 +370,7 @@ int vo_config(struct vo *vo, uint32_t width, uint32_t height, { struct MPOpts *opts = vo->opts; panscan_init(vo); - aspect_save_orig(vo, width, height); - aspect_save_prescale(vo, d_width, d_height); + aspect_save_videores(vo, width, height, d_width, d_height); if (vo_control(vo, VOCTRL_UPDATE_SCREENINFO, NULL) == VO_TRUE) { aspect(vo, &d_width, &d_height, A_NOZOOM); diff --git a/libvo/video_out.h b/libvo/video_out.h index 5bd84ab4af..2689c244a8 100644 --- a/libvo/video_out.h +++ b/libvo/video_out.h @@ -265,12 +265,13 @@ struct vo { int panscan_x; int panscan_y; float panscan_amount; - float monitor_aspect; + float monitor_par; struct aspect_data { int orgw; // real width int orgh; // real height int prew; // prescaled width int preh; // prescaled height + float par; // pixel aspect ratio out of orgw/orgh and prew/preh int scrw; // horizontal resolution int scrh; // vertical resolution float asp; diff --git a/libvo/vo_lavc.c b/libvo/vo_lavc.c index 5ba548926e..72a1351d85 100644 --- a/libvo/vo_lavc.c +++ b/libvo/vo_lavc.c @@ -34,7 +34,7 @@ #include "encode_lavc.h" #include "sub/sub.h" -#include "sub/draw_bmp.h" +#include "sub/dec_sub.h" struct priv { uint8_t *buffer; @@ -485,6 +485,29 @@ static void check_events(struct vo *vo) { } +static void draw_osd(struct vo *vo, struct osd_state *osd) +{ + struct priv *vc = vo->priv; + + if (vc->lastimg && vc->lastimg_wants_osd) { + struct aspect_data asp = vo->aspdat; + double sar = (double)asp.orgw / asp.orgh; + double dar = (double)asp.prew / asp.preh; + + struct sub_render_params subparams = { + .pts = osd->vo_sub_pts, + .dim = { + .w = asp.orgw, + .h = asp.orgh, + .display_par = sar / dar, + .video_par = dar / sar, + }, + }; + + osd_draw_on_image(osd, vc->lastimg, &vc->colorspace, &subparams); + } +} + static int control(struct vo *vo, uint32_t request, void *data) { struct priv *vc = vo->priv; @@ -506,25 +529,6 @@ static int control(struct vo *vo, uint32_t request, void *data) case VOCTRL_GET_YUV_COLORSPACE: *(struct mp_csp_details *)data = vc->colorspace; return 1; - case VOCTRL_DRAW_EOSD: - if (vc->lastimg && vc->lastimg_wants_osd) { - struct sub_bitmaps *imgs = data; - mp_draw_sub_bitmaps(vc->lastimg, imgs, &vc->colorspace); - } - return VO_TRUE; - case VOCTRL_GET_EOSD_RES: { - struct mp_eosd_res *r = data; - r->w = vc->stream->codec->width; - r->h = vc->stream->codec->height; - r->ml = r->mr = 0; - r->mt = r->mb = 0; - return VO_TRUE; - } - case VOCTRL_QUERY_EOSD_FORMAT: { - int format = *(int *)data; - return (format == SUBBITMAP_LIBASS || format == SUBBITMAP_RGBA) - ? VO_TRUE : VO_NOTIMPL; - } } return VO_NOTIMPL; } @@ -543,7 +547,7 @@ const struct vo_driver video_out_lavc = { .control = control, .uninit = uninit, .check_events = check_events, - .draw_osd = draw_osd_with_eosd, + .draw_osd = draw_osd, .flip_page_timed = flip_page_timed, }; diff --git a/libvo/vo_x11.c b/libvo/vo_x11.c index 8725279bb8..6ea95527f3 100644 --- a/libvo/vo_x11.c +++ b/libvo/vo_x11.c @@ -43,7 +43,6 @@ #include "sub/sub.h" #include "sub/dec_sub.h" -#include "sub/draw_bmp.h" #include "libmpcodecs/sws_utils.h" #define MODE_RGB 0x1 @@ -446,9 +445,12 @@ static void draw_osd(struct vo *vo, struct osd_state *osd) struct sub_render_params subparams = { .pts = osd->vo_sub_pts, - .dim = {.w = img.w, .h = img.h}, - .normal_scale = 1, - .vsfilter_scale = 1, + .dim = { + .w = img.w, + .h = img.h, + .display_par = vo->monitor_par, + .video_par = vo->aspdat.par, + }, }; osd_draw_on_image(osd, &img, &csp, &subparams); diff --git a/libvo/vo_xv.c b/libvo/vo_xv.c index b62eaf18d7..8ea22c4da4 100644 --- a/libvo/vo_xv.c +++ b/libvo/vo_xv.c @@ -344,11 +344,18 @@ static void draw_osd(struct vo *vo, struct osd_state *osd) struct mp_csp_details csp = {0}; vo_control(vo, VOCTRL_GET_YUV_COLORSPACE, &csp); + struct vo_rect *src = &ctx->src_rect; + struct vo_rect *dst = &ctx->dst_rect; + double xvpar = (double)dst->width / dst->height * src->height / src->width; + struct sub_render_params subparams = { .pts = osd->vo_sub_pts, - .dim = {.w = ctx->image_width, .h = ctx->image_height}, - .normal_scale = 1, - .vsfilter_scale = 1, + .dim = { + .w = ctx->image_width, + .h = ctx->image_height, + .display_par = vo->monitor_par / xvpar, + .video_par = vo->aspdat.par, + }, }; if (osd_draw_on_image(osd, &img, &csp, &subparams)) diff --git a/sub/dec_sub.h b/sub/dec_sub.h index 0c5c1ab7ee..389851503e 100644 --- a/sub/dec_sub.h +++ b/sub/dec_sub.h @@ -13,8 +13,6 @@ struct MPOpts *opts; struct sub_render_params { double pts; struct mp_eosd_res dim; - double normal_scale; - double vsfilter_scale; }; static inline bool is_text_sub(int type) diff --git a/sub/osd_libass.c b/sub/osd_libass.c index d77c0d1af2..a182c6bdf2 100644 --- a/sub/osd_libass.c +++ b/sub/osd_libass.c @@ -283,6 +283,7 @@ void osd_object_get_bitmaps(struct osd_state *osd, struct osd_object *obj, return; ass_set_frame_size(osd->osd_render, osd->res.w, osd->res.h); + ass_set_aspect_ratio(osd->osd_render, osd->res.display_par, 1.0); 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 a5e23d74da..7926820ece 100644 --- a/sub/sd_ass.c +++ b/sub/sd_ass.c @@ -137,11 +137,11 @@ static void get_bitmaps(struct sh_sub *sh, struct osd_state *osd, if (params->pts == MP_NOPTS_VALUE) return; - double scale = params->normal_scale; + double scale = params->dim.display_par; bool use_vs_aspect = opts->ass_style_override ? opts->ass_vsfilter_aspect_compat : 1; if (ctx->vsfilter_aspect && use_vs_aspect) - scale = params->vsfilter_scale; + scale = scale * params->dim.video_par; ASS_Renderer *renderer = osd->ass_renderer; mp_ass_configure(renderer, opts, ¶ms->dim); ass_set_aspect_ratio(renderer, scale, 1); diff --git a/sub/sub.c b/sub/sub.c index 862f5d1f6e..8599002927 100644 --- a/sub/sub.c +++ b/sub/sub.c @@ -270,15 +270,14 @@ void draw_osd_with_eosd(struct vo *vo, struct osd_state *osd) formats[n] = vo_control(vo, VOCTRL_QUERY_EOSD_FORMAT, &data) == VO_TRUE; } - osd_update_ext(osd, dim); + dim.display_par = vo->monitor_par; + dim.video_par = vo->aspdat.par; - struct aspect_data asp = vo->aspdat; + osd_update_ext(osd, dim); struct sub_render_params subparams = { .pts = osd->vo_sub_pts, .dim = dim, - .normal_scale = 1, - .vsfilter_scale = (double) asp.prew / asp.preh * asp.orgh / asp.orgw, }; for (int n = 0; n < MAX_OSD_PARTS; n++) { diff --git a/sub/sub.h b/sub/sub.h index 4f3ca905b6..3d40186b60 100644 --- a/sub/sub.h +++ b/sub/sub.h @@ -82,6 +82,8 @@ struct sub_bitmaps { struct mp_eosd_res { int w, h; // screen dimensions, including black borders int mt, mb, ml, mr; // borders (top, bottom, left, right) + double display_par; + double video_par; // PAR of the original video (for some sub decoders) }; enum mp_osdtype { From 97c6425140aecc3910a622fb0ad7d79916cfebbe Mon Sep 17 00:00:00 2001 From: wm4 Date: Fri, 19 Oct 2012 19:11:08 +0200 Subject: [PATCH 46/83] sub, vf_ass: allow rendering RGBA subs, replace old vf_ass rendering Do this by replacing all the old vf_ass drawing code by draw_bmp.c. Change sub.c to always use osd_draw() for the other OSD drawing routines, and simplify the code a bit. spudec.c subtitles (i.e. DVD subs) are now considered subtitles, and are rendered by vf_ass, if that filter is inserted. --- libmpcodecs/vf_ass.c | 171 ++++--------------------------------------- libvo/vo_lavc.c | 2 +- libvo/vo_x11.c | 2 +- libvo/vo_xv.c | 2 +- sub/sub.c | 122 +++++++++++++++--------------- sub/sub.h | 17 +++-- 6 files changed, 88 insertions(+), 228 deletions(-) diff --git a/libmpcodecs/vf_ass.c b/libmpcodecs/vf_ass.c index 167ebd6e15..9695ecfdfc 100644 --- a/libmpcodecs/vf_ass.c +++ b/libmpcodecs/vf_ass.c @@ -38,25 +38,16 @@ #include "sub/dec_sub.h" #include "libvo/fastmemcpy.h" +#include "libvo/csputils.h" #include "m_option.h" #include "m_struct.h" -#include "sub/ass_mp.h" - -#define _r(c) ((c)>>24) -#define _g(c) (((c)>>16)&0xFF) -#define _b(c) (((c)>>8)&0xFF) -#define _a(c) ((c)&0xFF) -#define rgba2y(c) ( (( 263*_r(c) + 516*_g(c) + 100*_b(c)) >> 10) + 16 ) -#define rgba2u(c) ( ((-152*_r(c) - 298*_g(c) + 450*_b(c)) >> 10) + 128 ) -#define rgba2v(c) ( (( 450*_r(c) - 376*_g(c) - 73*_b(c)) >> 10) + 128 ) - - static const struct vf_priv_s { int outh, outw; unsigned int outfmt; + struct mp_csp_details csp; // 1 = auto-added filter: insert only if chain does not support EOSD already // 0 = insert always @@ -64,13 +55,9 @@ static const struct vf_priv_s { struct osd_state *osd; struct mp_eosd_res dim; - - unsigned char *planes[3]; - struct line_limits { - uint16_t start; - uint16_t end; - } *line_limits; -} vf_priv_dflt; +} vf_priv_dflt = { + .csp = MP_CSP_DETAILS_DEFAULTS, +}; static int config(struct vf_instance *vf, int width, int height, int d_width, int d_height, @@ -88,10 +75,6 @@ static int config(struct vf_instance *vf, d_height = d_height * vf->priv->outh / height; } - vf->priv->planes[1] = malloc(vf->priv->outw * vf->priv->outh); - vf->priv->planes[2] = malloc(vf->priv->outw * vf->priv->outh); - vf->priv->line_limits = malloc((vf->priv->outh + 1) / 2 * sizeof(*vf->priv->line_limits)); - double dar = (double)d_width / d_height; double sar = (double)width / height; @@ -236,148 +219,22 @@ static int prepare_image(struct vf_instance *vf, mp_image_t *mpi) return 0; } -static void update_limits(struct vf_instance *vf, int starty, int endy, - int startx, int endx) -{ - starty >>= 1; - endy = (endy + 1) >> 1; - startx >>= 1; - endx = (endx + 1) >> 1; - for (int i = starty; i < endy; i++) { - struct line_limits *ll = vf->priv->line_limits + i; - if (startx < ll->start) - ll->start = startx; - if (endx > ll->end) - ll->end = endx; - } -} - -/** - * \brief Copy specified rows from render_context.dmpi to render_context.planes, upsampling to 4:4:4 - */ -static void copy_from_image(struct vf_instance *vf) -{ - int pl; - - for (pl = 1; pl < 3; ++pl) { - int dst_stride = vf->priv->outw; - int src_stride = vf->dmpi->stride[pl]; - - unsigned char *src = vf->dmpi->planes[pl]; - unsigned char *dst = vf->priv->planes[pl]; - for (int i = 0; i < (vf->priv->outh + 1) / 2; i++) { - struct line_limits *ll = vf->priv->line_limits + i; - unsigned char *dst_next = dst + dst_stride; - for (int j = ll->start; j < ll->end; j++) { - unsigned char val = src[j]; - dst[j << 1] = val; - dst[(j << 1) + 1] = val; - dst_next[j << 1] = val; - dst_next[(j << 1) + 1] = val; - } - src += src_stride; - dst = dst_next + dst_stride; - } - } -} - -/** - * \brief Copy all previously copied rows back to render_context.dmpi - */ -static void copy_to_image(struct vf_instance *vf) -{ - int pl; - int i, j; - for (pl = 1; pl < 3; ++pl) { - int dst_stride = vf->dmpi->stride[pl]; - int src_stride = vf->priv->outw; - - unsigned char *dst = vf->dmpi->planes[pl]; - unsigned char *src = vf->priv->planes[pl]; - unsigned char *src_next = vf->priv->planes[pl] + src_stride; - for (i = 0; i < vf->priv->outh / 2; ++i) { - for (j = vf->priv->line_limits[i].start; j < vf->priv->line_limits[i].end; j++) { - unsigned val = 0; - val += src[j << 1]; - val += src[(j << 1) + 1]; - val += src_next[j << 1]; - val += src_next[(j << 1) + 1]; - dst[j] = val >> 2; - } - dst += dst_stride; - src = src_next + src_stride; - src_next = src + src_stride; - } - } -} - -static void my_draw_bitmap(struct vf_instance *vf, unsigned char *bitmap, - int bitmap_w, int bitmap_h, int stride, - int dst_x, int dst_y, unsigned color) -{ - unsigned char y = rgba2y(color); - unsigned char u = rgba2u(color); - unsigned char v = rgba2v(color); - unsigned char opacity = 255 - _a(color); - unsigned char *src, *dsty, *dstu, *dstv; - int i, j; - mp_image_t *dmpi = vf->dmpi; - - src = bitmap; - dsty = dmpi->planes[0] + dst_x + dst_y * dmpi->stride[0]; - dstu = vf->priv->planes[1] + dst_x + dst_y * vf->priv->outw; - dstv = vf->priv->planes[2] + dst_x + dst_y * vf->priv->outw; - for (i = 0; i < bitmap_h; ++i) { - for (j = 0; j < bitmap_w; ++j) { - unsigned k = (src[j] * opacity + 255) >> 8; - dsty[j] = (k * y + (255 - k) * dsty[j] + 255) >> 8; - dstu[j] = (k * u + (255 - k) * dstu[j] + 255) >> 8; - dstv[j] = (k * v + (255 - k) * dstv[j] + 255) >> 8; - } - src += stride; - dsty += dmpi->stride[0]; - dstu += vf->priv->outw; - dstv += vf->priv->outw; - } -} - -static int render_frame(struct vf_instance *vf, mp_image_t *mpi, - const ASS_Image *img) -{ - if (img) { - for (int i = 0; i < (vf->priv->outh + 1) / 2; i++) - vf->priv->line_limits[i] = (struct line_limits){65535, 0}; - for (const ASS_Image *im = img; im; im = im->next) - update_limits(vf, im->dst_y, im->dst_y + im->h, - im->dst_x, im->dst_x + im->w); - copy_from_image(vf); - while (img) { - my_draw_bitmap(vf, img->bitmap, img->w, img->h, img->stride, - img->dst_x, img->dst_y, img->color); - img = img->next; - } - copy_to_image(vf); - } - return 0; -} - static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts) { struct vf_priv_s *priv = vf->priv; struct osd_state *osd = priv->osd; - struct sub_bitmaps imgs = (struct sub_bitmaps) {0}; + + prepare_image(vf, mpi); + if (pts != MP_NOPTS_VALUE) { struct sub_render_params subparams = { .pts = pts, .dim = priv->dim, }; - bool formats[SUBBITMAP_COUNT] = {[SUBBITMAP_LIBASS] = true}; - osd_draw_sub(osd, &imgs, &subparams, formats); + osd_draw_on_image(osd, &subparams, OSD_DRAW_SUB_FILTER, vf->dmpi, + &priv->csp); } - prepare_image(vf, mpi); - render_frame(vf, mpi, imgs.imgs); - return vf_next_put_image(vf, vf->dmpi, pts); } @@ -400,15 +257,17 @@ static int control(vf_instance_t *vf, int request, void *data) break; case VFCTRL_INIT_OSD: return CONTROL_TRUE; + case VFCTRL_SET_YUV_COLORSPACE: { + struct mp_csp_details colorspace = *(struct mp_csp_details *)data; + vf->priv->csp = colorspace; + break; + } } return vf_next_control(vf, request, data); } static void uninit(struct vf_instance *vf) { - free(vf->priv->planes[1]); - free(vf->priv->planes[2]); - free(vf->priv->line_limits); free(vf->priv); } diff --git a/libvo/vo_lavc.c b/libvo/vo_lavc.c index 72a1351d85..caa3b4202c 100644 --- a/libvo/vo_lavc.c +++ b/libvo/vo_lavc.c @@ -504,7 +504,7 @@ static void draw_osd(struct vo *vo, struct osd_state *osd) }, }; - osd_draw_on_image(osd, vc->lastimg, &vc->colorspace, &subparams); + osd_draw_on_image(osd, &subparams, 0, vc->lastimg, &vc->colorspace); } } diff --git a/libvo/vo_x11.c b/libvo/vo_x11.c index 6ea95527f3..61066a2ec6 100644 --- a/libvo/vo_x11.c +++ b/libvo/vo_x11.c @@ -453,7 +453,7 @@ static void draw_osd(struct vo *vo, struct osd_state *osd) }, }; - osd_draw_on_image(osd, &img, &csp, &subparams); + osd_draw_on_image(osd, &subparams, 0, &img, &csp); } static void flip_page(struct vo *vo) diff --git a/libvo/vo_xv.c b/libvo/vo_xv.c index 8ea22c4da4..9aca1005ec 100644 --- a/libvo/vo_xv.c +++ b/libvo/vo_xv.c @@ -358,7 +358,7 @@ static void draw_osd(struct vo *vo, struct osd_state *osd) }, }; - if (osd_draw_on_image(osd, &img, &csp, &subparams)) + if (osd_draw_on_image(osd, &subparams, 0, &img, &csp)) ctx->unchanged_image = false; } diff --git a/sub/sub.c b/sub/sub.c index 8599002927..0438ffccab 100644 --- a/sub/sub.c +++ b/sub/sub.c @@ -127,7 +127,7 @@ struct osd_state *osd_create(struct MPOpts *opts, struct ass_library *asslib) osd->objs[n] = obj; } - // OSDTYPE_SPU is an odd case, because vf_ass.c can't render it. + osd->objs[OSDTYPE_SPU]->is_sub = true; // spudec.c osd->objs[OSDTYPE_SUB]->is_sub = true; // dec_sub.c osd->objs[OSDTYPE_SUBTITLE]->is_sub = true; // osd_libass.c @@ -162,17 +162,14 @@ static bool spu_visible(struct osd_state *osd, struct osd_object *obj) 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, +static void render_object(struct osd_state *osd, struct osd_object *obj, struct sub_bitmaps *out_imgs, struct sub_render_params *sub_params, const bool formats[SUBBITMAP_COUNT]) { - memset(out_imgs, 0x55, sizeof(*out_imgs)); + *out_imgs = (struct sub_bitmaps) {0}; if (obj->type == OSDTYPE_SPU) { - *out_imgs = (struct sub_bitmaps) {0}; if (spu_visible(osd, obj)) { //spudec_get_bitmap(vo_spudec, osd->res.w, osd->res.h, out_imgs); spudec_get_indexed(vo_spudec, &osd->res, out_imgs); @@ -196,14 +193,14 @@ static bool render_object(struct osd_state *osd, struct osd_object *obj, obj->vo_bitmap_pos_id += out_imgs->bitmap_pos_id; if (out_imgs->num_parts == 0) - return false; + return; if (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 out_imgs->num_parts > 0; + return; } out_imgs->render_index = obj->type; @@ -211,7 +208,7 @@ static bool render_object(struct osd_state *osd, struct osd_object *obj, out_imgs->bitmap_pos_id = obj->vo_bitmap_pos_id; if (formats[out_imgs->format]) - return out_imgs->num_parts > 0; + return; bool cached = false; // do we have a copy of all the image data? @@ -221,41 +218,46 @@ static bool render_object(struct osd_state *osd, struct osd_object *obj, if (cached) obj->cached = *out_imgs; - - if (!formats[out_imgs->format]) { - mp_msg(MSGT_OSD, MSGL_ERR, "Can't render OSD part %d (format %d).\n", - obj->type, out_imgs->format); - return false; - } - return out_imgs->num_parts > 0; } -// This is a hack to render the first subtitle OSD object, which is not empty. -// It's a hack because it's really only useful for subtitles: normal OSD can -// have multiple objects, and rendering one object may invalidate data of a -// previously rendered, different object (that's how osd_libass.c works). -// Also, it assumes this is called from a filter: it disables VO rendering of -// subtitles, because we don't want to render both. -bool osd_draw_sub(struct osd_state *osd, struct sub_bitmaps *out_imgs, - struct sub_render_params *sub_params, - const bool formats[SUBBITMAP_COUNT]) +// draw_flags is a bit field of OSD_DRAW_* constants +void osd_draw(struct osd_state *osd, struct sub_render_params *params, + int draw_flags, const bool formats[SUBBITMAP_COUNT], + void (*cb)(void *ctx, struct sub_bitmaps *imgs), void *cb_ctx) { - *out_imgs = (struct sub_bitmaps) {0}; + if (draw_flags & OSD_DRAW_SUB_FILTER) + draw_flags |= OSD_DRAW_SUB_ONLY; + + osd_update_ext(osd, params->dim); + for (int n = 0; n < MAX_OSD_PARTS; n++) { struct osd_object *obj = osd->objs[n]; - if (obj->is_sub) { - // hack to allow rendering non-ASS subs with vf_ass inserted - // (vf_ass is auto-inserted if VOs don't support EOSD) -#ifdef CONFIG_ASS - osd->render_subs_in_filter = !!sub_get_ass_track(osd); - if (!osd->render_subs_in_filter) - return false; -#endif - if (render_object(osd, obj, out_imgs, sub_params, formats)) - return true; + + // Object is drawn into the video frame itself; don't draw twice + if (osd->render_subs_in_filter && obj->is_sub && + !(draw_flags & OSD_DRAW_SUB_FILTER)) + continue; + if ((draw_flags & OSD_DRAW_SUB_ONLY) && !obj->is_sub) + continue; + + struct sub_bitmaps imgs; + render_object(osd, obj, &imgs, params, formats); + if (imgs.num_parts > 0) { + if (formats[imgs.format]) { + cb(cb_ctx, &imgs); + } else { + mp_msg(MSGT_OSD, MSGL_ERR, + "Can't render OSD part %d (format %d).\n", + obj->type, imgs.format); + } } } - return false; +} + +static void vo_draw_eosd(void *ctx, struct sub_bitmaps *imgs) +{ + struct vo *vo = ctx; + vo_control(vo, VOCTRL_DRAW_EOSD, imgs); } void draw_osd_with_eosd(struct vo *vo, struct osd_state *osd) @@ -273,45 +275,39 @@ void draw_osd_with_eosd(struct vo *vo, struct osd_state *osd) dim.display_par = vo->monitor_par; dim.video_par = vo->aspdat.par; - osd_update_ext(osd, dim); - struct sub_render_params subparams = { .pts = osd->vo_sub_pts, .dim = dim, }; - for (int n = 0; n < MAX_OSD_PARTS; n++) { - struct osd_object *obj = osd->objs[n]; - if (obj->is_sub && osd->render_subs_in_filter) - continue; - struct sub_bitmaps imgs; - if (render_object(osd, obj, &imgs, &subparams, formats)) - vo_control(vo, VOCTRL_DRAW_EOSD, &imgs); - } + osd_draw(osd, &subparams, 0, formats, &vo_draw_eosd, vo); +} + +struct draw_on_image_closure { + struct mp_image *dest; + struct mp_csp_details *dest_csp; + bool changed; +}; + +static void draw_on_image(void *ctx, struct sub_bitmaps *imgs) +{ + struct draw_on_image_closure *closure = ctx; + mp_draw_sub_bitmaps(closure->dest, imgs, closure->dest_csp); + closure->changed = true; } // Returns whether anything was drawn. -bool osd_draw_on_image(struct osd_state *osd, struct mp_image *dest, - struct mp_csp_details *dest_csp, - struct sub_render_params *sub_params) +bool osd_draw_on_image(struct osd_state *osd, struct sub_render_params *params, + int draw_flags, struct mp_image *dest, + struct mp_csp_details *dest_csp) { static const bool formats[SUBBITMAP_COUNT] = { [SUBBITMAP_LIBASS] = true, [SUBBITMAP_RGBA] = true, }; - bool changed = false; - osd_update_ext(osd, sub_params->dim); - for (int n = 0; n < MAX_OSD_PARTS; n++) { - struct osd_object *obj = osd->objs[n]; - if (obj->is_sub && osd->render_subs_in_filter) - continue; - struct sub_bitmaps imgs; - if (render_object(osd, obj, &imgs, sub_params, formats)) { - mp_draw_sub_bitmaps(dest, &imgs, dest_csp); - changed = true; - } - } - return changed; + struct draw_on_image_closure closure = {dest, dest_csp}; + osd_draw(osd, params, draw_flags, formats, &draw_on_image, &closure); + return closure.changed; } void vo_osd_changed(int new_value) diff --git a/sub/sub.h b/sub/sub.h index 3d40186b60..ecfd0c40cc 100644 --- a/sub/sub.h +++ b/sub/sub.h @@ -212,15 +212,20 @@ void vo_osd_reset_changed(void); bool vo_osd_has_changed(struct osd_state *osd); void osd_free(struct osd_state *osd); -bool osd_draw_sub(struct osd_state *osd, struct sub_bitmaps *out_imgs, - struct sub_render_params *sub_params, - const bool formats[SUBBITMAP_COUNT]); +enum mp_osd_draw_flags { + OSD_DRAW_SUB_FILTER = (1 << 0), + OSD_DRAW_SUB_ONLY = (1 << 1), +}; + +void osd_draw(struct osd_state *osd, struct sub_render_params *params, + int draw_flags, const bool formats[SUBBITMAP_COUNT], + void (*cb)(void *ctx, struct sub_bitmaps *imgs), void *cb_ctx); struct mp_image; struct mp_csp_details; -bool osd_draw_on_image(struct osd_state *osd, struct mp_image *dest, - struct mp_csp_details *dest_csp, - struct sub_render_params *sub_params); +bool osd_draw_on_image(struct osd_state *osd, struct sub_render_params *params, + int draw_flags, struct mp_image *dest, + struct mp_csp_details *dest_csp); bool sub_bitmaps_bb(struct sub_bitmaps *imgs, int *x1, int *y1, int *x2, int *y2); From bf68634d15c747fd05f118b1bd95e3017c1eb6bb Mon Sep 17 00:00:00 2001 From: wm4 Date: Fri, 19 Oct 2012 17:49:49 +0200 Subject: [PATCH 47/83] sub: add cache to mp_draw_sub_bitmaps() This caches scaled RGBA sub-bitmaps. --- sub/draw_bmp.c | 77 ++++++++++++++++++++++++++++++++++++++++++++------ sub/draw_bmp.h | 9 ++++-- sub/sub.c | 15 +++++----- sub/sub.h | 4 ++- 4 files changed, 86 insertions(+), 19 deletions(-) diff --git a/sub/draw_bmp.c b/sub/draw_bmp.c index fba3513ee4..315e52dfdd 100644 --- a/sub/draw_bmp.c +++ b/sub/draw_bmp.c @@ -19,6 +19,7 @@ #include "sub/draw_bmp.h" #include +#include #include #include "sub/sub.h" @@ -27,6 +28,26 @@ #include "libmpcodecs/img_format.h" #include "libvo/csputils.h" +const bool mp_draw_sub_formats[SUBBITMAP_COUNT] = { + [SUBBITMAP_LIBASS] = true, + [SUBBITMAP_RGBA] = true, +}; + +struct sub_cache { + struct mp_image *i, *a; +}; + +struct part { + int bitmap_pos_id; + int num_imgs; + struct sub_cache *imgs; +}; + +struct mp_draw_sub_cache +{ + struct part *parts[MAX_OSD_PARTS]; +}; + #define ACCURATE #define CONDITIONAL #define CONDITIONAL2 @@ -430,8 +451,11 @@ static bool align_bbox_to_swscale_requirements(int *x1, int *y1, return (*x2 > *x1) && (*y2 > *y1); } -void mp_draw_sub_bitmaps(struct mp_image *dst, struct sub_bitmaps *sbs, - struct mp_csp_details *csp) +// cache: if not NULL, the function will set *cache to a talloc-allocated cache +// containing scaled versions of sbs contents - free the cache with +// talloc_free() +void mp_draw_sub_bitmaps(struct mp_draw_sub_cache **cache, struct mp_image *dst, + struct sub_bitmaps *sbs, struct mp_csp_details *csp) { int i; int x1, y1, x2, y2; @@ -440,6 +464,29 @@ void mp_draw_sub_bitmaps(struct mp_image *dst, struct sub_bitmaps *sbs, float yuv2rgb[3][4]; float rgb2yuv[3][4]; + if (cache && !*cache) + *cache = talloc_zero(NULL, struct mp_draw_sub_cache); + + struct part *part = NULL; + + bool use_cache = sbs->format == SUBBITMAP_RGBA; + if (cache && use_cache) { + part = (*cache)->parts[sbs->render_index]; + if (part && part->bitmap_pos_id != sbs->bitmap_pos_id) { + talloc_free(part); + part = NULL; + } + if (!part) { + part = talloc_zero(*cache, struct part); + part->bitmap_pos_id = sbs->bitmap_pos_id; + part->num_imgs = sbs->num_parts; + part->imgs = talloc_zero_array(part, struct sub_cache, + part->num_imgs); + } + assert(part->num_imgs == sbs->num_parts); + (*cache)->parts[sbs->render_index] = part; + } + #ifdef ACCURATE int format = IMGFMT_444P16; int bits = 16; @@ -528,11 +575,20 @@ void mp_draw_sub_bitmaps(struct mp_image *dst, struct sub_bitmaps *sbs, 0, 0, temp->w, temp->h)) continue; - if (!sub_bitmap_to_mp_images(&sbi, color_yuv, &color_a, &sba, sb, - sbs->format, csp, rgb2yuv, format, bits)) { - mp_msg(MSGT_VO, MSGL_ERR, - "render_sub_bitmap: invalid sub bitmap type\n"); - continue; + if (part) { + sbi = part->imgs[i].i; + sba = part->imgs[i].a; + } + + if (!(sbi && sba)) { + if (!sub_bitmap_to_mp_images(&sbi, color_yuv, &color_a, &sba, sb, + sbs->format, csp, rgb2yuv, format, + bits)) + { + mp_msg(MSGT_VO, MSGL_ERR, + "render_sub_bitmap: invalid sub bitmap type\n"); + continue; + } } // call blend_alpha 3 times @@ -563,10 +619,13 @@ void mp_draw_sub_bitmaps(struct mp_image *dst, struct sub_bitmaps *sbs, } } - if (sbi) + if (part) { + part->imgs[i].i = talloc_steal(part, sbi); + part->imgs[i].a = talloc_steal(part, sba); + } else { free_mp_image(sbi); - if (sba) free_mp_image(sba); + } } if (temp != &dst_region) { diff --git a/sub/draw_bmp.h b/sub/draw_bmp.h index 478965af15..b7ebcf5e8a 100644 --- a/sub/draw_bmp.h +++ b/sub/draw_bmp.h @@ -1,11 +1,16 @@ #ifndef MPLAYER_DRAW_BMP_H #define MPLAYER_DRAW_BMP_H +#include "sub/sub.h" + struct mp_image; struct sub_bitmaps; struct mp_csp_details; -void mp_draw_sub_bitmaps(struct mp_image *dst, struct sub_bitmaps *sbs, - struct mp_csp_details *csp); +struct mp_draw_sub_cache; +void mp_draw_sub_bitmaps(struct mp_draw_sub_cache **cache, struct mp_image *dst, + struct sub_bitmaps *sbs, struct mp_csp_details *csp); + +extern const bool mp_draw_sub_formats[SUBBITMAP_COUNT]; #endif /* MPLAYER_DRAW_BMP_H */ diff --git a/sub/sub.c b/sub/sub.c index 0438ffccab..6c0f740766 100644 --- a/sub/sub.c +++ b/sub/sub.c @@ -284,6 +284,7 @@ void draw_osd_with_eosd(struct vo *vo, struct osd_state *osd) } struct draw_on_image_closure { + struct osd_state *osd; struct mp_image *dest; struct mp_csp_details *dest_csp; bool changed; @@ -292,7 +293,10 @@ struct draw_on_image_closure { static void draw_on_image(void *ctx, struct sub_bitmaps *imgs) { struct draw_on_image_closure *closure = ctx; - mp_draw_sub_bitmaps(closure->dest, imgs, closure->dest_csp); + struct osd_state *osd = closure->osd; + mp_draw_sub_bitmaps(&osd->draw_cache, closure->dest, imgs, + closure->dest_csp); + talloc_steal(osd, osd->draw_cache); closure->changed = true; } @@ -301,12 +305,9 @@ bool osd_draw_on_image(struct osd_state *osd, struct sub_render_params *params, int draw_flags, struct mp_image *dest, struct mp_csp_details *dest_csp) { - static const bool formats[SUBBITMAP_COUNT] = { - [SUBBITMAP_LIBASS] = true, - [SUBBITMAP_RGBA] = true, - }; - struct draw_on_image_closure closure = {dest, dest_csp}; - osd_draw(osd, params, draw_flags, formats, &draw_on_image, &closure); + struct draw_on_image_closure closure = {osd, dest, dest_csp}; + osd_draw(osd, params, draw_flags, mp_draw_sub_formats, + &draw_on_image, &closure); return closure.changed; } diff --git a/sub/sub.h b/sub/sub.h index ecfd0c40cc..494b84379b 100644 --- a/sub/sub.h +++ b/sub/sub.h @@ -106,7 +106,6 @@ struct osd_object { // caches for OSD conversion (internal to render_object()) struct osd_conv_cache *cache[OSD_CONV_CACHE_MAX]; - struct sub_bitmaps cached; // VO cache state @@ -138,6 +137,9 @@ struct osd_state { struct MPOpts *opts; + // Internal to sub.c + struct mp_draw_sub_cache *draw_cache; + // Internally used by osd_libass.c struct ass_renderer *osd_render; struct ass_library *osd_ass_library; From a4f9077f6c1a897120616cc70c1ca37c6a247be2 Mon Sep 17 00:00:00 2001 From: wm4 Date: Fri, 19 Oct 2012 19:11:58 +0200 Subject: [PATCH 48/83] draw_bmp: don't try to call swscale if image format not supported If that happens, we silently fail. --- libmpcodecs/sws_utils.c | 8 ++++++++ libmpcodecs/sws_utils.h | 9 +++++++-- sub/draw_bmp.c | 3 +++ 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/libmpcodecs/sws_utils.c b/libmpcodecs/sws_utils.c index 65b079dd84..d7500efe2e 100644 --- a/libmpcodecs/sws_utils.c +++ b/libmpcodecs/sws_utils.c @@ -131,6 +131,14 @@ struct SwsContext *sws_getContextFromCmdLine_hq(int srcW, int srcH, SWS_ACCURATE_RND | SWS_BITEXACT); } +bool mp_sws_supported_format(int imgfmt) +{ + enum PixelFormat av_format = imgfmt2pixfmt(imgfmt); + + return av_format != PIX_FMT_NONE && sws_isSupportedInput(av_format) + && sws_isSupportedOutput(av_format); +} + void mp_image_swscale(struct mp_image *dst, const struct mp_image *src, struct mp_csp_details *csp, diff --git a/libmpcodecs/sws_utils.h b/libmpcodecs/sws_utils.h index b2c55eb407..70b7d0b7fb 100644 --- a/libmpcodecs/sws_utils.h +++ b/libmpcodecs/sws_utils.h @@ -1,6 +1,7 @@ #ifndef MPLAYER_SWS_UTILS_H #define MPLAYER_SWS_UTILS_H +#include #include struct mp_image; @@ -22,8 +23,12 @@ struct SwsContext *sws_getContextFromCmdLine_hq(int srcW, int srcH, int dstFormat); int mp_sws_set_colorspace(struct SwsContext *sws, struct mp_csp_details *csp); -void mp_image_swscale(struct mp_image *dst, const struct mp_image *src, - struct mp_csp_details *csp, int my_sws_flags); +bool mp_sws_supported_format(int imgfmt); + +void mp_image_swscale(struct mp_image *dst, + const struct mp_image *src, + struct mp_csp_details *csp, + int my_sws_flags); #endif /* MP_SWS_UTILS_H */ diff --git a/sub/draw_bmp.c b/sub/draw_bmp.c index 315e52dfdd..9945a8fc89 100644 --- a/sub/draw_bmp.c +++ b/sub/draw_bmp.c @@ -464,6 +464,9 @@ void mp_draw_sub_bitmaps(struct mp_draw_sub_cache **cache, struct mp_image *dst, float yuv2rgb[3][4]; float rgb2yuv[3][4]; + if (!mp_sws_supported_format(dst->imgfmt)) + return; + if (cache && !*cache) *cache = talloc_zero(NULL, struct mp_draw_sub_cache); From 4d11f32162b08e3b48ae382e2ed0a151035f8aea Mon Sep 17 00:00:00 2001 From: wm4 Date: Fri, 19 Oct 2012 19:25:18 +0200 Subject: [PATCH 49/83] VO, sub: refactor Remove VFCTRL_DRAW_OSD, VFCAP_EOSD_FILTER, VFCAP_EOSD_RGBA, VFCAP_EOSD, VOCTRL_DRAW_EOSD, VOCTRL_GET_EOSD_RES, VOCTRL_QUERY_EOSD_FORMAT. Remove draw_osd_with_eosd(), which rendered the OSD by calling VOCTRL_DRAW_EOSD. Change VOs to call osd_draw() directly, which takes a callback as argument. (This basically works like the old OSD API, except multiple OSD bitmap formats are supported and caching is possible.) Remove all mentions of "eosd". It's simply "osd" now. Make OSD size per-OSD-object, as they can be different when using vf_sub. Include display_par/video_par in resolution change detection. Fix the issue with margin borders in vo_corevideo. --- DOCS/man/en/vf.rst | 6 +-- DOCS/man/en/vo.rst | 4 +- libmpcodecs/vf.h | 1 - libmpcodecs/vf_ass.c | 16 +++---- libmpcodecs/vf_vo.c | 5 -- libmpcodecs/vfcap.h | 4 -- libvo/gl_osd.c | 33 ++++++++------ libvo/gl_osd.h | 11 +++-- libvo/video_out.h | 3 -- libvo/vo_corevideo.m | 42 +++++++++++------ libvo/vo_direct3d.c | 98 ++++++++++++++++++++++------------------ libvo/vo_lavc.c | 20 ++++---- libvo/vo_opengl.c | 52 ++++++++++----------- libvo/vo_opengl_old.c | 50 ++++++++++---------- libvo/vo_vdpau.c | 103 ++++++++++++++++++++++++------------------ libvo/vo_x11.c | 16 +++---- libvo/vo_xv.c | 18 +++----- mplayer.c | 29 ++++++------ sub/ass_mp.c | 6 +-- sub/ass_mp.h | 6 +-- sub/dec_sub.c | 4 +- sub/dec_sub.h | 11 ++--- sub/osd_libass.c | 6 +-- sub/sd.h | 7 +-- sub/sd_ass.c | 12 ++--- sub/sd_lavc.c | 15 +++--- sub/spudec.c | 2 +- sub/spudec.h | 4 +- sub/sub.c | 96 ++++++++++++--------------------------- sub/sub.h | 26 ++++------- 30 files changed, 331 insertions(+), 375 deletions(-) diff --git a/DOCS/man/en/vf.rst b/DOCS/man/en/vf.rst index d46bd5bc06..b5a672e236 100644 --- a/DOCS/man/en/vf.rst +++ b/DOCS/man/en/vf.rst @@ -664,14 +664,14 @@ screenshot ``Taking screenshots`` section for details. ass - Moves SSA/ASS subtitle rendering to an arbitrary point in the filter + Moves subtitle rendering to an arbitrary point in the filter chain, or force subtitle rendering in the video filter as opposed to using - video output EOSD support. See the ``--ass`` option. + video output OSD support. *EXAMPLE*: ``--vf=ass,eq`` - Moves SSA/ASS rendering before the eq filter. This will put both + Moves sub rendering before the eq filter. This will put both subtitle colors and video under the influence of the video equalizer settings. diff --git a/DOCS/man/en/vo.rst b/DOCS/man/en/vo.rst index 6248073944..09d12e2994 100644 --- a/DOCS/man/en/vo.rst +++ b/DOCS/man/en/vo.rst @@ -171,8 +171,8 @@ direct3d_shaders (Windows only) Never render YUV video with more than 8 bits per component. (Using this flag will force software conversion to 8 bit.) - disable-eosd - Disable EOSD rendering for subtitles. + disable-osd + Disable OSD rendering for subtitles. (Using this flag might force the insertion of the 'ass' video filter, which will render the subtitles in software.) diff --git a/libmpcodecs/vf.h b/libmpcodecs/vf.h index 8b18470e62..7db9bd5808 100644 --- a/libmpcodecs/vf.h +++ b/libmpcodecs/vf.h @@ -99,7 +99,6 @@ struct vf_ctrl_screenshot { #define VFCTRL_SET_PP_LEVEL 5 // set postprocessing level #define VFCTRL_SET_EQUALIZER 6 // set color options (brightness,contrast etc) #define VFCTRL_GET_EQUALIZER 8 // get color options (brightness,contrast etc) -#define VFCTRL_DRAW_OSD 7 #define VFCTRL_DUPLICATE_FRAME 11 // For encoding - encode zero-change frame #define VFCTRL_SKIP_NEXT_FRAME 12 // For encoding - drop the next frame that passes thru #define VFCTRL_FLUSH_FRAMES 13 // For encoding - flush delayed frames diff --git a/libmpcodecs/vf_ass.c b/libmpcodecs/vf_ass.c index 9695ecfdfc..1da0b03b44 100644 --- a/libmpcodecs/vf_ass.c +++ b/libmpcodecs/vf_ass.c @@ -49,12 +49,12 @@ static const struct vf_priv_s { unsigned int outfmt; struct mp_csp_details csp; - // 1 = auto-added filter: insert only if chain does not support EOSD already + // 1 = auto-added filter: insert only if chain does not support OSD already // 0 = insert always int auto_insert; struct osd_state *osd; - struct mp_eosd_res dim; + struct mp_osd_res dim; } vf_priv_dflt = { .csp = MP_CSP_DETAILS_DEFAULTS, }; @@ -78,7 +78,7 @@ static int config(struct vf_instance *vf, double dar = (double)d_width / d_height; double sar = (double)width / height; - vf->priv->dim = (struct mp_eosd_res) { + vf->priv->dim = (struct mp_osd_res) { .w = vf->priv->outw, .h = vf->priv->outh, .mt = opts->ass_top_margin, @@ -227,11 +227,7 @@ static int put_image(struct vf_instance *vf, mp_image_t *mpi, double pts) prepare_image(vf, mpi); if (pts != MP_NOPTS_VALUE) { - struct sub_render_params subparams = { - .pts = pts, - .dim = priv->dim, - }; - osd_draw_on_image(osd, &subparams, OSD_DRAW_SUB_FILTER, vf->dmpi, + osd_draw_on_image(osd, priv->dim, pts, OSD_DRAW_SUB_FILTER, vf->dmpi, &priv->csp); } @@ -287,7 +283,7 @@ static int vf_open(vf_instance_t *vf, char *args) if (!vf->priv->outfmt) { uninit(vf); return 0; - } else if (vf->priv->auto_insert && flags & VFCAP_EOSD) { + } else if (vf->priv->auto_insert && flags & VFCAP_OSD) { uninit(vf); return -1; } @@ -301,7 +297,7 @@ static int vf_open(vf_instance_t *vf, char *args) vf->control = control; vf->get_image = get_image; vf->put_image = put_image; - vf->default_caps = VFCAP_EOSD | VFCAP_EOSD_FILTER; + vf->default_caps = VFCAP_OSD; return 1; } diff --git a/libmpcodecs/vf_vo.c b/libmpcodecs/vf_vo.c index 998b4b6dfa..16d10f0cdc 100644 --- a/libmpcodecs/vf_vo.c +++ b/libmpcodecs/vf_vo.c @@ -91,11 +91,6 @@ static int control(struct vf_instance *vf, int request, void *data) return vo_control(video_out, VOCTRL_GET_YUV_COLORSPACE, data) == true; case VFCTRL_SET_YUV_COLORSPACE: return vo_control(video_out, VOCTRL_SET_YUV_COLORSPACE, data) == true; - case VFCTRL_DRAW_OSD: - if (!video_out->config_ok) - return CONTROL_FALSE; // vo not configured? - vo_draw_osd(video_out, data); - return CONTROL_TRUE; case VFCTRL_SET_EQUALIZER: { vf_equalizer_t *eq = data; if (!video_out->config_ok) diff --git a/libmpcodecs/vfcap.h b/libmpcodecs/vfcap.h index 0fb73f5a51..acc7ce31c6 100644 --- a/libmpcodecs/vfcap.h +++ b/libmpcodecs/vfcap.h @@ -40,11 +40,7 @@ #define VFCAP_ACCEPT_STRIDE 0x400 // filter does postprocessing (so you shouldn't scale/filter image before it) #define VFCAP_POSTPROC 0x800 -// filter can draw EOSD -#define VFCAP_EOSD 0x2000 // used by libvo and vf_vo, indicates the VO does not support draw_slice for this format #define VOCAP_NOSLICES 0x8000 -#define VFCAP_EOSD_FILTER 0x20000 // EOSD is drawn in filter chain -#define VFCAP_EOSD_RGBA 0x40000 #endif /* MPLAYER_VFCAP_H */ diff --git a/libvo/gl_osd.c b/libvo/gl_osd.c index 5266dca4ac..81485cabe9 100644 --- a/libvo/gl_osd.c +++ b/libvo/gl_osd.c @@ -68,6 +68,9 @@ struct mpgl_osd *mpgl_osd_init(GL *gl, bool legacy) ctx->parts[n] = p; } + for (int n = 0; n < SUBBITMAP_COUNT; n++) + ctx->formats[n] = ctx->fmt_table[n].type != 0; + return ctx; } @@ -84,11 +87,6 @@ void mpgl_osd_destroy(struct mpgl_osd *ctx) talloc_free(ctx); } -bool mpgl_osd_query_format(struct mpgl_osd *ctx, int osd_format) -{ - return ctx->fmt_table[osd_format].type != 0; -} - static bool upload_pbo(struct mpgl_osd *ctx, struct mpgl_osd_part *osd, struct sub_bitmaps *imgs) { @@ -159,9 +157,9 @@ static bool upload_osd(struct mpgl_osd *ctx, struct mpgl_osd_part *osd, osd->packer->padding = ctx->scaled || imgs->scaled; int r = packer_pack_from_subbitmaps(osd->packer, imgs); if (r < 0) { - mp_msg(MSGT_VO, MSGL_ERR, "[gl] EOSD bitmaps do not fit on " - "a surface with the maximum supported size %dx%d.\n", - osd->packer->w_max, osd->packer->h_max); + mp_msg(MSGT_VO, MSGL_ERR, "[gl] OSD bitmaps do not fit on " + "a surface with the maximum supported size %dx%d.\n", + osd->packer->w_max, osd->packer->h_max); return false; } @@ -207,7 +205,7 @@ static bool upload_osd(struct mpgl_osd *ctx, struct mpgl_osd_part *osd, struct mpgl_osd_part *mpgl_osd_generate(struct mpgl_osd *ctx, struct sub_bitmaps *imgs) { - if (imgs->num_parts == 0 || !mpgl_osd_query_format(ctx, imgs->format)) + if (imgs->num_parts == 0 || !ctx->formats[imgs->format]) return NULL; struct mpgl_osd_part *osd = ctx->parts[imgs->render_index]; @@ -226,7 +224,7 @@ struct mpgl_osd_part *mpgl_osd_generate(struct mpgl_osd *ctx, return osd->packer->count ? osd : NULL; } -void mpgl_osd_gl_set_state(struct mpgl_osd *ctx, struct mpgl_osd_part *p) +void mpgl_osd_set_gl_state(struct mpgl_osd *ctx, struct mpgl_osd_part *p) { GL *gl = ctx->gl; @@ -235,7 +233,7 @@ void mpgl_osd_gl_set_state(struct mpgl_osd *ctx, struct mpgl_osd_part *p) gl->BlendFunc(blend_factors[p->format][0], blend_factors[p->format][1]); } -void mpgl_osd_gl_unset_state(struct mpgl_osd *ctx, struct mpgl_osd_part *p) +void mpgl_osd_unset_gl_state(struct mpgl_osd *ctx, struct mpgl_osd_part *p) { GL *gl = ctx->gl; @@ -249,8 +247,9 @@ struct vertex { float texcoord[2]; }; -void mpgl_osd_draw_legacy(struct mpgl_osd *ctx, struct sub_bitmaps *imgs) +static void draw_legacy_cb(void *pctx, struct sub_bitmaps *imgs) { + struct mpgl_osd *ctx = pctx; struct mpgl_osd_part *osd = mpgl_osd_generate(ctx, imgs); if (!osd) return; @@ -309,11 +308,17 @@ void mpgl_osd_draw_legacy(struct mpgl_osd *ctx, struct sub_bitmaps *imgs) gl->EnableClientState(GL_TEXTURE_COORD_ARRAY); gl->EnableClientState(GL_COLOR_ARRAY); - mpgl_osd_gl_set_state(ctx, osd); + mpgl_osd_set_gl_state(ctx, osd); gl->DrawArrays(GL_TRIANGLES, 0, osd->num_vertices); - mpgl_osd_gl_unset_state(ctx, osd); + mpgl_osd_unset_gl_state(ctx, osd); gl->DisableClientState(GL_VERTEX_ARRAY); gl->DisableClientState(GL_TEXTURE_COORD_ARRAY); gl->DisableClientState(GL_COLOR_ARRAY); } + +void mpgl_osd_draw_legacy(struct mpgl_osd *ctx, struct osd_state *osd, + struct mp_osd_res res) +{ + osd_draw(osd, res, osd->vo_pts, 0, ctx->formats, draw_legacy_cb, ctx); +} diff --git a/libvo/gl_osd.h b/libvo/gl_osd.h index 9bbf6ad785..cf3182ffb2 100644 --- a/libvo/gl_osd.h +++ b/libvo/gl_osd.h @@ -24,19 +24,20 @@ struct mpgl_osd { bool scaled; struct mpgl_osd_part *parts[MAX_OSD_PARTS]; const struct osd_fmt_entry *fmt_table; + bool formats[SUBBITMAP_COUNT]; void *scratch; }; struct mpgl_osd *mpgl_osd_init(GL *gl, bool legacy); void mpgl_osd_destroy(struct mpgl_osd *ctx); -bool mpgl_osd_query_format(struct mpgl_osd *ctx, int osd_format); - -void mpgl_osd_draw_legacy(struct mpgl_osd *ctx, struct sub_bitmaps *b); struct mpgl_osd_part *mpgl_osd_generate(struct mpgl_osd *ctx, struct sub_bitmaps *b); -void mpgl_osd_gl_set_state(struct mpgl_osd *ctx, struct mpgl_osd_part *p); -void mpgl_osd_gl_unset_state(struct mpgl_osd *ctx, struct mpgl_osd_part *p); +void mpgl_osd_set_gl_state(struct mpgl_osd *ctx, struct mpgl_osd_part *p); +void mpgl_osd_unset_gl_state(struct mpgl_osd *ctx, struct mpgl_osd_part *p); + +void mpgl_osd_draw_legacy(struct mpgl_osd *ctx, struct osd_state *osd, + struct mp_osd_res res); #endif diff --git a/libvo/video_out.h b/libvo/video_out.h index 2689c244a8..ffb5c0c4f3 100644 --- a/libvo/video_out.h +++ b/libvo/video_out.h @@ -64,9 +64,6 @@ enum mp_voctrl { VOCTRL_ONTOP, VOCTRL_ROOTWIN, 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_corevideo.m b/libvo/vo_corevideo.m index c3d832d589..0e841f7530 100644 --- a/libvo/vo_corevideo.m +++ b/libvo/vo_corevideo.m @@ -19,6 +19,8 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#include + #import "vo_corevideo.h" // mplayer includes @@ -50,6 +52,7 @@ struct priv { unsigned int image_width; unsigned int image_height; struct mp_csp_details colorspace; + int ass_border_x, ass_border_y; CVPixelBufferRef pixelBuffer; CVOpenGLTextureCacheRef textureCache; @@ -84,6 +87,8 @@ static void resize(struct vo *vo, int width, int height) scale_x = (GLdouble)new_w / (GLdouble)p->image_width; scale_y = (GLdouble)new_h / (GLdouble)p->image_height; gl->Scaled(scale_x, scale_y, 1); + p->ass_border_x = (vo->dwidth - new_w) / 2; + p->ass_border_y = (vo->dheight - new_h) / 2; } gl->Ortho(0, p->image_width, p->image_height, 0, -1.0, 1.0); @@ -249,7 +254,7 @@ static int query_format(struct vo *vo, uint32_t format) struct priv *p = vo->priv; const int flags = VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW | VFCAP_OSD | VFCAP_HWSCALE_UP | VFCAP_HWSCALE_DOWN | - VOCAP_NOSLICES | VFCAP_EOSD; + VOCAP_NOSLICES; switch (format) { case IMGFMT_YUY2: p->pixelFormat = kYUVSPixelFormat; @@ -293,6 +298,26 @@ static int preinit(struct vo *vo, const char *arg) return 0; } +static void draw_osd(struct vo *vo, struct osd_state *osd) +{ + struct priv *p = vo->priv; + GL *gl = p->mpglctx->gl; + assert(p->osd); + + struct mp_osd_res res = { + .w = vo->dwidth, + .h = vo->dheight, + .ml = p->ass_border_x, + .mr = p->ass_border_x, + .mt = p->ass_border_y, + .mb = p->ass_border_y, + .display_par = vo->monitor_par, + .video_par = vo->aspdat.par, + }; + + mpgl_osd_draw_legacy(p->osd, osd, res); +} + static CFStringRef get_cv_csp_matrix(struct vo *vo) { struct priv *p = vo->priv; @@ -324,19 +349,6 @@ static int control(struct vo *vo, uint32_t request, void *data) return draw_image(vo, data); case VOCTRL_QUERY_FORMAT: return query_format(vo, *(uint32_t*)data); - case VOCTRL_DRAW_EOSD: - mpgl_osd_draw_legacy(p->osd, data); - return VO_TRUE; - case VOCTRL_QUERY_EOSD_FORMAT: - return mpgl_osd_query_format(p->osd, *(int *)data) - ? VO_TRUE : VO_NOTIMPL; - case VOCTRL_GET_EOSD_RES: { - struct mp_eosd_res *r = data; - r->w = vo->dwidth; - r->h = vo->dheight; - r->mt = r->mb = r->ml = r->mr = 0; - return VO_TRUE; - } case VOCTRL_ONTOP: p->mpglctx->ontop(vo); return VO_TRUE; @@ -377,7 +389,7 @@ const struct vo_driver video_out_corevideo = { .preinit = preinit, .config = config, .control = control, - .draw_osd = draw_osd_with_eosd, + .draw_osd = draw_osd, .flip_page = flip_page, .check_events = check_events, .uninit = uninit, diff --git a/libvo/vo_direct3d.c b/libvo/vo_direct3d.c index 2b8f3429e4..bbcce41ca1 100644 --- a/libvo/vo_direct3d.c +++ b/libvo/vo_direct3d.c @@ -59,13 +59,13 @@ #define DEVTYPE D3DDEVTYPE_HAL //#define DEVTYPE D3DDEVTYPE_REF -#define D3DFVF_EOSD_VERTEX (D3DFVF_XYZ | D3DFVF_TEX1 | D3DFVF_DIFFUSE) +#define D3DFVF_OSD_VERTEX (D3DFVF_XYZ | D3DFVF_TEX1 | D3DFVF_DIFFUSE) typedef struct { float x, y, z; D3DCOLOR color; float tu, tv; -} vertex_eosd; +} vertex_osd; #define D3DFVF_VIDEO_VERTEX (D3DFVF_XYZ | D3DFVF_TEX3) @@ -113,7 +113,7 @@ struct osdpart { int bitmap_id, bitmap_pos_id; struct d3dtex texture; int num_vertices; - vertex_eosd *vertices; + vertex_osd *vertices; struct bitmap_packer *packer; }; @@ -125,7 +125,7 @@ typedef struct d3d_priv { int opt_disable_stretchrect; int opt_disable_shaders; int opt_only_8bit; - int opt_disable_eosd; + int opt_disable_osd; int opt_disable_texture_align; // debugging int opt_force_power_of_2; @@ -232,6 +232,10 @@ static const D3DFORMAT osd_fmt_table[SUBBITMAP_COUNT] = { [SUBBITMAP_LIBASS] = D3DFMT_A8, [SUBBITMAP_RGBA] = D3DFMT_A8R8G8B8, }; +static const bool osd_fmt_supported[SUBBITMAP_COUNT] = { + [SUBBITMAP_LIBASS] = true, + [SUBBITMAP_RGBA] = true, +}; static void update_colorspace(d3d_priv *priv); @@ -241,7 +245,6 @@ static uint32_t d3d_draw_frame(d3d_priv *priv); static int draw_slice(struct vo *vo, uint8_t *src[], int stride[], int w, int h, int x, int y); static void uninit(struct vo *vo); -static void draw_osd(d3d_priv *priv, struct sub_bitmaps *imgs); static void flip_page(struct vo *vo); static mp_image_t *get_screenshot(d3d_priv *priv); static mp_image_t *get_window_screenshot(d3d_priv *priv); @@ -1224,11 +1227,11 @@ static int query_format(d3d_priv *priv, uint32_t movie_fmt) if (!init_rendering_mode(priv, movie_fmt, false)) return 0; - int eosd_caps = VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW - | VFCAP_OSD | VFCAP_HWSCALE_UP | VFCAP_HWSCALE_DOWN; - if (!priv->opt_disable_eosd) - eosd_caps |= VFCAP_EOSD | VFCAP_EOSD_RGBA; - return eosd_caps; + int osd_caps = VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW + | VFCAP_HWSCALE_UP | VFCAP_HWSCALE_DOWN; + if (!priv->opt_disable_osd) + osd_caps |= VFCAP_OSD; + return osd_caps; } /**************************************************************************** @@ -1296,7 +1299,7 @@ static void update_colorspace(d3d_priv *priv) } const char *options_help_text = "-vo direct3d command line help:\n" -"Example: -vo direct3d:disable-eosd:disable-textures\n" +"Example: -vo direct3d:disable-osd:disable-textures\n" "Options:\n" " prefer-stretchrect\n" " Use IDirect3DDevice9::StretchRect over other methods if possible.\n" @@ -1311,8 +1314,8 @@ const char *options_help_text = "-vo direct3d command line help:\n" " only-8bit\n" " Never render YUV video with more than 8 bits per component.\n" " (Using this flag will force software conversion to 8 bit.)\n" -" disable-eosd\n" -" Disable EOSD rendering for subtitles.\n" +" disable-osd\n" +" Disable OSD rendering.\n" " (Using this flag might force the insertion of the 'ass' video filter,\n" " which will render the subtitles in software.)\n" " disable-texture-align\n" @@ -1386,7 +1389,7 @@ static int preinit_internal(struct vo *vo, const char *arg, bool allow_shaders) {"disable-stretchrect", OPT_ARG_BOOL, &priv->opt_disable_stretchrect}, {"disable-shaders", OPT_ARG_BOOL, &priv->opt_disable_shaders}, {"only-8bit", OPT_ARG_BOOL, &priv->opt_only_8bit}, - {"disable-eosd", OPT_ARG_BOOL, &priv->opt_disable_eosd}, + {"disable-osd", OPT_ARG_BOOL, &priv->opt_disable_osd}, {"force-power-of-2", OPT_ARG_BOOL, &priv->opt_force_power_of_2}, {"disable-texture-align", OPT_ARG_BOOL, &priv->opt_disable_texture_align}, {"texture-memory", OPT_ARG_INT, &priv->opt_texture_memory}, @@ -1507,21 +1510,6 @@ static int control(struct vo *vo, uint32_t request, void *data) return VO_TRUE; case VOCTRL_GET_PANSCAN: return VO_TRUE; - case VOCTRL_DRAW_EOSD: - if (!data) - return VO_FALSE; - draw_osd(priv, data); - return VO_TRUE; - case VOCTRL_QUERY_EOSD_FORMAT: - return osd_fmt_table[*(int *)data] ? VO_TRUE : VO_NOTIMPL; - case VOCTRL_GET_EOSD_RES: { - struct mp_eosd_res *r = data; - r->w = vo->dwidth; - r->h = vo->dheight; - r->ml = r->mr = priv->border_x; - r->mt = r->mb = priv->border_y; - return VO_TRUE; - } case VOCTRL_SCREENSHOT: { struct voctrl_screenshot_args *args = data; if (args->full_window) @@ -1905,7 +1893,7 @@ static bool upload_osd(d3d_priv *priv, struct osdpart *osd, osd->packer->padding = imgs->scaled; // assume 2x2 filter on scaling int r = packer_pack_from_subbitmaps(osd->packer, imgs); if (r < 0) { - mp_msg(MSGT_VO, MSGL_ERR, "EOSD bitmaps do not fit on " + mp_msg(MSGT_VO, MSGL_ERR, "OSD bitmaps do not fit on " "a surface with the maximum supported size %dx%d.\n", osd->packer->w_max, osd->packer->h_max); return false; @@ -1939,7 +1927,7 @@ static bool upload_osd(d3d_priv *priv, struct osdpart *osd, if (FAILED(IDirect3DTexture9_LockRect(osd->texture.system, 0, &locked_rect, &dirty_rc, 0))) { - mp_msg(MSGT_VO,MSGL_ERR, "EOSD texture lock failed.\n"); + mp_msg(MSGT_VO,MSGL_ERR, "OSD texture lock failed.\n"); return false; } @@ -1948,7 +1936,7 @@ static bool upload_osd(d3d_priv *priv, struct osdpart *osd, locked_rect.Pitch); if (FAILED(IDirect3DTexture9_UnlockRect(osd->texture.system, 0))) { - mp_msg(MSGT_VO,MSGL_ERR, "EOSD texture unlock failed.\n"); + mp_msg(MSGT_VO,MSGL_ERR, "OSD texture unlock failed.\n"); return false; } @@ -1985,10 +1973,9 @@ static D3DCOLOR ass_to_d3d_color(uint32_t color) return D3DCOLOR_ARGB(a, r, g, b); } -static void draw_osd(d3d_priv *priv, struct sub_bitmaps *imgs) +static void draw_osd_cb(void *ctx, struct sub_bitmaps *imgs) { - if (!priv->d3d_device) - return; + d3d_priv *priv = ctx; struct osdpart *osd = generate_osd(priv, imgs); if (!osd) @@ -1999,7 +1986,7 @@ static void draw_osd(d3d_priv *priv, struct sub_bitmaps *imgs) // the number of vertices by using an indexed vertex array, but it's // probably not worth doing) osd->num_vertices = osd->packer->count * 6; - osd->vertices = talloc_realloc(osd, osd->vertices, vertex_eosd, + osd->vertices = talloc_realloc(osd, osd->vertices, vertex_osd, osd->num_vertices); float tex_w = osd->texture.tex_w; @@ -2022,11 +2009,11 @@ static void draw_osd(d3d_priv *priv, struct sub_bitmaps *imgs) float tx1 = (p.x + b->w) / tex_w; float ty1 = (p.y + b->h) / tex_h; - vertex_eosd *v = &osd->vertices[n * 6]; - v[0] = (vertex_eosd) { x0, y0, 0, color, tx0, ty0 }; - v[1] = (vertex_eosd) { x1, y0, 0, color, tx1, ty0 }; - v[2] = (vertex_eosd) { x0, y1, 0, color, tx0, ty1 }; - v[3] = (vertex_eosd) { x1, y1, 0, color, tx1, ty1 }; + vertex_osd *v = &osd->vertices[n * 6]; + v[0] = (vertex_osd) { x0, y0, 0, color, tx0, ty0 }; + v[1] = (vertex_osd) { x1, y0, 0, color, tx1, ty0 }; + v[2] = (vertex_osd) { x0, y1, 0, color, tx0, ty1 }; + v[3] = (vertex_osd) { x1, y1, 0, color, tx1, ty1 }; v[4] = v[2]; v[5] = v[1]; } @@ -2054,10 +2041,10 @@ static void draw_osd(d3d_priv *priv, struct sub_bitmaps *imgs) D3DBLEND_ONE); } - IDirect3DDevice9_SetFVF(priv->d3d_device, D3DFVF_EOSD_VERTEX); + IDirect3DDevice9_SetFVF(priv->d3d_device, D3DFVF_OSD_VERTEX); IDirect3DDevice9_DrawPrimitiveUP(priv->d3d_device, D3DPT_TRIANGLELIST, osd->num_vertices / 3, - osd->vertices, sizeof(vertex_eosd)); + osd->vertices, sizeof(vertex_osd)); IDirect3DDevice9_SetTextureStageState(priv->d3d_device,0, D3DTSS_COLORARG1, D3DTA_TEXTURE); @@ -2072,6 +2059,27 @@ static void draw_osd(d3d_priv *priv, struct sub_bitmaps *imgs) D3DRS_ALPHABLENDENABLE, FALSE); } + +static void draw_osd(struct vo *vo, struct osd_state *osd) +{ + d3d_priv *priv = vo->priv; + if (!priv->d3d_device) + return; + + struct mp_osd_res res = { + .w = vo->dwidth, + .h = vo->dheight, + .ml = priv->border_x, + .mr = priv->border_x, + .mt = priv->border_y, + .mb = priv->border_y, + .display_par = vo->monitor_par, + .video_par = vo->aspdat.par, + }; + + osd_draw(osd, res, osd->vo_pts, 0, osd_fmt_supported, draw_osd_cb, priv); +} + #define AUTHOR "Georgi Petrov (gogothebee) and others" const struct vo_driver video_out_direct3d = { @@ -2086,7 +2094,7 @@ const struct vo_driver video_out_direct3d = { .config = config, .control = control, .draw_slice = draw_slice, - .draw_osd = draw_osd_with_eosd, + .draw_osd = draw_osd, .flip_page = flip_page, .check_events = check_events, .uninit = uninit, @@ -2104,7 +2112,7 @@ const struct vo_driver video_out_direct3d_shaders = { .config = config, .control = control, .draw_slice = draw_slice, - .draw_osd = draw_osd_with_eosd, + .draw_osd = draw_osd, .flip_page = flip_page, .check_events = check_events, .uninit = uninit, diff --git a/libvo/vo_lavc.c b/libvo/vo_lavc.c index caa3b4202c..5c90207256 100644 --- a/libvo/vo_lavc.c +++ b/libvo/vo_lavc.c @@ -198,8 +198,8 @@ static int query_format(struct vo *vo, uint32_t format) VFCAP_CSP_SUPPORTED | // we can do it VFCAP_CSP_SUPPORTED_BY_HW | - // we don't convert colorspaces here (TODO: if we add EOSD rendering, only set this flag if EOSD can be rendered without extra conversions) - VFCAP_OSD | VFCAP_EOSD | + // we don't convert colorspaces here + VFCAP_OSD | // we have OSD VOCAP_NOSLICES; // we don't use slices @@ -494,17 +494,15 @@ static void draw_osd(struct vo *vo, struct osd_state *osd) double sar = (double)asp.orgw / asp.orgh; double dar = (double)asp.prew / asp.preh; - struct sub_render_params subparams = { - .pts = osd->vo_sub_pts, - .dim = { - .w = asp.orgw, - .h = asp.orgh, - .display_par = sar / dar, - .video_par = dar / sar, - }, + struct mp_osd_res dim = { + .w = asp.orgw, + .h = asp.orgh, + .display_par = sar / dar, + .video_par = dar / sar, }; - osd_draw_on_image(osd, &subparams, 0, vc->lastimg, &vc->colorspace); + osd_draw_on_image(osd, dim, osd->vo_pts, 0, vc->lastimg, + &vc->colorspace); } } diff --git a/libvo/vo_opengl.c b/libvo/vo_opengl.c index 413ca78710..df82a239d1 100644 --- a/libvo/vo_opengl.c +++ b/libvo/vo_opengl.c @@ -1420,12 +1420,11 @@ static mp_image_t *get_window_screenshot(struct gl_priv *p) return image; } -static void draw_eosd(struct gl_priv *p, struct sub_bitmaps *imgs) +static void draw_osd_cb(void *ctx, struct sub_bitmaps *imgs) { + struct gl_priv *p = ctx; GL *gl = p->gl; - assert(p->osd); - struct mpgl_osd_part *osd = mpgl_osd_generate(p->osd, imgs); if (!osd) return; @@ -1459,14 +1458,33 @@ static void draw_eosd(struct gl_priv *p, struct sub_bitmaps *imgs) debug_check_gl(p, "before drawing osd"); gl->UseProgram(p->osd_programs[osd->format]); - mpgl_osd_gl_set_state(p->osd, osd); + mpgl_osd_set_gl_state(p->osd, osd); draw_triangles(p, osd->vertices, osd->num_vertices); - mpgl_osd_gl_unset_state(p->osd, osd); + mpgl_osd_unset_gl_state(p->osd, osd); gl->UseProgram(0); debug_check_gl(p, "after drawing osd"); } +static void draw_osd(struct vo *vo, struct osd_state *osd) +{ + struct gl_priv *p = vo->priv; + assert(p->osd); + + struct mp_osd_res res = { + .w = vo->dwidth, + .h = vo->dheight, + .ml = p->border_x, + .mr = p->border_x, + .mt = p->border_y, + .mb = p->border_y, + .display_par = vo->monitor_par, + .video_par = vo->aspdat.par, + }; + + osd_draw(osd, res, osd->vo_pts, 0, p->osd->formats, draw_osd_cb, p); +} + // Disable features that are not supported with the current OpenGL version. static void check_gl_features(struct gl_priv *p) { @@ -1691,7 +1709,7 @@ static int query_format(uint32_t format) { int caps = VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW | VFCAP_FLIP | VFCAP_HWSCALE_UP | VFCAP_HWSCALE_DOWN | VFCAP_ACCEPT_STRIDE | - VFCAP_OSD | VFCAP_EOSD | VFCAP_EOSD_RGBA; + VFCAP_OSD; if (!init_format(format, NULL)) return 0; return caps; @@ -1767,24 +1785,6 @@ static int control(struct vo *vo, uint32_t request, void *data) return query_format(*(uint32_t *)data); case VOCTRL_DRAW_IMAGE: return draw_image(p, data); - case VOCTRL_DRAW_EOSD: - if (!data) - return VO_FALSE; - draw_eosd(p, data); - return VO_TRUE; - case VOCTRL_GET_EOSD_RES: { - struct mp_eosd_res *r = data; - r->w = vo->dwidth; - r->h = vo->dheight; - r->ml = r->mr = p->border_x; - r->mt = r->mb = p->border_y; - return VO_TRUE; - } - case VOCTRL_QUERY_EOSD_FORMAT: { - int f = *(int *)data; - return (mpgl_osd_query_format(p->osd, f) && osd_shaders[f]) - ? VO_TRUE : VO_NOTIMPL; - } case VOCTRL_ONTOP: if (!p->glctx->ontop) break; @@ -2304,7 +2304,7 @@ const struct vo_driver video_out_opengl = { .config = config, .control = control, .draw_slice = draw_slice, - .draw_osd = draw_osd_with_eosd, + .draw_osd = draw_osd, .flip_page = flip_page, .check_events = check_events, .uninit = uninit, @@ -2322,7 +2322,7 @@ const struct vo_driver video_out_opengl_hq = { .config = config, .control = control, .draw_slice = draw_slice, - .draw_osd = draw_osd_with_eosd, + .draw_osd = draw_osd, .flip_page = flip_page, .check_events = check_events, .uninit = uninit, diff --git a/libvo/vo_opengl_old.c b/libvo/vo_opengl_old.c index 98a111b454..ac104a3cde 100644 --- a/libvo/vo_opengl_old.c +++ b/libvo/vo_opengl_old.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "config.h" #include "talloc.h" @@ -229,11 +230,14 @@ static void update_yuvconv(struct vo *vo) } } -// Note: relies on state being setup, like projection matrix and blending -static void render_osd(struct vo *vo, struct sub_bitmaps *imgs) +static void draw_osd(struct vo *vo, struct osd_state *osd) { struct gl_priv *p = vo->priv; GL *gl = p->gl; + assert(p->osd); + + if (!p->use_osd) + return; if (!p->scaled_osd) { gl->MatrixMode(GL_PROJECTION); @@ -241,9 +245,26 @@ static void render_osd(struct vo *vo, struct sub_bitmaps *imgs) gl->LoadIdentity(); gl->Ortho(0, vo->dwidth, vo->dheight, 0, -1, 1); } + gl->Color4ub((p->osd_color >> 16) & 0xff, (p->osd_color >> 8) & 0xff, p->osd_color & 0xff, 0xff - (p->osd_color >> 24)); - mpgl_osd_draw_legacy(p->osd, imgs); + + struct mp_osd_res res = { + .w = vo->dwidth, + .h = vo->dheight, + .display_par = vo->monitor_par, + .video_par = vo->aspdat.par, + }; + if (p->scaled_osd) { + res.w = p->image_width; + res.h = p->image_height; + } else if (aspect_scaling()) { + res.ml = res.mr = p->ass_border_x; + res.mt = res.mb = p->ass_border_y; + } + + mpgl_osd_draw_legacy(p->osd, osd, res); + if (!p->scaled_osd) gl->PopMatrix(); } @@ -843,7 +864,7 @@ static int query_format(struct vo *vo, uint32_t format) int caps = VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW | VFCAP_FLIP | VFCAP_HWSCALE_UP | VFCAP_HWSCALE_DOWN | VFCAP_ACCEPT_STRIDE; if (p->use_osd) - caps |= VFCAP_OSD | VFCAP_EOSD; + caps |= VFCAP_OSD; if (format == IMGFMT_RGB24 || format == IMGFMT_RGBA) return caps; if (p->use_yuv && mp_get_chroma_shift(format, NULL, NULL, &depth) && @@ -1077,25 +1098,6 @@ static int control(struct vo *vo, uint32_t request, void *data) return query_format(vo, *(uint32_t *)data); case VOCTRL_DRAW_IMAGE: return draw_image(vo, data); - case VOCTRL_DRAW_EOSD: - render_osd(vo, data); - return VO_TRUE; - case VOCTRL_QUERY_EOSD_FORMAT: - return mpgl_osd_query_format(p->osd, *(int *)data) ? VO_TRUE : VO_NOTIMPL; - case VOCTRL_GET_EOSD_RES: { - struct mp_eosd_res *r = data; - r->w = vo->dwidth; - r->h = vo->dheight; - r->mt = r->mb = r->ml = r->mr = 0; - if (p->scaled_osd) { - r->w = p->image_width; - r->h = p->image_height; - } else if (aspect_scaling()) { - r->ml = r->mr = p->ass_border_x; - r->mt = r->mb = p->ass_border_y; - } - return VO_TRUE; - } case VOCTRL_ONTOP: if (!p->glctx->ontop) break; @@ -1177,7 +1179,7 @@ const struct vo_driver video_out_opengl_old = { .config = config, .control = control, .draw_slice = draw_slice, - .draw_osd = draw_osd_with_eosd, + .draw_osd = draw_osd, .flip_page = flip_page, .check_events = check_events, .uninit = uninit, diff --git a/libvo/vo_vdpau.c b/libvo/vo_vdpau.c index 94d37e3018..1d4bf8adf7 100644 --- a/libvo/vo_vdpau.c +++ b/libvo/vo_vdpau.c @@ -157,15 +157,15 @@ struct vdpctx { VdpChromaType vdp_chroma_type; VdpYCbCrFormat vdp_pixel_format; - // EOSD - struct eosd_bitmap_surface { + // OSD + struct osd_bitmap_surface { VdpRGBAFormat format; VdpBitmapSurface surface; uint32_t max_width; uint32_t max_height; struct bitmap_packer *packer; // List of surfaces to be rendered - struct eosd_target { + struct osd_target { VdpRect source; VdpRect dest; VdpColor color; @@ -174,7 +174,7 @@ struct vdpctx { int render_count; int bitmap_id; int bitmap_pos_id; - } eosd_surfaces[MAX_OSD_PARTS]; + } osd_surfaces[MAX_OSD_PARTS]; // Video equalizer struct mp_csp_equalizer video_eq; @@ -183,6 +183,8 @@ struct vdpctx { bool mode_switched; }; +static bool status_ok(struct vo *vo); + static int change_vdptime_sync(struct vdpctx *vc, unsigned int *t) { struct vdp_functions *vdp = vc->vdp; @@ -800,10 +802,10 @@ static void mark_vdpau_objects_uninitialized(struct vo *vo) vc->output_surfaces[i] = VDP_INVALID_HANDLE; vc->vdp_device = VDP_INVALID_HANDLE; for (int i = 0; i < MAX_OSD_PARTS; i++) { - struct eosd_bitmap_surface *sfc = &vc->eosd_surfaces[i]; + struct osd_bitmap_surface *sfc = &vc->osd_surfaces[i]; talloc_free(sfc->packer); sfc->bitmap_id = sfc->bitmap_pos_id = 0; - *sfc = (struct eosd_bitmap_surface){ + *sfc = (struct osd_bitmap_surface){ .surface = VDP_INVALID_HANDLE, }; } @@ -941,18 +943,18 @@ static struct bitmap_packer *make_packer(struct vo *vo, VdpRGBAFormat format) VdpStatus vdp_st = vdp-> bitmap_surface_query_capabilities(vc->vdp_device, format, &(VdpBool){0}, &w_max, &h_max); - CHECK_ST_WARNING("Query to get max EOSD surface size failed"); + CHECK_ST_WARNING("Query to get max OSD surface size failed"); packer->w_max = w_max; packer->h_max = h_max; return packer; } -static void draw_eosd(struct vo *vo, int index) +static void draw_osd_part(struct vo *vo, int index) { struct vdpctx *vc = vo->priv; struct vdp_functions *vdp = vc->vdp; VdpStatus vdp_st; - struct eosd_bitmap_surface *sfc = &vc->eosd_surfaces[index]; + struct osd_bitmap_surface *sfc = &vc->osd_surfaces[index]; VdpOutputSurface output_surface = vc->output_surfaces[vc->surface_num]; int i; @@ -986,16 +988,16 @@ static void draw_eosd(struct vo *vo, int index) &sfc->targets[i].color, blend, VDP_OUTPUT_SURFACE_RENDER_ROTATE_0); - CHECK_ST_WARNING("EOSD: Error when rendering"); + CHECK_ST_WARNING("OSD: Error when rendering"); } } -static void generate_eosd(struct vo *vo, struct sub_bitmaps *imgs) +static void generate_osd_part(struct vo *vo, struct sub_bitmaps *imgs) { struct vdpctx *vc = vo->priv; struct vdp_functions *vdp = vc->vdp; VdpStatus vdp_st; - struct eosd_bitmap_surface *sfc = &vc->eosd_surfaces[imgs->render_index]; + struct osd_bitmap_surface *sfc = &vc->osd_surfaces[imgs->render_index]; bool need_upload = false; if (imgs->bitmap_pos_id == sfc->bitmap_pos_id) @@ -1007,7 +1009,7 @@ static void generate_eosd(struct vo *vo, struct sub_bitmaps *imgs) return; if (imgs->bitmap_id == sfc->bitmap_id) - goto eosd_skip_upload; + goto osd_skip_upload; need_upload = true; VdpRGBAFormat format; @@ -1034,7 +1036,7 @@ static void generate_eosd(struct vo *vo, struct sub_bitmaps *imgs) sfc->packer->padding = imgs->scaled; // assume 2x2 filter on scaling int r = packer_pack_from_subbitmaps(sfc->packer, imgs); if (r < 0) { - mp_msg(MSGT_VO, MSGL_ERR, "[vdpau] EOSD bitmaps do not fit on " + mp_msg(MSGT_VO, MSGL_ERR, "[vdpau] OSD bitmaps do not fit on " "a surface with the maximum supported size\n"); return; } else if (r == 1) { @@ -1043,13 +1045,13 @@ static void generate_eosd(struct vo *vo, struct sub_bitmaps *imgs) CHECK_ST_WARNING("Error when calling vdp_bitmap_surface_destroy"); } mp_msg(MSGT_VO, MSGL_V, "[vdpau] Allocating a %dx%d surface for " - "EOSD bitmaps.\n", sfc->packer->w, sfc->packer->h); + "OSD bitmaps.\n", sfc->packer->w, sfc->packer->h); vdp_st = vdp->bitmap_surface_create(vc->vdp_device, format, sfc->packer->w, sfc->packer->h, true, &sfc->surface); if (vdp_st != VDP_STATUS_OK) sfc->surface = VDP_INVALID_HANDLE; - CHECK_ST_WARNING("EOSD: error when creating surface"); + CHECK_ST_WARNING("OSD: error when creating surface"); } if (imgs->scaled) { char zeros[sfc->packer->used_width * format_size]; @@ -1060,7 +1062,7 @@ static void generate_eosd(struct vo *vo, struct sub_bitmaps *imgs) sfc->packer->used_height}); } -eosd_skip_upload: +osd_skip_upload: if (sfc->surface == VDP_INVALID_HANDLE) return; if (sfc->packer->count > sfc->targets_size) { @@ -1072,7 +1074,7 @@ eosd_skip_upload: for (int i = 0 ;i < sfc->packer->count; i++) { struct sub_bitmap *b = &imgs->parts[i]; - struct eosd_target *target = sfc->targets + sfc->render_count; + struct osd_target *target = sfc->targets + sfc->render_count; int x = sfc->packer->result[i].x; int y = sfc->packer->result[i].y; target->source = (VdpRect){x, y, x + b->w, y + b->h}; @@ -1091,7 +1093,7 @@ eosd_skip_upload: &(const void *){b->bitmap}, &(uint32_t){b->stride}, &target->source); - CHECK_ST_WARNING("EOSD: putbits failed"); + CHECK_ST_WARNING("OSD: putbits failed"); } sfc->render_count++; } @@ -1100,6 +1102,39 @@ eosd_skip_upload: sfc->bitmap_pos_id = imgs->bitmap_pos_id; } +static void draw_osd_cb(void *ctx, struct sub_bitmaps *imgs) +{ + struct vo *vo = ctx; + generate_osd_part(vo, imgs); + draw_osd_part(vo, imgs->render_index); +} + +static void draw_osd(struct vo *vo, struct osd_state *osd) +{ + struct vdpctx *vc = vo->priv; + + if (!status_ok(vo)) + return; + + static const bool formats[SUBBITMAP_COUNT] = { + [SUBBITMAP_LIBASS] = true, + [SUBBITMAP_RGBA] = true, + }; + + struct mp_osd_res res = { + .w = vo->dwidth, + .h = vo->dheight, + .ml = vc->border_x, + .mr = vc->border_x, + .mt = vc->border_y, + .mb = vc->border_y, + .display_par = vo->monitor_par, + .video_par = vo->aspdat.par, + }; + + osd_draw(osd, res, osd->vo_pts, 0, formats, draw_osd_cb, vo); +} + static int update_presentation_queue_status(struct vo *vo) { struct vdpctx *vc = vo->priv; @@ -1401,8 +1436,8 @@ static uint32_t get_image(struct vo *vo, mp_image_t *mpi) static int query_format(uint32_t format) { int default_flags = VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW - | VFCAP_HWSCALE_UP | VFCAP_HWSCALE_DOWN | VFCAP_OSD | VFCAP_EOSD - | VFCAP_EOSD_RGBA | VFCAP_FLIP; + | VFCAP_HWSCALE_UP | VFCAP_HWSCALE_DOWN | VFCAP_OSD + | VFCAP_FLIP; switch (format) { case IMGFMT_YV12: case IMGFMT_I420: @@ -1451,7 +1486,7 @@ static void destroy_vdpau_objects(struct vo *vo) } for (int i = 0; i < MAX_OSD_PARTS; i++) { - struct eosd_bitmap_surface *sfc = &vc->eosd_surfaces[i]; + struct osd_bitmap_surface *sfc = &vc->osd_surfaces[i]; if (sfc->surface != VDP_INVALID_HANDLE) { vdp_st = vdp->bitmap_surface_destroy(sfc->surface); CHECK_ST_WARNING("Error when calling vdp_bitmap_surface_destroy"); @@ -1619,28 +1654,6 @@ static int control(struct vo *vo, uint32_t request, void *data) case VOCTRL_UPDATE_SCREENINFO: update_xinerama_info(vo); return VO_TRUE; - case VOCTRL_DRAW_EOSD: - if (!data) - return VO_FALSE; - if (status_ok(vo)) { - struct sub_bitmaps *imgs = data; - generate_eosd(vo, imgs); - draw_eosd(vo, imgs->render_index); - } - return VO_TRUE; - case VOCTRL_GET_EOSD_RES: { - struct mp_eosd_res *r = data; - r->w = vo->dwidth; - r->h = vo->dheight; - r->ml = r->mr = vc->border_x; - r->mt = r->mb = vc->border_y; - return VO_TRUE; - } - case VOCTRL_QUERY_EOSD_FORMAT: { - int format = *(int *)data; - return (format == SUBBITMAP_LIBASS || format == SUBBITMAP_RGBA) - ? VO_TRUE : VO_NOTIMPL; - } case VOCTRL_NEWFRAME: vc->deint_queue_pos = next_deint_queue_pos(vo, true); if (status_ok(vo)) @@ -1688,7 +1701,7 @@ const struct vo_driver video_out_vdpau = { .draw_image = draw_image, .get_buffered_frame = set_next_frame_info, .draw_slice = draw_slice, - .draw_osd = draw_osd_with_eosd, + .draw_osd = draw_osd, .flip_page_timed = flip_page_timed, .check_events = check_events, .uninit = uninit, diff --git a/libvo/vo_x11.c b/libvo/vo_x11.c index 61066a2ec6..587730a89a 100644 --- a/libvo/vo_x11.c +++ b/libvo/vo_x11.c @@ -42,7 +42,6 @@ #endif #include "sub/sub.h" -#include "sub/dec_sub.h" #include "libmpcodecs/sws_utils.h" #define MODE_RGB 0x1 @@ -443,17 +442,14 @@ static void draw_osd(struct vo *vo, struct osd_state *osd) struct mp_csp_details csp = MP_CSP_DETAILS_DEFAULTS; - struct sub_render_params subparams = { - .pts = osd->vo_sub_pts, - .dim = { - .w = img.w, - .h = img.h, - .display_par = vo->monitor_par, - .video_par = vo->aspdat.par, - }, + struct mp_osd_res res = { + .w = img.w, + .h = img.h, + .display_par = vo->monitor_par, + .video_par = vo->aspdat.par, }; - osd_draw_on_image(osd, &subparams, 0, &img, &csp); + osd_draw_on_image(osd, res, osd->vo_pts, 0, &img, &csp); } static void flip_page(struct vo *vo) diff --git a/libvo/vo_xv.c b/libvo/vo_xv.c index 9aca1005ec..92ac9a2461 100644 --- a/libvo/vo_xv.c +++ b/libvo/vo_xv.c @@ -50,7 +50,6 @@ #include "x11_common.h" #include "fastmemcpy.h" #include "sub/sub.h" -#include "sub/dec_sub.h" #include "aspect.h" #include "csputils.h" #include "subopt-helper.h" @@ -348,17 +347,14 @@ static void draw_osd(struct vo *vo, struct osd_state *osd) struct vo_rect *dst = &ctx->dst_rect; double xvpar = (double)dst->width / dst->height * src->height / src->width; - struct sub_render_params subparams = { - .pts = osd->vo_sub_pts, - .dim = { - .w = ctx->image_width, - .h = ctx->image_height, - .display_par = vo->monitor_par / xvpar, - .video_par = vo->aspdat.par, - }, + struct mp_osd_res res = { + .w = ctx->image_width, + .h = ctx->image_height, + .display_par = vo->monitor_par / xvpar, + .video_par = vo->aspdat.par, }; - if (osd_draw_on_image(osd, &subparams, 0, &img, &csp)) + if (osd_draw_on_image(osd, res, osd->vo_pts, 0, &img, &csp)) ctx->unchanged_image = false; } @@ -466,7 +462,7 @@ static uint32_t draw_image(struct vo *vo, mp_image_t *mpi) static int query_format(struct xvctx *ctx, uint32_t format) { uint32_t i; - int flag = VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW | VFCAP_HWSCALE_UP | VFCAP_HWSCALE_DOWN | VFCAP_OSD | VFCAP_EOSD | VFCAP_ACCEPT_STRIDE; // FIXME! check for DOWN + int flag = VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW | VFCAP_HWSCALE_UP | VFCAP_HWSCALE_DOWN | VFCAP_OSD | VFCAP_OSD | VFCAP_ACCEPT_STRIDE; // FIXME! check for DOWN /* check image formats */ for (i = 0; i < ctx->formats; i++) { diff --git a/mplayer.c b/mplayer.c index 450beb58f9..0edd8bfc1c 100644 --- a/mplayer.c +++ b/mplayer.c @@ -2292,7 +2292,7 @@ int reinit_video_chain(struct MPContext *mpctx) &retcode); if (vf_ass) sh_video->vfilter = vf_ass; - else if (retcode == -1) // vf_ass open() returns -1 VO has EOSD + else if (retcode == -1) // vf_ass open() returns -1 VO has OSD mp_msg(MSGT_CPLAYER, MSGL_V, "[ass] vf_ass not needed\n"); else mp_msg(MSGT_CPLAYER, MSGL_ERR, @@ -2546,17 +2546,15 @@ void unpause_player(struct MPContext *mpctx) static int redraw_osd(struct MPContext *mpctx) { - struct sh_video *sh_video = mpctx->sh_video; - struct vf_instance *vf = sh_video->vfilter; - if (vo_redraw_frame(mpctx->video_out) < 0) + struct vo *vo = mpctx->video_out; + if (vo_redraw_frame(vo) < 0) return -1; - mpctx->osd->vo_sub_pts = mpctx->video_pts; - // NOTE: probably should use VO ctrl directly, and/or check if a filter does - // OSD rendering (a filter can't redraw anything here) - vf->control(vf, VFCTRL_DRAW_OSD, mpctx->osd); - vo_osd_reset_changed(); - vo_flip_page(mpctx->video_out, 0, -1); + mpctx->osd->vo_pts = mpctx->video_pts; + vo_draw_osd(vo, mpctx->osd); + osd_reset_changed(mpctx->osd); + + vo_flip_page(vo, 0, -1); return 0; } @@ -3160,10 +3158,10 @@ static void run_playloop(struct MPContext *mpctx) mpctx->video_pts = sh_video->pts; update_subtitles(mpctx, sh_video->pts); update_osd_msg(mpctx); - struct vf_instance *vf = sh_video->vfilter; - mpctx->osd->vo_sub_pts = mpctx->video_pts; - vf->control(vf, VFCTRL_DRAW_OSD, mpctx->osd); - vo_osd_reset_changed(); + + mpctx->osd->vo_pts = mpctx->video_pts; + vo_draw_osd(vo, mpctx->osd); + osd_reset_changed(mpctx->osd); mpctx->time_frame -= get_relative_time(mpctx); mpctx->time_frame -= vo->flip_queue_offset; @@ -3305,8 +3303,7 @@ static void run_playloop(struct MPContext *mpctx) if (sleeptime > 0) { if (!mpctx->sh_video) goto novideo; - if (vo_osd_has_changed(mpctx->osd) || mpctx->video_out->want_redraw) - { + if (osd_has_changed(mpctx->osd) || mpctx->video_out->want_redraw) { if (redraw_osd(mpctx) < 0) { if (mpctx->paused && video_left) add_step_frame(mpctx); diff --git a/sub/ass_mp.c b/sub/ass_mp.c index 65b34d0a18..c4c418d5ba 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) + struct mp_osd_res *dim) { ass_set_frame_size(priv, dim->w, dim->h); ass_set_margins(priv, dim->mt, dim->mb, dim->ml, dim->mr); @@ -282,7 +282,7 @@ 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); + ASS_Image *imgs = ass_render_frame(renderer, track, time, &changed); if (changed == 2) res->bitmap_id = ++res->bitmap_pos_id; else if (changed) @@ -292,7 +292,7 @@ void mp_ass_render_frame(ASS_Renderer *renderer, ASS_Track *track, double time, 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) { + for (struct ass_image *img = imgs; img; img = img->next) { if (img->w == 0 || img->h == 0) continue; if (res->num_parts >= num_parts_alloc) { diff --git a/sub/ass_mp.h b/sub/ass_mp.h index 4ca43dfb2e..c3dbc5e28f 100644 --- a/sub/ass_mp.h +++ b/sub/ass_mp.h @@ -32,7 +32,7 @@ #include struct MPOpts; -struct mp_eosd_res; +struct mp_osd_res; ASS_Track *mp_ass_default_track(ASS_Library *library, struct MPOpts *opts); ASS_Track *mp_ass_read_subdata(ASS_Library *library, struct MPOpts *opts, @@ -42,7 +42,7 @@ 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); + struct mp_osd_res *dim); void mp_ass_configure_fonts(ASS_Renderer *priv); ASS_Library *mp_ass_init(struct MPOpts *opts); @@ -53,7 +53,7 @@ void mp_ass_render_frame(ASS_Renderer *renderer, ASS_Track *track, double time, #else /* CONFIG_ASS */ -/* Needed for EOSD code using this type to compile */ +/* Needed for OSD code using this type to compile */ typedef struct ass_image { int w, h; diff --git a/sub/dec_sub.c b/sub/dec_sub.c index 09d9989494..5ceb3b2422 100644 --- a/sub/dec_sub.c +++ b/sub/dec_sub.c @@ -58,7 +58,7 @@ 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_render_params *params, +void sub_get_bitmaps(struct osd_state *osd, struct mp_osd_res dim, double pts, struct sub_bitmaps *res) { struct MPOpts *opts = osd->opts; @@ -74,7 +74,7 @@ void sub_get_bitmaps(struct osd_state *osd, struct sub_render_params *params, 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); + osd->sh_sub->sd_driver->get_bitmaps(osd->sh_sub, osd, dim, pts, res); } res->bitmap_id += osd->switch_sub_id; diff --git a/sub/dec_sub.h b/sub/dec_sub.h index 389851503e..f66f05c021 100644 --- a/sub/dec_sub.h +++ b/sub/dec_sub.h @@ -4,16 +4,11 @@ #include #include -#include "sub.h" +#include "sub/sub.h" struct sh_sub; struct ass_track; -struct MPOpts *opts; - -struct sub_render_params { - double pts; - struct mp_eosd_res dim; -}; +struct MPOpts; static inline bool is_text_sub(int type) { @@ -22,7 +17,7 @@ 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_render_params *params, +void sub_get_bitmaps(struct osd_state *osd, struct mp_osd_res dim, double pts, struct sub_bitmaps *res); void sub_init(struct sh_sub *sh, struct osd_state *osd); void sub_reset(struct sh_sub *sh, struct osd_state *osd); diff --git a/sub/osd_libass.c b/sub/osd_libass.c index a182c6bdf2..4a6a0c88cb 100644 --- a/sub/osd_libass.c +++ b/sub/osd_libass.c @@ -191,7 +191,7 @@ static void update_progbar(struct osd_state *osd, struct osd_object *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->res.w / osd->res.h; + double asp = (double)obj->vo_res.w / obj->vo_res.h; double scale = (asp / 1.77777) * (obj->osd_track->PlayResY / 288.0); style->ScaleX = style->ScaleY = scale; style->FontSize = 22.0; @@ -282,8 +282,8 @@ void osd_object_get_bitmaps(struct osd_state *osd, struct osd_object *obj, if (!obj->osd_track) return; - ass_set_frame_size(osd->osd_render, osd->res.w, osd->res.h); - ass_set_aspect_ratio(osd->osd_render, osd->res.display_par, 1.0); + ass_set_frame_size(osd->osd_render, obj->vo_res.w, obj->vo_res.h); + ass_set_aspect_ratio(osd->osd_render, obj->vo_res.display_par, 1.0); 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 b286d3691b..29f021ab5e 100644 --- a/sub/sd.h +++ b/sub/sd.h @@ -1,17 +1,14 @@ #ifndef MPLAYER_SD_H #define MPLAYER_SD_H -struct osd_state; -struct sub_render_params; -struct sh_sub; -struct sub_bitmaps; +#include "dec_sub.h" struct sd_functions { int (*init)(struct sh_sub *sh, struct osd_state *osd); 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 mp_osd_res dim, double pts, 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 7926820ece..8c0719658b 100644 --- a/sub/sd_ass.c +++ b/sub/sd_ass.c @@ -128,24 +128,24 @@ static void decode(struct sh_sub *sh, struct osd_state *osd, void *data, } static void get_bitmaps(struct sh_sub *sh, struct osd_state *osd, - struct sub_render_params *params, + struct mp_osd_res dim, double pts, struct sub_bitmaps *res) { struct sd_ass_priv *ctx = sh->context; struct MPOpts *opts = osd->opts; - if (params->pts == MP_NOPTS_VALUE) + if (pts == MP_NOPTS_VALUE) return; - double scale = params->dim.display_par; + double scale = dim.display_par; bool use_vs_aspect = opts->ass_style_override ? opts->ass_vsfilter_aspect_compat : 1; if (ctx->vsfilter_aspect && use_vs_aspect) - scale = scale * params->dim.video_par; + scale = scale * dim.video_par; ASS_Renderer *renderer = osd->ass_renderer; - mp_ass_configure(renderer, opts, ¶ms->dim); + mp_ass_configure(renderer, opts, &dim); ass_set_aspect_ratio(renderer, scale, 1); - mp_ass_render_frame(renderer, ctx->ass_track, params->pts * 1000 + .5, + mp_ass_render_frame(renderer, ctx->ass_track, pts * 1000 + .5, &ctx->parts, res); talloc_steal(ctx, ctx->parts); } diff --git a/sub/sd_lavc.c b/sub/sd_lavc.c index 4311db7dc5..bee224c506 100644 --- a/sub/sd_lavc.c +++ b/sub/sd_lavc.c @@ -176,13 +176,13 @@ static void decode(struct sh_sub *sh, struct osd_state *osd, void *data, } static void get_bitmaps(struct sh_sub *sh, struct osd_state *osd, - struct sub_render_params *params, + struct mp_osd_res d, double pts, struct sub_bitmaps *res) { struct sd_lavc_priv *priv = sh->context; - if (priv->endpts != MP_NOPTS_VALUE && (params->pts >= priv->endpts || - params->pts < priv->endpts - 300)) + if (priv->endpts != MP_NOPTS_VALUE && (pts >= priv->endpts || + pts < priv->endpts - 300)) clear(priv); if (priv->bitmaps_changed && priv->count > 0) priv->outbitmaps = talloc_memdup(priv, priv->inbitmaps, @@ -190,14 +190,13 @@ static void get_bitmaps(struct sh_sub *sh, struct osd_state *osd, int inw = priv->avctx->width; int inh = priv->avctx->height; guess_resolution(sh->type, &inw, &inh); - struct mp_eosd_res *d = ¶ms->dim; - double xscale = (double) (d->w - d->ml - d->mr) / inw; - double yscale = (double) (d->h - d->mt - d->mb) / inh; + double xscale = (double) (d.w - d.ml - d.mr) / inw; + double yscale = (double) (d.h - d.mt - d.mb) / inh; for (int i = 0; i < priv->count; i++) { struct sub_bitmap *bi = &priv->inbitmaps[i]; struct sub_bitmap *bo = &priv->outbitmaps[i]; - bo->x = bi->x * xscale + d->ml; - bo->y = bi->y * yscale + d->mt; + bo->x = bi->x * xscale + d.ml; + bo->y = bi->y * yscale + d.mt; bo->dw = bi->w * xscale; bo->dh = bi->h * yscale; } diff --git a/sub/spudec.c b/sub/spudec.c index 353f72de7a..d51f62c0fc 100644 --- a/sub/spudec.c +++ b/sub/spudec.c @@ -634,7 +634,7 @@ void spudec_set_forced_subs_only(void * const this, const unsigned int flag) } } -void spudec_get_indexed(void *this, struct mp_eosd_res *dim, +void spudec_get_indexed(void *this, struct mp_osd_res *dim, struct sub_bitmaps *res) { spudec_handle_t *spu = this; diff --git a/sub/spudec.h b/sub/spudec.h index 6611a28327..84a05cbee0 100644 --- a/sub/spudec.h +++ b/sub/spudec.h @@ -22,11 +22,11 @@ #include struct sub_bitmaps; -struct mp_eosd_res; +struct mp_osd_res; void spudec_heartbeat(void *this, unsigned int pts100); void spudec_assemble(void *this, unsigned char *packet, unsigned int len, int pts100); -void spudec_get_indexed(void *this, struct mp_eosd_res *dim, struct sub_bitmaps *res); +void spudec_get_indexed(void *this, struct mp_osd_res *dim, struct sub_bitmaps *res); 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); void spudec_free(void *this); diff --git a/sub/sub.c b/sub/sub.c index 6c0f740766..5a39fbdf60 100644 --- a/sub/sub.c +++ b/sub/sub.c @@ -91,21 +91,12 @@ void *vo_vobsub=NULL; static struct osd_state *global_osd; -static void osd_update_ext(struct osd_state *osd, struct mp_eosd_res res) +static bool osd_res_equals(struct mp_osd_res a, struct mp_osd_res b) { - struct mp_eosd_res old = osd->res; - if (old.w != res.w || old.h != res.h || old.ml != res.ml || old.mt != res.mt - || old.mr != res.mr || old.mb != res.mb) - { - osd->res = res; - for (int n = 0; n < MAX_OSD_PARTS; n++) - osd->objs[n]->force_redraw = true; - } -} - -void osd_update(struct osd_state *osd, int w, int h) -{ - osd_update_ext(osd, (struct mp_eosd_res) {.w = w, .h = h}); + return a.w == b.w && a.h == b.h && a.ml == b.ml && a.mt == b.mt + && a.mr == b.mr && a.mb == b.mb + && a.display_par == b.display_par + && a.video_par == b.video_par; } struct osd_state *osd_create(struct MPOpts *opts, struct ass_library *asslib) @@ -163,22 +154,24 @@ static bool spu_visible(struct osd_state *osd, struct osd_object *obj) } static void render_object(struct osd_state *osd, struct osd_object *obj, - struct sub_bitmaps *out_imgs, - struct sub_render_params *sub_params, - const bool formats[SUBBITMAP_COUNT]) + struct mp_osd_res res, double video_pts, + const bool formats[SUBBITMAP_COUNT], + struct sub_bitmaps *out_imgs) { *out_imgs = (struct sub_bitmaps) {0}; + if (!osd_res_equals(res, obj->vo_res)) + obj->force_redraw = true; + obj->vo_res = res; + if (obj->type == OSDTYPE_SPU) { - if (spu_visible(osd, obj)) { - //spudec_get_bitmap(vo_spudec, osd->res.w, osd->res.h, out_imgs); - spudec_get_indexed(vo_spudec, &osd->res, out_imgs); - } + if (spu_visible(osd, obj)) + spudec_get_indexed(vo_spudec, &obj->vo_res, out_imgs); } else if (obj->type == OSDTYPE_SUB) { - struct sub_render_params p = *sub_params; - if (p.pts != MP_NOPTS_VALUE) - p.pts += sub_delay - osd->sub_offset; - sub_get_bitmaps(osd, &p, out_imgs); + double sub_pts = video_pts; + if (sub_pts != MP_NOPTS_VALUE) + sub_pts += sub_delay - osd->sub_offset; + sub_get_bitmaps(osd, obj->vo_res, sub_pts, out_imgs); } else { osd_object_get_bitmaps(osd, obj, out_imgs); } @@ -212,24 +205,22 @@ static void render_object(struct osd_state *osd, struct osd_object *obj, bool cached = false; // do we have a copy of all the image data? - if (formats[SUBBITMAP_RGBA] && out_imgs->format == SUBBITMAP_INDEXED) { + if (formats[SUBBITMAP_RGBA] && out_imgs->format == SUBBITMAP_INDEXED) cached |= osd_conv_idx_to_rgba(obj->cache[0], out_imgs); - } if (cached) obj->cached = *out_imgs; } // draw_flags is a bit field of OSD_DRAW_* constants -void osd_draw(struct osd_state *osd, struct sub_render_params *params, - int draw_flags, const bool formats[SUBBITMAP_COUNT], +void osd_draw(struct osd_state *osd, struct mp_osd_res res, + double video_pts, int draw_flags, + const bool formats[SUBBITMAP_COUNT], void (*cb)(void *ctx, struct sub_bitmaps *imgs), void *cb_ctx) { if (draw_flags & OSD_DRAW_SUB_FILTER) draw_flags |= OSD_DRAW_SUB_ONLY; - osd_update_ext(osd, params->dim); - for (int n = 0; n < MAX_OSD_PARTS; n++) { struct osd_object *obj = osd->objs[n]; @@ -241,7 +232,7 @@ void osd_draw(struct osd_state *osd, struct sub_render_params *params, continue; struct sub_bitmaps imgs; - render_object(osd, obj, &imgs, params, formats); + render_object(osd, obj, res, video_pts, formats, &imgs); if (imgs.num_parts > 0) { if (formats[imgs.format]) { cb(cb_ctx, &imgs); @@ -254,35 +245,6 @@ void osd_draw(struct osd_state *osd, struct sub_render_params *params, } } -static void vo_draw_eosd(void *ctx, struct sub_bitmaps *imgs) -{ - struct vo *vo = ctx; - vo_control(vo, VOCTRL_DRAW_EOSD, imgs); -} - -void draw_osd_with_eosd(struct vo *vo, struct osd_state *osd) -{ - struct mp_eosd_res dim = {0}; - if (vo_control(vo, VOCTRL_GET_EOSD_RES, &dim) != 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; - } - - dim.display_par = vo->monitor_par; - dim.video_par = vo->aspdat.par; - - struct sub_render_params subparams = { - .pts = osd->vo_sub_pts, - .dim = dim, - }; - - osd_draw(osd, &subparams, 0, formats, &vo_draw_eosd, vo); -} - struct draw_on_image_closure { struct osd_state *osd; struct mp_image *dest; @@ -301,12 +263,12 @@ static void draw_on_image(void *ctx, struct sub_bitmaps *imgs) } // Returns whether anything was drawn. -bool osd_draw_on_image(struct osd_state *osd, struct sub_render_params *params, - int draw_flags, struct mp_image *dest, +bool osd_draw_on_image(struct osd_state *osd, struct mp_osd_res res, + double video_pts, int draw_flags, struct mp_image *dest, struct mp_csp_details *dest_csp) { struct draw_on_image_closure closure = {osd, dest, dest_csp}; - osd_draw(osd, params, draw_flags, mp_draw_sub_formats, + osd_draw(osd, res, video_pts, draw_flags, mp_draw_sub_formats, &draw_on_image, &closure); return closure.changed; } @@ -320,7 +282,7 @@ void vo_osd_changed(int new_value) } } -bool vo_osd_has_changed(struct osd_state *osd) +bool osd_has_changed(struct osd_state *osd) { for (int n = 0; n < MAX_OSD_PARTS; n++) { if (osd->objs[n]->force_redraw) @@ -329,10 +291,8 @@ bool vo_osd_has_changed(struct osd_state *osd) return false; } -// Needed for VOs using the old OSD API (osd_draw_text_[ext]). -void vo_osd_reset_changed(void) +void osd_reset_changed(struct osd_state *osd) { - struct osd_state *osd = global_osd; for (int n = 0; n < MAX_OSD_PARTS; n++) osd->objs[n]->force_redraw = false; } diff --git a/sub/sub.h b/sub/sub.h index 494b84379b..3ac160a323 100644 --- a/sub/sub.h +++ b/sub/sub.h @@ -72,14 +72,11 @@ struct sub_bitmaps { struct sub_bitmap *parts; int num_parts; - // Provided for VOs with old code - struct ass_image *imgs; - // Incremented on each change int bitmap_id, bitmap_pos_id; }; -struct mp_eosd_res { +struct mp_osd_res { int w, h; // screen dimensions, including black borders int mt, mb, ml, mr; // borders (top, bottom, left, right) double display_par; @@ -111,6 +108,7 @@ struct osd_object { // VO cache state int vo_bitmap_id; int vo_bitmap_pos_id; + struct mp_osd_res vo_res; // Internally used by osd_libass.c struct ass_track *osd_track; @@ -124,12 +122,10 @@ struct osd_state { struct ass_renderer *ass_renderer; struct sh_sub *sh_sub; double sub_offset; - double vo_sub_pts; + double vo_pts; bool render_subs_in_filter; - struct mp_eosd_res res; - char *osd_text; // OSDTYPE_OSD int progbar_type, progbar_value; // OSDTYPE_PROGBAR @@ -204,14 +200,11 @@ extern float sub_fps; extern int sub_justify; -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); -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 osd_reset_changed(struct osd_state *osd); +bool osd_has_changed(struct osd_state *osd); void osd_free(struct osd_state *osd); enum mp_osd_draw_flags { @@ -219,14 +212,15 @@ enum mp_osd_draw_flags { OSD_DRAW_SUB_ONLY = (1 << 1), }; -void osd_draw(struct osd_state *osd, struct sub_render_params *params, - int draw_flags, const bool formats[SUBBITMAP_COUNT], +void osd_draw(struct osd_state *osd, struct mp_osd_res res, + double video_pts, int draw_flags, + const bool formats[SUBBITMAP_COUNT], void (*cb)(void *ctx, struct sub_bitmaps *imgs), void *cb_ctx); struct mp_image; struct mp_csp_details; -bool osd_draw_on_image(struct osd_state *osd, struct sub_render_params *params, - int draw_flags, struct mp_image *dest, +bool osd_draw_on_image(struct osd_state *osd, struct mp_osd_res res, + double video_pts, int draw_flags, struct mp_image *dest, struct mp_csp_details *dest_csp); bool sub_bitmaps_bb(struct sub_bitmaps *imgs, int *x1, int *y1, From 821c01a5f50284a839ab879724a5c67b3f855a84 Mon Sep 17 00:00:00 2001 From: wm4 Date: Sat, 20 Oct 2012 21:01:42 +0200 Subject: [PATCH 50/83] vo_corevideo: uninitialize CoreVideo objects before OpenGL --- libvo/vo_corevideo.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libvo/vo_corevideo.m b/libvo/vo_corevideo.m index 0e841f7530..16e53abeb5 100644 --- a/libvo/vo_corevideo.m +++ b/libvo/vo_corevideo.m @@ -280,8 +280,8 @@ static void uninit(struct vo *vo) struct priv *p = vo->priv; if (p->osd) mpgl_osd_destroy(p->osd); - mpgl_uninit(p->mpglctx); release_cv_entities(vo); + mpgl_uninit(p->mpglctx); } From 11ed093182f29c796ba6fd08f6c5c80e8fdb9349 Mon Sep 17 00:00:00 2001 From: wm4 Date: Sat, 20 Oct 2012 23:32:45 +0200 Subject: [PATCH 51/83] screenshot: allow taking screenshots with subtitles This adds a new screenshot mode "subtitles", which basically takes the video frame as decoded, and renders subtitles into it. This may fail for some pixel formats, because libswscale sucks. If this becomes ever a real problem, the code could be changed to convert the image to RGBA first (or whatever the image writer wants), and then render the subtitles into it. This would avoid the additional image copy needed with vo_xv too. But for now, it seems better to go with the current method in the common case: vo_opengl creates an image copy anyway, and drawing bitmaps to yv12 is better, as no color space conversion is involved in draw_bmp.c's up/downsampling conversion. --- DOCS/man/en/input.rst | 3 ++ input/input.c | 3 +- libvo/video_out.h | 2 ++ libvo/vo_xv.c | 1 + screenshot.c | 66 +++++++++++++++++++++++++++++++++++-------- screenshot.h | 9 ++---- 6 files changed, 65 insertions(+), 19 deletions(-) diff --git a/DOCS/man/en/input.rst b/DOCS/man/en/input.rst index 74c4929684..63593c53ca 100644 --- a/DOCS/man/en/input.rst +++ b/DOCS/man/en/input.rst @@ -104,6 +104,9 @@ screenshot [single|each-frame] [video|window] Save the video image, in its original resolution. Typically without OSD or subtitles, but the exact behavior depends on the selected video output. + + Like ``video``, but add subtitles. Some video outputs may still include + the OSD in the output under certain circumstances. Save the contents of the mplayer window. Typically scaled, with OSD and subtitles. The exact behavior depends on the selected video output, and diff --git a/input/input.c b/input/input.c index f2b601fdbe..ea9d2376b2 100644 --- a/input/input.c +++ b/input/input.c @@ -162,7 +162,8 @@ static const mp_cmd_t mp_cmds[] = { OARG_CHOICE(0, ({"single", 0}, {"0", 0}, {"each-frame", 1}, {"1", 1})), OARG_CHOICE(0, ({"video", 0}, {"0", 0}, - {"window", 1}, {"1", 1})), + {"window", 1}, {"1", 1}, + {"subtitles", 2})), }}, { MP_CMD_LOADFILE, "loadfile", { ARG_STRING, diff --git a/libvo/video_out.h b/libvo/video_out.h index ffb5c0c4f3..1c48b5fb06 100644 --- a/libvo/video_out.h +++ b/libvo/video_out.h @@ -105,6 +105,8 @@ struct voctrl_screenshot_args { // image data directly. // Is never NULL. (Failure has to be indicated by returning VO_FALSE.) struct mp_image *out_image; + // Whether the VO rendered OSD/subtitles into out_image + bool has_osd; }; typedef struct { diff --git a/libvo/vo_xv.c b/libvo/vo_xv.c index 92ac9a2461..8095490f4a 100644 --- a/libvo/vo_xv.c +++ b/libvo/vo_xv.c @@ -679,6 +679,7 @@ static int control(struct vo *vo, uint32_t request, void *data) case VOCTRL_SCREENSHOT: { struct voctrl_screenshot_args *args = data; args->out_image = get_screenshot(vo); + args->has_osd = !ctx->have_image_copy; return true; } } diff --git a/screenshot.c b/screenshot.c index 1f2b0694fc..c60b17649b 100644 --- a/screenshot.c +++ b/screenshot.c @@ -36,13 +36,17 @@ #include "libmpcodecs/vf.h" #include "libvo/video_out.h" #include "image_writer.h" +#include "sub/sub.h" #include "libvo/csputils.h" +#define MODE_FULL_WINDOW 1 +#define MODE_SUBTITLES 2 + typedef struct screenshot_ctx { struct MPContext *mpctx; - int full_window; + int mode; int each_frame; int using_vf_screenshot; @@ -230,7 +234,35 @@ static char *gen_fname(screenshot_ctx *ctx, const char *file_ext) } } -void screenshot_save(struct MPContext *mpctx, struct mp_image *image) +static struct mp_image *add_subs(struct MPContext *mpctx, + struct mp_image *image, + struct mp_csp_details *csp) +{ + if (!(image->flags & MP_IMGFLAG_ALLOCATED)) { + struct mp_image *new_image = alloc_mpi(image->width, image->height, + image->imgfmt); + copy_mpi(new_image, image); + new_image->w = image->w; + new_image->h = image->h; + image = new_image; + } + + double sar = (double)image->width / image->height; + double dar = (double)image->w / image->h; + struct mp_osd_res res = { + .w = image->width, + .h = image->height, + .display_par = sar / dar, + .video_par = dar / sar, + }; + osd_draw_on_image(mpctx->osd, res, mpctx->osd->vo_pts, + OSD_DRAW_SUB_ONLY, image, csp); + + return image; +} + +static void screenshot_save(struct MPContext *mpctx, struct mp_image *image, + bool with_subs) { screenshot_ctx *ctx = mpctx->screenshot_ctx; @@ -239,22 +271,29 @@ void screenshot_save(struct MPContext *mpctx, struct mp_image *image) struct image_writer_opts *opts = mpctx->opts.screenshot_image_opts; + struct mp_image *new_image = image; + if (with_subs) + new_image = add_subs(mpctx, new_image, &colorspace); + char *filename = gen_fname(ctx, image_writer_file_ext(opts)); if (filename) { mp_msg(MSGT_CPLAYER, MSGL_INFO, "*** screenshot '%s' ***\n", filename); - if (!write_image(image, &colorspace, opts, filename)) + if (!write_image(new_image, &colorspace, opts, filename)) mp_msg(MSGT_CPLAYER, MSGL_ERR, "\nError writing screenshot!\n"); talloc_free(filename); } + + if (new_image != image) + free_mp_image(new_image); } static void vf_screenshot_callback(void *pctx, struct mp_image *image) { struct MPContext *mpctx = (struct MPContext *)pctx; screenshot_ctx *ctx = mpctx->screenshot_ctx; - screenshot_save(mpctx, image); + screenshot_save(mpctx, image, ctx->mode); if (ctx->each_frame) - screenshot_request(mpctx, 0, ctx->full_window); + screenshot_request(mpctx, 0, ctx->mode); } static bool force_vf(struct MPContext *mpctx) @@ -270,26 +309,31 @@ static bool force_vf(struct MPContext *mpctx) return false; } -void screenshot_request(struct MPContext *mpctx, bool each_frame, - bool full_window) +void screenshot_request(struct MPContext *mpctx, bool each_frame, int mode) { if (mpctx->video_out && mpctx->video_out->config_ok) { screenshot_ctx *ctx = mpctx->screenshot_ctx; ctx->using_vf_screenshot = 0; + if (mode == MODE_SUBTITLES && mpctx->osd->render_subs_in_filter) + mode = 0; + if (each_frame) { ctx->each_frame = !ctx->each_frame; - ctx->full_window = full_window; + ctx->mode = mode; if (!ctx->each_frame) return; } - struct voctrl_screenshot_args args = { .full_window = full_window }; + struct voctrl_screenshot_args args = + { .full_window = (mode == MODE_FULL_WINDOW) }; if (!force_vf(mpctx) && vo_control(mpctx->video_out, VOCTRL_SCREENSHOT, &args) == true) { - screenshot_save(mpctx, args.out_image); + if (args.has_osd) + mode = 0; + screenshot_save(mpctx, args.out_image, mode == MODE_SUBTITLES); free_mp_image(args.out_image); } else { mp_msg(MSGT_CPLAYER, MSGL_INFO, "No VO support for taking" @@ -322,5 +366,5 @@ void screenshot_flip(struct MPContext *mpctx) if (ctx->using_vf_screenshot) return; - screenshot_request(mpctx, 0, ctx->full_window); + screenshot_request(mpctx, 0, ctx->mode); } diff --git a/screenshot.h b/screenshot.h index 6d205990f8..01dd372aa2 100644 --- a/screenshot.h +++ b/screenshot.h @@ -22,7 +22,6 @@ #include struct MPContext; -struct mp_image; // One time initialization at program start. void screenshot_init(struct MPContext *mpctx); @@ -30,13 +29,9 @@ void screenshot_init(struct MPContext *mpctx); // Request a taking & saving a screenshot of the currently displayed frame. // each_frame: If set, this toggles per-frame screenshots, exactly like the // screenshot slave command (MP_CMD_SCREENSHOT). -// full_window: If set, save the actual output window contents. +// mode: 0: -, 1: save the actual output window contents, 2: with subtitles. void screenshot_request(struct MPContext *mpctx, bool each_frame, - bool full_window); - -// Save the screenshot contained in the image to disk. -// The image can be in any format supported by libswscale. -void screenshot_save(struct MPContext *mpctx, struct mp_image *image); + int mode); // Called by the playback core code when a new frame is displayed. void screenshot_flip(struct MPContext *mpctx); From 48ce4ab7f9259977f426d52b51601a54dbe15465 Mon Sep 17 00:00:00 2001 From: wm4 Date: Sat, 20 Oct 2012 23:58:02 +0200 Subject: [PATCH 52/83] screenshot: change "screenshot" input command "screenshot" now maps to "screenshot subtitles" by default, instead of "screenshot video". Swap the argument order: the more useful argument should come first. Remove the compatibility aliases for numeric choices (e.g. "screenshot 1 0" won't work anymore). --- DOCS/man/en/changes.rst | 3 ++- DOCS/man/en/input.rst | 30 +++++++++++++++--------------- DOCS/man/en/mpv.rst | 5 +++-- etc/input.conf | 7 +++---- input/input.c | 8 ++++---- screenshot.c | 6 +++--- screenshot.h | 5 ++--- 7 files changed, 32 insertions(+), 32 deletions(-) diff --git a/DOCS/man/en/changes.rst b/DOCS/man/en/changes.rst index 402bdbd336..725385a2b1 100644 --- a/DOCS/man/en/changes.rst +++ b/DOCS/man/en/changes.rst @@ -52,7 +52,8 @@ General changes for mplayer2 to mpv * Improved OpenGL output (``vo_opengl``) * Make ``--softvol`` default (**mpv** is not a mixer control panel) * Improved support for .cue files -* Screenshot improvements (can save screenshots as JPG, configurable filenames) +* Screenshot improvements (can save screenshots as JPG, configurable filenames, + support not taking screenshots with or without subtitles) * Removal of teletext support * Replace image VOs (``vo_jpeg`` etc.) with ``vo_image`` * Remove ``vo_gif89a``, ``vo_md5sum``, ``vo_yuv4mpeg`` (the plan is to merge diff --git a/DOCS/man/en/input.rst b/DOCS/man/en/input.rst index 63593c53ca..18e5b824e1 100644 --- a/DOCS/man/en/input.rst +++ b/DOCS/man/en/input.rst @@ -87,31 +87,31 @@ cycle [up|down] speed_mult Multiply the ``speed`` property by the given value. -screenshot [single|each-frame] [video|window] +screenshot [subtitles|video|window] [single|each-frame] Take a screenshot. First argument: + (default) + Save the video image, in its original resolution, and with subtitles. + Some video outputs may still include the OSD in the output under certain + circumstances. +