/* 2004.02.01 first released source code for IOMP */ /* * * Copyright (C) James Courtier-Dutton James@superbug.demon.co.uk - July 2001 * * 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 * *------------------------------------------------------------ * */ /* #define LOG_BLEND_YUV #define LOG_BLEND_RGB16 */ int XINE_CB_PAUSE = 0; int XINE_CB_RESET = 0; extern int AVAMAX_OSD_SHOW; #define OSD_CMD_COLORBLOCK 0 #define OSD_CMD_SHOW 1 #define OSD_CMD_HIDE 2 #define OSD_CMD_ALPHA 3 #define OSD_CMD_COLOR 4 #include #include #include #include #include "xine_internal.h" #include "video_out.h" #include "alphablend.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) extern dvdspu_color_block_t *global_color_blocks; 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 *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_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) 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; } typedef struct { int x1; int x2; unsigned int *color; unsigned int *trans; } split_info_t; #define XINE_CB_SIGNATURE 0x879a #if 1 static void reset_all_cb(vo_overlay_t *img_overl) { dvdspu_color_block_t *cb; //thread_mutex_lock(&img_overl->update_lock); for (cb=global_color_blocks; cb->signature==XINE_CB_SIGNATURE; cb = cb->next); while (cb) { if (cb->signature==XINE_CB_SIGNATURE) cb->displayed = 1; cb = cb->next; } XINE_CB_RESET = 0; /* clear reset flag */ //thread_mutex_unlock(&img_overl->update_lock); } #endif static int tail_frames = 0; extern dvdspu_color_block_t *global_travel_cb; extern int previous_timestamp; extern int frame_rate_code; /* decalre in xine-engine/osd.c */ extern int osd_frame_counter; /* declare in xine-engine/osd.c */ #define FRAME_OFFSET 20 #if 0 inline int frame_to_time(int frame_counter) { int f_count; if (frame_rate_code==3) { /* PAL */ f_count = (3003 * (frame_counter-FRAME_OFFSET))/1024; return (f_count*6)/5; } /* DEFAULT NTSC */ return (3003 * (frame_counter-FRAME_OFFSET))/1024; } #endif inline int frame_to_time(int frame_counter) { int f_count; if (frame_rate_code==3) { /* PAL */ f_count = (3120 * (frame_counter-FRAME_OFFSET))/1024; return (f_count*6)/5; } /* DEFAULT NTSC */ return (3120 * (frame_counter-FRAME_OFFSET))/1024; } static void dump_cb(dvdspu_color_block_t *cb) { dvdspu_vert_block_t *vb; int i; for (vb = cb->vert_blocks; vb; vb=vb->next) { printf("vb->y=%d, vb->height=%d\n", vb->y, vb->height); for (i=0; inum_hori_blocks; i++) printf("vb->hori_blocks[%d].x=%d\n", i, vb->hori_blocks[i].x); } printf("dump cb->osd_state=%d, timestamp=%d now_time=%d\n", cb->osd_cmd, cb->time_stamp, frame_to_time(osd_frame_counter)); printf("---------------------------------------\n"); } extern int osd_is_showing; /* in xine-engine/osd.c */ extern int forced_display; /* in xine-engine/osd.c, indicate if output is "forced" */ extern int SPU_ON; /* declase in xine-engine/xine.c */ extern int enable_alpha; /* in xine-engine/osd.c */ extern int enable_color; /* in xine-engine/osd.c */ uint8_t TRANS_ALPHA[4]; uint32_t TRANS_COLOR[4]; static void unpack_trans(uint32_t value) { TRANS_ALPHA[0] = (value>>24)&0xff; TRANS_ALPHA[1] = (value>>16)&0xff; TRANS_ALPHA[2] = (value>>8)&0xff; TRANS_ALPHA[3] = (value)&0xff; #if 0 printf("trans (%d,%d,%d,%d)\n", TRANS_ALPHA[0], TRANS_ALPHA[1], TRANS_ALPHA[2], TRANS_ALPHA[3]); #endif } #if 1 void check_osd_state(dvdspu_color_block_t *cb) { static dvdspu_color_block_t *previous_cb = NULL; if (cb==NULL) return; if (cb==previous_cb) return; previous_cb = cb; if (cb->vert_blocks==NULL) { /* is show hide message */ switch (cb->osd_cmd) { case OSD_CMD_SHOW: osd_is_showing = 1; break; case OSD_CMD_HIDE: osd_is_showing = 0; break; case OSD_CMD_ALPHA: enable_alpha = 1; unpack_trans(cb->alpha_color); break; case OSD_CMD_COLOR: //printf("ENABLE COLOR !!!! ==================> \n"); enable_color = 1; TRANS_COLOR[0] = cb->set_color[0]; TRANS_COLOR[1] = cb->set_color[1]; TRANS_COLOR[2] = cb->set_color[2]; TRANS_COLOR[3] = cb->set_color[3]; } } //dump_cb(cb); } #endif static int spu_skip_frames; /* this function can only be call ONCE per frame !!!! */ void eat_one_spu() { int now_time, eaten; dvdspu_color_block_t *cb; dvdspu_color_block_t *next_cb; if (XINE_CB_PAUSE==0) { osd_frame_counter++; } if (spu_skip_frames>0) spu_skip_frames--; very_dirty: eaten = 0; if (osd_frame_counter<0) return; /* don't eat any thing until osd_frame_counter is ticking */ if (global_travel_cb==NULL) { cb = global_color_blocks; } else { cb = global_color_blocks; } for (; cb && cb->displayed && cb->signature==XINE_CB_SIGNATURE; cb = cb->next); next_cb = cb ? cb->next : NULL; check_osd_state(cb); if (next_cb==NULL&&cb!=NULL) { //printf("osd_frame_counter=%d, tail_frames=%d\n", osd_frame_counter, tail_frames); if (osd_frame_counter>tail_frames) { cb->displayed = 1; global_travel_cb = cb->next; eaten = 1; } } //printf("eat_one_spu=0x%x\n", cb); if (next_cb && cb && (cb->signature==XINE_CB_SIGNATURE)) { //printf("cb=%p, osd_frame_counter=%d\n", cb, osd_frame_counter); if (previous_timestamp > next_cb->time_stamp) { //printf("reset previous_timestamp, previous_timestamp=%d, next_cb->time_stamp=%d\n", // previous_timestamp, next_cb->time_stamp); #if 1 osd_frame_counter = 0; /* reset */ previous_timestamp = 0; /* reset */ #else while (cb) { cb->time_stamp += (previous_timestamp+1); cb = cb->next; } #endif goto very_dirty; } if (osd_frame_counter>=0&&osd_frame_counter<=22347) { now_time = frame_to_time(osd_frame_counter); //printf("next_cb->time_stamp=%d, cb->time_stamp=%d, now_time=%d\n", // next_cb->time_stamp, cb->time_stamp, now_time); if (next_cb->time_stamp <= now_time) { if ((cb->next!=NULL)&& (cb->next->signature==XINE_CB_SIGNATURE)) { cb->displayed = 1; global_travel_cb = cb->next; tail_frames = osd_frame_counter + (next_cb->time_stamp-cb->time_stamp)/3; /* around 1 second */ eaten = 1; } else { if (osd_frame_counter>tail_frames) { cb->displayed = 1; global_travel_cb = cb->next; eaten = 1; } } } previous_timestamp = next_cb->time_stamp; } else { if ((cb->next!=NULL)&&(cb->next->signature==XINE_CB_SIGNATURE)) { cb->displayed = 1; /* force eat */ global_travel_cb = cb->next; eaten = 1; } } //printf("===========> SPU !!! (0x%x)\n", img_overl); } else { /* no SPU !! */ if (cb==NULL) osd_frame_counter = -1; /* clear the frame counter */ } if (eaten!=0) goto very_dirty; } split_info_t rle_split_info[20]; extern dvdspu_color_block_t *global_color_blocks; extern int spu_current_enable; static int split_rle(vo_overlay_t *img_overl, int x1, int x2, int y, unsigned int *color, unsigned int *trans, int now_time) { int split_count = 1; int now_time; rle_split_info[0].x1 = x1; rle_split_info[0].x2 = x2; rle_split_info[0].color = color; rle_split_info[0].trans = trans; if (spu_current_enable==0) { /* disable spu */ spu_skip_frames = 5; return 0; } if (spu_skip_frames>0) return 0; /* if not "fouced display", remove ths OSD */ //if (osd_is_showing==0&&forced_display==0) // return 0; if (osd_is_showing==0) { // OSD is not showing, return 0 for non-showing OSD return 0; } if (forced_display==0&&SPU_ON==0) return 0; if(global_color_blocks!=NULL) { dvdspu_color_block_t *cb; dvdspu_vert_block_t *vb; int i; if (global_travel_cb==NULL) { cb = global_color_blocks; } else { cb = global_travel_cb; } /* skip displayed chunk */ for (;cb && cb->displayed && cb->signature==XINE_CB_SIGNATURE; cb = cb->next) ; if (cb==NULL) { osd_frame_counter = -1; /* reset */ } if (cb && cb->signature==XINE_CB_SIGNATURE) { if (osd_frame_counter<0) { //printf("reset osd_frame_counter !\n"); osd_frame_counter = 0; /* reset */ } if (cb->vert_blocks==0) return 1; /* no split */ for (vb = cb->vert_blocks; vb; vb=vb->next) { #if 0 if (vb->y==138&&vb->height==4) { hi_test = 1; //printf("y=%d\n", y); } #endif if ((y>=vb->y)&&(yy+vb->height)) { /* fall into */ for (i=0; inum_hori_blocks; i++) { if (x2<(vb->hori_blocks[i].x - img_overl->x)) { //if (hi_test) printf("case 0\n"); return split_count; /* don't have to split anymore*/ } if (x1<(vb->hori_blocks[i].x - img_overl->x)) { //if (hi_test) printf("case 1\n"); rle_split_info[split_count-1].x1 = x1; rle_split_info[split_count-1].x2 = vb->hori_blocks[i].x - img_overl->x; rle_split_info[split_count-1].color = color; rle_split_info[split_count-1].trans = trans; rle_split_info[split_count].x1 = vb->hori_blocks[i].x - img_overl->x; rle_split_info[split_count].x2 = x2; color = vb->hori_blocks[i].color; trans = vb->hori_blocks[i].trans; rle_split_info[split_count].color = color; /* set new color */ rle_split_info[split_count].trans = trans; split_count++; x1 = vb->hori_blocks[i].x -img_overl->x; /* move to next */ } else { //if (hi_test) return 1; color = vb->hori_blocks[i].color; trans = vb->hori_blocks[i].trans; rle_split_info[split_count-1].color = color; /* set new color here !! */ rle_split_info[split_count-1].trans = trans; #if 0 if (hi_test) { printf("case 2\n"); printf("split_count=%d, trans=(%d,%d,%d,%d)\n", split_count, trans[0], trans[1], trans[2], trans[3]); } #endif } } } } } } //thread_mutex_unlock(&img_overl->update_lock); return split_count; /* no split */ } typedef struct { uint32_t yuv; uint16_t rgb; } yuv_cache_t; #define CACHE_SIZE 3 yuv_cache_t cache[CACHE_SIZE] = { {0,0}, {0,0}, {0,0} }; static int cache_idx = 0; uint16_t get_cache(uint32_t value, uint16_t *ret) { int i; for (i=0; i255) r = 255; if (g<0) g = 0; if (g>255) g = 255; if (b<0) b = 0; if (b>255) b = 255; ret = ((r&0xf8)<<8) | ((g&0xfc)<<3) | ((b&0xf8)>>3); insert_cache(yuv, ret); return (uint16_t)ret; } extern void avamax_xine_osd_display(unsigned char *fb,int w, int h); extern void avamax_xine_osd_draw_text(int x, int y,const char *text); int test_inited = 0; void blend_rgb16 (uint8_t * img, vo_overlay_t * img_overl, int img_width, int img_height, int dst_width, int dst_height) { uint8_t *trans; 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 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. */ int now_time = frame_to_time(osd_frame_counter); #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");} #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); */ /* 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; /* avoid buffer overflow */ if( (src_height + img_overl->y) >= dst_height ) src_height = dst_height - 1 - img_overl->y; 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; #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 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]; 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) { 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; } } } 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; } 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) { zone_state = 6; } break; case 6: /* Finished */ XINE_ASSERT(0,"Don't ever get here\n"); /* This case will not fall through, XINE_ASSERT contains a call to abort() */ case 7: /* No button */ clut = (clut_t*) img_overl->color; trans = img_overl->trans; if (enable_alpha) trans = TRANS_ALPHA; #if 0 if (enable_color) clut = TRANS_COLOR; #endif o = trans[clr]; rle_this_bite = rle_remainder; rle_remainder = 0; rlelen -= rle_this_bite; if (1) { int i, split_count; split_count = split_rle(img_overl, x, x+rle_this_bite, y+img_overl->y, (unsigned int *)clut, (unsigned int *)trans, now_time); for (i=0; i65536) { mem_blend16(img_pix+x1_scaled, makergb16(*((uint32_t *)&clut[clr])), o, x2_scaled-x1_scaled); } else { 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) { zone_state = 6; } break; default: ; } } if (XINE_CB_RESET) { printf("XINE_CB_RESET !!\n"); reset_all_cb(img_overl); } if (AVAMAX_OSD_SHOW) avamax_xine_osd_display(img, img_width, img_height); #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) { 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 ) clip_right = img_overl->clip_right; else clip_right = dst_width - 1 - img_overl->x; /* avoid buffer overflow */ if( (src_height + img_overl->y) >= dst_height ) src_height = dst_height - 1 - 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); rle_elem_t *rle_start = rle; for (x = x1_scaled = 0; x < src_width;) { uint8_t clr; 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; } else { o = 0; } } 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 { o = 0; } } } 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, o, x2_scaled-x1_scaled); } x1_scaled = x2_scaled; x += rlelen; rle++; if (rle >= rle_limit) break; } 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 */ } } if (AVAMAX_OSD_SHOW) avamax_xine_osd_display(img, img_width, img_height); } void blend_rgb32 (uint8_t * img, vo_overlay_t * img_overl, int img_width, int img_height, int dst_width, int dst_height) { 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 ) clip_right = img_overl->clip_right; else clip_right = dst_width - 1 - img_overl->x; /* avoid buffer overflow */ if( (src_height + img_overl->y) >= dst_height ) src_height = dst_height - 1 - 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; for (x = x1_scaled = 0; x < src_width;) { uint8_t clr; 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; } else { o = 0; } } else if( clip_right < x + rlelen ) { if( clip_right > x ) { x2_scaled = SCALED_TO_INT( clip_right * x_scale); mem_blend32(img_pix + x1_scaled*4, (uint8_t *)&clut[clr], o, x2_scaled-x1_scaled); o = 0; } else { o = 0; } } } x2_scaled = SCALED_TO_INT((x + rlelen) * x_scale); if (o && mask) { mem_blend32(img_pix + x1_scaled*4, (uint8_t *)&clut[clr], o, x2_scaled-x1_scaled); } x1_scaled = x2_scaled; x += rlelen; rle++; if (rle >= rle_limit) break; } 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 */ } } if (AVAMAX_OSD_SHOW) avamax_xine_osd_display(img, img_width, img_height); } 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++; } } void blend_yuv (uint8_t *dst_base[3], vo_overlay_t * img_overl, int dst_width, int dst_height, int dst_pitches[3]) { 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 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_pitches[0] * y_off + x_off; uint8_t *dst_cr = dst_base[2] + (y_off / 2) * dst_pitches[1] + (x_off / 2) + 1; uint8_t *dst_cb = dst_base[1] + (y_off / 2) * dst_pitches[2] + (x_off / 2) + 1; #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 ) clip_right = img_overl->clip_right; else clip_right = dst_width - 1 - x_off; /* avoid buffer overflow */ if( (src_height + y_off) >= dst_height ) src_height = dst_height - 1 - y_off; rlelen=rle_remainder=0; for (y = 0; y < src_height; y++) { ymask = ((img_overl->clip_top > y) || (img_overl->clip_bottom < y)); 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; #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)) { printf("alphablend: major bug in blend_yuv < 0\n"); } 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 - 1) > 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_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 */ 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); } } } #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_pitches[0]; if (y & 1) { dst_cr += dst_pitches[2]; dst_cb += dst_pitches[1]; } } #ifdef LOG_BLEND_YUV printf("overlay_blend ended\n"); #endif } void blend_yuy2 (uint8_t * dst_img, vo_overlay_t * img_overl, int dst_width, int dst_height, int dst_pitch) { 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, y; int l; int clip_right; uint32_t yuy2; 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 ) clip_right = img_overl->clip_right; else clip_right = dst_width - 1 - x_off; /* avoid buffer overflow */ if( (src_height + y_off) >= dst_height ) src_height = dst_height - 1 - y_off; for (y = 0; y < src_height; y++) { mask = !(img_overl->clip_top > y || img_overl->clip_bottom < y); 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; } else { o = 0; } } else if( clip_right < x + rlelen ) { if( clip_right > x ) { /* fixme: case not implemented */ o = 0; } else { o = 0; } } } if (o && mask) { l = rlelen>>1; if( !((x_off+x) & 1) ) { *(((uint8_t *)&yuy2) + 0) = my_clut[clr].y; *(((uint8_t *)&yuy2) + 1) = my_clut[clr].cb; *(((uint8_t *)&yuy2) + 2) = my_clut[clr].y; *(((uint8_t *)&yuy2) + 3) = my_clut[clr].cr; } else { *(((uint8_t *)&yuy2) + 0) = my_clut[clr].y; *(((uint8_t *)&yuy2) + 1) = my_clut[clr].cr; *(((uint8_t *)&yuy2) + 2) = my_clut[clr].y; *(((uint8_t *)&yuy2) + 3) = my_clut[clr].cb; } if (o >= 15) { while(l--) { *((uint16_t *)dst)++ = *(((uint16_t *)&yuy2) + 0); *((uint16_t *)dst)++ = *(((uint16_t *)&yuy2) + 1); } if(rlelen & 1) *((uint16_t *)dst)++ = *(((uint16_t *)&yuy2) + 0); } else { if( l ) { mem_blend32(dst, (uint8_t *)&yuy2, o, l); dst += 4*l; } if(rlelen & 1) { *dst = BLEND_BYTE(*dst, *(((uint8_t *)&yuy2) + 0), o); dst++; *dst = BLEND_BYTE(*dst, *(((uint8_t *)&yuy2) + 1), o); dst++; } } } else { dst += rlelen*2; } x += rlelen; rle++; if (rle >= rle_limit) break; } if (rle >= rle_limit) break; dst_y += dst_pitch; } }