mirror of
https://github.com/game-stop/veejay.git
synced 2025-12-18 05:40:02 +01:00
258 lines
5.9 KiB
C
258 lines
5.9 KiB
C
/*
|
|
* Linux VeeJay
|
|
*
|
|
* Copyright(C)2007 Niels Elburg <nwelburg@gmail.com>
|
|
*
|
|
* 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 <config.h>
|
|
#include <stdint.h>
|
|
#include <libvjmem/vjmem.h>
|
|
#include <libvjmsg/vj-msg.h>
|
|
#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);
|
|
}
|
|
|
|
|
|
|
|
}
|