From: Good Guy Date: Thu, 25 Mar 2021 22:54:08 +0000 (-0600) Subject: add HV 7-3 new plugins X-Git-Tag: 2021-03~1 X-Git-Url: https://cinelerra-gg.org/git/?a=commitdiff_plain;h=1180ebf94abe64513c184997927634ef20ea9075;p=goodguy%2Fcinelerra.git add HV 7-3 new plugins --- diff --git a/cinelerra-5.1/plugins/Makefile b/cinelerra-5.1/plugins/Makefile index 39230250..ff00d785 100644 --- a/cinelerra-5.1/plugins/Makefile +++ b/cinelerra-5.1/plugins/Makefile @@ -110,6 +110,7 @@ DIRS = $(OPENCV_OBJS) \ parametric \ perspective \ photoscale \ + posterize \ pitch \ polar \ radialblur \ @@ -142,6 +143,7 @@ DIRS = $(OPENCV_OBJS) \ timeavg \ timeblur \ timefront \ + timelapsehelper \ timestretch \ timestretchrt \ titler \ diff --git a/cinelerra-5.1/plugins/posterize/Makefile b/cinelerra-5.1/plugins/posterize/Makefile new file mode 100644 index 00000000..3e62f965 --- /dev/null +++ b/cinelerra-5.1/plugins/posterize/Makefile @@ -0,0 +1,9 @@ +include ../../plugin_defs + +OBJS = $(OBJDIR)/posterize.o + +PLUGIN = posterize + +include ../../plugin_config + +$(OBJDIR)/posterize.o: posterize.C diff --git a/cinelerra-5.1/plugins/posterize/posterize.C b/cinelerra-5.1/plugins/posterize/posterize.C new file mode 100644 index 00000000..2966ef2e --- /dev/null +++ b/cinelerra-5.1/plugins/posterize/posterize.C @@ -0,0 +1,339 @@ + +/* + * CINELERRA + * Copyright (C) 2008-2021 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 "filexml.h" +#include "language.h" +#include "posterize.h" +#include "theme.h" + +#include +#include + + +REGISTER_PLUGIN(PosterizeMain) + + +#define MIN_STEPS 1 +#define MAX_STEPS 255 + +PosterizeConfig::PosterizeConfig() +{ + steps = 255; +} + +int PosterizeConfig::equivalent(PosterizeConfig &that) +{ + return steps == that.steps; +} + +void PosterizeConfig::copy_from(PosterizeConfig &that) +{ + steps = that.steps; +} + +void PosterizeConfig::boundaries() +{ + CLAMP(steps, MIN_STEPS, MAX_STEPS); +} + + +void PosterizeConfig::interpolate(PosterizeConfig &prev, + PosterizeConfig &next, + int64_t prev_frame, + int64_t next_frame, + int64_t 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->steps = (int)(prev.steps * prev_scale + next.steps * next_scale); + boundaries(); +} + +PosterizeMain::PosterizeMain(PluginServer *server) + : PluginVClient(server) +{ + +} + +PosterizeMain::~PosterizeMain() +{ + +} + +const char* PosterizeMain::plugin_title() { return N_("Posterize"); } +int PosterizeMain::is_realtime() { return 1; } + +NEW_WINDOW_MACRO(PosterizeMain, PosterizeWindow) +LOAD_CONFIGURATION_MACRO(PosterizeMain, PosterizeConfig) + + +void PosterizeMain::update_gui() +{ + if(thread) + { + if(load_configuration()) + { + thread->window->lock_window(); + ((PosterizeWindow*)thread->window)->update(1, 1); + thread->window->unlock_window(); + } + } +} + + + +void PosterizeMain::save_data(KeyFrame *keyframe) +{ + FileXML output; + +// cause data to be stored directly in text + output.set_shared_output(keyframe->xbuf); + output.tag.set_title("POSTERIZE"); + output.tag.set_property("STEPS", config.steps); + output.append_tag(); + output.tag.set_title("/POSTERIZE"); + output.append_tag(); + output.append_newline(); + output.terminate_string(); +} + +void PosterizeMain::read_data(KeyFrame *keyframe) +{ + FileXML input; + + input.set_shared_input(keyframe->xbuf); + + int result = 0; + + while(!result) + { + result = input.read_tag(); + + if(!result) + { + if(input.tag.title_is("POSTERIZE")) + { + config.steps = input.tag.get_property("STEPS", config.steps); + } + } + } + + config.boundaries(); +} + + +#define PROCESS(type, components, yuv) \ +{ \ + for(int i = 0; i < h; i++) \ + { \ + type *in_row = (type*)frame->get_rows()[i]; \ + type *out_row = (type*)frame->get_rows()[i]; \ + \ + for(int j = 0; j < w; j++) \ + { \ + if(sizeof(type) == 4) \ + { \ + out_row[j * components + 0] = (int)(in_row[j * components + 0] / division) * division; \ + out_row[j * components + 1] = (int)(in_row[j * components + 1] / division) * division; \ + out_row[j * components + 2] = (int)(in_row[j * components + 2] / division) * division; \ + } \ + else \ + { \ + out_row[j * components + 0] = table_r[(int)in_row[j * components + 0]]; \ + out_row[j * components + 1] = table_g[(int)in_row[j * components + 1]]; \ + out_row[j * components + 2] = table_b[(int)in_row[j * components + 2]]; \ + } \ + } \ + } \ +} + + +int PosterizeMain::process_buffer(VFrame *frame, + int64_t start_position, + double frame_rate) +{ + load_configuration(); + + read_frame(frame, + 0, + start_position, + frame_rate, + 0); + + int w = frame->get_w(); + int h = frame->get_h(); + + int table_r[256]; + int table_g[256]; + int table_b[256]; + float division = (float)255 / config.steps; + for(int i = 0; i < 256; i++) + { +// luma/red + table_r[i] = (int)(i / division) * division; +//printf("PosterizeMain::process_buffer %d i=%d %d\n", __LINE__, i, table_r[i]); +// if(BC_CModels::is_yuv(frame->get_color_model())) +// { +// table_g[i] = (int)(i / division) * division; +// table_b[i] = (int)(i / division) * division; +// } +// else +// { + table_g[i] = table_r[i]; + table_b[i] = table_r[i]; +// } + } + + + + switch(frame->get_color_model()) + { + case BC_YUV888: + PROCESS(unsigned char, 3, 1); + break; + case BC_YUVA8888: + PROCESS(unsigned char, 4, 1); + break; + case BC_RGB888: + PROCESS(unsigned char, 3, 0); + break; + case BC_RGBA8888: + PROCESS(unsigned char, 4, 0); + break; + case BC_RGB_FLOAT: + division = (float)1 / config.steps; + PROCESS(float, 3, 0); + break; + case BC_RGBA_FLOAT: + division = (float)1 / config.steps; + PROCESS(float, 4, 0); + break; + } + + return 0; +} + + + +PosterizeText::PosterizeText(PosterizeMain *plugin, + PosterizeWindow *gui, + int x, + int y, + int w, + int *output) + : BC_TextBox(x, y, w, 1, (int64_t)*output, 1, MEDIUMFONT) +{ + this->plugin = plugin; + this->gui = gui; + this->output = output; +} + +int PosterizeText::handle_event() +{ + *output = atoi(get_text()); + gui->update(1, 0); + plugin->send_configure_change(); + return 1; +} + + + + +PosterizeSlider::PosterizeSlider(PosterizeMain *plugin, + PosterizeWindow *gui, + int x, + int y, + int w, + int *output, + int min, + int max) + : BC_ISlider(x, y, 0, w, w, min, max, *output) +{ + this->plugin = plugin; + this->gui = gui; + this->output = output; +} +int PosterizeSlider::handle_event() +{ + *output = get_value(); + gui->update(0, 1); + plugin->send_configure_change(); + return 1; +} + + + + + +PosterizeWindow::PosterizeWindow(PosterizeMain *plugin) + : PluginClientWindow(plugin, + xS(300), + yS(100), + xS(300), + yS(100), + 0) +{ + this->plugin = plugin; +} + +PosterizeWindow::~PosterizeWindow() +{ +} + +void PosterizeWindow::create_objects() +{ + int text_w = xS(100); + int margin = client->get_theme()->widget_border; + int x = margin, y = margin; + BC_Title *title; + add_tool(title = new BC_Title(x, y, _("Steps per channel:"))); + y += title->get_h() + margin; + add_tool(slider = new PosterizeSlider(plugin, + this, + x, + y, + get_w() - text_w - margin - margin - margin, + &plugin->config.steps, + MIN_STEPS, + MAX_STEPS)); + x += slider->get_w() + margin; + add_tool(text = new PosterizeText(plugin, + this, + x, + y, + text_w, + &plugin->config.steps)); + + show_window(); + flush(); +} + +void PosterizeWindow::update(int do_slider, int do_text) +{ + if(do_text) text->update((int64_t)plugin->config.steps); + if(do_slider) slider->update(plugin->config.steps); +} + + + + + diff --git a/cinelerra-5.1/plugins/posterize/posterize.h b/cinelerra-5.1/plugins/posterize/posterize.h new file mode 100644 index 00000000..aae6466a --- /dev/null +++ b/cinelerra-5.1/plugins/posterize/posterize.h @@ -0,0 +1,117 @@ + +/* + * CINELERRA + * Copyright (C) 2008-2020 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 + * + */ + +#ifndef POSTERIZE_H +#define POSTERIZE_H + +class PosterizeMain; +class PosterizeWindow; + +#include "bchash.h" +#include "mutex.h" +#include "pluginvclient.h" +#include + +class PosterizeConfig +{ +public: + PosterizeConfig(); + int equivalent(PosterizeConfig &that); + void copy_from(PosterizeConfig &that); + void interpolate(PosterizeConfig &prev, + PosterizeConfig &next, + int64_t prev_frame, + int64_t next_frame, + int64_t current_frame); + void boundaries(); + int steps; +}; + +class PosterizeMain : public PluginVClient +{ +public: + PosterizeMain(PluginServer *server); + ~PosterizeMain(); + +// required for all realtime plugins + PLUGIN_CLASS_MEMBERS(PosterizeConfig); + int process_buffer(VFrame *frame, + int64_t start_position, + double frame_rate); + int is_realtime(); + void update_gui(); + void save_data(KeyFrame *keyframe); + void read_data(KeyFrame *keyframe); +}; + + + +class PosterizeSlider : public BC_ISlider +{ +public: + PosterizeSlider(PosterizeMain *plugin, + PosterizeWindow *gui, + int x, + int y, + int w, + int *output, + int min, + int max); + int handle_event(); + PosterizeMain *plugin; + PosterizeWindow *gui; + int *output; +}; + +class PosterizeText : public BC_TextBox +{ +public: + PosterizeText(PosterizeMain *plugin, + PosterizeWindow *gui, + int x, + int y, + int w, + int *output); + int handle_event(); + PosterizeMain *plugin; + PosterizeWindow *gui; + int *output; +}; + + + +class PosterizeWindow : public PluginClientWindow +{ +public: + PosterizeWindow(PosterizeMain *plugin); + ~PosterizeWindow(); + + void create_objects(); + + void update(int do_slider, int do_text); + + PosterizeMain *plugin; + PosterizeText *text; + PosterizeSlider *slider; +}; + + +#endif diff --git a/cinelerra-5.1/plugins/timelapsehelper/Makefile b/cinelerra-5.1/plugins/timelapsehelper/Makefile new file mode 100644 index 00000000..030abcca --- /dev/null +++ b/cinelerra-5.1/plugins/timelapsehelper/Makefile @@ -0,0 +1,9 @@ +include ../../plugin_defs + +OBJS = $(OBJDIR)/timelapsehelper.o + +PLUGIN = timelapsehelper + +include ../../plugin_config + +$(OBJDIR)/timelapsehelper.o: timelapsehelper.C diff --git a/cinelerra-5.1/plugins/timelapsehelper/timelapsehelper.C b/cinelerra-5.1/plugins/timelapsehelper/timelapsehelper.C new file mode 100644 index 00000000..3605d2af --- /dev/null +++ b/cinelerra-5.1/plugins/timelapsehelper/timelapsehelper.C @@ -0,0 +1,447 @@ + +/* + * CINELERRA + * Copyright (C) 2021 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 + * + */ + + +// output 1 frame for each block of frames +// take the most similar frame in the current block of frames to the previous frame +// this is for 3D printers where you want the bed in the same position + + +#include "bcdisplayinfo.h" +#include "clip.h" +#include "bchash.h" +#include "filexml.h" +#include "guicast.h" +#include "keyframe.h" +#include "language.h" +#include "transportque.inc" +#include "pluginvclient.h" +#include "theme.h" +#include "vframe.h" + +#include +#include + + +class TimelapseHelper; +class TimelapseHelperWindow; + + +class TimelapseHelperConfig +{ +public: + TimelapseHelperConfig(); + void copy_from(TimelapseHelperConfig &config); + int equivalent(TimelapseHelperConfig &config); + void interpolate(TimelapseHelperConfig &prev, + TimelapseHelperConfig &next, + int64_t prev_frame, + int64_t next_frame, + int64_t current_frame); + + int block_size; +}; + + + + +class TimelapseHelperSize : public BC_TumbleTextBox +{ +public: + TimelapseHelperSize(TimelapseHelper *plugin, + TimelapseHelperWindow *gui, + int x, + int y, + int w); + int handle_event(); + TimelapseHelper *plugin; + TimelapseHelperWindow *gui; +}; + + +class TimelapseHelperWindow : public PluginClientWindow +{ +public: + TimelapseHelperWindow(TimelapseHelper *plugin); + ~TimelapseHelperWindow(); + + void create_objects(); + + TimelapseHelper *plugin; + TimelapseHelperSize *size; +}; + + + + + +class TimelapseHelper : public PluginVClient +{ +public: + TimelapseHelper(PluginServer *server); + ~TimelapseHelper(); + + PLUGIN_CLASS_MEMBERS(TimelapseHelperConfig) + + int process_buffer(VFrame *frame, + int64_t start_position, + double frame_rate); + int is_realtime(); + void save_data(KeyFrame *keyframe); + void read_data(KeyFrame *keyframe); + void update_gui(); + + int64_t calculate_difference(VFrame *frame1, VFrame *frame2); + + +// frame used from the last block + VFrame *ref; +}; + + + + + + + + + + + + +TimelapseHelperConfig::TimelapseHelperConfig() +{ + block_size = 10; +} + +void TimelapseHelperConfig::copy_from(TimelapseHelperConfig &config) +{ + this->block_size = config.block_size; +} + +int TimelapseHelperConfig::equivalent(TimelapseHelperConfig &config) +{ + return this->block_size == config.block_size; +} + +void TimelapseHelperConfig::interpolate(TimelapseHelperConfig &prev, + TimelapseHelperConfig &next, + int64_t prev_frame, + int64_t next_frame, + int64_t current_frame) +{ + this->block_size = next.block_size; +} + + + + + + + + +TimelapseHelperWindow::TimelapseHelperWindow(TimelapseHelper *plugin) + : PluginClientWindow(plugin, + xS(230), + yS(160), + xS(230), + yS(160), + 0) +{ + this->plugin = plugin; +} + +TimelapseHelperWindow::~TimelapseHelperWindow() +{ +} + +void TimelapseHelperWindow::create_objects() +{ + int margin = client->get_theme()->widget_border; + int x = margin, y = margin; + + BC_Title *title; + add_subwindow(title = new BC_Title(x, y, _("Number of frames per block:"))); + y += title->get_h() + margin; + size = new TimelapseHelperSize(plugin, + this, + x, + y, + get_w() - x - margin); + size->create_objects(); + show_window(); +} + + + + + + + + + + + + + +TimelapseHelperSize::TimelapseHelperSize(TimelapseHelper *plugin, + TimelapseHelperWindow *gui, + int x, + int y, + int w) + : BC_TumbleTextBox(gui, + plugin->config.block_size, + 1, + 1000, + x, + y, + w) +{ + this->plugin = plugin; + this->gui = gui; +} + +int TimelapseHelperSize::handle_event() +{ + plugin->config.block_size = atoi(get_text()); + plugin->send_configure_change(); + return 1; +} + + + + + + + + + + +REGISTER_PLUGIN(TimelapseHelper) + + + + + + +TimelapseHelper::TimelapseHelper(PluginServer *server) + : PluginVClient(server) +{ + ref = 0; +} + + +TimelapseHelper::~TimelapseHelper() +{ + if(ref) + { + delete ref; + } +} + +#define DIFFERENCE_MACRO(type, temp_type, components) \ +{ \ + temp_type result2 = 0; \ + for(int i = 0; i < h; i++) \ + { \ + type *row1 = (type*)frame1->get_rows()[i]; \ + type *row2 = (type*)frame2->get_rows()[i]; \ + for(int j = 0; j < w * components; j++) \ + { \ + temp_type temp = *row1 - *row2; \ + result2 += (temp > 0 ? temp : -temp); \ + row1++; \ + row2++; \ + } \ + } \ + result = (int64_t)result2; \ +} + +int64_t TimelapseHelper::calculate_difference(VFrame *frame1, VFrame *frame2) +{ + int w = frame1->get_w(); + int h = frame1->get_h(); + int64_t result = 0; + switch(frame1->get_color_model()) + { + case BC_RGB888: + case BC_YUV888: + DIFFERENCE_MACRO(unsigned char, int64_t, 3); + break; + case BC_RGB_FLOAT: + DIFFERENCE_MACRO(float, double, 3); + break; + case BC_RGBA8888: + case BC_YUVA8888: + DIFFERENCE_MACRO(unsigned char, int64_t, 4); + break; + case BC_RGBA_FLOAT: + DIFFERENCE_MACRO(float, double, 4); + break; + case BC_RGB161616: + case BC_YUV161616: + DIFFERENCE_MACRO(uint16_t, int64_t, 3); + break; + case BC_RGBA16161616: + case BC_YUVA16161616: + DIFFERENCE_MACRO(uint16_t, int64_t, 4); + break; + } + return result; +} + + + +int TimelapseHelper::process_buffer(VFrame *frame, + int64_t start_position, + double frame_rate) +{ + load_configuration(); + +// calculate frame positions + int64_t ref_position = get_source_start(); + int64_t block_start; + int64_t block_end; + block_start = ref_position + (start_position - ref_position) * config.block_size; + block_end = block_start + config.block_size; + +printf("TimelapseHelper::process_buffer %d current_position=%ld ref_position=%ld block_start=%ld block_end=%ld\n", +__LINE__, +start_position, +ref_position, +block_start, +block_end); + +// load initial reference frame from plugin start + if(!ref) + { + ref = new VFrame(0, + -1, + frame->get_w(), + frame->get_h(), + frame->get_color_model(), + -1); + read_frame(ref, + 0, + ref_position, + frame_rate, + 0); + frame->copy_from(ref); + } + else +// compare next block of frames to reference frame + { + VFrame *temp = new_temp(frame->get_w(), + frame->get_h(), + frame->get_color_model()); + int64_t best = 0x7fffffffffffffffLL; + for(int64_t i = block_start; i < block_end; i++) + { + + if(get_direction() == PLAY_FORWARD) + { + read_frame(temp, + 0, + i, + frame_rate, + 0); + } + else + { + read_frame(temp, + 0, + i + 1, + frame_rate, + 0); + } + + int64_t diff = calculate_difference(temp, + ref); + if(diff < best) + { + best = diff; + frame->copy_from(temp); + } + } + +// replace reference frame with best match + ref->copy_from(frame); + } + + return 0; +} + + + +const char* TimelapseHelper::plugin_title() { return N_("Timelapse Helper"); } +int TimelapseHelper::is_realtime() { return 1; } + +NEW_WINDOW_MACRO(TimelapseHelper, TimelapseHelperWindow) + +LOAD_CONFIGURATION_MACRO(TimelapseHelper, TimelapseHelperConfig) + + +void TimelapseHelper::save_data(KeyFrame *keyframe) +{ + FileXML output; + +// cause data to be stored directly in text + output.set_shared_output(keyframe->xbuf); + output.tag.set_title("TIMELAPSEHELPER"); + output.tag.set_property("BLOCK_SIZE", config.block_size); + output.append_tag(); + output.tag.set_title("/TIMELAPSEHELPER"); + output.append_tag(); + output.append_newline(); + output.terminate_string(); +} + +void TimelapseHelper::read_data(KeyFrame *keyframe) +{ + FileXML input; + + input.set_shared_input(keyframe->xbuf); + + while(!input.read_tag()) + { + if(input.tag.title_is("TIMELAPSEHELPER")) + { + config.block_size = input.tag.get_property("BLOCK_SIZE", config.block_size); + } + } +} + +void TimelapseHelper::update_gui() +{ + if(thread) + { + if(load_configuration()) + { + ((TimelapseHelperWindow*)thread->window)->lock_window("TimelapseHelper::update_gui"); + ((TimelapseHelperWindow*)thread->window)->size->update((int64_t)config.block_size); + ((TimelapseHelperWindow*)thread->window)->unlock_window(); + } + } +} + + + +