fix mask vframe setup, add unshared vframe constructor
[goodguy/history.git] / cinelerra-5.1 / plugins / crikey / crikey.C
1 /*
2  * CINELERRA
3  * Copyright (C) 1997-2015 Adam Williams <broadcast at earthling dot net>
4  *
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.
9  *
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.
14  *
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
18  *
19  */
20
21 #include<stdio.h>
22 #include<stdint.h>
23 #include<math.h>
24 #include<string.h>
25
26 #include "arraylist.h"
27 #include "bccmodels.h"
28 #include "bccolors.h"
29 #include "clip.h"
30 #include "edlsession.h"
31 #include "filexml.h"
32 #include "crikey.h"
33 #include "crikeywindow.h"
34 #include "language.h"
35 #include "vframe.h"
36
37 // chroma interpolated key, crikey
38
39 REGISTER_PLUGIN(CriKey)
40
41 #if 0
42 void crikey_pgm(const char *fn,VFrame *vfrm)
43 {
44         FILE *fp = fopen(fn,"w");
45         int w = vfrm->get_w(), h = vfrm->get_h();
46         fprintf(fp,"P5\n%d %d\n255\n",w,h);
47         fwrite(vfrm->get_data(),w,h,fp);
48         fclose(fp);
49 }
50 #endif
51
52 CriKeyPoint::CriKeyPoint(int t, int e, float x, float y)
53 {
54         this->t = t;  this->e = e; this->x = x; this->y = y;
55 }
56 CriKeyPoint::~CriKeyPoint()
57 {
58 }
59
60 CriKeyConfig::CriKeyConfig()
61 {
62         color = 0x000000;
63         threshold = 0.5f;
64         draw_mode = DRAW_ALPHA;
65         drag = 0;
66         selected = 0;
67 }
68 CriKeyConfig::~CriKeyConfig()
69 {
70         points.remove_all_objects();
71 }
72
73 int CriKeyConfig::equivalent(CriKeyConfig &that)
74 {
75         if( this->color != that.color ) return 0;
76         if( !EQUIV(this->threshold, that.threshold) ) return 0;
77         if( this->draw_mode != that.draw_mode ) return 0;
78         if( this->drag != that.drag ) return 0;
79         if( this->points.size() != that.points.size() ) return 0;
80         for( int i=0, n=points.size(); i<n; ++i ) {
81                 CriKeyPoint *ap = this->points[i], *bp = that.points[i];
82                 if( ap->t != bp->t ) return 0;
83                 if( ap->e != bp->e ) return 0;
84                 if( !EQUIV(ap->x, bp->x) ) return 0;
85                 if( !EQUIV(ap->y, bp->y) ) return 0;
86         }
87         return 1;
88 }
89
90 void CriKeyConfig::copy_from(CriKeyConfig &that)
91 {
92         this->color = that.color;
93         this->threshold = that.threshold;
94         this->draw_mode = that.draw_mode;
95         this->drag = that.drag;
96         this->selected = that.selected;
97
98         points.remove_all_objects();
99         for( int i=0,n=that.points.size(); i<n; ++i ) {
100                 CriKeyPoint *pt = that.points[i];
101                 add_point(pt->t, pt->e, pt->x, pt->y);
102         }
103 }
104
105 void CriKeyConfig::interpolate(CriKeyConfig &prev, CriKeyConfig &next,
106                 long prev_frame, long next_frame, long current_frame)
107 {
108         this->color = prev.color;
109         this->draw_mode = prev.draw_mode;
110         this->drag = prev.drag;
111         this->selected = prev.selected;
112
113         double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
114         double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
115         this->threshold = prev.threshold * prev_scale + next.threshold * next_scale;
116  // interpolate rgb components
117         float prev_target[3];  set_target(0, prev.color, prev_target);
118         float next_target[3];  set_target(0, next.color, next_target);
119         float target[3];
120         for( int i=0; i<3; ++i )
121                 target[i] = prev_target[i] * prev_scale + next_target[i] * next_scale;
122         set_color(0, target, this->color);
123
124         points.remove_all_objects();
125         int prev_sz = prev.points.size(), next_sz = next.points.size();
126         for( int i=0; i<prev_sz; ++i ) {
127                 CriKeyPoint *pt = prev.points[i], *nt = 0;
128                 float x = pt->x, y = pt->y;
129                 int k = next_sz;  // associated by tag id in next
130                 while( --k >= 0 && pt->t != (nt=next.points[k])->t );
131                 if( k >= 0 ) {
132                         x = x * prev_scale + nt->x * next_scale;
133                         y = y * prev_scale + nt->y * next_scale;
134                 }
135                 add_point(pt->t, pt->e, x, y);
136         }
137 }
138
139 void CriKeyConfig::limits()
140 {
141         bclamp(threshold, 0.0f, 1.0f);
142         bclamp(draw_mode, 0, DRAW_MODES-1);
143 }
144
145 int CriKeyConfig::add_point(int t, int e, float x, float y)
146 {
147         int k = points.size();
148         if( t < 0 ) {
149                 t = 0;
150                 for( int i=k; --i>=0; ) {
151                         int n = points[i]->t;
152                         if( n >= t ) t = n + 1;
153                 }
154         }
155         points.append(new CriKeyPoint(t, e, x, y));
156         return k;
157 }
158
159 void CriKeyConfig::del_point(int i)
160 {
161         points.remove_object_number(i);
162 }
163
164
165 class FillRegion
166 {
167         class segment { public: int y, lt, rt; };
168         ArrayList<segment> stack;
169
170         void push(int y, int lt, int rt) {
171                 segment &seg = stack.append();
172                 seg.y = y;  seg.lt = lt;  seg.rt = rt;
173         }
174         void pop(int &y, int &lt, int &rt) {
175                 segment &seg = stack.last();
176                 y = seg.y;  lt = seg.lt;  rt = seg.rt;
177                 stack.remove();
178         }
179  
180         int w, h;
181         uint8_t *data, *mask;
182         bool edge_pixel(uint8_t *dp) { return *dp; }
183
184 public:
185         void fill(int x, int y);
186         void run();
187
188         FillRegion(VFrame *d, VFrame *m);
189 };
190
191 FillRegion::FillRegion(VFrame *d, VFrame *m)
192 {
193         w = d->get_w();
194         h = d->get_h();
195         data = d->get_data();
196         mask = m->get_data();
197 }
198
199 void FillRegion::fill(int x, int y)
200 {
201         push(y, x, x);
202 }
203
204 void FillRegion::run()
205 {
206         while( stack.size() > 0 ) {
207                 int y, ilt, irt;
208                 pop(y, ilt, irt);
209                 int ofs = y*w + ilt;
210                 uint8_t *idp = data + ofs;
211                 uint8_t *imp = mask + ofs;
212                 for( int x=ilt; x<=irt; ++x,++imp,++idp ) {
213                         if( !*imp ) continue;
214                         *imp = 0;
215                         if( edge_pixel(idp) ) continue;
216                         int lt = x, rt = x;
217                         uint8_t *ldp = idp, *lmp = imp;
218                         for( int i=lt; --i>=0; ) {
219                                 if( !*--lmp ) break;
220                                 *lmp = 0;  lt = i;
221                                 if( edge_pixel(--ldp) ) break;
222                         }
223                         uint8_t *rdp = idp, *rmp = imp;
224                         for( int i=rt; ++i< w; rt=i,*rmp=0 ) {
225                                 if( !*++rmp ) break;
226                                 *rmp = 0;  rt = i;
227                                 if( edge_pixel(++rdp) ) break;
228                         }
229                         if( y+1 <  h ) push(y+1, lt, rt);
230                         if( y-1 >= 0 ) push(y-1, lt, rt);
231                 }
232         }
233 }
234
235
236 CriKey::CriKey(PluginServer *server)
237  : PluginVClient(server)
238 {
239         engine = 0;
240         msk = 0;
241         dst = 0;
242 }
243
244 CriKey::~CriKey()
245 {
246         delete engine;
247         delete msk;
248         delete dst;
249 }
250
251 void CriKeyConfig::set_target(int is_yuv, int color, float *target)
252 {
253         float r = ((color>>16) & 0xff) / 255.0f;
254         float g = ((color>> 8) & 0xff) / 255.0f;
255         float b = ((color>> 0) & 0xff) / 255.0f;
256         if( is_yuv ) {
257                 float y, u, v;
258                 YUV::rgb_to_yuv_f(r,g,b, y,u,v);
259                 target[0] = y;
260                 target[1] = u + 0.5f;
261                 target[2] = v + 0.5f;
262         }
263         else {
264                 target[0] = r;
265                 target[1] = g;
266                 target[2] = b;
267         }
268 }
269 void CriKeyConfig::set_color(int is_yuv, float *target, int &color)
270 {
271         float r = target[0];
272         float g = target[1];
273         float b = target[2];
274         if( is_yuv ) {
275                 float y = r, u = g-0.5f, v = b-0.5f;
276                 YUV::yuv_to_rgb_f(y,u,v, r,g,b);
277         }
278         int ir = r >= 1 ? 0xff : r < 0 ? 0 : (int)(r * 256);
279         int ig = g >= 1 ? 0xff : g < 0 ? 0 : (int)(g * 256);
280         int ib = b >= 1 ? 0xff : b < 0 ? 0 : (int)(b * 256);
281         color = (ir << 16) | (ig << 8) | (ib << 0);
282 }
283
284 void CriKey::get_color(int x, int y)
285 {
286         if( x < 0 || x >= w ) return;
287         if( y < 0 || y >= h ) return;
288         uint8_t **src_rows = src->get_rows();
289         uint8_t *sp = src_rows[y] + x*bpp;
290         if( is_float ) {
291                 float *fp = (float *)sp;
292                 for( int i=0; i<comp; ++i,++fp )
293                         target[i] = *fp;
294         }
295         else {
296                 float scale = 1./255;
297                 for( int i=0; i<comp; ++i,++sp )
298                         target[i] = *sp * scale;
299         }
300 }
301
302 const char* CriKey::plugin_title() { return _("CriKey"); }
303 int CriKey::is_realtime() { return 1; }
304
305 NEW_WINDOW_MACRO(CriKey, CriKeyWindow);
306 LOAD_CONFIGURATION_MACRO(CriKey, CriKeyConfig)
307
308 int CriKey::new_point()
309 {
310         EDLSession *session = get_edlsession();
311         float x = !session ? 0.f : session->output_w / 2.f;
312         float y = !session ? 0.f : session->output_h / 2.f;
313         return config.add_point(-1, 0, x, y);
314 }
315
316 void CriKey::save_data(KeyFrame *keyframe)
317 {
318         FileXML output;
319
320 // cause data to be stored directly in text
321         output.set_shared_output(keyframe->get_data(), MESSAGESIZE);
322
323         output.tag.set_title("CRIKEY");
324         output.tag.set_property("COLOR", config.color);
325         output.tag.set_property("THRESHOLD", config.threshold);
326         output.tag.set_property("DRAW_MODE", config.draw_mode);
327         output.tag.set_property("DRAG", config.drag);
328         output.tag.set_property("SELECTED", config.selected);
329         output.append_tag();
330         output.append_newline();
331         output.tag.set_title("/CRIKEY");
332         output.append_tag();
333         output.append_newline();
334         for( int i=0, n = config.points.size(); i<n; ++i ) {
335                 CriKeyPoint *pt = config.points[i];
336                 char point[BCSTRLEN];
337                 sprintf(point,"/POINT_%d",pt->t);
338                 output.tag.set_title(point+1);
339                 output.tag.set_property("E", pt->e);
340                 output.tag.set_property("X", pt->x);
341                 output.tag.set_property("Y", pt->y);
342                 output.append_tag();
343                 output.tag.set_title(point+0);
344                 output.append_tag();
345                 output.append_newline();
346         }
347         output.terminate_string();
348 }
349
350 void CriKey::read_data(KeyFrame *keyframe)
351 {
352         FileXML input;
353         input.set_shared_input(keyframe->get_data(), strlen(keyframe->get_data()));
354         config.points.remove_all_objects();
355         int result = 0;
356
357         while( !(result=input.read_tag()) ) {
358                 if( input.tag.title_is("CRIKEY") ) {
359                         config.color = input.tag.get_property("COLOR", config.color);
360                         config.threshold = input.tag.get_property("THRESHOLD", config.threshold);
361                         config.draw_mode = input.tag.get_property("DRAW_MODE", config.draw_mode);
362                         config.drag = input.tag.get_property("DRAG", config.drag);
363                         config.selected = input.tag.get_property("SELECTED", 0);
364                         config.limits();
365                 }
366                 else if( !strncmp(input.tag.get_title(),"POINT_",6) ) {
367                         int t = atoi(input.tag.get_title() + 6);
368                         int e = input.tag.get_property("E", 0);
369                         float x = input.tag.get_property("X", 0.f);
370                         float y = input.tag.get_property("Y", 0.f);
371                         config.add_point(t, e, x, y);
372                 }
373         }
374
375         if( !config.points.size() ) new_point();
376 }
377
378 void CriKey::update_gui()
379 {
380         if( !thread ) return;
381         if( !load_configuration() ) return;
382         thread->window->lock_window("CriKey::update_gui");
383         CriKeyWindow *window = (CriKeyWindow*)thread->window;
384         window->update_gui();
385         window->flush();
386         thread->window->unlock_window();
387 }
388
389 void CriKey::draw_alpha(VFrame *msk)
390 {
391         uint8_t **src_rows = src->get_rows();
392         uint8_t **msk_rows = msk->get_rows();
393         switch( color_model ) {
394         case BC_RGB_FLOAT:
395                 for( int y=0; y<h; ++y ) {
396                         uint8_t *sp = src_rows[y], *mp = msk_rows[y];
397                         for( int x=0; x<w; ++x,++mp,sp+=bpp ) {
398                                 if( *mp ) continue;
399                                 float *px = (float *)sp;
400                                 px[0] = px[1] = px[2] = 0;
401                         }
402                 }
403                 break;
404         case BC_RGBA_FLOAT:
405                 for( int y=0; y<h; ++y ) {
406                         uint8_t *sp = src_rows[y], *mp = msk_rows[y];
407                         for( int x=0; x<w; ++x,++mp,sp+=bpp ) {
408                                 if( *mp ) continue;
409                                 float *px = (float *)sp;
410                                 px[3] = 0;
411                         }
412                 }
413                 break;
414         case BC_RGB888:
415                 for( int y=0; y<h; ++y ) {
416                         uint8_t *sp = src_rows[y], *mp = msk_rows[y];
417                         for( int x=0; x<w; ++x,++mp,sp+=bpp ) {
418                                 if( *mp ) continue;
419                                 uint8_t *px = sp;
420                                 px[0] = px[1] = px[2] = 0;
421                         }
422                 }
423                 break;
424         case BC_YUV888:
425                 for( int y=0; y<h; ++y ) {
426                         uint8_t *sp = src_rows[y], *mp = msk_rows[y];
427                         for( int x=0; x<w; ++x,++mp,sp+=bpp ) {
428                                 if( *mp ) continue;
429                                 uint8_t *px = sp;
430                                 px[0] = 0;
431                                 px[1] = px[2] = 0x80;
432                         }
433                 }
434                 break;
435         case BC_RGBA8888:
436         case BC_YUVA8888:
437                 for( int y=0; y<h; ++y ) {
438                         uint8_t *sp = src_rows[y], *mp = msk_rows[y];
439                         for( int x=0; x<w; ++x,++mp,sp+=bpp ) {
440                                 if( *mp ) continue;
441                                 uint8_t *px = sp;
442                                 px[3] = 0;
443                         }
444                 }
445                 break;
446         }
447 }
448
449 void CriKey::draw_mask(VFrame *msk)
450 {
451         uint8_t **src_rows = src->get_rows();
452         uint8_t **msk_rows = msk->get_rows();
453         float scale = 1 / 255.0f;
454         switch( color_model ) {
455         case BC_RGB_FLOAT:
456                 for( int y=0; y<h; ++y ) {
457                         uint8_t *sp = src_rows[y], *mp = msk_rows[y];
458                         for( int x=0; x<w; ++x,++mp,sp+=bpp ) {
459                                 float a = *mp * scale;
460                                 float *px = (float *)sp;
461                                 px[0] = px[1] = px[2] = a;
462                         }
463                 }
464                 break;
465         case BC_RGBA_FLOAT:
466                 for( int y=0; y<h; ++y ) {
467                         uint8_t *sp = src_rows[y], *mp = msk_rows[y];
468                         for( int x=0; x<w; ++x,++mp,sp+=bpp ) {
469                                 float a = *mp * scale;
470                                 float *px = (float *)sp;
471                                 px[0] = px[1] = px[2] = a;
472                                 px[3] = 1.0f;
473                         }
474                 }
475                 break;
476         case BC_RGB888:
477                 for( int y=0; y<h; ++y ) {
478                         uint8_t *sp = src_rows[y], *mp = msk_rows[y];
479                         for( int x=0; x<w; ++x,++mp,sp+=bpp ) {
480                                 float a = *mp * scale;
481                                 uint8_t *px = sp;
482                                 px[0] = px[1] = px[2] = a * 255;
483                         }
484                 }
485                 break;
486         case BC_RGBA8888:
487                 for( int y=0; y<h; ++y ) {
488                         uint8_t *sp = src_rows[y], *mp = msk_rows[y];
489                         for( int x=0; x<w; ++x,++mp,sp+=bpp ) {
490                                 float a = *mp * scale;
491                                 uint8_t *px = sp;
492                                 px[0] = px[1] = px[2] = a * 255;
493                                 px[3] = 0xff;
494                         }
495                 }
496                 break;
497         case BC_YUV888:
498                 for( int y=0; y<h; ++y ) {
499                         uint8_t *sp = src_rows[y], *mp = msk_rows[y];
500                         for( int x=0; x<w; ++x,++mp,sp+=bpp ) {
501                                 float a = *mp * scale;
502                                 uint8_t *px = sp;
503                                 px[0] = a * 255;
504                                 px[1] = px[2] = 0x80;
505                         }
506                 }
507                 break;
508         case BC_YUVA8888:
509                 for( int y=0; y<h; ++y ) {
510                         uint8_t *sp = src_rows[y], *mp = msk_rows[y];
511                         for( int x=0; x<w; ++x,++mp,sp+=bpp ) {
512                                 float a = *mp * scale;
513                                 uint8_t *px = sp;
514                                 px[0] = a * 255;
515                                 px[1] = px[2] = 0x80;
516                                 px[3] = 0xff;
517                         }
518                 }
519                 break;
520         }
521 }
522
523 void CriKey::draw_point(VFrame *src, CriKeyPoint *pt)
524 {
525         int d = bmax(w,h) / 200 + 2;
526         int r = d/2+1, x = pt->x, y = pt->y;
527         src->draw_smooth(x-r,y+0, x-r, y-r, x+0,y-r);
528         src->draw_smooth(x+0,y-r, x+r, y-r, x+r,y+0);
529         src->draw_smooth(x+r,y+0, x+r, y+r, x+0,y+r);
530         src->draw_smooth(x+0,y+r, x-r, y+r, x-r,y+0);
531         if( pt->e ) {
532                 src->set_pixel_color(RED);
533                 src->draw_x(pt->x, pt->y, d);
534         }
535         else {
536                 src->set_pixel_color(BLUE);
537                 src->draw_t(pt->x, pt->y, d);
538         }
539 }
540
541 int CriKey::process_buffer(VFrame *frame, int64_t start_position, double frame_rate)
542 {
543         load_configuration();
544         src = frame;
545         w = src->get_w(), h = src->get_h();
546         color_model = src->get_color_model();
547         bpp = BC_CModels::calculate_pixelsize(color_model);
548         comp = BC_CModels::components(color_model);
549         if( comp > 3 ) comp = 3;
550         is_yuv = BC_CModels::is_yuv(color_model);
551         is_float = BC_CModels::is_float(color_model);
552
553         read_frame(src, 0, start_position, frame_rate, 0);
554
555         set_target(is_yuv, config.color, target);
556
557         if( dst && ( dst->get_w() != w || src->get_h() != h ) ) {
558                 delete dst;  dst = 0;
559         }
560         if( !dst )
561                 dst = new VFrame(w, h, BC_A8, 0);
562         dst->clear_frame();
563
564         if( !engine )
565                 engine = new CriKeyEngine(this,
566                         PluginClient::get_project_smp() + 1,
567                         PluginClient::get_project_smp() + 1);
568         engine->process_packages();
569 // copy fill btm/rt edges
570         int w1 = w-1, h1 = h-1;
571         uint8_t *dp = dst->get_data();
572         if( w1 > 0 ) for( int y=0; y<h1; ++y,dp+=w ) dp[w1] = dp[w1-1];
573         if( h1 > 0 ) for( int x=0; x<w; ++x ) dp[x] = dp[x-w];
574 //crikey_pgm("/tmp/dst.pgm",dst);
575
576         if( config.draw_mode != DRAW_EDGE ) {
577                 if( msk && ( msk->get_w() != w || msk->get_h() != h ) ) {
578                         delete msk;  msk = 0;
579                 }
580                 if( !msk )
581                         msk = new VFrame(w, h, BC_A8, 0);
582                 memset(msk->get_data(), 0xff, msk->get_data_size());
583
584                 FillRegion fill_region(dst, msk);
585                 for( int i=0, n=config.points.size(); i<n; ++i ) {
586                         CriKeyPoint *pt = config.points[i];
587                         if( !pt->e ) continue;
588                         float x = pt->x, y = pt->y;
589                         if( x >= 0 && x < w && y >= 0 && y < h )
590                                 fill_region.fill(x, y);
591                 }
592                 fill_region.run();
593
594 //crikey_pgm("/tmp/msk.pgm",msk);
595
596                 if( config.draw_mode == DRAW_MASK )
597                         draw_mask(msk);
598                 else
599                         draw_alpha(msk);
600         }
601         else
602                 draw_mask(dst);
603
604         if( config.drag ) {
605                 for( int i=0, n=config.points.size(); i<n; ++i ) {
606                         CriKeyPoint *pt = config.points[i];
607                         src->set_pixel_color(config.selected == i ? GREEN : WHITE);
608                         draw_point(src, pt);
609                 }
610         }
611         return 0;
612 }
613
614
615 void CriKeyEngine::init_packages()
616 {
617         int y = 0, h1 = plugin->h-1;
618         for(int i = 0; i < get_total_packages(); ) {
619                 CriKeyPackage *pkg = (CriKeyPackage*)get_package(i++);
620                 pkg->y1 = y;
621                 y = h1 * i / LoadServer::get_total_packages();
622                 pkg->y2 = y;
623         }
624 }
625
626 LoadPackage* CriKeyEngine::new_package()
627 {
628         return new CriKeyPackage();
629 }
630
631 LoadClient* CriKeyEngine::new_client()
632 {
633         return new CriKeyUnit(this);
634 }
635
636 #define EDGE_MACRO(type, max, components, is_yuv) \
637 { \
638         uint8_t **src_rows = src->get_rows(); \
639         int comps = MIN(components, 3); \
640         float scale = 1.0f/max; \
641         for( int y=y1; y<y2; ++y ) { \
642                 uint8_t *row0 = src_rows[y], *row1 = src_rows[y+1]; \
643                 uint8_t *outp = dst_rows[y]; \
644                 for( int v,x=x1; x<x2; *outp++=v,++x,row0+=bpp,row1+=bpp ) { \
645                         type *r0 = (type*)row0, *r1 = (type*)row1; \
646                         float a00 = 0, a01 = 0, a10 = 0, a11 = 0; \
647                         for( int i=0; i<comps; ++i,++r0,++r1 ) { \
648                                 float t = target[i]; \
649                                 a00 += fabs(t - r0[0]*scale); \
650                                 a01 += fabs(t - r0[components]*scale); \
651                                 a10 += fabs(t - r1[0]*scale); \
652                                 a11 += fabs(t - r1[components]*scale); \
653                         } \
654                         v = 0; \
655                         float a = bmin(bmin(a00, a01), bmin(a10, a11)); \
656                         if( a > threshold ) continue; \
657                         float b = bmax(bmax(a00, a01), bmax(a10, a11)); \
658                         if( threshold >= b ) continue; \
659                         v = 255; \
660                 } \
661         } \
662 } break
663
664
665 void CriKeyUnit::process_package(LoadPackage *package)
666 {
667         VFrame *src = server->plugin->src;
668         int bpp = server->plugin->bpp;
669         VFrame *dst = server->plugin->dst;
670         uint8_t **dst_rows = dst->get_rows();
671         float *target = server->plugin->target;
672         float threshold = server->plugin->config.threshold;
673         CriKeyPackage *pkg = (CriKeyPackage*)package;
674         int x1 = 0, x2 = server->plugin->w-1;
675         int y1 = pkg->y1, y2 = pkg->y2;
676
677         switch( src->get_color_model() ) {
678         case BC_RGB_FLOAT:  EDGE_MACRO(float, 1, 3, 0);
679         case BC_RGBA_FLOAT: EDGE_MACRO(float, 1, 4, 0);
680         case BC_RGB888:     EDGE_MACRO(unsigned char, 0xff, 3, 0);
681         case BC_YUV888:     EDGE_MACRO(unsigned char, 0xff, 3, 1);
682         case BC_RGBA8888:   EDGE_MACRO(unsigned char, 0xff, 4, 0);
683         case BC_YUVA8888:   EDGE_MACRO(unsigned char, 0xff, 4, 1);
684         }
685 }
686