/* * 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 "filexml.h" #include "language.h" #include "blurzoom.h" #include "blurzoomwindow.h" #include #include #include PluginClient* new_plugin(PluginServer *server) { return new BlurZoomMain(server); } BlurZoomConfig::BlurZoomConfig() { } BlurZoomMain::BlurZoomMain(PluginServer *server) : PluginVClient(server) { } BlurZoomMain::~BlurZoomMain() { } char* BlurZoomMain::plugin_title() { return N_("RadioacTV"); } int BlurZoomMain::is_realtime() { return 1; } NEW_WINDOW_MACRO(BlurZoomMain, BlurZoomWindow) int BlurZoomMain::load_configuration() { return 1; } void BlurZoomMain::save_data(KeyFrame *keyframe) { } void BlurZoomMain::read_data(KeyFrame *keyframe) { } #define VIDEO_HWIDTH (buf_width/2) #define VIDEO_HHEIGHT (buf_height/2) #define MAGIC_THRESHOLD 40 #define RATIO 0.95 void BlurZoomMain::image_set_threshold_y(int threshold) { y_threshold = threshold * 7; /* fake-Y value is timed by 7 */ } void BlurZoomMain::set_table() { int bits, x, y, tx, ty, xx; int ptr, prevptr; 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 |= 1; 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; } } void BlurZoomMain::make_palette() { int i; #define DELTA (255 / (COLORS / 2 - 1)) for(i = 0; i < COLORS / 2; i++) { palette_r[i] = i * DELTA; palette_g[i] = i * DELTA; palette_b[i] = i * DELTA; } for(i = 0; i < COLORS / 2; i++) { palette_r[i + COLORS / 2] = (i * DELTA); palette_g[i + COLORS / 2] = (i * DELTA); palette_b[i + COLORS / 2] = 255; } } int BlurZoomMain::start_realtime() { buf_width_blocks = project_frame_w / 32; buf_width = buf_width_blocks * 32; buf_height = project_frame_h; buf_area = buf_width * buf_height; buf_margin_left = (project_frame_w - buf_width) / 2; buf_margin_right = project_frame_w - buf_width - buf_margin_left; blurzoombuf = new unsigned char[buf_area * 2]; blurzoomx = new int[buf_width]; blurzoomy = new int[buf_height]; set_table(); make_palette(); bzero(blurzoombuf, buf_area * 2); background = new uint16_t[project_frame_w * project_frame_h]; diff = new unsigned char[project_frame_w * project_frame_h]; image_set_threshold_y(MAGIC_THRESHOLD); blurzoom_server = new BlurZoomServer(this, 1, 1); return 0; } int BlurZoomMain::stop_realtime() { delete blurzoom_server; delete [] blurzoombuf; delete [] blurzoomx; delete [] blurzoomy; delete [] background; delete [] diff; return 0; } int BlurZoomMain::process_realtime(VFrame *input_ptr, VFrame *output_ptr) { load_configuration(); this->input_ptr = input_ptr; this->output_ptr = output_ptr; blurzoom_server->process_packages(); return 0; } BlurZoomServer::BlurZoomServer(BlurZoomMain *plugin, int total_clients, total_packages) : LoadServer(total_clients, get_total_packages()) { this->plugin = plugin; } LoadClient* BlurZoomServer::new_client() { return new BlurZoomClient(this); } LoadPackage* BlurZoomServer::new_package() { return new BlurZoomPackage; } void BlurZoomServer::init_packages() { for(int i = 0; i < get_total_packages(); i++) { BlurZoomPackage *package = (BlurZoomPackage*)get_package(i); package->row1 = plugin->input_ptr->get_h() / get_total_packages() * i; package->row2 = package->row1 + plugin->input_ptr->get_h() / get_total_packages(); if(i >= get_total_packages() - 1) package->row2 = plugin->input_ptr->get_h(); } } BlurZoomClient::BlurZoomClient(BlurZoomServer *server) : LoadClient(server) { this->plugin = server->plugin; } /* Background image is refreshed every frame */ #define IMAGE_BGSUBTRACT_UPDATE_Y(result, \ input_rows, \ type, \ components) \ { \ int i; \ int R, G, B; \ type *p; \ int16_t *q; \ unsigned char *r; \ int v; \ \ q = (int16_t *)background; \ r = diff; \ \ for(i = 0; i < project_frame_h; i++) \ { \ p = input_rows[j]; \ \ for(j = 0; j < project_frame_w; j++) \ { \ if(sizeof(type) == 2) \ { \ R = p[0] >> (8 - 1); \ G = p[1] >> (8 - 2); \ B = p[2] >> 8; \ } \ else \ { \ R = p[0] << 1; \ G = p[1] << 2; \ B = p[2]; \ } \ \ v = (R + G + B) - (int)(*q); \ *q = (int16_t)(R + G + B); \ *r = ((v + y_threshold) >> 24) | ((y_threshold - v) >> 24); \ \ p += components; \ q++; \ r++; \ } \ } \ \ result = diff; \ } #define BLURZOOM_FINAL(type, components) { for(y = 0; y < h; y++) { memcpy(output_rows[y], input_rows[y], buf_margin_left * plugin->input_ptr->get_bytes_per_pixel()); for(x = 0; x < buf_width; x++) { for(c = 0; c < components; c++) { a = *src++ & 0xfefeff; b = palette[*p++]; a += b; b = a & 0x1010100; *dest++ = a | (b - (b >> 8)); } } memcpy(output_rows[y] + project_frame_w - buf_margin_right, input_rows[y] + project_frame_w - buf_margin_right, buf_margin_right * plugin->input_ptr->get_bytes_per_pixel()); } } void BlurZoomClient::process_package(LoadPackage *package) { BlurZoomPackage *local_package = (BlurZoomPackage*)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 w = plugin->input_ptr->get_w(); int h = local_package->row2 - local_package->row1; int x, y; int a, b, c; unsigned char *diff, *p; switch(plugin->input_ptr->get_color_model()) { case BC_RGB888: case BC_YUV888: IMAGE_BGSUBTRACT_UPDATE_Y(diff, input_rows, uint8_t, 3); break; case BC_RGBA8888: case BC_YUVA8888: IMAGE_BGSUBTRACT_UPDATE_Y(diff, input_rows, uint8_t, 4); break; case BC_RGB161616: case BC_YUV161616: IMAGE_BGSUBTRACT_UPDATE_Y(diff, input_rows, uint16_t, 3); break; case BC_RGBA16161616: case BC_YUVA16161616: IMAGE_BGSUBTRACT_UPDATE_Y(diff, input_rows, uint16_t, 4); break; } diff += buf_margin_left; p = blurzoombuf; for(y = 0; y < buf_height; y++) { for(x = 0; x < buf_width; x++) { p[x] |= diff[x] >> 3; } diff += w; p += buf_width; } // Assembly language only blurzoomcore(); p = blurzoombuf; switch(plugin->input_ptr->get_color_model()) { case BC_RGB888: case BC_YUV888: BLURZOOM_FINAL(uint8_t, 3); break; case BC_RGBA8888: case BC_YUVA8888: BLURZOOM_FINAL(uint8_t, 4); break; case BC_RGB161616: case BC_YUV161616: BLURZOOM_FINAL(uint16_t, 3); break; case BC_RGBA16161616: case BC_YUVA16161616: BLURZOOM_FINAL(uint16_t, 4); break; } } BlurZoomPackage::BlurZoomPackage() { }