+++ /dev/null
-
-/*
- * CINELERRA
- * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
- *
- * 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 "condition.h"
-#include "filexml.h"
-#include "language.h"
-#include "sharpen.h"
-#include "sharpenwindow.h"
-
-#include <stdio.h>
-#include <string.h>
-
-REGISTER_PLUGIN(SharpenMain)
-
-
-
-
-
-
-
-SharpenConfig::SharpenConfig()
-{
- horizontal = 0;
- interlace = 0;
- sharpness = 50;
- luminance = 0;
-}
-
-void SharpenConfig::copy_from(SharpenConfig &that)
-{
- horizontal = that.horizontal;
- interlace = that.interlace;
- sharpness = that.sharpness;
- luminance = that.luminance;
-}
-
-int SharpenConfig::equivalent(SharpenConfig &that)
-{
- return horizontal == that.horizontal &&
- interlace == that.interlace &&
- EQUIV(sharpness, that.sharpness) &&
- luminance == that.luminance;
-}
-
-void SharpenConfig::interpolate(SharpenConfig &prev,
- SharpenConfig &next,
- long prev_frame,
- long next_frame,
- long current_frame)
-{
- double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
- double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
- this->sharpness = prev.sharpness * prev_scale + next.sharpness * next_scale;
- this->interlace = prev.interlace;
- this->horizontal = prev.horizontal;
- this->luminance = prev.luminance;
-}
-
-
-
-
-
-
-
-
-
-
-
-SharpenMain::SharpenMain(PluginServer *server)
- : PluginVClient(server)
-{
-
- engine = 0;
-}
-
-SharpenMain::~SharpenMain()
-{
-
-
- if(engine)
- {
- for(int i = 0; i < total_engines; i++)
- {
- delete engine[i];
- }
- delete engine;
- }
-}
-
-NEW_WINDOW_MACRO(SharpenMain, SharpenWindow)
-
-
-LOAD_CONFIGURATION_MACRO(SharpenMain, SharpenConfig)
-
-const char* SharpenMain::plugin_title() { return _("Sharpen"); }
-int SharpenMain::is_realtime() { return 1; }
-
-
-
-int SharpenMain::process_realtime(VFrame *input_ptr, VFrame *output_ptr)
-{
- int j, k;
- output = output_ptr;
- input = input_ptr;
-
- load_configuration();
- if(!engine)
- {
-
- total_engines = PluginClient::smp > 1 ? 2 : 1;
- engine = new SharpenEngine*[total_engines];
- for(int i = 0; i < total_engines; i++)
- {
- engine[i] = new SharpenEngine(this);
- engine[i]->start();
- }
- }
-
- get_luts(pos_lut, neg_lut, input_ptr->get_color_model());
-
- if(config.sharpness != 0)
- {
-// Arm first row
- row_step = (config.interlace /* || config.horizontal */) ? 2 : 1;
-
- for(j = 0; j < row_step; j += total_engines)
- {
- for(k = 0; k < total_engines && k + j < row_step; k++)
- {
- engine[k]->start_process_frame(input_ptr, input_ptr, k + j);
- }
- for(k = 0; k < total_engines && k + j < row_step; k++)
- {
- engine[k]->wait_process_frame();
- }
- }
- }
- else
- if(input_ptr->get_rows()[0] != output_ptr->get_rows()[0])
- {
- output_ptr->copy_from(input_ptr);
- }
- return 0;
-}
-
-void SharpenMain::update_gui()
-{
- if(thread)
- {
- load_configuration();
- thread->window->lock_window("SharpenMain::update_gui");
- ((SharpenWindow*)thread->window)->sharpen_slider->update((int)config.sharpness);
- ((SharpenWindow*)thread->window)->sharpen_interlace->update(config.interlace);
- ((SharpenWindow*)thread->window)->sharpen_horizontal->update(config.horizontal);
- ((SharpenWindow*)thread->window)->sharpen_luminance->update(config.luminance);
- thread->window->unlock_window();
- }
-}
-
-
-
-
-int SharpenMain::get_luts(int *pos_lut, int *neg_lut, int color_model)
-{
- int i, inv_sharpness, vmax;
-
- vmax = BC_CModels::calculate_max(color_model);
-
- inv_sharpness = (int)(100 - config.sharpness);
- if(config.horizontal) inv_sharpness /= 2;
- if(inv_sharpness < 1) inv_sharpness = 1;
-
- for(i = 0; i < vmax + 1; i++)
- {
- pos_lut[i] = 800 * i / inv_sharpness;
- neg_lut[i] = (4 + pos_lut[i] - (i << 3)) >> 3;
- }
-
- return 0;
-}
-
-void SharpenMain::save_data(KeyFrame *keyframe)
-{
- FileXML output;
-
-// cause data to be stored directly in text
- output.set_shared_output(keyframe->get_data(), MESSAGESIZE);
- output.tag.set_title("SHARPNESS");
- output.tag.set_property("VALUE", config.sharpness);
- output.tag.set_property("INTERLACE", config.interlace);
- output.tag.set_property("HORIZONTAL", config.horizontal);
- output.tag.set_property("LUMINANCE", config.luminance);
- output.append_tag();
- output.tag.set_title("/SHARPNESS");
- output.append_tag();
- output.append_newline();
- output.terminate_string();
-}
-
-void SharpenMain::read_data(KeyFrame *keyframe)
-{
- FileXML input;
-
- input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
-
- int result = 0;
-
- while(!result)
- {
- result = input.read_tag();
-
- if(!result)
- {
- if(input.tag.title_is("SHARPNESS"))
- {
- config.sharpness = input.tag.get_property("VALUE", config.sharpness);
- config.interlace = input.tag.get_property("INTERLACE", config.interlace);
- config.horizontal = input.tag.get_property("HORIZONTAL", config.horizontal);
- config.luminance = input.tag.get_property("LUMINANCE", config.luminance);
-//printf("SharpenMain::read_data %f\n", sharpness);
- }
- }
- }
-
- if(config.sharpness > MAXSHARPNESS)
- config.sharpness = MAXSHARPNESS;
- else
- if(config.sharpness < 0) config.sharpness = 0;
-}
-
-
-
-
-SharpenEngine::SharpenEngine(SharpenMain *plugin)
- : Thread(1, 0, 0)
-{
- this->plugin = plugin;
- input_lock = new Condition(0,"SharpenEngine::input_lock");
- output_lock = new Condition(0, "SharpenEngine::output_lock");
- last_frame = 0;
- for(int i = 0; i < 4; i++)
- {
- neg_rows[i] = new unsigned char[plugin->input->get_w() *
- 4 *
- MAX(sizeof(float), sizeof(int))];
- }
-}
-
-SharpenEngine::~SharpenEngine()
-{
- last_frame = 1;
- input_lock->unlock();
- Thread::join();
-
- for(int i = 0; i < 4; i++)
- {
- delete [] neg_rows[i];
- }
- delete input_lock;
- delete output_lock;
-}
-
-int SharpenEngine::start_process_frame(VFrame *output, VFrame *input, int field)
-{
- this->output = output;
- this->input = input;
- this->field = field;
-
-// Get coefficient for floating point
- sharpness_coef = 100 - plugin->config.sharpness;
- if(plugin->config.horizontal) sharpness_coef /= 2;
- if(sharpness_coef < 1) sharpness_coef = 1;
- sharpness_coef = 800.0 / sharpness_coef;
-
- input_lock->unlock();
- return 0;
-}
-
-int SharpenEngine::wait_process_frame()
-{
- output_lock->lock("SharpenEngine::wait_process_frame");
- return 0;
-}
-
-float SharpenEngine::calculate_pos(float value)
-{
- return sharpness_coef * value;
-}
-
-float SharpenEngine::calculate_neg(float value)
-{
- return (calculate_pos(value) - (value * 8)) / 8;
-}
-
-#define FILTER(components, vmax) \
-{ \
- int *pos_lut = plugin->pos_lut; \
- const int wordsize = sizeof(*src); \
- \
-/* Skip first pixel in row */ \
- memcpy(dst, src, components * wordsize); \
- dst += components; \
- src += components; \
- \
- w -= 2; \
- \
- while(w > 0) \
- { \
- long pixel; \
- pixel = (long)pos_lut[src[0]] - \
- (long)neg0[-components] - \
- (long)neg0[0] - \
- (long)neg0[components] - \
- (long)neg1[-components] - \
- (long)neg1[components] - \
- (long)neg2[-components] - \
- (long)neg2[0] - \
- (long)neg2[components]; \
- pixel = (pixel + 4) >> 3; \
- if(pixel < 0) dst[0] = 0; \
- else \
- if(pixel > vmax) dst[0] = vmax; \
- else \
- dst[0] = pixel; \
- \
- pixel = (long)pos_lut[src[1]] - \
- (long)neg0[-components + 1] - \
- (long)neg0[1] - \
- (long)neg0[components + 1] - \
- (long)neg1[-components + 1] - \
- (long)neg1[components + 1] - \
- (long)neg2[-components + 1] - \
- (long)neg2[1] - \
- (long)neg2[components + 1]; \
- pixel = (pixel + 4) >> 3; \
- if(pixel < 0) dst[1] = 0; \
- else \
- if(pixel > vmax) dst[1] = vmax; \
- else \
- dst[1] = pixel; \
- \
- pixel = (long)pos_lut[src[2]] - \
- (long)neg0[-components + 2] - \
- (long)neg0[2] - \
- (long)neg0[components + 2] - \
- (long)neg1[-components + 2] - \
- (long)neg1[components + 2] - \
- (long)neg2[-components + 2] - \
- (long)neg2[2] - \
- (long)neg2[components + 2]; \
- pixel = (pixel + 4) >> 3; \
- if(pixel < 0) dst[2] = 0; \
- else \
- if(pixel > vmax) dst[2] = vmax; \
- else \
- dst[2] = pixel; \
- \
- src += components; \
- dst += components; \
- \
- neg0 += components; \
- neg1 += components; \
- neg2 += components; \
- w--; \
- } \
- \
-/* Skip last pixel in row */ \
- memcpy(dst, src, components * wordsize); \
-}
-
-void SharpenEngine::filter(int components,
- int vmax,
- int w,
- u_int16_t *src,
- u_int16_t *dst,
- int *neg0,
- int *neg1,
- int *neg2)
-{
- FILTER(components, vmax);
-}
-
-void SharpenEngine::filter(int components,
- int vmax,
- int w,
- unsigned char *src,
- unsigned char *dst,
- int *neg0,
- int *neg1,
- int *neg2)
-{
- FILTER(components, vmax);
-}
-
-void SharpenEngine::filter(int components,
- int vmax,
- int w,
- float *src,
- float *dst,
- float *neg0,
- float *neg1,
- float *neg2)
-{
- const int wordsize = sizeof(float);
-// First pixel in row
- memcpy(dst, src, components * wordsize);
- dst += components;
- src += components;
-
- w -= 2;
- while(w > 0)
- {
- float pixel;
- pixel = calculate_pos(src[0]) -
- neg0[-components] -
- neg0[0] -
- neg0[components] -
- neg1[-components] -
- neg1[components] -
- neg2[-components] -
- neg2[0] -
- neg2[components];
- pixel /= 8;
- dst[0] = pixel;
-
- pixel = calculate_pos(src[1]) -
- neg0[-components + 1] -
- neg0[1] -
- neg0[components + 1] -
- neg1[-components + 1] -
- neg1[components + 1] -
- neg2[-components + 1] -
- neg2[1] -
- neg2[components + 1];
- pixel /= 8;
- dst[1] = pixel;
-
- pixel = calculate_pos(src[2]) -
- neg0[-components + 2] -
- neg0[2] -
- neg0[components + 2] -
- neg1[-components + 2] -
- neg1[components + 2] -
- neg2[-components + 2] -
- neg2[2] -
- neg2[components + 2];
- pixel /= 8;
- dst[2] = pixel;
-
- src += components;
- dst += components;
- neg0 += components;
- neg1 += components;
- neg2 += components;
- w--;
- }
-
-/* Last pixel */
- memcpy(dst, src, components * wordsize);
-}
-
-
-
-
-
-
-
-#define SHARPEN(components, type, temp_type, vmax) \
-{ \
- int count, row; \
- int wordsize = sizeof(type); \
- unsigned char **input_rows, **output_rows; \
- int w = plugin->input->get_w(); \
- int h = plugin->input->get_h(); \
- \
- input_rows = input->get_rows(); \
- output_rows = output->get_rows(); \
- src_rows[0] = input_rows[field]; \
- src_rows[1] = input_rows[field]; \
- src_rows[2] = input_rows[field]; \
- src_rows[3] = input_rows[field]; \
- \
- for(int j = 0; j < w; j++) \
- { \
- temp_type *neg = (temp_type*)neg_rows[0]; \
- type *src = (type*)src_rows[0]; \
- for(int k = 0; k < components; k++) \
- { \
- if(wordsize == 4) \
- { \
- neg[j * components + k] = \
- (temp_type)calculate_neg(src[j * components + k]); \
- } \
- else \
- { \
- neg[j * components + k] = \
- (temp_type)plugin->neg_lut[(int)src[j * components + k]]; \
- } \
- } \
- } \
- \
- row = 1; \
- count = 1; \
- \
- for(int i = field; i < h; i += plugin->row_step) \
- { \
- if((i + plugin->row_step) < h) \
- { \
- if(count >= 3) count--; \
-/* Arm next row */ \
- src_rows[row] = input_rows[i + plugin->row_step]; \
-/* Calculate neg rows */ \
- type *src = (type*)src_rows[row]; \
- temp_type *neg = (temp_type*)neg_rows[row]; \
- for(int k = 0; k < w; k++) \
- { \
- for(int j = 0; j < components; j++) \
- { \
- if(wordsize == 4) \
- { \
- neg[k * components + j] = \
- (temp_type)calculate_neg(src[k * components + j]); \
- } \
- else \
- { \
- neg[k * components + j] = \
- plugin->neg_lut[(int)src[k * components + j]]; \
- } \
- } \
- } \
- \
- count++; \
- row = (row + 1) & 3; \
- } \
- else \
- { \
- count--; \
- } \
- \
- dst_row = output_rows[i]; \
- if(count == 3) \
- { \
-/* Do the filter */ \
- if(plugin->config.horizontal) \
- filter(components, \
- vmax, \
- w, \
- (type*)src_rows[(row + 2) & 3], \
- (type*)dst_row, \
- (temp_type*)neg_rows[(row + 2) & 3] + components, \
- (temp_type*)neg_rows[(row + 2) & 3] + components, \
- (temp_type*)neg_rows[(row + 2) & 3] + components); \
- else \
- filter(components, \
- vmax, \
- w, \
- (type*)src_rows[(row + 2) & 3], \
- (type*)dst_row, \
- (temp_type*)neg_rows[(row + 1) & 3] + components, \
- (temp_type*)neg_rows[(row + 2) & 3] + components, \
- (temp_type*)neg_rows[(row + 3) & 3] + components); \
- } \
- else \
- if(count == 2) \
- { \
- if(i == 0) \
- memcpy(dst_row, src_rows[0], w * components * wordsize); \
- else \
- memcpy(dst_row, src_rows[2], w * components * wordsize); \
- } \
- } \
-}
-
-
-
-void SharpenEngine::run()
-{
- while(1)
- {
- input_lock->lock("SharpenEngine::run");
- if(last_frame)
- {
- output_lock->unlock();
- return;
- }
-
-
- switch(input->get_color_model())
- {
- case BC_RGB_FLOAT:
- SHARPEN(3, float, float, 1);
- break;
-
- case BC_RGB888:
- case BC_YUV888:
- SHARPEN(3, unsigned char, int, 0xff);
- break;
-
- case BC_RGBA_FLOAT:
- SHARPEN(4, float, float, 1);
- break;
-
- case BC_RGBA8888:
- case BC_YUVA8888:
- SHARPEN(4, unsigned char, int, 0xff);
- break;
-
- case BC_RGB161616:
- case BC_YUV161616:
- SHARPEN(3, u_int16_t, int, 0xffff);
- break;
-
- case BC_RGBA16161616:
- case BC_YUVA16161616:
- SHARPEN(4, u_int16_t, int, 0xffff);
- break;
- }
-
- output_lock->unlock();
- }
-}
-