From: Good Guy Date: Sun, 9 Feb 2020 22:55:52 +0000 (-0700) Subject: new colorspace plugin X-Git-Tag: 2020-02~3 X-Git-Url: https://git.cinelerra-gg.org/git/?a=commitdiff_plain;h=ae9b00c3f960e5bd9f74a9d9103e332f4c288ab4;p=goodguy%2Fcinelerra.git new colorspace plugin --- diff --git a/cinelerra-5.1/blds/bld_prepare.sh b/cinelerra-5.1/blds/bld_prepare.sh index 61e09500..a34f123d 100755 --- a/cinelerra-5.1/blds/bld_prepare.sh +++ b/cinelerra-5.1/blds/bld_prepare.sh @@ -7,7 +7,7 @@ fi if [ $# -ne 1 ]; then echo "usage: $0 " - echo " = [centos | suse | ubuntu]" + echo " = [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 \ diff --git a/cinelerra-5.1/expanders.txt b/cinelerra-5.1/expanders.txt index 1138f800..425026c7 100644 --- a/cinelerra-5.1/expanders.txt +++ b/cinelerra-5.1/expanders.txt @@ -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 diff --git a/cinelerra-5.1/ffmpeg/plugin.opts b/cinelerra-5.1/ffmpeg/plugin.opts index 13dd4032..bea77e27 100644 --- a/cinelerra-5.1/ffmpeg/plugin.opts +++ b/cinelerra-5.1/ffmpeg/plugin.opts @@ -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 diff --git a/cinelerra-5.1/info/plugins.txt b/cinelerra-5.1/info/plugins.txt index 5012a25f..2c7c62a8 100644 --- a/cinelerra-5.1/info/plugins.txt +++ b/cinelerra-5.1/info/plugins.txt @@ -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. diff --git a/cinelerra-5.1/plugin_defs b/cinelerra-5.1/plugin_defs index d7313206..7658ede7 100644 --- a/cinelerra-5.1/plugin_defs +++ b/cinelerra-5.1/plugin_defs @@ -35,6 +35,7 @@ video := \ chromakeyhsv \ color3way \ colorbalance \ + colorspace \ crikey \ cropp \ crossfade \ diff --git a/cinelerra-5.1/plugins/Makefile b/cinelerra-5.1/plugins/Makefile index 22bc7dd6..e63682dc 100644 --- a/cinelerra-5.1/plugins/Makefile +++ b/cinelerra-5.1/plugins/Makefile @@ -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 index 00000000..a39df9ad --- /dev/null +++ b/cinelerra-5.1/plugins/colorspace/Makefile @@ -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 index 00000000..01814ec8 --- /dev/null +++ b/cinelerra-5.1/plugins/colorspace/colorspace.C @@ -0,0 +1,628 @@ + +/* + * CINELERRA + * Copyright (C) 2020 Adam Williams + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "bccmodels.h" +#include "filexml.h" +#include "language.h" +#include "colorspace.h" +#include "pluginserver.h" +#include "preferences.h" + +#include +#include + + +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<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; yomx ? omx : v) >> s; \ + } \ + ip += comps; op += comps; \ + } \ + } \ +} + +#define PROCESS_EQNS(type, comps) { \ + for( int y=row1; yomx ? 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(); irow1 = 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 index 00000000..a8fcb050 --- /dev/null +++ b/cinelerra-5.1/plugins/colorspace/colorspace.h @@ -0,0 +1,156 @@ + +/* + * CINELERRA + * Copyright (C) 2008 Adam Williams + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef __COLORSPACE_H__ +#define __COLORSPACE_H__ + +class ColorSpaceMain; + +#include "bchash.h" +#include "mutex.h" +#include "loadbalance.h" +#include "pluginvclient.h" +#include "colorspacewindow.h" +#include + +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 index 00000000..f9198f2b --- /dev/null +++ b/cinelerra-5.1/plugins/colorspace/colorspacewindow.C @@ -0,0 +1,193 @@ + +/* + * CINELERRA + * Copyright (C) 2008 Adam Williams + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "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]); idplugin->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]); idplugin->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 index 00000000..daceaee7 --- /dev/null +++ b/cinelerra-5.1/plugins/colorspace/colorspacewindow.h @@ -0,0 +1,113 @@ + +/* + * CINELERRA + * Copyright (C) 2008 Adam Williams + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#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