mirror of
https://github.com/game-stop/veejay.git
synced 2025-12-17 13:20:01 +01:00
423 lines
10 KiB
C
423 lines
10 KiB
C
/*
|
|
* EffecTV - Realtime Digital Video Effector
|
|
* RadioacTV - motion-enlightment effect.
|
|
* I referred to "DUNE!" by QuoVadis for this effect.
|
|
* Copyright (C) 2001-2006 FUKUCHI Kentaro
|
|
*
|
|
* Veejay FX 'RadioActiveVJ'
|
|
* (C) 2007 Niels Elburg
|
|
* This effect was ported from EffecTV.
|
|
* Differences:
|
|
* - difference frame over 2 frame interval intsead of bg substraction
|
|
* - several mask methods
|
|
* - more parameters
|
|
* - no palette (but mixing source)
|
|
*
|
|
* 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 "common.h"
|
|
#include <veejaycore/vjmem.h>
|
|
//#include <libavutil/avutil.h>
|
|
#include <veejaycore/yuvconv.h>
|
|
#include "softblur.h"
|
|
#include "radioactive.h"
|
|
|
|
vj_effect *radioactivetv_init(int w, int h)
|
|
{
|
|
vj_effect *ve = (vj_effect *) vj_calloc(sizeof(vj_effect));
|
|
ve->num_params = 4;
|
|
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; /* methods */
|
|
ve->limits[1][0] = 6;
|
|
ve->limits[0][1] = 50;// zoom ratio
|
|
ve->limits[1][1] = 100;
|
|
ve->limits[0][2] = 0; // strength
|
|
ve->limits[1][2] = 255;
|
|
ve->limits[0][3] = 0; //diff threhsold
|
|
ve->limits[1][3] = 255;
|
|
ve->defaults[0] = 0;
|
|
ve->defaults[1] = 95;
|
|
ve->defaults[2] = 200;
|
|
ve->defaults[3] = 30;
|
|
ve->description = "RadioActive EffecTV";
|
|
ve->sub_format = 1;
|
|
ve->extra_frame = 1;
|
|
ve->has_user = 0;
|
|
ve->param_description = vje_build_param_list(ve->num_params, "Mode", "Zoom ratio", "Strength", "Difference Threshold" );
|
|
|
|
|
|
ve->hints = vje_init_value_hint_list( ve->num_params );
|
|
|
|
vje_build_value_hint_list( ve->hints, ve->limits[1][0], 0,
|
|
"Average", "Normal", "Strobe", "Spill (greyscale)", "Flood (greyscale)", "Frontal (greyscale)", "Low (greyscale)" );
|
|
|
|
return ve;
|
|
}
|
|
|
|
typedef struct {
|
|
uint8_t *diffbuf;
|
|
uint8_t *blurzoombuf;
|
|
int *blurzoomx;
|
|
int *blurzoomy;
|
|
int buf_width_blocks;
|
|
int buf_width;
|
|
int buf_height;
|
|
int buf_area;
|
|
int buf_margin_left;
|
|
int buf_margin_right;
|
|
int first_frame;
|
|
int last_mode; // -1;
|
|
float ratio_; // 0.95;
|
|
} radioactive_t;
|
|
|
|
#define VIDEO_HWIDTH (buf_width/2)
|
|
#define VIDEO_HHEIGHT (buf_height/2)
|
|
|
|
|
|
/* this table assumes that video_width is multiple of 32 */
|
|
static void setTable(radioactive_t *r)
|
|
{
|
|
unsigned int bits;
|
|
int x, y, tx, ty, xx;
|
|
int ptr, prevptr;
|
|
int *blurzoomx = r->blurzoomx;
|
|
int *blurzoomy = r->blurzoomy;
|
|
int buf_width_blocks = r->buf_width_blocks;
|
|
float ratio_ = r->ratio_;
|
|
int buf_width = r->buf_width;
|
|
int buf_height = r->buf_height;
|
|
|
|
prevptr = (int)(0.5+ratio_*(-VIDEO_HWIDTH)+VIDEO_HWIDTH);
|
|
for(xx=0; xx<(buf_width_blocks); xx++){
|
|
bits = 0;
|
|
for(x=0; x<32; x++){
|
|
ptr= (int)(0.5+ratio_*(xx*32+x-VIDEO_HWIDTH)+VIDEO_HWIDTH);
|
|
bits = bits>>1;
|
|
if(ptr != prevptr)
|
|
bits |= 0x80000000;
|
|
prevptr = ptr;
|
|
}
|
|
blurzoomx[xx] = bits;
|
|
}
|
|
|
|
ty = (int)(0.5+ratio_*(-VIDEO_HHEIGHT)+VIDEO_HHEIGHT);
|
|
tx = (int)(0.5+ratio_*(-VIDEO_HWIDTH)+VIDEO_HWIDTH);
|
|
xx=(int)(0.5+ratio_*(buf_width-1-VIDEO_HWIDTH)+VIDEO_HWIDTH);
|
|
blurzoomy[0] = ty * buf_width + tx;
|
|
prevptr = ty * buf_width + xx;
|
|
for(y=1; y<buf_height; y++){
|
|
ty = (int)(0.5+ratio_*(y-VIDEO_HHEIGHT)+VIDEO_HHEIGHT);
|
|
blurzoomy[y] = ty * buf_width + tx - prevptr;
|
|
prevptr = ty * buf_width + xx;
|
|
}
|
|
}
|
|
|
|
static void kentaro_blur(radioactive_t *r)
|
|
{
|
|
int x, y;
|
|
int width;
|
|
unsigned char *p, *q;
|
|
unsigned char v;
|
|
|
|
width = r->buf_width;
|
|
p = r->blurzoombuf + width + 1;
|
|
q = p + r->buf_area;
|
|
|
|
for(y=r->buf_height-2; y>0; y--) {
|
|
for(x=width-2; x>0; x--) {
|
|
v = (*(p-width) + *(p-1) + *(p+1) + *(p+width))/4 - 1;
|
|
if(v == 255) v = 0;
|
|
*q = v;
|
|
p++;
|
|
q++;
|
|
}
|
|
p += 2;
|
|
q += 2;
|
|
}
|
|
}
|
|
|
|
static void zoom(radioactive_t *r)
|
|
{
|
|
int b, x, y;
|
|
unsigned char *p, *q;
|
|
int blocks, height;
|
|
int dx;
|
|
int *blurzoomy = r->blurzoomy;
|
|
int *blurzoomx = r->blurzoomx;
|
|
p = r->blurzoombuf + r->buf_area;
|
|
q = r->blurzoombuf;
|
|
height = r->buf_height;
|
|
blocks = r->buf_width_blocks;
|
|
|
|
for(y=0; y<height; y++) {
|
|
p += blurzoomy[y];
|
|
for(b=0; b<blocks; b++) {
|
|
dx = blurzoomx[b];
|
|
for(x=0; x<32; x++) {
|
|
p += (dx & 1);
|
|
*q++ = *p;
|
|
dx = dx>>1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void blurzoomcore(radioactive_t *r)
|
|
{
|
|
kentaro_blur(r);
|
|
zoom(r);
|
|
}
|
|
|
|
void *radioactivetv_malloc(int w, int h)
|
|
{
|
|
if( (w/32) > 255 )
|
|
return NULL;
|
|
|
|
radioactive_t *r = (radioactive_t*) vj_calloc(sizeof(radioactive_t));
|
|
if(!r) {
|
|
return NULL;
|
|
}
|
|
|
|
r->ratio_ = 0.95f;
|
|
r->last_mode = -1;
|
|
|
|
r->buf_width_blocks = (w / 32 );
|
|
r->buf_width = r->buf_width_blocks * 32;
|
|
r->buf_height = h;
|
|
|
|
r->buf_area = r->buf_width * r->buf_height;
|
|
r->buf_margin_left = (w - r->buf_width ) >> 1;
|
|
r->buf_margin_right = (w - r->buf_width - r->buf_margin_left);
|
|
|
|
r->blurzoombuf = (uint8_t*) vj_calloc( RUP8(r->buf_area * 2 ));
|
|
if(!r->blurzoombuf) {
|
|
radioactivetv_free(r);
|
|
return NULL;
|
|
}
|
|
|
|
r->blurzoomx = (int*) vj_calloc( RUP8(r->buf_width * sizeof(int)));
|
|
if(!r->blurzoomx) {
|
|
radioactivetv_free(r);
|
|
return NULL;
|
|
}
|
|
|
|
r->blurzoomy = (int*) vj_calloc( RUP8(r->buf_width * sizeof(int)));
|
|
if(!r->blurzoomy) {
|
|
radioactivetv_free(r);
|
|
return NULL;
|
|
}
|
|
|
|
r->diffbuf = (uint8_t*) vj_calloc( RUP8((4*w) + 2 * w * h * sizeof(uint8_t)));
|
|
if(!r->diffbuf) {
|
|
radioactivetv_free(r);
|
|
return NULL;
|
|
}
|
|
|
|
setTable(r);
|
|
|
|
return (void*) r;
|
|
}
|
|
|
|
void radioactivetv_free(void *ptr)
|
|
{
|
|
radioactive_t *r = (radioactive_t*) ptr;
|
|
if(r) {
|
|
if(r->blurzoombuf)
|
|
free(r->blurzoombuf);
|
|
if(r->blurzoomx )
|
|
free(r->blurzoomx);
|
|
if(r->blurzoomy )
|
|
free(r->blurzoomy);
|
|
if(r->diffbuf)
|
|
free(r->diffbuf);
|
|
}
|
|
}
|
|
|
|
void radioactivetv_apply( void *ptr, VJFrame *frame, VJFrame *blue, int *args ) {
|
|
int mode = args[0];
|
|
int snapRatio = args[1];
|
|
int snapInterval = args[2];
|
|
int threshold = args[3];
|
|
|
|
unsigned int x, y;
|
|
const unsigned int width = frame->width;
|
|
const unsigned int height = frame->height;
|
|
const int len = frame->len;
|
|
|
|
radioactive_t *r = (radioactive_t*) ptr;
|
|
|
|
uint8_t *diff = r->diffbuf;
|
|
uint8_t *prev = diff + len;
|
|
uint8_t *lum = frame->data[0];
|
|
uint8_t *dstY = lum;
|
|
uint8_t *dstU = frame->data[1];
|
|
uint8_t *dstV = frame->data[2];
|
|
uint8_t *p;
|
|
uint8_t *blueY = blue->data[0];
|
|
uint8_t *blueU = blue->data[1];
|
|
uint8_t *blueV = blue->data[2];
|
|
float new_ratio = r->ratio_;
|
|
|
|
int buf_width = r->buf_width;
|
|
int buf_height = r->buf_height;
|
|
int buf_margin_left = r->buf_margin_left;
|
|
int buf_margin_right = r->buf_margin_right;
|
|
|
|
VJFrame smooth;
|
|
veejay_memcpy( &smooth, frame, sizeof(VJFrame));
|
|
smooth.data[0] = prev;
|
|
|
|
//@ set new zoom ratio
|
|
new_ratio = (snapRatio * 0.01);
|
|
if ( r->ratio_ != new_ratio )
|
|
{
|
|
r->ratio_ = new_ratio;
|
|
setTable(r);
|
|
}
|
|
|
|
if( !r->first_frame )
|
|
{ //@ take current
|
|
veejay_memcpy( prev, lum, len );
|
|
softblur_apply_internal( &smooth, 0);
|
|
r->first_frame++;
|
|
return;
|
|
}
|
|
|
|
if( r->last_mode != mode )
|
|
{
|
|
//@ mode changed, reset
|
|
veejay_memset( r->blurzoombuf, 0, 2*r->buf_area);
|
|
veejay_memset( diff, 0, len );
|
|
veejay_memset( prev, 0, len );
|
|
r->last_mode = mode;
|
|
}
|
|
|
|
uint8_t *d = diff;
|
|
|
|
//@ varying diff methods (strobe, normal, average, etc)
|
|
switch( mode )
|
|
{
|
|
case 0:
|
|
for( y = 0; y < len; y ++ ){
|
|
diff[y] = abs(lum[y] - prev[y]);
|
|
if(diff[y] < threshold )
|
|
diff[y] = 0;
|
|
prev[y] = (prev[y] + lum[y])>>1;
|
|
}
|
|
break;
|
|
case 1:
|
|
for( y = 0; y < len; y ++ ) {
|
|
diff[y] = abs(lum[y] - prev[y]);
|
|
if(diff[y] < threshold )
|
|
diff[y] = 0;
|
|
prev[y] = lum[y];
|
|
}
|
|
break;
|
|
case 2:
|
|
for( y = 0; y < len; y ++ ){
|
|
diff[y] = ( prev[y] >> 1 ) + (lum[y] >> 1);
|
|
if( diff[y] < threshold )
|
|
diff[y] = 0;
|
|
prev[y] = lum[y];
|
|
}
|
|
break;
|
|
case 3:
|
|
for( y = 0; y < len; y ++ ) {
|
|
diff[y] = abs( lum[y] - prev[y] );
|
|
diff[y] = (prev[y] + lum[y] + lum[y] + lum[y])>>2;
|
|
if( diff[y] < threshold )
|
|
diff[y] = 0;
|
|
prev[y] = diff[y];
|
|
}
|
|
break;
|
|
case 4:
|
|
for( y = 0; y < len; y ++ ) {
|
|
diff[y] = abs( lum[y] - prev[y] );
|
|
diff[y] = (lum[y] - prev[y])>>1;
|
|
if( diff[y] < threshold )
|
|
{
|
|
if(diff[y]) diff[y]--;
|
|
}
|
|
prev[y] = lum[y];
|
|
}
|
|
break;
|
|
case 5:
|
|
for( y = 0; y < len; y ++ ) {
|
|
diff[y] = abs(lum[y] - prev[y]);
|
|
if(diff[y] < threshold )
|
|
diff[y] = 0;
|
|
prev[y] = lum[y];
|
|
}
|
|
break;
|
|
case 6:
|
|
for( y = 0; y < len; y ++ ){
|
|
if( abs( lum[y] - prev[y]) > threshold )
|
|
diff[y] = lum[y]>>2;
|
|
else
|
|
diff[y] = 0;
|
|
prev[y] = lum[y];
|
|
}
|
|
|
|
break;
|
|
}
|
|
//@ end of diff
|
|
|
|
|
|
p = r->blurzoombuf;
|
|
d += r->buf_margin_left;
|
|
for( y = 0; y < buf_height; y++ ) {
|
|
for( x = 0; x< buf_width; x ++ ) {
|
|
p[x] |= ( (d[x] * snapInterval)>>7);
|
|
}
|
|
d += width;
|
|
p += buf_width;
|
|
}
|
|
//@ prepare frame for next difference take
|
|
softblur_apply_internal( &smooth, 0);
|
|
|
|
blurzoomcore(r);
|
|
p = r->blurzoombuf;
|
|
|
|
if(mode >= 3 )
|
|
{
|
|
veejay_memset( dstU,128,len);
|
|
veejay_memset( dstV,128,len);
|
|
veejay_memcpy( dstY, r->blurzoombuf, len );
|
|
return;
|
|
}
|
|
|
|
|
|
uint32_t k =0;
|
|
for( y = 0; y < height; y ++ )
|
|
{
|
|
k += buf_margin_left;
|
|
for( x = 0; x < buf_width; x ++ )
|
|
{
|
|
uint8_t op0 = (*p ++);
|
|
uint8_t op1 = 0xff - op0;
|
|
|
|
dstY[k] = (op0 * blueY[k] + op1 * dstY[k])>>8;
|
|
dstU[k] = (op0 * blueU[k] + op1 * dstU[k])>>8;
|
|
dstV[k] = (op0 * blueV[k] + op1 * dstV[k])>>8;
|
|
|
|
k ++;
|
|
}
|
|
k += buf_margin_right;
|
|
}
|
|
}
|