You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
215 lines
5.7 KiB
215 lines
5.7 KiB
/*
|
|
* filter_burn.c -- burning filter
|
|
* Copyright (C) 2007 Stephane Fillod
|
|
*
|
|
* Filter taken from EffecTV - Realtime Digital Video Effector
|
|
* Copyright (C) 2001-2006 FUKUCHI Kentaro
|
|
*
|
|
* BurningTV - burns incoming objects.
|
|
* Copyright (C) 2001-2002 FUKUCHI Kentaro
|
|
*
|
|
* Fire routine is taken from Frank Jan Sorensen's demo program.
|
|
*
|
|
*
|
|
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
#include "filter_burn.h"
|
|
|
|
#include <framework/mlt_frame.h>
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <math.h>
|
|
#include "utils.h"
|
|
|
|
|
|
#define MaxColor 120
|
|
#define Decay 15
|
|
#define MAGIC_THRESHOLD "50"
|
|
|
|
static RGB32 palette[256];
|
|
|
|
/* FIXME: endianess? */
|
|
static void makePalette(void)
|
|
{
|
|
int i, r, g, b;
|
|
|
|
for(i=0; i<MaxColor; i++) {
|
|
HSItoRGB(4.6-1.5*i/MaxColor, (double)i/MaxColor, (double)i/MaxColor, &r, &g, &b);
|
|
palette[i] = ((r<<16)|(g<<8)|b) & 0xfefeff;
|
|
}
|
|
for(i=MaxColor; i<256; i++) {
|
|
if(r<255)r++;if(r<255)r++;if(r<255)r++;
|
|
if(g<255)g++;
|
|
if(g<255)g++;
|
|
if(b<255)b++;
|
|
if(b<255)b++;
|
|
palette[i] = ((r<<16)|(g<<8)|b) & 0xfefeff;
|
|
}
|
|
}
|
|
|
|
static int filter_get_image( mlt_frame this, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable )
|
|
{
|
|
RGB32 *background;
|
|
unsigned char *diff;
|
|
unsigned char *buffer;
|
|
|
|
// Get the filter
|
|
mlt_filter filter = mlt_frame_pop_service( this );
|
|
|
|
// Get the image
|
|
int error = mlt_frame_get_image( this, image, format, width, height, 1 );
|
|
|
|
// Only process if we have no error and a valid colour space
|
|
if ( error == 0 && *format == mlt_image_yuv422 )
|
|
{
|
|
// Get the "Burn the foreground" value
|
|
int burn_foreground = mlt_properties_get_int( MLT_FILTER_PROPERTIES( filter ), "foreground" );
|
|
int y_threshold = image_set_threshold_y(
|
|
mlt_properties_get_int( MLT_FILTER_PROPERTIES( filter ), "threshold" ));
|
|
|
|
// We'll process pixel by pixel
|
|
int x = 0;
|
|
int y = 0;
|
|
int i;
|
|
|
|
int video_width = *width;
|
|
int video_height = *height;
|
|
int video_area = video_width * video_height;
|
|
// We need to create a new frame as this effect modifies the input
|
|
RGB32 *dest = mlt_pool_alloc( video_area * sizeof(RGB32) );
|
|
RGB32 *src = (RGB32*)dest;
|
|
|
|
unsigned char v, w;
|
|
RGB32 a, b;
|
|
|
|
mlt_convert_yuv422_to_rgb24a(*image, (uint8_t *)dest, video_area);
|
|
|
|
|
|
diff = mlt_properties_get_data( MLT_FILTER_PROPERTIES( filter ),
|
|
"_diff", NULL );
|
|
if (diff == NULL)
|
|
{
|
|
diff = mlt_pool_alloc(video_area*sizeof(unsigned char));
|
|
mlt_properties_set_data( MLT_FILTER_PROPERTIES( filter ), "_diff",
|
|
diff, video_area*sizeof(unsigned char), mlt_pool_release, NULL );
|
|
}
|
|
|
|
buffer = mlt_properties_get_data( MLT_FILTER_PROPERTIES( filter ),
|
|
"_buffer", NULL );
|
|
if (buffer == NULL)
|
|
{
|
|
buffer = mlt_pool_alloc(video_area*sizeof(unsigned char));
|
|
memset(buffer, 0, video_area*sizeof(unsigned char));
|
|
mlt_properties_set_data( MLT_FILTER_PROPERTIES( filter ), "_buffer",
|
|
buffer, video_area*sizeof(unsigned char), mlt_pool_release, NULL );
|
|
}
|
|
|
|
|
|
if (burn_foreground == 1) {
|
|
/* to burn the foreground, we need a background */
|
|
background = mlt_properties_get_data( MLT_FILTER_PROPERTIES( filter ),
|
|
"_background", NULL );
|
|
if (background == NULL)
|
|
{
|
|
background = mlt_pool_alloc(video_area*sizeof(RGB32));
|
|
image_bgset_y(background, src, video_area, y_threshold);
|
|
mlt_properties_set_data( MLT_FILTER_PROPERTIES( filter ), "_background",
|
|
background, video_area*sizeof(RGB32), mlt_pool_release, NULL );
|
|
}
|
|
}
|
|
|
|
if (burn_foreground == 1) {
|
|
image_bgsubtract_y(diff, background, src, video_area, y_threshold);
|
|
} else {
|
|
/* default */
|
|
image_y_over(diff, src, video_area, y_threshold);
|
|
}
|
|
|
|
for(x=1; x<video_width-1; x++) {
|
|
v = 0;
|
|
for(y=0; y<video_height-1; y++) {
|
|
w = diff[y*video_width+x];
|
|
buffer[y*video_width+x] |= v ^ w;
|
|
v = w;
|
|
}
|
|
}
|
|
for(x=1; x<video_width-1; x++) {
|
|
i = video_width + x;
|
|
for(y=1; y<video_height; y++) {
|
|
v = buffer[i];
|
|
if(v<Decay)
|
|
buffer[i-video_width] = 0;
|
|
else
|
|
buffer[i-video_width+fastrand()%3-1] = v - (fastrand()&Decay);
|
|
i += video_width;
|
|
}
|
|
}
|
|
|
|
i = 1;
|
|
for(y=0; y<video_height; y++) {
|
|
for(x=1; x<video_width-1; x++) {
|
|
/* FIXME: endianess? */
|
|
a = (src[i] & 0xfefeff) + palette[buffer[i]];
|
|
b = a & 0x1010100;
|
|
dest[i] = a | (b - (b >> 8));
|
|
i++;
|
|
}
|
|
i += 2;
|
|
}
|
|
|
|
mlt_convert_rgb24a_to_yuv422((uint8_t *)dest, *width, *height, *width * sizeof(RGB32),
|
|
*image, NULL );
|
|
|
|
mlt_pool_release(dest);
|
|
}
|
|
|
|
return error;
|
|
}
|
|
|
|
/** Filter processing.
|
|
*/
|
|
|
|
static mlt_frame filter_process( mlt_filter this, mlt_frame frame )
|
|
{
|
|
// Push the frame filter
|
|
mlt_frame_push_service( frame, this );
|
|
mlt_frame_push_get_image( frame, filter_get_image );
|
|
|
|
return frame;
|
|
}
|
|
|
|
/** Constructor for the filter.
|
|
*/
|
|
|
|
mlt_filter filter_burn_init( char *arg )
|
|
{
|
|
mlt_filter this = mlt_filter_new( );
|
|
if ( this != NULL )
|
|
{
|
|
this->process = filter_process;
|
|
mlt_properties_set( MLT_FILTER_PROPERTIES( this ), "foreground", "0" );
|
|
mlt_properties_set( MLT_FILTER_PROPERTIES( this ), "threshold", MAGIC_THRESHOLD );
|
|
}
|
|
if (!palette[128])
|
|
{
|
|
makePalette();
|
|
}
|
|
return this;
|
|
}
|
|
|