/* * Linux VeeJay * EffecTV - Realtime Digital Video Effector * Copyright (C) 2001-2006 FUKUCHI Kentaro * * ChameleonTV - Vanishing into the wall!! * Copyright (C) 2003 FUKUCHI Kentaro * * Ported to veejay by Niels Elburg * * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307 , USA. */ #include #include "chameleon.h" #include "common.h" #include vj_effect *chameleon_init(int w, int h) { vj_effect *ve = (vj_effect *) vj_calloc(sizeof(vj_effect)); ve->num_params = 2; ve->defaults = (int *) vj_calloc(sizeof(int) * ve->num_params); /* default values */ ve->limits[0] = (int *) vj_calloc(sizeof(int) * ve->num_params); /* min */ ve->limits[1] = (int *) vj_calloc(sizeof(int) * ve->num_params); /* max */ ve->limits[0][0] = 0; ve->limits[1][0] = 1; ve->limits[0][1] = 0; ve->limits[1][1] = 1; ve->defaults[0] = 0; ve->defaults[1] = 0; ve->description = "Chameleon TV"; ve->sub_format = 1; ve->extra_frame = 0; ve->has_user = 0; return ve; } static int refresh_bg_ = -1; static int last_mode_ = -1; static int N__ = 0; static int n__ = 0; static int has_bg = 0; int32_t *sum = NULL; uint8_t *timebuffer = NULL; uint8_t *tmpimage[3] = { NULL,NULL,NULL}; static int plane = 0; uint8_t *bgimage[3] = { NULL,NULL,NULL}; #define PLANES_DEPTH 6 #define PLANES (1<< PLANES_DEPTH) int chameleon_malloc(int w, int h) { if( bgimage[0] ) free(bgimage[0]); bgimage[0] = (uint8_t*)vj_yuvalloc(w,h); if(!bgimage[0]) return 0; bgimage[1] = bgimage[0] + (w*h); bgimage[2] = bgimage[1] + (w*h); if(tmpimage[0]) free(tmpimage[0]); tmpimage[0] = (uint8_t*)vj_yuvalloc(w,h); if(!tmpimage[0]) return 0; tmpimage[1] = tmpimage[0] + (w*h); tmpimage[2] = tmpimage[1] + (w*h); if( sum ) free(sum); sum = (int32_t*) vj_calloc( w * h * sizeof(int32_t)); if( timebuffer ) free(timebuffer); timebuffer = (uint8_t*) vj_calloc( w* h * PLANES ); has_bg = 0; plane = 0; N__ = 0; n__ = 0; last_mode_ = -1; refresh_bg_ = -1; return 1; } void chameleon_free() { if( bgimage[0]) free(bgimage[0]); if( tmpimage[0]) free(tmpimage[0]); if( timebuffer ) free(timebuffer); if( sum ) free(sum); bgimage[0] = NULL; tmpimage[0] = NULL; timebuffer = NULL; sum = NULL; has_bg = 0; plane = 0; } static void drawAppearing(VJFrame *src, VJFrame *dest) { int i; unsigned int Y; uint8_t *p, *qy, *qu, *qv; int32_t *s; const int video_area = src->len; p = timebuffer + plane * video_area; qy = bgimage[0]; qu = bgimage[1]; qv = bgimage[2]; uint8_t *lum = src->data[0]; uint8_t *u0 = src->data[1]; uint8_t *v0 = src->data[2]; uint8_t *Y1 = dest->data[0]; uint8_t *U1 = dest->data[1]; uint8_t *V1 = dest->data[2]; s = sum; uint8_t a,b,c; for(i=0; i>PLANES_DEPTH; if(Y>255) Y = 255; a = lum[i]; b = u0[i]; c = v0[i]; a += (( qy[i] - a ) * Y )>>8; Y1[i] = a; b += (( qu[i] - b ) * Y )>>8; U1[i] = b; c += (( qv[i] - c ) * Y )>>8; V1[i] = c; p++; s++; } plane++; plane = plane & (PLANES-1); } static void drawDisappearing(VJFrame *src, VJFrame *dest) { int i; unsigned int Y; uint8_t *p, *qu, *qv, *qy; int32_t *s; const int video_area = src->len; uint8_t *Y1 = dest->data[0]; uint8_t *U1 = dest->data[1]; uint8_t *V1 = dest->data[2]; uint8_t *lum = src->data[0]; uint8_t *u0 = src->data[1]; uint8_t *v0 = src->data[2]; p = timebuffer + (plane * video_area); qy = bgimage[0]; qu= bgimage[1]; qv= bgimage[2]; s = sum; uint8_t a,b,c,A,B,C; for(i=0; i < video_area; i++) { Y = a = lum[i]; b = u0[i]; c = v0[i]; A = qy[i]; B = qu[i]; C = qv[i]; *s -= *p; *s += Y; *p = Y; Y = (abs(((int)Y<>PLANES_DEPTH; if(Y>255) Y = 255; A += (( a - A ) * Y )>> 8; Y1[i] = A; B += (( b - B ) * Y ) >> 8; U1[i] = B; C += (( c - C ) * Y ) >> 8; V1[i] = C; p++; s++; } plane++; plane = plane & (PLANES-1); } void chameleon_apply( VJFrame *frame, int width, int height, int mode, int refresh_bg) { unsigned int i; const int len = (width * height); VJFrame source; veejay_memcpy( tmpimage[0], frame->data[0], len ); veejay_memcpy( tmpimage[1], frame->data[1], len ); veejay_memcpy( tmpimage[2], frame->data[2], len ); veejay_memcpy( &source, frame, sizeof(VJFrame)); source.data[0] = tmpimage[0]; source.data[1] = tmpimage[1]; source.data[2] = tmpimage[2]; int interpolate = 0; uint32_t activity = 0; int auto_switch = 0; int tmp1,tmp2; if( motionmap_active() ) { motionmap_scale_to( 32,32,1,1, &tmp1,&tmp2, &n__, &N__ ); auto_switch = 1; activity = motionmap_activity(); } else { N__ = 0; n__ = 0; } if( n__ == N__ || n__ == 0 ) auto_switch = 0; if( refresh_bg != refresh_bg_ ) { veejay_memcpy( bgimage[0], frame->data[0], len ); veejay_memcpy( bgimage[1], frame->data[1], len ); veejay_memcpy( bgimage[2], frame->data[2], len ); refresh_bg_ = refresh_bg; } if(auto_switch) { if( activity <= 40 ) { // into the wall drawDisappearing( &source, frame ); } else { // out of the wall drawAppearing( &source, frame ); } } if( mode == 0 ) drawDisappearing( &source, frame ); else drawAppearing( &source, frame ); }