new colorspace plugin
authorGood Guy <good1.2guy@gmail.com>
Sun, 9 Feb 2020 22:55:52 +0000 (15:55 -0700)
committerGood Guy <good1.2guy@gmail.com>
Sun, 9 Feb 2020 22:55:52 +0000 (15:55 -0700)
cinelerra-5.1/blds/bld_prepare.sh
cinelerra-5.1/expanders.txt
cinelerra-5.1/ffmpeg/plugin.opts
cinelerra-5.1/info/plugins.txt
cinelerra-5.1/plugin_defs
cinelerra-5.1/plugins/Makefile
cinelerra-5.1/plugins/colorspace/Makefile [new file with mode: 0644]
cinelerra-5.1/plugins/colorspace/colorspace.C [new file with mode: 0644]
cinelerra-5.1/plugins/colorspace/colorspace.h [new file with mode: 0644]
cinelerra-5.1/plugins/colorspace/colorspacewindow.C [new file with mode: 0644]
cinelerra-5.1/plugins/colorspace/colorspacewindow.h [new file with mode: 0644]

index 61e0950068cca20b950624f52daec53ca37df4dc..a34f123d9c4ae3c6387296ac16d4fc3ab41922ce 100755 (executable)
@@ -7,7 +7,7 @@ fi
 
 if [ $# -ne 1 ]; then
   echo "usage: $0 <os>"
-  echo "  <os> = [centos | suse | ubuntu]"
+  echo "  <os> = [centos | suse | ubuntu | fedora | mint | debian]"
 fi
 
 dir="$1"
@@ -56,7 +56,7 @@ case "$dir" in
     gettext-devel inkscape udftools autoconf automake numactl-devel \
     jbigkit-devel libvdpau-devel libva-devel gtk2-devel mesa-vdpau-drivers
   ;;
-"suse" | "leap")
+"suse" | "leap" | "tumbleweed")
   zypper -n install nasm gcc gcc-c++ zlib-devel texinfo libpng16-devel \
     freeglut-devel libXv-devel alsa-devel libbz2-devel ncurses-devel \
     libXinerama-devel freetype-devel libXft-devel giflib-devel ctags \
index 1138f800f9f882a3a26f0dac06af007587c99955..425026c7af67bea5f40bd20449db4087d37731b1 100644 (file)
@@ -5,6 +5,7 @@ Video Effects
                C41
                Color 3 Way
                Color Balance
+               ColorSpace
                Gamma
                Gradient
                HistEq
@@ -30,6 +31,7 @@ Video Effects
                F_colorkey
                F_colorlevels
                F_colormatrix
+               F_colorspace
                F_curves
                F_elbg
                F_eq
index 13dd40322141d3b801ccf12448a3ff0a7d297d18..bea77e27144ff4c797514cbc906a7c27a49f01f6 100644 (file)
@@ -83,7 +83,7 @@ colorchannelmixer
 colorkey
 colorlevels
 colormatrix src=bt601:dst=bt709
-#colorspace bt709
+colorspace iall=smpte170m:all=bt709
 compand
 compensationdelay
 #concat ###Operation not permitted
index 5012a25f0217a66bddd686d7687ed551c50c6294..2c7c62a89dd324afc2c355515287d666e2956f2a 100644 (file)
@@ -43,6 +43,8 @@ Color 3 Way:  Modify color of Shadows, Midtones, and Highlights
                as you specify.
 Color Balance: Modify RGB colors or white balance to compensate
                for errors in video such as low lighting.
+ColorSpace:    Tweak colors from one color space/range to another
+               space=BT601/BT709/BT2020  range=MPEG/JPEG
 CriKey:                Regionally based chroma key with interpolation;
                useful when you only want a specific zone defined.
                .
@@ -262,6 +264,7 @@ F_colorhold:        Turns a certain color range into gray when RGB.
 F_colorkey:    Turns a certain color into transparency when RGB.
 F_colorlevels: Adjusts the color levels.
 F_colormatrix: Converts color matrix.
+F_colorspace:  Converts color space/range.
 F_cover_rect:  Find and cover a user specified object.
 F_crop:                Crops the input video.
 F_cropdetect:  Auto-detect crop size.
index d73132066b9d71923a63ceb9c79c0069451afcc4..7658ede7867a77c28e0baae2673bc57ed60115e9 100644 (file)
@@ -35,6 +35,7 @@ video := \
        chromakeyhsv \
        color3way \
        colorbalance \
+       colorspace \
        crikey \
        cropp \
        crossfade \
index 22bc7dd659ed08d068ee29665ff4f9dde4a69676..e63682dca787dfb7aed490c7778f95e7123b745a 100644 (file)
@@ -42,6 +42,7 @@ DIRS = $(OPENCV_OBJS) \
        chromakeyhsv \
        color3way \
        colorbalance \
+       colorspace \
        compressor \
        compressormulti \
        crikey \
diff --git a/cinelerra-5.1/plugins/colorspace/Makefile b/cinelerra-5.1/plugins/colorspace/Makefile
new file mode 100644 (file)
index 0000000..a39df9a
--- /dev/null
@@ -0,0 +1,12 @@
+include ../../plugin_defs
+
+OBJS = $(OBJDIR)/colorspace.o  \
+       $(OBJDIR)/colorspacewindow.o
+
+PLUGIN = colorspace
+
+include ../../plugin_config
+
+$(OBJDIR)/colorspace.o: colorspace.C
+$(OBJDIR)/colorspacewindow.o: colorspacewindow.C
+
diff --git a/cinelerra-5.1/plugins/colorspace/colorspace.C b/cinelerra-5.1/plugins/colorspace/colorspace.C
new file mode 100644 (file)
index 0000000..01814ec
--- /dev/null
@@ -0,0 +1,628 @@
+
+/*
+ * CINELERRA
+ * Copyright (C) 2020 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 "bccmodels.h"
+#include "filexml.h"
+#include "language.h"
+#include "colorspace.h"
+#include "pluginserver.h"
+#include "preferences.h"
+
+#include <stdio.h>
+#include <string.h>
+
+
+REGISTER_PLUGIN(ColorSpaceMain)
+
+ColorSpaceConfig::ColorSpaceConfig()
+{
+       inverse = 0;
+       inp_colorspace = BC_COLORS_BT601;
+       inp_colorrange = BC_COLORS_JPEG;
+       out_colorspace = BC_COLORS_BT709;
+       out_colorrange = BC_COLORS_JPEG;
+}
+
+ColorSpaceMain::ColorSpaceMain(PluginServer *server)
+ : PluginVClient(server)
+{
+       inp_color_space = -1;
+       inp_color_range = -1;
+       out_color_space = -1;
+       out_color_range = -1;
+       xtable = 0;
+       engine = 0;
+}
+
+ColorSpaceMain::~ColorSpaceMain()
+{
+       delete xtable;
+       delete engine;
+}
+
+const char* ColorSpaceMain::plugin_title() { return N_("ColorSpace"); }
+int ColorSpaceMain::is_realtime() { return 1; }
+
+
+NEW_WINDOW_MACRO(ColorSpaceMain, ColorSpaceWindow)
+
+
+void ColorSpaceMain::update_gui()
+{
+       if( !thread ) return;
+       load_configuration();
+       ColorSpaceWindow *window = (ColorSpaceWindow *)thread->window;
+       window->lock_window();
+       window->update();
+       window->unlock_window();
+}
+
+
+int ColorSpaceMain::load_configuration()
+{
+       KeyFrame *prev_keyframe = get_prev_keyframe(get_source_position());
+       read_data(prev_keyframe);
+       return 1;
+}
+
+
+void ColorSpaceMain::save_data(KeyFrame *keyframe)
+{
+       FileXML output;
+
+// cause data to be stored directly in text
+       output.set_shared_output(keyframe->xbuf);
+       output.tag.set_title("COLORSPACE");
+       output.tag.set_property("INVERSE", config.inverse);
+       output.tag.set_property("INP_COLORSPACE", config.inp_colorspace);
+       output.tag.set_property("INP_COLORRANGE", config.inp_colorrange);
+       output.tag.set_property("OUT_COLORSPACE", config.out_colorspace);
+       output.tag.set_property("OUT_COLORRANGE", config.out_colorrange);
+       output.append_tag();
+       output.tag.set_title("/COLORSPACE");
+       output.append_tag();
+       output.append_newline();
+       output.terminate_string();
+}
+
+void ColorSpaceMain::read_data(KeyFrame *keyframe)
+{
+       FileXML input;
+       input.set_shared_input(keyframe->xbuf);
+
+       int result = 0;
+       while( !(result = input.read_tag()) ) {
+               if( input.tag.title_is("COLORSPACE") ) {
+                       config.inverse = input.tag.
+                               get_property("INVERSE", config.inverse);
+                       config.inp_colorspace = input.tag.
+                               get_property("INP_COLORSPACE", config.inp_colorspace);
+                       config.inp_colorrange = input.tag.
+                               get_property("INP_COLORRANGE", config.inp_colorrange);
+                       config.out_colorspace = input.tag.
+                               get_property("OUT_COLORSPACE", config.out_colorspace);
+                       config.out_colorrange = input.tag.
+                               get_property("OUT_COLORRANGE", config.out_colorrange);
+               }
+       }
+}
+
+XTable::XTable()
+{
+       this->typ = -1;
+       this->len = 0;
+       this->inv = 0;
+       memset(eqns, 0, sizeof(eqns));
+       memset(luts, 0, sizeof(luts));
+       for( int i=0; i<3; ++i ) {
+               imin[i] = omin[i] = 0;  imax[i] = omax[i] = 0xff;
+               izro[i] = ozro[i] = 0;  irng[i] = orng[i] = 0xff;
+               izrf[i] = ozrf[i] = 0;  omnf[i] = 0;  omxf[i] = 1;
+       }
+}
+
+XTable::~XTable()
+{
+       alloc_lut(0);
+}
+
+void XTable::create_table(lut_t **lut, int len, float *vars)
+{
+       int s = len == 0x100 ? (24-8) : (24-16);
+       for( int i=0; i<3; ++i ) {
+               lut_t imn = imin[i], imx = imax[i];
+               lut_t omn = omin[i], omx = omax[i];
+               double irng = imx+1 - imn;
+               double orng = omx+1 - omn;
+               double r = vars[i] * orng / irng;
+               lut_t izr = izro[i], v = r*(imn-izr);
+               lut_t *tbl = lut[i]; int k;
+               for( k=0; (k<<s)<imn; ++k ) tbl[k] = v;
+               for(  ; (v=k<<s)<imx; ++k ) tbl[k] = r*(v-izr);
+               for( v=r*(imx-izr); k<len; ++k ) tbl[k] = v;
+       }
+}
+
+void XTable::create_tables(int len)
+{
+       for( int i=0; i<3; ++i )
+               create_table(luts[i], len, eqns[i]);
+}
+
+
+void XTable::alloc_lut(int len)
+{
+       if( this->len == len ) return;
+       for( int i=0; i<3; ++i ) {
+               for( int j=0; j<3; ++j ) {
+                       delete [] luts[i][j];
+                       luts[i][j] = len>0 ? new lut_t[len] : 0;
+               }
+       }
+       this->len = len;
+}
+
+// these eqns were derived using python sympy
+// and the conversion forms in bccolors.h
+/*
+>>> from sympy import *
+>>> var('iKr,iKg,iKb,oKr,oKg,oKb,R,G,B,Y,U,V,Py,Pr,Pb')
+(iKr, iKg, iKb, oKr, oKg, oKb, R, G, B, Y, U, V, Py, Pr, Pb)
+>>>
+>>> Y  =   iKr * R  +  iKg * G  +  iKb * B
+>>> U  = - 0.5*iKr/(1-iKb)*R - 0.5*iKg/(1-iKb)*G + 0.5*B
+>>> V  =   0.5*R - 0.5*iKg/(1-iKr)*G - 0.5*iKb/(1-iKr)*B
+>>>
+>>> r = Y + V * 2*(1-oKr)
+>>> g = Y - V * 2*oKr*(1-oKr)/oKg - U * 2*oKb*(1-oKb)/oKg
+>>> b = Y                         + U * 2*(1-oKb)
+>>>
+>>> factor(r,(R,G,B))
+-1.0*(B*(1.0*iKb*iKr - 1.0*iKb*oKr) + G*(1.0*iKg*iKr - 1.0*iKg*oKr)
+ + R*(1.0*iKr**2 - 1.0*iKr*oKr + 1.0*oKr - 1.0))/(1 - iKr)
+>>> factor((1.0*iKr**2 - 1.0*iKr*oKr + 1.0*oKr - 1.0))
+1.0*(iKr - 1)*(iKr - oKr + 1)
+>>> factor((1.0*iKg*iKr - 1.0*iKg*oKr))
+1.0*iKg*(iKr - oKr)
+>>> factor((1.0*iKb*iKr - 1.0*iKb*oKr))
+1.0*iKb*(iKr - oKr)
+>>>
+>>> factor(g,(R,G,B))       strlen(result)=778
+results: eqn terms r*R + g*G + b*B, where r,g,b are the eqns coefs.
+with some renaming, this can be done symetrically with Y,U,V
+each coef eqn r,g,b can be reduced using factor([r,g,b])
+which creates eqns forms that simplify to the used calculation
+>>> factor(y,(Y,U,V))
+results in: y*Y + u*U + v*V which y,u,v are the eqns factors
+with same simplify and use
+*/
+
+//   yuv->(cs)->rgb->(cs)->yuv
+int XTable::init_yuv2yuv(double iKr, double iKb, double oKr, double oKb)
+{
+       double iKg = 1 - iKr - iKb;
+       double oKg = 1 - oKr - oKb;
+       double d = iKg;
+       Yy = iKg*(oKb + oKg + oKr) / d;
+       Uy = 2*(iKb - 1)*(iKb*oKg - oKb*iKg) / d;
+       Vy = -2*(iKr - 1)*(iKg*oKr - oKg*iKr) / d;
+       d = (iKg*(1 - oKb));
+       Yu = -0.5*iKg*(oKb + oKg + oKr - 1) / d;
+       Uu = -(iKb - 1)*(iKb*oKg - oKb*iKg + iKg) / d;
+       Vu = (iKr - 1)*(iKg*oKr - oKg*iKr) / d;
+       d = (iKg*(1 - oKr));
+       Yv = -0.5*iKg*(oKb + oKg + oKr - 1) / d;
+       Uv = -(iKb - 1)*(iKb*oKg - oKb*iKg) / d;
+       Vv = (iKr - 1)*(iKg*oKr - iKg - oKg*iKr) / d;
+       return yuv2yuv;
+}
+
+//   rgb->(cs)->yuv
+int XTable::init_rgb2yuv(double Kr, double Kb)
+{
+       double Kg = 1 - Kr - Kb;
+       Ry = Kr;
+       Gy = 1 - Kr - Kb;
+       By = Kb;
+       Ru = -0.5*Kr / (1 - Kb);
+       Gu = -0.5*Kg / (1 - Kb);
+       Bu =  0.5;
+       Rv =  0.5;
+       Gv = -0.5*Kg / (1 - Kr);
+       Bv = -0.5*Kb / (1 - Kr);
+       return rgb2yuv;
+}
+
+//   yuv->(cs)->rgb
+int XTable::init_yuv2rgb(double Kr, double Kb)
+{
+       double Kg = 1 - Kr - Kb;
+       Yr =  1.0;
+       Ur =  2*(1 - Kr);
+       Vr =  0.0;
+       Yg =  1.0;
+       Ug = -2*Kr*(1 - Kr) / Kg;
+       Vg = -2*Kb*(1 - Kb) / Kg;
+       Yb =  1.0;
+       Ub =  0.0;
+       Vb =  2*(1 - Kb);
+       return yuv2rgb;
+}
+
+//   rgb->(cs)->yuv->(cs)->rgb
+int XTable::init_rgb2rgb(double iKr, double iKb, double oKr, double oKb)
+{
+       double iKg = 1 - iKr - iKb;
+       double oKg = 1 - oKr - oKb;
+       double d = (1 - iKr);
+       Rr = -(iKr - 1)*(iKr - oKr + 1) / d;
+       Gr = -iKg*(iKr - oKr) / d;
+       Br = -iKb*(iKr - oKr) / d;
+       d = (oKg*(1 - iKb)*(1 - iKr));
+       Rg = (iKr - 1)*(iKb*oKg*iKr + iKb*oKr*oKr - iKb*oKr +
+               oKb*oKb*iKr - oKb*iKr - oKg*iKr - oKr*oKr + oKr) / d;
+       Gg = iKg*(iKb*oKg*iKr - iKb*oKg + iKb*oKr*oKr - iKb*oKr +
+               oKb*oKb*iKr - oKb*oKb - oKb*iKr + oKb - oKg*iKr +
+               oKg - oKr*oKr + oKr) / d;
+       Bg = (iKb - 1)*(iKb*oKg*iKr - iKb*oKg + iKb*oKr*oKr -
+                iKb*oKr + oKb*oKb*iKr - oKb*oKb - oKb*iKr + oKb) / d;
+       d = (1 - iKb);
+       Rb = -iKr*(iKb - oKb) / d;
+       Gb = -iKg*(iKb - oKb) / d;
+       Bb = -(iKb - 1)*(iKb - oKb + 1) / d;
+       return rgb2rgb;
+}
+
+void XTable::init(int len, int inv,
+               int inp_model, int inp_space, int inp_range,
+               int out_model, int out_space, int out_range)
+{
+       if( this->typ >= 0 && this->len == len && this->inv == inv &&
+           this->inp_model == inp_model && this->out_model == out_model &&
+           this->inp_space == inp_space && this->out_space == out_space &&
+           this->inp_range == inp_range && this->out_range == out_range )
+                return;
+
+       alloc_lut(len);
+       this->inv = inv;
+       this->inp_model = inp_model;  this->out_model = out_model;
+       this->inp_space = inp_space;  this->out_space = out_space;
+       this->inp_range = inp_range;  this->out_range = out_range;
+
+       double iKr = BT601_Kr, iKb = BT601_Kb;
+       double oKr = BT601_Kr, oKb = BT601_Kb;
+       int impg = 0, ompg = 0;
+       switch( inp_space ) {
+       default:
+       case BC_COLORS_BT601:  iKr = BT601_Kr;   iKb = BT601_Kb;   break;
+       case BC_COLORS_BT709:  iKr = BT709_Kr;   iKb = BT709_Kb;   break;
+       case BC_COLORS_BT2020: iKr = BT2020_Kr;  iKb = BT2020_Kb;  break;
+       }
+       switch( out_space ) {
+       default:
+       case BC_COLORS_BT601:  oKr = BT601_Kr;   oKb = BT601_Kb;   break;
+       case BC_COLORS_BT709:  oKr = BT709_Kr;   oKb = BT709_Kb;   break;
+       case BC_COLORS_BT2020: oKr = BT2020_Kr;  oKb = BT2020_Kb;  break;
+       }
+
+       int iyuv = BC_CModels::is_yuv(inp_model);
+       int oyuv = BC_CModels::is_yuv(out_model);
+       this->typ = iyuv ?
+               (oyuv ? init_yuv2yuv(iKr,iKb, oKr,oKb) :
+                       init_yuv2rgb(iKr,iKb)) :
+               (oyuv ? init_rgb2yuv(oKr,oKb) :
+                       init_rgb2rgb(iKr,iKb, oKr, oKb));
+
+       switch( inp_range ) {
+       default:
+       case BC_COLORS_JPEG: impg = 0;  break;
+       case BC_COLORS_MPEG: impg = 1;  break;
+       }
+       switch( out_range ) {
+       default:
+       case BC_COLORS_JPEG: ompg = 0;  break;
+       case BC_COLORS_MPEG: ompg = 1;  break;
+       }
+
+// mpg ? mpeg : jpeg/rgb
+       imin[0] = impg ? 0x100000 : 0x000000;
+       imin[1] = impg ? 0x100000 : 0x000000;
+       imin[2] = impg ? 0x100000 : 0x000000;
+       imax[0] = impg ? 0xebffff : 0xffffff;
+       imax[1] = impg ? 0xf0ffff : 0xffffff;
+       imax[2] = impg ? 0xf0ffff : 0xffffff;
+       omin[0] = ompg ? 0x100000 : 0x000000;
+       omin[1] = ompg ? 0x100000 : 0x000000;
+       omin[2] = ompg ? 0x100000 : 0x000000;
+       omax[0] = ompg ? 0xebffff : 0xffffff;
+       omax[1] = ompg ? 0xf0ffff : 0xffffff;
+       omax[2] = ompg ? 0xf0ffff : 0xffffff;
+       izro[0] = imin[0];
+       izro[1] = iyuv ? 0x800000 : imin[1];
+       izro[2] = iyuv ? 0x800000 : imin[2];
+       ozro[0] = omin[0];
+       ozro[1] = oyuv ? 0x800000 : omin[1];
+       ozro[2] = oyuv ? 0x800000 : omin[2];
+       for( int i=0; i<3; ++i ) {
+               irng[i] = imax[i]+1 - imin[i];
+               orng[i] = omax[i]+1 - omin[i];
+               int sz = 0x1000000;
+               izrf[i] = (float)izro[i] / sz;
+               ozrf[i] = (float)ozro[i] / sz;
+               omnf[i] = (float)omin[i] / sz;
+               omxf[i] = (float)(omax[i]+1) / sz;
+       }
+       if( inv )
+               inverse();
+       if( len > 0 )
+               create_tables(len);
+// prescale eqns for opengl
+       for( int i=0; i<3; ++i ) {
+               float *eqn = eqns[i];
+               float s = (float)orng[i] / irng[i];
+               for( int j=0; j<3; ++j ) eqn[j] *= s;
+       }
+#if 0
+printf("XTable::init len=%06x\n"
+ " impg=%d, ompg=%d, iyuv=%d, oyuv=%d\n"
+ " imin=%06x,%06x,%06x, imax=%06x,%06x,%06x\n"
+ " omin=%06x,%06x,%06x, omax=%06x,%06x,%06x\n"
+ " izro=%06x,%06x,%06x, ozro=%06x,%06x,%06x\n"
+ " izrf=%0.3f,%0.3f,%0.3f, ozrf=%0.3f,%0.3f,%0.3f\n"
+ " omnf=%0.3f,%0.3f,%0.3f, omxf=%0.3f,%0.3f,%0.3f\n"
+ " eqns= %6.3f,%6.3f,%6.3f\n"
+ "       %6.3f,%6.3f,%6.3f\n"
+ "       %6.3f,%6.3f,%6.3f\n",
+ len, impg, ompg, iyuv, oyuv,
+ imin[0], imin[1], imin[2], imax[0], imax[1], imax[2],
+ omin[0], omin[1], omin[2], omax[0], omax[1], omax[2],
+ izro[0], izro[1], izro[2], ozro[0], ozro[1], ozro[2],
+ izrf[0], izrf[0], izrf[0], ozrf[0], ozrf[0], ozrf[0],
+ omnf[0], omnf[0], omnf[0], omxf[0], omxf[0], omxf[0],
+ eqns[0][0], eqns[0][1], eqns[0][2],
+ eqns[1][0], eqns[1][1], eqns[1][2],
+ eqns[2][0], eqns[2][1], eqns[2][2]);
+#endif
+}
+
+/*
+out = (inp-izro)*eqns + ozro
+inverse: invert(eqns), swap(inp,out), swap(izro,ozro)
+inp = (out-ozro)*iqns + izro
+*/
+int XTable::inverse()
+{
+// [[ a b c ],
+//  [ d e f ],
+//  [ g h i ]] inverse =
+// 1/(a(ei-fh) + b(fg-di) + c(dh-eg)) *
+//    [[ ei-fh, ch-bi, bf-ce ],
+//     [ fg-di, ai-cg, cd-af ],
+//     [ dh-eg, bg-ah, ae-bd ]]
+       float a = eqns[0][0], b = eqns[0][1], c = eqns[0][2];
+       float d = eqns[1][0], e = eqns[1][1], f = eqns[1][2];
+       float g = eqns[2][0], h = eqns[2][1], i = eqns[2][2];
+       float s = a*(e*i-f*h) + b*(f*g-d*i) + c*(d*h-e*g);
+       float eps = 1e-4;
+       if( s < eps ) return 1;
+       s = 1.f / s;
+       eqns[0][0] = s*(e*i-f*h);  eqns[0][1] = s*(c*h-b*i);  eqns[0][2] = s*(b*f-c*e);
+       eqns[1][0] = s*(f*g-d*i);  eqns[1][1] = s*(a*i-c*g);  eqns[1][2] = s*(c*d-a*f);
+       eqns[2][0] = s*(d*h-e*g);  eqns[2][1] = s*(b*g-a*h);  eqns[2][2] = s*(a*e-b*d);
+       for( int v,i=0; i<3; ++i ) {
+               v = imin[i];  imin[i] = omin[i];  omin[i] = v;
+               v = imax[i];  imax[i] = omax[i];  omax[i] = v;
+               v = irng[i];  irng[i] = orng[i];  orng[i] = v;
+               v = izro[i];  izro[i] = ozro[i];  ozro[i] = v;
+               int sz = 0x1000000;
+               omnf[i] = (float)omin[i] / sz;
+               omxf[i] = (float)(omax[i]+1) / sz;
+               izrf[i] = (float)izro[i] / sz;
+               ozrf[i] = (float)ozro[i] / sz;
+       }
+       return 0;
+}
+
+
+#define PROCESS_LUTS(type, comps) { \
+       for( int y=row1; y<row2; ++y ) { \
+               type *ip = (type*)irows[y]; \
+               type *op = (type*)orows[y]; \
+               for( int x=0; x<w; ++x ) { \
+                       for( int i=0; i<3; ++i ) { \
+                               lut_t omn = omin[i], omx = omax[i]; \
+                               lut_t **lut = luts[i], v = ozro[i]; \
+                               for( int j=0; j<3; ++j ) v += lut[j][ip[j]]; \
+                               op[i] = (v<omn ? omn : v>omx ? omx : v) >> s; \
+                       } \
+                       ip += comps;  op += comps; \
+               } \
+       } \
+}
+
+#define PROCESS_EQNS(type, comps) { \
+       for( int y=row1; y<row2; ++y ) { \
+               type *ip = (type*)irows[y]; \
+               type *op = (type*)orows[y]; \
+               for( int x=0; x<w; ++x ) { \
+                       for( int i=0; i<3; ++i ) { \
+                               float omn = omnf[i], omx = omxf[i]; \
+                               type v = ozrf[i];  float *eqn = eqns[i]; \
+                               for( int j=0; j<3; ++j ) v += eqn[j]*(ip[j] - izrf[j]); \
+                               op[i] = v<omn ? omn : v>omx ? omx : v; \
+                       } \
+                       ip += comps;  op += comps; \
+               } \
+       } \
+}
+
+void XTable::process(VFrame *inp, VFrame *out, int row1, int row2)
+{
+       int s = len == 0x100 ? (24-8) : (24-16);
+       int w = inp->get_w(), comps = 3;
+       uint8_t **irows = inp->get_rows();
+       uint8_t **orows = out->get_rows();
+
+       switch( inp->get_color_model() ) {
+       case BC_RGBA8888:
+       case BC_YUVA8888:
+               comps = 4;
+       case BC_RGB888:
+       case BC_YUV888:
+               PROCESS_LUTS(uint8_t, comps);
+               break;
+       case BC_RGBA16161616:
+       case BC_YUVA16161616:
+               comps = 4;
+       case BC_RGB161616:
+       case BC_YUV161616:
+               PROCESS_LUTS(uint16_t, comps);
+               break;
+       case BC_RGBA_FLOAT:
+               comps = 4;
+       case BC_RGB_FLOAT:
+               PROCESS_EQNS(float, comps);
+               break;
+       }
+}
+
+int ColorSpaceMain::process_realtime(VFrame *input, VFrame *output)
+{
+       load_configuration();
+//printf(" inv=%d, ispc=%d, irng=%d, ospc=%d, orng=%d\n", config.inverse,
+// config.inp_colorspace, config.inp_colorrange,
+// config.out_colorspace, config.out_colorrange);
+       if( input->get_color_model() == output->get_color_model() &&
+           config.inp_colorspace == config.out_colorspace &&
+           config.inp_colorrange == config.out_colorrange )
+               return 0;
+
+       int color_model = input->get_color_model();
+// opengl < 0, float == 0, tables > 0
+       int len = get_use_opengl() ? -1 :
+               BC_CModels::is_float(color_model) ? 0 :
+               BC_CModels::calculate_pixelsize(color_model)/
+                   BC_CModels::components(color_model) == 2 ?
+                        0x10000 : 0x100;
+       if( !engine && len >= 0 ) {
+               int cpus = output->get_w()*output->get_h() / 0x80000 + 1;
+               int max_cpus = BC_Resources::machine_cpus / 2;
+               if( cpus > max_cpus ) cpus = max_cpus;
+               if( cpus < 1 ) cpus = 1;
+               engine = new ColorSpaceEngine(this, cpus);
+       }
+
+       if( !xtable ) xtable = new XTable();
+       xtable->init(len, config.inverse,
+               color_model, config.inp_colorspace, config.inp_colorrange,
+               color_model, config.out_colorspace, config.out_colorrange);
+       inp = input;  out = output;
+       if( get_use_opengl() )
+               run_opengl();
+       else
+               engine->process_packages();
+       return 0;
+}
+
+
+void ColorSpaceUnit::process_package(LoadPackage *package)
+{
+       ColorSpacePackage *pkg = (ColorSpacePackage*)package;
+       plugin->xtable->process(plugin->inp, plugin->out, pkg->row1, pkg->row2);
+}
+
+ColorSpaceEngine::ColorSpaceEngine(ColorSpaceMain *plugin, int cpus)
+// : LoadServer(1, 1)
+ : LoadServer(cpus, cpus)
+{
+       this->plugin = plugin;
+}
+
+void ColorSpaceEngine::init_packages()
+{
+       int row = 0, h = plugin->inp->get_h();
+       for( int i=0, n=get_total_packages(); i<n; ) {
+               ColorSpacePackage *pkg = (ColorSpacePackage*)get_package(i);
+               pkg->row1 = row;
+               pkg->row2 = row = (++i * h) / n;
+       }
+}
+
+LoadClient* ColorSpaceEngine::new_client()
+{
+       return new ColorSpaceUnit(plugin, this);
+}
+
+LoadPackage* ColorSpaceEngine::new_package()
+{
+       return new ColorSpacePackage();
+}
+
+ColorSpacePackage::ColorSpacePackage()
+ : LoadPackage()
+{
+}
+
+ColorSpaceUnit::ColorSpaceUnit(ColorSpaceMain *plugin, ColorSpaceEngine *engine)
+ : LoadClient(engine)
+{
+        this->plugin = plugin;
+}
+
+
+
+int ColorSpaceMain::handle_opengl()
+{
+#ifdef HAVE_GL
+       static const char *colorspace_frag =
+               "uniform sampler2D tex;\n"
+               "uniform mat3 eqns;\n"
+               "uniform vec3 izrf, ozrf;\n"
+               "uniform vec3 omnf, omxf;\n"
+               "void main()\n"
+               "{\n"
+               "       gl_FragColor = texture2D(tex, gl_TexCoord[0].st);\n"
+               "       gl_FragColor.rgb = clamp((gl_FragColor.rgb-izrf)*eqns + ozrf, omnf, omxf);\n"
+               "}\n";
+       inp->to_texture();
+       inp->enable_opengl();
+       inp->bind_texture(0);
+
+       unsigned int frag_shader = VFrame::make_shader(0, colorspace_frag, 0);
+       if( xtable && frag_shader > 0 ) {
+               glUseProgram(frag_shader);
+               glUniform1i(glGetUniformLocation(frag_shader, "tex"), 0);
+               glUniformMatrix3fv(glGetUniformLocation(frag_shader, "eqns"), 1, false, xtable->eqns[0]);
+               glUniform3fv(glGetUniformLocation(frag_shader, "izrf"), 1, xtable->izrf);
+               glUniform3fv(glGetUniformLocation(frag_shader, "ozrf"), 1, xtable->ozrf);
+               glUniform3fv(glGetUniformLocation(frag_shader, "omnf"), 1, xtable->omnf);
+               glUniform3fv(glGetUniformLocation(frag_shader, "omxf"), 1, xtable->omxf);
+       }
+
+       out->enable_opengl();
+       VFrame::init_screen(out->get_w(), out->get_h());
+       out->draw_texture();
+       glUseProgram(0);
+       out->set_opengl_state(VFrame::SCREEN);
+#endif
+       return 0;
+}
+
diff --git a/cinelerra-5.1/plugins/colorspace/colorspace.h b/cinelerra-5.1/plugins/colorspace/colorspace.h
new file mode 100644 (file)
index 0000000..a8fcb05
--- /dev/null
@@ -0,0 +1,156 @@
+
+/*
+ * 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
+ *
+ */
+
+#ifndef __COLORSPACE_H__
+#define __COLORSPACE_H__
+
+class ColorSpaceMain;
+
+#include "bchash.h"
+#include "mutex.h"
+#include "loadbalance.h"
+#include "pluginvclient.h"
+#include "colorspacewindow.h"
+#include <sys/types.h>
+
+class ColorSpaceConfig;
+class ColorSpaceMain;
+class ColorSpacePackage;
+class ColorSpaceUnit;
+class ColorSpaceEngine;
+
+class XTable {
+public:
+       typedef int lut_t;
+       enum lut_typ { yuv2yuv, rgb2yuv, yuv2rgb, rgb2rgb };
+
+       XTable();
+       ~XTable();
+       int init_yuv2yuv(double iKr, double iKb, double oKr, double oKb);
+       int init_rgb2yuv(double Kr, double Kb);
+       int init_yuv2rgb(double Kr, double Kb);
+       int init_rgb2rgb(double iKr, double iKb, double oKr, double oKb);
+
+       void init(int len, int inv,
+               int inp_model, int inp_space, int inp_range,
+               int out_model, int out_space, int out_range);
+       void alloc_lut(int len);
+       void create_table(lut_t **lut, int len, float *vars);
+       void create_tables(int len);
+       int inverse();
+       void process(VFrame *inp, VFrame *out, int row1, int row2);
+
+       int typ, len, inv;
+       int inp_model, inp_space, inp_range;
+       int out_model, out_space, out_range;
+
+       lut_t imin[3], omin[3], imax[3], omax[3];
+       lut_t izro[3], ozro[3], irng[3], orng[3];
+       float izrf[3], ozrf[3], omnf[3], omxf[3];
+
+       union {
+               struct {
+                       float Yy, Uy, Vy;
+                       float Yu, Uu, Vu;
+                       float Yv, Uv, Vv;
+               };
+               struct {
+                       float Ry, Gy, By;
+                       float Ru, Gu, Bu;
+                       float Rv, Gv, Bv;
+               };
+               struct {
+                       float Yr, Ur, Vr;
+                       float Yg, Ug, Vg;
+                       float Yb, Ub, Vb;
+               };
+               struct {
+                       float Rr, Gr, Br;
+                       float Rg, Gg, Bg;
+                       float Rb, Gb, Bb;
+               };
+               float eqns[3][3];
+       };
+       lut_t *luts[3][3];
+};
+
+
+class ColorSpaceConfig
+{
+public:
+       ColorSpaceConfig();
+       int inverse;
+       int inp_colorspace, inp_colorrange;
+       int out_colorspace, out_colorrange;
+};
+
+class ColorSpacePackage : public LoadPackage
+{
+public:
+       ColorSpacePackage();
+       int row1, row2;
+};
+
+class ColorSpaceUnit : public LoadClient
+{
+public:
+       ColorSpaceUnit(ColorSpaceMain *plugin, ColorSpaceEngine *engine);
+       void process_package(LoadPackage *package);
+       ColorSpaceEngine *engine;
+       ColorSpaceMain *plugin;
+
+};
+
+class ColorSpaceEngine : public LoadServer
+{
+public:
+       ColorSpaceEngine(ColorSpaceMain *plugin, int cpus);
+       void init_packages();
+       LoadClient* new_client();
+       LoadPackage* new_package();
+       ColorSpaceMain *plugin;
+};
+
+
+class ColorSpaceMain : public PluginVClient
+{
+public:
+       ColorSpaceMain(PluginServer *server);
+       ~ColorSpaceMain();
+
+       PLUGIN_CLASS_MEMBERS(ColorSpaceConfig);
+       int process_realtime(VFrame *input, VFrame *output);
+       int is_realtime();
+       void update_gui();
+       void save_data(KeyFrame *keyframe);
+       void read_data(KeyFrame *keyframe);
+       int handle_opengl();
+       int create_luts();
+
+       int inp_color_space, inp_color_range;
+       int out_color_space, out_color_range;
+       VFrame *inp, *out;
+       XTable *xtable;
+       ColorSpaceEngine *engine;
+};
+
+
+#endif
diff --git a/cinelerra-5.1/plugins/colorspace/colorspacewindow.C b/cinelerra-5.1/plugins/colorspace/colorspacewindow.C
new file mode 100644 (file)
index 0000000..f9198f2
--- /dev/null
@@ -0,0 +1,193 @@
+
+/*
+ * 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 "bcdisplayinfo.h"
+#include "language.h"
+#include "colorspacewindow.h"
+
+
+const char *ColorSpaceSpace::color_space[] = {
+       N_("BT601"), // COLOR_SPACE_BT601
+       N_("BT709"), // COLOR_SPACE_BT709
+       N_("BT2020"), // COLOR_SPACE_BT2020
+};
+
+ColorSpaceSpace::ColorSpaceSpace(ColorSpaceWindow *gui, int x, int y, int *value)
+ : BC_PopupMenu(x, y, xS(120), _(color_space[*value]), 1)
+{
+       this->gui = gui;
+       this->value = value;
+}
+ColorSpaceSpace::~ColorSpaceSpace()
+{
+}
+
+void ColorSpaceSpace::create_objects()
+{
+       for( int id=0,nid=sizeof(color_space)/sizeof(color_space[0]); id<nid; ++id )
+               add_item(new ColorSpaceSpaceItem(this, _(color_space[id]), id));
+       update();
+}
+
+void ColorSpaceSpace::update()
+{
+       set_text(_(color_space[*value]));
+}
+
+int ColorSpaceSpace::handle_event()
+{
+       update();
+       gui->plugin->send_configure_change();
+       return 1;
+}
+
+ColorSpaceSpaceItem::ColorSpaceSpaceItem(ColorSpaceSpace *popup, const char *text, int id)
+ : BC_MenuItem(text)
+{
+       this->popup = popup;
+       this->id = id;
+}
+
+int ColorSpaceSpaceItem::handle_event()
+{
+       *popup->value = id;
+       return popup->handle_event();
+}
+
+
+const char *ColorSpaceRange::color_range[] = {
+       N_("JPEG"), // COLOR_RANGE_JPEG
+       N_("MPEG"), // COLOR_RANGE_MPEG
+};
+
+ColorSpaceRange::ColorSpaceRange(ColorSpaceWindow *gui, int x, int y, int *value)
+ : BC_PopupMenu(x, y, xS(100), _(color_range[*value]), 1)
+{
+       this->gui = gui;
+       this->value = value;
+}
+ColorSpaceRange::~ColorSpaceRange()
+{
+}
+
+void ColorSpaceRange::create_objects()
+{
+       for( int id=0,nid=sizeof(color_range)/sizeof(color_range[0]); id<nid; ++id )
+               add_item(new ColorSpaceRangeItem(this, _(color_range[id]), id));
+       update();
+}
+
+void ColorSpaceRange::update()
+{
+       set_text(color_range[*value]);
+}
+
+int ColorSpaceRange::handle_event()
+{
+       update();
+       gui->plugin->send_configure_change();
+       return 1;
+}
+
+ColorSpaceRangeItem::ColorSpaceRangeItem(ColorSpaceRange *popup, const char *text, int id)
+ : BC_MenuItem(text)
+{
+       this->popup = popup;
+       this->id = id;
+}
+
+int ColorSpaceRangeItem::handle_event()
+{
+       *popup->value = id;
+       return popup->handle_event();
+}
+
+ColorSpaceInverse::ColorSpaceInverse(ColorSpaceWindow *gui, int x, int y, int *value)
+ : BC_CheckBox(x, y, value, _("Inverse"))
+{
+       this->gui = gui;
+}
+
+ColorSpaceInverse::~ColorSpaceInverse()
+{
+}
+
+void ColorSpaceInverse::update()
+{
+       set_value(*value, 1);
+}
+
+int ColorSpaceInverse::handle_event()
+{
+       *value = get_value();
+       gui->plugin->send_configure_change();
+       return 1;
+}
+
+
+ColorSpaceWindow::ColorSpaceWindow(ColorSpaceMain *plugin)
+ : PluginClientWindow(plugin, xS(360), yS(130), xS(360), yS(130), 0)
+{
+       this->plugin = plugin;
+}
+
+ColorSpaceWindow::~ColorSpaceWindow()
+{
+}
+
+void ColorSpaceWindow::create_objects()
+{
+       int ys10 = yS(10);
+       int x = xS(10), y = ys10;
+       int x1 = x + xS(80), x2 = x1 + xS(150);
+       BC_Title *title;
+       add_subwindow(title = new BC_Title(x, y, _("Color Space/Range conversion")));
+       ColorSpaceConfig &config = plugin->config;
+       add_subwindow(inverse = new ColorSpaceInverse(this, x2, y, &config.inverse));
+       y += title->get_h() + yS(15);
+       add_subwindow(title = new BC_Title(x1, y, _("Space")));
+       add_subwindow(title = new BC_Title(x2, y, _("Range")));
+       y += title->get_h() + ys10;
+       add_subwindow(title = new BC_Title(x, y, _("Input:")));
+       add_subwindow(inp_space = new ColorSpaceSpace(this, x1, y, &config.inp_colorspace));
+       inp_space->create_objects();
+       add_subwindow(inp_range = new ColorSpaceRange(this, x2, y, &config.inp_colorrange));
+       inp_range->create_objects();
+       y += title->get_h() + ys10;
+       add_subwindow(title = new BC_Title(x, y, _("Output:")));
+       add_subwindow(out_space = new ColorSpaceSpace(this, x1, y, &config.out_colorspace));
+       out_space->create_objects();
+       add_subwindow(out_range = new ColorSpaceRange(this, x2, y, &config.out_colorrange));
+       out_range->create_objects();
+
+       show_window();
+       flush();
+}
+
+void ColorSpaceWindow::update()
+{
+       inverse->update();
+       inp_space->update();
+       inp_range->update();
+       out_space->update();
+       out_range->update();
+}
+
diff --git a/cinelerra-5.1/plugins/colorspace/colorspacewindow.h b/cinelerra-5.1/plugins/colorspace/colorspacewindow.h
new file mode 100644 (file)
index 0000000..daceaee
--- /dev/null
@@ -0,0 +1,113 @@
+
+/*
+ * 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
+ *
+ */
+
+#ifndef ColorSpaceWINDOW_H
+#define ColorSpaceWINDOW_H
+
+#include "guicast.h"
+
+class ColorSpaceSpace;
+class ColorSpaceRange;
+class ColorSpaceThread;
+class ColorSpaceWindow;
+
+#include "filexml.h"
+#include "mutex.h"
+#include "colorspace.h"
+
+
+class ColorSpaceSpace : public BC_PopupMenu
+{
+       static const char *color_space[3];
+public:
+       ColorSpaceSpace(ColorSpaceWindow *gui, int x, int y, int *value);
+       ~ColorSpaceSpace();
+       void create_objects();
+       void update();
+       int handle_event();
+
+       ColorSpaceWindow *gui;
+       int *value;
+};
+
+class ColorSpaceSpaceItem : public BC_MenuItem
+{
+public:
+       ColorSpaceSpaceItem(ColorSpaceSpace *popup, const char *text, int id);
+       int handle_event();
+
+       ColorSpaceSpace *popup;
+       int id;
+};
+
+class ColorSpaceRange : public BC_PopupMenu
+{
+       static const char *color_range[2];
+public:
+       ColorSpaceRange(ColorSpaceWindow *gui, int x, int y, int *value);
+       ~ColorSpaceRange();
+       void create_objects();
+       void update();
+       int handle_event();
+
+       ColorSpaceWindow *gui;
+       int *value;
+};
+
+class ColorSpaceRangeItem : public BC_MenuItem
+{
+public:
+       ColorSpaceRangeItem(ColorSpaceRange *popup, const char *text, int id);
+       int handle_event();
+
+       ColorSpaceRange *popup;
+       int id;
+};
+
+class ColorSpaceInverse : public BC_CheckBox
+{
+public:
+       ColorSpaceInverse(ColorSpaceWindow *gui, int x, int y, int *value);
+       ~ColorSpaceInverse();
+       void update();
+       int handle_event();
+
+       ColorSpaceWindow *gui;
+};
+
+
+class ColorSpaceWindow : public PluginClientWindow
+{
+public:
+       ColorSpaceWindow(ColorSpaceMain *plugin);
+       ~ColorSpaceWindow();
+
+       void create_objects();
+
+       void update();
+
+       ColorSpaceMain *plugin;
+       ColorSpaceInverse *inverse;
+       ColorSpaceSpace *inp_space, *out_space;
+       ColorSpaceRange *inp_range, *out_range;
+};
+
+#endif