mirror of
https://github.com/game-stop/veejay.git
synced 2025-12-23 16:20:03 +01:00
177 lines
5.0 KiB
C
177 lines
5.0 KiB
C
/*
|
|
* Linux VeeJay
|
|
*
|
|
* Copyright(C)2023 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 "common.h"
|
|
#include <veejaycore/vjmem.h>
|
|
#include "smartblur.h"
|
|
|
|
vj_effect *smartblur_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] = 1;
|
|
ve->limits[1][0] = 16;
|
|
ve->limits[0][1] = 0;
|
|
ve->limits[1][1] = 255;
|
|
ve->limits[0][2] = 0;
|
|
ve->limits[1][2] = 1;
|
|
ve->limits[0][3] = 0;
|
|
ve->limits[1][3] = 1;
|
|
ve->defaults[0] = 1;
|
|
ve->defaults[1] = 10;
|
|
ve->defaults[2] = 0;
|
|
ve->defaults[3] = 0;
|
|
ve->description = "Smart Blur";
|
|
ve->sub_format = 1;
|
|
ve->extra_frame = 0;
|
|
ve->parallel = 0;
|
|
ve->has_user = 0;
|
|
ve->param_description = vje_build_param_list( ve->num_params, "Radius", "Threshold", "Swap", "Show Mask" );
|
|
return ve;
|
|
}
|
|
|
|
typedef struct {
|
|
uint8_t *buf[3];
|
|
uint8_t *mask;
|
|
} smartblur_t;
|
|
|
|
|
|
void *smartblur_malloc(int w, int h) {
|
|
smartblur_t *s = (smartblur_t*) vj_malloc( sizeof(smartblur_t) );
|
|
if(!s) {
|
|
return NULL;
|
|
}
|
|
s->buf[0] = (uint8_t*) vj_malloc( sizeof(uint8_t) * w * h * 3 );
|
|
if(!s->buf[0]) {
|
|
free(s);
|
|
return NULL;
|
|
}
|
|
s->buf[1] = s->buf[0] + (w*h);
|
|
s->buf[2] = s->buf[1] + (w*h);
|
|
|
|
s->mask = (uint8_t*) vj_calloc(sizeof(uint8_t) * w * h );
|
|
if(!s->mask) {
|
|
free(s->buf[0]);
|
|
free(s);
|
|
return NULL;
|
|
}
|
|
|
|
return (void*) s;
|
|
}
|
|
|
|
void smartblur_free(void *ptr) {
|
|
smartblur_t *s = (smartblur_t*) ptr;
|
|
free(s->buf[0]);
|
|
free(s->mask);
|
|
free(s);
|
|
}
|
|
|
|
void smartblur_apply(void *ptr, VJFrame *frame, int *args) {
|
|
smartblur_t *s = (smartblur_t*) ptr;
|
|
|
|
const int w = frame->width;
|
|
const int h = frame->height;
|
|
const int radius = args[0];
|
|
const int threshold = args[1];
|
|
const int show = args[3];
|
|
const int swap = args[2];
|
|
uint8_t *srcY = frame->data[0];
|
|
uint8_t *srcU = frame->data[1];
|
|
uint8_t *srcV = frame->data[2];
|
|
uint8_t *dstY = s->buf[0];
|
|
uint8_t *dstU = s->buf[1];
|
|
uint8_t *dstV = s->buf[2];
|
|
uint8_t *mask = s->mask;
|
|
|
|
const minMaskValue = (swap ? 0xff: 0);
|
|
const maxMaskValue = (swap ? 0: 0xff);
|
|
|
|
for (int y = radius; y < h - radius; y++) {
|
|
for (int x = radius; x < w - radius; x++) {
|
|
uint8_t maskValue = minMaskValue;
|
|
for (int ky = -radius; ky <= radius; ky++) {
|
|
for (int kx = -radius; kx <= radius; kx++) {
|
|
|
|
const int intensity_diff = srcY[y * w + x] - srcY[ky * w + kx];
|
|
const int abs_diff = (intensity_diff >= 0) ? intensity_diff : -intensity_diff;
|
|
if( abs_diff <= threshold ) {
|
|
maskValue = maxMaskValue;
|
|
break;
|
|
}
|
|
}
|
|
if(maskValue)
|
|
break;
|
|
}
|
|
mask[y * w + x] = maskValue;
|
|
}
|
|
}
|
|
|
|
if(show) {
|
|
veejay_memcpy( srcY, mask, frame->len );
|
|
veejay_memset( srcU, 128, frame->len );
|
|
veejay_memset( srcV, 128, frame->len );
|
|
return;
|
|
}
|
|
|
|
for (int y = radius; y < h - radius; y++) {
|
|
for (int x = radius; x < w - radius; x++) {
|
|
int ySum = 0;
|
|
int uSum = 0;
|
|
int vSum = 0;
|
|
int pixelCount = 0;
|
|
|
|
for (int ky = -radius; ky <= radius; ky++) {
|
|
for (int kx = -radius; kx <= radius; kx++) {
|
|
if (mask[(y + ky) * w + (x + kx)]) {
|
|
ySum += srcY[(y + ky) * w + (x + kx)];
|
|
uSum += (srcU[(y + ky) * w + (x + kx)] - 128);
|
|
vSum += (srcV[(y + ky) * w + (x + kx)] - 128);
|
|
pixelCount++;
|
|
}
|
|
}
|
|
}
|
|
|
|
if( pixelCount == 0 ) {
|
|
dstY[y * w + x ] = srcY[ y * w + x];
|
|
dstU[y * w + x ] = srcU[ y * w + x];
|
|
dstV[y * w + x ] = srcV[ y * w + x];
|
|
}
|
|
else {
|
|
const float averagedY = (ySum / pixelCount);
|
|
const float averagedU = 128 + (uSum / pixelCount);
|
|
const float averagedV = 128 + (vSum / pixelCount);
|
|
|
|
dstY[y * w + x] = (uint8_t)(averagedY);
|
|
dstU[y * w + x] = (uint8_t)(averagedU);
|
|
dstV[y * w + x] = (uint8_t)(averagedV);
|
|
}
|
|
}
|
|
}
|
|
|
|
veejay_memcpy(srcY, dstY, frame->len);
|
|
veejay_memcpy(srcU, dstU, frame->len);
|
|
veejay_memcpy(srcV, dstV, frame->len);
|
|
}
|
|
|