2 * Cinelerra :: Blue Banana - color modification plugin for Cinelerra-CV
3 * Copyright (C) 2012-2013 Monty <monty@xiph.org>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 #include "bluebanana.h"
27 #include "bluebananaconfig.h"
28 #include "loadbalance.h"
29 #include "bluebananacolor.c" // need the inlines
31 BluebananaPackage::BluebananaPackage(BluebananaEngine *engine) : LoadPackage(){
35 BluebananaUnit::BluebananaUnit(BluebananaEngine *server,
36 BluebananaMain *plugin) : LoadClient(server) {
37 this->plugin = plugin;
38 this->server = server;
41 BluebananaUnit::~BluebananaUnit(){}
43 void BluebananaUnit::process_package(LoadPackage *package){
44 BluebananaPackage *pkg = (BluebananaPackage*)package;
45 BluebananaEngine *engine = (BluebananaEngine*)pkg->engine;
47 VFrame *frame = engine->data;
48 int w = frame->get_w();
49 int h = frame->get_h();
50 int ant = plugin->ants_counter;
51 int gui_open = plugin->gui_open();
52 int show_ants = plugin->config.mark && gui_open;
55 int active = plugin->config.active;
56 int use_mask = plugin->config.use_mask;
57 int capture_mask = plugin->config.capture_mask;
58 int invert_selection = plugin->config.invert_selection;
60 float *Hl = (plugin->config.Hsel_active &&
61 (plugin->config.Hsel_lo!=0 ||
62 plugin->config.Hsel_hi!=360)) ? plugin->hue_select_alpha_lookup : NULL;
63 float *Sl = (plugin->config.Ssel_active &&
64 (plugin->config.Ssel_lo!=0 ||
65 plugin->config.Ssel_hi!=100)) ? plugin->sat_select_alpha_lookup : NULL;
66 float *Vl = (plugin->config.Vsel_active &&
67 (plugin->config.Vsel_lo!=0 ||
68 plugin->config.Vsel_hi!=100)) ? plugin->val_select_alpha_lookup : NULL;
70 float Hal = plugin->config.Hadj_active ? plugin->config.Hadj_val/60.f : 0.f;
72 float *Sal = (plugin->config.Sadj_active &&
73 (plugin->config.Sadj_lo!=0 ||
74 plugin->config.Sadj_hi!=100 ||
75 plugin->config.Sadj_gamma!=1)) ? plugin->sat_adj_lookup : NULL;
76 float *Val = (plugin->config.Vadj_active &&
77 (plugin->config.Vadj_lo!=0 ||
78 plugin->config.Vadj_hi!=100 ||
79 plugin->config.Vadj_gamma!=1)) ? plugin->val_adj_lookup : NULL;
80 float *Ral = (plugin->config.Radj_active &&
81 (plugin->config.Radj_lo!=0 ||
82 plugin->config.Radj_hi!=100 ||
83 plugin->config.Radj_gamma!=1)) ? plugin->red_adj_lookup : NULL;
84 float *Gal = (plugin->config.Gadj_active &&
85 (plugin->config.Gadj_lo!=0 ||
86 plugin->config.Gadj_hi!=100 ||
87 plugin->config.Gadj_gamma!=1)) ? plugin->green_adj_lookup : NULL;
88 float *Bal = (plugin->config.Badj_active &&
89 (plugin->config.Badj_lo!=0 ||
90 plugin->config.Badj_hi!=100 ||
91 plugin->config.Badj_gamma!=1)) ? plugin->blue_adj_lookup : NULL;
93 float Sas = plugin->sat_adj_toe_slope;
94 float Vas = plugin->val_adj_toe_slope;
95 float Ras = plugin->red_adj_toe_slope;
96 float Gas = plugin->green_adj_toe_slope;
97 float Bas = plugin->blue_adj_toe_slope;
99 float Aal = plugin->config.Oadj_active ? plugin->config.Oadj_val*.01 : 1.f;
101 float Vscale = (plugin->config.Vadj_hi-plugin->config.Vadj_lo) / 100.f;
102 float Vshift = plugin->config.Vadj_lo / 100.f;
103 float Vgamma = plugin->config.Vadj_gamma;
105 int doRGB = Ral || Gal || Bal;
107 int doHSV = (Hal!=0) || Sal || Val;
109 int doSEL = ( Hl || Sl || Vl ) && (active || show_ants);
111 int shaping = plugin->config.Fsel_active && doSEL &&
112 (plugin->config.Fsel_lo || plugin->config.Fsel_hi || plugin->config.Fsel_over);
119 int tasks = engine->get_total_packages()*16;
122 /* do as much work entirely local to thread memory as possible */
123 unsigned char row_fragment[SPLIT*16];
124 float *selection_fullframe=NULL;
125 float selection[SPLIT];
136 float *Rhist = pkg->Rhist;
137 float *Ghist = pkg->Ghist;
138 float *Bhist = pkg->Bhist;
139 float *Hhist = pkg->Hhist;
140 float *Shist = pkg->Shist;
141 float *Vhist = pkg->Vhist;
145 float *Hhr = pkg->Hhr;
146 float *Hhg = pkg->Hhg;
147 float *Hhb = pkg->Hhb;
148 float *Shr = pkg->Shr;
149 float *Shg = pkg->Shg;
150 float *Shb = pkg->Shb;
151 float *Vhr = pkg->Vhr;
152 float *Vhg = pkg->Vhg;
153 float *Vhb = pkg->Vhb;
155 memset(Rhist,0,sizeof(pkg->Rhist));
156 memset(Ghist,0,sizeof(pkg->Ghist));
157 memset(Bhist,0,sizeof(pkg->Bhist));
158 memset(Hhist,0,sizeof(pkg->Hhist));
159 memset(Shist,0,sizeof(pkg->Shist));
160 memset(Vhist,0,sizeof(pkg->Vhist));
162 memset(Hhr,0,sizeof(pkg->Hhr));
163 memset(Hhg,0,sizeof(pkg->Hhg));
164 memset(Hhb,0,sizeof(pkg->Hhb));
165 memset(Shr,0,sizeof(pkg->Shr));
166 memset(Shg,0,sizeof(pkg->Shg));
167 memset(Shb,0,sizeof(pkg->Shb));
168 memset(Vhr,0,sizeof(pkg->Vhr));
169 memset(Vhg,0,sizeof(pkg->Vhg));
170 memset(Vhb,0,sizeof(pkg->Vhb));
172 /* If we're doing fill shaping, we need to compute base selection
173 for the entire frame before shaping. */
176 engine->set_task(tasks*2,"shaping_even");
177 while ( (taski = engine->next_task()) >= 0){
179 /* operate on discontinuous, interleaved sections of the source
180 buffer in two passes. Although we could take extra steps to
181 make cache contention across cores completely impossible, the
182 extra locking and central join required isn't worth it. It's
183 preferable to make contention merely highly unlikely. */
185 int start_row, end_row;
187 start_row = (taski*2)*h/(tasks*2);
188 end_row = (taski*2+1)*h/(tasks*2);
190 start_row = ((taski-tasks)*2+1)*h/(tasks*2);
191 end_row = ((taski-tasks)*2+2)*h/(tasks*2);
194 for(rowi = start_row; rowi<end_row; rowi++){
195 unsigned char *row = frame->get_rows()[rowi];
197 for(coli=0;coli<w;coli+=SPLIT){
199 int todo = (w-coli>SPLIT)?SPLIT:(w-coli);
200 float *A = engine->selection_workA+w*rowi+coli;
202 switch(frame->get_color_model()) {
204 rgb8_to_RGB((unsigned char *)row,Rvec,Gvec,Bvec,todo);
208 rgba8_to_RGBA((unsigned char *)row,Rvec,Gvec,Bvec,Avec,todo);
212 rgbF_to_RGB((float *)row,Rvec,Gvec,Bvec,todo);
216 rgbaF_to_RGBA((float *)row,Rvec,Gvec,Bvec,Avec,todo);
220 yuv8_to_RGB((unsigned char *)row,Rvec,Gvec,Bvec,todo);
224 yuva8_to_RGBA((unsigned char *)row,Rvec,Gvec,Bvec,Avec,todo);
229 for(j = 0; j < todo; j++)
230 RGB_to_HSpV(Rvec[j],Gvec[j],Bvec[j],Hvec[j],Svec[j],Vvec[j]);
233 for(j = 0; j < todo; j++)
234 selection[j]=sel_lookup(Hvec[j]*.166666667f,Hl);
236 for(j = 0; j < todo; j++)
240 for(j = 0; j < todo; j++)
241 selection[j]*=sel_lookup(Svec[j],Sl);
244 for(j = 0; j < todo; j++)
245 selection[j]*=sel_lookup(Vvec[j],Vl);
247 /* lock the memcpy to prevent pessimal cache coherency
248 interleave across cores. */
249 pthread_mutex_lock(&engine->copylock);
250 memcpy(A,selection,sizeof(*selection)*todo);
251 pthread_mutex_unlock(&engine->copylock);
256 /* Perform fill shaping on the selection */
257 selection_fullframe = plugin->fill_selection(engine->selection_workA,
258 engine->selection_workB, w, h, engine);
261 /* row-by-row color modification and histogram feedback */
262 engine->set_task(tasks*2,"modification_even");
263 while((taski = engine->next_task())>=0){
265 /* operate on discontinuous, interleaved sections of the source
266 buffer in two passes. Although we could take extra steps to
267 make cache contention across cores completely impossible, the
268 extra locking and central join required isn't worth it. It's
269 preferable to make contention merely highly unlikely. */
271 int start_row, end_row;
273 start_row = (taski*2)*h/(tasks*2);
274 end_row = (taski*2+1)*h/(tasks*2);
276 start_row = ((taski-tasks)*2+1)*h/(tasks*2);
277 end_row = ((taski-tasks)*2+2)*h/(tasks*2);
280 for(rowi = start_row; rowi<end_row; rowi++){
281 unsigned char *row = frame->get_rows()[rowi];
283 for(int coli=0;coli<w;coli+=SPLIT){
284 int todo = (w-coli>SPLIT)?SPLIT:(w-coli);
285 int have_selection = 0;
287 /* convert from pipeline color format */
288 if(active || show_ants || (use_mask && capture_mask && have_alpha)){
290 switch(frame->get_color_model()) {
292 pthread_mutex_lock(&engine->copylock);
293 memcpy(row_fragment,row,todo*3);
294 pthread_mutex_unlock(&engine->copylock);
295 rgb8_to_RGB(row_fragment,Rvec,Gvec,Bvec,todo);
296 byte_advance = todo*3;
301 pthread_mutex_lock(&engine->copylock);
302 memcpy(row_fragment,row,todo*4);
303 pthread_mutex_unlock(&engine->copylock);
304 rgba8_to_RGBA(row_fragment,Rvec,Gvec,Bvec,Avec,todo);
305 byte_advance = todo*4;
310 pthread_mutex_lock(&engine->copylock);
311 memcpy(row_fragment,row,todo*12);
312 pthread_mutex_unlock(&engine->copylock);
313 rgbF_to_RGB((float *)row_fragment,Rvec,Gvec,Bvec,todo);
314 byte_advance = todo*12;
319 pthread_mutex_lock(&engine->copylock);
320 memcpy(row_fragment,row,todo*16);
321 pthread_mutex_unlock(&engine->copylock);
322 rgbaF_to_RGBA((float *)row_fragment,Rvec,Gvec,Bvec,Avec,todo);
323 byte_advance = todo*16;
328 pthread_mutex_lock(&engine->copylock);
329 memcpy(row_fragment,row,todo*3);
330 pthread_mutex_unlock(&engine->copylock);
331 yuv8_to_RGB(row_fragment,Rvec,Gvec,Bvec,todo);
332 byte_advance = todo*3;
337 pthread_mutex_lock(&engine->copylock);
338 memcpy(row_fragment,row,todo*4);
339 pthread_mutex_unlock(&engine->copylock);
340 yuva8_to_RGBA(row,Rvec,Gvec,Bvec,Avec,todo);
341 byte_advance = todo*4;
347 /* generate initial HSV values [if selection active] */
348 for(j = 0; j < todo; j++)
349 RGB_to_HSpV(Rvec[j],Gvec[j],Bvec[j],Hvec[j],Svec[j],Vvec[j]);
352 float selection_test=todo;
354 if(selection_fullframe){
356 /* get the full-frame selection data we need into thread-local storage */
357 /* the full-frame data is read-only at this point, no need to lock */
358 float *sf = selection_fullframe + rowi*w + coli;
360 for(j = 0; j < todo; j++)
361 selection_test += selection[j] = sf[j];
366 /* selection computation when no full-frame shaping */
369 for(j = 0; j < todo; j++)
370 selection_test += selection[j] = sel_lookup(Hvec[j]*.166666667f,Hl);
376 if(selection_test>SELECT_THRESH){
378 for(j = 0; j < todo; j++)
379 selection_test += selection[j] *= sel_lookup(Svec[j],Sl);
383 for(j = 0; j < todo; j++)
384 selection_test += selection[j] = sel_lookup(Svec[j],Sl);
391 if(selection_test>SELECT_THRESH){
393 for(j = 0; j < todo; j++)
394 selection_test += selection[j] *= sel_lookup(Vvec[j],Vl);
398 for(j = 0; j < todo; j++)
399 selection_test += selection[j] = sel_lookup(Vvec[j],Vl);
405 /* selection modification according to config */
406 if(use_mask && have_alpha){
408 /* selection consists only of mask */
410 for(j = 0; j < todo; j++)
411 selection_test += selection[j] = Avec[j];
414 if(invert_selection){
415 if(selection_test < SELECT_THRESH){
416 /* fully selected after invert, clip to mask */
418 for(j = 0; j < todo; j++)
419 selection_test += selection[j] = Avec[j];
420 }else if (selection_test >= todo-SELECT_THRESH){
421 /* fully deselected after invert */
424 /* partial selection after invert, clip to mask */
426 for(j = 0; j < todo; j++)
427 selection_test += selection[j] = Avec[j]*(1.f-selection[j]);
430 if(selection_test < SELECT_THRESH){
431 /* fully deselected */
432 }else if (selection_test >= todo-SELECT_THRESH){
433 /* fully selected, clip to mask */
435 for(j = 0; j < todo; j++)
436 selection_test += selection[j] = Avec[j];
438 /* partial selection, clip to mask */
440 for(j = 0; j < todo; j++)
441 selection_test += selection[j] *= Avec[j];
445 if(selection_test < SELECT_THRESH){
446 /* skip processing this fragment */
447 /* we're using a mask; if the mask is set to capture, we
448 need to restore alpha before skipping */
450 switch(frame->get_color_model()) {
452 unmask_rgba8(row_fragment,todo);
455 unmask_rgbaF((float *)row_fragment,todo);
458 unmask_yuva8(row_fragment,todo);
461 pthread_mutex_lock(&engine->copylock);
462 memcpy(row,row_fragment,byte_advance);
463 pthread_mutex_unlock(&engine->copylock);
469 if(selection_test > todo-SELECT_THRESH)
470 have_selection=0; // fully selected
473 if(invert_selection){
474 if(selection_test < SELECT_THRESH){
475 /* fully selected after inversion */
477 }else if (selection_test >= todo-SELECT_THRESH){
478 /* fully deselected after invert, skip fragment */
482 /* partial selection */
484 for(j = 0; j < todo; j++)
485 selection_test += selection[j] = (1.f-selection[j]);
488 if(selection_test < SELECT_THRESH){
489 /* fully deselected, skip fragment */
492 }else if (selection_test >= todo-SELECT_THRESH){
496 /* partial selection; already calculated */
499 if(selection_test < SELECT_THRESH){
501 continue; // inactive fragment
503 if(selection_test > todo-SELECT_THRESH)
504 have_selection=0; // fully selected
506 if(invert_selection){
519 for(j = 0; j < todo; j++)
520 if(selection[j]>SELECT_THRESH) Rvec[j]=adj_lookup(Rvec[j],Ral,Ras);
522 for(j = 0; j < todo; j++)
523 Rvec[j] = adj_lookup(Rvec[j],Ral,Ras);
529 for(j = 0; j < todo; j++)
530 if(selection[j]>SELECT_THRESH) Rhist[(int)CLAMP((Rvec[j]+HISTOFF)*HISTSCALE,0,HISTSIZE)] += selection[j];
532 for(j = 0; j < todo; j++)
533 Rhist[(int)CLAMP((Rvec[j]+HISTOFF)*HISTSCALE,0,HISTSIZE)] += 1.f;
540 for(j = 0; j < todo; j++)
541 if(selection[j]>SELECT_THRESH) Gvec[j]=adj_lookup(Gvec[j],Gal,Gas);
543 for(j = 0; j < todo; j++)
544 Gvec[j] = adj_lookup(Gvec[j],Gal,Gas);
547 /* green histogram */
550 for(j = 0; j < todo; j++)
551 if(selection[j]>SELECT_THRESH) Ghist[(int)CLAMP((Gvec[j]+HISTOFF)*HISTSCALE,0,HISTSIZE)] += selection[j];
553 for(j = 0; j < todo; j++)
554 Ghist[(int)CLAMP((Gvec[j]+HISTOFF)*HISTSCALE,0,HISTSIZE)] += 1.f;
561 for(j = 0; j < todo; j++)
562 if(selection[j]>SELECT_THRESH) Bvec[j]=adj_lookup(Bvec[j],Bal,Bas);
564 for(j = 0; j < todo; j++)
565 Bvec[j] = adj_lookup(Bvec[j],Bal,Bas);
571 for(j = 0; j < todo; j++)
572 if(selection[j]>SELECT_THRESH) Bhist[(int)CLAMP((Bvec[j]+HISTOFF)*HISTSCALE,0,HISTSIZE)] += selection[j];
574 for(j = 0; j < todo; j++)
575 Bhist[(int)CLAMP((Bvec[j]+HISTOFF)*HISTSCALE,0,HISTSIZE)] += 1.f;
579 /* compute HSV values or update values from earlier selection work if
581 if( (!doSEL || doRGB) && // not yet computed, or since modified
582 (doHSV || gui_open) ) // needed for HSV mod and/or histograms
583 for(j = 0; j < todo; j++)
584 RGB_to_HSpV(Rvec[j],Gvec[j],Bvec[j],Hvec[j],Svec[j],Vvec[j]);
588 /* don't bother checking selection, H adj is lightweight */
590 for(j = 0; j < todo; j++){
592 if(Hvec[j]<0.f)Hvec[j]+=6.f;
593 if(Hvec[j]>=6.f)Hvec[j]-=6.f;
597 /* this is pre-shift RGB data; shift hue later to save an HSV->RGB transform */
600 for(j = 0; j < todo; j++){
601 if(selection[j]>SELECT_THRESH){
602 float weight = selection[j]*Svec[j];
603 int bin = CLAMP(Hvec[j]*HUESCALE,0,HISTSIZE);
604 Htotal += selection[j];
606 Hhist[bin] += weight;
607 Hhr[bin>>HRGBSHIFT] += Rvec[j]*weight;
608 Hhg[bin>>HRGBSHIFT] += Gvec[j]*weight;
609 Hhb[bin>>HRGBSHIFT] += Bvec[j]*weight;
613 for(j = 0; j < todo; j++){
614 float weight = Svec[j];
615 int bin = CLAMP(Hvec[j]*HUESCALE,0,HISTSIZE);
618 Hhist[bin] += weight;
619 Hhr[bin>>HRGBSHIFT] += Rvec[j]*weight;
620 Hhg[bin>>HRGBSHIFT] += Gvec[j]*weight;
621 Hhb[bin>>HRGBSHIFT] += Bvec[j]*weight;
629 for(j = 0; j < todo; j++)
630 if(selection[j]>SELECT_THRESH) Svec[j] = adj_lookup(Svec[j],Sal,Sas);
632 for(j = 0; j < todo; j++)
633 Svec[j] = adj_lookup(Svec[j],Sal,Sas);
637 /* This is unrolled a few times below...
638 Although we're using HSV, we don't want hue/saturation
639 changes to have a strong effect on apparent brightness.
640 Apply a correction to V (not Y!) based on luma change. */
641 /* Calculate new RGB values at same time */
644 for(j = 0; j < todo; j++){
645 if(selection[j]>SELECT_THRESH){
646 HSpV_correct_RGB(Hvec[j],Svec[j],Vvec[j],Rvec[j],Gvec[j],Bvec[j]);
647 /* run S histogram at the same time as we've got
650 int bin = CLAMP((Svec[j]+HISTOFF)*HISTSCALE,0,HISTSIZE);
651 Shist[bin] += selection[j];
652 Shr[bin>>HRGBSHIFT] += Rvec[j]*selection[j];
653 Shg[bin>>HRGBSHIFT] += Gvec[j]*selection[j];
654 Shb[bin>>HRGBSHIFT] += Bvec[j]*selection[j];
659 for(j = 0; j < todo; j++){
660 HSpV_correct_RGB(Hvec[j],Svec[j],Vvec[j],Rvec[j],Gvec[j],Bvec[j]);
662 int bin = CLAMP((Svec[j]+HISTOFF)*HISTSCALE,0,HISTSIZE);
664 Shr[bin>>HRGBSHIFT] += Rvec[j];
665 Shg[bin>>HRGBSHIFT] += Gvec[j];
666 Shb[bin>>HRGBSHIFT] += Bvec[j];
673 for(j = 0; j < todo; j++){
674 if(selection[j]>SELECT_THRESH){
675 int bin = CLAMP((Svec[j]+HISTOFF)*HISTSCALE,0,HISTSIZE);
676 Shist[bin] += selection[j];
677 Shr[bin>>HRGBSHIFT] += Rvec[j]*selection[j];
678 Shg[bin>>HRGBSHIFT] += Gvec[j]*selection[j];
679 Shb[bin>>HRGBSHIFT] += Bvec[j]*selection[j];
683 for(j = 0; j < todo; j++){
684 int bin = CLAMP((Svec[j]+HISTOFF)*HISTSCALE,0,HISTSIZE);
686 Shr[bin>>HRGBSHIFT] += Rvec[j];
687 Shg[bin>>HRGBSHIFT] += Gvec[j];
688 Shb[bin>>HRGBSHIFT] += Bvec[j];
695 /* This one is a bit unlike the others; Value gamma
696 behavior is conditional. When < 1.0 (darkening the
697 picture) gamma directly operates on Value as normally
698 expected (thus scaling R G and B about zero). When
699 gamma > 1.0 (lightening the picture) it operates on the
700 Value scale's zero point rather than the Value. Both
701 are done to get the most natural behavior out of
702 saturation as gamma changes. The only drawback: One
703 can no longer reverse a gamma operation by applying the
704 inverse gamma in a subsequent step. */
709 for(j = 0; j < todo; j++)
710 if(selection[j]>SELECT_THRESH){
711 float scale = adj_lookup(Vvec[j],Val,Vas);
712 Vvec[j] = Vvec[j] * scale + Vshift;
713 Rvec[j] = Rvec[j] * scale + Vshift;
714 Gvec[j] = Gvec[j] * scale + Vshift;
715 Bvec[j] = Bvec[j] * scale + Vshift;
719 for(j = 0; j < todo; j++)
720 if(selection[j]>SELECT_THRESH){
721 float shift = adj_lookup(Vvec[j],Val,Vas);
722 Vvec[j] = Vvec[j] * Vscale + shift;
723 Rvec[j] = Rvec[j] * Vscale + shift;
724 Gvec[j] = Gvec[j] * Vscale + shift;
725 Bvec[j] = Bvec[j] * Vscale + shift;
731 for(j = 0; j < todo; j++){
732 float scale = adj_lookup(Vvec[j],Val,Vas);
733 Vvec[j] = Vvec[j] * scale + Vshift;
734 Rvec[j] = Rvec[j] * scale + Vshift;
735 Gvec[j] = Gvec[j] * scale + Vshift;
736 Bvec[j] = Bvec[j] * scale + Vshift;
740 for(j = 0; j < todo; j++){
741 float shift = adj_lookup(Vvec[j],Val,Vas);
742 Vvec[j] = Vvec[j] * Vscale + shift;
743 Rvec[j] = Rvec[j] * Vscale + shift;
744 Gvec[j] = Gvec[j] * Vscale + shift;
745 Bvec[j] = Bvec[j] * Vscale + shift;
754 for(j = 0; j < todo; j++){
755 if(selection[j]>SELECT_THRESH){
756 int bin = CLAMP((Vvec[j]+HISTOFF)*HISTSCALE,0,HISTSIZE);
757 Vhist[bin] += selection[j];
758 Vhr[bin>>HRGBSHIFT] += Rvec[j]*selection[j];
759 Vhg[bin>>HRGBSHIFT] += Gvec[j]*selection[j];
760 Vhb[bin>>HRGBSHIFT] += Bvec[j]*selection[j];
764 for(j = 0; j < todo; j++){
765 int bin = CLAMP((Vvec[j]+HISTOFF)*HISTSCALE,0,HISTSIZE);
767 Vhr[bin>>HRGBSHIFT] += Rvec[j];
768 Vhg[bin>>HRGBSHIFT] += Gvec[j];
769 Vhb[bin>>HRGBSHIFT] += Bvec[j];
778 for(j = 0; j < todo; j++){
779 if(selection[j]>SELECT_THRESH){
780 float weight = selection[j]*Svec[j];
781 int bin = CLAMP(Hvec[j]*HUESCALE,0,HISTSIZE);
782 Htotal += selection[j];
784 Hhist[bin] += weight;
785 Hhr[bin>>HRGBSHIFT] += Rvec[j]*weight;
786 Hhg[bin>>HRGBSHIFT] += Gvec[j]*weight;
787 Hhb[bin>>HRGBSHIFT] += Bvec[j]*weight;
791 for(j = 0; j < todo; j++){
792 if(selection[j]>SELECT_THRESH){
793 int bin = CLAMP((Svec[j]+HISTOFF)*HISTSCALE,0,HISTSIZE);
794 Shist[bin] += selection[j];
795 Shr[bin>>HRGBSHIFT] += Rvec[j]*selection[j];
796 Shg[bin>>HRGBSHIFT] += Gvec[j]*selection[j];
797 Shb[bin>>HRGBSHIFT] += Bvec[j]*selection[j];
801 for(j = 0; j < todo; j++){
802 if(selection[j]>SELECT_THRESH){
803 int bin = CLAMP((Vvec[j]+HISTOFF)*HISTSCALE,0,HISTSIZE);
804 Vhist[bin] += selection[j];
805 Vhr[bin>>HRGBSHIFT] += Rvec[j]*selection[j];
806 Vhg[bin>>HRGBSHIFT] += Gvec[j]*selection[j];
807 Vhb[bin>>HRGBSHIFT] += Bvec[j]*selection[j];
813 for(j = 0; j < todo; j++){
814 float weight = Svec[j];
815 int bin = CLAMP(Hvec[j]*HUESCALE,0,HISTSIZE);
818 Hhist[bin] += weight;
819 Hhr[bin>>HRGBSHIFT] += Rvec[j]*weight;
820 Hhg[bin>>HRGBSHIFT] += Gvec[j]*weight;
821 Hhb[bin>>HRGBSHIFT] += Bvec[j]*weight;
824 for(j = 0; j < todo; j++){
825 int bin = CLAMP((Svec[j]+HISTOFF)*HISTSCALE,0,HISTSIZE);
827 Shr[bin>>HRGBSHIFT] += Rvec[j];
828 Shg[bin>>HRGBSHIFT] += Gvec[j];
829 Shb[bin>>HRGBSHIFT] += Bvec[j];
832 for(j = 0; j < todo; j++){
833 int bin = CLAMP((Vvec[j]+HISTOFF)*HISTSCALE,0,HISTSIZE);
835 Vhr[bin>>HRGBSHIFT] += Rvec[j];
836 Vhg[bin>>HRGBSHIFT] += Gvec[j];
837 Vhb[bin>>HRGBSHIFT] += Bvec[j];
842 /* layer back into pipeline color format; master fader applies here */
843 switch(frame->get_color_model()) {
845 RGB_to_rgb8(Rvec,Gvec,Bvec,have_selection?selection:0,Aal,row_fragment,todo,3);
848 RGB_to_rgb8(Rvec,Gvec,Bvec,have_selection?selection:0,Aal,row_fragment,todo,4);
851 RGB_to_rgbF(Rvec,Gvec,Bvec,have_selection?selection:0,Aal,(float *)row_fragment,todo,3);
854 RGB_to_rgbF(Rvec,Gvec,Bvec,have_selection?selection:0,Aal,(float *)row_fragment,todo,4);
857 RGB_to_yuv8(Rvec,Gvec,Bvec,have_selection?selection:0,Aal,row_fragment,todo,3);
860 RGB_to_yuv8(Rvec,Gvec,Bvec,have_selection?selection:0,Aal,row_fragment,todo,4);
867 for(j = 0; j < todo; j++){
868 float A = have_selection ? selection[j] : 1.f;
870 if( (ant+rowi-j)&0x4 ){
882 if( (ant+rowi+j)&0x4 ){
896 /* re-layer back into pipeline color format */
897 switch(frame->get_color_model()) {
899 RGB_to_rgb8(Rvec,Gvec,Bvec,have_selection?selection:0,1.f,row_fragment,todo,3);
902 RGB_to_rgb8(Rvec,Gvec,Bvec,have_selection?selection:0,1.f,row_fragment,todo,4);
905 RGB_to_rgbF(Rvec,Gvec,Bvec,have_selection?selection:0,1.f,(float *)row_fragment,todo,3);
908 RGB_to_rgbF(Rvec,Gvec,Bvec,have_selection?selection:0,1.f,(float *)row_fragment,todo,4);
911 RGB_to_yuv8(Rvec,Gvec,Bvec,have_selection?selection:0,1.f,row_fragment,todo,3);
914 RGB_to_yuv8(Rvec,Gvec,Bvec,have_selection?selection:0,1.f,row_fragment,todo,4);
919 if(active || show_ants || (use_mask && capture_mask)){
921 if(use_mask && capture_mask){
922 switch(frame->get_color_model()) {
924 unmask_rgba8(row_fragment,todo);
927 unmask_rgbaF((float *)row_fragment,todo);
930 unmask_yuva8(row_fragment,todo);
935 /* lock to prevent interleaved cache coherency collisions
936 across cores. Two memcpys touching the same cache line
937 will cause the wings to fall off the processor. */
939 pthread_mutex_lock(&engine->copylock);
940 memcpy(row,row_fragment,byte_advance);
941 pthread_mutex_unlock(&engine->copylock);
949 pthread_mutex_lock(&engine->copylock);
951 plugin->hue_total+=Htotal;
952 plugin->hue_weight+=Hweight;
954 for(int i=0;i<HISTSIZE;i++){
955 plugin->red_histogram[i] += Rhist[i];
956 plugin->green_histogram[i] += Ghist[i];
957 plugin->blue_histogram[i] += Bhist[i];
959 plugin->hue_histogram[i] += Hhist[i];
960 plugin->sat_histogram[i] += Shist[i];
962 plugin->value_histogram[i] += Vhist[i];
965 for(int i=0;i<(HISTSIZE>>HRGBSHIFT);i++){
966 plugin->hue_histogram_red[i] += Hhr[i];
967 plugin->hue_histogram_green[i] += Hhg[i];
968 plugin->hue_histogram_blue[i] += Hhb[i];
970 plugin->sat_histogram_red[i] += Shr[i];
971 plugin->sat_histogram_green[i] += Shg[i];
972 plugin->sat_histogram_blue[i] += Shb[i];
974 plugin->value_histogram_red[i] += Vhr[i];
975 plugin->value_histogram_green[i] += Vhg[i];
976 plugin->value_histogram_blue[i] += Vhb[i];
978 pthread_mutex_unlock(&engine->copylock);
982 BluebananaEngine::BluebananaEngine(BluebananaMain *plugin, int total_clients,
983 int total_packages) : LoadServer(total_clients, total_packages){
984 this->plugin = plugin;
988 pthread_mutex_init(©lock,NULL);
989 pthread_mutex_init(&tasklock,NULL);
990 pthread_cond_init(&taskcond,NULL);
992 BluebananaEngine::~BluebananaEngine(){
993 pthread_cond_destroy(&taskcond);
994 pthread_mutex_destroy(&tasklock);
995 pthread_mutex_destroy(©lock);
996 if(selection_workA) delete[] selection_workA;
997 if(selection_workB) delete[] selection_workB;
1000 void BluebananaEngine::init_packages(){}
1002 LoadClient* BluebananaEngine::new_client(){
1003 return new BluebananaUnit(this, plugin);
1006 LoadPackage* BluebananaEngine::new_package(){
1007 return new BluebananaPackage(this);
1010 static float lt(float *data,float pos, int n){
1015 return data[i]*(1.f-del) + data[i+1]*del;
1018 static float lt_shift(float *data, float pos, int n, int over){
1026 for(int j=0; j<over; j++)
1028 for(int j=0; j<over; j++)
1031 float temp=(s0*(1.f-del) + s1*del);
1038 void BluebananaEngine::process_packages(VFrame *data){
1039 int w = data->get_w();
1040 int h = data->get_h();
1044 task_finish_count=0;
1046 /* If we're doing any spatial modification of the selection, we'll
1047 need to operate on a temporary selection array that covers the
1049 if(plugin->config.Fsel_active){
1050 if(plugin->config.Fsel_lo ||
1051 plugin->config.Fsel_mid ||
1052 plugin->config.Fsel_hi ||
1053 plugin->config.Fsel_over){
1054 selection_workA = new float[w*h];
1055 selection_workB = new float[w*h];
1059 memset(plugin->red_histogram,0,sizeof(plugin->red_histogram));
1060 memset(plugin->green_histogram,0,sizeof(plugin->green_histogram));
1061 memset(plugin->blue_histogram,0,sizeof(plugin->blue_histogram));
1062 memset(plugin->hue_histogram,0,sizeof(plugin->hue_histogram));
1063 plugin->hue_total=0.f;
1064 plugin->hue_weight=0.f;
1065 memset(plugin->sat_histogram,0,sizeof(plugin->sat_histogram));
1066 memset(plugin->value_histogram,0,sizeof(plugin->value_histogram));
1068 memset(plugin->hue_histogram_red,0,sizeof(plugin->hue_histogram_red));
1069 memset(plugin->hue_histogram_green,0,sizeof(plugin->hue_histogram_green));
1070 memset(plugin->hue_histogram_blue,0,sizeof(plugin->hue_histogram_blue));
1072 memset(plugin->sat_histogram_red,0,sizeof(plugin->sat_histogram_red));
1073 memset(plugin->sat_histogram_green,0,sizeof(plugin->sat_histogram_green));
1074 memset(plugin->sat_histogram_blue,0,sizeof(plugin->sat_histogram_blue));
1076 memset(plugin->value_histogram_red,0,sizeof(plugin->value_histogram_red));
1077 memset(plugin->value_histogram_green,0,sizeof(plugin->value_histogram_green));
1078 memset(plugin->value_histogram_blue,0,sizeof(plugin->value_histogram_blue));
1080 LoadServer::process_packages();
1082 /* The Hue histogram needs to be adjusted/shifted */
1083 if(plugin->config.active && plugin->hue_weight){
1085 float scale = plugin->hue_total/plugin->hue_weight;
1086 float Hshift = plugin->config.Hsel_active ? (plugin->config.Hsel_lo + plugin->config.Hsel_hi)/720.f-.5f : 0.f;
1087 float Hal = plugin->config.Hadj_active ? plugin->config.Hadj_val/60.f : 0.f;
1088 float hist[HISTSIZE + (1<<HRGBSHIFT)];
1089 float red[(HISTSIZE>>HRGBSHIFT)+1];
1090 float green[(HISTSIZE>>HRGBSHIFT)+1];
1091 float blue[(HISTSIZE>>HRGBSHIFT)+1];
1093 for(i=0;i<(1<<HRGBSHIFT);i++){
1094 plugin->hue_histogram[i]+=plugin->hue_histogram[HISTSIZE+i];
1095 plugin->hue_histogram[HISTSIZE+i]=plugin->hue_histogram[i];
1097 plugin->hue_histogram_red[0]+=plugin->hue_histogram_red[HISTSIZE>>HRGBSHIFT];
1098 plugin->hue_histogram_red[HISTSIZE>>HRGBSHIFT]=plugin->hue_histogram_red[0];
1099 plugin->hue_histogram_green[0]+=plugin->hue_histogram_green[HISTSIZE>>HRGBSHIFT];
1100 plugin->hue_histogram_green[HISTSIZE>>HRGBSHIFT]=plugin->hue_histogram_green[0];
1101 plugin->hue_histogram_blue[0]+=plugin->hue_histogram_blue[HISTSIZE>>HRGBSHIFT];
1102 plugin->hue_histogram_blue[HISTSIZE>>HRGBSHIFT]=plugin->hue_histogram_blue[0];
1104 for(i=0; i<(HISTSIZE>>HRGBSHIFT); i++){
1105 float pos = i+Hshift*(HISTSIZE>>HRGBSHIFT);
1106 if(pos<0)pos+=(HISTSIZE>>HRGBSHIFT);
1107 if(pos>=(HISTSIZE>>HRGBSHIFT))pos-=(HISTSIZE>>HRGBSHIFT);
1109 float div = lt_shift(plugin->hue_histogram,i+Hshift*(HISTSIZE>>HRGBSHIFT),
1110 (HISTSIZE>>HRGBSHIFT), (1<<HRGBSHIFT));
1111 red[i] = lt(plugin->hue_histogram_red,i+Hshift*(HISTSIZE>>HRGBSHIFT),
1112 (HISTSIZE>>HRGBSHIFT))*div;
1113 green[i] = lt(plugin->hue_histogram_green,i+Hshift*(HISTSIZE>>HRGBSHIFT),
1114 (HISTSIZE>>HRGBSHIFT))*div;
1115 blue[i] = lt(plugin->hue_histogram_blue,i+Hshift*(HISTSIZE>>HRGBSHIFT),
1116 (HISTSIZE>>HRGBSHIFT))*div;
1119 for(int i=0; i<HISTSIZE; i++)
1120 hist[i] = lt(plugin->hue_histogram,i+Hshift*HISTSIZE,HISTSIZE)*scale;
1122 memcpy(hist+HISTSIZE,hist,sizeof(*hist)*(1<<HRGBSHIFT));
1123 memcpy(plugin->hue_histogram,hist,sizeof(hist));
1125 red[HISTSIZE>>HRGBSHIFT]=red[0];
1126 green[HISTSIZE>>HRGBSHIFT]=green[0];
1127 blue[HISTSIZE>>HRGBSHIFT]=blue[0];
1129 for(i=0,j=0; i<=(HISTSIZE>>HRGBSHIFT); i++){
1130 float sum=0.f,H,S,V;
1131 for(int k=0; k<(1<<HRGBSHIFT); j++,k++)
1134 RGB_to_HSpV(red[i],green[i],blue[i],H,S,V);
1138 HSpV_to_RGB(H,S,V,red[i],green[i],blue[i]);
1140 plugin->hue_histogram_red[i] = red[i] * sum;
1141 plugin->hue_histogram_green[i] = green[i] * sum;
1142 plugin->hue_histogram_blue[i] = blue[i] * sum;
1146 if(selection_workA){
1147 delete[] selection_workA;
1150 if(selection_workB){
1151 delete[] selection_workB;
1156 /* create a coordinated work-division list and join point */
1157 void BluebananaEngine::set_task(int n, const char *task){
1158 pthread_mutex_lock(&this->tasklock);
1159 if(task_init_state==0){
1160 //fprintf(stderr,"New task!: %s",task);
1162 task_finish_count=get_total_packages();
1166 pthread_mutex_unlock(&this->tasklock);
1169 /* fetch the next task ticket. If the task is complete, wait here for
1170 all package threads to complete before returning <0 */
1171 int BluebananaEngine::next_task(){
1172 pthread_mutex_lock(&tasklock);
1175 //fprintf(stderr,".");
1176 pthread_mutex_unlock(&tasklock);
1179 task_finish_count--;
1180 if(task_finish_count==0){
1182 //fprintf(stderr,"done\n");
1183 pthread_cond_broadcast(&taskcond);
1185 int serial = task_init_serial;
1186 while(task_finish_count && serial == task_init_serial){
1187 //fprintf(stderr,"+");
1188 pthread_cond_wait(&taskcond,&tasklock);
1191 pthread_mutex_unlock(&tasklock);
1192 //fprintf(stderr,"-");
1197 /* same as above, but waits for join without fetching a task slot */
1198 void BluebananaEngine::wait_task(){
1199 pthread_mutex_lock(&tasklock);
1200 task_finish_count--;
1201 if(task_finish_count==0){
1203 //fprintf(stderr,"done\n");
1204 pthread_cond_broadcast(&taskcond);
1206 int serial = task_init_serial;
1207 while(task_finish_count && serial == task_init_serial){
1208 //fprintf(stderr,"+");
1209 pthread_cond_wait(&taskcond,&tasklock);
1212 pthread_mutex_unlock(&tasklock);
1213 //fprintf(stderr,"-");