/* * Linux VeeJay * * Copyright(C)2007 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 #include #include #include "motionmap.h" #include "common.h" #include "softblur.h" #include "opacity.h" #define HIS_DEFAULT 2 #define HIS_LEN (8*25) #define ACT_TOP 4000 #define MAXCAPBUF 55 typedef struct { int p; int t; } boxes_t; vj_effect *motionmap_init(int w, int h) { vj_effect *ve = (vj_effect *) vj_calloc(sizeof(vj_effect)); ve->num_params = 3; 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; // motionmap ve->limits[1][0] = 255; ve->limits[0][1] = 50; // reverse ve->limits[1][1] = 10000; ve->limits[0][2] = 0; ve->limits[1][2] = 60*25; /* ve->limits[0][4] = 0; // buffer ve->limits[1][4] = 255; ve->limits[0][3] = HIS_DEFAULT; ve->limits[1][3] = HIS_LEN; */ ve->defaults[0] = 40; ve->defaults[1] = ACT_TOP; ve->defaults[2] = 1; /* ve->defaults[3] = HIS_DEFAULT; ve->defaults[4] = 0; */ ve->description = "Motion Mapping"; ve->sub_format = 1; ve->extra_frame = 0; ve->has_user = 0; ve->n_out = 2; ve->param_description = vje_build_param_list( ve->num_params, "Threshold", "Min weight", "Decay" ); return ve; } static uint8_t *binary_img = NULL; static uint8_t *original_img = NULL; static uint8_t *previous_img = NULL; static uint8_t *large_buf = NULL; static uint32_t key1_ = 0, key2_ = 0, keyv_ = 0, keyp_ = 0; static int have_bg = 0; static int running = 0; static boxes_t *boxes = NULL; int motionmap_prepare( uint8_t *map[3], int w, int h ) { if(!previous_img) return 0; vj_frame_copy( map, previous_img, w*h ); have_bg = 1; nframe_ = 0; running = 0; veejay_msg(2, "Motion Mapping: Snapped background frame"); return 1; } int motionmap_malloc(int w, int h ) { binary_img = (uint8_t*) vj_malloc(sizeof(uint8_t) * RUP8(w * h * 3) ); original_img = binary_img + RUP8(w*h); previous_img = original_img + RUP8(w*h); large_buf = vj_malloc(sizeof(uint8_t) * RUP8(w*h*3) * (MAXCAPBUF+1)); if(!large_buf) { veejay_msg(0, "Memory allocation error for Motion Mapping. Too large: %ld bytes",(long) ((RUP8(w*h*3)*(MAXCAPBUF+1)))); return 0; } nframe_ = 0; boxes = (boxes_t*) vj_malloc(sizeof(boxes_t) * 64 * 64 ); int i ; for ( i = 0;i < 64*64; i ++ ) { boxes[i].p = 0; boxes[i].t = 0; } return 1; } void motionmap_free(void) { if(binary_img) free(binary_img); if(large_buf) free(large_buf); have_bg = 0; nframe_ = 0; running = 0; binary_img = NULL; } #ifndef MIN #define MIN(a,b) ( (a)>(b) ? (b) : (a) ) #endif #ifndef MAX #define MAX(a,b) ( (a)>(b) ? (a) : (b) ) #endif static void update_bgmask( uint8_t *dst,uint8_t *in, uint8_t *src, int len, int threshold ) { int i; unsigned int op0,op1; for( i =0; i < len ; i ++ ) { if( abs(in[i] - src[i]) > threshold ) { dst[i] = 1; in[i] = (in[i] + src[i])>>1; } else { dst[i] = 0; } } } static void put_photo( uint8_t *dst_plane, uint8_t *src_plane, int dst_w, int dst_h, int index , matrix_t matrix, int box_w, int box_h) { int x,y; uint8_t *P = dst_plane + (matrix.h*dst_w); uint8_t *Q = src_plane + (matrix.h*dst_w); int offset = matrix.w; for( y = 0; y < box_h; y ++ ) { for( x = 0; x < box_w; x ++ ) { *(P+offset+x) = *(Q+offset+x); } P += dst_w; Q += dst_w; } } void motionmap_apply( VJFrame *frame, int width, int height, int threshold, int param1, int param2 ) { unsigned int i,x,y; int len = (width * height); uint8_t *Y = frame->data[0]; uint8_t *Cb = frame->data[1]; uint8_t *Cr = frame->data[2]; int w = frame->width; int h = frame->height; vj_frame_copy1( frame->data[0], original_img, len ); // softblur_apply( frame, width,height,0 ); if(!have_bg) { vj_frame_copy1( frame->data[0], previous_img, len ); have_bg = 1; nframe_ = 0; running = 0; return; } else { update_bgmask( binary_img, previous_img, frame->data[0], len , threshold); } int x,y,dx,dy; int sum; int dst_x, dst_y; int step_y; int step_x; int box_width = photo_list[index]->w; int box_height = photo_list[index]->h; int it = 0; uint8_t *plane = binary_img; matrix_f matrix_placement = get_matrix_func(mode); step_x = w / box_width; step_y = h / box_height; for( y = 0 ; y < h ; y += step_y ) { for( x = 0; x < w ; x+= step_x ) { sum = 0; for( dy = 0; dy < step_y; dy ++ ) { for( dx = 0; dx < step_x; dx++) { sum += plane[ ((y+dy)*w+(dx+x)) ]; } } } boxes[ it ].p = sum; it ++; sum = 0; } for( y = 0 ; y < it ; y ++ ) { if(boxes[it].p > param1) //@ sufficient motion { if( boxes[it].t < 5 ) //@ update timer boxes[it].t = param2; //@ Time stop } if( boxes[it].t > 0 ) boxes[it].t --; if( boxes[it].t == 0 ) { boxes[it].p = 0; } } for ( i = 0; i < num_photos; i ++ ) { matrix_t m = matrix_placement(i, size,width,height ); put_photo( dstY, photo_list[i]->data[0],width,height,i, m); put_photo( dstU, photo_list[i]->data[1],width,height,i, m); put_photo( dstV, photo_list[i]->data[2],width,height,i, m); } }