summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/video_out/alphablend.c228
-rw-r--r--src/xine-engine/osd.c106
2 files changed, 255 insertions, 79 deletions
diff --git a/src/video_out/alphablend.c b/src/video_out/alphablend.c
index a0541304b..be5f01617 100644
--- a/src/video_out/alphablend.c
+++ b/src/video_out/alphablend.c
@@ -713,6 +713,81 @@ 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)
+{
+ 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 ];
+
+ /* 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 ];
+
+ 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)
+ {
+ /* 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
+ {
+ int t4, cr, cb;
+
+ /* blending required, so clamp opacity values to allowed range */
+ if (o00 > 0xf) o00 = 0xf;
+ if (o01 > 0xf) o01 = 0xf;
+ if (o10 > 0xf) o10 = 0xf;
+ if (o11 > 0xf) o11 = 0xf;
+
+ /* calculate transparency of background over the four pixels */
+ t4 = (0xf - o00) + (0xf - o01) + (0xf - o10) + (0xf - o11);
+
+ /* get background chroma */
+ cr = -128 + *dst_cr;
+ cb = -128 + *dst_cb;
+
+ /* blend the output chroma to the average of the four pixels */
+ *dst_cr = 128 + (cr * t4 + cr00 * o00 + cr01 * o01 + cr10 * o10 + cr11 * o11) / (4 * 0xf);
+ *dst_cb = 128 + (cb * t4 + cb00 * o00 + cb01 * o01 + cb10 * o10 + cb11 * o11) / (4 * 0xf);
+ }
+ }
+
+ /* next chroma sample */
+ dst_cr++;
+ dst_cb++;
+ }
+}
+
+#endif
+
void blend_yuv (uint8_t *dst_base[3], vo_overlay_t * img_overl,
int dst_width, int dst_height, int dst_pitches[3])
{
@@ -725,6 +800,8 @@ void blend_yuv (uint8_t *dst_base[3], 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 y_odd = y_off & 1;
int ymask,xmask;
int rle_this_bite;
int rle_remainder;
@@ -732,10 +809,14 @@ 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
+
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) + 1;
- uint8_t *dst_cb = dst_base[1] + (y_off / 2) * dst_pitches[2] + (x_off / 2) + 1;
+ uint8_t *dst_cr = dst_base[2] + (y_off / 2) * dst_pitches[1] + (x_off / 2);
+ uint8_t *dst_cb = dst_base[1] + (y_off / 2) * dst_pitches[2] + (x_off / 2);
#ifdef LOG_BLEND_YUV
printf("overlay_blend started x=%d, y=%d, w=%d h=%d\n",img_overl->x,img_overl->y,img_overl->width,img_overl->height);
#endif
@@ -743,18 +824,30 @@ void blend_yuv (uint8_t *dst_base[3], 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;
+#ifdef EXACT_BLENDING
+ /* make linebuffer transparent */
+ memset(&blend_yuv_data[ 0 ][ 0 ][ 0 ], 0, 2 * BLEND_MAXWIDTH);
+#endif
+
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) {
+#ifdef LOG_BLEND_YUV
+ printf("y-rle_limit\n");
+#endif
+ break;
+ }
+
+ ymask = ((y < img_overl->clip_top) || (y >= img_overl->clip_bottom));
xmask = 0;
#ifdef LOG_BLEND_YUV
printf("X started ymask=%d y=%d src_height=%d\n",ymask, y, src_height);
@@ -762,6 +855,14 @@ void blend_yuv (uint8_t *dst_base[3], vo_overlay_t * img_overl,
for (x = 0; x < src_width;) {
uint16_t o;
+
+ if (rle >= rle_limit) {
+#ifdef LOG_BLEND_YUV
+ printf("x-rle_limit\n");
+#endif
+ break;
+ }
+
#ifdef LOG_BLEND_YUV
printf("1:rle_len=%d, remainder=%d, x=%d\n",rlelen, rle_remainder, x);
#endif
@@ -788,14 +889,14 @@ void blend_yuv (uint8_t *dst_base[3], 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;
@@ -879,48 +980,97 @@ void blend_yuv (uint8_t *dst_base[3], vo_overlay_t * img_overl,
#ifdef LOG_BLEND_YUV
printf("Trans=%d clr=%d xmask=%d my_clut[clr]=%d\n",o, clr, xmask, my_clut[clr].y);
#endif
- if (o) {
- if(o >= 15) {
- memset(dst_y + x, my_clut[clr].y, rle_this_bite);
- if (y & 1) {
- memset(dst_cr + (x >> 1), my_clut[clr].cr, (rle_this_bite+1) >> 1);
- memset(dst_cb + (x >> 1), my_clut[clr].cb, (rle_this_bite+1) >> 1);
- }
- } else {
- mem_blend8(dst_y + x, my_clut[clr].y, o, rle_this_bite);
- if (y & 1) {
- /* Blending cr and cb should use a different function, with pre -128 to each sample */
- mem_blend8(dst_cr + (x >> 1), my_clut[clr].cr, o, (rle_this_bite+1) >> 1);
- mem_blend8(dst_cb + (x >> 1), my_clut[clr].cb, o, (rle_this_bite+1) >> 1);
- }
- }
- }
-#ifdef LOG_BLEND_YUV
- printf("rle_this_bite=%d, remainder=%d, x=%d\n",rle_this_bite, rle_remainder, x);
+ 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;
+ }
+
+#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
- x += rle_this_bite;
- if (rle >= rle_limit) {
-#ifdef LOG_BLEND_YUV
- printf("x-rle_limit\n");
+
+ 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);
+ }
#endif
- break;
+ } 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);
+ }
+#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 (rle >= rle_limit) {
#ifdef LOG_BLEND_YUV
- printf("x-rle_limit\n");
+ printf("rle_this_bite=%d, remainder=%d, x=%d\n",rle_this_bite, rle_remainder, x);
#endif
- break;
+ x += rle_this_bite;
}
dst_y += dst_pitches[0];
- if (y & 1) {
+ 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);
+ }
+
+ blend_yuv_exact(dst_cr, dst_cb, exactBlendWidth, x_odd);
+
+ anyLineBufferd = 0;
+ }
+#endif
+
dst_cr += dst_pitches[2];
dst_cb += dst_pitches[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);
+ }
+
+ blend_yuv_exact(dst_cr, dst_cb, exactBlendWidth, x_odd);
+ }
+#endif
+
#ifdef LOG_BLEND_YUV
printf("overlay_blend ended\n");
#endif
diff --git a/src/xine-engine/osd.c b/src/xine-engine/osd.c
index a0488992f..6585a7bf2 100644
--- a/src/xine-engine/osd.c
+++ b/src/xine-engine/osd.c
@@ -165,6 +165,10 @@ static osd_object_t *osd_new_object (osd_renderer_t *this, int width, int height
/*
+#define DEBUG_RLE
+*/
+
+/*
* send the osd to be displayed at given pts (0=now)
* the object is not changed. there may be subsequent drawing on it.
*/
@@ -173,7 +177,7 @@ static int _osd_show (osd_object_t *osd, int64_t vpts, int unscaled ) {
osd_renderer_t *this = osd->renderer;
video_overlay_manager_t *ovl_manager;
rle_elem_t rle, *rle_p=0;
- int x, y, spare;
+ int x, y, required;
uint8_t *c;
lprintf("osd=%p vpts=%lld\n", osd, vpts);
@@ -190,69 +194,91 @@ static int _osd_show (osd_object_t *osd, int64_t vpts, int unscaled ) {
}
pthread_mutex_lock (&this->osd_mutex);
-
+
+ /* clip update area to allowed range */
+ if(osd->x1 > osd->width)
+ osd->x1 = osd->width;
+ if(osd->x2 > osd->width)
+ osd->x2 = osd->width;
+ if(osd->y1 > osd->height)
+ osd->y1 = osd->height;
+ if(osd->y2 > osd->height)
+ osd->y2 = osd->height;
+
+#ifdef DEBUG_RLE
+ lprintf("osd_show %p rle starts\n", osd);
+#endif
+
/* check if osd is valid (something drawn on it) */
- if( osd->x2 >= osd->x1 ) {
+ if( osd->x2 > osd->x1 && osd->y2 > osd->y1 ) {
this->event.object.handle = osd->handle;
- if(osd->x1 > osd->width)
- osd->x1 = osd->width;
- if(osd->x2 > osd->width)
- osd->x2 = osd->width;
- if(osd->y1 > osd->height)
- osd->y1 = osd->height;
- if(osd->y2 > osd->height)
- osd->y2 = osd->height;
-
memset( this->event.object.overlay, 0, sizeof(*this->event.object.overlay) );
this->event.object.overlay->unscaled = unscaled;
this->event.object.overlay->x = osd->display_x + osd->x1;
this->event.object.overlay->y = osd->display_y + osd->y1;
- this->event.object.overlay->width = osd->x2 - osd->x1 + 1;
- this->event.object.overlay->height = osd->y2 - osd->y1 + 1;
+ this->event.object.overlay->width = osd->x2 - osd->x1;
+ this->event.object.overlay->height = osd->y2 - osd->y1;
- this->event.object.overlay->clip_top = -1;
- this->event.object.overlay->clip_bottom = this->event.object.overlay->height +
- osd->display_y;
+ this->event.object.overlay->clip_top = 0;
+ this->event.object.overlay->clip_bottom = this->event.object.overlay->height;
this->event.object.overlay->clip_left = 0;
- this->event.object.overlay->clip_right = this->event.object.overlay->width +
- osd->display_x;
+ this->event.object.overlay->clip_right = this->event.object.overlay->width;
- spare = osd->y2 - osd->y1;
+ /* there will be at least that many rle objects (one for each row) */
+ required = osd->y2 - osd->y1;
this->event.object.overlay->num_rle = 0;
this->event.object.overlay->data_size = 1024;
+ while (required > this->event.object.overlay->data_size)
+ this->event.object.overlay->data_size += 1024;
rle_p = this->event.object.overlay->rle =
malloc(this->event.object.overlay->data_size * sizeof(rle_elem_t) );
- for( y = osd->y1; y <= osd->y2; y++ ) {
- rle.len = 0;
- rle.color = 0;
- c = osd->area + y * osd->width + osd->x1;
- for( x = osd->x1; x <= osd->x2; x++, c++ ) {
+ for( y = osd->y1; y < osd->y2; y++ ) {
+#ifdef DEBUG_RLE
+ lprintf("osd_show %p y = %d: ", osd, y);
+#endif
+ c = osd->area + y * osd->width + osd->x1;
+
+ /* initialize a rle object with the first pixel's color */
+ rle.len = 1;
+ rle.color = *c++;
+
+ /* loop over the remaining pixels in the row */
+ for( x = osd->x1 + rle.len; x < osd->x2; x++, c++ ) {
if( rle.color != *c ) {
- if( rle.len ) {
- if( (this->event.object.overlay->num_rle + spare) >
- this->event.object.overlay->data_size ) {
- this->event.object.overlay->data_size += 1024;
- rle_p = this->event.object.overlay->rle =
- realloc( this->event.object.overlay->rle,
- this->event.object.overlay->data_size * sizeof(rle_elem_t) );
- rle_p += this->event.object.overlay->num_rle;
- }
- *rle_p++ = rle;
- this->event.object.overlay->num_rle++;
+ if( (this->event.object.overlay->num_rle + required) >
+ this->event.object.overlay->data_size ) {
+ this->event.object.overlay->data_size += 1024;
+ rle_p = this->event.object.overlay->rle =
+ realloc( this->event.object.overlay->rle,
+ this->event.object.overlay->data_size * sizeof(rle_elem_t) );
+ rle_p += this->event.object.overlay->num_rle;
}
+#ifdef DEBUG_RLE
+ lprintf("(%d, %d), ", rle.len, rle.color);
+#endif
+ *rle_p++ = rle;
+ this->event.object.overlay->num_rle++;
+
rle.color = *c;
rle.len = 1;
} else {
rle.len++;
}
}
+#ifdef DEBUG_RLE
+ lprintf("(%d, %d)\n", rle.len, rle.color);
+#endif
*rle_p++ = rle;
- this->event.object.overlay->num_rle++;
+ this->event.object.overlay->num_rle++;
+ /* another row done */
+ required--;
}
-
+#ifdef DEBUG_RLE
+ lprintf("osd_show %p rle ends\n", osd);
+#endif
lprintf("num_rle = %d\n", this->event.object.overlay->num_rle);
memcpy(this->event.object.overlay->clip_color, osd->color, sizeof(osd->color));
@@ -1307,9 +1333,9 @@ static void osd_draw_bitmap(osd_object_t *osd, uint8_t *bitmap,
/* update clipping area */
osd->x1 = MIN( osd->x1, x1 );
- osd->x2 = MAX( osd->x2, x1+width-1 );
+ osd->x2 = MAX( osd->x2, x1+width );
osd->y1 = MIN( osd->y1, y1 );
- osd->y2 = MAX( osd->y2, y1+height-1 );
+ osd->y2 = MAX( osd->y2, y1+height );
for( y=0; y<height; y++ ) {
if ( palette_map ) {