author | zecke <zecke> | 2005-04-17 13:56:34 (UTC) |
---|---|---|
committer | zecke <zecke> | 2005-04-17 13:56:34 (UTC) |
commit | 3d5e5c098ccb686588380bc1f220beafbc5a6d76 (patch) (side-by-side diff) | |
tree | 92fad8a98ea341ec290dc7f9fca7759470b795f6 | |
parent | 49335d66d8e96b1fc86ecfe95cd343c8960126bc (diff) | |
download | opie-3d5e5c098ccb686588380bc1f220beafbc5a6d76.zip opie-3d5e5c098ccb686588380bc1f220beafbc5a6d76.tar.gz opie-3d5e5c098ccb686588380bc1f220beafbc5a6d76.tar.bz2 |
Opie Player2 XINE update:
-update xine code alphablend, yuv2rgb to be up to date
-XINELib:
-use the XINE infrastructure to change the gui width/height
-use the XINE infrastructure to change the brightness
-Update the NULL Video Driver:
-make use of frame_dest_cb and and dest_size_cb (callback)
to update the size of the gui
-use alphablend
-merge the video_out_fb xine driver
To Alwin: your testvideo now lockups op2. with valgrind I see
it has to do with the yuv2rgb conversion methods
-rw-r--r-- | noncore/multimedia/opieplayer2/alphablend.c | 1567 | ||||
-rw-r--r-- | noncore/multimedia/opieplayer2/alphablend.h | 91 | ||||
-rw-r--r-- | noncore/multimedia/opieplayer2/lib.cpp | 74 | ||||
-rw-r--r-- | noncore/multimedia/opieplayer2/lib.h | 40 | ||||
-rw-r--r-- | noncore/multimedia/opieplayer2/mainTest.cpp | 16 | ||||
-rw-r--r-- | noncore/multimedia/opieplayer2/nullvideo.c | 292 | ||||
-rw-r--r-- | noncore/multimedia/opieplayer2/yuv2rgb.c | 446 | ||||
-rw-r--r-- | noncore/multimedia/opieplayer2/yuv2rgb.h | 56 |
8 files changed, 1893 insertions, 689 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,755 +1,1784 @@ -//TOAST_SPU will define ALL spu entries - no matter the tranparency -//#define TOAST_SPU -/* #define PRIV_CLUT */ -/* Currently only blend_yuv(..) works */ /* * * Copyright (C) James Courtier-Dutton James@superbug.demon.co.uk - July 2001 * * Copyright (C) 2000 Thomas Mirlacher + * 2002-2004 the xine project * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * The author may be reached as <dent@linuxvideo.org> * *------------------------------------------------------------ * */ /* #define LOG_BLEND_YUV +#define LOG_BLEND_RGB16 */ #include <string.h> #include <stdlib.h> #include <stdio.h> -#include <inttypes.h> -#include <xine.h> #include <xine/xine_internal.h> #include <xine/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) #define BLEND_BYTE(dst, src, o) (((src)*o + ((dst)*(0xf-o)))/0xf) static void mem_blend16(uint16_t *mem, uint16_t clr, uint8_t o, int len) { uint16_t *limit = mem + len; while (mem < limit) { *mem = BLEND_COLOR(*mem, clr, 0xf800, o) | BLEND_COLOR(*mem, clr, 0x07e0, o) | BLEND_COLOR(*mem, clr, 0x001f, o); mem++; } } 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); mem++; *mem = BLEND_BYTE(*mem, g, o); mem++; *mem = BLEND_BYTE(*mem, b, o); mem++; } } -static void mem_blend24_32(uint8_t *mem, uint8_t r, uint8_t g, uint8_t b, - uint8_t o, int len) { - uint8_t *limit = mem + len*4; - while (mem < limit) { - *mem = BLEND_BYTE(*mem, r, o); - mem++; - *mem = BLEND_BYTE(*mem, g, o); - mem++; - *mem = BLEND_BYTE(*mem, b, o); - mem += 2; - } -} - static void mem_blend32(uint8_t *mem, uint8_t *src, uint8_t o, int len) { uint8_t *limit = mem + len*4; while (mem < limit) { *mem = BLEND_BYTE(*mem, src[0], o); mem++; *mem = BLEND_BYTE(*mem, src[1], o); mem++; *mem = BLEND_BYTE(*mem, src[2], o); mem++; *mem = BLEND_BYTE(*mem, src[3], o); mem++; } } - /* * Some macros for fixed point arithmetic. * * The blend_rgb* routines perform rle image scaling using * scale factors that are expressed as integers scaled with * a factor of 2**16. * * INT_TO_SCALED()/SCALED_TO_INT() converts from integer * to scaled fixed point and back. */ #define SCALE_SHIFT 16 #define SCALE_FACTOR (1<<SCALE_SHIFT) #define INT_TO_SCALED(i) ((i) << SCALE_SHIFT) #define SCALED_TO_INT(sc) ((sc) >> SCALE_SHIFT) static rle_elem_t * rle_img_advance_line(rle_elem_t *rle, rle_elem_t *rle_limit, int w) { int x; for (x = 0; x < w && rle < rle_limit; ) { x += rle->len; rle++; } return rle; } - void blend_rgb16 (uint8_t * img, vo_overlay_t * img_overl, - int img_width, int img_height, - int dst_width, int dst_height) + int img_width, int img_height, + int dst_width, int dst_height, + alphablend_t *extra_data) { uint8_t *trans; - clut_t* clut = (clut_t*) img_overl->clip_color; + clut_t *clut; int src_width = img_overl->width; int src_height = img_overl->height; rle_elem_t *rle = img_overl->rle; + rle_elem_t *rle_start = img_overl->rle; rle_elem_t *rle_limit = rle + img_overl->num_rle; int x, y, x1_scaled, x2_scaled; - int dy, dy_step, x_scale; /* scaled 2**SCALE_SHIFT */ + int dy, dy_step, x_scale; /* scaled 2**SCALE_SHIFT */ int clip_right; uint16_t *img_pix; + int rlelen; + int rle_this_bite; + int rle_remainder; + int zone_state=0; + uint8_t clr_next,clr; + uint16_t o; + double img_offset; + int stripe_height; +/* + * Let zone_state keep state. + * 0 = Starting. + * 1 = Above button. + * 2 = Left of button. + * 3 = Inside of button. + * 4 = Right of button. + * 5 = Below button. + * 6 = Finished. + * + * Each time round the loop, update the state. + * We can do this easily and cheaply(fewer IF statements per cycle) as we are testing rle end position anyway. + * Possible optimization is to ensure that rle never overlaps from outside to inside a button. + * Possible optimization is to pre-scale the RLE overlay, so that no scaling is needed here. + */ - dy_step = INT_TO_SCALED(dst_height) / img_height; - x_scale = INT_TO_SCALED(img_width) / dst_width; +#ifdef LOG_BLEND_RGB16 + printf("blend_rgb16: img_height=%i, dst_height=%i\n", img_height, dst_height); + printf("blend_rgb16: img_width=%i, dst_width=%i\n", img_width, dst_width); + if (img_width & 1) { printf("blend_rgb16s: odd\n");} + else { printf("blend_rgb16s: even\n");} - img_pix = (uint16_t *) img +#endif +/* stripe_height is used in yuv2rgb scaling, so use the same scale factor here for overlays. */ + stripe_height = 16 * img_height / dst_height; +/* dy_step = INT_TO_SCALED(dst_height) / img_height; */ + dy_step = INT_TO_SCALED(16) / stripe_height; + x_scale = INT_TO_SCALED(img_width) / dst_width; +#ifdef LOG_BLEND_RGB16 + printf("blend_rgb16: dy_step=%i, x_scale=%i\n", dy_step, x_scale); +#endif + if (img_width & 1) img_width++; + img_offset = ( ( (img_overl->y * img_height) / dst_height) * img_width) + + ( (img_overl->x * img_width) / dst_width); +#ifdef LOG_BLEND_RGB16 + printf("blend_rgb16: x=%i, y=%i, w=%i, h=%i, img_offset=%lf\n", img_overl->x, img_overl->y, + img_overl->width, + img_overl->height, + img_offset); +#endif + img_pix = (uint16_t *) img + (int)img_offset; +/* + (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 ) 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; - for (y = dy = 0; y < src_height && rle < rle_limit;) { - int mask = !(img_overl->clip_top > y || img_overl->clip_bottom < y); - rle_elem_t *rle_start = rle; + rlelen = rle_remainder = rle_this_bite = 0; + rle_remainder = rlelen = rle->len; + clr_next = rle->color; + rle++; + y = dy = 0; + x = x1_scaled = x2_scaled = 0; - for (x = x1_scaled = 0; x < src_width;) { - uint8_t clr; - uint16_t o; - int rlelen; +#ifdef LOG_BLEND_RGB16 + printf("blend_rgb16 started\n"); +#endif + + while (zone_state != 6) { + clr = clr_next; + switch (zone_state) { + case 0: /* Starting */ + /* FIXME: Get libspudec to set clip_top to -1 if no button */ + if (img_overl->clip_top < 0) { +#ifdef LOG_BLEND_RGB16 + printf("blend_rgb16: No button clip area\n"); +#endif - clr = rle->color; + zone_state = 7; + break; + } +#ifdef LOG_BLEND_RGB16 + printf("blend_rgb16: Button clip area found. (%d,%d) .. (%d,%d)\n", + img_overl->clip_left, + img_overl->clip_top, + img_overl->clip_right, + img_overl->clip_bottom); +#endif + if (y < img_overl->clip_top) { + zone_state = 1; + break; + } 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) { + zone_state = 4; + break; + } else { + zone_state = 3; + break; + } + break; + case 1: /* Above clip area */ + clut = (clut_t*) img_overl->color; + trans = img_overl->trans; 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; - } else { - o = 0; + rle_this_bite = rle_remainder; + rle_remainder = 0; + rlelen -= rle_this_bite; + /*printf("(x,y) = (%03i,%03i), clr=%03x, len=%03i, zone=%i\n", x, y, clr, rle_this_bite, zone_state); */ + if (o) { + x1_scaled = SCALED_TO_INT( x * x_scale ); + x2_scaled = SCALED_TO_INT( (x + rle_this_bite) * x_scale); + mem_blend16(img_pix+x1_scaled, *((uint16_t *)&clut[clr]), o, x2_scaled-x1_scaled); + } + x += rle_this_bite; + if (x >= src_width ) { + x -= src_width; + img_pix += img_width; + + dy += dy_step; + if (dy >= INT_TO_SCALED(1)) { + dy -= INT_TO_SCALED(1); + ++y; + while (dy >= INT_TO_SCALED(1)) { + rle = rle_img_advance_line(rle, rle_limit, src_width); + dy -= INT_TO_SCALED(1); + ++y; } - } else if( clip_right < x + rlelen ) { - if( clip_right > x ) { - x2_scaled = SCALED_TO_INT( clip_right * x_scale); - mem_blend16(img_pix+x1_scaled, *((uint16_t *)&clut[clr]), o, - x2_scaled-x1_scaled); - o = 0; - } else { - o = 0; + rle_start = rle; + } else { + rle = rle_start; /* y-scaling, reuse the last rle encoded line */ + } + } + rle_remainder = rlelen = rle->len; + clr_next = rle->color; + rle++; + if (rle >= rle_limit) { + zone_state = 6; + } + if (y >= img_overl->clip_top) { + zone_state = 2; +#ifdef LOG_BLEND_RGB16 + printf("blend_rgb16: Button clip top reached. y=%i, top=%i\n", + y, img_overl->clip_top); +#endif + if (x >= img_overl->clip_left) { + zone_state = 3; + if (x >= img_overl->clip_right) { + zone_state = 4; } - } + } } - - x2_scaled = SCALED_TO_INT((x + rlelen) * x_scale); - if (o && mask) { - mem_blend16(img_pix+x1_scaled, *((uint16_t *)&clut[clr]), o, x2_scaled-x1_scaled); + break; + case 2: /* Left of button */ + clut = (clut_t*) img_overl->color; + trans = img_overl->trans; + o = trans[clr]; + if (x + rle_remainder <= img_overl->clip_left) { + rle_this_bite = rle_remainder; + rle_remainder = rlelen = rle->len; + clr_next = rle->color; + rle++; + } else { + rle_this_bite = img_overl->clip_left - x; + rle_remainder -= rle_this_bite; + zone_state = 3; } - - x1_scaled = x2_scaled; - x += rlelen; + if (o) { + x1_scaled = SCALED_TO_INT( x * x_scale ); + x2_scaled = SCALED_TO_INT( (x + rle_this_bite) * x_scale); + mem_blend16(img_pix+x1_scaled, *((uint16_t *)&clut[clr]), o, x2_scaled-x1_scaled); + } + x += rle_this_bite; + if (x >= src_width ) { + x -= src_width; + img_pix += img_width; + dy += dy_step; + if (dy >= INT_TO_SCALED(1)) { + dy -= INT_TO_SCALED(1); + ++y; + while (dy >= INT_TO_SCALED(1)) { + rle = rle_img_advance_line(rle, rle_limit, src_width); + dy -= INT_TO_SCALED(1); + ++y; + } + rle_start = rle; + } else { + rle = rle_start; /* y-scaling, reuse the last rle encoded line */ + } + if (y >= img_overl->clip_bottom) { + zone_state = 5; + break; + } + } + if (rle >= rle_limit) { + zone_state = 6; + } + break; + case 3: /* In button */ + clut = (clut_t*) img_overl->clip_color; + trans = img_overl->clip_trans; + o = trans[clr]; + if (x + rle_remainder <= img_overl->clip_right) { + rle_this_bite = rle_remainder; + rle_remainder = rlelen = rle->len; + clr_next = rle->color; + rle++; + } else { + rle_this_bite = img_overl->clip_right - x; + rle_remainder -= rle_this_bite; + zone_state = 4; + } + if (o) { + x1_scaled = SCALED_TO_INT( x * x_scale ); + x2_scaled = SCALED_TO_INT( (x + rle_this_bite) * x_scale); + mem_blend16(img_pix+x1_scaled, *((uint16_t *)&clut[clr]), o, x2_scaled-x1_scaled); + } + x += rle_this_bite; + if (x >= src_width ) { + x -= src_width; + img_pix += img_width; + dy += dy_step; + if (dy >= INT_TO_SCALED(1)) { + dy -= INT_TO_SCALED(1); + ++y; + while (dy >= INT_TO_SCALED(1)) { + rle = rle_img_advance_line(rle, rle_limit, src_width); + dy -= INT_TO_SCALED(1); + ++y; + } + rle_start = rle; + } else { + rle = rle_start; /* y-scaling, reuse the last rle encoded line */ + } + if (y >= img_overl->clip_bottom) { + zone_state = 5; + break; + } + } + if (rle >= rle_limit) { + zone_state = 6; + } + break; + case 4: /* Right of button */ + clut = (clut_t*) img_overl->color; + trans = img_overl->trans; + o = trans[clr]; + if (x + rle_remainder <= src_width) { + rle_this_bite = rle_remainder; + rle_remainder = rlelen = rle->len; + clr_next = rle->color; + rle++; + } else { + rle_this_bite = src_width - x; + rle_remainder -= rle_this_bite; + zone_state = 2; + } + if (o) { + x1_scaled = SCALED_TO_INT( x * x_scale ); + x2_scaled = SCALED_TO_INT( (x + rle_this_bite) * x_scale); + mem_blend16(img_pix+x1_scaled, *((uint16_t *)&clut[clr]), o, x2_scaled-x1_scaled); + } + x += rle_this_bite; + if (x >= src_width ) { + x -= src_width; + img_pix += img_width; + dy += dy_step; + if (dy >= INT_TO_SCALED(1)) { + dy -= INT_TO_SCALED(1); + ++y; + while (dy >= INT_TO_SCALED(1)) { + rle = rle_img_advance_line(rle, rle_limit, src_width); + dy -= INT_TO_SCALED(1); + ++y; + } + rle_start = rle; + } else { + rle = rle_start; /* y-scaling, reuse the last rle encoded line */ + } + if (y >= img_overl->clip_bottom) { + zone_state = 5; + break; + } + } + if (rle >= rle_limit) { + zone_state = 6; + } + break; + case 5: /* Below button */ + clut = (clut_t*) img_overl->color; + trans = img_overl->trans; + o = trans[clr]; + rle_this_bite = rle_remainder; + rle_remainder = 0; + rlelen -= rle_this_bite; + if (o) { + x1_scaled = SCALED_TO_INT( x * x_scale ); + x2_scaled = SCALED_TO_INT( (x + rle_this_bite) * x_scale); + mem_blend16(img_pix+x1_scaled, *((uint16_t *)&clut[clr]), o, x2_scaled-x1_scaled); + } + x += rle_this_bite; + if (x >= src_width ) { + x -= src_width; + img_pix += img_width; + dy += dy_step; + if (dy >= INT_TO_SCALED(1)) { + dy -= INT_TO_SCALED(1); + ++y; + while (dy >= INT_TO_SCALED(1)) { + rle = rle_img_advance_line(rle, rle_limit, src_width); + dy -= INT_TO_SCALED(1); + ++y; + } + rle_start = rle; + } else { + rle = rle_start; /* y-scaling, reuse the last rle encoded line */ + } + } + rle_remainder = rlelen = rle->len; + clr_next = rle->color; rle++; - if (rle >= rle_limit) break; - } + if (rle >= rle_limit) { + zone_state = 6; + } + break; + case 6: /* Finished */ + _x_abort(); - img_pix += img_width; - dy += dy_step; - if (dy >= INT_TO_SCALED(1)) { - dy -= INT_TO_SCALED(1); - ++y; - while (dy >= INT_TO_SCALED(1)) { - rle = rle_img_advance_line(rle, rle_limit, src_width); - dy -= INT_TO_SCALED(1); - ++y; + case 7: /* No button */ + clut = (clut_t*) img_overl->color; + trans = img_overl->trans; + o = trans[clr]; + rle_this_bite = rle_remainder; + rle_remainder = 0; + rlelen -= rle_this_bite; + if (o) { + x1_scaled = SCALED_TO_INT( x * x_scale ); + x2_scaled = SCALED_TO_INT( (x + rle_this_bite) * x_scale); + mem_blend16(img_pix+x1_scaled, *((uint16_t *)&clut[clr]), o, x2_scaled-x1_scaled); } - } else { - rle = rle_start; /* y-scaling, reuse the last rle encoded line */ + x += rle_this_bite; + if (x >= src_width ) { + x -= src_width; + img_pix += img_width; + dy += dy_step; + if (dy >= INT_TO_SCALED(1)) { + dy -= INT_TO_SCALED(1); + ++y; + while (dy >= INT_TO_SCALED(1)) { + rle = rle_img_advance_line(rle, rle_limit, src_width); + dy -= INT_TO_SCALED(1); + ++y; + } + rle_start = rle; + } else { + rle = rle_start; /* y-scaling, reuse the last rle encoded line */ + } + } + rle_remainder = rlelen = rle->len; + clr_next = rle->color; + rle++; + if (rle >= rle_limit) { + zone_state = 6; + } + break; + default: + ; } } +#ifdef LOG_BLEND_RGB16 + printf("blend_rgb16 ended\n"); +#endif + } 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; rle_elem_t *rle_limit = rle + img_overl->num_rle; int x, y, x1_scaled, x2_scaled; int dy, dy_step, x_scale; /* scaled 2**SCALE_SHIFT */ int clip_right; uint8_t *img_pix; dy_step = INT_TO_SCALED(dst_height) / img_height; x_scale = INT_TO_SCALED(img_width) / dst_width; 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; dy += dy_step; if (dy >= INT_TO_SCALED(1)) { dy -= INT_TO_SCALED(1); ++y; while (dy >= INT_TO_SCALED(1)) { rle = rle_img_advance_line(rle, rle_limit, src_width); dy -= INT_TO_SCALED(1); ++y; } } else { rle = rle_start; /* y-scaling, reuse the last rle encoded line */ } } } 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; rle_elem_t *rle_limit = rle + img_overl->num_rle; int x, y, x1_scaled, x2_scaled; int dy, dy_step, x_scale; /* scaled 2**SCALE_SHIFT */ int clip_right; uint8_t *img_pix; dy_step = INT_TO_SCALED(dst_height) / img_height; x_scale = INT_TO_SCALED(img_width) / dst_width; 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_blend24_32(img_pix + x1_scaled*4, 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 + rle_bite) * x_scale); - x2_scaled = SCALED_TO_INT((x + rlelen) * x_scale); - if (o && mask) { - mem_blend24_32(img_pix + x1_scaled*4, clut[clr].cb, - clut[clr].cr, clut[clr].y, - 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; dy += dy_step; if (dy >= INT_TO_SCALED(1)) { dy -= INT_TO_SCALED(1); ++y; while (dy >= INT_TO_SCALED(1)) { rle = rle_img_advance_line(rle, rle_limit, src_width); dy -= INT_TO_SCALED(1); ++y; } } else { rle = rle_start; /* y-scaling, reuse the last rle encoded line */ } } } static void mem_blend8(uint8_t *mem, uint8_t val, uint8_t o, size_t sz) { uint8_t *limit = mem + sz; while (mem < limit) { *mem = BLEND_BYTE(*mem, val, o); mem++; } } +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 ]; + + /* are there any pixels a little bit opaque? */ + 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 ]; + + /* 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++; + } +} + +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_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; int src_width = img_overl->width; int src_height = img_overl->height; rle_elem_t *rle = img_overl->rle; 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; int rlelen; int x, y; int clip_right; uint8_t clr=0; - - uint8_t *dst_y = dst_base[0] + dst_width * y_off + x_off; - uint8_t *dst_cr = dst_base[2] + - (y_off / 2) * (dst_width / 2) + (x_off / 2) + 1; - uint8_t *dst_cb = dst_base[1] + - (y_off / 2) * (dst_width / 2) + (x_off / 2) + 1; + + 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); + 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 my_clut = (clut_t*) img_overl->clip_color; 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_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++) { - 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); #endif 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 if ((rlelen < 0) || (rle_remainder < 0)) { +#ifdef LOG_BLEND_YUV printf("alphablend: major bug in blend_yuv < 0\n"); +#endif } if (rlelen == 0) { rle_remainder = rlelen = rle->len; clr = rle->color; rle++; } if (rle_remainder == 0) { rle_remainder = rlelen; } if ((rle_remainder + x) > src_width) { /* Do something for long rlelengths */ - rle_remainder = src_width - x; - ; + rle_remainder = src_width - x; } #ifdef LOG_BLEND_YUV printf("2:rle_len=%d, remainder=%d, x=%d\n",rlelen, rle_remainder, x); #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; my_trans = img_overl->trans; xmask = 0; } else { #ifdef LOG_BLEND_YUV printf("Outside clip left %d, ending outside\n", img_overl->clip_left); #endif /* no cutting needed, starts outside, ends outside */ rle_this_bite = rle_remainder; rle_remainder = 0; rlelen -= rle_this_bite; my_clut = (clut_t*) img_overl->color; my_trans = img_overl->trans; xmask = 0; } } else if (x < clip_right) { /* Starts inside clip area */ if ((x + rle_remainder) > clip_right ) { #ifdef LOG_BLEND_YUV printf("Inside clip right %d, ending outside\n", clip_right); #endif /* Cutting needed, starts inside, ends outside */ rle_this_bite = (clip_right - x); rle_remainder -= rle_this_bite; rlelen -= rle_this_bite; my_clut = (clut_t*) img_overl->clip_color; my_trans = img_overl->clip_trans; xmask++; } else { #ifdef LOG_BLEND_YUV printf("Inside clip right %d, ending inside\n", clip_right); #endif /* no cutting needed, starts inside, ends inside */ rle_this_bite = rle_remainder; rle_remainder = 0; rlelen -= rle_this_bite; my_clut = (clut_t*) img_overl->clip_color; my_trans = img_overl->clip_trans; 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); #endif /* Cutting needed, starts outside, ends at right edge */ /* It should never reach here due to the earlier test of src_width */ rle_this_bite = (src_width - x ); rle_remainder -= rle_this_bite; rlelen -= rle_this_bite; my_clut = (clut_t*) img_overl->color; my_trans = img_overl->trans; xmask = 0; } else { /* no cutting needed, starts outside, ends outside */ #ifdef LOG_BLEND_YUV printf("Outside clip right %d, ending outside\n", clip_right); #endif rle_this_bite = rle_remainder; rle_remainder = 0; rlelen -= rle_this_bite; my_clut = (clut_t*) img_overl->color; my_trans = img_overl->trans; xmask = 0; } } } else { /* Outside clip are due to y */ /* no cutting needed, starts outside, ends outside */ rle_this_bite = rle_remainder; rle_remainder = 0; rlelen -= rle_this_bite; my_clut = (clut_t*) img_overl->color; my_trans = img_overl->trans; xmask = 0; } o = my_trans[clr]; #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); - } + + 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_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); + 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); + } + } + } else { + mem_blend8(dst_y + x, my_clut[clr].y, o, rle_this_bite); + 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); + } + } + } + + 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 printf("rle_this_bite=%d, remainder=%d, x=%d\n",rle_this_bite, rle_remainder, x); #endif x += rle_this_bite; - if (rle >= rle_limit) { -#ifdef LOG_BLEND_YUV - printf("x-rle_limit\n"); -#endif - break; - } - } - if (rle >= rle_limit) { -#ifdef LOG_BLEND_YUV - printf("x-rle_limit\n"); -#endif - break; } - dst_y += dst_width; + if ((y + y_odd) & 1) { + 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; + } + } + + dst_cr += dst_pitches[2]; + dst_cb += dst_pitches[1]; + } + + dst_y += dst_pitches[0]; + } - if (y & 1) { - dst_cr += (dst_width + 1) / 2; - dst_cb += (dst_width + 1) / 2; + 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); } } + #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_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; int src_width = img_overl->width; int src_height = img_overl->height; rle_elem_t *rle = img_overl->rle; rle_elem_t *rle_limit = rle + img_overl->num_rle; int x_off = img_overl->x; int y_off = img_overl->y; - int mask; + 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; - uint32_t yuy2; + + union { + 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 + 2 * (dst_width * y_off + x_off); + uint8_t *dst_y = dst_img + dst_pitch * y_off + 2 * x_off; uint8_t *dst; my_clut = (clut_t*) img_overl->clip_color; 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++) { - mask = !(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;) { - uint8_t clr; uint16_t o; - int rlelen; - clr = rle->color; - o = my_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 ) { - rlelen -= img_overl->clip_left - x; - x += img_overl->clip_left - x; + if (rle >= rle_limit) + break; + + if ((rlelen < 0) || (rle_remainder < 0)) { +#ifdef LOG_BLEND_YUV + printf("alphablend: major bug in blend_yuv < 0\n"); +#endif + } + if (rlelen == 0) { + rle_remainder = rlelen = rle->len; + clr = rle->color; + rle++; + } + if (rle_remainder == 0) { + rle_remainder = rlelen; + } + if ((rle_remainder + x) > src_width) { + /* Do something for long rlelengths */ + rle_remainder = src_width - x; + } +#ifdef LOG_BLEND_YUV + printf("2:rle_len=%d, remainder=%d, x=%d\n",rlelen, rle_remainder, x); +#endif + + if (ymask == 0) { + if (x < img_overl->clip_left) { + /* Starts outside clip area */ + 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); + rle_remainder -= rle_this_bite; + rlelen -= rle_this_bite; + my_clut = (clut_t*) img_overl->color; + my_trans = img_overl->trans; } else { - o = 0; +#ifdef LOG_BLEND_YUV + printf("Outside clip left %d, ending outside\n", img_overl->clip_left); +#endif + /* no cutting needed, starts outside, ends outside */ + rle_this_bite = rle_remainder; + rle_remainder = 0; + rlelen -= rle_this_bite; + my_clut = (clut_t*) img_overl->color; + my_trans = img_overl->trans; } - } else if( clip_right < x + rlelen ) { - if( clip_right > x ) { - /* fixme: case not implemented */ - o = 0; + } else if (x < clip_right) { + /* Starts inside clip area */ + if ((x + rle_remainder) > clip_right ) { +#ifdef LOG_BLEND_YUV + printf("Inside clip right %d, ending outside\n", clip_right); +#endif + /* Cutting needed, starts inside, ends outside */ + rle_this_bite = (clip_right - x); + rle_remainder -= rle_this_bite; + rlelen -= rle_this_bite; + my_clut = (clut_t*) img_overl->clip_color; + my_trans = img_overl->clip_trans; } else { - o = 0; +#ifdef LOG_BLEND_YUV + printf("Inside clip right %d, ending inside\n", clip_right); +#endif + /* no cutting needed, starts inside, ends inside */ + rle_this_bite = rle_remainder; + rle_remainder = 0; + rlelen -= rle_this_bite; + my_clut = (clut_t*) img_overl->clip_color; + my_trans = img_overl->clip_trans; } - } + } else if (x >= clip_right) { + /* Starts outside clip area, ends outsite clip area */ + if ((x + rle_remainder ) > src_width ) { +#ifdef LOG_BLEND_YUV + printf("Outside clip right %d, ending eol\n", clip_right); +#endif + /* Cutting needed, starts outside, ends at right edge */ + /* It should never reach here due to the earlier test of src_width */ + rle_this_bite = (src_width - x ); + rle_remainder -= rle_this_bite; + rlelen -= rle_this_bite; + my_clut = (clut_t*) img_overl->color; + my_trans = img_overl->trans; + } else { + /* no cutting needed, starts outside, ends outside */ +#ifdef LOG_BLEND_YUV + printf("Outside clip right %d, ending outside\n", clip_right); +#endif + rle_this_bite = rle_remainder; + rle_remainder = 0; + rlelen -= rle_this_bite; + my_clut = (clut_t*) img_overl->color; + my_trans = img_overl->trans; + } + } + } else { + /* Outside clip are due to y */ + /* no cutting needed, starts outside, ends outside */ + rle_this_bite = rle_remainder; + rle_remainder = 0; + rlelen -= rle_this_bite; + my_clut = (clut_t*) img_overl->color; + my_trans = img_overl->trans; } - + o = my_trans[clr]; + + 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 (o && mask) { - l = rlelen>>1; - if( !(x & 1) ) { - yuy2 = my_clut[clr].y + (my_clut[clr].cb << 8) + - (my_clut[clr].y << 16) + (my_clut[clr].cr << 24); + 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 = my_clut[clr].y + (my_clut[clr].cr << 8) + - (my_clut[clr].y << 16) + (my_clut[clr].cb << 24); + dst += rle_this_bite*2; } + } + + x += rle_this_bite; + } + + 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); - if (o >= 15) { - while(l--) { - *((uint32_t *)dst)++ = yuy2; + any_line_buffered = 0; + } + } + + dst_y += dst_pitch; + } +} + +void clear_xx44_palette(xx44_palette_t *p) +{ + register int i; + register uint32_t *cluts = p->cluts; + register int *ids = p->lookup_cache; + + i= p->size; + while(i--) + *cluts++ = 0; + i = 2*OVL_PALETTE_SIZE; + while(i--) + *ids++ = -1; + p->max_used=1; +} + +void init_xx44_palette(xx44_palette_t *p, unsigned num_entries) +{ + p->size = (num_entries > XX44_PALETTE_SIZE) ? XX44_PALETTE_SIZE : num_entries; +} + +void dispose_xx44_palette(xx44_palette_t *p) +{ +} + +static void colorToPalette(const uint32_t *icolor, unsigned char *palette_p, + unsigned num_xvmc_components, char *xvmc_components) +{ + const clut_t *color = (const clut_t *) icolor; + int i; + for (i=0; i<num_xvmc_components; ++i) { + switch(xvmc_components[i]) { + case 'V': *palette_p = color->cr; break; + case 'U': *palette_p = color->cb; break; + case 'Y': + default: *palette_p = color->y; break; + } + *palette_p++; + } +} + + +void xx44_to_xvmc_palette(const xx44_palette_t *p,unsigned char *xvmc_palette, + unsigned first_xx44_entry, unsigned num_xx44_entries, + unsigned num_xvmc_components, char *xvmc_components) +{ + register int i; + register const uint32_t *cluts = p->cluts + first_xx44_entry; + + for (i=0; i<num_xx44_entries; ++i) { + if ((cluts - p->cluts) < p->size) { + colorToPalette(cluts++, xvmc_palette, num_xvmc_components, xvmc_components); + xvmc_palette += num_xvmc_components; + } + } +} + +static int xx44_paletteIndex(xx44_palette_t *p, int color, uint32_t clut) +{ + + register int i; + register uint32_t *cluts = p->cluts; + register int tmp; + + if ((tmp = p->lookup_cache[color]) >= 0) + if (cluts[tmp] == clut) return tmp; + + for (i=0; i<p->max_used; ++i) { + if (*cluts++ == clut) return p->lookup_cache[color] = i; + } + + if (p->max_used == p->size -1) { + printf("video_out: Warning! Out of xx44 palette colors!\n"); + return 1; + } + p->cluts[p->max_used] = clut; + return p->lookup_cache[color] = p->max_used++; +} + +static void memblend_xx44(uint8_t *mem,uint8_t val, register size_t size, uint8_t mask) +{ + register uint8_t masked_val = val & mask; + + while(size--) { + if ((*mem & mask) <= masked_val ) *mem = val; + mem++; + } +} + +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; + int src_height = img_overl->height; + rle_elem_t *rle = img_overl->rle; + rle_elem_t *rle_limit = rle + img_overl->num_rle; + int mask; + int x_off = img_overl->x; + int y_off = img_overl->y; + int x, y; + uint8_t norm_pixel,clip_pixel; + uint8_t *dst_y; + uint8_t *dst; + uint8_t alphamask = (ia44) ? 0x0F : 0xF0; + int clip_right; + + if (!img_overl) + return; + + dst_y = dst_img + dst_pitch*y_off + x_off; + + if( (x_off + img_overl->width) <= dst_width ) + clip_right = img_overl->width; + else + clip_right = dst_width - x_off; + + if ((src_height + y_off) > dst_height) + src_height = dst_height - y_off; + + for (y = 0; y < src_height; 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 : rle->len; + + if (len > 0) { + norm_pixel = (uint8_t)((xx44_paletteIndex(palette,rle->color, + img_overl->color[rle->color]) << 4) | + (img_overl->trans[rle->color] & 0x0F)); + clip_pixel = (uint8_t)((xx44_paletteIndex(palette,rle->color+OVL_PALETTE_SIZE, + img_overl->clip_color[rle->color]) << 4) | + (img_overl->clip_trans[rle->color] & 0x0F)); + if (!ia44) { + norm_pixel = ((norm_pixel & 0x0F) << 4) | ((norm_pixel & 0xF0) >> 4); + clip_pixel = ((clip_pixel & 0x0F) << 4) | ((clip_pixel & 0xF0) >> 4); + } + if (mask) { + if (x < 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) { + memblend_xx44(dst,clip_pixel,len, alphamask); + dst += len; + } else { + memblend_xx44(dst,clip_pixel,img_overl->clip_right - img_overl->clip_left, + alphamask); + 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) { + memblend_xx44(dst,clip_pixel,len, alphamask); + dst += len; + } else { + 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; + } + } else { + memblend_xx44(dst,norm_pixel,len, alphamask); + dst += len; } - if(rlelen & 1) - *((uint16_t *)dst)++ = yuy2 & 0xffff; } else { - if( l ) { - mem_blend32(dst, (uint8_t *)&yuy2, o, l); - dst += 4*l; - } - - if(rlelen & 1) { - *dst = BLEND_BYTE(*dst, *((uint8_t *)&yuy2), o); - dst++; - *dst = BLEND_BYTE(*dst, *((uint8_t *)&yuy2+1), o); - dst++; - } + memblend_xx44(dst,norm_pixel,len, alphamask); + dst += len; } - } else { - dst += rlelen*2; } - - x += rlelen; + x += rle->len; rle++; if (rle >= rle_limit) break; - } + } if (rle >= rle_limit) break; + 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; +} - dst_y += dst_width*2; +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.output.disable_exact_alphablend", 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; } + diff --git a/noncore/multimedia/opieplayer2/alphablend.h b/noncore/multimedia/opieplayer2/alphablend.h index 7230f41..1edb5ba 100644 --- a/noncore/multimedia/opieplayer2/alphablend.h +++ b/noncore/multimedia/opieplayer2/alphablend.h @@ -1,57 +1,134 @@ /* * * Copyright (C) 2000 Thomas Mirlacher * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * The author may be reached as <dent@linuxvideo.org> * *------------------------------------------------------------ * */ #ifndef __ALPHABLEND_H__ #define __ALPHABLEND_H__ #include <xine/video_out.h> +typedef struct { + void *buffer; + int buffer_size; + + int disable_exact_blending; +} alphablend_t; + +void _x_alphablend_init(alphablend_t *extra_data, xine_t *xine); +void _x_alphablend_free(alphablend_t *extra_data); + +/* _MSC_VER port changes */ +#undef ATTRIBUTE_PACKED +#undef PRAGMA_PACK_BEGIN +#undef PRAGMA_PACK_END + +#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95) || defined(__ICC) +#define ATTRIBUTE_PACKED __attribute__ ((packed)) +#define PRAGMA_PACK 0 +#endif + +#if !defined(ATTRIBUTE_PACKED) +#define ATTRIBUTE_PACKED +#define PRAGMA_PACK 1 +#endif + +#if PRAGMA_PACK +#pragma pack(8) +#endif + typedef struct { /* CLUT == Color LookUp Table */ uint8_t cb : 8; uint8_t cr : 8; uint8_t y : 8; uint8_t foo : 8; -} __attribute__ ((packed)) clut_t; +} ATTRIBUTE_PACKED clut_t; + + +#if PRAGMA_PACK +#pragma pack() +#endif + +#define XX44_PALETTE_SIZE 32 + +typedef struct { + unsigned size; + unsigned max_used; + uint32_t cluts[XX44_PALETTE_SIZE]; + /* cache palette entries for both colors and clip_colors */ + int lookup_cache[OVL_PALETTE_SIZE*2]; +} xx44_palette_t; + 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); 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); 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); void blend_yuv (uint8_t *dst_base[3], vo_overlay_t * img_overl, - int dst_width, int dst_height); + int dst_width, int dst_height, int dst_pitches[3], + alphablend_t *extra_data); void blend_yuy2 (uint8_t * dst_img, vo_overlay_t * img_overl, - int dst_width, int dst_height); + int dst_width, int dst_height, int dst_pitch, + alphablend_t *extra_data); + +/* + * This function isn't too smart about blending. We want to avoid creating new + * colors in the palette as a result from two non-zero colors needed to be + * blended. Instead we choose the color with the highest alpha value to be + * visible. Some parts of the code taken from the "VeXP" project. + */ + +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); + +/* + * Functions to handle the xine-specific palette. + */ + +void clear_xx44_palette(xx44_palette_t *p); +void init_xx44_palette(xx44_palette_t *p, unsigned num_entries); +void dispose_xx44_palette(xx44_palette_t *p); + +/* + * Convert the xine-specific palette to something useful. + */ + +void xx44_to_xvmc_palette(const xx44_palette_t *p,unsigned char *xvmc_palette, + unsigned first_xx44_entry, unsigned num_xx44_entries, + unsigned num_xvmc_components, char *xvmc_components); -void crop_overlay (vo_overlay_t * overlay); #endif diff --git a/noncore/multimedia/opieplayer2/lib.cpp b/noncore/multimedia/opieplayer2/lib.cpp index 4ae8490..84d28ce 100644 --- a/noncore/multimedia/opieplayer2/lib.cpp +++ b/noncore/multimedia/opieplayer2/lib.cpp @@ -1,471 +1,491 @@ /* This file is part of the Opie Project Copyright (c) 2002 Max Reiss <harlekin@handhelds.org> Copyright (c) 2002 LJP <> Copyright (c) 2002 Holger Freyther <zecke@handhelds.org> =. .=l. .>+-= _;:, .> :=|. This program is free software; you can .> <`_, > . <= redistribute it and/or modify it under :`=1 )Y*s>-.-- : the terms of the GNU General Public .="- .-=="i, .._ License as published by the Free Software - . .-<_> .<> Foundation; either version 2 of the License, ._= =} : or (at your option) any later version. .%`+i> _;_. .i_,=:_. -<s. This program is distributed in the hope that + . -:. = it will be useful, but WITHOUT ANY WARRANTY; : .. .:, . . . without even the implied warranty of =_ + =;=|` MERCHANTABILITY or FITNESS FOR A _.=:. : :=>`: PARTICULAR PURPOSE. See the GNU ..}^=.= = ; Library General Public License for more ++= -. .` .: details. : = ...= . :.=- -. .:....=;==+<; You should have received a copy of the GNU -_. . . )=. = Library General Public License along with -- :-=` this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "xinevideowidget.h" #include "lib.h" /* OPIE */ #include <opie2/odebug.h> #include <qpe/global.h> /* QT */ #include <qtextstream.h> #include <qdir.h> #include <qgfx_qws.h> /* STD */ #include <assert.h> #include <unistd.h> typedef void (*display_xine_frame_t) (void *user_data, uint8_t* frame, int width, int height,int bytes ); +typedef void (*vo_scale_cb) (void*, int, int, double, + int*, int*, int*, int*, double*, int*, int* ); +typedef void (*dest_size_cb) (void*, int, int, double, int*, int*, double*); + extern "C" { - xine_vo_driver_t* init_video_out_plugin( xine_t *xine, void* video, display_xine_frame_t, void * ); + xine_vo_driver_t* init_video_out_plugin( xine_t *xine, void* video, display_xine_frame_t, void *, vo_scale_cb, dest_size_cb ); int null_is_showing_video( const xine_vo_driver_t* self ); void null_set_show_video( const xine_vo_driver_t* self, int show ); - int null_is_fullscreen( const xine_vo_driver_t* self ); - void null_set_fullscreen( const xine_vo_driver_t* self, int screen ); - int null_is_scaling( const xine_vo_driver_t* self ); - void null_set_scaling( const xine_vo_driver_t* self, int scale ); - void null_set_gui_width( const xine_vo_driver_t* self, int width ); - void null_set_gui_height( const xine_vo_driver_t* self, int height ); void null_set_mode( const xine_vo_driver_t* self, int depth, int rgb ); - void null_set_videoGamma( const xine_vo_driver_t* self , int value ); void null_display_handler( const xine_vo_driver_t* self, display_xine_frame_t t, void* user_data ); - - void null_preload_decoders( xine_stream_t *stream ); } using namespace XINE; Lib::Lib( InitializationMode initMode, XineVideoWidget* widget ) { m_initialized = false; m_duringInitialization = false; m_video = false; m_wid = widget; printf("Lib"); QString configPath = QDir::homeDirPath() + "/Settings/opiexine.cf"; // get the configuration // not really OO, should be an extra class, later if ( !QFile::exists(configPath) ) { QFile f(configPath); f.open(IO_WriteOnly); QTextStream ts( &f ); ts << "misc.memcpy_method:glibc\n"; ts << "# uncomment if you experience double speed audio \n #audio.oss_sync_method:softsync\n"; ts << "codec.ffmpeg_pp_quality:3\n"; ts << "audio.num_buffers:50\n"; ts << "audio.size_buffers:4096\n"; ts << "video.num_buffers:20\n"; ts << "video.size_buffers:4096\n"; ts << "audio.out_num_audio_buf:16\n"; ts << "audio.out_size_audio_buf:8096\n"; ts << "audio.out_size_zero_buf:1024\n"; ts << "audio.passthrough_offset:0\n"; f.close(); } if ( initMode == InitializeImmediately ) { initialize(); m_initialized = true; } else start(); } void Lib::run() { odebug << "Lib::run() started" << oendl; initialize(); m_initialized = true; odebug << "Lib::run() finished" << oendl; } void Lib::initialize() { m_duringInitialization = true; m_xine = xine_new( ); QString configPath = QDir::homeDirPath() + "/Settings/opiexine.cf"; xine_config_load( m_xine, QFile::encodeName( configPath ) ); xine_init( m_xine ); // allocate oss for sound // and fb for framebuffer m_audioOutput = xine_open_audio_driver( m_xine, "oss", NULL ); - m_videoOutput = ::init_video_out_plugin( m_xine, NULL, xine_display_frame, this ); + m_videoOutput = ::init_video_out_plugin( m_xine, NULL, + xine_display_frame, this, + xine_vo_scale_cb, + xine_dest_cb ); m_stream = xine_stream_new (m_xine, m_audioOutput, m_videoOutput ); xine_set_param( m_stream, XINE_PARAM_AUDIO_CLOSE_DEVICE, 1); if (m_wid != 0 ) setWidget( m_wid ); m_queue = xine_event_new_queue (m_stream); xine_event_create_listener_thread (m_queue, xine_event_handler, this); - ::null_preload_decoders( m_stream ); - m_duringInitialization = false; } Lib::~Lib() { assert( isRunning() == false ); assert( m_initialized ); // free( m_config ); xine_close( m_stream ); xine_event_dispose_queue( m_queue ); xine_dispose( m_stream ); xine_close_audio_driver(m_xine,m_audioOutput); xine_close_video_driver(m_xine,m_videoOutput); xine_exit( m_xine ); /* FIXME either free or delete but valgrind bitches against both */ //free( m_videoOutput ); //delete m_audioOutput; } void Lib::resize ( const QSize &s ) { assert( m_initialized || m_duringInitialization ); - if ( s. width ( ) && s. height ( ) ) { - ::null_set_gui_width( m_videoOutput, s. width() ); - ::null_set_gui_height( m_videoOutput, s. height() ); - } + if ( s. width ( ) && s. height ( ) ) + m_videoSize = s; } int Lib::majorVersion() { int major, minor, sub; xine_get_version ( &major, &minor, &sub ); return major; } int Lib::minorVersion() { int major, minor, sub; xine_get_version ( &major, &minor, &sub ); return minor; } int Lib::subVersion() { int major, minor, sub; xine_get_version ( &major, &minor, &sub ); return sub; } int Lib::setfile(const QString& fileName) { QString str = fileName.stripWhiteSpace(); if ( !xine_open( m_stream, str.utf8().data() ) ) { return 0; } return 1; } int Lib::play( const QString& fileName, int startPos, int start_time ) { assert( m_initialized ); QString str = fileName.stripWhiteSpace(); if ( !xine_open( m_stream, str.utf8().data() ) ) { return 0; } return xine_play( m_stream, startPos, start_time); } void Lib::stop() { assert( m_initialized ); xine_stop( m_stream ); xine_set_param( m_stream, XINE_PARAM_AUDIO_CLOSE_DEVICE, 1); } void Lib::pause( bool toggle ) { assert( m_initialized ); if ( toggle ) { xine_set_param( m_stream, XINE_PARAM_SPEED, XINE_SPEED_PAUSE ); xine_set_param( m_stream, XINE_PARAM_AUDIO_CLOSE_DEVICE, 1); } else { xine_set_param( m_stream, XINE_PARAM_SPEED, XINE_SPEED_NORMAL ); } } int Lib::speed() const { assert( m_initialized ); return xine_get_param ( m_stream, XINE_PARAM_SPEED ); } void Lib::setSpeed( int speed ) { assert( m_initialized ); xine_set_param ( m_stream, XINE_PARAM_SPEED, speed ); } int Lib::status() const { assert( m_initialized ); return xine_get_status( m_stream ); } int Lib::currentPosition() const { assert( m_initialized ); int pos, time, length; xine_get_pos_length( m_stream, &pos, &time, &length ); return pos; } int Lib::currentTime() const { assert( m_initialized ); int pos, time, length; pos = time = length = 0; if ( xine_get_pos_length( m_stream, &pos, &time, &length ) ) return time/1000; else return 0; } int Lib::length() const { assert( m_initialized ); int pos, time, length; /* dilb: patch to solve the wrong stream length reported to the GUI*/ int iRetVal=0, iTestLoop=0; do { iRetVal = xine_get_pos_length( m_stream, &pos, &time, &length ); if (iRetVal) {/* if the function didn't return 0, then pos, time and length are valid.*/ return length/1000; } /*don't poll too much*/ usleep(100000); iTestLoop++; } while ( iTestLoop < 10 ); /* if after 1s, we still don't have any valid stream, then return -1 (this value could be used to make the stream unseekable, but it should never occur!! Mr. Murphy ? :) ) */ return -1; } /* info about current stream */ QSize Lib::videoSize()const { if (!m_initialized||!hasVideo()) return QSize(0,0); int width = xine_get_stream_info(m_stream,XINE_STREAM_INFO_VIDEO_WIDTH); int height = xine_get_stream_info(m_stream,XINE_STREAM_INFO_VIDEO_HEIGHT); return QSize(width,height); } bool Lib::isSeekable() const { assert( m_initialized ); return xine_get_stream_info( m_stream, XINE_STREAM_INFO_SEEKABLE ); } bool Lib::hasVideo() const { assert( m_initialized ); return xine_get_stream_info( m_stream, XINE_STREAM_INFO_HAS_VIDEO); } int Lib::audioBitrate()const { if (!m_initialized) return 0; return xine_get_stream_info( m_stream, XINE_STREAM_INFO_AUDIO_BITRATE); } int Lib::videoBitrate()const { if (!m_initialized||!hasVideo()) return 0; return xine_get_stream_info( m_stream, XINE_STREAM_INFO_VIDEO_BITRATE); } /* end info block */ void Lib::seekTo( int time ) { assert( m_initialized ); odebug << "Seeking to second " << time << oendl; //Keep it paused if it was in that state if ( xine_get_param( m_stream, XINE_PARAM_SPEED ) ) { xine_play( m_stream, 0, time*1000 ); } else { xine_play( m_stream, 0, time*1000 ); xine_set_param( m_stream, XINE_PARAM_SPEED, XINE_SPEED_PAUSE ); } } QString Lib::metaInfo( int number) const { assert( m_initialized ); return xine_get_meta_info( m_stream, number ); } int Lib::error() const { assert( m_initialized ); return xine_get_error( m_stream ); }; void Lib::ensureInitialized() { if ( m_initialized ) return; odebug << "waiting for initialization thread to finish" << oendl; wait(); odebug << "initialization thread finished!" << oendl; } void Lib::setWidget( XineVideoWidget *widget ) { m_wid = widget; if (m_wid) { resize ( m_wid-> size ( ) ); ::null_set_mode( m_videoOutput, qt_screen->depth(), qt_screen->pixelType() ); } } void Lib::receiveMessage( ThreadUtil::ChannelMessage *msg, SendType sendType ) { assert( sendType == ThreadUtil::Channel::OneWay ); handleXineEvent( msg->type(), msg->data(), msg->msg() ); delete msg; } void Lib::handleXineEvent( const xine_event_t* t ) { int prog = -1; const char* name = 0; if ( t->type == XINE_EVENT_PROGRESS ) { xine_progress_data_t *pt = static_cast<xine_progress_data_t*>( t->data ); prog = pt->percent; name = pt->description; } send( new ThreadUtil::ChannelMessage( t->type, prog, name ), OneWay ); } void Lib::handleXineEvent( int type, int data, const char* name ) { assert( m_initialized ); if ( type == XINE_EVENT_UI_PLAYBACK_FINISHED ) { emit stopped(); }else if ( type == XINE_EVENT_PROGRESS ) { QString str = name == 0 ? QString::null : QString::fromUtf8( name ); Global::statusMessage( tr( "Progress: %1 %2" ).arg( name, data ) );; } } void Lib::setShowVideo( bool video ) { assert( m_initialized ); m_video = video; ::null_set_show_video( m_videoOutput, video ); } bool Lib::isShowingVideo() const { assert( m_initialized ); return ::null_is_showing_video( m_videoOutput ); } void Lib::showVideoFullScreen( bool fullScreen ) { assert( m_initialized ); - ::null_set_fullscreen( m_videoOutput, fullScreen ); + #warning use xine } bool Lib::isVideoFullScreen() const { assert( m_initialized ); - return ::null_is_fullscreen( m_videoOutput ); + #warning use xine + return false; } void Lib::setScaling( bool scale ) { assert( m_initialized ); - ::null_set_scaling( m_videoOutput, scale ); + xine_set_param( m_stream, XINE_PARAM_VO_ASPECT_RATIO, + scale ? XINE_VO_ASPECT_AUTO : XINE_VO_ASPECT_SQUARE ); } void Lib::setGamma( int value ) { assert( m_initialized ); - - ::null_set_videoGamma( m_videoOutput, value ); + xine_set_param( m_stream, XINE_PARAM_VO_BRIGHTNESS, value ); } bool Lib::isScaling() const { assert( m_initialized ); - return ::null_is_scaling( m_videoOutput ); + int aratio = xine_get_param( m_stream, XINE_PARAM_VO_ASPECT_RATIO ); + return aratio == XINE_VO_ASPECT_AUTO; } void Lib::xine_event_handler( void* user_data, const xine_event_t* t ) { ( (Lib*)user_data)->handleXineEvent( t ); } void Lib::xine_display_frame( void* user_data, uint8_t *frame, int width, int height, int bytes ) { ( (Lib*)user_data)->drawFrame( frame, width, height, bytes ); } +void Lib::xine_vo_scale_cb( void *user_data, int video_with, int video_height, + double video_pixel_aspect, + int *dest_x, int *dest_y, int *dest_width, + int *dest_height, double *dest_pixel_aspect, + int *win_x, int *win_y ) { + QSize size = ((Lib*)user_data)->m_videoSize; + if (!size.isValid()) + return; + + *dest_x = 0; + *dest_y = 0; + *dest_width = size.width(); + *dest_height = size.height(); + *win_x = 0; + *win_y = 0; +} + +void Lib::xine_dest_cb( void* user_data, int, int, double, + int *dest_width, int* dest_height, double* ) { + QSize size = ((Lib*)user_data)->m_videoSize; + if ( !size.isValid() ) + return; + + *dest_width = size.width(); + *dest_height = size.height(); +} + void Lib::drawFrame( uint8_t* frame, int width, int height, int bytes ) { assert( m_initialized ); - if ( !m_video ) { + if ( !m_video ) return; - } - -// assert( m_wid ); if (m_wid) m_wid-> setVideoFrame ( frame, width, height, bytes ); } diff --git a/noncore/multimedia/opieplayer2/lib.h b/noncore/multimedia/opieplayer2/lib.h index 2607193..a6ac033 100644 --- a/noncore/multimedia/opieplayer2/lib.h +++ b/noncore/multimedia/opieplayer2/lib.h @@ -1,215 +1,219 @@ /* This file is part of the Opie Project Copyright (c) 2002 Max Reiss <harlekin@handhelds.org> Copyright (c) 2002 LJP <> Copyright (c) 2002 Holger Freyther <zecke@handhelds.org> =. .=l. .>+-= _;:, .> :=|. This program is free software; you can .> <`_, > . <= redistribute it and/or modify it under :`=1 )Y*s>-.-- : the terms of the GNU General Public .="- .-=="i, .._ License as published by the Free Software - . .-<_> .<> Foundation; either version 2 of the License, ._= =} : or (at your option) any later version. .%`+i> _;_. .i_,=:_. -<s. This program is distributed in the hope that + . -:. = it will be useful, but WITHOUT ANY WARRANTY; : .. .:, . . . without even the implied warranty of =_ + =;=|` MERCHANTABILITY or FITNESS FOR A _.=:. : :=>`: PARTICULAR PURPOSE. See the GNU ..}^=.= = ; Library General Public License for more ++= -. .` .: details. : = ...= . :.=- -. .:....=;==+<; You should have received a copy of the GNU -_. . . )=. = Library General Public License along with -- :-=` this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef XINE_VIDEO_LIB_H #define XINE_VIDEO_LIB_H #include <xine.h> #include "threadutil.h" class XineVideoWidget; namespace XINE { /** * Lib wrapps the simple interface * of libxine for easy every day use * This will become a full C++ Wrapper * It supports playing, pausing, info, * stooping, seeking. */ class Lib : public ThreadUtil::Channel, private ThreadUtil::Thread { Q_OBJECT public: enum InitializationMode { InitializeImmediately, InitializeInThread }; Lib( InitializationMode initMode, XineVideoWidget* = 0); ~Lib(); static int majorVersion(); static int minorVersion(); static int subVersion(); void resize ( const QSize &s ); int setfile(const QString& fileName); int play( const QString& fileName, int startPos = 0, int start_time = 0 ); void stop(); void pause( bool toggle ); int speed() const; /** * Set the speed of the stream, if codec supports it * XINE_SPEED_PAUSE 0 * XINE_SPEED_SLOW_4 1 * XINE_SPEED_SLOW_2 2 * XINE_SPEED_NORMAL 4 * XINE_SPEED_FAST_2 8 *XINE_SPEED_FAST_4 16 */ void setSpeed( int speed = XINE_SPEED_PAUSE ); int status() const; int currentPosition()const; //in seconds int currentTime()const; int length() const; bool isSeekable()const; /** * Whether or not to show video output */ void setShowVideo(bool video); /** * is we show video */ bool isShowingVideo() const; /** * */ void showVideoFullScreen( bool fullScreen ); /** * */ bool isVideoFullScreen() const; /** * Get the meta info (like author etc) from the stream * XINE_META_INFO_TITLE 0 * XINE_META_INFO_COMMENT 1 * XINE_META_INFO_ARTIST 2 * XINE_META_INFO_GENRE 3 * XINE_META_INFO_ALBUM 4 * XINE_META_INFO_YEAR 5 * XINE_META_INFO_VIDEOCODEC 6 * XINE_META_INFO_AUDIOCODEC 7 * XINE_META_INFO_SYSTEMLAYER 8 * XINE_META_INFO_INPUT_PLUGIN 9 */ QString metaInfo( int number ) const; /** * */ bool isScaling() const; /** * seek to a position */ void seekTo( int time ); /** * * @return is media stream has video */ bool hasVideo() const; /** * */ void setScaling( bool ); /** * Set the Gamma value for video output * @param int the value between -100 and 100, 0 is original */ void setGamma( int ); /** * Returns the error code * XINE_ERROR_NONE 0 * XINE_ERROR_NO_INPUT_PLUGIN 1 * XINE_ERROR_NO_DEMUXER_PLUGIN 2 * XINE_ERROR_DEMUXER_FAILED 3 */ int error() const; void ensureInitialized(); void setWidget( XineVideoWidget *widget ); QSize videoSize()const; int audioBitrate()const; int videoBitrate()const; signals: void stopped(); void initialized(); protected: virtual void receiveMessage( ThreadUtil::ChannelMessage *msg, SendType sendType ); virtual void run(); private: - void initialize(); - - int m_bytes_per_pixel; - bool m_initialized:1; - bool m_duringInitialization:1; - bool m_video:1; - XineVideoWidget *m_wid; - xine_t *m_xine; - xine_stream_t *m_stream; - xine_cfg_entry_t *m_config; - xine_vo_driver_t *m_videoOutput; - xine_ao_driver_t* m_audioOutput; - xine_event_queue_t *m_queue; - - void handleXineEvent( const xine_event_t* t ); - void handleXineEvent( int type, int data, const char* name ); - void drawFrame( uint8_t* frame, int width, int height, int bytes ); + void initialize(); + + int m_bytes_per_pixel; + bool m_initialized:1; + bool m_duringInitialization:1; + bool m_video:1; + XineVideoWidget *m_wid; + QSize m_videoSize; + xine_t *m_xine; + xine_stream_t *m_stream; + xine_cfg_entry_t *m_config; + xine_vo_driver_t *m_videoOutput; + xine_ao_driver_t* m_audioOutput; + xine_event_queue_t *m_queue; + + void handleXineEvent( const xine_event_t* t ); + void handleXineEvent( int type, int data, const char* name ); + void drawFrame( uint8_t* frame, int width, int height, int bytes ); // C -> C++ bridge for the event system static void xine_event_handler( void* user_data, const xine_event_t* t); static void xine_display_frame( void* user_data, uint8_t* frame , - int width, int height, int bytes ); + int width, int height, int bytes ); + static void xine_vo_scale_cb(void *, int, int, double, + int*,int*,int*,int*,double*,int*,int*); + static void xine_dest_cb(void*,int,int,double,int*,int*,double*); }; }; #endif diff --git a/noncore/multimedia/opieplayer2/mainTest.cpp b/noncore/multimedia/opieplayer2/mainTest.cpp deleted file mode 100644 index e374c89..0000000 --- a/noncore/multimedia/opieplayer2/mainTest.cpp +++ b/dev/null @@ -1,16 +0,0 @@ - -#include <stdlib.h> -#include <stdio.h> -#include <unistd.h> - -#include "lib.h" - -int main( int argc, char *argv[] ) { - printf("FixME\n"); - //return 0; - XINE::Lib lib; - QString str = QString::fromLatin1( argv[1] ); - lib.play( str ); - for (;;) sleep( 60 ); - return 0; -} diff --git a/noncore/multimedia/opieplayer2/nullvideo.c b/noncore/multimedia/opieplayer2/nullvideo.c index 6769a37..99fa329 100644 --- a/noncore/multimedia/opieplayer2/nullvideo.c +++ b/noncore/multimedia/opieplayer2/nullvideo.c @@ -1,735 +1,695 @@ /* This file is part of the Opie Project Copyright (c) 2002 Max Reiss <harlekin@handhelds.org> - Copyright (c) 2002 LJP <> Copyright (c) 2002 Holger Freyther <zecke@handhelds.org> Copyright (c) 2002-2003 Miguel Freitas of xine =. .=l. .>+-= _;:, .> :=|. This program is free software; you can .> <`_, > . <= redistribute it and/or modify it under :`=1 )Y*s>-.-- : the terms of the GNU General Public .="- .-=="i, .._ License as published by the Free Software - . .-<_> .<> Foundation; either version 2 of the License, ._= =} : or (at your option) any later version. .%`+i> _;_. .i_,=:_. -<s. This program is distributed in the hope that + . -:. = it will be useful, but WITHOUT ANY WARRANTY; : .. .:, . . . without even the implied warranty of =_ + =;=|` MERCHANTABILITY or FITNESS FOR A _.=:. : :=>`: PARTICULAR PURPOSE. See the GNU ..}^=.= = ; Library General Public License for more ++= -. .` .: details. : = ...= . :.=- -. .:....=;==+<; You should have received a copy of the GNU -_. . . )=. = Library General Public License along with -- :-=` this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include <stdlib.h> #include <stdio.h> #include <math.h> #include <xine.h> #include <xine/video_out.h> #include <xine/xine_internal.h> -//#include <xine/xineutils.h> #include <xine/vo_scale.h> #include <xine/buffer.h> #include <pthread.h> #include "alphablend.h" #include "yuv2rgb.h" #define printf(x,...) /* -#define LOG -*/ + * #define LOG + */ /* the caller for our event draw handler */ typedef void (*display_xine_frame_t) (void *user_data, uint8_t* frame, - int width, int height,int bytes ); + int width, int height,int bytes ); +typedef void (*vo_scale_cb) (void*, int, int, double, + int*, int*, int*, double*, int*, int* ); +typedef void (*dest_size_cb) (void*, int, int, double, int*, int*, double*); + typedef struct null_driver_s null_driver_t; struct null_driver_s { vo_driver_t vo_driver; - uint32_t m_capabilities; int m_show_video; int m_video_fullscreen; - int m_is_scaling; int depth, bpp, bytes_per_pixel; int yuv2rgb_mode; int yuv2rgb_swap; - int yuv2rgb_gamma; + int yuv2rgb_brightness; uint8_t *yuv2rgb_cmap; yuv2rgb_factory_t *yuv2rgb_factory; vo_overlay_t *overlay; - vo_scale_t sc; - - int gui_width; - int gui_height; - int gui_changed; + vo_scale_t sc; - double display_ratio; - void* caller; + /* + * DISPLAY to widget... + */ display_xine_frame_t frameDis; + void *userData; + + xine_t *xine; + alphablend_t alphablend_extra_data; }; typedef struct opie_frame_s opie_frame_t; struct opie_frame_s { vo_frame_t frame; int format; int flags; vo_scale_t sc; uint8_t *chunk[3]; uint8_t *data; /* rgb */ int bytes_per_line; yuv2rgb_t *yuv2rgb; uint8_t *rgb_dst; int yuv_stride; int stripe_height, stripe_inc; - + null_driver_t *output; }; static uint32_t null_get_capabilities( vo_driver_t *self ){ - null_driver_t* this = (null_driver_t*)self; - return this->m_capabilities; + self = self; + return VO_CAP_YUY2 | VO_CAP_YV12; } static void null_frame_proc_slice (vo_frame_t *vo_img, uint8_t **src) { opie_frame_t *frame = (opie_frame_t *) vo_img ; vo_img->proc_called = 1; - if (!frame->output->m_show_video) { - /* printf("nullvideo: no video\n"); */ + /* + * drop hard if we don't show the video + */ + if (!frame->output->m_show_video) + return; + + if( frame->frame.crop_left || frame->frame.crop_top || + frame->frame.crop_right || frame->frame.crop_bottom ) + { + /* we don't support crop, so don't even waste cpu cycles. + * cropping will be performed by video_out.c + */ return; } if (frame->format == XINE_IMGFMT_YV12) { frame->yuv2rgb->yuv2rgb_fun (frame->yuv2rgb, frame->rgb_dst, src[0], src[1], src[2]); } else { frame->yuv2rgb->yuy22rgb_fun (frame->yuv2rgb, frame->rgb_dst, src[0]); } frame->rgb_dst += frame->stripe_inc; } static void null_frame_field (vo_frame_t *vo_img, int which_field) { opie_frame_t *frame = (opie_frame_t *) vo_img ; switch (which_field) { case VO_TOP_FIELD: - frame->rgb_dst = (uint8_t *)frame->data; + frame->rgb_dst = frame->data; frame->stripe_inc = 2*frame->stripe_height * frame->bytes_per_line; break; case VO_BOTTOM_FIELD: - frame->rgb_dst = (uint8_t *)frame->data + frame->bytes_per_line ; + frame->rgb_dst = frame->data + frame->bytes_per_line ; frame->stripe_inc = 2*frame->stripe_height * frame->bytes_per_line; break; case VO_BOTH_FIELDS: - frame->rgb_dst = (uint8_t *)frame->data; + frame->rgb_dst = frame->data; break; } } /* take care of the frame*/ static void null_frame_dispose( vo_frame_t* vo_img){ opie_frame_t* frame = (opie_frame_t*)vo_img; if (frame->data) free( frame->data ); free (frame); } /* end take care of frames*/ static vo_frame_t* null_alloc_frame( vo_driver_t* self ){ null_driver_t* this = (null_driver_t*)self; opie_frame_t* frame; #ifdef LOG fprintf (stderr, "nullvideo: alloc_frame\n"); #endif frame = (opie_frame_t*)xine_xmalloc ( sizeof(opie_frame_t) ); + if(!frame) + return NULL; memcpy (&frame->sc, &this->sc, sizeof(vo_scale_t)); pthread_mutex_init (&frame->frame.mutex, NULL); frame->output = this; /* initialize the frame*/ frame->frame.driver = self; frame->frame.proc_slice = null_frame_proc_slice; + frame->frame.proc_frame = NULL; frame->frame.field = null_frame_field; frame->frame.dispose = null_frame_dispose; /* * colorspace converter for this frame */ frame->yuv2rgb = this->yuv2rgb_factory->create_converter (this->yuv2rgb_factory); return (vo_frame_t*) frame; } -static void null_frame_compute_ideal_size( null_driver_t *this, +static void null_frame_compute_ideal_size( null_driver_t *this, opie_frame_t *frame ) { this = this; _x_vo_scale_compute_ideal_size(&frame->sc); } static void null_frame_compute_rgb_size( null_driver_t *this, opie_frame_t *frame ){ this = this; _x_vo_scale_compute_output_size(&frame->sc); /* avoid problems in yuv2rgb */ if(frame->sc.output_height < (frame->sc.delivered_height+15) >> 4) frame->sc.output_height = (frame->sc.delivered_height+15) >> 4; if (frame->sc.output_width < 8) frame->sc.output_width = 8; /* yuv2rgb_mlib needs an even YUV2 width */ if (frame->sc.output_width & 1) frame->sc.output_width++; } static void null_frame_reallocate( null_driver_t *this, opie_frame_t *frame, uint32_t width, uint32_t height, int format){ /* * (re-) allocate */ - if( frame->data ) { - if( frame->chunk[0] ){ - free( frame->chunk[0] ); - frame->chunk[0] = NULL; - } - if( frame->chunk[1] ){ - free ( frame->chunk[1] ); - frame->chunk[1] = NULL; - } - if( frame->chunk[2] ){ - free ( frame->chunk[2] ); - frame->chunk[2] = NULL; - } - free ( frame->data ); + if( frame->chunk[0] ){ + free( frame->chunk[0] ); + frame->chunk[0] = NULL; + } + if( frame->chunk[1] ){ + free ( frame->chunk[1] ); + frame->chunk[1] = NULL; } + if( frame->chunk[2] ){ + free ( frame->chunk[2] ); + frame->chunk[2] = NULL; + } + if(frame->data) + free ( frame->data ); - frame->data = xine_xmalloc (frame->sc.output_width + frame->data = xine_xmalloc (frame->sc.output_width * frame->sc.output_height * this->bytes_per_pixel ); if( format == XINE_IMGFMT_YV12 ) { frame->frame.pitches[0] = 8*((width + 7) / 8); frame->frame.pitches[1] = 8*((width + 15) / 16); frame->frame.pitches[2] = 8*((width + 15) / 16); frame->frame.base[0] = xine_xmalloc_aligned (16, frame->frame.pitches[0] * height,(void **)&frame->chunk[0]); frame->frame.base[1] = xine_xmalloc_aligned (16, frame->frame.pitches[1] * ((height+ 1)/2), (void **)&frame->chunk[1]); frame->frame.base[2] = xine_xmalloc_aligned (16, frame->frame.pitches[2] * ((height+ 1)/2), (void **)&frame->chunk[2]); }else{ frame->frame.pitches[0] = 8*((width + 3) / 4); frame->frame.base[0] = xine_xmalloc_aligned (16, frame->frame.pitches[0] * height, (void **)&frame->chunk[0]); frame->chunk[1] = NULL; frame->chunk[2] = NULL; } } static void null_setup_colorspace_converter(opie_frame_t *frame, int flags ) { switch (flags) { case VO_TOP_FIELD: case VO_BOTTOM_FIELD: frame->yuv2rgb->configure (frame->yuv2rgb, frame->sc.delivered_width, 16, 2*frame->frame.pitches[0], 2*frame->frame.pitches[1], frame->sc.output_width, frame->stripe_height, frame->bytes_per_line*2); frame->yuv_stride = frame->bytes_per_line*2; break; case VO_BOTH_FIELDS: frame->yuv2rgb->configure (frame->yuv2rgb, frame->sc.delivered_width, 16, frame->frame.pitches[0], frame->frame.pitches[1], frame->sc.output_width, frame->stripe_height, frame->bytes_per_line); frame->yuv_stride = frame->bytes_per_line; break; } #ifdef LOG fprintf (stderr, "nullvideo: colorspace converter configured.\n"); #endif } static void null_update_frame_format( vo_driver_t* self, vo_frame_t* img, uint32_t width, uint32_t height, - double ratio_code, int format, + double ratio_code, int format, int flags ){ null_driver_t* this = (null_driver_t*) self; opie_frame_t* frame = (opie_frame_t*)img; #ifdef LOG fprintf (stderr, "nullvideo: update_frame_format\n"); #endif + int gui_width = 0; + int gui_height = 0; + double gui_pixel_aspect = 0.0; + flags &= VO_BOTH_FIELDS; - /* find out if we need to adapt this frame */ + frame->sc.dest_size_cb(frame->sc.user_data, width, height, + frame->sc.video_pixel_aspect, + &gui_width, &gui_height, &gui_pixel_aspect); + /* find out if we need to adapt this frame */ if ((width != frame->sc.delivered_width) || (height != frame->sc.delivered_height) || (ratio_code != frame->sc.delivered_ratio) || (flags != frame->flags) || (format != frame->format) || (this->sc.user_ratio != frame->sc.user_ratio) - || (this->gui_width != frame->sc.gui_width) - || (this->gui_height != frame->sc.gui_height)) { - + || (gui_width != frame->sc.gui_width) + || (gui_height != frame->sc.gui_height)) { frame->sc.delivered_width = width; frame->sc.delivered_height = height; frame->sc.delivered_ratio = ratio_code; frame->flags = flags; frame->format = format; frame->sc.user_ratio = this->sc.user_ratio; - frame->sc.gui_width = this->gui_width; - frame->sc.gui_height = this->gui_height; - frame->sc.gui_pixel_aspect = 1.0; + frame->sc.gui_width = gui_width; + frame->sc.gui_height = gui_height; null_frame_compute_ideal_size(this, frame); null_frame_compute_rgb_size(this, frame); null_frame_reallocate(this, frame, width, height, format); #ifdef LOG fprintf (stderr, "nullvideo: gui %dx%d delivered %dx%d output %dx%d\n", frame->sc.gui_width, frame->sc.gui_height, frame->sc.delivered_width, frame->sc.delivered_height, frame->sc.output_width, frame->sc.output_height); #endif frame->stripe_height = 16 * frame->sc.output_height / frame->sc.delivered_height; frame->bytes_per_line = frame->sc.output_width * this->bytes_per_pixel; /* * set up colorspace converter */ null_setup_colorspace_converter(frame, flags); } /* * reset dest pointers */ if (frame->data) { switch (flags) { case VO_TOP_FIELD: - frame->rgb_dst = (uint8_t *)frame->data; + frame->rgb_dst = frame->data; frame->stripe_inc = 2 * frame->stripe_height * frame->bytes_per_line; break; case VO_BOTTOM_FIELD: - frame->rgb_dst = (uint8_t *)frame->data + frame->bytes_per_line ; + frame->rgb_dst = frame->data + frame->bytes_per_line ; frame->stripe_inc = 2 * frame->stripe_height * frame->bytes_per_line; break; case VO_BOTH_FIELDS: - frame->rgb_dst = (uint8_t *)frame->data; + frame->rgb_dst = frame->data; frame->stripe_inc = frame->stripe_height * frame->bytes_per_line; break; } } } static void null_display_frame( vo_driver_t* self, vo_frame_t *frame_gen ){ null_driver_t* this = (null_driver_t*) self; opie_frame_t* frame = (opie_frame_t*)frame_gen; display_xine_frame_t display = this->frameDis; if (!this->m_show_video) return; if( display != NULL ) { - (*display)(this->caller, frame->data, + (*display)(this->userData, frame->data, frame->sc.output_width, frame->sc.output_height, frame->bytes_per_line ); } frame->frame.free(&frame->frame); } /* blending related */ static void null_overlay_clut_yuv2rgb (null_driver_t *this, vo_overlay_t *overlay, opie_frame_t *frame) { this = this; int i; clut_t* clut = (clut_t*) overlay->color; if (!overlay->rgb_clut) { for (i = 0; i < sizeof(overlay->color)/sizeof(overlay->color[0]); i++) { *((uint32_t *)&clut[i]) = frame->yuv2rgb-> yuv2rgb_single_pixel_fun (frame->yuv2rgb, clut[i].y, clut[i].cb, clut[i].cr); } overlay->rgb_clut++; } if (!overlay->clip_rgb_clut) { clut = (clut_t*) overlay->clip_color; for (i = 0; i < sizeof(overlay->color)/sizeof(overlay->color[0]); i++) { *((uint32_t *)&clut[i]) = frame->yuv2rgb->yuv2rgb_single_pixel_fun(frame->yuv2rgb, clut[i].y, clut[i].cb, clut[i].cr); } overlay->clip_rgb_clut++; } } static void null_overlay_blend ( vo_driver_t *this_gen, vo_frame_t *frame_gen, vo_overlay_t *overlay) { null_driver_t *this = (null_driver_t *) this_gen; opie_frame_t *frame = (opie_frame_t *) frame_gen; if(!this->m_show_video || frame->sc.output_width == 0 || frame->sc.output_height== 0) return; /* Alpha Blend here */ if (overlay->rle) { if( !overlay->rgb_clut || !overlay->clip_rgb_clut) null_overlay_clut_yuv2rgb(this,overlay,frame); switch(this->bpp) { case 16: - blend_rgb16((uint8_t *)frame->data, + blend_rgb16(frame->data, overlay, frame->sc.output_width, frame->sc.output_height, frame->sc.delivered_width, - frame->sc.delivered_height); + frame->sc.delivered_height, + &this->alphablend_extra_data); break; case 24: - blend_rgb24((uint8_t *)frame->data, + blend_rgb24(frame->data, overlay, frame->sc.output_width, frame->sc.output_height, frame->sc.delivered_width, - frame->sc.delivered_height); + frame->sc.delivered_height, + &this->alphablend_extra_data); break; case 32: - blend_rgb32((uint8_t *)frame->data, + blend_rgb32(frame->data, overlay, frame->sc.output_width, frame->sc.output_height, frame->sc.delivered_width, - frame->sc.delivered_height); + frame->sc.delivered_height, + &this->alphablend_extra_data); break; default: /* It should never get here */ break; } } } static int null_get_property( vo_driver_t* self, int property ){ -#if 0 null_driver_t *this = (null_driver_t *)self; switch(property) { case VO_PROP_ASPECT_RATIO: return this->sc.user_ratio; case VO_PROP_BRIGHTNESS: return this->yuv2rgb_brightness; case VO_PROP_WINDOW_WIDTH: return this->sc.gui_width; case VO_PROP_WINDOW_HEIGHT: return this->sc.gui_height; default: break; } -#else - property = property; - self = self; -#endif return 0; } static int null_set_property( vo_driver_t* self, int property, int value ){ -#if 0 null_driver_t *this = (null_driver_t *)self; switch(property) { case VO_PROP_ASPECT_RATIO: if(value>=XINE_VO_ASPECT_NUM_RATIOS) value = XINE_VO_ASPECT_AUTO; this->sc.user_ratio = value; break; case VO_PROP_BRIGHTNESS: this->yuv2rgb_brightness = value; this->yuv2rgb_factory-> set_csc_levels(this->yuv2rgb_factory, value, 128, 128); break; default: break; } -#else - self = self; - property = property; -#endif return value; } static void null_get_property_min_max( vo_driver_t* self, int property, int *min, int *max ){ - self = self; - property = property; - - *max = 0; - *min = 0; + if(property == VO_PROP_BRIGHTNESS) { + *min = -100; + *max = +100; + }else { + *min = 0; + *max = 0; + } } static int null_gui_data_exchange( vo_driver_t* self, int data_type, void *data ){ - self = self; - data_type = data_type; - data = data; - return 0; } static void null_dispose ( vo_driver_t* self ){ null_driver_t* this = (null_driver_t*)self; + _x_alphablend_free(&this->alphablend_extra_data); free ( this ); } static int null_redraw_needed( vo_driver_t* self ){ - self = self; - - return 0; + null_driver_t *this = (null_driver_t*)self; + return _x_vo_scale_redraw_needed(&this->sc); } xine_video_port_t* init_video_out_plugin( xine_t *xine, - void* video, - display_xine_frame_t frameDisplayFunc, - void *userData ){ - video = video; - - + void* video, + display_xine_frame_t frameDisplayFunc, + void *userData, vo_scale_cb frame_cb, + dest_size_cb dest_cb) { null_driver_t *vo; - vo = (null_driver_t*)malloc( sizeof(null_driver_t ) ); - - /* memset? */ - memset(vo,0, sizeof(null_driver_t ) ); + vo = (null_driver_t*)xine_xmalloc(sizeof(null_driver_t )); + vo->xine = xine; + _x_alphablend_init(&vo->alphablend_extra_data, xine); _x_vo_scale_init (&vo->sc, 0, 0, xine->config); + vo->sc.gui_width = 18; + vo->sc.gui_height = 6; + vo->sc.user_ratio = XINE_VO_ASPECT_AUTO; + vo->sc.user_data = userData; + vo->sc.frame_output_cb = frame_cb; + vo->sc.dest_size_cb = dest_cb; - vo->sc.gui_pixel_aspect = 1.0; vo->m_show_video = 0; // false - vo->m_video_fullscreen = 0; - vo->m_is_scaling = 0; - vo->display_ratio = 1.0; - vo->gui_width = 16; - vo->gui_height = 8; - vo->frameDis = NULL; /* install callback handlers*/ - vo->vo_driver.get_capabilities = null_get_capabilities; - vo->vo_driver.alloc_frame = null_alloc_frame; - vo->vo_driver.update_frame_format = null_update_frame_format; - vo->vo_driver.display_frame = null_display_frame; - vo->vo_driver.overlay_blend = null_overlay_blend; - vo->vo_driver.get_property = null_get_property; - vo->vo_driver.set_property = null_set_property; - vo->vo_driver.get_property_min_max = null_get_property_min_max; - vo->vo_driver.gui_data_exchange = null_gui_data_exchange; - vo->vo_driver.dispose = null_dispose; - vo->vo_driver.redraw_needed = null_redraw_needed; - + vo->vo_driver.get_capabilities = null_get_capabilities; + vo->vo_driver.alloc_frame = null_alloc_frame; + vo->vo_driver.update_frame_format = null_update_frame_format; + vo->vo_driver.display_frame = null_display_frame; + vo->vo_driver.overlay_begin = 0; + vo->vo_driver.overlay_blend = null_overlay_blend; + vo->vo_driver.overlay_end = 0; + vo->vo_driver.get_property = null_get_property; + vo->vo_driver.set_property = null_set_property; + vo->vo_driver.get_property_min_max= null_get_property_min_max; + vo->vo_driver.gui_data_exchange = null_gui_data_exchange; + vo->vo_driver.dispose = null_dispose; + vo->vo_driver.redraw_needed = null_redraw_needed; /* capabilities */ - vo->m_capabilities = VO_CAP_YUY2 | VO_CAP_YV12; - vo->yuv2rgb_factory = yuv2rgb_factory_init (MODE_16_RGB, vo->yuv2rgb_swap, + vo->yuv2rgb_mode = MODE_16_RGB; + vo->yuv2rgb_brightness = 0; + vo->yuv2rgb_factory = yuv2rgb_factory_init (vo->yuv2rgb_mode, + vo->yuv2rgb_swap, vo->yuv2rgb_cmap); + vo->yuv2rgb_factory->set_csc_levels(vo->yuv2rgb_factory, + vo->yuv2rgb_brightness, + 128,128); - vo->caller = userData; + vo->userData = userData; vo->frameDis = frameDisplayFunc; return _x_vo_new_port(xine, &vo->vo_driver, 0); } /* this is special for this device */ /** * We know that we will be controled by the XINE LIB++ */ /** * */ int null_is_showing_video( xine_vo_driver_t* self ){ null_driver_t* this = (null_driver_t*)self->driver; return this->m_show_video; } void null_set_show_video( xine_vo_driver_t* self, int show ) { ((null_driver_t*)self->driver)->m_show_video = show; } -int null_is_fullscreen( xine_vo_driver_t* self ){ - return ((null_driver_t*)self->driver)->m_video_fullscreen; -} -void null_set_fullscreen( xine_vo_driver_t* self, int screen ){ - ((null_driver_t*)self->driver)->m_video_fullscreen = screen; -} -int null_is_scaling( xine_vo_driver_t* self ){ - return ((null_driver_t*)self->driver)->m_is_scaling; -} - -void null_set_videoGamma( xine_vo_driver_t* self , int value ) { - ((null_driver_t*) self->driver) ->yuv2rgb_gamma = value; - ((null_driver_t*) self->driver) ->yuv2rgb_factory->set_gamma( ((null_driver_t*) self->driver) ->yuv2rgb_factory, value ); -} - -void null_set_scaling( xine_vo_driver_t* self, int scale ) { - ((null_driver_t*)self->driver)->m_is_scaling = scale; -} - -void null_set_gui_width( xine_vo_driver_t* self, int width ) { - ((null_driver_t*)self->driver)->gui_width = width; -} -void null_set_gui_height( xine_vo_driver_t* self, int height ) { - ((null_driver_t*)self->driver)->gui_height = height; -} void null_set_mode( xine_vo_driver_t* self, int depth, int rgb ) { null_driver_t* this = (null_driver_t*)self->driver; this->bytes_per_pixel = (depth + 7 ) / 8; this->bpp = this->bytes_per_pixel * 8; this->depth = depth; - + switch ( this->depth ) { case 32: if( rgb == 0 ) this->yuv2rgb_mode = MODE_32_RGB; else this->yuv2rgb_mode = MODE_32_BGR; case 24: if( this->bpp == 32 ) { if( rgb == 0 ) { this->yuv2rgb_mode = MODE_32_RGB; } else { this->yuv2rgb_mode = MODE_32_BGR; } }else{ if( rgb == 0 ) this->yuv2rgb_mode = MODE_24_RGB; else this->yuv2rgb_mode = MODE_24_BGR; }; break; case 16: if( rgb == 0 ) { this->yuv2rgb_mode = MODE_16_RGB; } else { this->yuv2rgb_mode = MODE_16_BGR; } break; case 15: if( rgb == 0 ) { this->yuv2rgb_mode = MODE_15_RGB; } else { this->yuv2rgb_mode = MODE_15_BGR; } break; case 8: if( rgb == 0 ) { this->yuv2rgb_mode = MODE_8_RGB; } else { this->yuv2rgb_mode = MODE_8_BGR; } break; }; - //free(this->yuv2rgb_factory ); - // this->yuv2rgb_factory = yuv2rgb_factory_init (this->yuv2rgb_mode, this->yuv2rgb_swap, - // this->yuv2rgb_cmap); }; -void null_display_handler( xine_vo_driver_t* self, display_xine_frame_t t, - void* user_data ) { +void null_display_handler( xine_vo_driver_t* self, display_xine_frame_t t, + void* user_data ) { null_driver_t* this = (null_driver_t*) self->driver; - this->caller = user_data; + this->userData = user_data; this->frameDis = t; } -void null_preload_decoders( xine_stream_t *stream ) -{ - static const uint32_t preloadedAudioDecoders[] = { BUF_AUDIO_MPEG, BUF_AUDIO_VORBIS }; - static const uint8_t preloadedAudioDecoderCount = sizeof( preloadedAudioDecoders ) / sizeof( preloadedAudioDecoders[ 0 ] ); - static const uint32_t preloadedVideoDecoders[] = { BUF_VIDEO_MPEG, BUF_VIDEO_MPEG4, BUF_VIDEO_DIVX5 }; - static const uint8_t preloadedVideoDecoderCount = sizeof( preloadedVideoDecoders ) / sizeof( preloadedVideoDecoders[ 0 ] ); - - uint8_t i; -#if 0 - - for ( i = 0; i < preloadedAudioDecoderCount; ++i ) { - audio_decoder_t *decoder = get_audio_decoder( stream, ( preloadedAudioDecoders[ i ] >> 16 ) & 0xff ); - decoder = decoder; -/* free_audio_decoder( stream, decoder ); */ - } - - for ( i = 0; i < preloadedVideoDecoderCount; ++i ) { - video_decoder_t *decoder = get_video_decoder( stream, ( preloadedVideoDecoders[ i ] >> 16 ) & 0xff ); - decoder = decoder; -/* free_video_decoder( stream, decoder ); */ - } -#endif -} diff --git a/noncore/multimedia/opieplayer2/yuv2rgb.c b/noncore/multimedia/opieplayer2/yuv2rgb.c index 8e34052..487ed20 100644 --- a/noncore/multimedia/opieplayer2/yuv2rgb.c +++ b/noncore/multimedia/opieplayer2/yuv2rgb.c @@ -1,529 +1,600 @@ /* * yuv2rgb.c * - * This file is part of xine, a unix video player. + * Copyright (C) 2003-2004 the xine project + * This file is part of xine, a free video player. * * based on work from mpeg2dec: * Copyright (C) 1999-2001 Aaron Holtzman <aholtzma@ess.engr.uvic.ca> * * This file is part of mpeg2dec, a free MPEG-2 video stream decoder. * * mpeg2dec is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * mpeg2dec is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Id$ */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <inttypes.h> #include "yuv2rgb.h" -#include <xine/xineutils.h> +#define LOG_MODULE "yuv2rgb" +#define LOG_VERBOSE +/* +#define LOG +*/ + +#include <xine/xineutils.h> static int prof_scale_line = -1; static scale_line_func_t find_scale_line_func(int step); const int32_t Inverse_Table_6_9[8][4] = { {117504, 138453, 13954, 34903}, /* no sequence_display_extension */ {117504, 138453, 13954, 34903}, /* ITU-R Rec. 709 (1990) */ {104597, 132201, 25675, 53279}, /* unspecified */ {104597, 132201, 25675, 53279}, /* reserved */ {104448, 132798, 24759, 53109}, /* FCC */ {104597, 132201, 25675, 53279}, /* ITU-R Rec. 624-4 System B, G */ {104597, 132201, 25675, 53279}, /* SMPTE 170M */ {117579, 136230, 16907, 35559} /* SMPTE 240M (1987) */ }; -static void *my_malloc_aligned (size_t alignment, size_t size, void **chunk) { - +static void *my_malloc_aligned (size_t alignment, size_t size, void **chunk) +{ char *pMem; pMem = xine_xmalloc (size+alignment); *chunk = pMem; - while ((int) pMem % alignment) + while ((uintptr_t) pMem % alignment) pMem++; return pMem; } +static int yuv2rgb_next_slice (yuv2rgb_t *this, uint8_t **dest) +{ + int y0, y1; + + if (dest == NULL) { + this->slice_offset = 0; + this->slice_height = 16; + return 0; + } + if (this->slice_height == this->source_height) { + return this->dest_height; + } + + y0 = (this->slice_offset * this->dest_height) / this->source_height; + y1 = ((this->slice_offset + this->slice_height) * this->dest_height) / this->source_height; + *dest += (this->rgb_stride * y0); + + if ((this->slice_offset + this->slice_height) >= this->source_height) { + this->slice_offset = 0; + return (this->dest_height - y0); + } else { + this->slice_offset += this->slice_height; + return (y1 - y0); + } +} + +static void yuv2rgb_dispose (yuv2rgb_t *this) +{ + free (this->y_chunk); + free (this->u_chunk); + free (this->v_chunk); +#ifdef HAVE_MLIB + free (this->mlib_chunk); +#endif + free (this); +} + static int yuv2rgb_configure (yuv2rgb_t *this, int source_width, int source_height, int y_stride, int uv_stride, int dest_width, int dest_height, int rgb_stride) { - /* +/* printf ("yuv2rgb setup (%d x %d => %d x %d)\n", source_width, source_height, dest_width, dest_height); - */ +*/ if (prof_scale_line == -1) prof_scale_line = xine_profiler_allocate_slot("xshm scale line"); this->source_width = source_width; this->source_height = source_height; this->y_stride = y_stride; this->uv_stride = uv_stride; this->dest_width = dest_width; this->dest_height = dest_height; this->rgb_stride = rgb_stride; - + this->slice_height = source_height; + this->slice_offset = 0; + if (this->y_chunk) { free (this->y_chunk); this->y_buffer = this->y_chunk = NULL; } if (this->u_chunk) { free (this->u_chunk); this->u_buffer = this->u_chunk = NULL; } if (this->v_chunk) { free (this->v_chunk); this->v_buffer = this->v_chunk = NULL; } - +#ifdef HAVE_MLIB + if (this->mlib_chunk) { + free (this->mlib_chunk); + this->mlib_buffer = this->mlib_chunk = NULL; + } + if (this->mlib_resize_chunk) { + free (this->mlib_resize_chunk); + this->mlib_resize_buffer = this->mlib_resize_chunk = NULL; + } +#endif + this->step_dx = source_width * 32768 / dest_width; this->step_dy = source_height * 32768 / dest_height; - +/* + printf("yuv2rgb config: src_ht=%i, dst_ht=%i\n",source_height, dest_height); + printf("yuv2rgb config: step_dy=%i %f\n",this->step_dy, (float)this->step_dy / 32768.0); +*/ this->scale_line = find_scale_line_func(this->step_dx); if ((source_width == dest_width) && (source_height == dest_height)) { this->do_scale = 0; /* * space for two y-lines (for yuv2rgb_mlib) * u,v subsampled 2:1 */ this->y_buffer = my_malloc_aligned (16, 2*dest_width, &this->y_chunk); if (!this->y_buffer) return 0; this->u_buffer = my_malloc_aligned (16, (dest_width+1)/2, &this->u_chunk); if (!this->u_buffer) return 0; this->v_buffer = my_malloc_aligned (16, (dest_width+1)/2, &this->v_chunk); if (!this->v_buffer) return 0; } else { this->do_scale = 1; /* * space for two y-lines (for yuv2rgb_mlib) * u,v subsampled 2:1 */ this->y_buffer = my_malloc_aligned (16, 2*dest_width, &this->y_chunk); if (!this->y_buffer) return 0; this->u_buffer = my_malloc_aligned (16, (dest_width+1)/2, &this->u_chunk); if (!this->u_buffer) return 0; this->v_buffer = my_malloc_aligned (16, (dest_width+1)/2, &this->v_chunk); if (!this->v_buffer) return 0; + +#if HAVE_MLIB + /* Only need these if we are resizing and in mlib code */ + this->mlib_buffer = my_malloc_aligned (16, source_width*source_height*4, &this->mlib_chunk); + if (!this->mlib_buffer) + return 0; + /* Only need this one if we are 24 bit */ + if((rgb_stride / dest_width) == 3) { + this->mlib_resize_buffer = my_malloc_aligned (16, dest_width*dest_height*4, &this->mlib_resize_chunk); + if (!this->mlib_resize_buffer) + return 0; + } +#endif } return 1; } - static void scale_line_gen (uint8_t *source, uint8_t *dest, int width, int step) { /* * scales a yuv source row to a dest row, with interpolation * (good quality, but slow) */ int p1; int p2; int dx; xine_profiler_start_count(prof_scale_line); p1 = *source++; p2 = *source++; dx = 0; /* * the following code has been optimized by Scott Smith <ssmith@akamai.com>: * * ok now I have a meaningful optimization for yuv2rgb.c:scale_line_gen. * it removes the loop from within the while() loop by separating it out * into 3 cases: where you are enlarging the line (<32768), where you are * between 50% and 100% of the original line (<=65536), and where you are * shrinking it by a lot. anyways, I went from 200 delivered / 100+ * skipped to 200 delivered / 80 skipped for the enlarging case. I * noticed when looking at the assembly that the compiler was able to * unroll these while(width) loops, whereas before it was trying to * unroll the while(dx>32768) loops. so the compiler is better able to * deal with this code. */ if (step < 32768) { while (width) { *dest = p1 + (((p2-p1) * dx)>>15); dx += step; if (dx > 32768) { dx -= 32768; p1 = p2; p2 = *source++; } dest ++; width --; } } else if (step <= 65536) { while (width) { *dest = p1 + (((p2-p1) * dx)>>15); dx += step; if (dx > 65536) { dx -= 65536; p1 = *source++; p2 = *source++; } else { dx -= 32768; p1 = p2; p2 = *source++; } dest ++; width --; } } else { while (width) { int offs; *dest = p1 + (((p2-p1) * dx)>>15); dx += step; offs=((dx-1)>>15); dx-=offs<<15; source+=offs-2; p1=*source++; p2=*source++; dest ++; width --; } } xine_profiler_stop_count(prof_scale_line); } /* * Interpolates 16 output pixels from 15 source pixels using shifts. * Useful for scaling a PAL mpeg2 dvd input source to 4:3 format on * a monitor using square pixels. * (720 x 576 ==> 768 x 576) */ static void scale_line_15_16 (uint8_t *source, uint8_t *dest, int width, int step) { int p1, p2; xine_profiler_start_count(prof_scale_line); while ((width -= 16) >= 0) { p1 = source[0]; dest[0] = p1; p2 = source[1]; dest[1] = (1*p1 + 7*p2) >> 3; p1 = source[2]; dest[2] = (1*p2 + 7*p1) >> 3; p2 = source[3]; dest[3] = (1*p1 + 3*p2) >> 2; p1 = source[4]; dest[4] = (1*p2 + 3*p1) >> 2; p2 = source[5]; dest[5] = (3*p1 + 5*p2) >> 3; p1 = source[6]; dest[6] = (3*p2 + 5*p1) >> 3; p2 = source[7]; dest[7] = (1*p1 + 1*p1) >> 1; p1 = source[8]; dest[8] = (1*p2 + 1*p1) >> 1; p2 = source[9]; dest[9] = (5*p1 + 3*p2) >> 3; p1 = source[10]; dest[10] = (5*p2 + 3*p1) >> 3; p2 = source[11]; dest[11] = (3*p1 + 1*p2) >> 2; p1 = source[12]; dest[12] = (3*p2 + 1*p1) >> 2; p2 = source[13]; dest[13] = (7*p1 + 1*p2) >> 3; p1 = source[14]; dest[14] = (7*p2 + 1*p1) >> 3; dest[15] = p1; source += 15; dest += 16; } if ((width += 16) <= 0) goto done; *dest++ = source[0]; if (--width <= 0) goto done; *dest++ = (1*source[0] + 7*source[1]) >> 3; if (--width <= 0) goto done; *dest++ = (1*source[1] + 7*source[2]) >> 3; if (--width <= 0) goto done; *dest++ = (1*source[2] + 3*source[3]) >> 2; if (--width <= 0) goto done; *dest++ = (1*source[3] + 3*source[4]) >> 2; if (--width <= 0) goto done; *dest++ = (3*source[4] + 5*source[5]) >> 3; if (--width <= 0) goto done; *dest++ = (3*source[5] + 5*source[6]) >> 3; if (--width <= 0) goto done; *dest++ = (1*source[6] + 1*source[7]) >> 1; if (--width <= 0) goto done; *dest++ = (1*source[7] + 1*source[8]) >> 1; if (--width <= 0) goto done; *dest++ = (5*source[8] + 3*source[9]) >> 3; if (--width <= 0) goto done; *dest++ = (5*source[9] + 3*source[10]) >> 3; if (--width <= 0) goto done; *dest++ = (3*source[10] + 1*source[11]) >> 2; if (--width <= 0) goto done; *dest++ = (3*source[11] + 1*source[12]) >> 2; if (--width <= 0) goto done; *dest++ = (7*source[12] + 1*source[13]) >> 3; if (--width <= 0) goto done; *dest++ = (7*source[13] + 1*source[14]) >> 3; done: xine_profiler_stop_count(prof_scale_line); } /* * Interpolates 53 output pixels from 45 source pixels using shifts. * Useful for scaling a NTSC mpeg2 dvd input source to 16:9 display * resulution * fullscreen resolution, or to 16:9 format on a monitor using square * pixels. * (720 x 480 ==> 848 x 480) */ static void scale_line_45_53 (uint8_t *source, uint8_t *dest, int width, int step) { int p1, p2; xine_profiler_start_count(prof_scale_line); while ((width -= 53) >= 0) { p1 = source[0]; p2 = source[1]; dest[0] = p1; dest[1] = (1*p1 + 7*p2) >> 3; p1 = source[2]; dest[2] = (1*p2 + 3*p1) >> 2; p2 = source[3]; dest[3] = (1*p1 + 1*p2) >> 1; p1 = source[4]; dest[4] = (5*p2 + 3*p1) >> 3; p2 = source[5]; dest[5] = (3*p1 + 1*p2) >> 2; p1 = source[6]; dest[6] = (7*p2 + 1*p1) >> 3; dest[7] = p1; p2 = source[7]; dest[8] = (1*p1 + 3*p2) >> 2; p1 = source[8]; dest[9] = (3*p2 + 5*p1) >> 3; p2 = source[9]; dest[10] = (1*p1 + 1*p2) >> 1; p1 = source[10]; dest[11] = (5*p2 + 3*p1) >> 3; p2 = source[11]; dest[12] = (3*p1 + 1*p2) >> 2; p1 = source[12]; dest[13] = p2; dest[14] = (1*p2 + 7*p1) >> 3; p2 = source[13]; dest[15] = (1*p1 + 3*p2) >> 2; p1 = source[14]; dest[16] = (3*p2 + 5*p1) >> 3; p2 = source[15]; dest[17] = (5*p1 + 3*p2) >> 3; p1 = source[16]; dest[18] = (3*p2 + 1*p1) >> 2; p2 = source[17]; dest[19] = (7*p1 + 1*p2) >> 3; dest[20] = p2; p1 = source[18]; dest[21] = (1*p2 + 7*p1) >> 3; p2 = source[19]; dest[22] = (3*p1 + 5*p2) >> 3; p1 = source[20]; dest[23] = (1*p2 + 1*p1) >> 1; p2 = source[21]; dest[24] = (5*p1 + 3*p2) >> 3; p1 = source[22]; dest[25] = (3*p2 + 1*p1) >> 2; p2 = source[23]; dest[26] = (7*p1 + 1*p2) >> 3; dest[27] = (1*p1 + 7*p2) >> 3; p1 = source[24]; dest[28] = (1*p2 + 3*p1) >> 2; p2 = source[25]; dest[29] = (3*p1 + 5*p2) >> 3; p1 = source[26]; dest[30] = (1*p2 + 1*p1) >> 1; p2 = source[27]; dest[31] = (5*p1 + 3*p2) >> 3; p1 = source[28]; dest[32] = (7*p2 + 1*p1) >> 3; p2 = source[29]; dest[33] = p1; dest[34] = (1*p1 + 7*p2) >> 3; p1 = source[30]; dest[35] = (1*p2 + 3*p1) >> 2; p2 = source[31]; dest[36] = (3*p1 + 5*p2) >> 3; p1 = source[32]; dest[37] = (5*p2 + 3*p1) >> 3; p2 = source[33]; dest[38] = (3*p1 + 1*p2) >> 2; p1 = source[34]; dest[39] = (7*p2 + 1*p1) >> 3; dest[40] = p1; p2 = source[35]; dest[41] = (1*p1 + 3*p2) >> 2; p1 = source[36]; dest[42] = (3*p2 + 5*p1) >> 3; p2 = source[37]; dest[43] = (1*p1 + 1*p2) >> 1; p1 = source[38]; dest[44] = (5*p2 + 3*p1) >> 3; p2 = source[39]; dest[45] = (3*p1 + 1*p2) >> 2; p1 = source[40]; dest[46] = p2; dest[47] = (1*p2 + 7*p1) >> 3; p2 = source[41]; dest[48] = (1*p1 + 3*p2) >> 2; p1 = source[42]; dest[49] = (3*p2 + 5*p1) >> 3; p2 = source[43]; dest[50] = (1*p1 + 1*p2) >> 1; p1 = source[44]; dest[51] = (3*p2 + 1*p1) >> 2; p2 = source[45]; dest[52] = (7*p1 + 1*p2) >> 3; source += 45; dest += 53; } if ((width += 53) <= 0) goto done; *dest++ = source[0]; if (--width <= 0) goto done; *dest++ = (1*source[0] + 7*source[1]) >> 3; if (--width <= 0) goto done; *dest++ = (1*source[1] + 3*source[2]) >> 2; if (--width <= 0) goto done; *dest++ = (1*source[2] + 1*source[3]) >> 1; if (--width <= 0) goto done; *dest++ = (5*source[3] + 3*source[4]) >> 3; if (--width <= 0) goto done; *dest++ = (3*source[4] + 1*source[5]) >> 2; if (--width <= 0) goto done; *dest++ = (7*source[5] + 1*source[6]) >> 3; if (--width <= 0) goto done; *dest++ = source[6]; if (--width <= 0) goto done; *dest++ = (1*source[6] + 3*source[7]) >> 2; if (--width <= 0) goto done; *dest++ = (3*source[7] + 5*source[8]) >> 3; if (--width <= 0) goto done; *dest++ = (1*source[8] + 1*source[9]) >> 1; if (--width <= 0) goto done; *dest++ = (5*source[9] + 3*source[10]) >> 3; if (--width <= 0) goto done; *dest++ = (3*source[10] + 1*source[11]) >> 2; if (--width <= 0) goto done; *dest++ = source[11]; if (--width <= 0) goto done; *dest++ = (1*source[11] + 7*source[12]) >> 3; if (--width <= 0) goto done; *dest++ = (1*source[12] + 3*source[13]) >> 2; if (--width <= 0) goto done; *dest++ = (3*source[13] + 5*source[14]) >> 3; if (--width <= 0) goto done; *dest++ = (5*source[14] + 3*source[15]) >> 3; if (--width <= 0) goto done; *dest++ = (3*source[15] + 1*source[16]) >> 2; if (--width <= 0) goto done; *dest++ = (7*source[16] + 1*source[17]) >> 3; if (--width <= 0) goto done; *dest++ = source[17]; if (--width <= 0) goto done; *dest++ = (1*source[17] + 7*source[18]) >> 3; if (--width <= 0) goto done; *dest++ = (3*source[18] + 5*source[19]) >> 3; if (--width <= 0) goto done; *dest++ = (1*source[19] + 1*source[20]) >> 1; if (--width <= 0) goto done; *dest++ = (5*source[20] + 3*source[21]) >> 3; if (--width <= 0) goto done; *dest++ = (3*source[21] + 1*source[22]) >> 2; if (--width <= 0) goto done; *dest++ = (7*source[22] + 1*source[23]) >> 3; if (--width <= 0) goto done; *dest++ = (1*source[22] + 7*source[23]) >> 3; if (--width <= 0) goto done; *dest++ = (1*source[23] + 3*source[24]) >> 2; if (--width <= 0) goto done; *dest++ = (3*source[24] + 5*source[25]) >> 3; if (--width <= 0) goto done; *dest++ = (1*source[25] + 1*source[26]) >> 1; if (--width <= 0) goto done; *dest++ = (5*source[26] + 3*source[27]) >> 3; if (--width <= 0) goto done; *dest++ = (7*source[27] + 1*source[28]) >> 3; if (--width <= 0) goto done; *dest++ = source[28]; if (--width <= 0) goto done; *dest++ = (1*source[28] + 7*source[29]) >> 3; if (--width <= 0) goto done; *dest++ = (1*source[29] + 3*source[30]) >> 2; if (--width <= 0) goto done; *dest++ = (3*source[30] + 5*source[31]) >> 3; if (--width <= 0) goto done; *dest++ = (5*source[31] + 3*source[32]) >> 3; if (--width <= 0) goto done; *dest++ = (3*source[32] + 1*source[33]) >> 2; if (--width <= 0) goto done; *dest++ = (7*source[33] + 1*source[34]) >> 3; if (--width <= 0) goto done; *dest++ = source[34]; if (--width <= 0) goto done; *dest++ = (1*source[34] + 3*source[35]) >> 2; if (--width <= 0) goto done; *dest++ = (3*source[35] + 5*source[36]) >> 3; if (--width <= 0) goto done; *dest++ = (1*source[36] + 1*source[37]) >> 1; if (--width <= 0) goto done; *dest++ = (5*source[37] + 3*source[38]) >> 3; if (--width <= 0) goto done; *dest++ = (3*source[38] + 1*source[39]) >> 2; if (--width <= 0) goto done; @@ -823,2345 +894,2384 @@ static void scale_line_9_16 (uint8_t *source, uint8_t *dest, dest[0] = p1; dest[1] = (1*p1 + 1*p2) >> 1; p1 = source[2]; dest[2] = (7*p2 + 1*p1) >> 3; dest[3] = (3*p2 + 5*p1) >> 3; p2 = source[3]; dest[4] = (3*p1 + 1*p2) >> 2; dest[5] = (1*p1 + 3*p2) >> 2; p1 = source[4]; dest[6] = (5*p2 + 3*p1) >> 3; dest[7] = (1*p2 + 7*p1) >> 3; p2 = source[5]; dest[8] = (1*p1 + 1*p2) >> 1; p1 = source[6]; dest[9] = p2; dest[10] = (3*p2 + 5*p1) >> 3; p2 = source[7]; dest[11] = (7*p1 + 1*p2) >> 3; dest[12] = (1*p1 + 3*p2) >> 2; p1 = source[8]; dest[13] = (3*p2 + 1*p1) >> 2; dest[14] = (1*p2 + 7*p1) >> 3; p2 = source[9]; dest[15] = (5*p1 + 3*p2) >> 3; source += 9; dest += 16; } if ((width += 16) <= 0) goto done; *dest++ = source[0]; if (--width <= 0) goto done; *dest++ = (1*source[0] + 1*source[1]) >> 1; if (--width <= 0) goto done; *dest++ = (7*source[1] + 1*source[2]) >> 3; if (--width <= 0) goto done; *dest++ = (3*source[1] + 5*source[2]) >> 3; if (--width <= 0) goto done; *dest++ = (3*source[2] + 1*source[3]) >> 2; if (--width <= 0) goto done; *dest++ = (1*source[2] + 3*source[3]) >> 2; if (--width <= 0) goto done; *dest++ = (5*source[3] + 3*source[4]) >> 3; if (--width <= 0) goto done; *dest++ = (1*source[3] + 7*source[4]) >> 3; if (--width <= 0) goto done; *dest++ = (1*source[4] + 1*source[5]) >> 1; if (--width <= 0) goto done; *dest++ = source[5]; if (--width <= 0) goto done; *dest++ = (3*source[5] + 5*source[6]) >> 3; if (--width <= 0) goto done; *dest++ = (7*source[6] + 1*source[7]) >> 3; if (--width <= 0) goto done; *dest++ = (1*source[6] + 3*source[7]) >> 2; if (--width <= 0) goto done; *dest++ = (3*source[7] + 1*source[8]) >> 2; if (--width <= 0) goto done; *dest++ = (1*source[7] + 7*source[8]) >> 3; done: xine_profiler_stop_count(prof_scale_line); } /* * Interpolates 12 output pixels from 11 source pixels using shifts. * Useful for scaling a PAL vcd input source to 4:3 display format. */ static void scale_line_11_12 (uint8_t *source, uint8_t *dest, int width, int step) { int p1, p2; xine_profiler_start_count(prof_scale_line); while ((width -= 12) >= 0) { p1 = source[0]; p2 = source[1]; dest[0] = p1; dest[1] = (1*p1 + 7*p2) >> 3; p1 = source[2]; dest[2] = (1*p2 + 7*p1) >> 3; p2 = source[3]; dest[3] = (1*p1 + 3*p2) >> 2; p1 = source[4]; dest[4] = (3*p2 + 5*p1) >> 3; p2 = source[5]; dest[5] = (3*p1 + 5*p2) >> 3; p1 = source[6]; dest[6] = (1*p2 + 1*p1) >> 1; p2 = source[7]; dest[7] = (5*p1 + 3*p2) >> 3; p1 = source[8]; dest[8] = (5*p2 + 3*p1) >> 3; p2 = source[9]; dest[9] = (3*p1 + 1*p2) >> 2; p1 = source[10]; dest[10] = (7*p2 + 1*p1) >> 3; p2 = source[11]; dest[11] = (7*p1 + 1*p2) >> 3; source += 11; dest += 12; } if ((width += 12) <= 0) goto done; *dest++ = source[0]; if (--width <= 0) goto done; *dest++ = (1*source[0] + 7*source[1]) >> 3; if (--width <= 0) goto done; *dest++ = (1*source[1] + 7*source[2]) >> 3; if (--width <= 0) goto done; *dest++ = (1*source[2] + 3*source[3]) >> 2; if (--width <= 0) goto done; *dest++ = (3*source[3] + 5*source[4]) >> 3; if (--width <= 0) goto done; *dest++ = (3*source[4] + 5*source[5]) >> 3; if (--width <= 0) goto done; *dest++ = (1*source[5] + 1*source[6]) >> 1; if (--width <= 0) goto done; *dest++ = (5*source[6] + 3*source[7]) >> 3; if (--width <= 0) goto done; *dest++ = (5*source[7] + 3*source[8]) >> 3; if (--width <= 0) goto done; *dest++ = (3*source[8] + 1*source[9]) >> 2; if (--width <= 0) goto done; *dest++ = (7*source[9] + 1*source[10]) >> 3; done: xine_profiler_stop_count(prof_scale_line); } /* * Interpolates 24 output pixels from 11 source pixels using shifts. * Useful for scaling a PAL vcd input source to 4:3 display format * at 2*zoom. */ static void scale_line_11_24 (uint8_t *source, uint8_t *dest, int width, int step) { int p1, p2; xine_profiler_start_count(prof_scale_line); while ((width -= 24) >= 0) { p1 = source[0]; p2 = source[1]; dest[0] = p1; dest[1] = (1*p1 + 1*p2) >> 1; dest[2] = (1*p1 + 7*p2) >> 3; p1 = source[2]; dest[3] = (5*p2 + 3*p1) >> 3; dest[4] = (1*p2 + 7*p1) >> 3; p2 = source[3]; dest[5] = (3*p1 + 1*p2) >> 2; dest[6] = (1*p1 + 3*p2) >> 2; p1 = source[4]; dest[7] = (3*p2 + 1*p1) >> 2; dest[8] = (3*p2 + 5*p1) >> 3; p2 = source[5]; dest[9] = (7*p1 + 1*p2) >> 3; dest[10] = (3*p1 + 5*p2) >> 3; p1 = source[6]; dest[11] = p2; dest[12] = (1*p2 + 1*p1) >> 1; dest[13] = p1; p2 = source[7]; dest[14] = (5*p1 + 3*p2) >> 3; dest[15] = (1*p1 + 7*p2) >> 3; p1 = source[8]; dest[16] = (5*p2 + 3*p1) >> 3; dest[17] = (1*p2 + 3*p1) >> 2; p2 = source[9]; dest[18] = (3*p1 + 1*p2) >> 2; dest[19] = (1*p1 + 3*p2) >> 2; p1 = source[10]; dest[20] = (7*p2 + 1*p1) >> 3; dest[21] = (3*p2 + 5*p1) >> 3; p2 = source[11]; dest[22] = (7*p1 + 1*p2) >> 3; dest[23] = (1*p1 + 1*p2) >> 1; source += 11; dest += 24; } if ((width += 24) <= 0) goto done; *dest++ = source[0]; if (--width <= 0) goto done; *dest++ = (1*source[0] + 1*source[1]) >> 1; if (--width <= 0) goto done; *dest++ = (1*source[0] + 7*source[1]) >> 3; if (--width <= 0) goto done; *dest++ = (5*source[1] + 3*source[2]) >> 3; if (--width <= 0) goto done; *dest++ = (1*source[1] + 7*source[2]) >> 3; if (--width <= 0) goto done; *dest++ = (3*source[2] + 1*source[3]) >> 2; if (--width <= 0) goto done; *dest++ = (1*source[2] + 3*source[3]) >> 2; if (--width <= 0) goto done; *dest++ = (3*source[3] + 1*source[4]) >> 2; if (--width <= 0) goto done; *dest++ = (3*source[3] + 5*source[4]) >> 3; if (--width <= 0) goto done; *dest++ = (7*source[4] + 1*source[5]) >> 3; if (--width <= 0) goto done; *dest++ = (3*source[4] + 5*source[5]) >> 3; if (--width <= 0) goto done; *dest++ = source[5]; if (--width <= 0) goto done; *dest++ = (1*source[5] + 1*source[6]) >> 1; if (--width <= 0) goto done; *dest++ = source[6]; if (--width <= 0) goto done; *dest++ = (5*source[6] + 3*source[7]) >> 3; if (--width <= 0) goto done; *dest++ = (1*source[6] + 7*source[7]) >> 3; if (--width <= 0) goto done; *dest++ = (5*source[7] + 3*source[8]) >> 3; if (--width <= 0) goto done; *dest++ = (1*source[7] + 3*source[8]) >> 2; if (--width <= 0) goto done; *dest++ = (3*source[8] + 1*source[9]) >> 2; if (--width <= 0) goto done; *dest++ = (1*source[8] + 3*source[9]) >> 2; if (--width <= 0) goto done; *dest++ = (7*source[9] + 1*source[10]) >> 3; if (--width <= 0) goto done; *dest++ = (3*source[9] + 5*source[10]) >> 3; if (--width <= 0) goto done; *dest++ = (7*source[10] + 1*source[11]) >> 3; done: xine_profiler_stop_count(prof_scale_line); } /* * Interpolates 8 output pixels from 5 source pixels using shifts. * Useful for scaling a PAL svcd input source to 4:3 display format. */ static void scale_line_5_8 (uint8_t *source, uint8_t *dest, int width, int step) { int p1, p2; xine_profiler_start_count(prof_scale_line); while ((width -= 8) >= 0) { p1 = source[0]; p2 = source[1]; dest[0] = p1; dest[1] = (3*p1 + 5*p2) >> 3; p1 = source[2]; dest[2] = (3*p2 + 1*p1) >> 2; dest[3] = (1*p2 + 7*p1) >> 3; p2 = source[3]; dest[4] = (1*p1 + 1*p2) >> 1; p1 = source[4]; dest[5] = (7*p2 + 1*p1) >> 3; dest[6] = (1*p2 + 3*p1) >> 2; p2 = source[5]; dest[7] = (5*p1 + 3*p2) >> 3; source += 5; dest += 8; } if ((width += 8) <= 0) goto done; *dest++ = source[0]; if (--width <= 0) goto done; *dest++ = (3*source[0] + 5*source[1]) >> 3; if (--width <= 0) goto done; *dest++ = (3*source[1] + 1*source[2]) >> 2; if (--width <= 0) goto done; *dest++ = (1*source[1] + 7*source[2]) >> 3; if (--width <= 0) goto done; *dest++ = (1*source[2] + 1*source[3]) >> 1; if (--width <= 0) goto done; *dest++ = (7*source[3] + 1*source[4]) >> 3; if (--width <= 0) goto done; *dest++ = (1*source[3] + 3*source[4]) >> 2; done: xine_profiler_stop_count(prof_scale_line); } /* * Interpolates 4 output pixels from 3 source pixels using shifts. * Useful for scaling a NTSC svcd input source to 4:3 display format. */ static void scale_line_3_4 (uint8_t *source, uint8_t *dest, int width, int step) { int p1, p2; xine_profiler_start_count(prof_scale_line); while ((width -= 4) >= 0) { p1 = source[0]; p2 = source[1]; dest[0] = p1; dest[1] = (1*p1 + 3*p2) >> 2; p1 = source[2]; dest[2] = (1*p2 + 1*p1) >> 1; p2 = source[3]; dest[3] = (3*p1 + 1*p2) >> 2; source += 3; dest += 4; } if ((width += 4) <= 0) goto done; *dest++ = source[0]; if (--width <= 0) goto done; *dest++ = (1*source[0] + 3*source[1]) >> 2; if (--width <= 0) goto done; *dest++ = (1*source[1] + 1*source[2]) >> 1; done: xine_profiler_stop_count(prof_scale_line); } /* Interpolate 2 output pixels from one source pixel. */ static void scale_line_1_2 (uint8_t *source, uint8_t *dest, int width, int step) { int p1, p2; xine_profiler_start_count(prof_scale_line); p1 = *source; while ((width -= 4) >= 0) { *dest++ = p1; p2 = *++source; *dest++ = (p1 + p2) >> 1; *dest++ = p2; p1 = *++source; *dest++ = (p2 + p1) >> 1; } if ((width += 4) <= 0) goto done; *dest++ = source[0]; if (--width <= 0) goto done; *dest++ = (source[0] + source[1]) >> 1; if (--width <= 0) goto done; *dest++ = source[1]; done: xine_profiler_stop_count(prof_scale_line); } /* * Scale line with no horizontal scaling. For NTSC mpeg2 dvd input in * 4:3 output format (720x480 -> 720x540) */ static void scale_line_1_1 (uint8_t *source, uint8_t *dest, int width, int step) { xine_profiler_start_count(prof_scale_line); xine_fast_memcpy(dest, source, width); xine_profiler_stop_count(prof_scale_line); } static scale_line_func_t find_scale_line_func(int step) { static struct { int src_step; int dest_step; scale_line_func_t func; char *desc; } scale_line[] = { { 15, 16, scale_line_15_16, "dvd 4:3(pal)" }, { 45, 64, scale_line_45_64, "dvd 16:9(pal), fullscreen(1024x768)" }, { 9, 16, scale_line_9_16, "dvd fullscreen(1280x1024)" }, { 45, 53, scale_line_45_53, "dvd 16:9(ntsc)" }, { 11, 12, scale_line_11_12, "vcd 4:3(pal)" }, { 11, 24, scale_line_11_24, "vcd 4:3(pal) 2*zoom" }, { 5, 8, scale_line_5_8, "svcd 4:3(pal)" }, { 3, 4, scale_line_3_4, "svcd 4:3(ntsc)" }, { 1, 2, scale_line_1_2, "2*zoom" }, { 1, 1, scale_line_1_1, "non-scaled" }, }; int i; +#ifdef LOG + /* to filter out multiple messages about the scale_line variant we're using */ + static int reported_for_step; +#endif for (i = 0; i < sizeof(scale_line)/sizeof(scale_line[0]); i++) { if (step == scale_line[i].src_step*32768/scale_line[i].dest_step) { - //printf("yuv2rgb: using %s optimized scale_line\n", scale_line[i].desc); +#ifdef LOG + if (step != reported_for_step) + printf("yuv2rgb: using %s optimized scale_line\n", scale_line[i].desc); + reported_for_step = step; +#endif return scale_line[i].func; } } - //printf("yuv2rgb: using generic scale_line with interpolation\n"); - return scale_line_gen; +#ifdef LOG + if (step != reported_for_step) + printf("yuv2rgb: using generic scale_line with interpolation\n"); + reported_for_step = step; +#endif + + return scale_line_gen; } static void scale_line_2 (uint8_t *source, uint8_t *dest, int width, int step) { int p1; int p2; int dx; p1 = *source; source+=2; p2 = *source; source+=2; dx = 0; while (width) { *dest = (p1 * (32768 - dx) + p2 * dx) / 32768; dx += step; while (dx > 32768) { dx -= 32768; p1 = p2; p2 = *source; source+=2; } dest ++; width --; } } static void scale_line_4 (uint8_t *source, uint8_t *dest, int width, int step) { int p1; int p2; int dx; p1 = *source; source+=4; p2 = *source; source+=4; dx = 0; while (width) { *dest = (p1 * (32768 - dx) + p2 * dx) / 32768; dx += step; while (dx > 32768) { dx -= 32768; p1 = p2; p2 = *source; source+=4; } dest ++; width --; } } -#define RGB(i) \ +#define X_RGB(i) \ U = pu[i]; \ V = pv[i]; \ r = this->table_rV[V]; \ g = (void *) (((uint8_t *)this->table_gU[U]) + this->table_gV[V]); \ b = this->table_bU[U]; #define DST1(i) \ Y = py_1[2*i]; \ dst_1[2*i] = r[Y] + g[Y] + b[Y]; \ Y = py_1[2*i+1]; \ dst_1[2*i+1] = r[Y] + g[Y] + b[Y]; #define DST2(i) \ Y = py_2[2*i]; \ dst_2[2*i] = r[Y] + g[Y] + b[Y]; \ Y = py_2[2*i+1]; \ dst_2[2*i+1] = r[Y] + g[Y] + b[Y]; #define DST1RGB(i) \ Y = py_1[2*i]; \ dst_1[6*i] = r[Y]; dst_1[6*i+1] = g[Y]; dst_1[6*i+2] = b[Y]; \ Y = py_1[2*i+1]; \ dst_1[6*i+3] = r[Y]; dst_1[6*i+4] = g[Y]; dst_1[6*i+5] = b[Y]; #define DST2RGB(i) \ Y = py_2[2*i]; \ dst_2[6*i] = r[Y]; dst_2[6*i+1] = g[Y]; dst_2[6*i+2] = b[Y]; \ Y = py_2[2*i+1]; \ dst_2[6*i+3] = r[Y]; dst_2[6*i+4] = g[Y]; dst_2[6*i+5] = b[Y]; #define DST1BGR(i) \ Y = py_1[2*i]; \ dst_1[6*i] = b[Y]; dst_1[6*i+1] = g[Y]; dst_1[6*i+2] = r[Y]; \ Y = py_1[2*i+1]; \ dst_1[6*i+3] = b[Y]; dst_1[6*i+4] = g[Y]; dst_1[6*i+5] = r[Y]; #define DST2BGR(i) \ Y = py_2[2*i]; \ dst_2[6*i] = b[Y]; dst_2[6*i+1] = g[Y]; dst_2[6*i+2] = r[Y]; \ Y = py_2[2*i+1]; \ dst_2[6*i+3] = b[Y]; dst_2[6*i+4] = g[Y]; dst_2[6*i+5] = r[Y]; #define DST1CMAP(i) \ Y = py_1[2*i]; \ dst_1[2*i] = this->cmap[r[Y] + g[Y] + b[Y]]; \ Y = py_1[2*i+1]; \ dst_1[2*i+1] = this->cmap[r[Y] + g[Y] + b[Y]]; #define DST2CMAP(i) \ Y = py_2[2*i]; \ dst_2[2*i] = this->cmap[r[Y] + g[Y] + b[Y]]; \ Y = py_2[2*i+1]; \ dst_2[2*i+1] = this->cmap[r[Y] + g[Y] + b[Y]]; static void yuv2rgb_c_32 (yuv2rgb_t *this, uint8_t * _dst, uint8_t * _py, uint8_t * _pu, uint8_t * _pv) { int U, V, Y; uint8_t * py_1, * py_2, * pu, * pv; uint32_t * r, * g, * b; uint32_t * dst_1, * dst_2; int width, height, dst_height; int dy; if (this->do_scale) { scale_line_func_t scale_line = this->scale_line; scale_line (_pu, this->u_buffer, this->dest_width >> 1, this->step_dx); scale_line (_pv, this->v_buffer, this->dest_width >> 1, this->step_dx); scale_line (_py, this->y_buffer, this->dest_width, this->step_dx); dy = 0; - dst_height = this->dest_height; + dst_height = this->next_slice (this, &_dst); for (height = 0;; ) { dst_1 = (uint32_t*)_dst; py_1 = this->y_buffer; pu = this->u_buffer; pv = this->v_buffer; width = this->dest_width >> 3; do { - RGB(0); + X_RGB(0); DST1(0); - RGB(1); + X_RGB(1); DST1(1); - RGB(2); + X_RGB(2); DST1(2); - RGB(3); + X_RGB(3); DST1(3); pu += 4; pv += 4; py_1 += 8; dst_1 += 8; } while (--width); dy += this->step_dy; _dst += this->rgb_stride; while (--dst_height > 0 && dy < 32768) { xine_fast_memcpy (_dst, (uint8_t*)_dst-this->rgb_stride, this->dest_width*4); dy += this->step_dy; _dst += this->rgb_stride; } if (dst_height <= 0) break; do { dy -= 32768; _py += this->y_stride; scale_line (_py, this->y_buffer, this->dest_width, this->step_dx); if (height & 1) { _pu += this->uv_stride; _pv += this->uv_stride; scale_line (_pu, this->u_buffer, this->dest_width >> 1, this->step_dx); scale_line (_pv, this->v_buffer, this->dest_width >> 1, this->step_dx); } height++; } while( dy>=32768); } } else { - height = this->source_height >> 1; + height = this->next_slice (this, &_dst) >> 1; do { dst_1 = (uint32_t*)_dst; dst_2 = (void*)( (uint8_t *)_dst + this->rgb_stride ); py_1 = _py; py_2 = _py + this->y_stride; pu = _pu; pv = _pv; width = this->source_width >> 3; do { - RGB(0); + X_RGB(0); DST1(0); DST2(0); - RGB(1); + X_RGB(1); DST2(1); DST1(1); - RGB(2); + X_RGB(2); DST1(2); DST2(2); - RGB(3); + X_RGB(3); DST2(3); DST1(3); pu += 4; pv += 4; py_1 += 8; py_2 += 8; dst_1 += 8; dst_2 += 8; } while (--width); _dst += 2 * this->rgb_stride; _py += 2 * this->y_stride; _pu += this->uv_stride; _pv += this->uv_stride; } while (--height); } } /* This is very near from the yuv2rgb_c_32 code */ static void yuv2rgb_c_24_rgb (yuv2rgb_t *this, uint8_t * _dst, uint8_t * _py, uint8_t * _pu, uint8_t * _pv) { int U, V, Y; uint8_t * py_1, * py_2, * pu, * pv; uint8_t * r, * g, * b; uint8_t * dst_1, * dst_2; int width, height, dst_height; int dy; if (this->do_scale) { scale_line_func_t scale_line = this->scale_line; scale_line (_pu, this->u_buffer, this->dest_width >> 1, this->step_dx); scale_line (_pv, this->v_buffer, this->dest_width >> 1, this->step_dx); scale_line (_py, this->y_buffer, this->dest_width, this->step_dx); dy = 0; - dst_height = this->dest_height; + dst_height = this->next_slice (this, &_dst); for (height = 0;; ) { dst_1 = _dst; py_1 = this->y_buffer; pu = this->u_buffer; pv = this->v_buffer; width = this->dest_width >> 3; do { - RGB(0); + X_RGB(0); DST1RGB(0); - RGB(1); + X_RGB(1); DST1RGB(1); - RGB(2); + X_RGB(2); DST1RGB(2); - RGB(3); + X_RGB(3); DST1RGB(3); pu += 4; pv += 4; py_1 += 8; dst_1 += 24; } while (--width); dy += this->step_dy; _dst += this->rgb_stride; while (--dst_height > 0 && dy < 32768) { xine_fast_memcpy (_dst, _dst-this->rgb_stride, this->dest_width*3); dy += this->step_dy; _dst += this->rgb_stride; } if (dst_height <= 0) break; do { dy -= 32768; _py += this->y_stride; scale_line (_py, this->y_buffer, this->dest_width, this->step_dx); if (height & 1) { _pu += this->uv_stride; _pv += this->uv_stride; scale_line (_pu, this->u_buffer, this->dest_width >> 1, this->step_dx); scale_line (_pv, this->v_buffer, this->dest_width >> 1, this->step_dx); } height++; } while (dy>=32768); } } else { - height = this->source_height >> 1; + height = this->next_slice (this, &_dst) >> 1; do { dst_1 = _dst; dst_2 = (void*)( (uint8_t *)_dst + this->rgb_stride ); py_1 = _py; py_2 = _py + this->y_stride; pu = _pu; pv = _pv; width = this->source_width >> 3; do { - RGB(0); + X_RGB(0); DST1RGB(0); DST2RGB(0); - RGB(1); + X_RGB(1); DST2RGB(1); DST1RGB(1); - RGB(2); + X_RGB(2); DST1RGB(2); DST2RGB(2); - RGB(3); + X_RGB(3); DST2RGB(3); DST1RGB(3); pu += 4; pv += 4; py_1 += 8; py_2 += 8; dst_1 += 24; dst_2 += 24; } while (--width); _dst += 2 * this->rgb_stride; _py += 2 * this->y_stride; _pu += this->uv_stride; _pv += this->uv_stride; } while (--height); } } /* only trivial mods from yuv2rgb_c_24_rgb */ static void yuv2rgb_c_24_bgr (yuv2rgb_t *this, uint8_t * _dst, uint8_t * _py, uint8_t * _pu, uint8_t * _pv) { int U, V, Y; uint8_t * py_1, * py_2, * pu, * pv; uint8_t * r, * g, * b; uint8_t * dst_1, * dst_2; int width, height, dst_height; int dy; if (this->do_scale) { scale_line_func_t scale_line = this->scale_line; scale_line (_pu, this->u_buffer, this->dest_width >> 1, this->step_dx); scale_line (_pv, this->v_buffer, this->dest_width >> 1, this->step_dx); scale_line (_py, this->y_buffer, this->dest_width, this->step_dx); dy = 0; - dst_height = this->dest_height; + dst_height = this->next_slice (this, &_dst); for (height = 0;; ) { dst_1 = _dst; py_1 = this->y_buffer; pu = this->u_buffer; pv = this->v_buffer; width = this->dest_width >> 3; do { - RGB(0); + X_RGB(0); DST1BGR(0); - RGB(1); + X_RGB(1); DST1BGR(1); - RGB(2); + X_RGB(2); DST1BGR(2); - RGB(3); + X_RGB(3); DST1BGR(3); pu += 4; pv += 4; py_1 += 8; dst_1 += 24; } while (--width); dy += this->step_dy; _dst += this->rgb_stride; while (--dst_height > 0 && dy < 32768) { xine_fast_memcpy (_dst, _dst-this->rgb_stride, this->dest_width*3); dy += this->step_dy; _dst += this->rgb_stride; } if (dst_height <= 0) break; do { dy -= 32768; _py += this->y_stride; scale_line (_py, this->y_buffer, this->dest_width, this->step_dx); if (height & 1) { _pu += this->uv_stride; _pv += this->uv_stride; scale_line (_pu, this->u_buffer, this->dest_width >> 1, this->step_dx); scale_line (_pv, this->v_buffer, this->dest_width >> 1, this->step_dx); } height++; } while( dy>=32768 ); } } else { - height = this->source_height >> 1; + height = this->next_slice (this, &_dst) >> 1; do { dst_1 = _dst; dst_2 = (void*)( (uint8_t *)_dst + this->rgb_stride ); py_1 = _py; py_2 = _py + this->y_stride; pu = _pu; pv = _pv; width = this->source_width >> 3; do { - RGB(0); + X_RGB(0); DST1BGR(0); DST2BGR(0); - RGB(1); + X_RGB(1); DST2BGR(1); DST1BGR(1); - RGB(2); + X_RGB(2); DST1BGR(2); DST2BGR(2); - RGB(3); + X_RGB(3); DST2BGR(3); DST1BGR(3); pu += 4; pv += 4; py_1 += 8; py_2 += 8; dst_1 += 24; dst_2 += 24; } while (--width); _dst += 2 * this->rgb_stride; _py += 2 * this->y_stride; _pu += this->uv_stride; _pv += this->uv_stride; } while (--height); } } /* This is exactly the same code as yuv2rgb_c_32 except for the types of */ /* r, g, b, dst_1, dst_2 */ static void yuv2rgb_c_16 (yuv2rgb_t *this, uint8_t * _dst, uint8_t * _py, uint8_t * _pu, uint8_t * _pv) { int U, V, Y; uint8_t * py_1, * py_2, * pu, * pv; uint16_t * r, * g, * b; uint16_t * dst_1, * dst_2; int width, height, dst_height; int dy; if (this->do_scale) { scale_line_func_t scale_line = this->scale_line; scale_line (_pu, this->u_buffer, this->dest_width >> 1, this->step_dx); scale_line (_pv, this->v_buffer, this->dest_width >> 1, this->step_dx); scale_line (_py, this->y_buffer, this->dest_width, this->step_dx); dy = 0; - dst_height = this->dest_height; + dst_height = this->next_slice (this, &_dst); for (height = 0;; ) { dst_1 = (uint16_t*)_dst; py_1 = this->y_buffer; pu = this->u_buffer; pv = this->v_buffer; width = this->dest_width >> 3; do { - RGB(0); + X_RGB(0); DST1(0); - RGB(1); + X_RGB(1); DST1(1); - RGB(2); + X_RGB(2); DST1(2); - RGB(3); + X_RGB(3); DST1(3); pu += 4; pv += 4; py_1 += 8; dst_1 += 8; } while (--width); dy += this->step_dy; _dst += this->rgb_stride; while (--dst_height > 0 && dy < 32768) { xine_fast_memcpy (_dst, (uint8_t*)_dst-this->rgb_stride, this->dest_width*2); dy += this->step_dy; _dst += this->rgb_stride; } if (dst_height <= 0) break; do { dy -= 32768; _py += this->y_stride; scale_line (_py, this->y_buffer, this->dest_width, this->step_dx); if (height & 1) { _pu += this->uv_stride; _pv += this->uv_stride; scale_line (_pu, this->u_buffer, this->dest_width >> 1, this->step_dx); scale_line (_pv, this->v_buffer, this->dest_width >> 1, this->step_dx); } height++; } while( dy>=32768); } } else { - height = this->source_height >> 1; + height = this->next_slice (this, &_dst) >> 1; do { dst_1 = (uint16_t*)_dst; dst_2 = (void*)( (uint8_t *)_dst + this->rgb_stride ); py_1 = _py; py_2 = _py + this->y_stride; pu = _pu; pv = _pv; width = this->source_width >> 3; do { - RGB(0); + X_RGB(0); DST1(0); DST2(0); - RGB(1); + X_RGB(1); DST2(1); DST1(1); - RGB(2); + X_RGB(2); DST1(2); DST2(2); - RGB(3); + X_RGB(3); DST2(3); DST1(3); pu += 4; pv += 4; py_1 += 8; py_2 += 8; dst_1 += 8; dst_2 += 8; } while (--width); _dst += 2 * this->rgb_stride; _py += 2 * this->y_stride; _pu += this->uv_stride; _pv += this->uv_stride; } while (--height); } } /* This is exactly the same code as yuv2rgb_c_32 except for the types of */ /* r, g, b, dst_1, dst_2 */ static void yuv2rgb_c_8 (yuv2rgb_t *this, uint8_t * _dst, uint8_t * _py, uint8_t * _pu, uint8_t * _pv) { int U, V, Y; uint8_t * py_1, * py_2, * pu, * pv; uint8_t * r, * g, * b; uint8_t * dst_1, * dst_2; int width, height, dst_height; int dy; if (this->do_scale) { scale_line_func_t scale_line = this->scale_line; scale_line (_pu, this->u_buffer, this->dest_width >> 1, this->step_dx); scale_line (_pv, this->v_buffer, this->dest_width >> 1, this->step_dx); scale_line (_py, this->y_buffer, this->dest_width, this->step_dx); dy = 0; - dst_height = this->dest_height; + dst_height = this->next_slice (this, &_dst); for (height = 0;; ) { dst_1 = (uint8_t*)_dst; py_1 = this->y_buffer; pu = this->u_buffer; pv = this->v_buffer; width = this->dest_width >> 3; do { - RGB(0); + X_RGB(0); DST1(0); - RGB(1); + X_RGB(1); DST1(1); - RGB(2); + X_RGB(2); DST1(2); - RGB(3); + X_RGB(3); DST1(3); pu += 4; pv += 4; py_1 += 8; dst_1 += 8; } while (--width); dy += this->step_dy; _dst += this->rgb_stride; while (--dst_height > 0 && dy < 32768) { xine_fast_memcpy (_dst, (uint8_t*)_dst-this->rgb_stride, this->dest_width); dy += this->step_dy; _dst += this->rgb_stride; } if (dst_height <= 0) break; do { dy -= 32768; _py += this->y_stride; scale_line (_py, this->y_buffer, this->dest_width, this->step_dx); if (height & 1) { _pu += this->uv_stride; _pv += this->uv_stride; scale_line (_pu, this->u_buffer, this->dest_width >> 1, this->step_dx); scale_line (_pv, this->v_buffer, this->dest_width >> 1, this->step_dx); } height++; } while( dy>=32768 ); } } else { - height = this->source_height >> 1; + height = this->next_slice (this, &_dst) >> 1; do { dst_1 = (uint8_t*)_dst; dst_2 = (void*)( (uint8_t *)_dst + this->rgb_stride ); py_1 = _py; py_2 = _py + this->y_stride; pu = _pu; pv = _pv; width = this->source_width >> 3; do { - RGB(0); + X_RGB(0); DST1(0); DST2(0); - RGB(1); + X_RGB(1); DST2(1); DST1(1); - RGB(2); + X_RGB(2); DST1(2); DST2(2); - RGB(3); + X_RGB(3); DST2(3); DST1(3); pu += 4; pv += 4; py_1 += 8; py_2 += 8; dst_1 += 8; dst_2 += 8; } while (--width); _dst += 2 * this->rgb_stride; _py += 2 * this->y_stride; _pu += this->uv_stride; _pv += this->uv_stride; } while (--height); } } /* now for something different: 256 grayscale mode */ static void yuv2rgb_c_gray (yuv2rgb_t *this, uint8_t * _dst, uint8_t * _py, uint8_t * _pu, uint8_t * _pv) { int height, dst_height; int dy; if (this->do_scale) { scale_line_func_t scale_line = this->scale_line; dy = 0; - dst_height = this->dest_height; + dst_height = this->next_slice (this, &_dst); for (;;) { scale_line (_py, _dst, this->dest_width, this->step_dx); dy += this->step_dy; _dst += this->rgb_stride; while (--dst_height > 0 && dy < 32768) { xine_fast_memcpy (_dst, (uint8_t*)_dst-this->rgb_stride, this->dest_width); dy += this->step_dy; _dst += this->rgb_stride; } if (dst_height <= 0) break; _py += this->y_stride*(dy>>15); dy &= 32767; /* dy -= 32768; _py += this->y_stride; */ } } else { - for (height = this->source_height; --height >= 0; ) { + for (height = this->next_slice (this, &_dst); --height >= 0; ) { xine_fast_memcpy(_dst, _py, this->dest_width); _dst += this->rgb_stride; _py += this->y_stride; } } } /* now for something different: 256 color mode */ static void yuv2rgb_c_palette (yuv2rgb_t *this, uint8_t * _dst, uint8_t * _py, uint8_t * _pu, uint8_t * _pv) { int U, V, Y; uint8_t * py_1, * py_2, * pu, * pv; uint16_t * r, * g, * b; uint8_t * dst_1, * dst_2; int width, height, dst_height; int dy; if (this->do_scale) { scale_line_func_t scale_line = this->scale_line; scale_line (_pu, this->u_buffer, this->dest_width >> 1, this->step_dx); scale_line (_pv, this->v_buffer, this->dest_width >> 1, this->step_dx); scale_line (_py, this->y_buffer, this->dest_width, this->step_dx); dy = 0; - dst_height = this->dest_height; + dst_height = this->next_slice (this, &_dst); for (height = 0;; ) { dst_1 = _dst; py_1 = this->y_buffer; pu = this->u_buffer; pv = this->v_buffer; width = this->dest_width >> 3; do { - RGB(0); + X_RGB(0); DST1CMAP(0); - RGB(1); + X_RGB(1); DST1CMAP(1); - RGB(2); + X_RGB(2); DST1CMAP(2); - RGB(3); + X_RGB(3); DST1CMAP(3); pu += 4; pv += 4; py_1 += 8; dst_1 += 8; } while (--width); dy += this->step_dy; _dst += this->rgb_stride; while (--dst_height > 0 && dy < 32768) { xine_fast_memcpy (_dst, (uint8_t*)_dst-this->rgb_stride, this->dest_width); dy += this->step_dy; _dst += this->rgb_stride; } if (dst_height <= 0) break; do { dy -= 32768; _py += this->y_stride; scale_line (_py, this->y_buffer, this->dest_width, this->step_dx); if (height & 1) { _pu += this->uv_stride; _pv += this->uv_stride; scale_line (_pu, this->u_buffer, this->dest_width >> 1, this->step_dx); scale_line (_pv, this->v_buffer, this->dest_width >> 1, this->step_dx); } height++; } while( dy>=32768 ); } } else { - height = this->source_height >> 1; + height = this->next_slice (this, &_dst) >> 1; do { dst_1 = _dst; dst_2 = _dst + this->rgb_stride; py_1 = _py; py_2 = _py + this->y_stride; pu = _pu; pv = _pv; width = this->source_width >> 3; do { - RGB(0); + X_RGB(0); DST1CMAP(0); DST2CMAP(0); - RGB(1); + X_RGB(1); DST2CMAP(1); DST1CMAP(1); - RGB(2); + X_RGB(2); DST1CMAP(2); DST2CMAP(2); - RGB(3); + X_RGB(3); DST2CMAP(3); DST1CMAP(3); pu += 4; pv += 4; py_1 += 8; py_2 += 8; dst_1 += 8; dst_2 += 8; } while (--width); _dst += 2 * this->rgb_stride; _py += 2 * this->y_stride; _pu += this->uv_stride; _pv += this->uv_stride; } while (--height); } } static int div_round (int dividend, int divisor) { if (dividend > 0) return (dividend + (divisor>>1)) / divisor; else return -((-dividend + (divisor>>1)) / divisor); } -static void yuv2rgb_setup_tables (yuv2rgb_factory_t *this, int mode, int swapped) +static void yuv2rgb_set_csc_levels (yuv2rgb_factory_t *this, + int brightness, int contrast, int saturation) { int i; uint8_t table_Y[1024]; uint32_t * table_32 = 0; uint16_t * table_16 = 0; uint8_t * table_8 = 0; int entry_size = 0; void *table_r = 0, *table_g = 0, *table_b = 0; int shift_r = 0, shift_g = 0, shift_b = 0; int crv = Inverse_Table_6_9[this->matrix_coefficients][0]; int cbu = Inverse_Table_6_9[this->matrix_coefficients][1]; int cgu = -Inverse_Table_6_9[this->matrix_coefficients][2]; int cgv = -Inverse_Table_6_9[this->matrix_coefficients][3]; + int mode = this->mode; + int swapped = this->swapped; + for (i = 0; i < 1024; i++) { int j; - j = (76309 * (i - 384 - 16) + 32768) >> 16; + j = (76309 * (i - 384 - 16 + brightness) + 32768) >> 16; j = (j < 0) ? 0 : ((j > 255) ? 255 : j); table_Y[i] = j; } switch (mode) { case MODE_32_RGB: case MODE_32_BGR: - table_32 = malloc ((197 + 2*682 + 256 + 132) * sizeof (uint32_t)); + if (this->table_base == NULL) { + this->table_base = malloc ((197 + 2*682 + 256 + 132) * sizeof (uint32_t)); + } + table_32 = this->table_base; entry_size = sizeof (uint32_t); table_r = table_32 + 197; table_b = table_32 + 197 + 685; table_g = table_32 + 197 + 2*682; if (swapped) { switch (mode) { case MODE_32_RGB: shift_r = 8; shift_g = 16; shift_b = 24; break; case MODE_32_BGR: shift_r = 24; shift_g = 16; shift_b = 8; break; } } else { switch (mode) { case MODE_32_RGB: shift_r = 16; shift_g = 8; shift_b = 0; break; case MODE_32_BGR: shift_r = 0; shift_g = 8; shift_b = 16; break; } } for (i = -197; i < 256+197; i++) ((uint32_t *) table_r)[i] = table_Y[i+384] << shift_r; for (i = -132; i < 256+132; i++) ((uint32_t *) table_g)[i] = table_Y[i+384] << shift_g; for (i = -232; i < 256+232; i++) ((uint32_t *) table_b)[i] = table_Y[i+384] << shift_b; break; case MODE_24_RGB: case MODE_24_BGR: - table_8 = malloc ((256 + 2*232) * sizeof (uint8_t)); + if (this->table_base == NULL) { + this->table_base = malloc ((256 + 2*232) * sizeof (uint8_t)); + } + table_8 = this->table_base; entry_size = sizeof (uint8_t); table_r = table_g = table_b = table_8 + 232; for (i = -232; i < 256+232; i++) ((uint8_t * )table_b)[i] = table_Y[i+384]; break; case MODE_15_BGR: case MODE_16_BGR: case MODE_15_RGB: case MODE_16_RGB: - table_16 = malloc ((197 + 2*682 + 256 + 132) * sizeof (uint16_t)); + if (this->table_base == NULL) { + this->table_base = malloc ((197 + 2*682 + 256 + 132) * sizeof (uint16_t)); + } + table_16 = this->table_base; entry_size = sizeof (uint16_t); table_r = table_16 + 197; table_b = table_16 + 197 + 685; table_g = table_16 + 197 + 2*682; if (swapped) { switch (mode) { case MODE_15_BGR: shift_r = 8; shift_g = 5; shift_b = 2; break; case MODE_16_BGR: shift_r = 8; shift_g = 5; shift_b = 3; break; case MODE_15_RGB: shift_r = 2; shift_g = 5; shift_b = 8; break; case MODE_16_RGB: shift_r = 3; shift_g = 5; shift_b = 8; break; } } else { switch (mode) { case MODE_15_BGR: shift_r = 0; shift_g = 5; shift_b = 10; break; case MODE_16_BGR: shift_r = 0; shift_g = 5; shift_b = 11; break; case MODE_15_RGB: shift_r = 10; shift_g = 5; shift_b = 0; break; case MODE_16_RGB: shift_r = 11; shift_g = 5; shift_b = 0; break; } } for (i = -197; i < 256+197; i++) ((uint16_t *)table_r)[i] = (table_Y[i+384] >> 3) << shift_r; for (i = -132; i < 256+132; i++) { int j = table_Y[i+384] >> (((mode==MODE_16_RGB) || (mode==MODE_16_BGR)) ? 2 : 3); if (swapped) ((uint16_t *)table_g)[i] = (j&7) << 13 | (j>>3); else ((uint16_t *)table_g)[i] = j << 5; } for (i = -232; i < 256+232; i++) ((uint16_t *)table_b)[i] = (table_Y[i+384] >> 3) << shift_b; break; case MODE_8_RGB: case MODE_8_BGR: - table_8 = malloc ((197 + 2*682 + 256 + 132) * sizeof (uint8_t)); + if (this->table_base == NULL) { + this->table_base = malloc ((197 + 2*682 + 256 + 132) * sizeof (uint8_t)); + } + table_8 = this->table_base; entry_size = sizeof (uint8_t); table_r = table_8 + 197; table_b = table_8 + 197 + 685; table_g = table_8 + 197 + 2*682; switch (mode) { case MODE_8_RGB: shift_r = 5; shift_g = 2; shift_b = 0; break; case MODE_8_BGR: shift_r = 0; shift_g = 3; shift_b = 6; break; } for (i = -197; i < 256+197; i++) ((uint8_t *) table_r)[i] = (table_Y[i+384] >> 5) << shift_r; for (i = -132; i < 256+132; i++) ((uint8_t *) table_g)[i] = (table_Y[i+384] >> 5) << shift_g; for (i = -232; i < 256+232; i++) ((uint8_t *) table_b)[i] = (table_Y[i+384] >> 6) << shift_b; break; case MODE_8_GRAY: return; case MODE_PALETTE: - table_16 = malloc ((197 + 2*682 + 256 + 132) * sizeof (uint16_t)); + if (this->table_base == NULL) { + this->table_base = malloc ((197 + 2*682 + 256 + 132) * sizeof (uint16_t)); + } + table_16 = this->table_base; entry_size = sizeof (uint16_t); table_r = table_16 + 197; table_b = table_16 + 197 + 685; table_g = table_16 + 197 + 2*682; shift_r = 10; shift_g = 5; shift_b = 0; for (i = -197; i < 256+197; i++) ((uint16_t *)table_r)[i] = (table_Y[i+384] >> 3) << 10; for (i = -132; i < 256+132; i++) ((uint16_t *)table_g)[i] = (table_Y[i+384] >> 3) << 5; for (i = -232; i < 256+232; i++) ((uint16_t *)table_b)[i] = (table_Y[i+384] >> 3) << 0; break; default: - fprintf (stderr, "mode %d not supported by yuv2rgb\n", mode); - abort(); + lprintf ("mode %d not supported by yuv2rgb\n", mode); + _x_abort(); } for (i = 0; i < 256; i++) { this->table_rV[i] = (((uint8_t *) table_r) + entry_size * div_round (crv * (i-128), 76309)); this->table_gU[i] = (((uint8_t *) table_g) + entry_size * div_round (cgu * (i-128), 76309)); this->table_gV[i] = entry_size * div_round (cgv * (i-128), 76309); this->table_bU[i] = (((uint8_t *)table_b) + entry_size * div_round (cbu * (i-128), 76309)); } - this->gamma = 0; - this->entry_size = entry_size; + +#if defined(ARCH_X86) || defined(ARCH_X86_64) + mmx_yuv2rgb_set_csc_levels (this, brightness, contrast, saturation); +#endif } static uint32_t yuv2rgb_single_pixel_32 (yuv2rgb_t *this, uint8_t y, uint8_t u, uint8_t v) { uint32_t * r, * g, * b; r = this->table_rV[v]; g = (void *) (((uint8_t *)this->table_gU[u]) + this->table_gV[v]); b = this->table_bU[u]; return r[y] + g[y] + b[y]; } static uint32_t yuv2rgb_single_pixel_24_rgb (yuv2rgb_t *this, uint8_t y, uint8_t u, uint8_t v) { uint8_t * r, * g, * b; r = this->table_rV[v]; g = (void *) (((uint8_t *)this->table_gU[u]) + this->table_gV[v]); b = this->table_bU[u]; return (uint32_t) r[y] + ((uint32_t) g[y] << 8) + ((uint32_t) b[y] << 16); } static uint32_t yuv2rgb_single_pixel_24_bgr (yuv2rgb_t *this, uint8_t y, uint8_t u, uint8_t v) { uint8_t * r, * g, * b; r = this->table_rV[v]; g = (void *) (((uint8_t *)this->table_gU[u]) + this->table_gV[v]); b = this->table_bU[u]; return (uint32_t) b[y] + ((uint32_t) g[y] << 8) + ((uint32_t) r[y] << 16); } static uint32_t yuv2rgb_single_pixel_16 (yuv2rgb_t *this, uint8_t y, uint8_t u, uint8_t v) { uint16_t * r, * g, * b; r = this->table_rV[v]; g = (void *) (((uint8_t *)this->table_gU[u]) + this->table_gV[v]); b = this->table_bU[u]; return r[y] + g[y] + b[y]; } static uint32_t yuv2rgb_single_pixel_8 (yuv2rgb_t *this, uint8_t y, uint8_t u, uint8_t v) { uint8_t * r, * g, * b; r = this->table_rV[v]; g = (void *) (((uint8_t *)this->table_gU[u]) + this->table_gV[v]); b = this->table_bU[u]; return r[y] + g[y] + b[y]; } static uint32_t yuv2rgb_single_pixel_gray (yuv2rgb_t *this, uint8_t y, uint8_t u, uint8_t v) { return y; } static uint32_t yuv2rgb_single_pixel_palette (yuv2rgb_t *this, uint8_t y, uint8_t u, uint8_t v) { uint16_t * r, * g, * b; r = this->table_rV[v]; g = (void *) (((uint8_t *)this->table_gU[u]) + this->table_gV[v]); b = this->table_bU[u]; return this->cmap[r[y] + g[y] + b[y]]; } static void yuv2rgb_c_init (yuv2rgb_factory_t *this) { switch (this->mode) { case MODE_32_RGB: case MODE_32_BGR: this->yuv2rgb_fun = yuv2rgb_c_32; break; case MODE_24_RGB: case MODE_24_BGR: this->yuv2rgb_fun = (this->mode==MODE_24_RGB && !this->swapped) || (this->mode==MODE_24_BGR && this->swapped) ? yuv2rgb_c_24_rgb : yuv2rgb_c_24_bgr; break; case MODE_15_BGR: case MODE_16_BGR: case MODE_15_RGB: case MODE_16_RGB: this->yuv2rgb_fun = yuv2rgb_c_16; break; case MODE_8_RGB: case MODE_8_BGR: this->yuv2rgb_fun = yuv2rgb_c_8; break; case MODE_8_GRAY: this->yuv2rgb_fun = yuv2rgb_c_gray; break; case MODE_PALETTE: this->yuv2rgb_fun = yuv2rgb_c_palette; break; default: - printf ("yuv2rgb: mode %d not supported by yuv2rgb\n", this->mode); - abort(); + lprintf ("mode %d not supported by yuv2rgb\n", this->mode); + _x_abort(); } } static void yuv2rgb_single_pixel_init (yuv2rgb_factory_t *this) { switch (this->mode) { case MODE_32_RGB: case MODE_32_BGR: this->yuv2rgb_single_pixel_fun = yuv2rgb_single_pixel_32; break; case MODE_24_RGB: case MODE_24_BGR: this->yuv2rgb_single_pixel_fun = (this->mode==MODE_24_RGB && !this->swapped) || (this->mode==MODE_24_BGR && this->swapped) ? yuv2rgb_single_pixel_24_rgb : yuv2rgb_single_pixel_24_bgr; break; case MODE_15_BGR: case MODE_16_BGR: case MODE_15_RGB: case MODE_16_RGB: this->yuv2rgb_single_pixel_fun = yuv2rgb_single_pixel_16; break; case MODE_8_RGB: case MODE_8_BGR: this->yuv2rgb_single_pixel_fun = yuv2rgb_single_pixel_8; break; case MODE_8_GRAY: this->yuv2rgb_single_pixel_fun = yuv2rgb_single_pixel_gray; break; case MODE_PALETTE: this->yuv2rgb_single_pixel_fun = yuv2rgb_single_pixel_palette; break; default: - printf ("yuv2rgb: mode %d not supported by yuv2rgb\n", this->mode); - abort(); + lprintf ("mode %d not supported by yuv2rgb\n", this->mode); + _x_abort(); } } /* * yuy2 stuff */ static void yuy22rgb_c_32 (yuv2rgb_t *this, uint8_t * _dst, uint8_t * _p) { int U, V, Y; uint8_t * py_1, * pu, * pv; uint32_t * r, * g, * b; uint32_t * dst_1; int width, height; int dy; /* FIXME: implement unscaled version */ scale_line_4 (_p+1, this->u_buffer, this->dest_width >> 1, this->step_dx); scale_line_4 (_p+3, this->v_buffer, this->dest_width >> 1, this->step_dx); scale_line_2 (_p, this->y_buffer, this->dest_width, this->step_dx); dy = 0; - height = this->dest_height; + height = this->next_slice (this, &_dst); for (;;) { dst_1 = (uint32_t*)_dst; py_1 = this->y_buffer; pu = this->u_buffer; pv = this->v_buffer; width = this->dest_width >> 3; do { - RGB(0); + X_RGB(0); DST1(0); - RGB(1); + X_RGB(1); DST1(1); - RGB(2); + X_RGB(2); DST1(2); - RGB(3); + X_RGB(3); DST1(3); pu += 4; pv += 4; py_1 += 8; dst_1 += 8; } while (--width); dy += this->step_dy; _dst += this->rgb_stride; while (--height > 0 && dy < 32768) { xine_fast_memcpy (_dst, (uint8_t*)_dst-this->rgb_stride, this->dest_width*4); dy += this->step_dy; _dst += this->rgb_stride; } if (height <= 0) break; - _p += this->y_stride*2*(dy>>15); + _p += this->y_stride*(dy>>15); dy &= 32767; /* dy -= 32768; _p += this->y_stride*2; */ scale_line_4 (_p+1, this->u_buffer, this->dest_width >> 1, this->step_dx); scale_line_4 (_p+3, this->v_buffer, this->dest_width >> 1, this->step_dx); scale_line_2 (_p, this->y_buffer, this->dest_width, this->step_dx); } } static void yuy22rgb_c_24_rgb (yuv2rgb_t *this, uint8_t * _dst, uint8_t * _p) { int U, V, Y; uint8_t * py_1, * pu, * pv; uint8_t * r, * g, * b; uint8_t * dst_1; int width, height; int dy; /* FIXME: implement unscaled version */ scale_line_4 (_p+1, this->u_buffer, this->dest_width >> 1, this->step_dx); scale_line_4 (_p+3, this->v_buffer, this->dest_width >> 1, this->step_dx); scale_line_2 (_p, this->y_buffer, this->dest_width, this->step_dx); dy = 0; - height = this->dest_height; + height = this->next_slice (this, &_dst); for (;;) { dst_1 = _dst; py_1 = this->y_buffer; pu = this->u_buffer; pv = this->v_buffer; width = this->dest_width >> 3; do { - RGB(0); + X_RGB(0); DST1RGB(0); - RGB(1); + X_RGB(1); DST1RGB(1); - RGB(2); + X_RGB(2); DST1RGB(2); - RGB(3); + X_RGB(3); DST1RGB(3); pu += 4; pv += 4; py_1 += 8; dst_1 += 24; } while (--width); dy += this->step_dy; _dst += this->rgb_stride; while (--height > 0 && dy < 32768) { xine_fast_memcpy (_dst, (uint8_t*)_dst-this->rgb_stride, this->dest_width*3); dy += this->step_dy; _dst += this->rgb_stride; } if (height <= 0) break; - _p += this->y_stride*2*(dy>>15); + _p += this->y_stride*(dy>>15); dy &= 32767; /* dy -= 32768; _p += this->y_stride*2; */ scale_line_4 (_p+1, this->u_buffer, this->dest_width >> 1, this->step_dx); scale_line_4 (_p+3, this->v_buffer, this->dest_width >> 1, this->step_dx); scale_line_2 (_p, this->y_buffer, this->dest_width, this->step_dx); } } static void yuy22rgb_c_24_bgr (yuv2rgb_t *this, uint8_t * _dst, uint8_t * _p) { int U, V, Y; uint8_t * py_1, * pu, * pv; uint8_t * r, * g, * b; uint8_t * dst_1; int width, height; int dy; /* FIXME: implement unscaled version */ scale_line_4 (_p+1, this->u_buffer, this->dest_width >> 1, this->step_dx); scale_line_4 (_p+3, this->v_buffer, this->dest_width >> 1, this->step_dx); scale_line_2 (_p, this->y_buffer, this->dest_width, this->step_dx); dy = 0; - height = this->dest_height; + height = this->next_slice (this, &_dst); for (;;) { dst_1 = _dst; py_1 = this->y_buffer; pu = this->u_buffer; pv = this->v_buffer; width = this->dest_width >> 3; do { - RGB(0); + X_RGB(0); DST1BGR(0); - RGB(1); + X_RGB(1); DST1BGR(1); - RGB(2); + X_RGB(2); DST1BGR(2); - RGB(3); + X_RGB(3); DST1BGR(3); pu += 4; pv += 4; py_1 += 8; dst_1 += 24; } while (--width); dy += this->step_dy; _dst += this->rgb_stride; while (--height > 0 && dy < 32768) { xine_fast_memcpy (_dst, (uint8_t*)_dst-this->rgb_stride, this->dest_width*3); dy += this->step_dy; _dst += this->rgb_stride; } if (height <= 0) break; - _p += this->y_stride*2*(dy>>15); + _p += this->y_stride*(dy>>15); dy &= 32767; scale_line_4 (_p+1, this->u_buffer, this->dest_width >> 1, this->step_dx); scale_line_4 (_p+3, this->v_buffer, this->dest_width >> 1, this->step_dx); scale_line_2 (_p, this->y_buffer, this->dest_width, this->step_dx); } } static void yuy22rgb_c_16 (yuv2rgb_t *this, uint8_t * _dst, uint8_t * _p) { int U, V, Y; uint8_t * py_1, * pu, * pv; uint16_t * r, * g, * b; uint16_t * dst_1; int width, height; int dy; /* FIXME: implement unscaled version */ scale_line_4 (_p+1, this->u_buffer, this->dest_width >> 1, this->step_dx); scale_line_4 (_p+3, this->v_buffer, this->dest_width >> 1, this->step_dx); scale_line_2 (_p, this->y_buffer, this->dest_width, this->step_dx); dy = 0; - height = this->dest_height; + height = this->next_slice (this, &_dst); for (;;) { dst_1 = (uint16_t*)_dst; py_1 = this->y_buffer; pu = this->u_buffer; pv = this->v_buffer; width = this->dest_width >> 3; do { - RGB(0); + X_RGB(0); DST1(0); - RGB(1); + X_RGB(1); DST1(1); - RGB(2); + X_RGB(2); DST1(2); - RGB(3); + X_RGB(3); DST1(3); pu += 4; pv += 4; py_1 += 8; dst_1 += 8; } while (--width); dy += this->step_dy; _dst += this->rgb_stride; while (--height > 0 && dy < 32768) { xine_fast_memcpy (_dst, (uint8_t*)_dst-this->rgb_stride, this->dest_width*2); dy += this->step_dy; _dst += this->rgb_stride; } if (height <= 0) break; - _p += this->y_stride*2*(dy>>15); + _p += this->y_stride*(dy>>15); dy &= 32767; scale_line_4 (_p+1, this->u_buffer, this->dest_width >> 1, this->step_dx); scale_line_4 (_p+3, this->v_buffer, this->dest_width >> 1, this->step_dx); scale_line_2 (_p, this->y_buffer, this->dest_width, this->step_dx); } } static void yuy22rgb_c_8 (yuv2rgb_t *this, uint8_t * _dst, uint8_t * _p) { int U, V, Y; uint8_t * py_1, * pu, * pv; uint8_t * r, * g, * b; uint8_t * dst_1; int width, height; int dy; /* FIXME: implement unscaled version */ scale_line_4 (_p+1, this->u_buffer, this->dest_width >> 1, this->step_dx); scale_line_4 (_p+3, this->v_buffer, this->dest_width >> 1, this->step_dx); scale_line_2 (_p, this->y_buffer, this->dest_width, this->step_dx); dy = 0; - height = this->dest_height; + height = this->next_slice (this, &_dst); for (;;) { dst_1 = _dst; py_1 = this->y_buffer; pu = this->u_buffer; pv = this->v_buffer; width = this->dest_width >> 3; do { - RGB(0); + X_RGB(0); DST1(0); - RGB(1); + X_RGB(1); DST1(1); - RGB(2); + X_RGB(2); DST1(2); - RGB(3); + X_RGB(3); DST1(3); pu += 4; pv += 4; py_1 += 8; dst_1 += 8; } while (--width); dy += this->step_dy; _dst += this->rgb_stride; while (--height > 0 && dy < 32768) { xine_fast_memcpy (_dst, (uint8_t*)_dst-this->rgb_stride, this->dest_width); dy += this->step_dy; _dst += this->rgb_stride; } if (height <= 0) break; - _p += this->y_stride*2*(dy>>15); + _p += this->y_stride*(dy>>15); dy &= 32767; scale_line_4 (_p+1, this->u_buffer, this->dest_width >> 1, this->step_dx); scale_line_4 (_p+3, this->v_buffer, this->dest_width >> 1, this->step_dx); scale_line_2 (_p, this->y_buffer, this->dest_width, this->step_dx); } } static void yuy22rgb_c_gray (yuv2rgb_t *this, uint8_t * _dst, uint8_t * _p) { int width, height; int dy; uint8_t * dst; uint8_t * y; if (this->do_scale) { dy = 0; - height = this->dest_height; + height = this->next_slice (this, &_dst); for (;;) { scale_line_2 (_p, _dst, this->dest_width, this->step_dx); dy += this->step_dy; _dst += this->rgb_stride; while (--height > 0 && dy < 32768) { xine_fast_memcpy (_dst, (uint8_t*)_dst-this->rgb_stride, this->dest_width); dy += this->step_dy; _dst += this->rgb_stride; } if (height <= 0) break; - _p += this->y_stride*2*(dy>>15); + _p += this->y_stride*(dy>>15); dy &= 32767; } } else { - for (height = this->source_height; --height >= 0; ) { + for (height = this->next_slice (this, &_dst); --height >= 0; ) { dst = _dst; y = _p; for (width = this->source_width; --width >= 0; ) { *dst++ = *y; y += 2; } _dst += this->rgb_stride; - _p += this->y_stride*2; + _p += this->y_stride; } } } static void yuy22rgb_c_palette (yuv2rgb_t *this, uint8_t * _dst, uint8_t * _p) { int U, V, Y; uint8_t * py_1, * pu, * pv; uint16_t * r, * g, * b; uint8_t * dst_1; int width, height; int dy; scale_line_4 (_p+1, this->u_buffer, this->dest_width >> 1, this->step_dx); scale_line_4 (_p+3, this->v_buffer, this->dest_width >> 1, this->step_dx); scale_line_2 (_p, this->y_buffer, this->dest_width, this->step_dx); dy = 0; - height = this->dest_height; + height = this->next_slice (this, &_dst); for (;;) { dst_1 = _dst; py_1 = this->y_buffer; pu = this->u_buffer; pv = this->v_buffer; width = this->dest_width >> 3; do { - RGB(0); + X_RGB(0); DST1CMAP(0); - RGB(1); + X_RGB(1); DST1CMAP(1); - RGB(2); + X_RGB(2); DST1CMAP(2); - RGB(3); + X_RGB(3); DST1CMAP(3); pu += 4; pv += 4; py_1 += 8; dst_1 += 8; } while (--width); dy += this->step_dy; _dst += this->rgb_stride; while (--height > 0 && dy < 32768) { xine_fast_memcpy (_dst, (uint8_t*)_dst-this->rgb_stride, this->dest_width); dy += this->step_dy; _dst += this->rgb_stride; } if (height <= 0) break; - _p += this->y_stride*2*(dy>>15); + _p += this->y_stride*(dy>>15); dy &= 32767; scale_line_4 (_p+1, this->u_buffer, this->dest_width >> 1, this->step_dx); scale_line_4 (_p+3, this->v_buffer, this->dest_width >> 1, this->step_dx); scale_line_2 (_p, this->y_buffer, this->dest_width, this->step_dx); } } static void yuy22rgb_c_init (yuv2rgb_factory_t *this) { switch (this->mode) { case MODE_32_RGB: case MODE_32_BGR: this->yuy22rgb_fun = yuy22rgb_c_32; break; case MODE_24_RGB: case MODE_24_BGR: this->yuy22rgb_fun = (this->mode==MODE_24_RGB && !this->swapped) || (this->mode==MODE_24_BGR && this->swapped) ? yuy22rgb_c_24_rgb : yuy22rgb_c_24_bgr; break; case MODE_15_BGR: case MODE_16_BGR: case MODE_15_RGB: case MODE_16_RGB: this->yuy22rgb_fun = yuy22rgb_c_16; break; case MODE_8_RGB: case MODE_8_BGR: this->yuy22rgb_fun = yuy22rgb_c_8; break; case MODE_8_GRAY: this->yuy22rgb_fun = yuy22rgb_c_gray; break; case MODE_PALETTE: this->yuy22rgb_fun = yuy22rgb_c_palette; break; default: - printf ("yuv2rgb: mode %d not supported for yuy2\n", this->mode); + lprintf ("mode %d not supported for yuy2\n", this->mode); } } -yuv2rgb_t *yuv2rgb_create_converter (yuv2rgb_factory_t *factory) { +static yuv2rgb_t *yuv2rgb_create_converter (yuv2rgb_factory_t *factory) { yuv2rgb_t *this = xine_xmalloc (sizeof (yuv2rgb_t)); - + + this->swapped = factory->swapped; this->cmap = factory->cmap; this->y_chunk = this->y_buffer = NULL; this->u_chunk = this->u_buffer = NULL; this->v_chunk = this->v_buffer = NULL; +#ifdef HAVE_MLIB + this->mlib_chunk = this->mlib_buffer = NULL; + this->mlib_resize_chunk = this->mlib_resize_buffer = NULL; + this->mlib_filter_type = MLIB_BILINEAR; +#endif + this->table_rV = factory->table_rV; this->table_gU = factory->table_gU; this->table_gV = factory->table_gV; this->table_bU = factory->table_bU; + this->table_mmx = factory->table_mmx; this->yuv2rgb_fun = factory->yuv2rgb_fun; this->yuy22rgb_fun = factory->yuy22rgb_fun; this->yuv2rgb_single_pixel_fun = factory->yuv2rgb_single_pixel_fun; this->configure = yuv2rgb_configure; + this->next_slice = yuv2rgb_next_slice; + this->dispose = yuv2rgb_dispose; return this; } /* * factory functions */ -void yuv2rgb_set_gamma (yuv2rgb_factory_t *this, int gamma) { - - int i; - - for (i = 0; i < 256; i++) { - (uint8_t *)this->table_rV[i] += this->entry_size*(gamma - this->gamma); - (uint8_t *)this->table_gU[i] += this->entry_size*(gamma - this->gamma); - (uint8_t *)this->table_bU[i] += this->entry_size*(gamma - this->gamma); - } -#ifdef ARCH_X86 - mmx_yuv2rgb_set_gamma(gamma); -#endif - this->gamma = gamma; -} -int yuv2rgb_get_gamma (yuv2rgb_factory_t *this) { +static void yuv2rgb_factory_dispose (yuv2rgb_factory_t *this) { - return this->gamma; + free (this->table_base); + free (this->table_mmx_base); + free (this); } yuv2rgb_factory_t* yuv2rgb_factory_init (int mode, int swapped, uint8_t *cmap) { yuv2rgb_factory_t *this; - -#ifdef ARCH_X86 uint32_t mm = xine_mm_accel(); -#endif this = malloc (sizeof (yuv2rgb_factory_t)); this->mode = mode; this->swapped = swapped; this->cmap = cmap; this->create_converter = yuv2rgb_create_converter; - this->set_gamma = yuv2rgb_set_gamma; - this->get_gamma = yuv2rgb_get_gamma; + this->set_csc_levels = yuv2rgb_set_csc_levels; + this->dispose = yuv2rgb_factory_dispose; this->matrix_coefficients = 6; + this->table_base = NULL; + this->table_mmx = NULL; + this->table_mmx_base = NULL; - yuv2rgb_setup_tables (this, mode, swapped); + yuv2rgb_set_csc_levels (this, 0, 128, 128); /* * auto-probe for the best yuv2rgb function */ this->yuv2rgb_fun = NULL; -#ifdef ARCH_X86 +#if defined(ARCH_X86) || defined(ARCH_X86_64) if ((this->yuv2rgb_fun == NULL) && (mm & MM_ACCEL_X86_MMXEXT)) { yuv2rgb_init_mmxext (this); +#ifdef LOG if (this->yuv2rgb_fun != NULL) printf ("yuv2rgb: using MMXEXT for colorspace transform\n"); +#endif } if ((this->yuv2rgb_fun == NULL) && (mm & MM_ACCEL_X86_MMX)) { yuv2rgb_init_mmx (this); +#ifdef LOG if (this->yuv2rgb_fun != NULL) printf ("yuv2rgb: using MMX for colorspace transform\n"); +#endif + } +#ifdef __arm__ + if (this->yuv2rgb_fun == NULL) { + yuv2rgb_init_arm ( this ); + + if(this->yuv2rgb_fun != NULL) + printf("yuv2rgb: using arm4l assembler for colorspace transform\n" ); } #endif + +#endif #if HAVE_MLIB - if (this->yuv2rgb_fun == NULL) { + if ((this->yuv2rgb_fun == NULL) && (mm & MM_ACCEL_MLIB)) { yuv2rgb_init_mlib (this); +#ifdef LOG if (this->yuv2rgb_fun != NULL) printf ("yuv2rgb: using medialib for colorspace transform\n"); - } #endif -#ifdef __arm__ - if (this->yuv2rgb_fun == NULL) { - yuv2rgb_init_arm ( this ); - - if(this->yuv2rgb_fun != NULL) - printf("yuv2rgb: using arm4l assembler for colorspace transform\n" ); } #endif if (this->yuv2rgb_fun == NULL) { - printf ("yuv2rgb: no accelerated colorspace conversion found\n"); + lprintf ("no accelerated colorspace conversion found\n"); + yuv2rgb_c_init (this); } /* * auto-probe for the best yuy22rgb function */ /* FIXME: implement mmx/mlib functions */ yuy22rgb_c_init (this); /* * set up single pixel function */ yuv2rgb_single_pixel_init (this); return this; } - diff --git a/noncore/multimedia/opieplayer2/yuv2rgb.h b/noncore/multimedia/opieplayer2/yuv2rgb.h index e453243..1833889 100644 --- a/noncore/multimedia/opieplayer2/yuv2rgb.h +++ b/noncore/multimedia/opieplayer2/yuv2rgb.h @@ -1,152 +1,172 @@ #ifndef HAVE_YUV2RGB_H #define HAVE_YUV2RGB_h +#ifdef HAVE_MLIB +#include <mlib_video.h> +#endif + #include <inttypes.h> typedef struct yuv2rgb_s yuv2rgb_t; typedef struct yuv2rgb_factory_s yuv2rgb_factory_t; /* * function types for functions which can be replaced * by hardware-accelerated versions */ /* internal function use to scale yuv data */ typedef void (*scale_line_func_t) (uint8_t *source, uint8_t *dest, int width, int step); typedef void (*yuv2rgb_fun_t) (yuv2rgb_t *this, uint8_t * image, uint8_t * py, uint8_t * pu, uint8_t * pv) ; typedef void (*yuy22rgb_fun_t) (yuv2rgb_t *this, uint8_t * image, uint8_t * p); typedef uint32_t (*yuv2rgb_single_pixel_fun_t) (yuv2rgb_t *this, uint8_t y, uint8_t u, uint8_t v); - /* * modes supported - feel free to implement yours */ #define MODE_8_RGB 1 #define MODE_8_BGR 2 #define MODE_15_RGB 3 #define MODE_15_BGR 4 #define MODE_16_RGB 5 #define MODE_16_BGR 6 #define MODE_24_RGB 7 #define MODE_24_BGR 8 #define MODE_32_RGB 9 #define MODE_32_BGR 10 #define MODE_8_GRAY 11 #define MODE_PALETTE 12 struct yuv2rgb_s { - /* * configure converter for scaling factors */ int (*configure) (yuv2rgb_t *this, int source_width, int source_height, int y_stride, int uv_stride, int dest_width, int dest_height, int rgb_stride); /* + * start a new field or frame if dest is NULL + */ + int (*next_slice) (yuv2rgb_t *this, uint8_t **dest); + + /* + * free resources + */ + void (*dispose) (yuv2rgb_t *this); + + /* * this is the function to call for the yuv2rgb and scaling process */ yuv2rgb_fun_t yuv2rgb_fun; /* * this is the function to call for the yuy2->rgb and scaling process */ yuy22rgb_fun_t yuy22rgb_fun; /* * this is the function to call for the yuv2rgb for a single pixel * (used for converting clut colors) */ yuv2rgb_single_pixel_fun_t yuv2rgb_single_pixel_fun; /* private stuff below */ int source_width, source_height; int y_stride, uv_stride; int dest_width, dest_height; int rgb_stride; + int slice_height, slice_offset; int step_dx, step_dy; - int do_scale; + int do_scale, swapped; uint8_t *y_buffer; uint8_t *u_buffer; uint8_t *v_buffer; void *y_chunk; void *u_chunk; void *v_chunk; +#ifdef HAVE_MLIB + uint8_t *mlib_buffer; + uint8_t *mlib_resize_buffer; + void *mlib_chunk; + void *mlib_resize_chunk; + mlib_filter mlib_filter_type; +#endif + void **table_rV; void **table_gU; int *table_gV; void **table_bU; + void *table_mmx; uint8_t *cmap; - scale_line_func_t scale_line; - + scale_line_func_t scale_line; } ; /* * convenience class to easily create a lot of converters */ struct yuv2rgb_factory_s { - yuv2rgb_t* (*create_converter) (yuv2rgb_factory_t *this); - /* - * adjust gamma (-100 to 100 looks fine) + /* + * set color space conversion levels * for all converters produced by this factory */ - void (*set_gamma) (yuv2rgb_factory_t *this, int gamma); + void (*set_csc_levels) (yuv2rgb_factory_t *this, + int brightness, int contrast, int saturation); /* - * get gamma value + * free resources */ - int (*get_gamma) (yuv2rgb_factory_t *this); + void (*dispose) (yuv2rgb_factory_t *this); /* private data */ int mode; int swapped; uint8_t *cmap; - int gamma; - int entry_size; - uint32_t matrix_coefficients; + void *table_base; void *table_rV[256]; void *table_gU[256]; int table_gV[256]; void *table_bU[256]; + void *table_mmx_base; + void *table_mmx; /* preselected functions for mode/swap/hardware */ yuv2rgb_fun_t yuv2rgb_fun; yuy22rgb_fun_t yuy22rgb_fun; yuv2rgb_single_pixel_fun_t yuv2rgb_single_pixel_fun; - }; yuv2rgb_factory_t *yuv2rgb_factory_init (int mode, int swapped, uint8_t *colormap); - + /* * internal stuff below this line */ -void mmx_yuv2rgb_set_gamma(int gamma); +void mmx_yuv2rgb_set_csc_levels(yuv2rgb_factory_t *this, + int brightness, int contrast, int saturation); void yuv2rgb_init_mmxext (yuv2rgb_factory_t *this); void yuv2rgb_init_mmx (yuv2rgb_factory_t *this); void yuv2rgb_init_mlib (yuv2rgb_factory_t *this); -void yuv2rgb_init_arm (yuv2rgb_factory_t *this); #endif |