/* * CINELERRA * Copyright (C) 2008 Adam Williams * * 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 "clip.h" #include "bccmodels.h" #include "effecttv.h" #include "filexml.h" #include "language.h" #include "bccolors.h" #include "burn.h" #include "burnwindow.h" #include #include #include REGISTER_PLUGIN(BurnMain) BurnConfig::BurnConfig() { threshold = 50; decay = 15; recycle = 1.0; } BurnMain::BurnMain(PluginServer *server) : PluginVClient(server) { input_ptr = 0; output_ptr = 0; burn_server = 0; buffer = 0; effecttv = 0; } BurnMain::~BurnMain() { if(buffer) delete [] buffer; if(burn_server) delete burn_server; if(effecttv) delete effecttv; } const char* BurnMain::plugin_title() { return N_("BurningTV"); } int BurnMain::is_realtime() { return 1; } NEW_WINDOW_MACRO(BurnMain, BurnWindow) int BurnMain::load_configuration() { return 0; //printf("BurnMain::load_configuration %d\n", source_position); } void BurnMain::save_data(KeyFrame *keyframe) { } void BurnMain::read_data(KeyFrame *keyframe) { } #define MAXCOLOR 120 void BurnMain::HSItoRGB(double H, double S, double I, int *r, int *g, int *b, int color_model) { double T, Rv, Gv, Bv; T = H; Rv = 1 + S * sin(T - 2 * M_PI / 3); Gv = 1 + S * sin(T); Bv = 1 + S * sin(T + 2 * M_PI / 3); T = 255.999 * I / 2; *r = (int)CLIP(Rv * T, 0, 255); *g = (int)CLIP(Gv * T, 0, 255); *b = (int)CLIP(Bv * T, 0, 255); } void BurnMain::make_palette(int color_model) { 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, color_model); palette[0][i] = r; palette[1][i] = g; palette[2][i] = b; //printf("BurnMain::make_palette %d %d %d %d\n", i, palette[0][i], palette[1][i], palette[2][i]); } 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[0][i] = r; palette[1][i] = g; palette[2][i] = b; //printf("BurnMain::make_palette %d %d %d %d\n", i, palette[0][i], palette[1][i], palette[2][i]); } } int BurnMain::process_realtime(VFrame *input_ptr, VFrame *output_ptr) { this->input_ptr = input_ptr; this->output_ptr = output_ptr; load_configuration(); if(!burn_server) { effecttv = new EffectTV(input_ptr->get_w(), input_ptr->get_h()); buffer = (unsigned char *)new unsigned char[input_ptr->get_w() * input_ptr->get_h()]; make_palette(input_ptr->get_color_model()); effecttv->image_set_threshold_y(config.threshold); total = 0; burn_server = new BurnServer(this, 1, 1); } if(total == 0) { bzero(buffer, input_ptr->get_w() * input_ptr->get_h()); effecttv->image_bgset_y(input_ptr); } burn_server->process_packages(); total++; // if(total >= config.recycle * project_frame_rate) total = 0; return 0; } BurnServer::BurnServer(BurnMain *plugin, int total_clients, int total_packages) : LoadServer(total_clients, total_packages) { this->plugin = plugin; } LoadClient* BurnServer::new_client() { return new BurnClient(this); } LoadPackage* BurnServer::new_package() { return new BurnPackage; } void BurnServer::init_packages() { for(int i = 0; i < get_total_packages(); i++) { BurnPackage *package = (BurnPackage*)get_package(i); package->row1 = plugin->input_ptr->get_h() * i / get_total_packages(); package->row2 = plugin->input_ptr->get_h() * (i + 1) / get_total_packages(); } } BurnClient::BurnClient(BurnServer *server) : LoadClient(server) { this->plugin = server->plugin; } #define BURN(type, components, is_yuv) \ { \ i = 1; \ type **rows = (type**)input_rows; \ for(y = 0; y < height; y++) \ { \ for(x = 1; x < width - 1; x++) \ { \ if(sizeof(type) == 4) \ { \ a1 = (int)(rows[0][i * components] * 0xff); \ a2 = (int)(rows[0][i * components + 1] * 0xff); \ a3 = (int)(rows[0][i * components + 2] * 0xff); \ CLAMP(a1, 0, 0xff); \ CLAMP(a2, 0, 0xff); \ CLAMP(a3, 0, 0xff); \ b1 = plugin->palette[0][plugin->buffer[i]]; \ b2 = plugin->palette[1][plugin->buffer[i]]; \ b3 = plugin->palette[2][plugin->buffer[i]]; \ a1 += b1; \ a2 += b2; \ a3 += b3; \ b1 = a1 & 0x100; \ b2 = a2 & 0x100; \ b3 = a3 & 0x100; \ rows[0][i * components] = (type)(a1 | (b1 - (b1 >> 8))) / 0xff; \ rows[0][i * components + 1] = (type)(a2 | (b2 - (b2 >> 8))) / 0xff; \ rows[0][i * components + 2] = (type)(a3 | (b3 - (b3 >> 8))) / 0xff; \ } \ else \ if(sizeof(type) == 2) \ { \ a1 = ((int)rows[0][i * components + 0]) >> 8; \ a2 = ((int)rows[0][i * components + 1]) >> 8; \ a3 = ((int)rows[0][i * components + 2]) >> 8; \ b1 = plugin->palette[0][plugin->buffer[i]]; \ b2 = plugin->palette[1][plugin->buffer[i]]; \ b3 = plugin->palette[2][plugin->buffer[i]]; \ if(is_yuv) YUV::yuv.yuv_to_rgb_8(a1, a2, a3); \ a1 += b1; \ a2 += b2; \ a3 += b3; \ b1 = a1 & 0x100; \ b2 = a2 & 0x100; \ b3 = a3 & 0x100; \ a1 = (a1 | (b1 - (b1 >> 8))); \ a2 = (a2 | (b2 - (b2 >> 8))); \ a3 = (a3 | (b3 - (b3 >> 8))); \ if(is_yuv) \ { \ CLAMP(a1, 0, 0xff); \ CLAMP(a2, 0, 0xff); \ CLAMP(a3, 0, 0xff); \ YUV::yuv.rgb_to_yuv_8(a1, a2, a3); \ } \ rows[0][i * components + 0] = a1 | (a1 << 8); \ rows[0][i * components + 1] = a2 | (a2 << 8); \ rows[0][i * components + 2] = a3 | (a3 << 8); \ } \ else \ { \ a1 = (int)rows[0][i * components + 0]; \ a2 = (int)rows[0][i * components + 1]; \ a3 = (int)rows[0][i * components + 2]; \ b1 = plugin->palette[0][plugin->buffer[i]]; \ b2 = plugin->palette[1][plugin->buffer[i]]; \ b3 = plugin->palette[2][plugin->buffer[i]]; \ if(is_yuv) YUV::yuv.yuv_to_rgb_8(a1, a2, a3); \ a1 += b1; \ a2 += b2; \ a3 += b3; \ b1 = a1 & 0x100; \ b2 = a2 & 0x100; \ b3 = a3 & 0x100; \ a1 = (a1 | (b1 - (b1 >> 8))); \ a2 = (a2 | (b2 - (b2 >> 8))); \ a3 = (a3 | (b3 - (b3 >> 8))); \ if(is_yuv) \ { \ CLAMP(a1, 0, 0xff); \ CLAMP(a2, 0, 0xff); \ CLAMP(a3, 0, 0xff); \ YUV::yuv.rgb_to_yuv_8(a1, a2, a3); \ } \ rows[0][i * components + 0] = a1; \ rows[0][i * components + 1] = a2; \ rows[0][i * components + 2] = a3; \ } \ i++; \ } \ i += 2; \ } \ } void BurnClient::process_package(LoadPackage *package) { BurnPackage *local_package = (BurnPackage*)package; unsigned char **input_rows = plugin->input_ptr->get_rows() + local_package->row1; //unsigned char **output_rows = plugin->output_ptr->get_rows() + local_package->row1; int width = plugin->input_ptr->get_w(); int height = local_package->row2 - local_package->row1; unsigned char *diff; //int pitch = width * plugin->input_ptr->get_bytes_per_pixel(); int i, x, y; int a1, a2, a3; int b1, b2, b3; diff = plugin->effecttv->image_bgsubtract_y(input_rows, plugin->input_ptr->get_color_model()); for(x = 1; x < width - 1; x++) { unsigned int v = 0; for(y = 0; y < height - 1; y++) { unsigned int w = diff[y * width + x]; plugin->buffer[y * width + x] |= v ^ w; v = w; } } for(x = 1; x < width - 1; x++) { i = width + x; for(y = 1; y < height; y++) { int v = plugin->buffer[i]; if(v < plugin->config.decay) plugin->buffer[i - width] = 0; else plugin->buffer[i - width + EffectTV::fastrand() % 3 - 1] = v - (EffectTV::fastrand() & plugin->config.decay); i += width; } } switch(plugin->input_ptr->get_color_model()) { case BC_RGB888: BURN(uint8_t, 3, 0); break; case BC_YUV888: BURN(uint8_t, 3, 1); break; case BC_RGB_FLOAT: BURN(float, 3, 0); break; case BC_RGBA_FLOAT: BURN(float, 4, 0); break; case BC_RGBA8888: BURN(uint8_t, 4, 0); break; case BC_YUVA8888: BURN(uint8_t, 4, 1); break; case BC_RGB161616: BURN(uint16_t, 3, 0); break; case BC_YUV161616: BURN(uint16_t, 3, 1); break; case BC_RGBA16161616: BURN(uint16_t, 4, 0); break; case BC_YUVA16161616: BURN(uint16_t, 4, 1); break; } } BurnPackage::BurnPackage() { }