Re: [MPlayer-dev-eng] [PATCH] color SPU
- Date: Sun, 22 Jun 2008 23:18:02 +0200
- From: Benjamin Zores <ben@xxxxxxxxxxx>
- Subject: Re: [MPlayer-dev-eng] [PATCH] color SPU
Evgeniy Stepanov a écrit :
I think the last one is in the "color SPU with ass (EOSD)" thread. I've
implemented some kind of support of registering providers of EOSD bitmaps.
I've ran into some difficulties with vf<->vo interface in the case of
multiple providers, and, having very little spare time at that moment, forgot
about it.
Attached is Attila/your latest patch with EOSD ported back to latest SVN.
Do you have however any idea how to link that to DVDNAV now ?
How did you test the patch ? Playing with -ass doesn't seem to do
anything more.
Ben
Index: libmpcodecs/vf_vo.c
===================================================================
--- libmpcodecs/vf_vo.c (revision 27123)
+++ libmpcodecs/vf_vo.c (working copy)
@@ -27,6 +27,8 @@
#ifdef USE_ASS
ass_renderer_t* ass_priv;
int prev_visibility;
+ unsigned int dxs, dys;
+ int eosd_regid; /* eosd generator index number; -1 = unused*/
#endif
};
#define video_out (vf->priv->vo)
@@ -68,12 +70,39 @@
#ifdef USE_ASS
if (vf->priv->ass_priv)
ass_configure(vf->priv->ass_priv, width, height, !!(vf->default_caps & VFCAP_EOSD_UNSCALED));
+ vf->priv->dxs = width;
+ vf->priv->dys = height;
#endif
++vo_config_count;
return 1;
}
+static void ass_eosd_generator(double pts, unsigned int dxs, unsigned int dys,
+ mp_eosd_images_t* dst, void* data)
+{
+ struct vf_priv_s* priv = data;
+ if (sub_visibility && priv->ass_priv && ass_track && (pts != MP_NOPTS_VALUE)) {
+ mp_eosd_res_t res;
+ memset(&res, 0, sizeof(res));
+ if (priv->vo->control(VOCTRL_GET_EOSD_RES, &res) == VO_TRUE) {
+ ass_set_frame_size(priv->ass_priv, res.w, res.h);
+ ass_set_margins(priv->ass_priv, res.mt, res.mb, res.ml, res.mr);
+ ass_set_aspect_ratio(priv->ass_priv, (double)res.w / res.h);
+ }
+
+ dst->imgs = ass_render_frame(priv->ass_priv, ass_track,
+ (pts+sub_delay) * 1000 + .5, &dst->changed);
+ if (!priv->prev_visibility)
+ dst->changed = 2;
+ priv->prev_visibility = 1;
+ } else {
+ dst->imgs = NULL;
+ dst->changed = 2;
+ priv->prev_visibility = 0;
+ }
+}
+
static int control(struct vf_instance_s* vf, int request, void* data)
{
switch(request){
@@ -118,30 +147,22 @@
if (!vf->priv->ass_priv) return CONTROL_FALSE;
ass_configure_fonts(vf->priv->ass_priv);
vf->priv->prev_visibility = 0;
+ if (vf->priv->eosd_regid == -1)
+ eosd_unregister(vf->priv->eosd_regid);
+ vf->priv->eosd_regid=eosd_register(ass_eosd_generator, vf->priv);
return CONTROL_TRUE;
}
case VFCTRL_DRAW_EOSD:
{
- mp_eosd_images_t images = {NULL, 2};
- double pts = vf->priv->pts;
- if (!vo_config_count || !vf->priv->ass_priv) return CONTROL_FALSE;
- if (sub_visibility && vf->priv->ass_priv && ass_track && (pts != MP_NOPTS_VALUE)) {
- mp_eosd_res_t res;
- memset(&res, 0, sizeof(res));
- if (video_out->control(VOCTRL_GET_EOSD_RES, &res) == VO_TRUE) {
- ass_set_frame_size(vf->priv->ass_priv, res.w, res.h);
- ass_set_margins(vf->priv->ass_priv, res.mt, res.mb, res.ml, res.mr);
- ass_set_aspect_ratio(vf->priv->ass_priv, (double)res.w / res.h);
- }
-
- images.imgs = ass_mp_render_frame(vf->priv->ass_priv, ass_track, (pts+sub_delay) * 1000 + .5, &images.changed);
- if (!vf->priv->prev_visibility)
- images.changed = 2;
- vf->priv->prev_visibility = 1;
- } else
- vf->priv->prev_visibility = 0;
- vf->priv->prev_visibility = sub_visibility;
- return (video_out->control(VOCTRL_DRAW_EOSD, &images) == VO_TRUE) ? CONTROL_TRUE : CONTROL_FALSE;
+ mp_eosd_images_t* images;
+ int i, img_count;
+ int retval = CONTROL_TRUE;
+ img_count = gen_eosd(vf->priv->pts, vf->priv->dxs, vf->priv->dys,
+ &images);
+ for (i = 0; i < img_count; ++i)
+ if (video_out->control(VOCTRL_DRAW_EOSD, images + i) != VO_TRUE)
+ retval = CONTROL_FALSE;
+ return retval;
}
#endif
case VFCTRL_GET_PTS:
@@ -204,6 +225,9 @@
{
if (vf->priv) {
#ifdef USE_ASS
+ if (vf->priv->eosd_regid!=-1)
+ eosd_unregister(vf->priv->eosd_regid);
+ vf->priv->eosd_regid=-1;
if (vf->priv->ass_priv)
ass_renderer_done(vf->priv->ass_priv);
#endif
@@ -223,6 +247,9 @@
vf->uninit=uninit;
vf->priv=calloc(1, sizeof(struct vf_priv_s));
vf->priv->vo = (const vo_functions_t *)args;
+#ifdef USE_ASS
+ vf->priv->eosd_regid=-1;
+#endif
if(!video_out) return 0; // no vo ?
// if(video_out->preinit(args)) return 0; // preinit failed
return 1;
Index: libmpcodecs/vf_ass.c
===================================================================
--- libmpcodecs/vf_ass.c (revision 27123)
+++ libmpcodecs/vf_ass.c (working copy)
@@ -35,6 +35,7 @@
#include "img_format.h"
#include "mp_image.h"
#include "vf.h"
+#include "libavutil/common.h"
#include "libvo/fastmemcpy.h"
@@ -55,6 +56,7 @@
static const struct vf_priv_s {
int outh, outw;
+ unsigned int dxs, dys;
unsigned int outfmt;
@@ -66,6 +68,8 @@
unsigned char* planes[3];
unsigned char* dirty_rows;
+
+ int eosd_regid; /* eosd generator index number; -1 = unused*/
} vf_priv_dflt;
extern int opt_screen_size_x;
@@ -83,6 +87,8 @@
vf->priv->outh = height + ass_top_margin + ass_bottom_margin;
vf->priv->outw = width;
+ vf->priv->dxs = width;
+ vf->priv->dys = height;
if(!opt_screen_size_x && !opt_screen_size_y){
d_width = d_width * vf->priv->outw / width;
@@ -215,6 +221,8 @@
unsigned char val;
int chroma_rows;
+ if (first_row>vf->dmpi->h) return;
+ last_row = FFMIN(vf->dmpi->h,last_row);
first_row -= (first_row % 2);
last_row += (last_row % 2);
chroma_rows = (last_row - first_row) / 2;
@@ -281,22 +289,24 @@
}
}
-static void my_draw_bitmap(struct vf_instance_s* vf, unsigned char* bitmap, int bitmap_w, int bitmap_h, int stride, int dst_x, int dst_y, unsigned color)
+static void my_draw_rgba8(struct vf_instance_s* 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;
+ int i, j, w, h;
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) {
+ h = FFMIN(bitmap_h,dmpi->h - dst_y);
+ w = FFMIN(bitmap_w,dmpi->w - dst_x);
+ for (i = 0; i < h; ++i) {
+ for (j = 0; j < w; ++j) {
unsigned k = ((unsigned)src[j]) * opacity / 255;
dsty[j] = (k*y + (255-k)*dsty[j]) / 255;
dstu[j] = (k*u + (255-k)*dstu[j]) / 255;
@@ -309,30 +319,90 @@
}
}
-static int render_frame(struct vf_instance_s* vf, mp_image_t *mpi, const ass_image_t* img)
+static void my_draw_yuva32(struct vf_instance_s* vf, const ass_image_t* img)
{
+ unsigned char *srcy, *srcu, *srcv, *srca;
+ unsigned char *dsty, *dstu, *dstv;
+ int i, j, w, h;
+ mp_image_t* dmpi = vf->dmpi;
+
+ srca = img->bitmap;
+ srcy = img->planes[0];
+ srcu = img->planes[1];
+ srcv = img->planes[2];
+ dsty = dmpi->planes[0] + img->dst_x + img->dst_y * dmpi->stride[0];
+ switch(dmpi->imgfmt) {
+ case IMGFMT_YV12:
+ dstu = vf->priv->planes[2] + img->dst_x + img->dst_y * vf->priv->outw;
+ dstv = vf->priv->planes[1] + img->dst_x + img->dst_y * vf->priv->outw;
+ default:
+ dstu = vf->priv->planes[1] + img->dst_x + img->dst_y * vf->priv->outw;
+ dstv = vf->priv->planes[2] + img->dst_x + img->dst_y * vf->priv->outw;
+ }
+ h = FFMIN(img->h,dmpi->h - img->dst_y);
+ w = FFMIN(img->w,dmpi->w - img->dst_x);
+ for (i = 0; i < h; ++i) {
+ for (j = 0; j < w; ++j) {
+ unsigned k = (unsigned)srca[j];
+ dsty[j] = (k*srcy[j] + (255-k)*dsty[j]) / 255;
+ dstu[j] = (k*srcu[j] + (255-k)*dstu[j]) / 255;
+ dstv[j] = (k*srcv[j] + (255-k)*dstv[j]) / 255;
+ }
+ srca += img->stride;
+ srcy += img->stride;
+ srcu += img->stride;
+ srcv += img->stride;
+ dsty += dmpi->stride[0];
+ dstu += vf->priv->outw;
+ dstv += vf->priv->outw;
+ }
+}
+
+static int render_images(struct vf_instance_s* vf, mp_image_t *mpi, const ass_image_t* img)
+{
if (img) {
- memset(vf->priv->dirty_rows, 0, vf->priv->outh); // reset dirty rows
while (img) {
copy_from_image(vf, img->dst_y, img->dst_y + img->h);
- my_draw_bitmap(vf, img->bitmap, img->w, img->h, img->stride,
- img->dst_x, img->dst_y, img->color);
+ switch (img->format) {
+ case ASS_FMT_RGBA8:
+ my_draw_rgba8(vf, img->bitmap, img->w, img->h, img->stride,
+ img->dst_x, img->dst_y, img->color);
+ break;
+ case ASS_FMT_YUVA32:
+ my_draw_yuva32(vf, img);
+ break;
+ default:
+ printf("unsupported EOSD format, ignored\n");
+ }
img = img->next;
}
- copy_to_image(vf);
}
return 0;
}
+static void ass_eosd_generator(double pts, unsigned int dxs, unsigned int dys,
+ mp_eosd_images_t* dst, void* data)
+{
+ struct vf_priv_s* priv = data;
+ dst->imgs = NULL;
+ dst->changed = 2; // unused
+ if (sub_visibility && priv->ass_priv && ass_track && (pts != MP_NOPTS_VALUE))
+ dst->imgs = ass_render_frame(priv->ass_priv, ass_track, (pts+sub_delay) * 1000 + .5, NULL);
+}
+
static int put_image(struct vf_instance_s* vf, mp_image_t *mpi, double pts)
{
- ass_image_t* images = 0;
- if (sub_visibility && vf->priv->ass_priv && ass_track && (pts != MP_NOPTS_VALUE))
- images = ass_mp_render_frame(vf->priv->ass_priv, ass_track, (pts+sub_delay) * 1000 + .5, NULL);
+ mp_eosd_images_t* images;
+ int i, img_count;
prepare_image(vf, mpi);
- if (images) render_frame(vf, mpi, images);
+ img_count = gen_eosd(pts, vf->priv->dxs, vf->priv->dys, &images);
+ memset(vf->priv->dirty_rows, 0, vf->priv->outh); // reset dirty rows
+ for (i = 0; i < img_count; ++i)
+ render_images(vf, mpi, images[i].imgs);
+ copy_to_image(vf);
+
return vf_next_put_image(vf, vf->dmpi, pts);
}
@@ -354,6 +424,9 @@
vf->priv->ass_priv = ass_renderer_init((ass_library_t*)data);
if (!vf->priv->ass_priv) return CONTROL_FALSE;
ass_configure_fonts(vf->priv->ass_priv);
+ if (vf->priv->eosd_regid!=-1)
+ eosd_unregister(vf->priv->eosd_regid);
+ vf->priv->eosd_regid=eosd_register(ass_eosd_generator, vf->priv);
return CONTROL_TRUE;
case VFCTRL_DRAW_EOSD:
if (vf->priv->ass_priv) return CONTROL_TRUE;
@@ -364,6 +437,9 @@
static void uninit(struct vf_instance_s* vf)
{
+ if (vf->priv->eosd_regid!=-1)
+ eosd_unregister(vf->priv->eosd_regid);
+ vf->priv->eosd_regid=-1;
if (vf->priv->ass_priv)
ass_renderer_done(vf->priv->ass_priv);
if (vf->priv->planes[1])
@@ -403,6 +479,7 @@
vf->get_image = get_image;
vf->put_image = put_image;
vf->default_caps=VFCAP_EOSD;
+ vf->priv->eosd_regid=-1;
return 1;
}
Index: spudec.c
===================================================================
--- spudec.c (revision 27123)
+++ spudec.c (working copy)
@@ -24,6 +24,10 @@
#include "libvo/video_out.h"
#include "spudec.h"
#include "libavutil/avutil.h"
+#ifdef USE_ASS
+#include "libass/ass.h"
+#include "libass/ass_mp.h"
+#endif
#include "libswscale/swscale.h"
/* Valid values for spu_aamode:
@@ -78,20 +82,31 @@
size_t image_size; /* Size of the image buffer */
unsigned char *image; /* Grayscale value */
unsigned char *aimage; /* Alpha value */
+ unsigned char *imageu, *imagev; /* U,V planes with color SPU */
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;
+ unsigned char *scaled_imageu, *scaled_imagev;
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 */
const vo_functions_t *hw_spu;
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 */
+#ifdef USE_ASS
+ int eosd_regid; /* eosd generator index number; -1 = unused*/
+ ass_image_t *ass_img; /* ass images with eosd */
+#endif
} spudec_handle_t;
+#ifdef USE_ASS
+static void ass_eosd_generator(double pts, unsigned int dxs, unsigned int dys,
+ mp_eosd_images_t* dst, void* data);
+#endif
+
static void spudec_queue_packet(spudec_handle_t *this, packet_t *packet)
{
if (this->queue_head == NULL)
@@ -174,6 +189,10 @@
unsigned int first_y, last_y;
unsigned char *image;
unsigned char *aimage;
+#ifdef USE_ASS
+ unsigned char *imageu;
+ unsigned char *imagev;
+#endif
if (this->stride == 0 || this->height == 0) {
return;
@@ -197,12 +216,27 @@
// printf("new h %d new start %d (sz %d st %d)---\n\n", this->height, this->start_row, this->image_size, this->stride);
+#ifdef USE_ASS
+ if (ass_enabled)
+ image = malloc(4 * this->stride * this->height);
+ else
+#endif
image = malloc(2 * this->stride * this->height);
if(image){
this->image_size = this->stride * this->height;
aimage = image + this->image_size;
memcpy(image, this->image + this->stride * first_y, this->image_size);
memcpy(aimage, this->aimage + this->stride * first_y, this->image_size);
+#ifdef USE_ASS
+ if (ass_enabled) {
+ imageu = image + this->image_size * 2;
+ imagev = image + this->image_size * 3;
+ memcpy(imageu, this->imageu + this->stride * first_y, this->image_size);
+ memcpy(imagev, this->imagev + this->stride * first_y, this->image_size);
+ this->imageu = imageu;
+ this->imagev = imagev;
+ }
+#endif
free(this->image);
this->image = image;
this->aimage = aimage;
@@ -214,6 +248,9 @@
static void spudec_process_data(spudec_handle_t *this, packet_t *packet)
{
unsigned int cmap[4], alpha[4];
+#ifdef USE_ASS
+ unsigned int cmapu[4], cmapv[4];
+#endif
unsigned int i, x, y;
this->scaled_frame_width = 0;
@@ -225,6 +262,25 @@
this->height = packet->height;
this->width = packet->width;
this->stride = packet->stride;
+#ifdef USE_ASS
+ if (ass_enabled)
+ for (i = 0; i < 4; ++i) {
+ cmap[i]=cmapu[i]=cmapv[i]=0;
+ alpha[i] = mkalpha(packet->alpha[i]);
+ if (alpha[i] == 0) continue;
+ alpha[i] = 0xff - alpha[i]; // linear alpha
+ if (this->custom){
+ cmap[i] = ((this->cuspal[i] >> 16) & 0xff);
+ cmapu[i] = ((this->cuspal[i] >> 8) & 0xff);
+ cmapv[i] = (this->cuspal[i] & 0xff);
+ } else {
+ cmap[i] = ((this->global_palette[packet->palette[i]] >> 16) & 0xff);
+ cmapu[i] = ((this->global_palette[packet->palette[i]] >> 8) & 0xff);
+ cmapv[i] = (this->global_palette[packet->palette[i]] & 0xff);
+ }
+ }
+ else
+#endif
for (i = 0; i < 4; ++i) {
alpha[i] = mkalpha(packet->alpha[i]);
if (this->custom && (this->cuspal[i] >> 31) != 0)
@@ -248,10 +304,21 @@
free(this->image);
this->image_size = 0;
}
+#ifdef USE_ASS
+ if (ass_enabled)
+ this->image = malloc(4 * this->stride * this->height);
+ else
+#endif
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;
+#ifdef USE_ASS
+ if (ass_enabled) {
+ this->imageu = this->image + this->image_size * 2;
+ this->imagev = this->image + this->image_size * 3;
+ }
+#endif
}
}
if (this->image == NULL)
@@ -263,6 +330,12 @@
memset(this->aimage + y * this->stride + this->width, 0, this->stride - this->width);
/* FIXME: Why is this one needed? */
memset(this->image + y * this->stride + this->width, 0, this->stride - this->width);
+#ifdef USE_ASS
+ if (ass_enabled) {
+ memset(this->imageu + y * this->stride + this->width, 0, this->stride - this->width);
+ memset(this->imagev + y * this->stride + this->width, 0, this->stride - this->width);
+ }
+#endif
}
i = packet->current_nibble[1];
@@ -292,6 +365,12 @@
/* FIXME have to use palette and alpha map*/
memset(this->image + y * this->stride + x, cmap[color], len);
memset(this->aimage + y * this->stride + x, alpha[color], len);
+#ifdef USE_ASS
+ if (ass_enabled) {
+ memset(this->imageu + y * this->stride + x, cmapu[color], len);
+ memset(this->imagev + y * this->stride + x, cmapv[color], len);
+ }
+#endif
x += len;
if (x >= this->width) {
next_line(packet);
@@ -773,6 +852,9 @@
scale_pixel *table_x;
scale_pixel *table_y;
+#ifdef USE_ASS
+ if (ass_enabled) return;
+#endif
if (spu->start_pts <= spu->now_pts && spu->now_pts < spu->end_pts) {
// check if only forced subtitles are requested
@@ -1147,6 +1229,11 @@
// forced subtitles default: show all subtitles
this->forced_subs_only=0;
this->is_forced_sub=0;
+#ifdef USE_ASS
+ this->eosd_regid=-1;
+ if(ass_enabled)
+ this->eosd_regid = eosd_register(ass_eosd_generator, this);
+#endif
}
else
mp_msg(MSGT_SPUDEC,MSGL_FATAL, "FATAL: spudec_init: calloc");
@@ -1162,6 +1249,12 @@
{
spudec_handle_t *spu = (spudec_handle_t*)this;
if (spu) {
+#ifdef USE_ASS
+ if (spu->eosd_regid!=-1)
+ eosd_unregister(spu->eosd_regid);
+ if (spu->ass_img)
+ free(spu->ass_img);
+#endif
while (spu->queue_head)
spudec_free_packet(spudec_dequeue_packet(spu));
if (spu->packet)
@@ -1182,3 +1275,486 @@
spu->hw_spu = hw_spu;
hw_spu->control(VOCTRL_SET_SPU_PALETTE,spu->global_palette);
}
+
+#ifdef USE_ASS
+static void scale_image_ass(int x, int y, scale_pixel* table_x,
+ scale_pixel* table_y, spudec_handle_t * spu) {
+ int alpha[4];
+ int colory[4];
+ int coloru[4];
+ int colorv[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] = spu->aimage[base];
+ alpha[1] = spu->aimage[base + 1];
+ alpha[2] = spu->aimage[base + spu->stride];
+ alpha[3] = spu->aimage[base + spu->stride + 1];
+ colory[0] = spu->image[base];
+ colory[1] = spu->image[base + 1];
+ colory[2] = spu->image[base + spu->stride];
+ colory[3] = spu->image[base + spu->stride + 1];
+ coloru[0] = spu->imageu[base];
+ coloru[1] = spu->imageu[base + 1];
+ coloru[2] = spu->imageu[base + spu->stride];
+ coloru[3] = spu->imageu[base + spu->stride + 1];
+ colorv[0] = spu->imagev[base];
+ colorv[1] = spu->imagev[base + 1];
+ colorv[2] = spu->imagev[base + spu->stride];
+ colorv[3] = spu->imagev[base + spu->stride + 1];
+ scale[0] = (table_x[x].left_up * table_y[y].left_up >> 16) * 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] =
+ (colory[0] * scale[0] +
+ colory[1] * scale[1] +
+ colory[2] * scale[2] +
+ colory[3] * scale[3])>>24;
+ spu->scaled_imageu[scaled] =
+ (coloru[0] * scale[0] +
+ coloru[1] * scale[1] +
+ coloru[2] * scale[2] +
+ coloru[3] * scale[3])>>24;
+ spu->scaled_imagev[scaled] =
+ (colorv[0] * scale[0] +
+ colorv[1] * scale[1] +
+ colorv[2] * scale[2] +
+ colorv[3] * scale[3])>>24;
+ spu->scaled_aimage[scaled] =
+ (scale[0] + scale[1] + scale[2] + scale[3]) >> 16;
+}
+
+void sws_spu_image_ass(unsigned char *dy, unsigned char *du, unsigned char *dv,
+ unsigned char *d2, int dw, int dh, int ds,
+ unsigned char *sy,unsigned char *su,unsigned char *sv,
+ unsigned char *s2, int sw, int sh, int ss) {
+
+ struct SwsContext *ctx;
+ static SwsFilter filter;
+ static int firsttime = 1;
+ static float oldvar;
+
+ 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,&sy,&ss,0,sh,&dy,&ds);
+ sws_scale(ctx,&su,&ss,0,sh,&du,&ds);
+ sws_scale(ctx,&sv,&ss,0,sh,&dv,&ds);
+ sws_scale(ctx,&s2,&ss,0,sh,&d2,&ds);
+ sws_freeContext(ctx);
+}
+
+static void spudec_draw_scaled_ass(void *this, unsigned int dxs,
+ unsigned int dys) {
+ spudec_handle_t *spu = (spudec_handle_t *)this;
+ scale_pixel *table_x;
+ scale_pixel *table_y;
+ unsigned int scalex = 0;
+ unsigned int scaley = 0;
+ unsigned int x, y;
+
+ /* scaled_x = scalex * x / 0x100
+ scaled_y = scaley * y / 0x100
+ order of operations is important because of rounding. */
+ scalex = 0x100 * dxs / spu->orig_frame_width;
+ 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(4 * 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;
+ spu->scaled_imageu = spu->scaled_image + spu->scaled_image_size * 2;
+ spu->scaled_imagev = spu->scaled_image + spu->scaled_image_size * 3;
+ }
+ }
+ if (!spu->scaled_image) return;
+ if (spu->scaled_width > 1 && spu->scaled_height > 1) {
+ switch(spu_aamode&15) {
+ case 4:
+ sws_spu_image_ass(spu->scaled_image, spu->scaled_imageu,
+ spu->scaled_imagev, spu->scaled_aimage,
+ spu->scaled_width, spu->scaled_height,
+ spu->scaled_stride,
+ spu->image, spu->imageu, spu->imagev, 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_ass(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_imageu[scaled_strides + x] =
+ spu->imageu[strides + unscaled_x];
+ spu->scaled_imagev[scaled_strides + x] =
+ spu->imagev[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 colory = 0;
+ unsigned int coloru = 0;
+ unsigned int colorv = 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 = spu->aimage[base];
+ alpha += tmp;
+ colory += tmp * spu->image[base];
+ coloru += tmp * spu->imageu[base];
+ colorv += tmp * spu->imagev[base];
+ }
+ base = y * spu->scaled_stride + x;
+ spu->scaled_image[base] = alpha ? colory / alpha : 0;
+ spu->scaled_imageu[base] = alpha ? coloru / alpha : 0;
+ spu->scaled_imagev[base] = alpha ? colorv / 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; */
+ }
+ }
+ }
+ 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 colory = 0.0;
+ double coloru = 0.0;
+ double colorv = 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 * (spu->aimage[base + (unsigned int) unscaled_x]);
+ alpha += tmp;
+ colory += tmp * spu->image[base + (unsigned int) unscaled_x];
+ coloru += tmp * spu->imageu[base + (unsigned int) unscaled_x];
+ colorv += tmp * spu->imagev[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 * spu->aimage[base];
+ alpha += tmp;
+ colory += tmp * spu->image[base];
+ coloru += tmp * spu->imageu[base];
+ colorv += tmp * spu->imagev[base];
+ }
+ }
+ /* 3: top right part */
+ if (right > 0.0) {
+ base = spu->stride * (unsigned int) unscaled_y +
+ (unsigned int) unscaled_x_right;
+ tmp = right * top * spu->aimage[base];
+ alpha += tmp;
+ colory += tmp * spu->image[base];
+ coloru += tmp * spu->imageu[base];
+ colorv += tmp * spu->imagev[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 */ * spu->aimage[base];
+ alpha += tmp;
+ colory += tmp * spu->image[base];
+ coloru += tmp * spu->imageu[base];
+ colorv += tmp * spu->imagev[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 * */ spu->aimage[base + walkx];
+ alpha += tmp;
+ colory += tmp * spu->image[base + walkx];
+ coloru += tmp * spu->imageu[base + walkx];
+ colorv += tmp * spu->imagev[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 */ * spu->aimage[base];
+ alpha += tmp;
+ colory += tmp * spu->image[base];
+ coloru += tmp * spu->imageu[base];
+ colorv += tmp * spu->imagev[base];
+ }
+ }
+ /* 7: bottom left part */
+ if (bottom > 0.0) {
+ base = spu->stride * (unsigned int) unscaled_y_bottom +
+ (unsigned int) unscaled_x;
+ tmp = left * bottom * spu->aimage[base];
+ alpha += tmp;
+ colory += tmp * spu->image[base];
+ coloru += tmp * spu->imageu[base];
+ colorv += tmp * spu->imagev[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 * spu->aimage[base + walkx];
+ alpha += tmp;
+ colory += tmp * spu->image[base + walkx];
+ coloru += tmp * spu->imageu[base + walkx];
+ colorv += tmp * spu->imagev[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 * spu->aimage[base];
+ alpha += tmp;
+ colory += tmp * spu->image[base];
+ coloru += tmp * spu->imageu[base];
+ colorv += tmp * spu->imagev[base];
+ }
+ /* Finally mix these transparency and brightness information suitably */
+ base = spu->scaled_stride * y + x;
+ spu->scaled_image[base] = alpha > 0 ? colory / alpha : 0;
+ spu->scaled_imageu[base] = alpha > 0 ? coloru / alpha : 0;
+ spu->scaled_imagev[base] = alpha > 0 ? colorv / alpha : 0;
+ spu->scaled_aimage[base] = alpha * scalex * scaley / 0x10000;
+ }
+ }
+ }
+ }
+ /* 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) {
+ if (spu->scaled_start_row < 0) spu->scaled_start_row = 0;
+ } else {
+ if (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;
+ if (spu->scaled_start_row < 0) spu->scaled_start_row = 0;
+ break;
+ }
+ }
+}
+
+static void ass_eosd_generator(double pts, unsigned int dxs, unsigned int dys,
+ mp_eosd_images_t* dst, void* data) {
+ spudec_handle_t *spu = (spudec_handle_t*)data;
+
+ dst->imgs=NULL;
+ if (!spu) return;
+ if (spu->start_pts > spu->now_pts || spu->now_pts >= spu->end_pts ||
+ !spu->image) return;
+ if ((spu->forced_subs_only) && !(spu->is_forced_sub)) return;
+ dst->changed = 0;
+ if (!spu->ass_img)
+ spu->ass_img = malloc(sizeof(ass_image_t));
+ memset(spu->ass_img,0,sizeof(ass_image_t));
+ spu->ass_img->format = ASS_FMT_YUVA32;
+ if (!(spu_aamode&16) && (spu->orig_frame_width == 0 ||
+ spu->orig_frame_height == 0 ||
+ (spu->orig_frame_width == dxs && spu->orig_frame_height == dys))) {
+ spu->ass_img->w = spu->width;
+ spu->ass_img->h = spu->height;
+ spu->ass_img->stride = spu->stride;
+ spu->ass_img->planes[0] = spu->image;
+ spu->ass_img->planes[1] = spu->imageu;
+ spu->ass_img->planes[2] = spu->imagev;
+ spu->ass_img->bitmap = spu->aimage;
+ spu->ass_img->dst_x = spu->start_col;
+ spu->ass_img->dst_y = spu->start_row;
+ } else {
+ if(!spu->scaled_image || spu->spu_changed)
+ spudec_draw_scaled_ass(spu, dxs, dys);
+
+ spu->ass_img->w = spu->scaled_width;
+ spu->ass_img->h = spu->scaled_height;
+ spu->ass_img->stride = spu->scaled_stride;
+ spu->ass_img->planes[0] = spu->scaled_image;
+ spu->ass_img->planes[1] = spu->scaled_imageu;
+ spu->ass_img->planes[2] = spu->scaled_imagev;
+ spu->ass_img->bitmap = spu->scaled_aimage;
+ spu->ass_img->dst_x = spu->scaled_start_col;
+ spu->ass_img->dst_y = spu->scaled_start_row;
+ }
+ if (spu->spu_changed) dst->changed = 2;
+ dst->imgs = spu->ass_img;
+ spu->spu_changed = 0;
+}
+#endif
Index: libass/ass_mp.c
===================================================================
--- libass/ass_mp.c (revision 27123)
+++ libass/ass_mp.c (working copy)
@@ -276,3 +276,47 @@
}
return ass_render_frame(priv, track, now, detect_change);
}
+
+#define MAX_EOSD 10
+mp_eosd_images_t eosd[MAX_EOSD];
+eosd_generator_p eosd_gens[MAX_EOSD];
+void* eosd_gen_data[MAX_EOSD];
+int eosd_count = 0;
+
+void eosd_reset()
+{
+ eosd_count = 0;
+}
+
+int eosd_register(eosd_generator_p gen, void* data)
+{
+ int i, genid = -1;
+ for (i = 0; i < eosd_count; ++i)
+ if(!eosd_gens[i]) { genid = i; break; }
+ if (eosd_count >= MAX_EOSD && genid == -1)
+ return -1;
+ if (genid == -1) genid = eosd_count ++;
+ memset(eosd + genid, 0, sizeof(mp_eosd_images_t));
+ eosd_gens[genid] = gen;
+ eosd_gen_data[genid] = data;
+ return genid;
+}
+
+void eosd_unregister(int genid)
+{
+ if (genid<0 || genid>eosd_count)
+ return;
+ eosd_gens[genid] = NULL;
+ memset(eosd + genid, 0, sizeof(mp_eosd_images_t));
+}
+
+int gen_eosd(double pts, unsigned int dxs, unsigned int dys,
+ mp_eosd_images_t** images)
+{
+ int i;
+ for (i = 0; i < eosd_count; ++i)
+ if (eosd_gens[i])
+ eosd_gens[i](pts, dxs, dys, eosd + i, eosd_gen_data[i]);
+ *images = eosd;
+ return eosd_count;
+}
Index: libass/ass_render.c
===================================================================
--- libass/ass_render.c (revision 27123)
+++ libass/ass_render.c (working copy)
@@ -301,6 +301,7 @@
{
ass_image_t* img = calloc(1, sizeof(ass_image_t));
+ img->format = ASS_FMT_RGBA8;
img->w = bitmap_w;
img->h = bitmap_h;
img->stride = stride;
Index: libass/ass_mp.h
===================================================================
--- libass/ass_mp.h (revision 27123)
+++ libass/ass_mp.h (working copy)
@@ -51,9 +51,46 @@
typedef struct {
ass_image_t* imgs;
- int changed;
+ int changed; // shows if imgs have changed:
+ // 0 - no change
+ // 1 - position changed
+ // 2 - contents changed
} mp_eosd_images_t;
+// update mp_eosd_images_t, data is private data defined in call to eosd_register
+// param dxs, dys: destination frame size with scaler of gen_esod()
+typedef void (*eosd_generator_p)(double pts, unsigned int dxs,
+ unsigned int dys,
+ mp_eosd_images_t* dst, void* data);
+
+/**
+ * \brief clear eosd generators list
+ */
+void eosd_reset();
+
+/**
+ * \brief register an EOSD generator
+ * \param gen: a pointer generator function
+ * \param data: private data, will be passed as a third argument in every gen() call
+ * \return index of the registered generator
+ */
+int eosd_register(eosd_generator_p gen, void* data);
+
+/**
+ * \brief unregister an EOSD generator
+ * \param genid: index of the registered generator
+ */
+void eosd_unregister(int genid);
+
+/**
+ * \brief update eosd
+ * \param dxs, dys: destination frame size with scaler of gen_esod()
+ * \param images out: contains a pointer to array of mp_eosd_images_t
+ * \return size of *images
+ */
+int gen_eosd(double pts, unsigned int dxs, unsigned int dys,
+ mp_eosd_images_t** images);
+
extern int ass_force_reload;
ass_image_t* ass_mp_render_frame(ass_renderer_t *priv, ass_track_t* track, long long now, int* detect_change);
Index: libass/ass.h
===================================================================
--- libass/ass.h (revision 27123)
+++ libass/ass.h (working copy)
@@ -31,10 +31,16 @@
/// a linked list of images produced by ass renderer
typedef struct ass_image_s {
+ enum {ASS_FMT_RGBA8 = 0, // RGB color + alpha plane
+ ASS_FMT_YUVA8, // YUV color + alpha plane
+ ASS_FMT_RGBA32, // 4 planes (r, g, b, a)
+ ASS_FMT_YUVA32 // 4 planes (y, u, v, a)
+ } format;
int w, h; // bitmap width/height
int stride; // bitmap stride
- unsigned char* bitmap; // 1bpp stride*h alpha buffer
- uint32_t color; // RGBA
+ unsigned char* planes[3];
+ unsigned char* bitmap; // 8bpp alpha buffer
+ uint32_t color;
int dst_x, dst_y; // bitmap placement inside the video frame
struct ass_image_s* next; // linked list
_______________________________________________
MPlayer-dev-eng mailing list
MPlayer-dev-eng@xxxxxxxxxxxx
https://lists.mplayerhq.hu/mailman/listinfo/mplayer-dev-eng