diff options
-rw-r--r-- | libmpcodecs/vf_ass.c | 171 | ||||
-rw-r--r-- | libvo/vo_lavc.c | 2 | ||||
-rw-r--r-- | libvo/vo_x11.c | 2 | ||||
-rw-r--r-- | libvo/vo_xv.c | 2 | ||||
-rw-r--r-- | sub/sub.c | 122 | ||||
-rw-r--r-- | 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; } @@ -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) @@ -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); |