+++ /dev/null
-/*
- * Cinelerra :: Blue Banana - color modification plugin for Cinelerra-CV
- * Copyright (C) 2012-2013 Monty <monty@xiph.org>
- *
- * 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 <math.h>
-#include <stdint.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "bluebanana.h"
-#include "bluebananaconfig.h"
-#include "loadbalance.h"
-#include "bluebananacolor.c" // need the inlines
-
-BluebananaPackage::BluebananaPackage(BluebananaEngine *engine) : LoadPackage(){
- this->engine=engine;
-}
-
-BluebananaUnit::BluebananaUnit(BluebananaEngine *server,
- BluebananaMain *plugin) : LoadClient(server) {
- this->plugin = plugin;
- this->server = server;
-}
-
-BluebananaUnit::~BluebananaUnit(){}
-
-void BluebananaUnit::process_package(LoadPackage *package){
- BluebananaPackage *pkg = (BluebananaPackage*)package;
- BluebananaEngine *engine = (BluebananaEngine*)pkg->engine;
-
- VFrame *frame = engine->data;
- int w = frame->get_w();
- int h = frame->get_h();
- int ant = plugin->ants_counter;
- int gui_open = plugin->gui_open();
- int show_ants = plugin->config.mark && gui_open;
- int j;
-
- int active = plugin->config.active;
- int use_mask = plugin->config.use_mask;
- int capture_mask = plugin->config.capture_mask;
- int invert_selection = plugin->config.invert_selection;
-
- float *Hl = (plugin->config.Hsel_active &&
- (plugin->config.Hsel_lo!=0 ||
- plugin->config.Hsel_hi!=360)) ? plugin->hue_select_alpha_lookup : NULL;
- float *Sl = (plugin->config.Ssel_active &&
- (plugin->config.Ssel_lo!=0 ||
- plugin->config.Ssel_hi!=100)) ? plugin->sat_select_alpha_lookup : NULL;
- float *Vl = (plugin->config.Vsel_active &&
- (plugin->config.Vsel_lo!=0 ||
- plugin->config.Vsel_hi!=100)) ? plugin->val_select_alpha_lookup : NULL;
-
- float Hal = plugin->config.Hadj_active ? plugin->config.Hadj_val/60.f : 0.f;
-
- float *Sal = (plugin->config.Sadj_active &&
- (plugin->config.Sadj_lo!=0 ||
- plugin->config.Sadj_hi!=100 ||
- plugin->config.Sadj_gamma!=1)) ? plugin->sat_adj_lookup : NULL;
- float *Val = (plugin->config.Vadj_active &&
- (plugin->config.Vadj_lo!=0 ||
- plugin->config.Vadj_hi!=100 ||
- plugin->config.Vadj_gamma!=1)) ? plugin->val_adj_lookup : NULL;
- float *Ral = (plugin->config.Radj_active &&
- (plugin->config.Radj_lo!=0 ||
- plugin->config.Radj_hi!=100 ||
- plugin->config.Radj_gamma!=1)) ? plugin->red_adj_lookup : NULL;
- float *Gal = (plugin->config.Gadj_active &&
- (plugin->config.Gadj_lo!=0 ||
- plugin->config.Gadj_hi!=100 ||
- plugin->config.Gadj_gamma!=1)) ? plugin->green_adj_lookup : NULL;
- float *Bal = (plugin->config.Badj_active &&
- (plugin->config.Badj_lo!=0 ||
- plugin->config.Badj_hi!=100 ||
- plugin->config.Badj_gamma!=1)) ? plugin->blue_adj_lookup : NULL;
-
- float Sas = plugin->sat_adj_toe_slope;
- float Vas = plugin->val_adj_toe_slope;
- float Ras = plugin->red_adj_toe_slope;
- float Gas = plugin->green_adj_toe_slope;
- float Bas = plugin->blue_adj_toe_slope;
-
- float Aal = plugin->config.Oadj_active ? plugin->config.Oadj_val*.01 : 1.f;
-
- float Vscale = (plugin->config.Vadj_hi-plugin->config.Vadj_lo) / 100.f;
- float Vshift = plugin->config.Vadj_lo / 100.f;
- float Vgamma = plugin->config.Vadj_gamma;
-
- int doRGB = Ral || Gal || Bal;
-
- int doHSV = (Hal!=0) || Sal || Val;
-
- int doSEL = ( Hl || Sl || Vl ) && (active || show_ants);
-
- int shaping = plugin->config.Fsel_active && doSEL &&
- (plugin->config.Fsel_lo || plugin->config.Fsel_hi || plugin->config.Fsel_over);
-
- int byte_advance=0;
- int have_alpha=1;
-
-#define SPLIT 128
-
- int tasks = engine->get_total_packages()*16;
- int taski,rowi,coli;
-
- /* do as much work entirely local to thread memory as possible */
- unsigned char row_fragment[SPLIT*16];
- float *selection_fullframe=NULL;
- float selection[SPLIT];
-
- float Rvec[SPLIT];
- float Gvec[SPLIT];
- float Bvec[SPLIT];
-
- float Avec[SPLIT];
- float Hvec[SPLIT];
- float Svec[SPLIT];
- float Vvec[SPLIT];
-
- float *Rhist = pkg->Rhist;
- float *Ghist = pkg->Ghist;
- float *Bhist = pkg->Bhist;
- float *Hhist = pkg->Hhist;
- float *Shist = pkg->Shist;
- float *Vhist = pkg->Vhist;
- float Htotal=0.f;
- float Hweight=0.f;
-
- float *Hhr = pkg->Hhr;
- float *Hhg = pkg->Hhg;
- float *Hhb = pkg->Hhb;
- float *Shr = pkg->Shr;
- float *Shg = pkg->Shg;
- float *Shb = pkg->Shb;
- float *Vhr = pkg->Vhr;
- float *Vhg = pkg->Vhg;
- float *Vhb = pkg->Vhb;
-
- memset(Rhist,0,sizeof(pkg->Rhist));
- memset(Ghist,0,sizeof(pkg->Ghist));
- memset(Bhist,0,sizeof(pkg->Bhist));
- memset(Hhist,0,sizeof(pkg->Hhist));
- memset(Shist,0,sizeof(pkg->Shist));
- memset(Vhist,0,sizeof(pkg->Vhist));
-
- memset(Hhr,0,sizeof(pkg->Hhr));
- memset(Hhg,0,sizeof(pkg->Hhg));
- memset(Hhb,0,sizeof(pkg->Hhb));
- memset(Shr,0,sizeof(pkg->Shr));
- memset(Shg,0,sizeof(pkg->Shg));
- memset(Shb,0,sizeof(pkg->Shb));
- memset(Vhr,0,sizeof(pkg->Vhr));
- memset(Vhg,0,sizeof(pkg->Vhg));
- memset(Vhb,0,sizeof(pkg->Vhb));
-
- /* If we're doing fill shaping, we need to compute base selection
- for the entire frame before shaping. */
-
- if(shaping){
- engine->set_task(tasks*2,"shaping_even");
- while ( (taski = engine->next_task()) >= 0){
-
- /* operate on discontinuous, interleaved sections of the source
- buffer in two passes. Although we could take extra steps to
- make cache contention across cores completely impossible, the
- extra locking and central join required isn't worth it. It's
- preferable to make contention merely highly unlikely. */
-
- int start_row, end_row;
- if(taski<tasks){
- start_row = (taski*2)*h/(tasks*2);
- end_row = (taski*2+1)*h/(tasks*2);
- }else{
- start_row = ((taski-tasks)*2+1)*h/(tasks*2);
- end_row = ((taski-tasks)*2+2)*h/(tasks*2);
- }
-
- for(rowi = start_row; rowi<end_row; rowi++){
- unsigned char *row = frame->get_rows()[rowi];
-
- for(coli=0;coli<w;coli+=SPLIT){
-
- int todo = (w-coli>SPLIT)?SPLIT:(w-coli);
- float *A = engine->selection_workA+w*rowi+coli;
-
- switch(frame->get_color_model()) {
- case BC_RGB888:
- rgb8_to_RGB((unsigned char *)row,Rvec,Gvec,Bvec,todo);
- row += todo*3;
- break;
- case BC_RGBA8888:
- rgba8_to_RGBA((unsigned char *)row,Rvec,Gvec,Bvec,Avec,todo);
- row += todo*4;
- break;
- case BC_RGB_FLOAT:
- rgbF_to_RGB((float *)row,Rvec,Gvec,Bvec,todo);
- row += todo*12;
- break;
- case BC_RGBA_FLOAT:
- rgbaF_to_RGBA((float *)row,Rvec,Gvec,Bvec,Avec,todo);
- row += todo*16;
- break;
- case BC_YUV888:
- yuv8_to_RGB((unsigned char *)row,Rvec,Gvec,Bvec,todo);
- row += todo*3;
- break;
- case BC_YUVA8888:
- yuva8_to_RGBA((unsigned char *)row,Rvec,Gvec,Bvec,Avec,todo);
- row += todo*4;
- break;
- }
-
- for(j = 0; j < todo; j++)
- RGB_to_HSpV(Rvec[j],Gvec[j],Bvec[j],Hvec[j],Svec[j],Vvec[j]);
-
- if(Hl)
- for(j = 0; j < todo; j++)
- selection[j]=sel_lookup(Hvec[j]*.166666667f,Hl);
- else
- for(j = 0; j < todo; j++)
- selection[j]=1.f;
-
- if(Sl)
- for(j = 0; j < todo; j++)
- selection[j]*=sel_lookup(Svec[j],Sl);
-
- if(Vl)
- for(j = 0; j < todo; j++)
- selection[j]*=sel_lookup(Vvec[j],Vl);
-
- /* lock the memcpy to prevent pessimal cache coherency
- interleave across cores. */
- pthread_mutex_lock(&engine->copylock);
- memcpy(A,selection,sizeof(*selection)*todo);
- pthread_mutex_unlock(&engine->copylock);
- }
- }
- }
-
- /* Perform fill shaping on the selection */
- selection_fullframe = plugin->fill_selection(engine->selection_workA,
- engine->selection_workB, w, h, engine);
- }
-
- /* row-by-row color modification and histogram feedback */
- engine->set_task(tasks*2,"modification_even");
- while((taski = engine->next_task())>=0){
-
- /* operate on discontinuous, interleaved sections of the source
- buffer in two passes. Although we could take extra steps to
- make cache contention across cores completely impossible, the
- extra locking and central join required isn't worth it. It's
- preferable to make contention merely highly unlikely. */
-
- int start_row, end_row;
- if(taski<tasks){
- start_row = (taski*2)*h/(tasks*2);
- end_row = (taski*2+1)*h/(tasks*2);
- }else{
- start_row = ((taski-tasks)*2+1)*h/(tasks*2);
- end_row = ((taski-tasks)*2+2)*h/(tasks*2);
- }
-
- for(rowi = start_row; rowi<end_row; rowi++){
- unsigned char *row = frame->get_rows()[rowi];
-
- for(int coli=0;coli<w;coli+=SPLIT){
- int todo = (w-coli>SPLIT)?SPLIT:(w-coli);
- int have_selection = 0;
-
- /* convert from pipeline color format */
- if(active || show_ants || (use_mask && capture_mask && have_alpha)){
-
- switch(frame->get_color_model()) {
- case BC_RGB888:
- pthread_mutex_lock(&engine->copylock);
- memcpy(row_fragment,row,todo*3);
- pthread_mutex_unlock(&engine->copylock);
- rgb8_to_RGB(row_fragment,Rvec,Gvec,Bvec,todo);
- byte_advance = todo*3;
- have_alpha=0;
- break;
-
- case BC_RGBA8888:
- pthread_mutex_lock(&engine->copylock);
- memcpy(row_fragment,row,todo*4);
- pthread_mutex_unlock(&engine->copylock);
- rgba8_to_RGBA(row_fragment,Rvec,Gvec,Bvec,Avec,todo);
- byte_advance = todo*4;
- have_alpha=1;
- break;
-
- case BC_RGB_FLOAT:
- pthread_mutex_lock(&engine->copylock);
- memcpy(row_fragment,row,todo*12);
- pthread_mutex_unlock(&engine->copylock);
- rgbF_to_RGB((float *)row_fragment,Rvec,Gvec,Bvec,todo);
- byte_advance = todo*12;
- have_alpha=0;
- break;
-
- case BC_RGBA_FLOAT:
- pthread_mutex_lock(&engine->copylock);
- memcpy(row_fragment,row,todo*16);
- pthread_mutex_unlock(&engine->copylock);
- rgbaF_to_RGBA((float *)row_fragment,Rvec,Gvec,Bvec,Avec,todo);
- byte_advance = todo*16;
- have_alpha=1;
- break;
-
- case BC_YUV888:
- pthread_mutex_lock(&engine->copylock);
- memcpy(row_fragment,row,todo*3);
- pthread_mutex_unlock(&engine->copylock);
- yuv8_to_RGB(row_fragment,Rvec,Gvec,Bvec,todo);
- byte_advance = todo*3;
- have_alpha=0;
- break;
-
- case BC_YUVA8888:
- pthread_mutex_lock(&engine->copylock);
- memcpy(row_fragment,row,todo*4);
- pthread_mutex_unlock(&engine->copylock);
- yuva8_to_RGBA(row,Rvec,Gvec,Bvec,Avec,todo);
- byte_advance = todo*4;
- have_alpha=1;
- break;
- }
-
- if(doSEL)
- /* generate initial HSV values [if selection active] */
- for(j = 0; j < todo; j++)
- RGB_to_HSpV(Rvec[j],Gvec[j],Bvec[j],Hvec[j],Svec[j],Vvec[j]);
-
-
- float selection_test=todo;
-
- if(selection_fullframe){
-
- /* get the full-frame selection data we need into thread-local storage */
- /* the full-frame data is read-only at this point, no need to lock */
- float *sf = selection_fullframe + rowi*w + coli;
- selection_test=0.f;
- for(j = 0; j < todo; j++)
- selection_test += selection[j] = sf[j];
- have_selection=1;
-
- }else{
-
- /* selection computation when no full-frame shaping */
- if(Hl){
- selection_test=0.f;
- for(j = 0; j < todo; j++)
- selection_test += selection[j] = sel_lookup(Hvec[j]*.166666667f,Hl);
- have_selection=1;
- }
-
- if(Sl){
- if(have_selection){
- if(selection_test>SELECT_THRESH){
- selection_test=0.f;
- for(j = 0; j < todo; j++)
- selection_test += selection[j] *= sel_lookup(Svec[j],Sl);
- }
- }else{
- selection_test=0.f;
- for(j = 0; j < todo; j++)
- selection_test += selection[j] = sel_lookup(Svec[j],Sl);
- have_selection=1;
- }
- }
-
- if(Vl){
- if(have_selection){
- if(selection_test>SELECT_THRESH){
- selection_test=0.f;
- for(j = 0; j < todo; j++)
- selection_test += selection[j] *= sel_lookup(Vvec[j],Vl);
- }
- }else{
- selection_test=0.f;
- for(j = 0; j < todo; j++)
- selection_test += selection[j] = sel_lookup(Vvec[j],Vl);
- have_selection=1;
- }
- }
- }
-
- /* selection modification according to config */
- if(use_mask && have_alpha){
- if(!have_selection){
- /* selection consists only of mask */
- selection_test=0.;
- for(j = 0; j < todo; j++)
- selection_test += selection[j] = Avec[j];
- have_selection=1;
- }else{
- if(invert_selection){
- if(selection_test < SELECT_THRESH){
- /* fully selected after invert, clip to mask */
- selection_test=0.f;
- for(j = 0; j < todo; j++)
- selection_test += selection[j] = Avec[j];
- }else if (selection_test >= todo-SELECT_THRESH){
- /* fully deselected after invert */
- selection_test=0.;
- }else{
- /* partial selection after invert, clip to mask */
- selection_test=0.f;
- for(j = 0; j < todo; j++)
- selection_test += selection[j] = Avec[j]*(1.f-selection[j]);
- }
- }else{
- if(selection_test < SELECT_THRESH){
- /* fully deselected */
- }else if (selection_test >= todo-SELECT_THRESH){
- /* fully selected, clip to mask */
- selection_test=0.f;
- for(j = 0; j < todo; j++)
- selection_test += selection[j] = Avec[j];
- }else{
- /* partial selection, clip to mask */
- selection_test=0.f;
- for(j = 0; j < todo; j++)
- selection_test += selection[j] *= Avec[j];
- }
- }
- }
- if(selection_test < SELECT_THRESH){
- /* skip processing this fragment */
- /* we're using a mask; if the mask is set to capture, we
- need to restore alpha before skipping */
- if(capture_mask){
- switch(frame->get_color_model()) {
- case BC_RGBA8888:
- unmask_rgba8(row_fragment,todo);
- break;
- case BC_RGBA_FLOAT:
- unmask_rgbaF((float *)row_fragment,todo);
- break;
- case BC_YUVA8888:
- unmask_yuva8(row_fragment,todo);
- break;
- }
- pthread_mutex_lock(&engine->copylock);
- memcpy(row,row_fragment,byte_advance);
- pthread_mutex_unlock(&engine->copylock);
- }
-
- row+=byte_advance;
- continue;
- }
- if(selection_test > todo-SELECT_THRESH)
- have_selection=0; // fully selected
- }else{
- if(have_selection){
- if(invert_selection){
- if(selection_test < SELECT_THRESH){
- /* fully selected after inversion */
- selection_test=todo;
- }else if (selection_test >= todo-SELECT_THRESH){
- /* fully deselected after invert, skip fragment */
- row+=byte_advance;
- continue;
- }else{
- /* partial selection */
- selection_test=0.f;
- for(j = 0; j < todo; j++)
- selection_test += selection[j] = (1.f-selection[j]);
- }
- }else{
- if(selection_test < SELECT_THRESH){
- /* fully deselected, skip fragment */
- row+=byte_advance;
- continue;
- }else if (selection_test >= todo-SELECT_THRESH){
- /* fully selected */
- selection_test=todo;
- }else{
- /* partial selection; already calculated */
- }
- }
- if(selection_test < SELECT_THRESH){
- row+=byte_advance;
- continue; // inactive fragment
- }
- if(selection_test > todo-SELECT_THRESH)
- have_selection=0; // fully selected
- }else{
- if(invert_selection){
- row+=byte_advance;
- continue;
- }
- }
- }
- }
-
- if(active){
-
- /* red adjust */
- if(Ral) {
- if(have_selection){
- for(j = 0; j < todo; j++)
- if(selection[j]>SELECT_THRESH) Rvec[j]=adj_lookup(Rvec[j],Ral,Ras);
- }else{
- for(j = 0; j < todo; j++)
- Rvec[j] = adj_lookup(Rvec[j],Ral,Ras);
- }
- }
- /* red histogram */
- if(gui_open){
- if(have_selection){
- for(j = 0; j < todo; j++)
- if(selection[j]>SELECT_THRESH) Rhist[(int)CLAMP((Rvec[j]+HISTOFF)*HISTSCALE,0,HISTSIZE)] += selection[j];
- }else{
- for(j = 0; j < todo; j++)
- Rhist[(int)CLAMP((Rvec[j]+HISTOFF)*HISTSCALE,0,HISTSIZE)] += 1.f;
- }
- }
-
- /* green adjust */
- if(Gal) {
- if(have_selection){
- for(j = 0; j < todo; j++)
- if(selection[j]>SELECT_THRESH) Gvec[j]=adj_lookup(Gvec[j],Gal,Gas);
- }else{
- for(j = 0; j < todo; j++)
- Gvec[j] = adj_lookup(Gvec[j],Gal,Gas);
- }
- }
- /* green histogram */
- if(gui_open){
- if(have_selection){
- for(j = 0; j < todo; j++)
- if(selection[j]>SELECT_THRESH) Ghist[(int)CLAMP((Gvec[j]+HISTOFF)*HISTSCALE,0,HISTSIZE)] += selection[j];
- }else{
- for(j = 0; j < todo; j++)
- Ghist[(int)CLAMP((Gvec[j]+HISTOFF)*HISTSCALE,0,HISTSIZE)] += 1.f;
- }
- }
-
- /* blue adjust */
- if(Bal) {
- if(have_selection){
- for(j = 0; j < todo; j++)
- if(selection[j]>SELECT_THRESH) Bvec[j]=adj_lookup(Bvec[j],Bal,Bas);
- }else{
- for(j = 0; j < todo; j++)
- Bvec[j] = adj_lookup(Bvec[j],Bal,Bas);
- }
- }
- /* blue histogram */
- if(gui_open){
- if(have_selection){
- for(j = 0; j < todo; j++)
- if(selection[j]>SELECT_THRESH) Bhist[(int)CLAMP((Bvec[j]+HISTOFF)*HISTSCALE,0,HISTSIZE)] += selection[j];
- }else{
- for(j = 0; j < todo; j++)
- Bhist[(int)CLAMP((Bvec[j]+HISTOFF)*HISTSCALE,0,HISTSIZE)] += 1.f;
- }
- }
-
- /* compute HSV values or update values from earlier selection work if
- they've changed */
- if( (!doSEL || doRGB) && // not yet computed, or since modified
- (doHSV || gui_open) ) // needed for HSV mod and/or histograms
- for(j = 0; j < todo; j++)
- RGB_to_HSpV(Rvec[j],Gvec[j],Bvec[j],Hvec[j],Svec[j],Vvec[j]);
-
- if(doHSV){
- /* H modification */
- /* don't bother checking selection, H adj is lightweight */
- if(Hal){
- for(j = 0; j < todo; j++){
- Hvec[j] += Hal;
- if(Hvec[j]<0.f)Hvec[j]+=6.f;
- if(Hvec[j]>=6.f)Hvec[j]-=6.f;
- }
- }
- /* H histogram */
- /* this is pre-shift RGB data; shift hue later to save an HSV->RGB transform */
- if(gui_open){
- if(have_selection){
- for(j = 0; j < todo; j++){
- if(selection[j]>SELECT_THRESH){
- float weight = selection[j]*Svec[j];
- int bin = CLAMP(Hvec[j]*HUESCALE,0,HISTSIZE);
- Htotal += selection[j];
- Hweight += weight;
- Hhist[bin] += weight;
- Hhr[bin>>HRGBSHIFT] += Rvec[j]*weight;
- Hhg[bin>>HRGBSHIFT] += Gvec[j]*weight;
- Hhb[bin>>HRGBSHIFT] += Bvec[j]*weight;
- }
- }
- }else{
- for(j = 0; j < todo; j++){
- float weight = Svec[j];
- int bin = CLAMP(Hvec[j]*HUESCALE,0,HISTSIZE);
- Htotal += 1.f;
- Hweight += weight;
- Hhist[bin] += weight;
- Hhr[bin>>HRGBSHIFT] += Rvec[j]*weight;
- Hhg[bin>>HRGBSHIFT] += Gvec[j]*weight;
- Hhb[bin>>HRGBSHIFT] += Bvec[j]*weight;
- }
- }
- }
-
- /* S modification */
- if(Sal) {
- if(have_selection){
- for(j = 0; j < todo; j++)
- if(selection[j]>SELECT_THRESH) Svec[j] = adj_lookup(Svec[j],Sal,Sas);
- }else{
- for(j = 0; j < todo; j++)
- Svec[j] = adj_lookup(Svec[j],Sal,Sas);
- }
- }
-
- /* This is unrolled a few times below...
- Although we're using HSV, we don't want hue/saturation
- changes to have a strong effect on apparent brightness.
- Apply a correction to V (not Y!) based on luma change. */
- /* Calculate new RGB values at same time */
- if(Hal || Sal){
- if(have_selection){
- for(j = 0; j < todo; j++){
- if(selection[j]>SELECT_THRESH){
- HSpV_correct_RGB(Hvec[j],Svec[j],Vvec[j],Rvec[j],Gvec[j],Bvec[j]);
- /* run S histogram at the same time as we've got
- the RGB data */
- if(gui_open){
- int bin = CLAMP((Svec[j]+HISTOFF)*HISTSCALE,0,HISTSIZE);
- Shist[bin] += selection[j];
- Shr[bin>>HRGBSHIFT] += Rvec[j]*selection[j];
- Shg[bin>>HRGBSHIFT] += Gvec[j]*selection[j];
- Shb[bin>>HRGBSHIFT] += Bvec[j]*selection[j];
- }
- }
- }
- }else{
- for(j = 0; j < todo; j++){
- HSpV_correct_RGB(Hvec[j],Svec[j],Vvec[j],Rvec[j],Gvec[j],Bvec[j]);
- if(gui_open){
- int bin = CLAMP((Svec[j]+HISTOFF)*HISTSCALE,0,HISTSIZE);
- Shist[bin] += 1.f;
- Shr[bin>>HRGBSHIFT] += Rvec[j];
- Shg[bin>>HRGBSHIFT] += Gvec[j];
- Shb[bin>>HRGBSHIFT] += Bvec[j];
- }
- }
- }
- }else{
- if(gui_open){
- if(have_selection){
- for(j = 0; j < todo; j++){
- if(selection[j]>SELECT_THRESH){
- int bin = CLAMP((Svec[j]+HISTOFF)*HISTSCALE,0,HISTSIZE);
- Shist[bin] += selection[j];
- Shr[bin>>HRGBSHIFT] += Rvec[j]*selection[j];
- Shg[bin>>HRGBSHIFT] += Gvec[j]*selection[j];
- Shb[bin>>HRGBSHIFT] += Bvec[j]*selection[j];
- }
- }
- }else{
- for(j = 0; j < todo; j++){
- int bin = CLAMP((Svec[j]+HISTOFF)*HISTSCALE,0,HISTSIZE);
- Shist[bin] += 1.f;
- Shr[bin>>HRGBSHIFT] += Rvec[j];
- Shg[bin>>HRGBSHIFT] += Gvec[j];
- Shb[bin>>HRGBSHIFT] += Bvec[j];
- }
- }
- }
- }
-
- /* V modification */
- /* This one is a bit unlike the others; Value gamma
- behavior is conditional. When < 1.0 (darkening the
- picture) gamma directly operates on Value as normally
- expected (thus scaling R G and B about zero). When
- gamma > 1.0 (lightening the picture) it operates on the
- Value scale's zero point rather than the Value. Both
- are done to get the most natural behavior out of
- saturation as gamma changes. The only drawback: One
- can no longer reverse a gamma operation by applying the
- inverse gamma in a subsequent step. */
- if(Val){
- if(have_selection){
- if(Vgamma<1.0){
- /* scale mode */
- for(j = 0; j < todo; j++)
- if(selection[j]>SELECT_THRESH){
- float scale = adj_lookup(Vvec[j],Val,Vas);
- Vvec[j] = Vvec[j] * scale + Vshift;
- Rvec[j] = Rvec[j] * scale + Vshift;
- Gvec[j] = Gvec[j] * scale + Vshift;
- Bvec[j] = Bvec[j] * scale + Vshift;
- }
- }else{
- /* shift mode */
- for(j = 0; j < todo; j++)
- if(selection[j]>SELECT_THRESH){
- float shift = adj_lookup(Vvec[j],Val,Vas);
- Vvec[j] = Vvec[j] * Vscale + shift;
- Rvec[j] = Rvec[j] * Vscale + shift;
- Gvec[j] = Gvec[j] * Vscale + shift;
- Bvec[j] = Bvec[j] * Vscale + shift;
- }
- }
- }else{
- if(Vgamma<1.0){
- /* scale mode */
- for(j = 0; j < todo; j++){
- float scale = adj_lookup(Vvec[j],Val,Vas);
- Vvec[j] = Vvec[j] * scale + Vshift;
- Rvec[j] = Rvec[j] * scale + Vshift;
- Gvec[j] = Gvec[j] * scale + Vshift;
- Bvec[j] = Bvec[j] * scale + Vshift;
- }
- }else{
- /* shift mode */
- for(j = 0; j < todo; j++){
- float shift = adj_lookup(Vvec[j],Val,Vas);
- Vvec[j] = Vvec[j] * Vscale + shift;
- Rvec[j] = Rvec[j] * Vscale + shift;
- Gvec[j] = Gvec[j] * Vscale + shift;
- Bvec[j] = Bvec[j] * Vscale + shift;
- }
- }
- }
- }
-
- /* V histogram */
- if(gui_open){
- if(have_selection){
- for(j = 0; j < todo; j++){
- if(selection[j]>SELECT_THRESH){
- int bin = CLAMP((Vvec[j]+HISTOFF)*HISTSCALE,0,HISTSIZE);
- Vhist[bin] += selection[j];
- Vhr[bin>>HRGBSHIFT] += Rvec[j]*selection[j];
- Vhg[bin>>HRGBSHIFT] += Gvec[j]*selection[j];
- Vhb[bin>>HRGBSHIFT] += Bvec[j]*selection[j];
- }
- }
- }else{
- for(j = 0; j < todo; j++){
- int bin = CLAMP((Vvec[j]+HISTOFF)*HISTSCALE,0,HISTSIZE);
- Vhist[bin] += 1.f;
- Vhr[bin>>HRGBSHIFT] += Rvec[j];
- Vhg[bin>>HRGBSHIFT] += Gvec[j];
- Vhb[bin>>HRGBSHIFT] += Bvec[j];
- }
- }
- }
-
- }else if (gui_open){
-
- if(have_selection){
- /* H histogram */
- for(j = 0; j < todo; j++){
- if(selection[j]>SELECT_THRESH){
- float weight = selection[j]*Svec[j];
- int bin = CLAMP(Hvec[j]*HUESCALE,0,HISTSIZE);
- Htotal += selection[j];
- Hweight += weight;
- Hhist[bin] += weight;
- Hhr[bin>>HRGBSHIFT] += Rvec[j]*weight;
- Hhg[bin>>HRGBSHIFT] += Gvec[j]*weight;
- Hhb[bin>>HRGBSHIFT] += Bvec[j]*weight;
- }
- }
- /* S histogram */
- for(j = 0; j < todo; j++){
- if(selection[j]>SELECT_THRESH){
- int bin = CLAMP((Svec[j]+HISTOFF)*HISTSCALE,0,HISTSIZE);
- Shist[bin] += selection[j];
- Shr[bin>>HRGBSHIFT] += Rvec[j]*selection[j];
- Shg[bin>>HRGBSHIFT] += Gvec[j]*selection[j];
- Shb[bin>>HRGBSHIFT] += Bvec[j]*selection[j];
- }
- }
- /* V histogram */
- for(j = 0; j < todo; j++){
- if(selection[j]>SELECT_THRESH){
- int bin = CLAMP((Vvec[j]+HISTOFF)*HISTSCALE,0,HISTSIZE);
- Vhist[bin] += selection[j];
- Vhr[bin>>HRGBSHIFT] += Rvec[j]*selection[j];
- Vhg[bin>>HRGBSHIFT] += Gvec[j]*selection[j];
- Vhb[bin>>HRGBSHIFT] += Bvec[j]*selection[j];
- }
- }
- }else{
-
- /* H histogram */
- for(j = 0; j < todo; j++){
- float weight = Svec[j];
- int bin = CLAMP(Hvec[j]*HUESCALE,0,HISTSIZE);
- Htotal += 1.f;
- Hweight += weight;
- Hhist[bin] += weight;
- Hhr[bin>>HRGBSHIFT] += Rvec[j]*weight;
- Hhg[bin>>HRGBSHIFT] += Gvec[j]*weight;
- Hhb[bin>>HRGBSHIFT] += Bvec[j]*weight;
- }
- /* S histogram */
- for(j = 0; j < todo; j++){
- int bin = CLAMP((Svec[j]+HISTOFF)*HISTSCALE,0,HISTSIZE);
- Shist[bin] += 1.f;
- Shr[bin>>HRGBSHIFT] += Rvec[j];
- Shg[bin>>HRGBSHIFT] += Gvec[j];
- Shb[bin>>HRGBSHIFT] += Bvec[j];
- }
- /* V histogram */
- for(j = 0; j < todo; j++){
- int bin = CLAMP((Vvec[j]+HISTOFF)*HISTSCALE,0,HISTSIZE);
- Vhist[bin] += 1.f;
- Vhr[bin>>HRGBSHIFT] += Rvec[j];
- Vhg[bin>>HRGBSHIFT] += Gvec[j];
- Vhb[bin>>HRGBSHIFT] += Bvec[j];
- }
- }
- }
-
- /* layer back into pipeline color format; master fader applies here */
- switch(frame->get_color_model()) {
- case BC_RGB888:
- RGB_to_rgb8(Rvec,Gvec,Bvec,have_selection?selection:0,Aal,row_fragment,todo,3);
- break;
- case BC_RGBA8888:
- RGB_to_rgb8(Rvec,Gvec,Bvec,have_selection?selection:0,Aal,row_fragment,todo,4);
- break;
- case BC_RGB_FLOAT:
- RGB_to_rgbF(Rvec,Gvec,Bvec,have_selection?selection:0,Aal,(float *)row_fragment,todo,3);
- break;
- case BC_RGBA_FLOAT:
- RGB_to_rgbF(Rvec,Gvec,Bvec,have_selection?selection:0,Aal,(float *)row_fragment,todo,4);
- break;
- case BC_YUV888:
- RGB_to_yuv8(Rvec,Gvec,Bvec,have_selection?selection:0,Aal,row_fragment,todo,3);
- break;
- case BC_YUVA8888:
- RGB_to_yuv8(Rvec,Gvec,Bvec,have_selection?selection:0,Aal,row_fragment,todo,4);
- break;
- }
- }
-
- /* ants */
- if(show_ants){
- for(j = 0; j < todo; j++){
- float A = have_selection ? selection[j] : 1.f;
- if(A>.99999f){
- if( (ant+rowi-j)&0x4 ){
- /* magenta */
- Rvec[j] = 1;
- Gvec[j] = 0;
- Bvec[j] = 1;
- }else{
- /* green */
- Rvec[j] = 0;
- Gvec[j] = 1;
- Bvec[j] = 0;
- }
- }else{
- if( (ant+rowi+j)&0x4 ){
- /* black */
- Rvec[j] = 0;
- Gvec[j] = 0;
- Bvec[j] = 0;
- }else{
- /* white */
- Rvec[j] = 1;
- Gvec[j] = 1;
- Bvec[j] = 1;
- }
- }
- }
-
- /* re-layer back into pipeline color format */
- switch(frame->get_color_model()) {
- case BC_RGB888:
- RGB_to_rgb8(Rvec,Gvec,Bvec,have_selection?selection:0,1.f,row_fragment,todo,3);
- break;
- case BC_RGBA8888:
- RGB_to_rgb8(Rvec,Gvec,Bvec,have_selection?selection:0,1.f,row_fragment,todo,4);
- break;
- case BC_RGB_FLOAT:
- RGB_to_rgbF(Rvec,Gvec,Bvec,have_selection?selection:0,1.f,(float *)row_fragment,todo,3);
- break;
- case BC_RGBA_FLOAT:
- RGB_to_rgbF(Rvec,Gvec,Bvec,have_selection?selection:0,1.f,(float *)row_fragment,todo,4);
- break;
- case BC_YUV888:
- RGB_to_yuv8(Rvec,Gvec,Bvec,have_selection?selection:0,1.f,row_fragment,todo,3);
- break;
- case BC_YUVA8888:
- RGB_to_yuv8(Rvec,Gvec,Bvec,have_selection?selection:0,1.f,row_fragment,todo,4);
- break;
- }
- }
-
- if(active || show_ants || (use_mask && capture_mask)){
-
- if(use_mask && capture_mask){
- switch(frame->get_color_model()) {
- case BC_RGBA8888:
- unmask_rgba8(row_fragment,todo);
- break;
- case BC_RGBA_FLOAT:
- unmask_rgbaF((float *)row_fragment,todo);
- break;
- case BC_YUVA8888:
- unmask_yuva8(row_fragment,todo);
- break;
- }
- }
-
- /* lock to prevent interleaved cache coherency collisions
- across cores. Two memcpys touching the same cache line
- will cause the wings to fall off the processor. */
-
- pthread_mutex_lock(&engine->copylock);
- memcpy(row,row_fragment,byte_advance);
- pthread_mutex_unlock(&engine->copylock);
- row+=byte_advance;
-
- }
- }
- }
- }
-
- pthread_mutex_lock(&engine->copylock);
-
- plugin->hue_total+=Htotal;
- plugin->hue_weight+=Hweight;
-
- for(int i=0;i<HISTSIZE;i++){
- plugin->red_histogram[i] += Rhist[i];
- plugin->green_histogram[i] += Ghist[i];
- plugin->blue_histogram[i] += Bhist[i];
-
- plugin->hue_histogram[i] += Hhist[i];
- plugin->sat_histogram[i] += Shist[i];
-
- plugin->value_histogram[i] += Vhist[i];
- }
-
- for(int i=0;i<(HISTSIZE>>HRGBSHIFT);i++){
- plugin->hue_histogram_red[i] += Hhr[i];
- plugin->hue_histogram_green[i] += Hhg[i];
- plugin->hue_histogram_blue[i] += Hhb[i];
-
- plugin->sat_histogram_red[i] += Shr[i];
- plugin->sat_histogram_green[i] += Shg[i];
- plugin->sat_histogram_blue[i] += Shb[i];
-
- plugin->value_histogram_red[i] += Vhr[i];
- plugin->value_histogram_green[i] += Vhg[i];
- plugin->value_histogram_blue[i] += Vhb[i];
- }
- pthread_mutex_unlock(&engine->copylock);
-
-}
-
-BluebananaEngine::BluebananaEngine(BluebananaMain *plugin, int total_clients,
- int total_packages) : LoadServer(total_clients, total_packages){
- this->plugin = plugin;
- selection_workA=0;
- selection_workB=0;
- task_init_serial=0;
- pthread_mutex_init(©lock,NULL);
- pthread_mutex_init(&tasklock,NULL);
- pthread_cond_init(&taskcond,NULL);
-}
-BluebananaEngine::~BluebananaEngine(){
- pthread_cond_destroy(&taskcond);
- pthread_mutex_destroy(&tasklock);
- pthread_mutex_destroy(©lock);
- if(selection_workA) delete[] selection_workA;
- if(selection_workB) delete[] selection_workB;
-}
-
-void BluebananaEngine::init_packages(){}
-
-LoadClient* BluebananaEngine::new_client(){
- return new BluebananaUnit(this, plugin);
-}
-
-LoadPackage* BluebananaEngine::new_package(){
- return new BluebananaPackage(this);
-}
-
-static float lt(float *data,float pos, int n){
- if(pos<0)pos+=n;
- if(pos>=n)pos-=n;
- int i = (int)pos;
- float del = pos-i;
- return data[i]*(1.f-del) + data[i+1]*del;
-}
-
-static float lt_shift(float *data, float pos, int n, int over){
- float s0=0, s1=0;
- if(pos<0)pos+=n;
- if(pos>=n)pos-=n;
- int i = (int)pos;
- float del = pos-i;
- i *= over;
- data += i;
- for(int j=0; j<over; j++)
- s0 += *data++;
- for(int j=0; j<over; j++)
- s1 += *data++;
-
- float temp=(s0*(1.f-del) + s1*del);
- if(temp>0)
- return 1./temp;
- else
- return 0;
-}
-
-void BluebananaEngine::process_packages(VFrame *data){
- int w = data->get_w();
- int h = data->get_h();
- this->data = data;
- task_init_state=0;
- task_n=0;
- task_finish_count=0;
-
- /* If we're doing any spatial modification of the selection, we'll
- need to operate on a temporary selection array that covers the
- complete frame */
- if(plugin->config.Fsel_active){
- if(plugin->config.Fsel_lo ||
- plugin->config.Fsel_mid ||
- plugin->config.Fsel_hi ||
- plugin->config.Fsel_over){
- selection_workA = new float[w*h];
- selection_workB = new float[w*h];
- }
- }
-
- memset(plugin->red_histogram,0,sizeof(plugin->red_histogram));
- memset(plugin->green_histogram,0,sizeof(plugin->green_histogram));
- memset(plugin->blue_histogram,0,sizeof(plugin->blue_histogram));
- memset(plugin->hue_histogram,0,sizeof(plugin->hue_histogram));
- plugin->hue_total=0.f;
- plugin->hue_weight=0.f;
- memset(plugin->sat_histogram,0,sizeof(plugin->sat_histogram));
- memset(plugin->value_histogram,0,sizeof(plugin->value_histogram));
-
- memset(plugin->hue_histogram_red,0,sizeof(plugin->hue_histogram_red));
- memset(plugin->hue_histogram_green,0,sizeof(plugin->hue_histogram_green));
- memset(plugin->hue_histogram_blue,0,sizeof(plugin->hue_histogram_blue));
-
- memset(plugin->sat_histogram_red,0,sizeof(plugin->sat_histogram_red));
- memset(plugin->sat_histogram_green,0,sizeof(plugin->sat_histogram_green));
- memset(plugin->sat_histogram_blue,0,sizeof(plugin->sat_histogram_blue));
-
- memset(plugin->value_histogram_red,0,sizeof(plugin->value_histogram_red));
- memset(plugin->value_histogram_green,0,sizeof(plugin->value_histogram_green));
- memset(plugin->value_histogram_blue,0,sizeof(plugin->value_histogram_blue));
-
- LoadServer::process_packages();
-
- /* The Hue histogram needs to be adjusted/shifted */
- if(plugin->config.active && plugin->hue_weight){
- int i,j;
- float scale = plugin->hue_total/plugin->hue_weight;
- float Hshift = plugin->config.Hsel_active ? (plugin->config.Hsel_lo + plugin->config.Hsel_hi)/720.f-.5f : 0.f;
- float Hal = plugin->config.Hadj_active ? plugin->config.Hadj_val/60.f : 0.f;
- float hist[HISTSIZE + (1<<HRGBSHIFT)];
- float red[(HISTSIZE>>HRGBSHIFT)+1];
- float green[(HISTSIZE>>HRGBSHIFT)+1];
- float blue[(HISTSIZE>>HRGBSHIFT)+1];
-
- for(i=0;i<(1<<HRGBSHIFT);i++){
- plugin->hue_histogram[i]+=plugin->hue_histogram[HISTSIZE+i];
- plugin->hue_histogram[HISTSIZE+i]=plugin->hue_histogram[i];
- }
- plugin->hue_histogram_red[0]+=plugin->hue_histogram_red[HISTSIZE>>HRGBSHIFT];
- plugin->hue_histogram_red[HISTSIZE>>HRGBSHIFT]=plugin->hue_histogram_red[0];
- plugin->hue_histogram_green[0]+=plugin->hue_histogram_green[HISTSIZE>>HRGBSHIFT];
- plugin->hue_histogram_green[HISTSIZE>>HRGBSHIFT]=plugin->hue_histogram_green[0];
- plugin->hue_histogram_blue[0]+=plugin->hue_histogram_blue[HISTSIZE>>HRGBSHIFT];
- plugin->hue_histogram_blue[HISTSIZE>>HRGBSHIFT]=plugin->hue_histogram_blue[0];
-
- for(i=0; i<(HISTSIZE>>HRGBSHIFT); i++){
- float pos = i+Hshift*(HISTSIZE>>HRGBSHIFT);
- if(pos<0)pos+=(HISTSIZE>>HRGBSHIFT);
- if(pos>=(HISTSIZE>>HRGBSHIFT))pos-=(HISTSIZE>>HRGBSHIFT);
-
- float div = lt_shift(plugin->hue_histogram,i+Hshift*(HISTSIZE>>HRGBSHIFT),
- (HISTSIZE>>HRGBSHIFT), (1<<HRGBSHIFT));
- red[i] = lt(plugin->hue_histogram_red,i+Hshift*(HISTSIZE>>HRGBSHIFT),
- (HISTSIZE>>HRGBSHIFT))*div;
- green[i] = lt(plugin->hue_histogram_green,i+Hshift*(HISTSIZE>>HRGBSHIFT),
- (HISTSIZE>>HRGBSHIFT))*div;
- blue[i] = lt(plugin->hue_histogram_blue,i+Hshift*(HISTSIZE>>HRGBSHIFT),
- (HISTSIZE>>HRGBSHIFT))*div;
- }
-
- for(int i=0; i<HISTSIZE; i++)
- hist[i] = lt(plugin->hue_histogram,i+Hshift*HISTSIZE,HISTSIZE)*scale;
-
- memcpy(hist+HISTSIZE,hist,sizeof(*hist)*(1<<HRGBSHIFT));
- memcpy(plugin->hue_histogram,hist,sizeof(hist));
-
- red[HISTSIZE>>HRGBSHIFT]=red[0];
- green[HISTSIZE>>HRGBSHIFT]=green[0];
- blue[HISTSIZE>>HRGBSHIFT]=blue[0];
-
- for(i=0,j=0; i<=(HISTSIZE>>HRGBSHIFT); i++){
- float sum=0.f,H,S,V;
- for(int k=0; k<(1<<HRGBSHIFT); j++,k++)
- sum+=hist[j];
-
- RGB_to_HSpV(red[i],green[i],blue[i],H,S,V);
- H+=Hal;
- if(H<0)H+=6;
- if(H>=6)H-=6;
- HSpV_to_RGB(H,S,V,red[i],green[i],blue[i]);
-
- plugin->hue_histogram_red[i] = red[i] * sum;
- plugin->hue_histogram_green[i] = green[i] * sum;
- plugin->hue_histogram_blue[i] = blue[i] * sum;
- }
- }
-
- if(selection_workA){
- delete[] selection_workA;
- selection_workA=0;
- }
- if(selection_workB){
- delete[] selection_workB;
- selection_workB=0;
- }
-}
-
-/* create a coordinated work-division list and join point */
-void BluebananaEngine::set_task(int n, const char *task){
- pthread_mutex_lock(&this->tasklock);
- if(task_init_state==0){
- //fprintf(stderr,"New task!: %s",task);
- task_n=n;
- task_finish_count=get_total_packages();
- task_init_state=1;
- task_init_serial++;
- }
- pthread_mutex_unlock(&this->tasklock);
-}
-
-/* fetch the next task ticket. If the task is complete, wait here for
- all package threads to complete before returning <0 */
-int BluebananaEngine::next_task(){
- pthread_mutex_lock(&tasklock);
- if(task_n){
- int ret = --task_n;
- //fprintf(stderr,".");
- pthread_mutex_unlock(&tasklock);
- return ret;
- }else{
- task_finish_count--;
- if(task_finish_count==0){
- task_init_state=0;
- //fprintf(stderr,"done\n");
- pthread_cond_broadcast(&taskcond);
- }else{
- int serial = task_init_serial;
- while(task_finish_count && serial == task_init_serial){
- //fprintf(stderr,"+");
- pthread_cond_wait(&taskcond,&tasklock);
- }
- }
- pthread_mutex_unlock(&tasklock);
- //fprintf(stderr,"-");
- return -1;
- }
-}
-
-/* same as above, but waits for join without fetching a task slot */
-void BluebananaEngine::wait_task(){
- pthread_mutex_lock(&tasklock);
- task_finish_count--;
- if(task_finish_count==0){
- task_init_state=0;
- //fprintf(stderr,"done\n");
- pthread_cond_broadcast(&taskcond);
- }else{
- int serial = task_init_serial;
- while(task_finish_count && serial == task_init_serial){
- //fprintf(stderr,"+");
- pthread_cond_wait(&taskcond,&tasklock);
- }
- }
- pthread_mutex_unlock(&tasklock);
- //fprintf(stderr,"-");
-}