rework edge plugin, add crikey plugin, text tumbler tweak, eyedropper coords
authorGood Guy <good1.2guy@gmail.com>
Sun, 25 Jun 2017 19:30:21 +0000 (13:30 -0600)
committerGood Guy <good1.2guy@gmail.com>
Sun, 25 Jun 2017 19:30:21 +0000 (13:30 -0600)
14 files changed:
cinelerra-5.1/cinelerra/cwindowtool.C
cinelerra-5.1/cinelerra/cwindowtool.h
cinelerra-5.1/guicast/bctextbox.C
cinelerra-5.1/guicast/bctextbox.h
cinelerra-5.1/plugin_defs
cinelerra-5.1/plugins/Makefile
cinelerra-5.1/plugins/crikey/Makefile [new file with mode: 0644]
cinelerra-5.1/plugins/crikey/crikey.C [new file with mode: 0644]
cinelerra-5.1/plugins/crikey/crikey.h [new file with mode: 0644]
cinelerra-5.1/plugins/crikey/crikeywindow.C [new file with mode: 0644]
cinelerra-5.1/plugins/crikey/crikeywindow.h [new file with mode: 0644]
cinelerra-5.1/plugins/crikey/picon.png [new file with mode: 0644]
cinelerra-5.1/plugins/edge/edge.C
cinelerra-5.1/plugins/edge/edge.h

index ee1c1044f2e34cec1871b278196ae66026ba4799..caf0bf82d2953b65b9f4eeb2d9917d9a958cdd9b 100644 (file)
@@ -480,7 +480,9 @@ void CWindowEyedropGUI::create_objects()
        int y = margin;
        int x2 = 70;
        lock_window("CWindowEyedropGUI::create_objects");
-       BC_Title *title1, *title2, *title3, *title4, *title5, *title6, *title7;
+       BC_Title *title0, *title1, *title2, *title3, *title4, *title5, *title6, *title7;
+       add_subwindow(title0 = new BC_Title(x, y,_("X,Y:")));
+       y += title0->get_h() + margin;
        add_subwindow(title7 = new BC_Title(x, y, _("Radius:")));
        y += BC_TextBox::calculate_h(this, MEDIUMFONT, 1, 1) + margin;
 
@@ -497,6 +499,7 @@ void CWindowEyedropGUI::create_objects()
        y += title5->get_h() + margin;
        add_subwindow(title6 = new BC_Title(x, y, "V:"));
 
+       add_subwindow(current = new BC_Title(x2, title0->get_y(), ""));
 
        radius = new CWindowCoord(this, x2, title7->get_y(),
                mwindow->edl->session->eyedrop_radius);
@@ -520,6 +523,12 @@ void CWindowEyedropGUI::create_objects()
 
 void CWindowEyedropGUI::update()
 {
+       char string[BCTEXTLEN];
+       sprintf(string, "%d, %d",
+               thread->gui->eyedrop_x,
+               thread->gui->eyedrop_y);
+       current->update(string);
+
        radius->update((int64_t)mwindow->edl->session->eyedrop_radius);
 
        red->update(mwindow->edl->local_session->red);
index 2fb3ab9ff63891ce1c6f90909015b3341601964c..5761ae8ae80387a62efe29e5bf0bdf991a8ba391 100644 (file)
@@ -264,6 +264,7 @@ public:
        void create_objects();
        void update();
 
+       BC_Title *current;
        CWindowCoord *radius;
        BC_Title *red, *green, *blue, *y, *u, *v;
        BC_SubWindow *sample;
index bd43f1cdf31b0bb4c63c45a3f797807d74286f44..ef3ffb1f587f652b3a4e43fc20583557d9077627 100644 (file)
@@ -2561,8 +2561,8 @@ BC_TumbleTextBoxText::BC_TumbleTextBoxText(BC_TumbleTextBox *popup,
 }
 
 BC_TumbleTextBoxText::BC_TumbleTextBoxText(BC_TumbleTextBox *popup,
-       float default_value, int x, int y)
- : BC_TextBox(x, y, popup->text_w, 1, default_value)
+       float default_value, int x, int y, int precision)
+ : BC_TextBox(x, y, popup->text_w, 1, default_value, 1, MEDIUMFONT, precision)
 {
        this->popup = popup;
 }
@@ -2714,31 +2714,17 @@ int BC_TumbleTextBox::create_objects()
 {
        int x = this->x, y = this->y;
 
-       if(use_float)
-       {
-               parent_window->add_subwindow(textbox = new BC_TumbleTextBoxText(this,
-                       default_value_f, x, y));
-               textbox->set_precision(precision);
-       }
-       else
-               parent_window->add_subwindow(textbox = new BC_TumbleTextBoxText(this,
-                       default_value, x, y));
+       textbox = use_float ?
+               new BC_TumbleTextBoxText(this, default_value_f, x, y, precision) :
+               new BC_TumbleTextBoxText(this, default_value, x, y);
 
+       parent_window->add_subwindow(textbox);
        x += textbox->get_w();
 
-       if(use_float)
-               parent_window->add_subwindow(tumbler = new BC_FTumbler(textbox,
-                       min_f,
-                       max_f,
-                       x,
-                       y));
-       else
-               parent_window->add_subwindow(tumbler = new BC_ITumbler(textbox,
-                       min,
-                       max,
-                       x,
-                       y));
-
+       tumbler = use_float ?
+               (BC_Tumbler *)new BC_FTumbler(textbox, min_f, max_f, x, y) :
+               (BC_Tumbler *)new BC_ITumbler(textbox, min, max, x, y);
+       parent_window->add_subwindow(tumbler);
        tumbler->set_increment(increment);
        return 0;
 }
index e681f76fc2de3e66155ad018c8ca72333ed7519b..a3db2b69189dc4014376b54404fa6215daadef55 100644 (file)
@@ -453,7 +453,7 @@ class BC_TumbleTextBoxText : public BC_TextBox
 {
 public:
        BC_TumbleTextBoxText(BC_TumbleTextBox *popup, int64_t default_value, int x, int y);
-       BC_TumbleTextBoxText(BC_TumbleTextBox *popup, float default_value, int x, int y);
+       BC_TumbleTextBoxText(BC_TumbleTextBox *popup, float default_value, int x, int y, int precision);
        virtual ~BC_TumbleTextBoxText();
        int handle_event();
        int button_press_event();
index 4eba17c5813c7c800dbe96557bd8d9d226158d5c..de386bc7f574ec76c2aadb33e345b207fae03f37 100644 (file)
@@ -43,7 +43,7 @@ video_tools := blur decimate delayvideo denoisemjpeg denoisevideo downsample \
        unsharp videoscope wave zoomblur
 
 plugin_dirs += blending
-blending := chromakeyhsv chromakey diffkey
+blending := crikey chromakeyhsv chromakey diffkey
 
 plugin_dirs += tv_effects
 tv_effects := deinterlace-cv deinterlace ivtc liveaudio livevideo rgb601 \
index c2000234e952352f83d64ccf1ae43a1c5742c244..6b9e9395ae3a3aa5d4865ac436a209ee33974b59 100644 (file)
@@ -30,6 +30,7 @@ DIRS = \
        color3way \
        colorbalance \
        compressor \
+       crikey \
        crossfade \
        dcoffset \
        decimate \
diff --git a/cinelerra-5.1/plugins/crikey/Makefile b/cinelerra-5.1/plugins/crikey/Makefile
new file mode 100644 (file)
index 0000000..84def47
--- /dev/null
@@ -0,0 +1,13 @@
+include ../../plugin_defs
+
+OBJS := \
+       $(OBJDIR)/crikey.o \
+       $(OBJDIR)/crikeywindow.o
+
+PLUGIN = crikey
+
+include ../../plugin_config
+
+$(OBJDIR)/crikey.o: crikey.C
+$(OBJDIR)/crikeywindow.o: crikeywindow.C
+
diff --git a/cinelerra-5.1/plugins/crikey/crikey.C b/cinelerra-5.1/plugins/crikey/crikey.C
new file mode 100644 (file)
index 0000000..ccbb216
--- /dev/null
@@ -0,0 +1,651 @@
+/*
+ * CINELERRA
+ * Copyright (C) 1997-2015 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<stdio.h>
+#include<stdint.h>
+#include<math.h>
+#include<string.h>
+
+#include "arraylist.h"
+#include "bccmodels.h"
+#include "cicolors.h"
+#include "clip.h"
+#include "filexml.h"
+#include "crikey.h"
+#include "crikeywindow.h"
+#include "language.h"
+#include "vframe.h"
+
+// chroma interpolated key, crikey
+
+REGISTER_PLUGIN(CriKey)
+
+#if 0
+void crikey_pgm(const char *fn,VFrame *vfrm)
+{
+       FILE *fp = fopen(fn,"w");
+       int w = vfrm->get_w(), h = vfrm->get_h();
+       fprintf(fp,"P5\n%d %d\n255\n",w,h);
+       fwrite(vfrm->get_data(),w,h,fp);
+       fclose(fp);
+}
+#endif
+
+CriKeyConfig::CriKeyConfig()
+{
+       color = 0x000000;
+       threshold = 0.5f;
+       draw_mode = DRAW_ALPHA;
+       key_mode = KEY_SEARCH;
+       point_x = point_y = 0;
+       drag = 0;
+}
+
+int CriKeyConfig::equivalent(CriKeyConfig &that)
+{
+       return this->color != that.color ||
+               !EQUIV(this->threshold, that.threshold) ||
+               this->draw_mode != that.draw_mode ||
+               this->key_mode != that.key_mode ||
+               !EQUIV(this->point_x, that.point_x) ||
+               !EQUIV(this->point_y, that.point_y) ||
+               this->drag != that.drag ? 0 : 1;
+}
+
+void CriKeyConfig::copy_from(CriKeyConfig &that)
+{
+       this->color = that.color;
+       this->threshold = that.threshold;
+       this->draw_mode = that.draw_mode;
+       this->key_mode = that.key_mode;
+       this->point_x = that.point_x;
+       this->point_y = that.point_y;
+       this->drag = that.drag;
+}
+
+void CriKeyConfig::interpolate(CriKeyConfig &prev, CriKeyConfig &next,
+               long prev_frame, long next_frame, long current_frame)
+{
+       copy_from(prev);
+       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->threshold = prev.threshold * prev_scale + next.threshold * next_scale;
+       switch( prev.key_mode ) {
+       case KEY_POINT: {
+               this->point_x = prev.point_x * prev_scale + next.point_x * next_scale;
+               this->point_y = prev.point_y * prev_scale + next.point_y * next_scale;
+               break; }
+       case KEY_SEARCH:
+       case KEY_SEARCH_ALL: {
+               float prev_target[3];  set_target(0, prev.color, prev_target);
+               float next_target[3];  set_target(0, next.color, next_target);
+               float target[3];  // interpolates rgb components
+               for( int i=0; i<3; ++i )
+                       target[i] = prev_target[i] * prev_scale + next_target[i] * next_scale;
+               set_color(0, target, this->color);
+               break; }
+       }
+}
+
+void CriKeyConfig::limits()
+{
+       bclamp(threshold, 0.0f, 1.0f);
+       bclamp(draw_mode, 0, DRAW_MODES-1);
+       bclamp(key_mode,  0, KEY_MODES-1);
+}
+
+
+class FillRegion
+{
+       class segment { public: int y, lt, rt; };
+       ArrayList<segment> stack;
+
+       void push(int y, int lt, int rt) {
+               segment &seg = stack.append();
+               seg.y = y;  seg.lt = lt;  seg.rt = rt;
+       }
+       void pop(int &y, int &lt, int &rt) {
+               segment &seg = stack.last();
+               y = seg.y;  lt = seg.lt;  rt = seg.rt;
+               stack.remove();
+       }
+       int w, h, threshold;
+       uint8_t *data, *mask;
+       bool edge_pixel(uint8_t *dp) { return *dp; }
+
+public:
+       void fill(int x, int y);
+       void set_threshold(float v) { threshold = v; }
+
+       FillRegion(VFrame *d, VFrame *m);
+};
+
+FillRegion::FillRegion(VFrame *d, VFrame *m)
+{
+       threshold = 128;
+       w = d->get_w();
+       h = d->get_h();
+       data = d->get_data();
+       mask = m->get_data();
+}
+
+void FillRegion::fill(int x, int y)
+{
+       push(y, x, x);
+
+       do {
+               int ilt, irt, lt, rt;
+               pop(y, ilt, irt);
+               int ofs = y*w + ilt;
+               uint8_t *idp = data + ofs, *dp;
+               uint8_t *imp = mask + ofs, *mp;
+               for( int x=ilt; x<=irt; ++x,++imp,++idp ) {
+                       if( !*imp || edge_pixel(idp) ) continue;
+                       *imp = 0;
+                       lt = rt = x;
+                       dp = idp;  mp = imp;
+                       for( int i=lt; --i>=0; lt=i,*mp=0 )
+                               if( !*--mp || edge_pixel(--dp) ) break;
+                       dp = idp;  mp = imp;
+                       for( int i=rt; ++i< w; rt=i,*mp=0 )
+                               if( !*++mp || edge_pixel(++dp) ) break;
+                       if( y+1 <  h ) push(y+1, lt, rt);
+                       if( y-1 >= 0 ) push(y-1, lt, rt);
+               }
+       } while( stack.size() > 0 );
+}
+
+
+CriKey::CriKey(PluginServer *server)
+ : PluginVClient(server)
+{
+       engine = 0;
+       msk = 0;
+       dst = 0;
+       diff_pixel = 0;
+}
+
+CriKey::~CriKey()
+{
+       delete engine;
+       delete msk;
+       delete dst;
+}
+
+void CriKeyConfig::set_target(int is_yuv, int color, float *target)
+{
+       float r = ((color>>16) & 0xff) / 255.0f;
+       float g = ((color>> 8) & 0xff) / 255.0f;
+       float b = ((color>> 0) & 0xff) / 255.0f;
+       if( is_yuv ) {
+               float y, u, v;
+               YUV::rgb_to_yuv_f(r,g,b, y,u,v);
+               target[0] = y;
+               target[1] = u + 0.5f;
+               target[2] = v + 0.5f;
+       }
+       else {
+               target[0] = r;
+               target[1] = g;
+               target[2] = b;
+       }
+}
+void CriKeyConfig::set_color(int is_yuv, float *target, int &color)
+{
+       float r = target[0];
+       float g = target[1];
+       float b = target[2];
+       if( is_yuv ) {
+               float y = r, u = g-0.5f, v = b-0.5f;
+               YUV::yuv_to_rgb_f(y,u,v, r,g,b);
+       }
+       int ir = r >= 1 ? 0xff : r < 0 ? 0 : (int)(r * 256);
+       int ig = g >= 1 ? 0xff : g < 0 ? 0 : (int)(g * 256);
+       int ib = b >= 1 ? 0xff : b < 0 ? 0 : (int)(b * 256);
+       color = (ir << 16) | (ig << 8) | (ib << 0);
+}
+
+void CriKey::get_color(int x, int y)
+{
+       if( x < 0 || x >= w ) return;
+       if( y < 0 || y >= h ) return;
+       uint8_t **src_rows = src->get_rows();
+       uint8_t *sp = src_rows[y] + x*bpp;
+       if( is_float ) {
+               float *fp = (float *)sp;
+               for( int i=0; i<comp; ++i,++fp )
+                       target[i] = *fp;
+       }
+       else {
+               float scale = 1./255;
+               for( int i=0; i<comp; ++i,++sp )
+                       target[i] = *sp * scale;
+       }
+}
+
+float CriKey::diff_uint8(uint8_t *dp)
+{
+       float scale = 1./255., v = 0;
+       for( int i=0; i<comp; ++i,++dp )
+               v += fabs(*dp * scale - target[i]);
+       return v / comp;
+}
+float CriKey::diff_float(uint8_t *dp)
+{
+       float *fp = (float *)dp, v = 0;
+       for( int i=0; i<comp; ++i,++fp )
+               v += fabs(*fp - target[i]);
+       return v / comp;
+}
+
+void CriKey::min_key(int &ix, int &iy)
+{
+       float mv = 1;
+       uint8_t **src_rows = src->get_rows();
+       for( int y=0; y<h; ++y ) {
+               uint8_t *sp = src_rows[y];
+               for( int x=0; x<w; ++x,sp+=bpp ) {
+                       float v = (this->*diff_pixel)(sp);
+                       if( v >= mv ) continue;
+                       mv = v;  ix = x;  iy = y;
+               }
+       }
+}
+bool CriKey::find_key(int &ix, int &iy, float thr)
+{
+       uint8_t **src_rows = src->get_rows();
+       uint8_t **msk_rows = msk->get_rows();
+       int x = ix, y = iy;
+       for( ; y<h; ++y ) {
+               uint8_t *sp = src_rows[y] + x*bpp;
+               uint8_t *mp = msk_rows[y] + x;
+               for( ; x<w; ++x,++mp,sp+=bpp ) {
+                       if( !*mp ) continue;
+                       float v = (this->*diff_pixel)(sp);
+                       if( v < thr ) {
+                               ix = x;  iy = y;
+                               return true;
+                       }
+               }
+               x = 0;
+       }
+       return false;
+}
+
+const char* CriKey::plugin_title() { return _("CriKey"); }
+int CriKey::is_realtime() { return 1; }
+
+NEW_WINDOW_MACRO(CriKey, CriKeyWindow);
+LOAD_CONFIGURATION_MACRO(CriKey, CriKeyConfig)
+
+void CriKey::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("CRIKEY");
+       output.tag.set_property("COLOR", config.color);
+       output.tag.set_property("THRESHOLD", config.threshold);
+       output.tag.set_property("DRAW_MODE", config.draw_mode);
+       output.tag.set_property("KEY_MODE", config.key_mode);
+       output.tag.set_property("POINT_X", config.point_x);
+       output.tag.set_property("POINT_Y", config.point_y);
+       output.tag.set_property("DRAG", config.drag);
+       output.append_tag();
+       output.append_newline();
+       output.tag.set_title("/CRIKEY");
+       output.append_tag();
+       output.append_newline();
+       output.terminate_string();
+}
+
+void CriKey::read_data(KeyFrame *keyframe)
+{
+       FileXML input;
+       input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
+       int result = 0;
+
+       while( !(result=input.read_tag()) ) {
+               if(input.tag.title_is("CRIKEY")) {
+                       config.color = input.tag.get_property("COLOR", config.color);
+                       config.threshold = input.tag.get_property("THRESHOLD", config.threshold);
+                       config.draw_mode = input.tag.get_property("DRAW_MODE", config.draw_mode);
+                       config.key_mode = input.tag.get_property("KEY_MODE", config.key_mode);
+                       config.point_x = input.tag.get_property("POINT_X", config.point_x);
+                       config.point_y = input.tag.get_property("POINT_Y", config.point_y);
+                       config.drag = input.tag.get_property("DRAG", config.drag);
+                       config.limits();
+               }
+               else if(input.tag.title_is("/CRIKEY")) {
+                       result = 1;
+               }
+       }
+
+}
+
+void CriKey::update_gui()
+{
+       if( !thread ) return;
+       if( !load_configuration() ) return;
+       thread->window->lock_window("CriKey::update_gui");
+       CriKeyWindow *window = (CriKeyWindow*)thread->window;
+       window->update_gui();
+       window->flush();
+       thread->window->unlock_window();
+}
+
+void CriKey::draw_alpha(VFrame *msk)
+{
+       uint8_t **src_rows = src->get_rows();
+       uint8_t **msk_rows = msk->get_rows();
+       switch( color_model ) {
+       case BC_RGB_FLOAT:
+               for( int y=0; y<h; ++y ) {
+                       uint8_t *sp = src_rows[y], *mp = msk_rows[y];
+                       for( int x=0; x<w; ++x,++mp,sp+=bpp ) {
+                               if( *mp ) continue;
+                               float *px = (float *)sp;
+                               px[0] = px[1] = px[2] = 0;
+                       }
+               }
+               break;
+       case BC_RGBA_FLOAT:
+               for( int y=0; y<h; ++y ) {
+                       uint8_t *sp = src_rows[y], *mp = msk_rows[y];
+                       for( int x=0; x<w; ++x,++mp,sp+=bpp ) {
+                               if( *mp ) continue;
+                               float *px = (float *)sp;
+                               px[3] = 0;
+                       }
+               }
+               break;
+       case BC_RGB888:
+               for( int y=0; y<h; ++y ) {
+                       uint8_t *sp = src_rows[y], *mp = msk_rows[y];
+                       for( int x=0; x<w; ++x,++mp,sp+=bpp ) {
+                               if( *mp ) continue;
+                               uint8_t *px = sp;
+                               px[0] = px[1] = px[2] = 0;
+                       }
+               }
+               break;
+       case BC_YUV888:
+               for( int y=0; y<h; ++y ) {
+                       uint8_t *sp = src_rows[y], *mp = msk_rows[y];
+                       for( int x=0; x<w; ++x,++mp,sp+=bpp ) {
+                               if( *mp ) continue;
+                               uint8_t *px = sp;
+                               px[0] = 0;
+                               px[1] = px[2] = 0x80;
+                       }
+               }
+               break;
+       case BC_RGBA8888:
+       case BC_YUVA8888:
+               for( int y=0; y<h; ++y ) {
+                       uint8_t *sp = src_rows[y], *mp = msk_rows[y];
+                       for( int x=0; x<w; ++x,++mp,sp+=bpp ) {
+                               if( *mp ) continue;
+                               uint8_t *px = sp;
+                               px[3] = 0;
+                       }
+               }
+               break;
+       }
+}
+
+void CriKey::draw_mask(VFrame *msk)
+{
+       uint8_t **src_rows = src->get_rows();
+       uint8_t **msk_rows = msk->get_rows();
+       float scale = 1 / 255.0f;
+       switch( color_model ) {
+       case BC_RGB_FLOAT:
+               for( int y=0; y<h; ++y ) {
+                       uint8_t *sp = src_rows[y], *mp = msk_rows[y];
+                       for( int x=0; x<w; ++x,++mp,sp+=bpp ) {
+                               float a = *mp * scale;
+                               float *px = (float *)sp;
+                               px[0] = px[1] = px[2] = a;
+                       }
+               }
+               break;
+       case BC_RGBA_FLOAT:
+               for( int y=0; y<h; ++y ) {
+                       uint8_t *sp = src_rows[y], *mp = msk_rows[y];
+                       for( int x=0; x<w; ++x,++mp,sp+=bpp ) {
+                               float a = *mp * scale;
+                               float *px = (float *)sp;
+                               px[0] = px[1] = px[2] = a;
+                               px[3] = 1.0f;
+                       }
+               }
+               break;
+       case BC_RGB888:
+               for( int y=0; y<h; ++y ) {
+                       uint8_t *sp = src_rows[y], *mp = msk_rows[y];
+                       for( int x=0; x<w; ++x,++mp,sp+=bpp ) {
+                               float a = *mp * scale;
+                               uint8_t *px = sp;
+                               px[0] = px[1] = px[2] = a * 255;
+                       }
+               }
+               break;
+       case BC_RGBA8888:
+               for( int y=0; y<h; ++y ) {
+                       uint8_t *sp = src_rows[y], *mp = msk_rows[y];
+                       for( int x=0; x<w; ++x,++mp,sp+=bpp ) {
+                               float a = *mp * scale;
+                               uint8_t *px = sp;
+                               px[0] = px[1] = px[2] = a * 255;
+                               px[3] = 0xff;
+                       }
+               }
+               break;
+       case BC_YUV888:
+               for( int y=0; y<h; ++y ) {
+                       uint8_t *sp = src_rows[y], *mp = msk_rows[y];
+                       for( int x=0; x<w; ++x,++mp,sp+=bpp ) {
+                               float a = *mp * scale;
+                               uint8_t *px = sp;
+                               px[0] = a * 255;
+                               px[1] = px[2] = 0x80;
+                       }
+               }
+               break;
+       case BC_YUVA8888:
+               for( int y=0; y<h; ++y ) {
+                       uint8_t *sp = src_rows[y], *mp = msk_rows[y];
+                       for( int x=0; x<w; ++x,++mp,sp+=bpp ) {
+                               float a = *mp * scale;
+                               uint8_t *px = sp;
+                               px[0] = a * 255;
+                               px[1] = px[2] = 0x80;
+                               px[3] = 0xff;
+                       }
+               }
+               break;
+       }
+}
+
+int CriKey::process_buffer(VFrame *frame, int64_t start_position, double frame_rate)
+{
+       load_configuration();
+       src = frame;
+       w = src->get_w(), h = src->get_h();
+       color_model = src->get_color_model();
+       bpp = BC_CModels::calculate_pixelsize(color_model);
+       comp = BC_CModels::components(color_model);
+        if( comp > 3 ) comp = 3;
+       is_yuv = BC_CModels::is_yuv(color_model);
+       is_float = BC_CModels::is_float(color_model);
+       diff_pixel = is_float ? &CriKey::diff_float : &CriKey::diff_uint8;
+
+       read_frame(src, 0, start_position, frame_rate, 0);
+
+       switch( config.key_mode ) {
+       case KEY_SEARCH:
+       case KEY_SEARCH_ALL:
+               set_target(is_yuv, config.color, target);
+               break;
+       case KEY_POINT:
+               get_color(config.point_x, config.point_y);
+               break;
+       }
+
+        if( dst && ( dst->get_w() != w || src->get_h() != h ) ) {
+               delete dst;  dst = 0;
+        }
+        if( !dst )
+               dst = new VFrame(w, h, BC_A8);
+       memset(dst->get_data(), 0x00, dst->get_data_size());
+
+       if( !engine )
+               engine = new CriKeyEngine(this,
+                       PluginClient::get_project_smp() + 1,
+                       PluginClient::get_project_smp() + 1);
+       engine->process_packages();
+// copy fill btm/rt edges
+       int w1 = w-1, h1 = h-1;
+       uint8_t *dp = dst->get_data();
+       if( w1 > 0 ) for( int y=0; y<h1; ++y,dp+=w ) dp[w1] = dp[w1-1];
+       if( h1 > 0 ) for( int x=0; x<w; ++x ) dp[x] = dp[x-w];
+//crikey_pgm("/tmp/dst.pgm",dst);
+
+       if( config.draw_mode == DRAW_EDGE ) {
+               draw_mask(dst);
+               return 0;
+       }
+
+       if( msk && ( msk->get_w() != w || msk->get_h() != h ) ) {
+               delete msk;  msk = 0;
+       }
+       if( !msk )
+               msk = new VFrame(w, h, BC_A8);
+       memset(msk->get_data(), 0xff, msk->get_data_size());
+
+       FillRegion fill_region(dst, msk);
+       fill_region.set_threshold(config.threshold);
+
+       int x = 0, y = 0;
+       switch( config.key_mode ) {
+       case KEY_SEARCH:
+               min_key(x, y);
+               fill_region.fill(x, y);
+               break;
+       case KEY_SEARCH_ALL:
+               while( find_key(x, y, config.threshold) ) {
+                       fill_region.fill(x, y);
+                       ++x;
+               }
+               break;
+       case KEY_POINT:
+               x = config.point_x, y = config.point_y;
+               if( x >= 0 && x < w && y >= 0 && y < h )
+                       fill_region.fill(x, y);
+               break;
+       }
+//crikey_pgm("/tmp/msk.pgm",msk);
+
+       if( config.draw_mode == DRAW_MASK ) {
+               draw_mask(msk);
+               return 0;
+       }
+
+       draw_alpha(msk);
+       return 0;
+}
+
+
+void CriKeyEngine::init_packages()
+{
+       int y = 0, h1 = plugin->h-1;
+       for(int i = 0; i < get_total_packages(); ) {
+               CriKeyPackage *pkg = (CriKeyPackage*)get_package(i++);
+               pkg->y1 = y;
+               y = h1 * i / LoadServer::get_total_packages();
+               pkg->y2 = y;
+       }
+}
+
+LoadPackage* CriKeyEngine::new_package()
+{
+       return new CriKeyPackage();
+}
+
+LoadClient* CriKeyEngine::new_client()
+{
+       return new CriKeyUnit(this);
+}
+
+#define EDGE_MACRO(type, max, components, is_yuv) \
+{ \
+       uint8_t **src_rows = src->get_rows(); \
+       int comps = MIN(components, 3); \
+       float scale = 1.0f/max; \
+       for( int y=y1; y<y2; ++y ) { \
+               uint8_t *row0 = src_rows[y], *row1 = src_rows[y+1]; \
+               uint8_t *outp = dst_rows[y]; \
+               for( int v,x=x1; x<x2; *outp++=v,++x,row0+=bpp,row1+=bpp ) { \
+                       type *r0 = (type*)row0, *r1 = (type*)row1; \
+                       float a00 = 0, a01 = 0, a10 = 0, a11 = 0; \
+                       for( int i=0; i<comps; ++i,++r0,++r1 ) { \
+                               float t = target[i]; \
+                               a00 += fabs(t - r0[0]*scale); \
+                               a01 += fabs(t - r0[components]*scale); \
+                               a10 += fabs(t - r1[0]*scale); \
+                               a11 += fabs(t - r1[components]*scale); \
+                       } \
+                       v = 0; \
+                       float a = bmin(bmin(a00, a01), bmin(a10, a11)); \
+                       if( a < threshold ) continue; \
+                       float b = bmax(bmax(a00, a01), bmax(a10, a11)); \
+                       if( b <= threshold ) continue; \
+                       v = (b-a)*254 + 1; \
+               } \
+       } \
+} break
+
+
+void CriKeyUnit::process_package(LoadPackage *package)
+{
+       VFrame *src = server->plugin->src;
+       int bpp = server->plugin->bpp;
+       VFrame *dst = server->plugin->dst;
+       uint8_t **dst_rows = dst->get_rows();
+       float *target = server->plugin->target;
+       float threshold = server->plugin->config.threshold;
+       CriKeyPackage *pkg = (CriKeyPackage*)package;
+       int x1 = 0, x2 = server->plugin->w-1;
+       int y1 = pkg->y1, y2 = pkg->y2;
+
+       switch( src->get_color_model() ) {
+       case BC_RGB_FLOAT:  EDGE_MACRO(float, 1, 3, 0);
+       case BC_RGBA_FLOAT: EDGE_MACRO(float, 1, 4, 0);
+       case BC_RGB888:     EDGE_MACRO(unsigned char, 0xff, 3, 0);
+       case BC_YUV888:     EDGE_MACRO(unsigned char, 0xff, 3, 1);
+       case BC_RGBA8888:   EDGE_MACRO(unsigned char, 0xff, 4, 0);
+       case BC_YUVA8888:   EDGE_MACRO(unsigned char, 0xff, 4, 1);
+       }
+}
+
diff --git a/cinelerra-5.1/plugins/crikey/crikey.h b/cinelerra-5.1/plugins/crikey/crikey.h
new file mode 100644 (file)
index 0000000..3b8c1cf
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+ * CINELERRA
+ * Copyright (C) 1997-2014 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
+ *
+ */
+
+
+
+#ifndef EDGE_H
+#define EDGE_H
+
+#include "loadbalance.h"
+#include "pluginvclient.h"
+
+class CriKeyEngine;
+class CriKey;
+
+#define DRAW_ALPHA      0
+#define DRAW_EDGE       1
+#define DRAW_MASK       2
+#define DRAW_MODES      3
+
+#define KEY_SEARCH      0
+#define KEY_SEARCH_ALL  1
+#define KEY_POINT       2
+#define KEY_MODES       3
+
+class CriKeyConfig
+{
+public:
+       CriKeyConfig();
+
+       int equivalent(CriKeyConfig &that);
+       void copy_from(CriKeyConfig &that);
+       void interpolate(CriKeyConfig &prev, CriKeyConfig &next,
+               long prev_frame, long next_frame, long current_frame);
+       void limits();
+       static void set_target(int is_yuv, int color, float *target);
+       static void set_color(int is_yuv, float *target, int &color);
+
+       int color;
+       float threshold;
+       int draw_mode, key_mode;
+       float point_x, point_y;
+       int drag;
+};
+
+class CriKeyPackage : public LoadPackage
+{
+public:
+       CriKeyPackage() : LoadPackage() {}
+       int y1, y2;
+};
+
+class CriKeyEngine : public LoadServer
+{
+public:
+       CriKeyEngine(CriKey *plugin, int total_clients, int total_packages)
+        : LoadServer(total_clients, total_packages) { this->plugin = plugin; }
+       ~CriKeyEngine() {}
+
+       void init_packages();
+       LoadPackage* new_package();
+       LoadClient* new_client();
+
+       CriKey *plugin;
+};
+
+class CriKeyUnit : public LoadClient
+{
+public:
+       CriKeyUnit(CriKeyEngine *server)
+        : LoadClient(server) { this->server = server; }
+       ~CriKeyUnit() {}
+
+       float edge_detect(float *data, float max, int do_max);
+       void process_package(LoadPackage *package);
+       CriKeyEngine *server;
+};
+
+
+class CriKey : public PluginVClient
+{
+public:
+       CriKey(PluginServer *server);
+       ~CriKey();
+// required for all realtime plugins
+       PLUGIN_CLASS_MEMBERS2(CriKeyConfig)
+       int is_realtime();
+       void update_gui();
+       void save_data(KeyFrame *keyframe);
+       void read_data(KeyFrame *keyframe);
+       int process_buffer(VFrame *frame, int64_t start_position, double frame_rate);
+       void draw_alpha(VFrame *msk);
+       void draw_mask(VFrame *msk);
+       float diff_uint8(uint8_t *tp);
+       float diff_float(uint8_t *tp);
+       float (CriKey::*diff_pixel)(uint8_t *dp);
+       void min_key(int &ix, int &iy);
+       bool find_key(int &ix, int &iy, float threshold);
+       static void set_target(int is_yuv, int color, float *target) {
+               CriKeyConfig::set_target(is_yuv, color, target);
+       }
+       static void set_color(int is_yuv, float *target, int &color) {
+               CriKeyConfig::set_color(is_yuv, target, color);
+       }
+
+       CriKeyEngine *engine;
+       VFrame *src, *dst, *msk;
+       int w, h, color_model, bpp, comp, is_yuv, is_float;
+
+       void get_color(int x, int y);
+       float target[3];
+};
+
+#endif
diff --git a/cinelerra-5.1/plugins/crikey/crikeywindow.C b/cinelerra-5.1/plugins/crikey/crikeywindow.C
new file mode 100644 (file)
index 0000000..f8fcd1f
--- /dev/null
@@ -0,0 +1,360 @@
+/*
+ * CINELERRA
+ * Copyright (C) 2014 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 "automation.h"
+#include "bcdisplayinfo.h"
+#include "clip.h"
+#include "crikey.h"
+#include "crikeywindow.h"
+#include "cwindow.h"
+#include "cwindowgui.h"
+#include "edl.h"
+#include "edlsession.h"
+#include "language.h"
+#include "mwindow.h"
+#include "plugin.h"
+#include "pluginserver.h"
+#include "theme.h"
+#include "track.h"
+
+#define COLOR_W 50
+#define COLOR_H 30
+
+CriKeyNum::CriKeyNum(CriKeyWindow *gui, int x, int y, float &output)
+ : BC_TumbleTextBox(gui, output, -32767.0f, 32767.0f, x, y, 80)
+{
+       this->gui = gui;
+       this->output = &output;
+       set_increment(1);
+       set_precision(1);
+}
+
+CriKeyNum::~CriKeyNum()
+{
+}
+
+int CriKeyNum::handle_event()
+{
+       *output = atof(get_text());
+       gui->plugin->send_configure_change();
+       return 1;
+}
+
+int CriKeyDrawModeItem::handle_event()
+{
+       ((CriKeyDrawMode *)get_popup_menu())->update(id);
+       return 1;
+}
+CriKeyDrawMode::CriKeyDrawMode(CriKeyWindow *gui, int x, int y)
+ : BC_PopupMenu(x, y, 100, "", 1)
+{
+       this->gui = gui;
+       draw_modes[DRAW_ALPHA]     = _("Alpha");
+       draw_modes[DRAW_EDGE]      = _("Edge");
+       draw_modes[DRAW_MASK]      = _("Mask");
+       mode = -1;
+}
+void CriKeyDrawMode::create_objects()
+{
+       for( int i=0; i<DRAW_MODES; ++i )
+               add_item(new CriKeyDrawModeItem(draw_modes[i], i));
+       update(gui->plugin->config.draw_mode);
+}
+void CriKeyDrawMode::update(int mode)
+{
+       if( this->mode == mode ) return;
+       this->mode = mode;
+       set_text(draw_modes[mode]);
+       gui->plugin->config.draw_mode = mode;
+       gui->plugin->send_configure_change();
+}
+
+int CriKeyKeyModeItem::handle_event()
+{
+       ((CriKeyKeyMode *)get_popup_menu())->update(id);
+       return 1;
+}
+CriKeyKeyMode::CriKeyKeyMode(CriKeyWindow *gui, int x, int y)
+ : BC_PopupMenu(x, y, 100, "", 1)
+{
+       this->gui = gui;
+       key_modes[KEY_SEARCH]      = _("Search");
+       key_modes[KEY_SEARCH_ALL]  = _("Search all");
+       key_modes[KEY_POINT]       = _("Point");
+       this->mode = -1;
+}
+void CriKeyKeyMode::create_objects()
+{
+       for( int i=0; i<KEY_MODES; ++i )
+               add_item(new CriKeyKeyModeItem(key_modes[i], i));
+       update(gui->plugin->config.key_mode);
+}
+void CriKeyKeyMode::update(int mode)
+{
+       if( this->mode == mode ) return;
+       this->mode = mode;
+       set_text(key_modes[mode]);
+       gui->draw_key(mode);
+       gui->plugin->send_configure_change();
+}
+
+CriKeyColorButton::CriKeyColorButton(CriKeyWindow *gui, int x, int y)
+ : BC_GenericButton(x, y, _("Color"))
+{
+       this->gui = gui;
+}
+int CriKeyColorButton::handle_event()
+{
+       gui->start_color_thread();
+       return 1;
+}
+
+CriKeyColorPicker::CriKeyColorPicker(CriKeyColorButton *color_button)
+ : ColorPicker(0, _("Color"))
+{
+       this->color_button = color_button;
+}
+
+void CriKeyColorPicker::start(int color)
+{
+       start_window(this->color = color, 0, 1);
+}
+
+void CriKeyColorPicker::handle_done_event(int result)
+{
+       if( !result ) {
+               CriKeyWindow *gui = color_button->gui;
+               gui->lock_window("CriKeyColorPicker::handle_done_event");
+               gui->update_color(color);
+               gui->plugin->config.color = color;
+               gui->plugin->send_configure_change();
+               gui->unlock_window();
+       }
+}
+
+int CriKeyColorPicker::handle_new_color(int color, int alpha)
+{
+       CriKeyWindow *gui = color_button->gui;
+       gui->lock_window("CriKeyColorPicker::handle_new_color");
+       gui->update_color(this->color = color);
+       gui->flush();
+       gui->unlock_window();
+       return 1;
+}
+
+
+void CriKeyWindow::start_color_thread()
+{
+       unlock_window();
+       delete color_picker;
+       color_picker = new CriKeyColorPicker(color_button);
+       color_picker->start(plugin->config.color);
+       lock_window("CriKeyWindow::start_color_thread");
+}
+
+
+CriKeyWindow::CriKeyWindow(CriKey *plugin)
+ : PluginClientWindow(plugin, 320, 220, 320, 220, 0)
+{
+       this->plugin = plugin;
+       this->color_button = 0;
+       this->color_picker = 0;
+       this->title_x = 0;  this->point_x = 0;
+       this->title_y = 0;  this->point_y = 0;
+       this->dragging = 0; this->drag = 0;
+}
+
+CriKeyWindow::~CriKeyWindow()
+{
+       delete color_picker;
+}
+
+void CriKeyWindow::create_objects()
+{
+       int x = 10, y = 10;
+       int margin = plugin->get_theme()->widget_border;
+       BC_Title *title;
+       add_subwindow(title = new BC_Title(x, y, _("Threshold:")));
+       y += title->get_h() + margin;
+       add_subwindow(threshold = new CriKeyThreshold(this, x, y, get_w() - x * 2));
+       y += threshold->get_h() + margin;
+       add_subwindow(title = new BC_Title(x, y+5, _("Draw mode:")));
+       int x1 = x + title->get_w() + 10 + margin;
+       add_subwindow(draw_mode = new CriKeyDrawMode(this, x1, y));
+       draw_mode->create_objects();
+       y += draw_mode->get_h() + margin;
+       add_subwindow(title = new BC_Title(x, y+5, _("Key mode:")));
+       add_subwindow(key_mode = new CriKeyKeyMode(this, x1, y));
+       y += key_mode->get_h() + margin;
+       key_x = x + 10 + margin;  key_y = y + 10 + margin;
+       key_mode->create_objects();
+
+        if( plugin->config.drag )
+                grab(plugin->server->mwindow->cwindow->gui);
+       show_window(1);
+}
+
+int CriKeyWindow::grab_event(XEvent *event)
+{
+       if( key_mode->mode != KEY_POINT ) return 0;
+
+       switch( event->type ) {
+       case ButtonPress:
+               if( dragging ) return 0;
+               dragging = 1;
+               break;
+       case ButtonRelease:
+               if( !dragging ) return 0;
+               dragging = 0;
+               return 1;
+       case MotionNotify:
+               if( dragging ) break;
+       default:
+               return 0;
+       }
+       MWindow *mwindow = plugin->server->mwindow;
+       CWindowGUI *cwindow_gui = mwindow->cwindow->gui;
+       CWindowCanvas *canvas = cwindow_gui->canvas;
+       float cursor_x = canvas->get_canvas()->get_relative_cursor_x();
+       float cursor_y = canvas->get_canvas()->get_relative_cursor_y();
+       canvas->canvas_to_output(mwindow->edl, 0, cursor_x, cursor_y);
+       int64_t position = plugin->get_source_position();
+       float projector_x, projector_y, projector_z;
+       Track *track = plugin->server->plugin->track;
+       int track_w = track->track_w, track_h = track->track_h;
+       track->automation->get_projector(
+               &projector_x, &projector_y, &projector_z,
+               position, PLAY_FORWARD);
+       projector_x += mwindow->edl->session->output_w / 2;
+       projector_y += mwindow->edl->session->output_h / 2;
+       float output_x = (cursor_x - projector_x) / projector_z + track_w / 2;
+       float output_y = (cursor_y - projector_y) / projector_z + track_h / 2;
+       point_x->update((int64_t)(plugin->config.point_x = output_x));
+       point_y->update((int64_t)(plugin->config.point_y = output_y));
+       plugin->send_configure_change();
+       return 1;
+}
+
+void CriKeyWindow::done_event(int result)
+{
+        ungrab(client->server->mwindow->cwindow->gui);
+       if( color_picker ) color_picker->close_window();
+}
+
+void CriKeyWindow::draw_key(int mode)
+{
+       int margin = plugin->get_theme()->widget_border;
+       int x = key_x, y = key_y;
+       delete color_picker;  color_picker = 0;
+       delete color_button;  color_button = 0;
+       delete title_x;  title_x = 0;
+       delete point_x;  point_x = 0;
+       delete title_y;  title_y = 0;
+       delete point_y;  point_y = 0;
+       delete drag;     drag = 0;
+
+       clear_box(x,y, get_w()-x,get_h()-y);
+       flash(x,y, get_w()-x,get_h()-y);
+
+       switch( mode ) {
+       case KEY_SEARCH:
+       case KEY_SEARCH_ALL:
+               add_subwindow(color_button = new CriKeyColorButton(this, x, y));
+               x += color_button->get_w() + margin;
+               color_x = x;  color_y = y;
+               update_color(plugin->config.color);
+               break;
+       case KEY_POINT:
+               add_subwindow(title_x = new BC_Title(x, y, _("X:")));
+               int x1 = x + title_x->get_w() + margin, y1 = y;
+               point_x = new CriKeyNum(this, x1, y, plugin->config.point_x);
+               point_x->create_objects();
+               y += point_x->get_h() + margin;
+               add_subwindow(title_y = new BC_Title(x, y, _("Y:")));
+               point_y = new CriKeyNum(this, x1, y, plugin->config.point_y);
+               point_y->create_objects();
+               x1 += point_x->get_w() + margin;
+               add_subwindow(drag = new CriKeyDrag(this, x1, y1));
+               break;
+       }
+       plugin->config.key_mode = mode;
+       show_window(1);
+}
+
+void CriKeyWindow::update_color(int color)
+{
+       set_color(color);
+       draw_box(color_x, color_y, COLOR_W, COLOR_H);
+       set_color(BLACK);
+       draw_rectangle(color_x, color_y, COLOR_W, COLOR_H);
+       flash(color_x, color_y, COLOR_W, COLOR_H);
+}
+
+void CriKeyWindow::update_gui()
+{
+       threshold->update(plugin->config.threshold);
+       draw_mode->update(plugin->config.draw_mode);
+       key_mode->update(plugin->config.key_mode);
+       switch( plugin->config.key_mode ) {
+       case KEY_POINT:
+               point_x->update(plugin->config.point_x);
+               point_y->update(plugin->config.point_y);
+               break;
+       case KEY_SEARCH:
+       case KEY_SEARCH_ALL:
+               update_color(plugin->config.color);
+               break;
+       }
+}
+
+
+CriKeyThreshold::CriKeyThreshold(CriKeyWindow *gui, int x, int y, int w)
+ : BC_FSlider(x, y, 0, w, w, 0, 1, gui->plugin->config.threshold, 0)
+{
+       this->gui = gui;
+       set_precision(0.005);
+}
+
+int CriKeyThreshold::handle_event()
+{
+       gui->plugin->config.threshold = get_value();
+       gui->plugin->send_configure_change();
+       return 1;
+}
+
+
+CriKeyDrag::CriKeyDrag(CriKeyWindow *gui, int x, int y)
+ : BC_CheckBox(x, y, gui->plugin->config.drag, _("Drag"))
+{
+       this->gui = gui;
+}
+int CriKeyDrag::handle_event()
+{
+        int value = get_value();
+        gui->plugin->config.drag = value;
+       CWindowGUI *cwindow_gui = gui->plugin->server->mwindow->cwindow->gui;
+        if( value )
+                gui->grab(cwindow_gui);
+        else
+                gui->ungrab(cwindow_gui);
+        gui->plugin->send_configure_change();
+        return 1;
+}
+
diff --git a/cinelerra-5.1/plugins/crikey/crikeywindow.h b/cinelerra-5.1/plugins/crikey/crikeywindow.h
new file mode 100644 (file)
index 0000000..0814aba
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+ * CINELERRA
+ * Copyright (C) 2008-2015 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
+ *
+ */
+
+#ifndef __CRIKEYWINDOW_H__
+#define __CRIKEYWINDOW_H__
+
+#include "guicast.h"
+#include "colorpicker.h"
+
+class CriKey;
+class CriKeyWindow;
+class CriKeyNum;
+class CriKeyColorButton;
+class CriKeyColorPicker;
+class CriKeyDrawMode;
+class CriKeyDrawModeItem;
+class CriKeyKeyMode;
+class CriKeyKeyModeItem;
+class CriKeyThreshold;
+
+class CriKeyNum : public BC_TumbleTextBox
+{
+public:
+       CriKeyWindow *gui;
+       float *output;
+       int handle_event();
+
+       CriKeyNum(CriKeyWindow *gui, int x, int y, float &output);
+       ~CriKeyNum();
+};
+
+class CriKeyColorButton : public BC_GenericButton
+{
+public:
+       CriKeyColorButton(CriKeyWindow *gui, int x, int y);
+
+       int handle_event();
+       CriKeyWindow *gui;
+};
+
+class CriKeyColorPicker : public ColorPicker
+{
+public:
+       CriKeyColorPicker(CriKeyColorButton *color_button);
+
+       void start(int color);
+       int handle_new_color(int color, int alpha);
+       void handle_done_event(int result);
+
+       CriKeyColorButton *color_button;
+       int color;
+};
+
+class CriKeyDrawMode : public BC_PopupMenu
+{
+       const char *draw_modes[DRAW_MODES];
+public:
+       CriKeyDrawMode(CriKeyWindow *gui, int x, int y);
+
+       void create_objects();
+       void update(int mode);
+       CriKeyWindow *gui;
+       int mode;
+};
+class CriKeyDrawModeItem : public BC_MenuItem
+{
+public:
+       CriKeyDrawModeItem(const char *txt, int id)
+       : BC_MenuItem(txt) { this->id = id; }
+
+       int handle_event();
+       CriKeyWindow *gui;
+       int id;
+};
+
+class CriKeyKeyMode : public BC_PopupMenu
+{
+       const char *key_modes[KEY_MODES];
+public:
+       CriKeyKeyMode(CriKeyWindow *gui, int x, int y);
+
+       void create_objects();
+       void update(int mode);
+       CriKeyWindow *gui;
+       int mode;
+};
+class CriKeyKeyModeItem : public BC_MenuItem
+{
+public:
+       CriKeyKeyModeItem(const char *text, int id)
+       : BC_MenuItem(text) { this->id = id; }
+
+       int handle_event();
+       CriKeyWindow *gui;
+       int id;
+};
+
+class CriKeyThreshold : public BC_FSlider
+{
+public:
+       CriKeyThreshold(CriKeyWindow *gui, int x, int y, int w);
+       int handle_event();
+       CriKeyWindow *gui;
+};
+
+class CriKeyDrag : public BC_CheckBox
+{
+public:
+       CriKeyDrag(CriKeyWindow *gui, int x, int y);
+
+       int handle_event();
+       CriKeyWindow *gui;
+};
+
+class CriKeyWindow : public PluginClientWindow
+{
+public:
+       CriKeyWindow(CriKey *plugin);
+       ~CriKeyWindow();
+
+       void create_objects();
+       void draw_key(int mode);
+       void update_color(int color);
+       void update_gui();
+       void start_color_thread();
+       int grab_event(XEvent *event);
+       void done_event(int result);
+
+       CriKey *plugin;
+       CriKeyThreshold *threshold;
+       CriKeyDrawMode *draw_mode;
+       CriKeyKeyMode *key_mode;
+
+       CriKeyColorButton *color_button;
+       CriKeyColorPicker *color_picker;
+       int color_x, color_y, key_x, key_y;
+       BC_Title *title_x, *title_y;
+       CriKeyNum *point_x, *point_y;
+       int dragging;
+       CriKeyDrag *drag;
+};
+
+#endif
+
diff --git a/cinelerra-5.1/plugins/crikey/picon.png b/cinelerra-5.1/plugins/crikey/picon.png
new file mode 100644 (file)
index 0000000..364b154
Binary files /dev/null and b/cinelerra-5.1/plugins/crikey/picon.png differ
index 45172ae896a75882a194045989c389f76eaa2e09..b0c14ea9cea1b12d73192cbbc88de11213d15f15 100644 (file)
@@ -28,8 +28,6 @@
 #include "transportque.inc"
 #include <string.h>
 
-// Edge detection from the Gimp
-
 REGISTER_PLUGIN(Edge)
 
 EdgeConfig::EdgeConfig()
@@ -48,12 +46,8 @@ void EdgeConfig::copy_from(EdgeConfig &that)
        this->amount = that.amount;
 }
 
-void EdgeConfig::interpolate(
-       EdgeConfig &prev,
-       EdgeConfig &next,
-       long prev_frame,
-       long next_frame,
-       long current_frame)
+void EdgeConfig::interpolate( EdgeConfig &prev, EdgeConfig &next,
+               long prev_frame, long next_frame, long current_frame)
 {
        copy_from(next);
 }
@@ -68,13 +62,13 @@ Edge::Edge(PluginServer *server)
  : PluginVClient(server)
 {
        engine = 0;
-       temp = 0;
+       dst = 0;
 }
 
 Edge::~Edge()
 {
-       if(engine) delete engine;
-       if(temp) delete temp;
+       delete engine;
+       delete dst;
 }
 
 const char* Edge::plugin_title() { return _("Edge"); }
@@ -103,27 +97,16 @@ void Edge::save_data(KeyFrame *keyframe)
 void Edge::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("EDGE"))
-                       {
-                               config.amount = input.tag.get_property("AMOUNT", config.amount);
-                               config.limits();
-
-                       }
-                       else
-                       if(input.tag.title_is("/EDGE"))
-                       {
-                               result = 1;
-                       }
+
+       while( !(result=input.read_tag()) ) {
+               if(input.tag.title_is("EDGE")) {
+                       config.amount = input.tag.get_property("AMOUNT", config.amount);
+                       config.limits();
+               }
+               else if(input.tag.title_is("/EDGE")) {
+                       result = 1;
                }
        }
 
@@ -131,61 +114,41 @@ void Edge::read_data(KeyFrame *keyframe)
 
 void Edge::update_gui()
 {
-       if(thread)
-       {
-               if(load_configuration())
-               {
-                       thread->window->lock_window("Edge::update_gui");
-                       EdgeWindow *window = (EdgeWindow*)thread->window;
-                       window->flush();
-                       thread->window->unlock_window();
-               }
-       }
+       if( !thread ) return;
+       if( !load_configuration() ) return;
+       thread->window->lock_window("Edge::update_gui");
+       EdgeWindow *window = (EdgeWindow*)thread->window;
+       window->flush();
+       thread->window->unlock_window();
 }
 
-
-
-int Edge::process_buffer(VFrame *frame,
-       int64_t start_position,
-       double frame_rate)
+int Edge::process_buffer(VFrame *frame, int64_t start_position, double frame_rate)
 {
-
-//     int need_reconfigure =
        load_configuration();
-       int w = frame->get_w();
-       int h = frame->get_h();
-       int color_model = frame->get_color_model();
+       src = frame;
+       w = src->get_w(), h = src->get_h();
+       color_model = frame->get_color_model();
+       bpp = BC_CModels::calculate_pixelsize(color_model);
+
+       if( dst && (dst->get_w() != w || dst->get_h() != h ||
+           dst->get_color_model() != color_model ) ) {
+               delete dst;  dst = 0;
+       }
+       if( !dst )
+               dst = new VFrame(0, -1, w, h, color_model, -1);
 
-// initialize everything
-       if(!temp)
-       {
+       if( !engine )
                engine = new EdgeEngine(this,
                        PluginClient::get_project_smp() + 1,
                        PluginClient::get_project_smp() + 1);
 
-               temp = new VFrame(0,
-                       -1,
-                       w,
-                       h,
-                       color_model,
-                       -1);
-
-       }
-
-       read_frame(frame,
-               0,
-               start_position,
-               frame_rate,
-               0);
-       engine->process(temp, frame);
-       frame->copy_from(temp);
-
+       read_frame(frame, 0, start_position, frame_rate, 0);
+       engine->process_packages();
+       frame->copy_from(dst);
        return 0;
 }
 
 
-
-
 EdgePackage::EdgePackage()
  : LoadPackage()
 {
@@ -200,143 +163,60 @@ EdgeUnit::~EdgeUnit()
 {
 }
 
-
-float EdgeUnit::edge_detect(float *data, float max, int do_max)
-{
-       const float v_kernel[9] = { 0,  0,  0,
-                               0,  2, -2,
-                               0,  2, -2 };
-       const float h_kernel[9] = { 0,  0,  0,
-                               0, -2, -2,
-                               0,  2,  2 };
-       int i;
-       float v_grad, h_grad;
-       float amount = server->plugin->config.amount;
-
-       for (i = 0, v_grad = 0, h_grad = 0; i < 9; i++)
-    {
-       v_grad += v_kernel[i] * data[i];
-       h_grad += h_kernel[i] * data[i];
-    }
-
-       float result = sqrt (v_grad * v_grad * amount +
-                h_grad * h_grad * amount);
-       if(do_max)
-               CLAMP(result, 0, max);
-       return result;
-}
-
 #define EDGE_MACRO(type, max, components, is_yuv) \
 { \
-       type **input_rows = (type**)server->src->get_rows(); \
-       type **output_rows = (type**)server->dst->get_rows(); \
        int comps = MIN(components, 3); \
-       for(int y = pkg->y1; y < pkg->y2; y++) \
-       { \
-               for(int x = 0; x < w; x++) \
-               { \
-/* kernel is in bounds */ \
-                       if(y > 0 && x > 0 && y < h - 2 && x < w - 2) \
-                       { \
-                               for(int chan = 0; chan < comps; chan++) \
-                               { \
-/* load kernel */ \
-                                       for(int kernel_y = 0; kernel_y < 3; kernel_y++) \
-                                       { \
-                                               for(int kernel_x = 0; kernel_x < 3; kernel_x++) \
-                                               { \
-                                                       kernel[3 * kernel_y + kernel_x] = \
-                                                               (type)input_rows[y - 1 + kernel_y][(x - 1 + kernel_x) * components + chan]; \
- \
-                                                       if(is_yuv && chan > 0) \
-                                                       { \
-                                                               kernel[3 * kernel_y + kernel_x] -= 0x80; \
-                                                       } \
- \
-                                               } \
-                                       } \
-/* do the business */ \
-                                       output_rows[y][x * components + chan] = edge_detect(kernel, max, sizeof(type) < 4); \
-                                       if(is_yuv && chan > 0) \
-                                       { \
-                                               output_rows[y][x * components + chan] += 0x80; \
-                                       } \
- \
-                               } \
- \
-                               if(components == 4) output_rows[y][x * components + 3] = \
-                                       input_rows[y][x * components + 3]; \
+       float amounts = amount * amount / max; \
+       for( int y=y1; y<y2; ++y ) { \
+               uint8_t *row0 = input_rows[y], *row1 = input_rows[y+1]; \
+               uint8_t *outp = output_rows[y]; \
+               for( int x=x1; x<x2; ++x ) { \
+                       type *r0 = (type *)row0, *r1 = (type *)row1, *op = (type *)outp; \
+                       float h_grad = 0, v_grad = 0; \
+                       for( int i=0; i<comps; ++i,++r0,++r1 ) { \
+                               float dh = -r0[0] - r0[components] + r1[0] + r1[components]; \
+                               if( (dh*=dh) > h_grad ) h_grad = dh; \
+                               float dv =  r0[0] - r0[components] + r1[0] - r1[components]; \
+                               if( (dv*=dv) > v_grad ) v_grad = dv; \
                        } \
-                       else \
-                       { \
-                               for(int chan = 0; chan < comps; chan++) \
-                               { \
-/* load kernel */ \
-                                       for(int kernel_y = 0; kernel_y < 3; kernel_y++) \
-                                       { \
-                                               for(int kernel_x = 0; kernel_x < 3; kernel_x++) \
-                                               { \
-                                                       int in_y = y - 1 + kernel_y; \
-                                                       int in_x = x - 1 + kernel_x; \
-                                                       CLAMP(in_y, 0, h - 1); \
-                                                       CLAMP(in_x, 0, w - 1); \
-                                                       kernel[3 * kernel_y + kernel_x] = \
-                                                               (type)input_rows[in_y][in_x * components + chan]; \
-                                                       if(is_yuv && chan > 0) \
-                                                       { \
-                                                               kernel[3 * kernel_y + kernel_x] -= 0x80; \
-                                                       } \
-                                               } \
-                                       } \
-/* do the business */ \
-                                       output_rows[y][x * components + chan] = edge_detect(kernel, max, sizeof(type) < 4); \
-                                       if(is_yuv && chan > 0) \
-                                       { \
-                                               output_rows[y][x * components + chan] += 0x80; \
-                                       } \
-                               } \
-                               if(components == 4) output_rows[y][x * components + 3] = \
-                                       input_rows[y][x * components + 3]; \
+                       float v = (h_grad + v_grad) * amounts; \
+                       type t = v > max ? max : v; \
+                       if( is_yuv ) { \
+                               *op++ = t;  *op++ = 0x80;  *op++ = 0x80; \
                        } \
+                       else { \
+                               for( int i=0; i<comps; ++i ) *op++ = t; \
+                       } \
+                       if( components == 4 ) *op = *r0; \
+                       row0 += bpp;  row1 += bpp;  outp += bpp; \
                } \
        } \
-}
+} break
 
 
 void EdgeUnit::process_package(LoadPackage *package)
 {
+       VFrame *src = server->plugin->src;
+       uint8_t **input_rows = src->get_rows();
+       VFrame *dst = server->plugin->dst;
+       uint8_t **output_rows = dst->get_rows();
+       float amount = (float)server->plugin->config.amount;
        EdgePackage *pkg = (EdgePackage*)package;
-       int w = server->src->get_w();
-       int h = server->src->get_h();
-       float kernel[9];
-
-       switch(server->src->get_color_model())
-       {
-               case BC_RGB_FLOAT:
-                       EDGE_MACRO(float, 1, 3, 0);
-                       break;
-               case BC_RGBA_FLOAT:
-                       EDGE_MACRO(float, 1, 4, 0);
-                       break;
-               case BC_RGB888:
-                       EDGE_MACRO(unsigned char, 0xff, 3, 0);
-                       break;
-               case BC_YUV888:
-                       EDGE_MACRO(unsigned char, 0xff, 3, 1);
-                       break;
-               case BC_RGBA8888:
-                       EDGE_MACRO(unsigned char, 0xff, 4, 0);
-                       break;
-               case BC_YUVA8888:
-                       EDGE_MACRO(unsigned char, 0xff, 4, 1);
-                       break;
+       int x1 = 0, x2 = server->plugin->w-1, bpp = server->plugin->bpp;
+       int y1 = pkg->y1, y2 = pkg->y2;
+
+       switch( server->plugin->color_model ) {
+       case BC_RGB_FLOAT:  EDGE_MACRO(float, 1, 3, 0);
+       case BC_RGBA_FLOAT: EDGE_MACRO(float, 1, 4, 0);
+       case BC_RGB888:     EDGE_MACRO(unsigned char, 0xff, 3, 0);
+       case BC_YUV888:     EDGE_MACRO(unsigned char, 0xff, 3, 1);
+       case BC_RGBA8888:   EDGE_MACRO(unsigned char, 0xff, 4, 0);
+       case BC_YUVA8888:   EDGE_MACRO(unsigned char, 0xff, 4, 1);
        }
 }
 
 
-EdgeEngine::EdgeEngine(Edge *plugin,
-       int total_clients,
-       int total_packages)
+EdgeEngine::EdgeEngine(Edge *plugin, int total_clients, int total_packages)
  : LoadServer(total_clients, total_packages)
 {
        this->plugin = plugin;
@@ -349,22 +229,15 @@ EdgeEngine::~EdgeEngine()
 
 void EdgeEngine::init_packages()
 {
-       for(int i = 0; i < get_total_packages(); i++)
-       {
-               EdgePackage *pkg = (EdgePackage*)get_package(i);
-               pkg->y1 = plugin->get_input(0)->get_h() * i / LoadServer::get_total_packages();
-               pkg->y2 = plugin->get_input(0)->get_h() * (i + 1) / LoadServer::get_total_packages();
+       int y = 0, h1 = plugin->h-1;
+       for(int i = 0; i < get_total_packages(); ) {
+               EdgePackage *pkg = (EdgePackage*)get_package(i++);
+               pkg->y1 = y;
+               y = h1 * i / LoadServer::get_total_packages();
+               pkg->y2 = y;
        }
 }
 
-void EdgeEngine::process(VFrame *dst, VFrame *src)
-{
-       this->dst = dst;
-       this->src = src;
-       process_packages();
-}
-
-
 LoadClient* EdgeEngine::new_client()
 {
        return new EdgeUnit(this);
@@ -375,4 +248,3 @@ LoadPackage* EdgeEngine::new_package()
        return new EdgePackage;
 }
 
-
index 6211fda6b861aa22ed0e8427fb0f56221925c89d..5fddd98298ec23e396209a770adaf5ecc9e0dad5 100644 (file)
@@ -36,14 +36,10 @@ public:
 
        int equivalent(EdgeConfig &that);
        void copy_from(EdgeConfig &that);
-       void interpolate(EdgeConfig &prev,
-               EdgeConfig &next,
-               long prev_frame,
-               long next_frame,
-               long current_frame);
+       void interpolate(EdgeConfig &prev, EdgeConfig &next,
+               long prev_frame, long next_frame, long current_frame);
        void limits();
 
-
        int amount;
 };
 
@@ -51,8 +47,7 @@ class EdgePackage : public LoadPackage
 {
 public:
        EdgePackage();
-       int y1;
-       int y2;
+       int y1, y2;
 };
 
 class EdgeUnit : public LoadClient
@@ -75,11 +70,9 @@ public:
        ~EdgeEngine();
 
        void init_packages();
-       void process(VFrame *dst, VFrame *src);
 
        LoadClient* new_client();
        LoadPackage* new_package();
-       VFrame *src, *dst;
        Edge *plugin;
 };
 
@@ -100,12 +93,8 @@ public:
                double frame_rate);
 
        EdgeEngine *engine;
-       VFrame *temp;
+       VFrame *src, *dst;
+       int w, h, color_model, bpp;
 };
 
-
-
 #endif
-
-
-