summaryrefslogtreecommitdiff
path: root/noncore/multimedia/opieplayer2/alphablend.c
Unidiff
Diffstat (limited to 'noncore/multimedia/opieplayer2/alphablend.c') (more/less context) (ignore whitespace changes)
-rw-r--r--noncore/multimedia/opieplayer2/alphablend.c1567
1 files changed, 1298 insertions, 269 deletions
diff --git a/noncore/multimedia/opieplayer2/alphablend.c b/noncore/multimedia/opieplayer2/alphablend.c
index cdd7b28..ab80531 100644
--- a/noncore/multimedia/opieplayer2/alphablend.c
+++ b/noncore/multimedia/opieplayer2/alphablend.c
@@ -1,12 +1,9 @@
1//TOAST_SPU will define ALL spu entries - no matter the tranparency
2//#define TOAST_SPU
3/* #define PRIV_CLUT */
4/* Currently only blend_yuv(..) works */
5/* 1/*
6 * 2 *
7 * Copyright (C) James Courtier-Dutton James@superbug.demon.co.uk - July 2001 3 * Copyright (C) James Courtier-Dutton James@superbug.demon.co.uk - July 2001
8 * 4 *
9 * Copyright (C) 2000 Thomas Mirlacher 5 * Copyright (C) 2000 Thomas Mirlacher
6 * 2002-2004 the xine project
10 * 7 *
11 * This program is free software; you can redistribute it and/or modify 8 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by 9 * it under the terms of the GNU General Public License as published by
@@ -30,17 +27,17 @@
30 27
31/* 28/*
32#define LOG_BLEND_YUV 29#define LOG_BLEND_YUV
30#define LOG_BLEND_RGB16
33*/ 31*/
34 32
35#include <string.h> 33#include <string.h>
36#include <stdlib.h> 34#include <stdlib.h>
37#include <stdio.h> 35#include <stdio.h>
38#include <inttypes.h>
39 36
40#include <xine.h>
41#include <xine/xine_internal.h> 37#include <xine/xine_internal.h>
42#include <xine/video_out.h> 38#include <xine/video_out.h>
43#include "alphablend.h" 39#include "alphablend.h"
40#include "bswap.h"
44 41
45 42
46#define BLEND_COLOR(dst, src, mask, o) ((((src&mask)*o + ((dst&mask)*(0x0f-o)))/0xf) & mask) 43#define BLEND_COLOR(dst, src, mask, o) ((((src&mask)*o + ((dst&mask)*(0x0f-o)))/0xf) & mask)
@@ -59,7 +56,7 @@ static void mem_blend16(uint16_t *mem, uint16_t clr, uint8_t o, int len) {
59} 56}
60 57
61static void mem_blend24(uint8_t *mem, uint8_t r, uint8_t g, uint8_t b, 58static void mem_blend24(uint8_t *mem, uint8_t r, uint8_t g, uint8_t b,
62 uint8_t o, int len) { 59 uint8_t o, int len) {
63 uint8_t *limit = mem + len*3; 60 uint8_t *limit = mem + len*3;
64 while (mem < limit) { 61 while (mem < limit) {
65 *mem = BLEND_BYTE(*mem, r, o); 62 *mem = BLEND_BYTE(*mem, r, o);
@@ -71,19 +68,6 @@ static void mem_blend24(uint8_t *mem, uint8_t r, uint8_t g, uint8_t b,
71 } 68 }
72} 69}
73 70
74static void mem_blend24_32(uint8_t *mem, uint8_t r, uint8_t g, uint8_t b,
75 uint8_t o, int len) {
76 uint8_t *limit = mem + len*4;
77 while (mem < limit) {
78 *mem = BLEND_BYTE(*mem, r, o);
79 mem++;
80 *mem = BLEND_BYTE(*mem, g, o);
81 mem++;
82 *mem = BLEND_BYTE(*mem, b, o);
83 mem += 2;
84 }
85}
86
87static void mem_blend32(uint8_t *mem, uint8_t *src, uint8_t o, int len) { 71static void mem_blend32(uint8_t *mem, uint8_t *src, uint8_t o, int len) {
88 uint8_t *limit = mem + len*4; 72 uint8_t *limit = mem + len*4;
89 while (mem < limit) { 73 while (mem < limit) {
@@ -98,7 +82,6 @@ static void mem_blend32(uint8_t *mem, uint8_t *src, uint8_t o, int len) {
98 } 82 }
99} 83}
100 84
101
102/* 85/*
103 * Some macros for fixed point arithmetic. 86 * Some macros for fixed point arithmetic.
104 * 87 *
@@ -127,110 +110,414 @@ rle_img_advance_line(rle_elem_t *rle, rle_elem_t *rle_limit, int w)
127 return rle; 110 return rle;
128} 111}
129 112
130
131void blend_rgb16 (uint8_t * img, vo_overlay_t * img_overl, 113void blend_rgb16 (uint8_t * img, vo_overlay_t * img_overl,
132 int img_width, int img_height, 114 int img_width, int img_height,
133 int dst_width, int dst_height) 115 int dst_width, int dst_height,
116 alphablend_t *extra_data)
134{ 117{
135 uint8_t *trans; 118 uint8_t *trans;
136 clut_t* clut = (clut_t*) img_overl->clip_color; 119 clut_t *clut;
137 120
138 int src_width = img_overl->width; 121 int src_width = img_overl->width;
139 int src_height = img_overl->height; 122 int src_height = img_overl->height;
140 rle_elem_t *rle = img_overl->rle; 123 rle_elem_t *rle = img_overl->rle;
124 rle_elem_t *rle_start = img_overl->rle;
141 rle_elem_t *rle_limit = rle + img_overl->num_rle; 125 rle_elem_t *rle_limit = rle + img_overl->num_rle;
142 int x, y, x1_scaled, x2_scaled; 126 int x, y, x1_scaled, x2_scaled;
143 int dy, dy_step, x_scale;/* scaled 2**SCALE_SHIFT */ 127 int dy, dy_step, x_scale; /* scaled 2**SCALE_SHIFT */
144 int clip_right; 128 int clip_right;
145 uint16_t *img_pix; 129 uint16_t *img_pix;
130 int rlelen;
131 int rle_this_bite;
132 int rle_remainder;
133 int zone_state=0;
134 uint8_t clr_next,clr;
135 uint16_t o;
136 double img_offset;
137 int stripe_height;
138/*
139 * Let zone_state keep state.
140 * 0 = Starting.
141 * 1 = Above button.
142 * 2 = Left of button.
143 * 3 = Inside of button.
144 * 4 = Right of button.
145 * 5 = Below button.
146 * 6 = Finished.
147 *
148 * Each time round the loop, update the state.
149 * We can do this easily and cheaply(fewer IF statements per cycle) as we are testing rle end position anyway.
150 * Possible optimization is to ensure that rle never overlaps from outside to inside a button.
151 * Possible optimization is to pre-scale the RLE overlay, so that no scaling is needed here.
152 */
146 153
147 dy_step = INT_TO_SCALED(dst_height) / img_height; 154#ifdef LOG_BLEND_RGB16
148 x_scale = INT_TO_SCALED(img_width) / dst_width; 155 printf("blend_rgb16: img_height=%i, dst_height=%i\n", img_height, dst_height);
156 printf("blend_rgb16: img_width=%i, dst_width=%i\n", img_width, dst_width);
157 if (img_width & 1) { printf("blend_rgb16s: odd\n");}
158 else { printf("blend_rgb16s: even\n");}
149 159
150 img_pix = (uint16_t *) img 160#endif
161/* stripe_height is used in yuv2rgb scaling, so use the same scale factor here for overlays. */
162 stripe_height = 16 * img_height / dst_height;
163/* dy_step = INT_TO_SCALED(dst_height) / img_height; */
164 dy_step = INT_TO_SCALED(16) / stripe_height;
165 x_scale = INT_TO_SCALED(img_width) / dst_width;
166#ifdef LOG_BLEND_RGB16
167 printf("blend_rgb16: dy_step=%i, x_scale=%i\n", dy_step, x_scale);
168#endif
169 if (img_width & 1) img_width++;
170 img_offset = ( ( (img_overl->y * img_height) / dst_height) * img_width)
171 + ( (img_overl->x * img_width) / dst_width);
172#ifdef LOG_BLEND_RGB16
173 printf("blend_rgb16: x=%i, y=%i, w=%i, h=%i, img_offset=%lf\n", img_overl->x, img_overl->y,
174 img_overl->width,
175 img_overl->height,
176 img_offset);
177#endif
178 img_pix = (uint16_t *) img + (int)img_offset;
179/*
151 + (img_overl->y * img_height / dst_height) * img_width 180 + (img_overl->y * img_height / dst_height) * img_width
152 + (img_overl->x * img_width / dst_width); 181 + (img_overl->x * img_width / dst_width);
153 182*/
154 trans = img_overl->clip_trans;
155 183
156 /* avoid wraping overlay if drawing to small image */ 184 /* avoid wraping overlay if drawing to small image */
157 if( (img_overl->x + img_overl->clip_right) < dst_width ) 185 if( (img_overl->x + img_overl->clip_right) < dst_width )
158 clip_right = img_overl->clip_right; 186 clip_right = img_overl->clip_right;
159 else 187 else
160 clip_right = dst_width - 1 - img_overl->x; 188 clip_right = dst_width - img_overl->x;
161 189
162 /* avoid buffer overflow */ 190 /* avoid buffer overflow */
163 if( (src_height + img_overl->y) >= dst_height ) 191 if( (src_height + img_overl->y) >= dst_height )
164 src_height = dst_height - 1 - img_overl->y; 192 src_height = dst_height - img_overl->y;
165 193
166 for (y = dy = 0; y < src_height && rle < rle_limit;) { 194 rlelen = rle_remainder = rle_this_bite = 0;
167 int mask = !(img_overl->clip_top > y || img_overl->clip_bottom < y); 195 rle_remainder = rlelen = rle->len;
168 rle_elem_t *rle_start = rle; 196 clr_next = rle->color;
197 rle++;
198 y = dy = 0;
199 x = x1_scaled = x2_scaled = 0;
169 200
170 for (x = x1_scaled = 0; x < src_width;) { 201#ifdef LOG_BLEND_RGB16
171 uint8_t clr; 202 printf("blend_rgb16 started\n");
172 uint16_t o; 203#endif
173 int rlelen; 204
205 while (zone_state != 6) {
206 clr = clr_next;
207 switch (zone_state) {
208 case 0: /* Starting */
209 /* FIXME: Get libspudec to set clip_top to -1 if no button */
210 if (img_overl->clip_top < 0) {
211#ifdef LOG_BLEND_RGB16
212 printf("blend_rgb16: No button clip area\n");
213#endif
174 214
175 clr = rle->color; 215 zone_state = 7;
216 break;
217 }
218#ifdef LOG_BLEND_RGB16
219 printf("blend_rgb16: Button clip area found. (%d,%d) .. (%d,%d)\n",
220 img_overl->clip_left,
221 img_overl->clip_top,
222 img_overl->clip_right,
223 img_overl->clip_bottom);
224#endif
225 if (y < img_overl->clip_top) {
226 zone_state = 1;
227 break;
228 } else if (y >= img_overl->clip_bottom) {
229 zone_state = 5;
230 break;
231 } else if (x < img_overl->clip_left) {
232 zone_state = 2;
233 break;
234 } else if (x >= img_overl->clip_right) {
235 zone_state = 4;
236 break;
237 } else {
238 zone_state = 3;
239 break;
240 }
241 break;
242 case 1: /* Above clip area */
243 clut = (clut_t*) img_overl->color;
244 trans = img_overl->trans;
176 o = trans[clr]; 245 o = trans[clr];
177 rlelen = rle->len; 246 rle_this_bite = rle_remainder;
178 247 rle_remainder = 0;
179 if (o && mask) { 248 rlelen -= rle_this_bite;
180 /* threat cases where clipping border is inside rle->len pixels */ 249 /*printf("(x,y) = (%03i,%03i), clr=%03x, len=%03i, zone=%i\n", x, y, clr, rle_this_bite, zone_state); */
181 if ( img_overl->clip_left > x ) { 250 if (o) {
182 if( img_overl->clip_left < x + rlelen ) { 251 x1_scaled = SCALED_TO_INT( x * x_scale );
183 x1_scaled = SCALED_TO_INT( img_overl->clip_left * x_scale ); 252 x2_scaled = SCALED_TO_INT( (x + rle_this_bite) * x_scale);
184 rlelen -= img_overl->clip_left - x; 253 mem_blend16(img_pix+x1_scaled, *((uint16_t *)&clut[clr]), o, x2_scaled-x1_scaled);
185 x += img_overl->clip_left - x; 254 }
186 } else { 255 x += rle_this_bite;
187 o = 0; 256 if (x >= src_width ) {
257 x -= src_width;
258 img_pix += img_width;
259
260 dy += dy_step;
261 if (dy >= INT_TO_SCALED(1)) {
262 dy -= INT_TO_SCALED(1);
263 ++y;
264 while (dy >= INT_TO_SCALED(1)) {
265 rle = rle_img_advance_line(rle, rle_limit, src_width);
266 dy -= INT_TO_SCALED(1);
267 ++y;
188 } 268 }
189 } else if( clip_right < x + rlelen ) { 269 rle_start = rle;
190 if( clip_right > x ) { 270 } else {
191 x2_scaled = SCALED_TO_INT( clip_right * x_scale); 271 rle = rle_start; /* y-scaling, reuse the last rle encoded line */
192 mem_blend16(img_pix+x1_scaled, *((uint16_t *)&clut[clr]), o, 272 }
193 x2_scaled-x1_scaled); 273 }
194 o = 0; 274 rle_remainder = rlelen = rle->len;
195 } else { 275 clr_next = rle->color;
196 o = 0; 276 rle++;
277 if (rle >= rle_limit) {
278 zone_state = 6;
279 }
280 if (y >= img_overl->clip_top) {
281 zone_state = 2;
282#ifdef LOG_BLEND_RGB16
283 printf("blend_rgb16: Button clip top reached. y=%i, top=%i\n",
284 y, img_overl->clip_top);
285#endif
286 if (x >= img_overl->clip_left) {
287 zone_state = 3;
288 if (x >= img_overl->clip_right) {
289 zone_state = 4;
197 } 290 }
198 } 291 }
199 } 292 }
200 293 break;
201 x2_scaled = SCALED_TO_INT((x + rlelen) * x_scale); 294 case 2: /* Left of button */
202 if (o && mask) { 295 clut = (clut_t*) img_overl->color;
203 mem_blend16(img_pix+x1_scaled, *((uint16_t *)&clut[clr]), o, x2_scaled-x1_scaled); 296 trans = img_overl->trans;
297 o = trans[clr];
298 if (x + rle_remainder <= img_overl->clip_left) {
299 rle_this_bite = rle_remainder;
300 rle_remainder = rlelen = rle->len;
301 clr_next = rle->color;
302 rle++;
303 } else {
304 rle_this_bite = img_overl->clip_left - x;
305 rle_remainder -= rle_this_bite;
306 zone_state = 3;
204 } 307 }
205 308 if (o) {
206 x1_scaled = x2_scaled; 309 x1_scaled = SCALED_TO_INT( x * x_scale );
207 x += rlelen; 310 x2_scaled = SCALED_TO_INT( (x + rle_this_bite) * x_scale);
311 mem_blend16(img_pix+x1_scaled, *((uint16_t *)&clut[clr]), o, x2_scaled-x1_scaled);
312 }
313 x += rle_this_bite;
314 if (x >= src_width ) {
315 x -= src_width;
316 img_pix += img_width;
317 dy += dy_step;
318 if (dy >= INT_TO_SCALED(1)) {
319 dy -= INT_TO_SCALED(1);
320 ++y;
321 while (dy >= INT_TO_SCALED(1)) {
322 rle = rle_img_advance_line(rle, rle_limit, src_width);
323 dy -= INT_TO_SCALED(1);
324 ++y;
325 }
326 rle_start = rle;
327 } else {
328 rle = rle_start; /* y-scaling, reuse the last rle encoded line */
329 }
330 if (y >= img_overl->clip_bottom) {
331 zone_state = 5;
332 break;
333 }
334 }
335 if (rle >= rle_limit) {
336 zone_state = 6;
337 }
338 break;
339 case 3: /* In button */
340 clut = (clut_t*) img_overl->clip_color;
341 trans = img_overl->clip_trans;
342 o = trans[clr];
343 if (x + rle_remainder <= img_overl->clip_right) {
344 rle_this_bite = rle_remainder;
345 rle_remainder = rlelen = rle->len;
346 clr_next = rle->color;
347 rle++;
348 } else {
349 rle_this_bite = img_overl->clip_right - x;
350 rle_remainder -= rle_this_bite;
351 zone_state = 4;
352 }
353 if (o) {
354 x1_scaled = SCALED_TO_INT( x * x_scale );
355 x2_scaled = SCALED_TO_INT( (x + rle_this_bite) * x_scale);
356 mem_blend16(img_pix+x1_scaled, *((uint16_t *)&clut[clr]), o, x2_scaled-x1_scaled);
357 }
358 x += rle_this_bite;
359 if (x >= src_width ) {
360 x -= src_width;
361 img_pix += img_width;
362 dy += dy_step;
363 if (dy >= INT_TO_SCALED(1)) {
364 dy -= INT_TO_SCALED(1);
365 ++y;
366 while (dy >= INT_TO_SCALED(1)) {
367 rle = rle_img_advance_line(rle, rle_limit, src_width);
368 dy -= INT_TO_SCALED(1);
369 ++y;
370 }
371 rle_start = rle;
372 } else {
373 rle = rle_start; /* y-scaling, reuse the last rle encoded line */
374 }
375 if (y >= img_overl->clip_bottom) {
376 zone_state = 5;
377 break;
378 }
379 }
380 if (rle >= rle_limit) {
381 zone_state = 6;
382 }
383 break;
384 case 4: /* Right of button */
385 clut = (clut_t*) img_overl->color;
386 trans = img_overl->trans;
387 o = trans[clr];
388 if (x + rle_remainder <= src_width) {
389 rle_this_bite = rle_remainder;
390 rle_remainder = rlelen = rle->len;
391 clr_next = rle->color;
392 rle++;
393 } else {
394 rle_this_bite = src_width - x;
395 rle_remainder -= rle_this_bite;
396 zone_state = 2;
397 }
398 if (o) {
399 x1_scaled = SCALED_TO_INT( x * x_scale );
400 x2_scaled = SCALED_TO_INT( (x + rle_this_bite) * x_scale);
401 mem_blend16(img_pix+x1_scaled, *((uint16_t *)&clut[clr]), o, x2_scaled-x1_scaled);
402 }
403 x += rle_this_bite;
404 if (x >= src_width ) {
405 x -= src_width;
406 img_pix += img_width;
407 dy += dy_step;
408 if (dy >= INT_TO_SCALED(1)) {
409 dy -= INT_TO_SCALED(1);
410 ++y;
411 while (dy >= INT_TO_SCALED(1)) {
412 rle = rle_img_advance_line(rle, rle_limit, src_width);
413 dy -= INT_TO_SCALED(1);
414 ++y;
415 }
416 rle_start = rle;
417 } else {
418 rle = rle_start; /* y-scaling, reuse the last rle encoded line */
419 }
420 if (y >= img_overl->clip_bottom) {
421 zone_state = 5;
422 break;
423 }
424 }
425 if (rle >= rle_limit) {
426 zone_state = 6;
427 }
428 break;
429 case 5: /* Below button */
430 clut = (clut_t*) img_overl->color;
431 trans = img_overl->trans;
432 o = trans[clr];
433 rle_this_bite = rle_remainder;
434 rle_remainder = 0;
435 rlelen -= rle_this_bite;
436 if (o) {
437 x1_scaled = SCALED_TO_INT( x * x_scale );
438 x2_scaled = SCALED_TO_INT( (x + rle_this_bite) * x_scale);
439 mem_blend16(img_pix+x1_scaled, *((uint16_t *)&clut[clr]), o, x2_scaled-x1_scaled);
440 }
441 x += rle_this_bite;
442 if (x >= src_width ) {
443 x -= src_width;
444 img_pix += img_width;
445 dy += dy_step;
446 if (dy >= INT_TO_SCALED(1)) {
447 dy -= INT_TO_SCALED(1);
448 ++y;
449 while (dy >= INT_TO_SCALED(1)) {
450 rle = rle_img_advance_line(rle, rle_limit, src_width);
451 dy -= INT_TO_SCALED(1);
452 ++y;
453 }
454 rle_start = rle;
455 } else {
456 rle = rle_start; /* y-scaling, reuse the last rle encoded line */
457 }
458 }
459 rle_remainder = rlelen = rle->len;
460 clr_next = rle->color;
208 rle++; 461 rle++;
209 if (rle >= rle_limit) break; 462 if (rle >= rle_limit) {
210 } 463 zone_state = 6;
464 }
465 break;
466 case 6: /* Finished */
467 _x_abort();
211 468
212 img_pix += img_width; 469 case 7: /* No button */
213 dy += dy_step; 470 clut = (clut_t*) img_overl->color;
214 if (dy >= INT_TO_SCALED(1)) { 471 trans = img_overl->trans;
215 dy -= INT_TO_SCALED(1); 472 o = trans[clr];
216 ++y; 473 rle_this_bite = rle_remainder;
217 while (dy >= INT_TO_SCALED(1)) { 474 rle_remainder = 0;
218 rle = rle_img_advance_line(rle, rle_limit, src_width); 475 rlelen -= rle_this_bite;
219 dy -= INT_TO_SCALED(1); 476 if (o) {
220 ++y; 477 x1_scaled = SCALED_TO_INT( x * x_scale );
478 x2_scaled = SCALED_TO_INT( (x + rle_this_bite) * x_scale);
479 mem_blend16(img_pix+x1_scaled, *((uint16_t *)&clut[clr]), o, x2_scaled-x1_scaled);
221 } 480 }
222 } else { 481 x += rle_this_bite;
223 rle = rle_start; /* y-scaling, reuse the last rle encoded line */ 482 if (x >= src_width ) {
483 x -= src_width;
484 img_pix += img_width;
485 dy += dy_step;
486 if (dy >= INT_TO_SCALED(1)) {
487 dy -= INT_TO_SCALED(1);
488 ++y;
489 while (dy >= INT_TO_SCALED(1)) {
490 rle = rle_img_advance_line(rle, rle_limit, src_width);
491 dy -= INT_TO_SCALED(1);
492 ++y;
493 }
494 rle_start = rle;
495 } else {
496 rle = rle_start; /* y-scaling, reuse the last rle encoded line */
497 }
498 }
499 rle_remainder = rlelen = rle->len;
500 clr_next = rle->color;
501 rle++;
502 if (rle >= rle_limit) {
503 zone_state = 6;
504 }
505 break;
506 default:
507 ;
224 } 508 }
225 } 509 }
510#ifdef LOG_BLEND_RGB16
511 printf("blend_rgb16 ended\n");
512#endif
513
226} 514}
227 515
228void blend_rgb24 (uint8_t * img, vo_overlay_t * img_overl, 516void blend_rgb24 (uint8_t * img, vo_overlay_t * img_overl,
229 int img_width, int img_height, 517 int img_width, int img_height,
230 int dst_width, int dst_height) 518 int dst_width, int dst_height,
519 alphablend_t *extra_data)
231{ 520{
232 clut_t* clut = (clut_t*) img_overl->clip_color;
233 uint8_t *trans;
234 int src_width = img_overl->width; 521 int src_width = img_overl->width;
235 int src_height = img_overl->height; 522 int src_height = img_overl->height;
236 rle_elem_t *rle = img_overl->rle; 523 rle_elem_t *rle = img_overl->rle;
@@ -246,65 +533,106 @@ void blend_rgb24 (uint8_t * img, vo_overlay_t * img_overl,
246 img_pix = img + 3 * ( (img_overl->y * img_height / dst_height) * img_width 533 img_pix = img + 3 * ( (img_overl->y * img_height / dst_height) * img_width
247 + (img_overl->x * img_width / dst_width)); 534 + (img_overl->x * img_width / dst_width));
248 535
249 trans = img_overl->clip_trans;
250
251 /* avoid wraping overlay if drawing to small image */ 536 /* avoid wraping overlay if drawing to small image */
252 if( (img_overl->x + img_overl->clip_right) < dst_width ) 537 if( (img_overl->x + img_overl->clip_right) <= dst_width )
253 clip_right = img_overl->clip_right; 538 clip_right = img_overl->clip_right;
254 else 539 else
255 clip_right = dst_width - 1 - img_overl->x; 540 clip_right = dst_width - img_overl->x;
256 541
257 /* avoid buffer overflow */ 542 /* avoid buffer overflow */
258 if( (src_height + img_overl->y) >= dst_height ) 543 if( (src_height + img_overl->y) > dst_height )
259 src_height = dst_height - 1 - img_overl->y; 544 src_height = dst_height - img_overl->y;
260 545
261 for (dy = y = 0; y < src_height && rle < rle_limit; ) { 546 for (dy = y = 0; y < src_height && rle < rle_limit; ) {
262 int mask = !(img_overl->clip_top > y || img_overl->clip_bottom < y); 547 int mask = !(y < img_overl->clip_top || y >= img_overl->clip_bottom);
263 rle_elem_t *rle_start = rle; 548 rle_elem_t *rle_start = rle;
264 549
550 int rlelen = 0;
551 uint8_t clr = 0;
552
265 for (x = x1_scaled = 0; x < src_width;) { 553 for (x = x1_scaled = 0; x < src_width;) {
266 uint8_t clr; 554 int rle_bite;
555 clut_t *colors;
556 uint8_t *trans;
267 uint16_t o; 557 uint16_t o;
268 int rlelen;
269 558
270 clr = rle->color; 559 /* take next element from rle list everytime an element is finished */
271 o = trans[clr]; 560 if (rlelen <= 0) {
272 rlelen = rle->len; 561 if (rle >= rle_limit)
273 562 break;
274 if (o && mask) { 563
275 /* threat cases where clipping border is inside rle->len pixels */ 564 rlelen = rle->len;
276 if ( img_overl->clip_left > x ) { 565 clr = rle->color;
277 if( img_overl->clip_left < x + rlelen ) { 566 rle++;
278 x1_scaled = SCALED_TO_INT( img_overl->clip_left * x_scale ); 567 }
279 rlelen -= img_overl->clip_left - x; 568
280 x += img_overl->clip_left - x; 569 if (!mask) {
570 /* above or below clipping area */
571
572 rle_bite = rlelen;
573 /* choose palette for surrounding area */
574 colors = (clut_t*)img_overl->color;
575 trans = img_overl->trans;
576 } else {
577 /* treat cases where clipping border is inside rle->len pixels */
578 if ( x < img_overl->clip_left ) {
579 /* starts left */
580 if( x + rlelen > img_overl->clip_left ) {
581 /* ends not left */
582
583 /* choose the largest "bite" up to palette change */
584 rle_bite = img_overl->clip_left - x;
585 /* choose palette for surrounding area */
586 colors = (clut_t*)img_overl->color;
587 trans = img_overl->trans;
281 } else { 588 } else {
282 o = 0; 589 /* ends left */
590
591 rle_bite = rlelen;
592 /* choose palette for surrounding area */
593 colors = (clut_t*)img_overl->color;
594 trans = img_overl->trans;
283 } 595 }
284 } else if( clip_right < x + rlelen ) { 596 } else if( x + rlelen > clip_right ) {
285 if( clip_right > x ) { 597 /* ends right */
286 x2_scaled = SCALED_TO_INT( clip_right * x_scale); 598 if( x < clip_right ) {
287 mem_blend24(img_pix + x1_scaled*3, clut[clr].cb, 599 /* starts not right */
288 clut[clr].cr, clut[clr].y, 600
289 o, x2_scaled-x1_scaled); 601 /* choose the largest "bite" up to palette change */
290 o = 0; 602 rle_bite = clip_right - x;
603 /* we're in the center area so choose clip palette */
604 colors = (clut_t*)img_overl->clip_color;
605 trans = img_overl->clip_trans;
291 } else { 606 } else {
292 o = 0; 607 /* starts right */
608
609 rle_bite = rlelen;
610 /* choose palette for surrounding area */
611 colors = (clut_t*)img_overl->color;
612 trans = img_overl->trans;
293 } 613 }
294 } 614 } else {
615 /* starts not left and ends not right */
616
617 rle_bite = rlelen;
618 /* we're in the center area so choose clip palette */
619 colors = (clut_t*)img_overl->clip_color;
620 trans = img_overl->clip_trans;
621 }
295 } 622 }
296 623
297 x2_scaled = SCALED_TO_INT((x + rlelen) * x_scale); 624 x2_scaled = SCALED_TO_INT((x + rle_bite) * x_scale);
298 if (o && mask) { 625
299 mem_blend24(img_pix + x1_scaled*3, clut[clr].cb, 626 o = trans[clr];
300 clut[clr].cr, clut[clr].y, 627 if (o) {
628 mem_blend24(img_pix + x1_scaled*3,
629 colors[clr].cb, colors[clr].cr, colors[clr].y,
301 o, x2_scaled-x1_scaled); 630 o, x2_scaled-x1_scaled);
302 } 631 }
303 632
304 x1_scaled = x2_scaled; 633 x1_scaled = x2_scaled;
305 x += rlelen; 634 x += rle_bite;
306 rle++; 635 rlelen -= rle_bite;
307 if (rle >= rle_limit) break;
308 } 636 }
309 637
310 img_pix += img_width * 3; 638 img_pix += img_width * 3;
@@ -325,10 +653,9 @@ void blend_rgb24 (uint8_t * img, vo_overlay_t * img_overl,
325 653
326void blend_rgb32 (uint8_t * img, vo_overlay_t * img_overl, 654void blend_rgb32 (uint8_t * img, vo_overlay_t * img_overl,
327 int img_width, int img_height, 655 int img_width, int img_height,
328 int dst_width, int dst_height) 656 int dst_width, int dst_height,
657 alphablend_t *extra_data)
329{ 658{
330 clut_t* clut = (clut_t*) img_overl->clip_color;
331 uint8_t *trans;
332 int src_width = img_overl->width; 659 int src_width = img_overl->width;
333 int src_height = img_overl->height; 660 int src_height = img_overl->height;
334 rle_elem_t *rle = img_overl->rle; 661 rle_elem_t *rle = img_overl->rle;
@@ -344,65 +671,104 @@ void blend_rgb32 (uint8_t * img, vo_overlay_t * img_overl,
344 img_pix = img + 4 * ( (img_overl->y * img_height / dst_height) * img_width 671 img_pix = img + 4 * ( (img_overl->y * img_height / dst_height) * img_width
345 + (img_overl->x * img_width / dst_width)); 672 + (img_overl->x * img_width / dst_width));
346 673
347 trans = img_overl->clip_trans;
348
349 /* avoid wraping overlay if drawing to small image */ 674 /* avoid wraping overlay if drawing to small image */
350 if( (img_overl->x + img_overl->clip_right) < dst_width ) 675 if( (img_overl->x + img_overl->clip_right) <= dst_width )
351 clip_right = img_overl->clip_right; 676 clip_right = img_overl->clip_right;
352 else 677 else
353 clip_right = dst_width - 1 - img_overl->x; 678 clip_right = dst_width - img_overl->x;
354 679
355 /* avoid buffer overflow */ 680 /* avoid buffer overflow */
356 if( (src_height + img_overl->y) >= dst_height ) 681 if( (src_height + img_overl->y) > dst_height )
357 src_height = dst_height - 1 - img_overl->y; 682 src_height = dst_height - img_overl->y;
358 683
359 for (y = dy = 0; y < src_height && rle < rle_limit; ) { 684 for (y = dy = 0; y < src_height && rle < rle_limit; ) {
360 int mask = !(img_overl->clip_top > y || img_overl->clip_bottom < y); 685 int mask = !(y < img_overl->clip_top || y >= img_overl->clip_bottom);
361 rle_elem_t *rle_start = rle; 686 rle_elem_t *rle_start = rle;
362 687
688 int rlelen = 0;
689 uint8_t clr = 0;
690
363 for (x = x1_scaled = 0; x < src_width;) { 691 for (x = x1_scaled = 0; x < src_width;) {
364 uint8_t clr; 692 int rle_bite;
693 clut_t *colors;
694 uint8_t *trans;
365 uint16_t o; 695 uint16_t o;
366 int rlelen; 696
697 /* take next element from rle list everytime an element is finished */
698 if (rlelen <= 0) {
699 if (rle >= rle_limit)
700 break;
701
702 rlelen = rle->len;
703 clr = rle->color;
704 rle++;
705 }
367 706
368 clr = rle->color; 707 if (!mask) {
369 o = trans[clr]; 708 /* above or below clipping area */
370 rlelen = rle->len; 709
371 710 rle_bite = rlelen;
372 if (o && mask) { 711 /* choose palette for surrounding area */
373 /* threat cases where clipping border is inside rle->len pixels */ 712 colors = (clut_t*)img_overl->color;
374 if ( img_overl->clip_left > x ) { 713 trans = img_overl->trans;
375 if( img_overl->clip_left < x + rlelen ) { 714 } else {
376 x1_scaled = SCALED_TO_INT( img_overl->clip_left * x_scale ); 715 /* treat cases where clipping border is inside rle->len pixels */
377 rlelen -= img_overl->clip_left - x; 716 if ( x < img_overl->clip_left ) {
378 x += img_overl->clip_left - x; 717 /* starts left */
718 if( x + rlelen > img_overl->clip_left ) {
719 /* ends not left */
720
721 /* choose the largest "bite" up to palette change */
722 rle_bite = img_overl->clip_left - x;
723 /* choose palette for surrounding area */
724 colors = (clut_t*)img_overl->color;
725 trans = img_overl->trans;
379 } else { 726 } else {
380 o = 0; 727 /* ends left */
728
729 rle_bite = rlelen;
730 /* choose palette for surrounding area */
731 colors = (clut_t*)img_overl->color;
732 trans = img_overl->trans;
381 } 733 }
382 } else if( clip_right < x + rlelen ) { 734 } else if( x + rlelen > clip_right ) {
383 if( clip_right > x ) { 735 /* ends right */
384 x2_scaled = SCALED_TO_INT( clip_right * x_scale); 736 if( x < clip_right ) {
385 mem_blend24_32(img_pix + x1_scaled*4, clut[clr].cb, 737 /* starts not right */
386 clut[clr].cr, clut[clr].y, 738
387 o, x2_scaled-x1_scaled); 739 /* choose the largest "bite" up to palette change */
388 o = 0; 740 rle_bite = clip_right - x;
741 /* we're in the center area so choose clip palette */
742 colors = (clut_t*)img_overl->clip_color;
743 trans = img_overl->clip_trans;
389 } else { 744 } else {
390 o = 0; 745 /* starts right */
746
747 rle_bite = rlelen;
748 /* choose palette for surrounding area */
749 colors = (clut_t*)img_overl->color;
750 trans = img_overl->trans;
391 } 751 }
392 } 752 } else {
753 /* starts not left and ends not right */
754
755 rle_bite = rlelen;
756 /* we're in the center area so choose clip palette */
757 colors = (clut_t*)img_overl->clip_color;
758 trans = img_overl->clip_trans;
759 }
393 } 760 }
761
762 x2_scaled = SCALED_TO_INT((x + rle_bite) * x_scale);
394 763
395 x2_scaled = SCALED_TO_INT((x + rlelen) * x_scale); 764 o = trans[clr];
396 if (o && mask) { 765 if (o) {
397 mem_blend24_32(img_pix + x1_scaled*4, clut[clr].cb, 766 mem_blend32(img_pix + x1_scaled*4, (uint8_t *)&colors[clr], o, x2_scaled-x1_scaled);
398 clut[clr].cr, clut[clr].y,
399 o, x2_scaled-x1_scaled);
400 } 767 }
401 768
402 x1_scaled = x2_scaled; 769 x1_scaled = x2_scaled;
403 x += rlelen; 770 x += rle_bite;
404 rle++; 771 rlelen -= rle_bite;
405 if (rle >= rle_limit) break;
406 } 772 }
407 773
408 img_pix += img_width * 4; 774 img_pix += img_width * 4;
@@ -430,9 +796,109 @@ static void mem_blend8(uint8_t *mem, uint8_t val, uint8_t o, size_t sz)
430 } 796 }
431} 797}
432 798
799static void blend_yuv_exact(uint8_t *dst_cr, uint8_t *dst_cb,
800 int src_width, int x_odd,
801 uint8_t *(*blend_yuv_data)[ 3 ][ 2 ])
802{
803 int x;
804
805 for (x = 0; x < src_width; x += 2) {
806 /* get opacity of the 4 pixels that share chroma */
807 int o00 = (*blend_yuv_data)[ 0 ][ 0 ][ x + 0 ];
808 int o01 = (*blend_yuv_data)[ 0 ][ 0 ][ x + 1 ];
809 int o10 = (*blend_yuv_data)[ 0 ][ 1 ][ x + 0 ];
810 int o11 = (*blend_yuv_data)[ 0 ][ 1 ][ x + 1 ];
811
812 /* are there any pixels a little bit opaque? */
813 if (o00 || o01 || o10 || o11) {
814 /* get the chroma components of the 4 pixels */
815 int cr00 = -128 + (*blend_yuv_data)[ 1 ][ 0 ][ x + 0 ];
816 int cr01 = -128 + (*blend_yuv_data)[ 1 ][ 0 ][ x + 1 ];
817 int cr10 = -128 + (*blend_yuv_data)[ 1 ][ 1 ][ x + 0 ];
818 int cr11 = -128 + (*blend_yuv_data)[ 1 ][ 1 ][ x + 1 ];
819
820 int cb00 = -128 + (*blend_yuv_data)[ 2 ][ 0 ][ x + 0 ];
821 int cb01 = -128 + (*blend_yuv_data)[ 2 ][ 0 ][ x + 1 ];
822 int cb10 = -128 + (*blend_yuv_data)[ 2 ][ 1 ][ x + 0 ];
823 int cb11 = -128 + (*blend_yuv_data)[ 2 ][ 1 ][ x + 1 ];
824
825 /* are all pixels completely opaque? */
826 if (o00 >= 0xf && o01 >= 0xf && o10 >= 0xf && o11 >= 0xf) {
827 /* set the output chroma to the average of the four pixels */
828 *dst_cr = 128 + (cr00 + cr01 + cr10 + cr11) / 4;
829 *dst_cb = 128 + (cb00 + cb01 + cb10 + cb11) / 4;
830 } else {
831 int t4, cr, cb;
832
833 /* blending required, so clamp opacity values to allowed range */
834 if (o00 > 0xf) o00 = 0xf;
835 if (o01 > 0xf) o01 = 0xf;
836 if (o10 > 0xf) o10 = 0xf;
837 if (o11 > 0xf) o11 = 0xf;
838
839 /* calculate transparency of background over the four pixels */
840 t4 = (0xf - o00) + (0xf - o01) + (0xf - o10) + (0xf - o11);
841
842 /* get background chroma */
843 cr = -128 + *dst_cr;
844 cb = -128 + *dst_cb;
845
846 /* blend the output chroma to the average of the four pixels */
847 *dst_cr = 128 + (cr * t4 + cr00 * o00 + cr01 * o01 + cr10 * o10 + cr11 * o11) / (4 * 0xf);
848 *dst_cb = 128 + (cb * t4 + cb00 * o00 + cb01 * o01 + cb10 * o10 + cb11 * o11) / (4 * 0xf);
849 }
850 }
851
852 /* next chroma sample */
853 dst_cr++;
854 dst_cb++;
855 }
856}
857
858static uint8_t *(*blend_yuv_grow_extra_data(alphablend_t *extra_data, int osd_width))[ 3 ][ 2 ]
859{
860 struct __attribute__((packed)) header_s {
861 int id;
862 int max_width;
863 uint8_t *data[ 3 ][ 2 ];
864 } **header = (struct header_s **)&extra_data->buffer;
865
866 int needed_buffer_size = sizeof (**header) + sizeof (uint8_t[ 3 ][ 2 ][ osd_width ]);
867
868 if (extra_data->buffer_size < needed_buffer_size) {
869
870 free(extra_data->buffer);
871 extra_data->buffer = xine_xmalloc(needed_buffer_size);
872
873 if (!extra_data->buffer) {
874 extra_data->buffer_size = 0;
875 return 0;
876 }
877
878 extra_data->buffer_size = needed_buffer_size;
879 (*header)->max_width = 0;
880 }
881
882 if ((*header)->id != ME_FOURCC('y', 'u', 'v', 0) || (*header)->max_width < osd_width) {
883 (*header)->id = ME_FOURCC('y', 'u', 'v', 0);
884 (*header)->max_width = osd_width;
885
886 (*header)->data[ 0 ][ 0 ] = ((uint8_t *)extra_data->buffer) + sizeof (**header);
887 (*header)->data[ 0 ][ 1 ] = (*header)->data[ 0 ][ 0 ] + osd_width;
888 (*header)->data[ 1 ][ 0 ] = (*header)->data[ 0 ][ 1 ] + osd_width;
889 (*header)->data[ 1 ][ 1 ] = (*header)->data[ 1 ][ 0 ] + osd_width;
890 (*header)->data[ 2 ][ 0 ] = (*header)->data[ 1 ][ 1 ] + osd_width;
891 (*header)->data[ 2 ][ 1 ] = (*header)->data[ 2 ][ 0 ] + osd_width;
892 }
893
894 return &(*header)->data;
895}
896
433void blend_yuv (uint8_t *dst_base[3], vo_overlay_t * img_overl, 897void blend_yuv (uint8_t *dst_base[3], vo_overlay_t * img_overl,
434 int dst_width, int dst_height) 898 int dst_width, int dst_height, int dst_pitches[3],
899 alphablend_t *extra_data)
435{ 900{
901 int enable_exact_blending = !extra_data->disable_exact_blending;
436 clut_t *my_clut; 902 clut_t *my_clut;
437 uint8_t *my_trans; 903 uint8_t *my_trans;
438 904
@@ -442,6 +908,8 @@ void blend_yuv (uint8_t *dst_base[3], vo_overlay_t * img_overl,
442 rle_elem_t *rle_limit = rle + img_overl->num_rle; 908 rle_elem_t *rle_limit = rle + img_overl->num_rle;
443 int x_off = img_overl->x; 909 int x_off = img_overl->x;
444 int y_off = img_overl->y; 910 int y_off = img_overl->y;
911 int x_odd = x_off & 1;
912 int y_odd = y_off & 1;
445 int ymask,xmask; 913 int ymask,xmask;
446 int rle_this_bite; 914 int rle_this_bite;
447 int rle_remainder; 915 int rle_remainder;
@@ -449,12 +917,15 @@ void blend_yuv (uint8_t *dst_base[3], vo_overlay_t * img_overl,
449 int x, y; 917 int x, y;
450 int clip_right; 918 int clip_right;
451 uint8_t clr=0; 919 uint8_t clr=0;
452 920
453 uint8_t *dst_y = dst_base[0] + dst_width * y_off + x_off; 921 int any_line_buffered = 0;
454 uint8_t *dst_cr = dst_base[2] + 922 int exact_blend_width = ((src_width <= (dst_width - x_off)) ? src_width : (dst_width - x_off));
455 (y_off / 2) * (dst_width / 2) + (x_off / 2) + 1; 923 int exact_blend_width_m2 = (x_odd + exact_blend_width + 1) & ~1; /* make it a (larger) multiple of 2 */
456 uint8_t *dst_cb = dst_base[1] + 924 uint8_t *(*blend_yuv_data)[ 3 ][ 2 ] = 0;
457 (y_off / 2) * (dst_width / 2) + (x_off / 2) + 1; 925
926 uint8_t *dst_y = dst_base[0] + dst_pitches[0] * y_off + x_off;
927 uint8_t *dst_cr = dst_base[2] + (y_off / 2) * dst_pitches[1] + (x_off / 2);
928 uint8_t *dst_cb = dst_base[1] + (y_off / 2) * dst_pitches[2] + (x_off / 2);
458#ifdef LOG_BLEND_YUV 929#ifdef LOG_BLEND_YUV
459 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); 930 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);
460#endif 931#endif
@@ -462,18 +933,41 @@ void blend_yuv (uint8_t *dst_base[3], vo_overlay_t * img_overl,
462 my_trans = img_overl->clip_trans; 933 my_trans = img_overl->clip_trans;
463 934
464 /* avoid wraping overlay if drawing to small image */ 935 /* avoid wraping overlay if drawing to small image */
465 if( (x_off + img_overl->clip_right) < dst_width ) 936 if( (x_off + img_overl->clip_right) <= dst_width )
466 clip_right = img_overl->clip_right; 937 clip_right = img_overl->clip_right;
467 else 938 else
468 clip_right = dst_width - 1 - x_off; 939 clip_right = dst_width - x_off;
469 940
470 /* avoid buffer overflow */ 941 /* avoid buffer overflow */
471 if( (src_height + y_off) >= dst_height ) 942 if( (src_height + y_off) > dst_height )
472 src_height = dst_height - 1 - y_off; 943 src_height = dst_height - y_off;
473 944
945 if (src_height <= 0)
946 return;
947
948 if (enable_exact_blending) {
949 if (exact_blend_width <= 0)
950 return;
951
952 blend_yuv_data = blend_yuv_grow_extra_data(extra_data, exact_blend_width_m2);
953 if (!blend_yuv_data)
954 return;
955
956 /* make linebuffer transparent */
957 memset(&(*blend_yuv_data)[ 0 ][ 0 ][ 0 ], 0, exact_blend_width_m2);
958 memset(&(*blend_yuv_data)[ 0 ][ 1 ][ 0 ], 0, exact_blend_width_m2);
959 }
960
474 rlelen=rle_remainder=0; 961 rlelen=rle_remainder=0;
475 for (y = 0; y < src_height; y++) { 962 for (y = 0; y < src_height; y++) {
476 ymask = ((img_overl->clip_top > y) || (img_overl->clip_bottom < y)); 963 if (rle >= rle_limit) {
964#ifdef LOG_BLEND_YUV
965 printf("y-rle_limit\n");
966#endif
967 break;
968 }
969
970 ymask = ((y < img_overl->clip_top) || (y >= img_overl->clip_bottom));
477 xmask = 0; 971 xmask = 0;
478#ifdef LOG_BLEND_YUV 972#ifdef LOG_BLEND_YUV
479 printf("X started ymask=%d y=%d src_height=%d\n",ymask, y, src_height); 973 printf("X started ymask=%d y=%d src_height=%d\n",ymask, y, src_height);
@@ -481,12 +975,22 @@ void blend_yuv (uint8_t *dst_base[3], vo_overlay_t * img_overl,
481 975
482 for (x = 0; x < src_width;) { 976 for (x = 0; x < src_width;) {
483 uint16_t o; 977 uint16_t o;
978
979 if (rle >= rle_limit) {
980#ifdef LOG_BLEND_YUV
981 printf("x-rle_limit\n");
982#endif
983 break;
984 }
985
484#ifdef LOG_BLEND_YUV 986#ifdef LOG_BLEND_YUV
485 printf("1:rle_len=%d, remainder=%d, x=%d\n",rlelen, rle_remainder, x); 987 printf("1:rle_len=%d, remainder=%d, x=%d\n",rlelen, rle_remainder, x);
486#endif 988#endif
487 989
488 if ((rlelen < 0) || (rle_remainder < 0)) { 990 if ((rlelen < 0) || (rle_remainder < 0)) {
991#ifdef LOG_BLEND_YUV
489 printf("alphablend: major bug in blend_yuv < 0\n"); 992 printf("alphablend: major bug in blend_yuv < 0\n");
993#endif
490 } 994 }
491 if (rlelen == 0) { 995 if (rlelen == 0) {
492 rle_remainder = rlelen = rle->len; 996 rle_remainder = rlelen = rle->len;
@@ -498,22 +1002,21 @@ void blend_yuv (uint8_t *dst_base[3], vo_overlay_t * img_overl,
498 } 1002 }
499 if ((rle_remainder + x) > src_width) { 1003 if ((rle_remainder + x) > src_width) {
500 /* Do something for long rlelengths */ 1004 /* Do something for long rlelengths */
501 rle_remainder = src_width - x; 1005 rle_remainder = src_width - x;
502 ;
503 } 1006 }
504#ifdef LOG_BLEND_YUV 1007#ifdef LOG_BLEND_YUV
505 printf("2:rle_len=%d, remainder=%d, x=%d\n",rlelen, rle_remainder, x); 1008 printf("2:rle_len=%d, remainder=%d, x=%d\n",rlelen, rle_remainder, x);
506#endif 1009#endif
507 1010
508 if (ymask == 0) { 1011 if (ymask == 0) {
509 if (x <= img_overl->clip_left) { 1012 if (x < img_overl->clip_left) {
510 /* Starts outside clip area */ 1013 /* Starts outside clip area */
511 if ((x + rle_remainder - 1) > img_overl->clip_left ) { 1014 if ((x + rle_remainder) > img_overl->clip_left ) {
512#ifdef LOG_BLEND_YUV 1015#ifdef LOG_BLEND_YUV
513 printf("Outside clip left %d, ending inside\n", img_overl->clip_left); 1016 printf("Outside clip left %d, ending inside\n", img_overl->clip_left);
514#endif 1017#endif
515 /* Cutting needed, starts outside, ends inside */ 1018 /* Cutting needed, starts outside, ends inside */
516 rle_this_bite = (img_overl->clip_left - x + 1); 1019 rle_this_bite = (img_overl->clip_left - x);
517 rle_remainder -= rle_this_bite; 1020 rle_remainder -= rle_this_bite;
518 rlelen -= rle_this_bite; 1021 rlelen -= rle_this_bite;
519 my_clut = (clut_t*) img_overl->color; 1022 my_clut = (clut_t*) img_overl->color;
@@ -557,7 +1060,7 @@ void blend_yuv (uint8_t *dst_base[3], vo_overlay_t * img_overl,
557 xmask++; 1060 xmask++;
558 } 1061 }
559 } else if (x >= clip_right) { 1062 } else if (x >= clip_right) {
560 /* Starts outside clip area, ends outsite clip area */ 1063 /* Starts outside clip area, ends outside clip area */
561 if ((x + rle_remainder ) > src_width ) { 1064 if ((x + rle_remainder ) > src_width ) {
562#ifdef LOG_BLEND_YUV 1065#ifdef LOG_BLEND_YUV
563 printf("Outside clip right %d, ending eol\n", clip_right); 1066 printf("Outside clip right %d, ending eol\n", clip_right);
@@ -597,56 +1100,187 @@ void blend_yuv (uint8_t *dst_base[3], vo_overlay_t * img_overl,
597#ifdef LOG_BLEND_YUV 1100#ifdef LOG_BLEND_YUV
598 printf("Trans=%d clr=%d xmask=%d my_clut[clr]=%d\n",o, clr, xmask, my_clut[clr].y); 1101 printf("Trans=%d clr=%d xmask=%d my_clut[clr]=%d\n",o, clr, xmask, my_clut[clr].y);
599#endif 1102#endif
600 if (o) { 1103
601 if(o >= 15) { 1104 if (x < (dst_width - x_off)) {
602 memset(dst_y + x, my_clut[clr].y, rle_this_bite); 1105 /* clip against right edge of destination area */
603 if (y & 1) { 1106 if ((x + rle_this_bite) > (dst_width - x_off)) {
604 memset(dst_cr + (x >> 1), my_clut[clr].cr, (rle_this_bite+1) >> 1); 1107 int toClip = (x + rle_this_bite) - (dst_width - x_off);
605 memset(dst_cb + (x >> 1), my_clut[clr].cb, (rle_this_bite+1) >> 1); 1108
606 } 1109 rle_this_bite -= toClip;
607 } else { 1110 rle_remainder += toClip;
608 mem_blend8(dst_y + x, my_clut[clr].y, o, rle_this_bite); 1111 rlelen += toClip;
609 if (y & 1) {
610 /* Blending cr and cb should use a different function, with pre -128 to each sample */
611 mem_blend8(dst_cr + (x >> 1), my_clut[clr].cr, o, (rle_this_bite+1) >> 1);
612 mem_blend8(dst_cb + (x >> 1), my_clut[clr].cb, o, (rle_this_bite+1) >> 1);
613 }
614 } 1112 }
615 1113
1114 if (enable_exact_blending) {
1115 /* remember opacity of current line */
1116 memset(&(*blend_yuv_data)[ 0 ][ (y + y_odd) & 1 ][ x + x_odd ], o, rle_this_bite);
1117 any_line_buffered |= ((y + y_odd) & 1) ? 2 : 1;
1118 }
1119
1120 if (o) {
1121 if(o >= 15) {
1122 memset(dst_y + x, my_clut[clr].y, rle_this_bite);
1123 if (!enable_exact_blending) {
1124 if ((y + y_odd) & 1) {
1125 memset(dst_cr + ((x + x_odd) >> 1), my_clut[clr].cr, (rle_this_bite+1) >> 1);
1126 memset(dst_cb + ((x + x_odd) >> 1), my_clut[clr].cb, (rle_this_bite+1) >> 1);
1127 }
1128 }
1129 } else {
1130 mem_blend8(dst_y + x, my_clut[clr].y, o, rle_this_bite);
1131 if (!enable_exact_blending) {
1132 if ((y + y_odd) & 1) {
1133 /* Blending cr and cb should use a different function, with pre -128 to each sample */
1134 mem_blend8(dst_cr + ((x + x_odd) >> 1), my_clut[clr].cr, o, (rle_this_bite+1) >> 1);
1135 mem_blend8(dst_cb + ((x + x_odd) >> 1), my_clut[clr].cb, o, (rle_this_bite+1) >> 1);
1136 }
1137 }
1138 }
1139
1140 if (enable_exact_blending) {
1141 /* remember chroma of current line */
1142 memset(&(*blend_yuv_data)[ 1 ][ (y + y_odd) & 1 ][ x + x_odd ], my_clut[ clr ].cr, rle_this_bite);
1143 memset(&(*blend_yuv_data)[ 2 ][ (y + y_odd) & 1 ][ x + x_odd ], my_clut[ clr ].cb, rle_this_bite);
1144 }
1145 }
616 } 1146 }
617#ifdef LOG_BLEND_YUV 1147#ifdef LOG_BLEND_YUV
618 printf("rle_this_bite=%d, remainder=%d, x=%d\n",rle_this_bite, rle_remainder, x); 1148 printf("rle_this_bite=%d, remainder=%d, x=%d\n",rle_this_bite, rle_remainder, x);
619#endif 1149#endif
620 x += rle_this_bite; 1150 x += rle_this_bite;
621 if (rle >= rle_limit) {
622#ifdef LOG_BLEND_YUV
623 printf("x-rle_limit\n");
624#endif
625 break;
626 }
627 }
628 if (rle >= rle_limit) {
629#ifdef LOG_BLEND_YUV
630 printf("x-rle_limit\n");
631#endif
632 break;
633 } 1151 }
634 1152
635 dst_y += dst_width; 1153 if ((y + y_odd) & 1) {
1154 if (enable_exact_blending) {
1155 /* blend buffered lines */
1156 if (any_line_buffered) {
1157 if (!(any_line_buffered & 2)) {
1158 /* make second line transparent */
1159 memset(&(*blend_yuv_data)[ 0 ][ 1 ][ 0 ], 0, exact_blend_width_m2);
1160 }
1161
1162 blend_yuv_exact(dst_cr, dst_cb, exact_blend_width, x_odd, blend_yuv_data);
1163
1164 any_line_buffered = 0;
1165 }
1166 }
1167
1168 dst_cr += dst_pitches[2];
1169 dst_cb += dst_pitches[1];
1170 }
1171
1172 dst_y += dst_pitches[0];
1173 }
636 1174
637 if (y & 1) { 1175 if (enable_exact_blending) {
638 dst_cr += (dst_width + 1) / 2; 1176 /* blend buffered lines */
639 dst_cb += (dst_width + 1) / 2; 1177 if (any_line_buffered) {
1178 if (!(any_line_buffered & 2)) {
1179 /* make second line transparent */
1180 memset(&(*blend_yuv_data)[ 0 ][ 1 ][ 0 ], 0, exact_blend_width_m2);
1181 }
1182
1183 blend_yuv_exact(dst_cr, dst_cb, exact_blend_width, x_odd, blend_yuv_data);
640 } 1184 }
641 } 1185 }
1186
642#ifdef LOG_BLEND_YUV 1187#ifdef LOG_BLEND_YUV
643 printf("overlay_blend ended\n"); 1188 printf("overlay_blend ended\n");
644#endif 1189#endif
645} 1190}
646 1191
1192static void blend_yuy2_exact(uint8_t *dst_cr, uint8_t *dst_cb,
1193 int src_width, int x_odd,
1194 uint8_t *(*blend_yuy2_data)[ 3 ])
1195{
1196 int x;
1197
1198 for (x = 0; x < src_width; x += 2) {
1199 /* get opacity of the 2 pixels that share chroma */
1200 int o0 = (*blend_yuy2_data)[ 0 ][ x + 0 ];
1201 int o1 = (*blend_yuy2_data)[ 0 ][ x + 1 ];
1202
1203 /* are there any pixels a little bit opaque? */
1204 if (o0 || o1) {
1205 /* get the chroma components of the 2 pixels */
1206 int cr0 = -128 + (*blend_yuy2_data)[ 1 ][ x + 0 ];
1207 int cr1 = -128 + (*blend_yuy2_data)[ 1 ][ x + 1 ];
1208
1209 int cb0 = -128 + (*blend_yuy2_data)[ 2 ][ x + 0 ];
1210 int cb1 = -128 + (*blend_yuy2_data)[ 2 ][ x + 1 ];
1211
1212 /* are all pixels completely opaque? */
1213 if (o0 >= 0xf && o1 >= 0xf) {
1214 /* set the output chroma to the average of the two pixels */
1215 *dst_cr = 128 + (cr0 + cr1) / 2;
1216 *dst_cb = 128 + (cb0 + cb1) / 2;
1217 } else {
1218 int t2, cr, cb;
1219
1220 /* blending required, so clamp opacity values to allowed range */
1221 if (o0 > 0xf) o0 = 0xf;
1222 if (o1 > 0xf) o1 = 0xf;
1223
1224 /* calculate transparency of background over the two pixels */
1225 t2 = (0xf - o0) + (0xf - o1);
1226
1227 /* get background chroma */
1228 cr = -128 + *dst_cr;
1229 cb = -128 + *dst_cb;
1230
1231 /* blend the output chroma to the average of the two pixels */
1232 *dst_cr = 128 + (cr * t2 + cr0 * o0 + cr1 * o1) / (2 * 0xf);
1233 *dst_cb = 128 + (cb * t2 + cb0 * o0 + cb1 * o1) / (2 * 0xf);
1234 }
1235 }
1236
1237 /* next chroma sample */
1238 dst_cr += 4;
1239 dst_cb += 4;
1240 }
1241}
1242
1243static uint8_t *(*blend_yuy2_grow_extra_data(alphablend_t *extra_data, int osd_width))[ 3 ]
1244{
1245 struct __attribute__((packed)) header_s {
1246 int id;
1247 int max_width;
1248 uint8_t *data[ 3 ];
1249 } **header = (struct header_s **)&extra_data->buffer;
1250
1251 int needed_buffer_size = sizeof (**header) + sizeof (uint8_t[ 3 ][ osd_width ]);
1252
1253 if (extra_data->buffer_size < needed_buffer_size) {
1254
1255 free(extra_data->buffer);
1256 extra_data->buffer = xine_xmalloc(needed_buffer_size);
1257
1258 if (!extra_data->buffer) {
1259 extra_data->buffer_size = 0;
1260 return 0;
1261 }
1262
1263 extra_data->buffer_size = needed_buffer_size;
1264 (*header)->max_width = 0;
1265 }
1266
1267 if ((*header)->id != ME_FOURCC('y', 'u', 'y', '2') || (*header)->max_width < osd_width) {
1268 (*header)->id = ME_FOURCC('y', 'u', 'y', '2');
1269 (*header)->max_width = osd_width;
1270
1271 (*header)->data[ 0 ] = ((uint8_t *)extra_data->buffer) + sizeof (**header);
1272 (*header)->data[ 1 ] = (*header)->data[ 0 ] + osd_width;
1273 (*header)->data[ 2 ] = (*header)->data[ 1 ] + osd_width;
1274 }
1275
1276 return &(*header)->data;
1277}
1278
647void blend_yuy2 (uint8_t * dst_img, vo_overlay_t * img_overl, 1279void blend_yuy2 (uint8_t * dst_img, vo_overlay_t * img_overl,
648 int dst_width, int dst_height) 1280 int dst_width, int dst_height, int dst_pitch,
1281 alphablend_t *extra_data)
649{ 1282{
1283 int enable_exact_blending = !extra_data->disable_exact_blending;
650 clut_t *my_clut; 1284 clut_t *my_clut;
651 uint8_t *my_trans; 1285 uint8_t *my_trans;
652 1286
@@ -656,100 +1290,495 @@ void blend_yuy2 (uint8_t * dst_img, vo_overlay_t * img_overl,
656 rle_elem_t *rle_limit = rle + img_overl->num_rle; 1290 rle_elem_t *rle_limit = rle + img_overl->num_rle;
657 int x_off = img_overl->x; 1291 int x_off = img_overl->x;
658 int y_off = img_overl->y; 1292 int y_off = img_overl->y;
659 int mask; 1293 int x_odd = x_off & 1;
1294 int ymask;
1295 int rle_this_bite;
1296 int rle_remainder;
1297 int rlelen;
660 int x, y; 1298 int x, y;
661 int l; 1299 int l = 0;
662 int clip_right; 1300 int clip_right;
663 uint32_t yuy2; 1301
1302 union {
1303 uint32_t value;
1304 uint8_t b[4];
1305 uint16_t h[2];
1306 } yuy2;
1307
1308 uint8_t clr = 0;
1309
1310 int any_line_buffered = 0;
1311 int exact_blend_width = ((src_width <= (dst_width - x_off)) ? src_width : (dst_width - x_off));
1312 int exact_blend_width_m2 = (x_odd + exact_blend_width + 1) & ~1; /* make it a (larger) multiple of 2 */
1313 uint8_t *(*blend_yuy2_data)[ 3 ] = 0;
664 1314
665 uint8_t *dst_y = dst_img + 2 * (dst_width * y_off + x_off); 1315 uint8_t *dst_y = dst_img + dst_pitch * y_off + 2 * x_off;
666 uint8_t *dst; 1316 uint8_t *dst;
667 1317
668 my_clut = (clut_t*) img_overl->clip_color; 1318 my_clut = (clut_t*) img_overl->clip_color;
669 my_trans = img_overl->clip_trans; 1319 my_trans = img_overl->clip_trans;
670 1320
671 /* avoid wraping overlay if drawing to small image */ 1321 /* avoid wraping overlay if drawing to small image */
672 if( (x_off + img_overl->clip_right) < dst_width ) 1322 if( (x_off + img_overl->clip_right) <= dst_width )
673 clip_right = img_overl->clip_right; 1323 clip_right = img_overl->clip_right;
674 else 1324 else
675 clip_right = dst_width - 1 - x_off; 1325 clip_right = dst_width - x_off;
676 1326
677 /* avoid buffer overflow */ 1327 /* avoid buffer overflow */
678 if( (src_height + y_off) >= dst_height ) 1328 if( (src_height + y_off) > dst_height )
679 src_height = dst_height - 1 - y_off; 1329 src_height = dst_height - y_off;
1330
1331 if (src_height <= 0)
1332 return;
1333
1334 if (enable_exact_blending) {
1335 if (exact_blend_width <= 0)
1336 return;
1337
1338 blend_yuy2_data = blend_yuy2_grow_extra_data(extra_data, exact_blend_width_m2);
1339 if (!blend_yuy2_data)
1340 return;
1341
1342 /* make linebuffer transparent */
1343 memset(&(*blend_yuy2_data)[ 0 ][ 0 ], 0, exact_blend_width_m2);
1344 }
680 1345
1346 rlelen=rle_remainder=0;
681 for (y = 0; y < src_height; y++) { 1347 for (y = 0; y < src_height; y++) {
682 mask = !(img_overl->clip_top > y || img_overl->clip_bottom < y); 1348 if (rle >= rle_limit)
1349 break;
1350
1351 ymask = ((y < img_overl->clip_top) || (y >= img_overl->clip_bottom));
683 1352
684 dst = dst_y; 1353 dst = dst_y;
685 for (x = 0; x < src_width;) { 1354 for (x = 0; x < src_width;) {
686 uint8_t clr;
687 uint16_t o; 1355 uint16_t o;
688 int rlelen;
689 1356
690 clr = rle->color; 1357 if (rle >= rle_limit)
691 o = my_trans[clr]; 1358 break;
692 rlelen = rle->len; 1359
693 1360 if ((rlelen < 0) || (rle_remainder < 0)) {
694 if (o && mask) { 1361#ifdef LOG_BLEND_YUV
695 /* threat cases where clipping border is inside rle->len pixels */ 1362 printf("alphablend: major bug in blend_yuv < 0\n");
696 if ( img_overl->clip_left > x ) { 1363#endif
697 if( img_overl->clip_left < x + rlelen ) { 1364 }
698 rlelen -= img_overl->clip_left - x; 1365 if (rlelen == 0) {
699 x += img_overl->clip_left - x; 1366 rle_remainder = rlelen = rle->len;
1367 clr = rle->color;
1368 rle++;
1369 }
1370 if (rle_remainder == 0) {
1371 rle_remainder = rlelen;
1372 }
1373 if ((rle_remainder + x) > src_width) {
1374 /* Do something for long rlelengths */
1375 rle_remainder = src_width - x;
1376 }
1377#ifdef LOG_BLEND_YUV
1378 printf("2:rle_len=%d, remainder=%d, x=%d\n",rlelen, rle_remainder, x);
1379#endif
1380
1381 if (ymask == 0) {
1382 if (x < img_overl->clip_left) {
1383 /* Starts outside clip area */
1384 if ((x + rle_remainder) > img_overl->clip_left ) {
1385#ifdef LOG_BLEND_YUV
1386 printf("Outside clip left %d, ending inside\n", img_overl->clip_left);
1387#endif
1388 /* Cutting needed, starts outside, ends inside */
1389 rle_this_bite = (img_overl->clip_left - x);
1390 rle_remainder -= rle_this_bite;
1391 rlelen -= rle_this_bite;
1392 my_clut = (clut_t*) img_overl->color;
1393 my_trans = img_overl->trans;
700 } else { 1394 } else {
701 o = 0; 1395#ifdef LOG_BLEND_YUV
1396 printf("Outside clip left %d, ending outside\n", img_overl->clip_left);
1397#endif
1398 /* no cutting needed, starts outside, ends outside */
1399 rle_this_bite = rle_remainder;
1400 rle_remainder = 0;
1401 rlelen -= rle_this_bite;
1402 my_clut = (clut_t*) img_overl->color;
1403 my_trans = img_overl->trans;
702 } 1404 }
703 } else if( clip_right < x + rlelen ) { 1405 } else if (x < clip_right) {
704 if( clip_right > x ) { 1406 /* Starts inside clip area */
705 /* fixme: case not implemented */ 1407 if ((x + rle_remainder) > clip_right ) {
706 o = 0; 1408#ifdef LOG_BLEND_YUV
1409 printf("Inside clip right %d, ending outside\n", clip_right);
1410#endif
1411 /* Cutting needed, starts inside, ends outside */
1412 rle_this_bite = (clip_right - x);
1413 rle_remainder -= rle_this_bite;
1414 rlelen -= rle_this_bite;
1415 my_clut = (clut_t*) img_overl->clip_color;
1416 my_trans = img_overl->clip_trans;
707 } else { 1417 } else {
708 o = 0; 1418#ifdef LOG_BLEND_YUV
1419 printf("Inside clip right %d, ending inside\n", clip_right);
1420#endif
1421 /* no cutting needed, starts inside, ends inside */
1422 rle_this_bite = rle_remainder;
1423 rle_remainder = 0;
1424 rlelen -= rle_this_bite;
1425 my_clut = (clut_t*) img_overl->clip_color;
1426 my_trans = img_overl->clip_trans;
709 } 1427 }
710 } 1428 } else if (x >= clip_right) {
1429 /* Starts outside clip area, ends outsite clip area */
1430 if ((x + rle_remainder ) > src_width ) {
1431#ifdef LOG_BLEND_YUV
1432 printf("Outside clip right %d, ending eol\n", clip_right);
1433#endif
1434 /* Cutting needed, starts outside, ends at right edge */
1435 /* It should never reach here due to the earlier test of src_width */
1436 rle_this_bite = (src_width - x );
1437 rle_remainder -= rle_this_bite;
1438 rlelen -= rle_this_bite;
1439 my_clut = (clut_t*) img_overl->color;
1440 my_trans = img_overl->trans;
1441 } else {
1442 /* no cutting needed, starts outside, ends outside */
1443#ifdef LOG_BLEND_YUV
1444 printf("Outside clip right %d, ending outside\n", clip_right);
1445#endif
1446 rle_this_bite = rle_remainder;
1447 rle_remainder = 0;
1448 rlelen -= rle_this_bite;
1449 my_clut = (clut_t*) img_overl->color;
1450 my_trans = img_overl->trans;
1451 }
1452 }
1453 } else {
1454 /* Outside clip are due to y */
1455 /* no cutting needed, starts outside, ends outside */
1456 rle_this_bite = rle_remainder;
1457 rle_remainder = 0;
1458 rlelen -= rle_this_bite;
1459 my_clut = (clut_t*) img_overl->color;
1460 my_trans = img_overl->trans;
711 } 1461 }
712 1462 o = my_trans[clr];
1463
1464 if (x < (dst_width - x_off)) {
1465 /* clip against right edge of destination area */
1466 if ((x + rle_this_bite) > (dst_width - x_off)) {
1467 int toClip = (x + rle_this_bite) - (dst_width - x_off);
1468
1469 rle_this_bite -= toClip;
1470 rle_remainder += toClip;
1471 rlelen += toClip;
1472 }
1473
1474 if (enable_exact_blending) {
1475 /* remember opacity of current line */
1476 memset(&(*blend_yuy2_data)[ 0 ][ x + x_odd ], o, rle_this_bite);
1477 any_line_buffered = 1;
1478 }
1479
1480 if (o) {
1481 if (!enable_exact_blending) {
1482 l = rle_this_bite>>1;
1483 if( !((x_odd+x) & 1) ) {
1484 yuy2.b[0] = my_clut[clr].y;
1485 yuy2.b[1] = my_clut[clr].cb;
1486 yuy2.b[2] = my_clut[clr].y;
1487 yuy2.b[3] = my_clut[clr].cr;
1488 } else {
1489 yuy2.b[0] = my_clut[clr].y;
1490 yuy2.b[1] = my_clut[clr].cr;
1491 yuy2.b[2] = my_clut[clr].y;
1492 yuy2.b[3] = my_clut[clr].cb;
1493 }
1494 }
1495 if (o >= 15) {
1496 if (!enable_exact_blending) {
1497 while(l--) {
1498 *(uint16_t *)dst = yuy2.h[0];
1499 dst += 2;
1500 *(uint16_t *)dst = yuy2.h[1];
1501 dst += 2;
1502 }
1503 if(rle_this_bite & 1) {
1504 *(uint16_t *)dst = yuy2.h[0];
1505 dst += 2;
1506 }
1507 } else {
1508 l = rle_this_bite;
1509 while (l--) {
1510 *dst = my_clut[clr].y;
1511 dst += 2;
1512 }
1513 }
1514 } else {
1515 if (!enable_exact_blending) {
1516 if( l ) {
1517 mem_blend32(dst, &yuy2.b[0], o, l);
1518 dst += 4*l;
1519 }
1520
1521 if(rle_this_bite & 1) {
1522 *dst = BLEND_BYTE(*dst, yuy2.b[0], o);
1523 dst++;
1524 *dst = BLEND_BYTE(*dst, yuy2.b[1], o);
1525 dst++;
1526 }
1527 } else {
1528 l = rle_this_bite;
1529 while (l--) {
1530 *dst = BLEND_BYTE(*dst, my_clut[clr].y, o);
1531 dst += 2;
1532 }
1533 }
1534 }
713 1535
714 if (o && mask) { 1536 if (enable_exact_blending) {
715 l = rlelen>>1; 1537 /* remember chroma of current line */
716 if( !(x & 1) ) { 1538 memset(&(*blend_yuy2_data)[ 1 ][ x + x_odd ], my_clut[ clr ].cr, rle_this_bite);
717 yuy2 = my_clut[clr].y + (my_clut[clr].cb << 8) + 1539 memset(&(*blend_yuy2_data)[ 2 ][ x + x_odd ], my_clut[ clr ].cb, rle_this_bite);
718 (my_clut[clr].y << 16) + (my_clut[clr].cr << 24); 1540 }
719 } else { 1541 } else {
720 yuy2 = my_clut[clr].y + (my_clut[clr].cr << 8) + 1542 dst += rle_this_bite*2;
721 (my_clut[clr].y << 16) + (my_clut[clr].cb << 24);
722 } 1543 }
1544 }
1545
1546 x += rle_this_bite;
1547 }
1548
1549 if (enable_exact_blending) {
1550 /* blend buffered line */
1551 if (any_line_buffered) {
1552 blend_yuy2_exact(dst_y - x_odd * 2 + 3, dst_y - x_odd * 2 + 1, exact_blend_width, x_odd, blend_yuy2_data);
723 1553
724 if (o >= 15) { 1554 any_line_buffered = 0;
725 while(l--) { 1555 }
726 *((uint32_t *)dst)++ = yuy2; 1556 }
1557
1558 dst_y += dst_pitch;
1559 }
1560}
1561
1562void clear_xx44_palette(xx44_palette_t *p)
1563{
1564 register int i;
1565 register uint32_t *cluts = p->cluts;
1566 register int *ids = p->lookup_cache;
1567
1568 i= p->size;
1569 while(i--)
1570 *cluts++ = 0;
1571 i = 2*OVL_PALETTE_SIZE;
1572 while(i--)
1573 *ids++ = -1;
1574 p->max_used=1;
1575}
1576
1577void init_xx44_palette(xx44_palette_t *p, unsigned num_entries)
1578{
1579 p->size = (num_entries > XX44_PALETTE_SIZE) ? XX44_PALETTE_SIZE : num_entries;
1580}
1581
1582void dispose_xx44_palette(xx44_palette_t *p)
1583{
1584}
1585
1586static void colorToPalette(const uint32_t *icolor, unsigned char *palette_p,
1587 unsigned num_xvmc_components, char *xvmc_components)
1588{
1589 const clut_t *color = (const clut_t *) icolor;
1590 int i;
1591 for (i=0; i<num_xvmc_components; ++i) {
1592 switch(xvmc_components[i]) {
1593 case 'V': *palette_p = color->cr; break;
1594 case 'U': *palette_p = color->cb; break;
1595 case 'Y':
1596 default: *palette_p = color->y; break;
1597 }
1598 *palette_p++;
1599 }
1600}
1601
1602
1603void xx44_to_xvmc_palette(const xx44_palette_t *p,unsigned char *xvmc_palette,
1604 unsigned first_xx44_entry, unsigned num_xx44_entries,
1605 unsigned num_xvmc_components, char *xvmc_components)
1606{
1607 register int i;
1608 register const uint32_t *cluts = p->cluts + first_xx44_entry;
1609
1610 for (i=0; i<num_xx44_entries; ++i) {
1611 if ((cluts - p->cluts) < p->size) {
1612 colorToPalette(cluts++, xvmc_palette, num_xvmc_components, xvmc_components);
1613 xvmc_palette += num_xvmc_components;
1614 }
1615 }
1616}
1617
1618static int xx44_paletteIndex(xx44_palette_t *p, int color, uint32_t clut)
1619{
1620
1621 register int i;
1622 register uint32_t *cluts = p->cluts;
1623 register int tmp;
1624
1625 if ((tmp = p->lookup_cache[color]) >= 0)
1626 if (cluts[tmp] == clut) return tmp;
1627
1628 for (i=0; i<p->max_used; ++i) {
1629 if (*cluts++ == clut) return p->lookup_cache[color] = i;
1630 }
1631
1632 if (p->max_used == p->size -1) {
1633 printf("video_out: Warning! Out of xx44 palette colors!\n");
1634 return 1;
1635 }
1636 p->cluts[p->max_used] = clut;
1637 return p->lookup_cache[color] = p->max_used++;
1638}
1639
1640static void memblend_xx44(uint8_t *mem,uint8_t val, register size_t size, uint8_t mask)
1641{
1642 register uint8_t masked_val = val & mask;
1643
1644 while(size--) {
1645 if ((*mem & mask) <= masked_val ) *mem = val;
1646 mem++;
1647 }
1648}
1649
1650void blend_xx44 (uint8_t *dst_img, vo_overlay_t *img_overl,
1651 int dst_width, int dst_height, int dst_pitch,
1652 alphablend_t *extra_data,
1653 xx44_palette_t *palette,int ia44)
1654{
1655 int src_width = img_overl->width;
1656 int src_height = img_overl->height;
1657 rle_elem_t *rle = img_overl->rle;
1658 rle_elem_t *rle_limit = rle + img_overl->num_rle;
1659 int mask;
1660 int x_off = img_overl->x;
1661 int y_off = img_overl->y;
1662 int x, y;
1663 uint8_t norm_pixel,clip_pixel;
1664 uint8_t *dst_y;
1665 uint8_t *dst;
1666 uint8_t alphamask = (ia44) ? 0x0F : 0xF0;
1667 int clip_right;
1668
1669 if (!img_overl)
1670 return;
1671
1672 dst_y = dst_img + dst_pitch*y_off + x_off;
1673
1674 if( (x_off + img_overl->width) <= dst_width )
1675 clip_right = img_overl->width;
1676 else
1677 clip_right = dst_width - x_off;
1678
1679 if ((src_height + y_off) > dst_height)
1680 src_height = dst_height - y_off;
1681
1682 for (y = 0; y < src_height; y++) {
1683
1684 mask = !(y < img_overl->clip_top || y >= img_overl->clip_bottom);
1685 dst = dst_y;
1686
1687 for (x = 0; x < src_width;) {
1688 int len = (x + rle->len > clip_right) ? clip_right - x : rle->len;
1689
1690 if (len > 0) {
1691 norm_pixel = (uint8_t)((xx44_paletteIndex(palette,rle->color,
1692 img_overl->color[rle->color]) << 4) |
1693 (img_overl->trans[rle->color] & 0x0F));
1694 clip_pixel = (uint8_t)((xx44_paletteIndex(palette,rle->color+OVL_PALETTE_SIZE,
1695 img_overl->clip_color[rle->color]) << 4) |
1696 (img_overl->clip_trans[rle->color] & 0x0F));
1697 if (!ia44) {
1698 norm_pixel = ((norm_pixel & 0x0F) << 4) | ((norm_pixel & 0xF0) >> 4);
1699 clip_pixel = ((clip_pixel & 0x0F) << 4) | ((clip_pixel & 0xF0) >> 4);
1700 }
1701 if (mask) {
1702 if (x < img_overl->clip_left) {
1703 if (x + len <= img_overl->clip_left) {
1704 memblend_xx44(dst,norm_pixel,len, alphamask);
1705 dst += len;
1706 } else {
1707 memblend_xx44(dst,norm_pixel,img_overl->clip_left -x, alphamask);
1708 dst += img_overl->clip_left - x;
1709 len -= img_overl->clip_left - x;
1710 if (len <= img_overl->clip_right - img_overl->clip_left) {
1711 memblend_xx44(dst,clip_pixel,len, alphamask);
1712 dst += len;
1713 } else {
1714 memblend_xx44(dst,clip_pixel,img_overl->clip_right - img_overl->clip_left,
1715 alphamask);
1716 dst += img_overl->clip_right - img_overl->clip_left;
1717 len -= img_overl->clip_right - img_overl->clip_left;
1718 memblend_xx44(dst,norm_pixel,len, alphamask);
1719 dst += len;
1720 }
1721 }
1722 } else if (x < img_overl->clip_right) {
1723 if (len <= img_overl->clip_right - x) {
1724 memblend_xx44(dst,clip_pixel,len, alphamask);
1725 dst += len;
1726 } else {
1727 memblend_xx44(dst,clip_pixel,img_overl->clip_right - x,alphamask);
1728 dst += img_overl->clip_right - x;
1729 len -= img_overl->clip_right - x;
1730 memblend_xx44(dst,norm_pixel,len, alphamask);
1731 dst += len;
1732 }
1733 } else {
1734 memblend_xx44(dst,norm_pixel,len, alphamask);
1735 dst += len;
727 } 1736 }
728 if(rlelen & 1)
729 *((uint16_t *)dst)++ = yuy2 & 0xffff;
730 } else { 1737 } else {
731 if( l ) { 1738 memblend_xx44(dst,norm_pixel,len, alphamask);
732 mem_blend32(dst, (uint8_t *)&yuy2, o, l); 1739 dst += len;
733 dst += 4*l;
734 }
735
736 if(rlelen & 1) {
737 *dst = BLEND_BYTE(*dst, *((uint8_t *)&yuy2), o);
738 dst++;
739 *dst = BLEND_BYTE(*dst, *((uint8_t *)&yuy2+1), o);
740 dst++;
741 }
742 } 1740 }
743 } else {
744 dst += rlelen*2;
745 } 1741 }
746 1742 x += rle->len;
747 x += rlelen;
748 rle++; 1743 rle++;
749 if (rle >= rle_limit) break; 1744 if (rle >= rle_limit) break;
750 } 1745 }
751 if (rle >= rle_limit) break; 1746 if (rle >= rle_limit) break;
1747 dst_y += dst_pitch;
1748 }
1749}
1750
1751static void alphablend_disable_exact_osd_alpha_blending_changed(void *user_data, xine_cfg_entry_t *entry)
1752{
1753 alphablend_t *extra_data = (alphablend_t *)user_data;
1754
1755 extra_data->disable_exact_blending = entry->num_value;
1756}
752 1757
753 dst_y += dst_width*2; 1758void _x_alphablend_init(alphablend_t *extra_data, xine_t *xine)
1759{
1760 config_values_t *config = xine->config;
1761
1762 extra_data->buffer = 0;
1763 extra_data->buffer_size = 0;
1764
1765 extra_data->disable_exact_blending =
1766 config->register_bool(config, "video.output.disable_exact_alphablend", 0,
1767 _("disable exact alpha blending of overlays"),
1768 _("If you experience a performance impact when an On Screen Display or other "
1769 "overlays like DVD subtitles are active, then you might want to enable this option.\n"
1770 "The result is that alpha blending of overlays is less accurate than before, "
1771 "but the CPU usage will be decreased as well."),
1772 10, alphablend_disable_exact_osd_alpha_blending_changed, extra_data);
1773}
1774
1775void _x_alphablend_free(alphablend_t *extra_data)
1776{
1777 if (extra_data->buffer) {
1778 free(extra_data->buffer);
1779 extra_data->buffer = NULL;
754 } 1780 }
1781
1782 extra_data->buffer_size = 0;
755} 1783}
1784