summaryrefslogtreecommitdiff
path: root/src/video_out/alphablend.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/video_out/alphablend.c')
-rw-r--r--src/video_out/alphablend.c820
1 files changed, 569 insertions, 251 deletions
diff --git a/src/video_out/alphablend.c b/src/video_out/alphablend.c
index a9f216a9e..1d8980103 100644
--- a/src/video_out/alphablend.c
+++ b/src/video_out/alphablend.c
@@ -38,6 +38,7 @@
#include "xine_internal.h"
#include "video_out.h"
#include "alphablend.h"
+#include "bswap.h"
#define BLEND_COLOR(dst, src, mask, o) ((((src&mask)*o + ((dst&mask)*(0x0f-o)))/0xf) & mask)
@@ -56,7 +57,7 @@ static void mem_blend16(uint16_t *mem, uint16_t clr, uint8_t o, int len) {
}
static void mem_blend24(uint8_t *mem, uint8_t r, uint8_t g, uint8_t b,
- uint8_t o, int len) {
+ uint8_t o, int len) {
uint8_t *limit = mem + len*3;
while (mem < limit) {
*mem = BLEND_BYTE(*mem, r, o);
@@ -112,7 +113,8 @@ rle_img_advance_line(rle_elem_t *rle, rle_elem_t *rle_limit, int w)
void blend_rgb16 (uint8_t * img, vo_overlay_t * img_overl,
int img_width, int img_height,
- int dst_width, int dst_height)
+ int dst_width, int dst_height,
+ alphablend_t *extra_data)
{
uint8_t *trans;
clut_t *clut;
@@ -184,11 +186,11 @@ void blend_rgb16 (uint8_t * img, vo_overlay_t * img_overl,
if( (img_overl->x + img_overl->clip_right) < dst_width )
clip_right = img_overl->clip_right;
else
- clip_right = dst_width - 1 - img_overl->x;
+ clip_right = dst_width - img_overl->x;
/* avoid buffer overflow */
if( (src_height + img_overl->y) >= dst_height )
- src_height = dst_height - 1 - img_overl->y;
+ src_height = dst_height - img_overl->y;
rlelen = rle_remainder = rle_this_bite = 0;
rle_remainder = rlelen = rle->len;
@@ -224,13 +226,13 @@ void blend_rgb16 (uint8_t * img, vo_overlay_t * img_overl,
if (y < img_overl->clip_top) {
zone_state = 1;
break;
- } else if (y > img_overl->clip_bottom) {
+ } else if (y >= img_overl->clip_bottom) {
zone_state = 5;
break;
} else if (x < img_overl->clip_left) {
zone_state = 2;
break;
- } else if (x > img_overl->clip_right) {
+ } else if (x >= img_overl->clip_right) {
zone_state = 4;
break;
} else {
@@ -294,7 +296,7 @@ void blend_rgb16 (uint8_t * img, vo_overlay_t * img_overl,
clut = (clut_t*) img_overl->color;
trans = img_overl->trans;
o = trans[clr];
- if (x + rle_remainder < img_overl->clip_left) {
+ if (x + rle_remainder <= img_overl->clip_left) {
rle_this_bite = rle_remainder;
rle_remainder = rlelen = rle->len;
clr_next = rle->color;
@@ -326,7 +328,7 @@ void blend_rgb16 (uint8_t * img, vo_overlay_t * img_overl,
} else {
rle = rle_start; /* y-scaling, reuse the last rle encoded line */
}
- if (y > img_overl->clip_bottom) {
+ if (y >= img_overl->clip_bottom) {
zone_state = 5;
break;
}
@@ -339,7 +341,7 @@ void blend_rgb16 (uint8_t * img, vo_overlay_t * img_overl,
clut = (clut_t*) img_overl->clip_color;
trans = img_overl->clip_trans;
o = trans[clr];
- if (x + rle_remainder < img_overl->clip_right) {
+ if (x + rle_remainder <= img_overl->clip_right) {
rle_this_bite = rle_remainder;
rle_remainder = rlelen = rle->len;
clr_next = rle->color;
@@ -371,7 +373,7 @@ void blend_rgb16 (uint8_t * img, vo_overlay_t * img_overl,
} else {
rle = rle_start; /* y-scaling, reuse the last rle encoded line */
}
- if (y > img_overl->clip_bottom) {
+ if (y >= img_overl->clip_bottom) {
zone_state = 5;
break;
}
@@ -384,7 +386,7 @@ void blend_rgb16 (uint8_t * img, vo_overlay_t * img_overl,
clut = (clut_t*) img_overl->color;
trans = img_overl->trans;
o = trans[clr];
- if (x + rle_remainder < src_width) {
+ if (x + rle_remainder <= src_width) {
rle_this_bite = rle_remainder;
rle_remainder = rlelen = rle->len;
clr_next = rle->color;
@@ -416,7 +418,7 @@ void blend_rgb16 (uint8_t * img, vo_overlay_t * img_overl,
} else {
rle = rle_start; /* y-scaling, reuse the last rle encoded line */
}
- if (y > img_overl->clip_bottom) {
+ if (y >= img_overl->clip_bottom) {
zone_state = 5;
break;
}
@@ -514,10 +516,9 @@ void blend_rgb16 (uint8_t * img, vo_overlay_t * img_overl,
void blend_rgb24 (uint8_t * img, vo_overlay_t * img_overl,
int img_width, int img_height,
- int dst_width, int dst_height)
+ int dst_width, int dst_height,
+ alphablend_t *extra_data)
{
- clut_t* clut = (clut_t*) img_overl->clip_color;
- uint8_t *trans;
int src_width = img_overl->width;
int src_height = img_overl->height;
rle_elem_t *rle = img_overl->rle;
@@ -533,65 +534,106 @@ void blend_rgb24 (uint8_t * img, vo_overlay_t * img_overl,
img_pix = img + 3 * ( (img_overl->y * img_height / dst_height) * img_width
+ (img_overl->x * img_width / dst_width));
- trans = img_overl->clip_trans;
-
/* avoid wraping overlay if drawing to small image */
- if( (img_overl->x + img_overl->clip_right) < dst_width )
+ if( (img_overl->x + img_overl->clip_right) <= dst_width )
clip_right = img_overl->clip_right;
else
- clip_right = dst_width - 1 - img_overl->x;
+ clip_right = dst_width - img_overl->x;
/* avoid buffer overflow */
- if( (src_height + img_overl->y) >= dst_height )
- src_height = dst_height - 1 - img_overl->y;
+ if( (src_height + img_overl->y) > dst_height )
+ src_height = dst_height - img_overl->y;
for (dy = y = 0; y < src_height && rle < rle_limit; ) {
- int mask = !(img_overl->clip_top > y || img_overl->clip_bottom < y);
+ int mask = !(y < img_overl->clip_top || y >= img_overl->clip_bottom);
rle_elem_t *rle_start = rle;
+ int rlelen = 0;
+ uint8_t clr = 0;
+
for (x = x1_scaled = 0; x < src_width;) {
- uint8_t clr;
+ int rle_bite;
+ clut_t *colors;
+ uint8_t *trans;
uint16_t o;
- int rlelen;
- clr = rle->color;
- o = trans[clr];
- rlelen = rle->len;
-
- if (o && mask) {
- /* threat cases where clipping border is inside rle->len pixels */
- if ( img_overl->clip_left > x ) {
- if( img_overl->clip_left < x + rlelen ) {
- x1_scaled = SCALED_TO_INT( img_overl->clip_left * x_scale );
- rlelen -= img_overl->clip_left - x;
- x += img_overl->clip_left - x;
+ /* take next element from rle list everytime an element is finished */
+ if (rlelen <= 0) {
+ if (rle >= rle_limit)
+ break;
+
+ rlelen = rle->len;
+ clr = rle->color;
+ rle++;
+ }
+
+ if (!mask) {
+ /* above or below clipping area */
+
+ rle_bite = rlelen;
+ /* choose palette for surrounding area */
+ colors = (clut_t*)img_overl->color;
+ trans = img_overl->trans;
+ } else {
+ /* treat cases where clipping border is inside rle->len pixels */
+ if ( x < img_overl->clip_left ) {
+ /* starts left */
+ if( x + rlelen > img_overl->clip_left ) {
+ /* ends not left */
+
+ /* choose the largest "bite" up to palette change */
+ rle_bite = img_overl->clip_left - x;
+ /* choose palette for surrounding area */
+ colors = (clut_t*)img_overl->color;
+ trans = img_overl->trans;
} else {
- o = 0;
+ /* ends left */
+
+ rle_bite = rlelen;
+ /* choose palette for surrounding area */
+ colors = (clut_t*)img_overl->color;
+ trans = img_overl->trans;
}
- } else if( clip_right < x + rlelen ) {
- if( clip_right > x ) {
- x2_scaled = SCALED_TO_INT( clip_right * x_scale);
- mem_blend24(img_pix + x1_scaled*3, clut[clr].cb,
- clut[clr].cr, clut[clr].y,
- o, x2_scaled-x1_scaled);
- o = 0;
+ } else if( x + rlelen > clip_right ) {
+ /* ends right */
+ if( x < clip_right ) {
+ /* starts not right */
+
+ /* choose the largest "bite" up to palette change */
+ rle_bite = clip_right - x;
+ /* we're in the center area so choose clip palette */
+ colors = (clut_t*)img_overl->clip_color;
+ trans = img_overl->clip_trans;
} else {
- o = 0;
+ /* starts right */
+
+ rle_bite = rlelen;
+ /* choose palette for surrounding area */
+ colors = (clut_t*)img_overl->color;
+ trans = img_overl->trans;
}
- }
+ } else {
+ /* starts not left and ends not right */
+
+ rle_bite = rlelen;
+ /* we're in the center area so choose clip palette */
+ colors = (clut_t*)img_overl->clip_color;
+ trans = img_overl->clip_trans;
+ }
}
- x2_scaled = SCALED_TO_INT((x + rlelen) * x_scale);
- if (o && mask) {
- mem_blend24(img_pix + x1_scaled*3, clut[clr].cb,
- clut[clr].cr, clut[clr].y,
+ x2_scaled = SCALED_TO_INT((x + rle_bite) * x_scale);
+
+ o = trans[clr];
+ if (o) {
+ mem_blend24(img_pix + x1_scaled*3,
+ colors[clr].cb, colors[clr].cr, colors[clr].y,
o, x2_scaled-x1_scaled);
}
x1_scaled = x2_scaled;
- x += rlelen;
- rle++;
- if (rle >= rle_limit) break;
+ x += rle_bite;
+ rlelen -= rle_bite;
}
img_pix += img_width * 3;
@@ -612,10 +654,9 @@ void blend_rgb24 (uint8_t * img, vo_overlay_t * img_overl,
void blend_rgb32 (uint8_t * img, vo_overlay_t * img_overl,
int img_width, int img_height,
- int dst_width, int dst_height)
+ int dst_width, int dst_height,
+ alphablend_t *extra_data)
{
- clut_t* clut = (clut_t*) img_overl->clip_color;
- uint8_t *trans;
int src_width = img_overl->width;
int src_height = img_overl->height;
rle_elem_t *rle = img_overl->rle;
@@ -631,61 +672,104 @@ void blend_rgb32 (uint8_t * img, vo_overlay_t * img_overl,
img_pix = img + 4 * ( (img_overl->y * img_height / dst_height) * img_width
+ (img_overl->x * img_width / dst_width));
- trans = img_overl->clip_trans;
-
/* avoid wraping overlay if drawing to small image */
- if( (img_overl->x + img_overl->clip_right) < dst_width )
+ if( (img_overl->x + img_overl->clip_right) <= dst_width )
clip_right = img_overl->clip_right;
else
- clip_right = dst_width - 1 - img_overl->x;
+ clip_right = dst_width - img_overl->x;
/* avoid buffer overflow */
- if( (src_height + img_overl->y) >= dst_height )
- src_height = dst_height - 1 - img_overl->y;
+ if( (src_height + img_overl->y) > dst_height )
+ src_height = dst_height - img_overl->y;
for (y = dy = 0; y < src_height && rle < rle_limit; ) {
- int mask = !(img_overl->clip_top > y || img_overl->clip_bottom < y);
+ int mask = !(y < img_overl->clip_top || y >= img_overl->clip_bottom);
rle_elem_t *rle_start = rle;
+ int rlelen = 0;
+ uint8_t clr = 0;
+
for (x = x1_scaled = 0; x < src_width;) {
- uint8_t clr;
+ int rle_bite;
+ clut_t *colors;
+ uint8_t *trans;
uint16_t o;
- int rlelen;
+
+ /* take next element from rle list everytime an element is finished */
+ if (rlelen <= 0) {
+ if (rle >= rle_limit)
+ break;
+
+ rlelen = rle->len;
+ clr = rle->color;
+ rle++;
+ }
- clr = rle->color;
- o = trans[clr];
- rlelen = rle->len;
-
- if (o && mask) {
- /* threat cases where clipping border is inside rle->len pixels */
- if ( img_overl->clip_left > x ) {
- if( img_overl->clip_left < x + rlelen ) {
- x1_scaled = SCALED_TO_INT( img_overl->clip_left * x_scale );
- rlelen -= img_overl->clip_left - x;
- x += img_overl->clip_left - x;
+ if (!mask) {
+ /* above or below clipping area */
+
+ rle_bite = rlelen;
+ /* choose palette for surrounding area */
+ colors = (clut_t*)img_overl->color;
+ trans = img_overl->trans;
+ } else {
+ /* treat cases where clipping border is inside rle->len pixels */
+ if ( x < img_overl->clip_left ) {
+ /* starts left */
+ if( x + rlelen > img_overl->clip_left ) {
+ /* ends not left */
+
+ /* choose the largest "bite" up to palette change */
+ rle_bite = img_overl->clip_left - x;
+ /* choose palette for surrounding area */
+ colors = (clut_t*)img_overl->color;
+ trans = img_overl->trans;
} else {
- o = 0;
+ /* ends left */
+
+ rle_bite = rlelen;
+ /* choose palette for surrounding area */
+ colors = (clut_t*)img_overl->color;
+ trans = img_overl->trans;
}
- } else if( clip_right < x + rlelen ) {
- if( clip_right > x ) {
- x2_scaled = SCALED_TO_INT( clip_right * x_scale);
- mem_blend32(img_pix + x1_scaled*4, (uint8_t *)&clut[clr], o, x2_scaled-x1_scaled);
- o = 0;
+ } else if( x + rlelen > clip_right ) {
+ /* ends right */
+ if( x < clip_right ) {
+ /* starts not right */
+
+ /* choose the largest "bite" up to palette change */
+ rle_bite = clip_right - x;
+ /* we're in the center area so choose clip palette */
+ colors = (clut_t*)img_overl->clip_color;
+ trans = img_overl->clip_trans;
} else {
- o = 0;
+ /* starts right */
+
+ rle_bite = rlelen;
+ /* choose palette for surrounding area */
+ colors = (clut_t*)img_overl->color;
+ trans = img_overl->trans;
}
- }
+ } else {
+ /* starts not left and ends not right */
+
+ rle_bite = rlelen;
+ /* we're in the center area so choose clip palette */
+ colors = (clut_t*)img_overl->clip_color;
+ trans = img_overl->clip_trans;
+ }
}
+
+ x2_scaled = SCALED_TO_INT((x + rle_bite) * x_scale);
- x2_scaled = SCALED_TO_INT((x + rlelen) * x_scale);
- if (o && mask) {
- mem_blend32(img_pix + x1_scaled*4, (uint8_t *)&clut[clr], o, x2_scaled-x1_scaled);
+ o = trans[clr];
+ if (o) {
+ mem_blend32(img_pix + x1_scaled*4, (uint8_t *)&colors[clr], o, x2_scaled-x1_scaled);
}
x1_scaled = x2_scaled;
- x += rlelen;
- rle++;
- if (rle >= rle_limit) break;
+ x += rle_bite;
+ rlelen -= rle_bite;
}
img_pix += img_width * 4;
@@ -713,52 +797,38 @@ static void mem_blend8(uint8_t *mem, uint8_t val, uint8_t o, size_t sz)
}
}
-
-#define EXACT_BLENDING 1
-
-
-#ifdef EXACT_BLENDING
-
-#define BLEND_MAXWIDTH 2048
-uint8_t blend_yuv_data[ 3 ][ 2 ][ BLEND_MAXWIDTH ];
-uint8_t blend_yuv_data[ 3 ][ 2 ][ BLEND_MAXWIDTH ];
-uint8_t blend_yuv_data[ 3 ][ 2 ][ BLEND_MAXWIDTH ];
-
-void blend_yuv_exact(uint8_t *dst_cr, uint8_t *dst_cb, int src_width, int x_odd);
-void blend_yuv_exact(uint8_t *dst_cr, uint8_t *dst_cb, int src_width, int x_odd)
+static void blend_yuv_exact(uint8_t *dst_cr, uint8_t *dst_cb,
+ int src_width, int x_odd,
+ uint8_t *(*blend_yuv_data)[ 3 ][ 2 ])
{
int x;
for (x = 0; x < src_width; x += 2) {
/* get opacity of the 4 pixels that share chroma */
- int o00 = blend_yuv_data[ 0 ][ 0 ][ x + 0 ];
- int o01 = blend_yuv_data[ 0 ][ 0 ][ x + 1 ];
- int o10 = blend_yuv_data[ 0 ][ 1 ][ x + 0 ];
- int o11 = blend_yuv_data[ 0 ][ 1 ][ x + 1 ];
+ int o00 = (*blend_yuv_data)[ 0 ][ 0 ][ x + 0 ];
+ int o01 = (*blend_yuv_data)[ 0 ][ 0 ][ x + 1 ];
+ int o10 = (*blend_yuv_data)[ 0 ][ 1 ][ x + 0 ];
+ int o11 = (*blend_yuv_data)[ 0 ][ 1 ][ x + 1 ];
/* are there any pixels a little bit opaque? */
- if (o00 || o01 || o10 || o11)
- {
- /* get the chroma componets of the 4 pixels */
- int cr00 = -128 + blend_yuv_data[ 1 ][ 0 ][ x + 0 ];
- int cr01 = -128 + blend_yuv_data[ 1 ][ 0 ][ x + 1 ];
- int cr10 = -128 + blend_yuv_data[ 1 ][ 1 ][ x + 0 ];
- int cr11 = -128 + blend_yuv_data[ 1 ][ 1 ][ x + 1 ];
+ if (o00 || o01 || o10 || o11) {
+ /* get the chroma components of the 4 pixels */
+ int cr00 = -128 + (*blend_yuv_data)[ 1 ][ 0 ][ x + 0 ];
+ int cr01 = -128 + (*blend_yuv_data)[ 1 ][ 0 ][ x + 1 ];
+ int cr10 = -128 + (*blend_yuv_data)[ 1 ][ 1 ][ x + 0 ];
+ int cr11 = -128 + (*blend_yuv_data)[ 1 ][ 1 ][ x + 1 ];
- int cb00 = -128 + blend_yuv_data[ 2 ][ 0 ][ x + 0 ];
- int cb01 = -128 + blend_yuv_data[ 2 ][ 0 ][ x + 1 ];
- int cb10 = -128 + blend_yuv_data[ 2 ][ 1 ][ x + 0 ];
- int cb11 = -128 + blend_yuv_data[ 2 ][ 1 ][ x + 1 ];
+ int cb00 = -128 + (*blend_yuv_data)[ 2 ][ 0 ][ x + 0 ];
+ int cb01 = -128 + (*blend_yuv_data)[ 2 ][ 0 ][ x + 1 ];
+ int cb10 = -128 + (*blend_yuv_data)[ 2 ][ 1 ][ x + 0 ];
+ int cb11 = -128 + (*blend_yuv_data)[ 2 ][ 1 ][ x + 1 ];
/* are all pixels completely opaque? */
- if (o00 >= 0xf && o01 >= 0xf && o10 >= 0xf && o11 >= 0xf)
- {
+ if (o00 >= 0xf && o01 >= 0xf && o10 >= 0xf && o11 >= 0xf) {
/* set the output chroma to the average of the four pixels */
*dst_cr = 128 + (cr00 + cr01 + cr10 + cr11) / 4;
*dst_cb = 128 + (cb00 + cb01 + cb10 + cb11) / 4;
- }
- else
- {
+ } else {
int t4, cr, cb;
/* blending required, so clamp opacity values to allowed range */
@@ -786,11 +856,50 @@ void blend_yuv_exact(uint8_t *dst_cr, uint8_t *dst_cb, int src_width, int x_odd)
}
}
-#endif
+static uint8_t *(*blend_yuv_grow_extra_data(alphablend_t *extra_data, int osd_width))[ 3 ][ 2 ]
+{
+ struct __attribute__((packed)) header_s {
+ int id;
+ int max_width;
+ uint8_t *data[ 3 ][ 2 ];
+ } **header = (struct header_s **)&extra_data->buffer;
+
+ int needed_buffer_size = sizeof (**header) + sizeof (uint8_t[ 3 ][ 2 ][ osd_width ]);
+
+ if (extra_data->buffer_size < needed_buffer_size) {
+
+ free(extra_data->buffer);
+ extra_data->buffer = xine_xmalloc(needed_buffer_size);
+
+ if (!extra_data->buffer) {
+ extra_data->buffer_size = 0;
+ return 0;
+ }
+
+ extra_data->buffer_size = needed_buffer_size;
+ (*header)->max_width = 0;
+ }
+ if ((*header)->id != ME_FOURCC('y', 'u', 'v', 0) || (*header)->max_width < osd_width) {
+ (*header)->id = ME_FOURCC('y', 'u', 'v', 0);
+ (*header)->max_width = osd_width;
+
+ (*header)->data[ 0 ][ 0 ] = ((uint8_t *)extra_data->buffer) + sizeof (**header);
+ (*header)->data[ 0 ][ 1 ] = (*header)->data[ 0 ][ 0 ] + osd_width;
+ (*header)->data[ 1 ][ 0 ] = (*header)->data[ 0 ][ 1 ] + osd_width;
+ (*header)->data[ 1 ][ 1 ] = (*header)->data[ 1 ][ 0 ] + osd_width;
+ (*header)->data[ 2 ][ 0 ] = (*header)->data[ 1 ][ 1 ] + osd_width;
+ (*header)->data[ 2 ][ 1 ] = (*header)->data[ 2 ][ 0 ] + osd_width;
+ }
+
+ return &(*header)->data;
+}
+
void blend_yuv (uint8_t *dst_base[3], vo_overlay_t * img_overl,
- int dst_width, int dst_height, int dst_pitches[3])
+ int dst_width, int dst_height, int dst_pitches[3],
+ alphablend_t *extra_data)
{
+ int enable_exact_blending = !extra_data->disable_exact_blending;
clut_t *my_clut;
uint8_t *my_trans;
@@ -809,10 +918,11 @@ void blend_yuv (uint8_t *dst_base[3], vo_overlay_t * img_overl,
int x, y;
int clip_right;
uint8_t clr=0;
-#ifdef EXACT_BLENDING
- int anyLineBufferd = 0;
- int exactBlendWidth = ((src_width <= (dst_width - x_off)) ? src_width : (dst_width - x_off));
-#endif
+
+ int any_line_buffered = 0;
+ int exact_blend_width = ((src_width <= (dst_width - x_off)) ? src_width : (dst_width - x_off));
+ int exact_blend_width_m2 = (x_odd + exact_blend_width + 1) & ~1; /* make it a (larger) multiple of 2 */
+ uint8_t *(*blend_yuv_data)[ 3 ][ 2 ] = 0;
uint8_t *dst_y = dst_base[0] + dst_pitches[0] * y_off + x_off;
uint8_t *dst_cr = dst_base[2] + (y_off / 2) * dst_pitches[1] + (x_off / 2);
@@ -833,10 +943,21 @@ void blend_yuv (uint8_t *dst_base[3], vo_overlay_t * img_overl,
if( (src_height + y_off) > dst_height )
src_height = dst_height - y_off;
-#ifdef EXACT_BLENDING
- /* make linebuffer transparent */
- memset(&blend_yuv_data[ 0 ][ 0 ][ 0 ], 0, 2 * BLEND_MAXWIDTH);
-#endif
+ if (src_height <= 0)
+ return;
+
+ if (enable_exact_blending) {
+ if (exact_blend_width <= 0)
+ return;
+
+ blend_yuv_data = blend_yuv_grow_extra_data(extra_data, exact_blend_width_m2);
+ if (!blend_yuv_data)
+ return;
+
+ /* make linebuffer transparent */
+ memset(&(*blend_yuv_data)[ 0 ][ 0 ][ 0 ], 0, exact_blend_width_m2);
+ memset(&(*blend_yuv_data)[ 0 ][ 1 ][ 0 ], 0, exact_blend_width_m2);
+ }
rlelen=rle_remainder=0;
for (y = 0; y < src_height; y++) {
@@ -940,7 +1061,7 @@ void blend_yuv (uint8_t *dst_base[3], vo_overlay_t * img_overl,
xmask++;
}
} else if (x >= clip_right) {
- /* Starts outside clip area, ends outsite clip area */
+ /* Starts outside clip area, ends outside clip area */
if ((x + rle_remainder ) > src_width ) {
#ifdef LOG_BLEND_YUV
printf("Outside clip right %d, ending eol\n", clip_right);
@@ -981,49 +1102,47 @@ void blend_yuv (uint8_t *dst_base[3], vo_overlay_t * img_overl,
printf("Trans=%d clr=%d xmask=%d my_clut[clr]=%d\n",o, clr, xmask, my_clut[clr].y);
#endif
- if (x < (dst_width - x_off))
- {
+ if (x < (dst_width - x_off)) {
/* clip against right edge of destination area */
- if ((x + rle_this_bite) > (dst_width - x_off))
- {
+ if ((x + rle_this_bite) > (dst_width - x_off)) {
int toClip = (x + rle_this_bite) - (dst_width - x_off);
rle_this_bite -= toClip;
rle_remainder += toClip;
rlelen += toClip;
}
-
-#ifdef EXACT_BLENDING
- /* remember opacity of current line */
- memset(&blend_yuv_data[ 0 ][ (y + y_odd) & 1 ][ x + x_odd ], o, rle_this_bite);
- anyLineBufferd |= ((y + y_odd) & 1) ? 2 : 1;
-#endif
+
+ if (enable_exact_blending) {
+ /* remember opacity of current line */
+ memset(&(*blend_yuv_data)[ 0 ][ (y + y_odd) & 1 ][ x + x_odd ], o, rle_this_bite);
+ any_line_buffered |= ((y + y_odd) & 1) ? 2 : 1;
+ }
if (o) {
if(o >= 15) {
memset(dst_y + x, my_clut[clr].y, rle_this_bite);
-#ifndef EXACT_BLENDING
- if ((y + y_odd) & 1) {
- memset(dst_cr + ((x + x_odd) >> 1), my_clut[clr].cr, (rle_this_bite+1) >> 1);
- memset(dst_cb + ((x + x_odd) >> 1), my_clut[clr].cb, (rle_this_bite+1) >> 1);
+ if (!enable_exact_blending) {
+ if ((y + y_odd) & 1) {
+ memset(dst_cr + ((x + x_odd) >> 1), my_clut[clr].cr, (rle_this_bite+1) >> 1);
+ memset(dst_cb + ((x + x_odd) >> 1), my_clut[clr].cb, (rle_this_bite+1) >> 1);
+ }
}
-#endif
} else {
mem_blend8(dst_y + x, my_clut[clr].y, o, rle_this_bite);
-#ifndef EXACT_BLENDING
- if ((y + y_odd) & 1) {
- /* Blending cr and cb should use a different function, with pre -128 to each sample */
- mem_blend8(dst_cr + ((x + x_odd) >> 1), my_clut[clr].cr, o, (rle_this_bite+1) >> 1);
- mem_blend8(dst_cb + ((x + x_odd) >> 1), my_clut[clr].cb, o, (rle_this_bite+1) >> 1);
+ if (!enable_exact_blending) {
+ if ((y + y_odd) & 1) {
+ /* Blending cr and cb should use a different function, with pre -128 to each sample */
+ mem_blend8(dst_cr + ((x + x_odd) >> 1), my_clut[clr].cr, o, (rle_this_bite+1) >> 1);
+ mem_blend8(dst_cb + ((x + x_odd) >> 1), my_clut[clr].cb, o, (rle_this_bite+1) >> 1);
+ }
}
-#endif
}
-
-#ifdef EXACT_BLENDING
- /* remember chroma of current line */
- memset(&blend_yuv_data[ 1 ][ (y + y_odd) & 1 ][ x + x_odd ], my_clut[ clr ].cr, rle_this_bite);
- memset(&blend_yuv_data[ 2 ][ (y + y_odd) & 1 ][ x + x_odd ], my_clut[ clr ].cb, rle_this_bite);
-#endif
+
+ if (enable_exact_blending) {
+ /* remember chroma of current line */
+ memset(&(*blend_yuv_data)[ 1 ][ (y + y_odd) & 1 ][ x + x_odd ], my_clut[ clr ].cr, rle_this_bite);
+ memset(&(*blend_yuv_data)[ 2 ][ (y + y_odd) & 1 ][ x + x_odd ], my_clut[ clr ].cb, rle_this_bite);
+ }
}
}
#ifdef LOG_BLEND_YUV
@@ -1032,53 +1151,137 @@ void blend_yuv (uint8_t *dst_base[3], vo_overlay_t * img_overl,
x += rle_this_bite;
}
- dst_y += dst_pitches[0];
-
if ((y + y_odd) & 1) {
-
-#ifdef EXACT_BLENDING
- /* blend bufferd chroma */
- if (anyLineBufferd)
- {
- if (!(anyLineBufferd & 2))
- {
- /* make second line transparent */
- memset(&blend_yuv_data[ 0 ][ 1 ][ 0 ], 0, BLEND_MAXWIDTH);
+ if (enable_exact_blending) {
+ /* blend buffered lines */
+ if (any_line_buffered) {
+ if (!(any_line_buffered & 2)) {
+ /* make second line transparent */
+ memset(&(*blend_yuv_data)[ 0 ][ 1 ][ 0 ], 0, exact_blend_width_m2);
+ }
+
+ blend_yuv_exact(dst_cr, dst_cb, exact_blend_width, x_odd, blend_yuv_data);
+
+ any_line_buffered = 0;
}
-
- blend_yuv_exact(dst_cr, dst_cb, exactBlendWidth, x_odd);
-
- anyLineBufferd = 0;
}
-#endif
dst_cr += dst_pitches[2];
dst_cb += dst_pitches[1];
}
+
+ dst_y += dst_pitches[0];
}
-
-#ifdef EXACT_BLENDING
- /* blend bufferd chroma */
- if (anyLineBufferd)
- {
- if (!(anyLineBufferd & 2))
- {
- /* make second line transparent */
- memset(&blend_yuv_data[ 0 ][ 1 ][ 0 ], 0, BLEND_MAXWIDTH);
+
+ if (enable_exact_blending) {
+ /* blend buffered lines */
+ if (any_line_buffered) {
+ if (!(any_line_buffered & 2)) {
+ /* make second line transparent */
+ memset(&(*blend_yuv_data)[ 0 ][ 1 ][ 0 ], 0, exact_blend_width_m2);
+ }
+
+ blend_yuv_exact(dst_cr, dst_cb, exact_blend_width, x_odd, blend_yuv_data);
}
-
- blend_yuv_exact(dst_cr, dst_cb, exactBlendWidth, x_odd);
}
-#endif
#ifdef LOG_BLEND_YUV
printf("overlay_blend ended\n");
#endif
}
+static void blend_yuy2_exact(uint8_t *dst_cr, uint8_t *dst_cb,
+ int src_width, int x_odd,
+ uint8_t *(*blend_yuy2_data)[ 3 ])
+{
+ int x;
+
+ for (x = 0; x < src_width; x += 2) {
+ /* get opacity of the 2 pixels that share chroma */
+ int o0 = (*blend_yuy2_data)[ 0 ][ x + 0 ];
+ int o1 = (*blend_yuy2_data)[ 0 ][ x + 1 ];
+
+ /* are there any pixels a little bit opaque? */
+ if (o0 || o1) {
+ /* get the chroma components of the 2 pixels */
+ int cr0 = -128 + (*blend_yuy2_data)[ 1 ][ x + 0 ];
+ int cr1 = -128 + (*blend_yuy2_data)[ 1 ][ x + 1 ];
+
+ int cb0 = -128 + (*blend_yuy2_data)[ 2 ][ x + 0 ];
+ int cb1 = -128 + (*blend_yuy2_data)[ 2 ][ x + 1 ];
+
+ /* are all pixels completely opaque? */
+ if (o0 >= 0xf && o1 >= 0xf) {
+ /* set the output chroma to the average of the two pixels */
+ *dst_cr = 128 + (cr0 + cr1) / 2;
+ *dst_cb = 128 + (cb0 + cb1) / 2;
+ } else {
+ int t2, cr, cb;
+
+ /* blending required, so clamp opacity values to allowed range */
+ if (o0 > 0xf) o0 = 0xf;
+ if (o1 > 0xf) o1 = 0xf;
+
+ /* calculate transparency of background over the two pixels */
+ t2 = (0xf - o0) + (0xf - o1);
+
+ /* get background chroma */
+ cr = -128 + *dst_cr;
+ cb = -128 + *dst_cb;
+
+ /* blend the output chroma to the average of the two pixels */
+ *dst_cr = 128 + (cr * t2 + cr0 * o0 + cr1 * o1) / (2 * 0xf);
+ *dst_cb = 128 + (cb * t2 + cb0 * o0 + cb1 * o1) / (2 * 0xf);
+ }
+ }
+
+ /* next chroma sample */
+ dst_cr += 4;
+ dst_cb += 4;
+ }
+}
+
+static uint8_t *(*blend_yuy2_grow_extra_data(alphablend_t *extra_data, int osd_width))[ 3 ]
+{
+ struct __attribute__((packed)) header_s {
+ int id;
+ int max_width;
+ uint8_t *data[ 3 ];
+ } **header = (struct header_s **)&extra_data->buffer;
+
+ int needed_buffer_size = sizeof (**header) + sizeof (uint8_t[ 3 ][ osd_width ]);
+
+ if (extra_data->buffer_size < needed_buffer_size) {
+
+ free(extra_data->buffer);
+ extra_data->buffer = xine_xmalloc(needed_buffer_size);
+
+ if (!extra_data->buffer) {
+ extra_data->buffer_size = 0;
+ return 0;
+ }
+
+ extra_data->buffer_size = needed_buffer_size;
+ (*header)->max_width = 0;
+ }
+
+ if ((*header)->id != ME_FOURCC('y', 'u', 'y', '2') || (*header)->max_width < osd_width) {
+ (*header)->id = ME_FOURCC('y', 'u', 'y', '2');
+ (*header)->max_width = osd_width;
+
+ (*header)->data[ 0 ] = ((uint8_t *)extra_data->buffer) + sizeof (**header);
+ (*header)->data[ 1 ] = (*header)->data[ 0 ] + osd_width;
+ (*header)->data[ 2 ] = (*header)->data[ 1 ] + osd_width;
+ }
+
+ return &(*header)->data;
+}
+
void blend_yuy2 (uint8_t * dst_img, vo_overlay_t * img_overl,
- int dst_width, int dst_height, int dst_pitch)
+ int dst_width, int dst_height, int dst_pitch,
+ alphablend_t *extra_data)
{
+ int enable_exact_blending = !extra_data->disable_exact_blending;
clut_t *my_clut;
uint8_t *my_trans;
@@ -1088,20 +1291,27 @@ void blend_yuy2 (uint8_t * dst_img, vo_overlay_t * img_overl,
rle_elem_t *rle_limit = rle + img_overl->num_rle;
int x_off = img_overl->x;
int y_off = img_overl->y;
+ int x_odd = x_off & 1;
int ymask;
int rle_this_bite;
int rle_remainder;
int rlelen;
int x, y;
- int l;
+ int l = 0;
int clip_right;
+
union {
- uint32_t value;
- uint8_t b[4];
- uint16_t h[2];
+ uint32_t value;
+ uint8_t b[4];
+ uint16_t h[2];
} yuy2;
uint8_t clr = 0;
+
+ int any_line_buffered = 0;
+ int exact_blend_width = ((src_width <= (dst_width - x_off)) ? src_width : (dst_width - x_off));
+ int exact_blend_width_m2 = (x_odd + exact_blend_width + 1) & ~1; /* make it a (larger) multiple of 2 */
+ uint8_t *(*blend_yuy2_data)[ 3 ] = 0;
uint8_t *dst_y = dst_img + dst_pitch * y_off + 2 * x_off;
uint8_t *dst;
@@ -1110,23 +1320,44 @@ void blend_yuy2 (uint8_t * dst_img, vo_overlay_t * img_overl,
my_trans = img_overl->clip_trans;
/* avoid wraping overlay if drawing to small image */
- if( (x_off + img_overl->clip_right) < dst_width )
+ if( (x_off + img_overl->clip_right) <= dst_width )
clip_right = img_overl->clip_right;
else
- clip_right = dst_width - 1 - x_off;
+ clip_right = dst_width - x_off;
/* avoid buffer overflow */
- if( (src_height + y_off) >= dst_height )
- src_height = dst_height - 1 - y_off;
+ if( (src_height + y_off) > dst_height )
+ src_height = dst_height - y_off;
+
+ if (src_height <= 0)
+ return;
+
+ if (enable_exact_blending) {
+ if (exact_blend_width <= 0)
+ return;
+
+ blend_yuy2_data = blend_yuy2_grow_extra_data(extra_data, exact_blend_width_m2);
+ if (!blend_yuy2_data)
+ return;
+
+ /* make linebuffer transparent */
+ memset(&(*blend_yuy2_data)[ 0 ][ 0 ], 0, exact_blend_width_m2);
+ }
rlelen=rle_remainder=0;
for (y = 0; y < src_height; y++) {
- ymask = ((img_overl->clip_top > y) || (img_overl->clip_bottom < y));
+ if (rle >= rle_limit)
+ break;
+
+ ymask = ((y < img_overl->clip_top) || (y >= img_overl->clip_bottom));
dst = dst_y;
for (x = 0; x < src_width;) {
uint16_t o;
+ if (rle >= rle_limit)
+ break;
+
if ((rlelen < 0) || (rle_remainder < 0)) {
#ifdef LOG_BLEND_YUV
printf("alphablend: major bug in blend_yuv < 0\n");
@@ -1149,14 +1380,14 @@ void blend_yuy2 (uint8_t * dst_img, vo_overlay_t * img_overl,
#endif
if (ymask == 0) {
- if (x <= img_overl->clip_left) {
+ if (x < img_overl->clip_left) {
/* Starts outside clip area */
- if ((x + rle_remainder - 1) > img_overl->clip_left ) {
+ if ((x + rle_remainder) > img_overl->clip_left ) {
#ifdef LOG_BLEND_YUV
printf("Outside clip left %d, ending inside\n", img_overl->clip_left);
#endif
/* Cutting needed, starts outside, ends inside */
- rle_this_bite = (img_overl->clip_left - x + 1);
+ rle_this_bite = (img_overl->clip_left - x);
rle_remainder -= rle_this_bite;
rlelen -= rle_this_bite;
my_clut = (clut_t*) img_overl->color;
@@ -1231,48 +1462,99 @@ void blend_yuy2 (uint8_t * dst_img, vo_overlay_t * img_overl,
}
o = my_trans[clr];
- if (o) {
- l = rle_this_bite>>1;
- if( !((x_off+x) & 1) ) {
- yuy2.b[0] = my_clut[clr].y;
- yuy2.b[1] = my_clut[clr].cb;
- yuy2.b[2] = my_clut[clr].y;
- yuy2.b[3] = my_clut[clr].cr;
+ if (x < (dst_width - x_off)) {
+ /* clip against right edge of destination area */
+ if ((x + rle_this_bite) > (dst_width - x_off)) {
+ int toClip = (x + rle_this_bite) - (dst_width - x_off);
+
+ rle_this_bite -= toClip;
+ rle_remainder += toClip;
+ rlelen += toClip;
+ }
+
+ if (enable_exact_blending) {
+ /* remember opacity of current line */
+ memset(&(*blend_yuy2_data)[ 0 ][ x + x_odd ], o, rle_this_bite);
+ any_line_buffered = 1;
+ }
+
+ if (o) {
+ if (!enable_exact_blending) {
+ l = rle_this_bite>>1;
+ if( !((x_odd+x) & 1) ) {
+ yuy2.b[0] = my_clut[clr].y;
+ yuy2.b[1] = my_clut[clr].cb;
+ yuy2.b[2] = my_clut[clr].y;
+ yuy2.b[3] = my_clut[clr].cr;
+ } else {
+ yuy2.b[0] = my_clut[clr].y;
+ yuy2.b[1] = my_clut[clr].cr;
+ yuy2.b[2] = my_clut[clr].y;
+ yuy2.b[3] = my_clut[clr].cb;
+ }
+ }
+ if (o >= 15) {
+ if (!enable_exact_blending) {
+ while(l--) {
+ *(uint16_t *)dst = yuy2.h[0];
+ dst += 2;
+ *(uint16_t *)dst = yuy2.h[1];
+ dst += 2;
+ }
+ if(rle_this_bite & 1) {
+ *(uint16_t *)dst = yuy2.h[0];
+ dst += 2;
+ }
+ } else {
+ l = rle_this_bite;
+ while (l--) {
+ *dst = my_clut[clr].y;
+ dst += 2;
+ }
+ }
+ } else {
+ if (!enable_exact_blending) {
+ if( l ) {
+ mem_blend32(dst, &yuy2.b[0], o, l);
+ dst += 4*l;
+ }
+
+ if(rle_this_bite & 1) {
+ *dst = BLEND_BYTE(*dst, yuy2.b[0], o);
+ dst++;
+ *dst = BLEND_BYTE(*dst, yuy2.b[1], o);
+ dst++;
+ }
+ } else {
+ l = rle_this_bite;
+ while (l--) {
+ *dst = BLEND_BYTE(*dst, my_clut[clr].y, o);
+ dst += 2;
+ }
+ }
+ }
+
+ if (enable_exact_blending) {
+ /* remember chroma of current line */
+ memset(&(*blend_yuy2_data)[ 1 ][ x + x_odd ], my_clut[ clr ].cr, rle_this_bite);
+ memset(&(*blend_yuy2_data)[ 2 ][ x + x_odd ], my_clut[ clr ].cb, rle_this_bite);
+ }
} else {
- yuy2.b[0] = my_clut[clr].y;
- yuy2.b[1] = my_clut[clr].cr;
- yuy2.b[2] = my_clut[clr].y;
- yuy2.b[3] = my_clut[clr].cb;
+ dst += rle_this_bite*2;
}
-
- if (o >= 15) {
- while(l--) {
- *((uint16_t *)dst)++ = yuy2.h[0];
- *((uint16_t *)dst)++ = yuy2.h[1];
- }
- if(rle_this_bite & 1)
- *((uint16_t *)dst)++ = yuy2.h[0];
- } else {
- if( l ) {
- mem_blend32(dst, &yuy2.b[0], o, l);
- dst += 4*l;
- }
-
- if(rle_this_bite & 1) {
- *dst = BLEND_BYTE(*dst, yuy2.b[0], o);
- dst++;
- *dst = BLEND_BYTE(*dst, yuy2.b[1], o);
- dst++;
- }
- }
- } else {
- dst += rle_this_bite*2;
}
-
+
x += rle_this_bite;
- if (rle >= rle_limit) break;
}
- if (rle >= rle_limit) break;
+
+ if (enable_exact_blending) {
+ /* blend buffered line */
+ if (any_line_buffered) {
+ blend_yuy2_exact(dst_y - x_odd * 2 + 3, dst_y - x_odd * 2 + 1, exact_blend_width, x_odd, blend_yuy2_data);
+
+ any_line_buffered = 0;
+ }
+ }
dst_y += dst_pitch;
}
@@ -1368,6 +1650,7 @@ static void memblend_xx44(uint8_t *mem,uint8_t val, register size_t size, uint8_
void blend_xx44 (uint8_t *dst_img, vo_overlay_t *img_overl,
int dst_width, int dst_height, int dst_pitch,
+ alphablend_t *extra_data,
xx44_palette_t *palette,int ia44)
{
int src_width = img_overl->width;
@@ -1389,7 +1672,7 @@ void blend_xx44 (uint8_t *dst_img, vo_overlay_t *img_overl,
dst_y = dst_img + dst_pitch*y_off + x_off;
- if( (x_off + img_overl->width) < dst_width )
+ if( (x_off + img_overl->width) <= dst_width )
clip_right = img_overl->width;
else
clip_right = dst_width - x_off;
@@ -1399,11 +1682,11 @@ void blend_xx44 (uint8_t *dst_img, vo_overlay_t *img_overl,
for (y = 0; y < src_height; y++) {
- mask = !(img_overl->clip_top > y || img_overl->clip_bottom < y);
+ mask = !(y < img_overl->clip_top || y >= img_overl->clip_bottom);
dst = dst_y;
for (x = 0; x < src_width;) {
- int len = (x + rle->len > clip_right) ? clip_right -x + 1 : rle->len;
+ int len = (x + rle->len > clip_right) ? clip_right - x : rle->len;
if (len > 0) {
norm_pixel = (uint8_t)((xx44_paletteIndex(palette,rle->color,
@@ -1418,33 +1701,33 @@ void blend_xx44 (uint8_t *dst_img, vo_overlay_t *img_overl,
}
if (mask) {
if (x < img_overl->clip_left) {
- if (x + len - 1 < img_overl->clip_left) {
+ if (x + len <= img_overl->clip_left) {
memblend_xx44(dst,norm_pixel,len, alphamask);
dst += len;
} else {
memblend_xx44(dst,norm_pixel,img_overl->clip_left -x, alphamask);
dst += img_overl->clip_left - x;
len -= img_overl->clip_left - x;
- if (len < img_overl->clip_right - img_overl->clip_left + 1) {
+ if (len <= img_overl->clip_right - img_overl->clip_left) {
memblend_xx44(dst,clip_pixel,len, alphamask);
dst += len;
} else {
- memblend_xx44(dst,clip_pixel,img_overl->clip_right - img_overl->clip_left +1,
+ memblend_xx44(dst,clip_pixel,img_overl->clip_right - img_overl->clip_left,
alphamask);
- dst += img_overl->clip_right - img_overl->clip_left +1;
- len -= img_overl->clip_right - img_overl->clip_left +1;
+ dst += img_overl->clip_right - img_overl->clip_left;
+ len -= img_overl->clip_right - img_overl->clip_left;
memblend_xx44(dst,norm_pixel,len, alphamask);
dst += len;
}
}
- } else if (x <= img_overl->clip_right) {
- if (len < img_overl->clip_right - x + 1) {
+ } else if (x < img_overl->clip_right) {
+ if (len <= img_overl->clip_right - x) {
memblend_xx44(dst,clip_pixel,len, alphamask);
dst += len;
} else {
- memblend_xx44(dst,clip_pixel,img_overl->clip_right - x +1,alphamask);
- dst += img_overl->clip_right - x +1;
- len -= img_overl->clip_right - x +1;
+ memblend_xx44(dst,clip_pixel,img_overl->clip_right - x,alphamask);
+ dst += img_overl->clip_right - x;
+ len -= img_overl->clip_right - x;
memblend_xx44(dst,norm_pixel,len, alphamask);
dst += len;
}
@@ -1465,3 +1748,38 @@ void blend_xx44 (uint8_t *dst_img, vo_overlay_t *img_overl,
dst_y += dst_pitch;
}
}
+
+static void alphablend_disable_exact_osd_alpha_blending_changed(void *user_data, xine_cfg_entry_t *entry)
+{
+ alphablend_t *extra_data = (alphablend_t *)user_data;
+
+ extra_data->disable_exact_blending = entry->num_value;
+}
+
+void _x_alphablend_init(alphablend_t *extra_data, xine_t *xine)
+{
+ config_values_t *config = xine->config;
+
+ extra_data->buffer = 0;
+ extra_data->buffer_size = 0;
+
+ extra_data->disable_exact_blending =
+ config->register_bool(config, "video.disable_exact_osd_alpha_blending", 0,
+ _("disable exact alpha blending of overlays"),
+ _("If you experience a performance impact when an On Screen Display or other "
+ "overlays like DVD subtitles are active, then you might want to enable this option.\n"
+ "The result is that alpha blending of overlays is less accurate than before, "
+ "but the CPU usage will be decreased as well."),
+ 10, alphablend_disable_exact_osd_alpha_blending_changed, extra_data);
+}
+
+void _x_alphablend_free(alphablend_t *extra_data)
+{
+ if (extra_data->buffer) {
+ free(extra_data->buffer);
+ extra_data->buffer = NULL;
+ }
+
+ extra_data->buffer_size = 0;
+}
+