r370: Heroine Virutal's official release 1.2.1
[cinelerra_cv/mob.git] / hvirtual / cinelerra / maskengine.C
blobfc84e531cc259dcdcc36ff1e528efbf9d352a10f
1 #include "condition.h"
2 #include "clip.h"
3 #include "maskauto.h"
4 #include "maskautos.h"
5 #include "maskengine.h"
6 #include "mutex.h"
7 #include "vframe.h"
9 #include <math.h>
10 #include <stdint.h>
11 #include <string.h>
13 MaskPackage::MaskPackage()
15         apply_mutex = new Condition(1, "MaskPackage::apply_mutex");
18 MaskPackage::~MaskPackage()
20         delete apply_mutex;
29 MaskUnit::MaskUnit(MaskEngine *engine)
30  : LoadClient(engine)
32         this->engine = engine;
33         this->temp = 0;
37 MaskUnit::~MaskUnit()
39         if(temp) delete temp;
42 #ifndef SQR
43 #define SQR(x) ((x) * (x))
44 #endif
46 #define OVERSAMPLE 8
63 void MaskUnit::draw_line_clamped(VFrame *frame, 
64         int &x1, 
65         int &y1, 
66         int x2, 
67         int y2,
68         unsigned char k)
70         int draw_x1;
71         int draw_y1;
72         int draw_x2;
73         int draw_y2;
74         unsigned char value;
76         if(y2 < y1)
77         {
78                 draw_x1 = x2;
79                 draw_y1 = y2;
80                 draw_x2 = x1;
81                 draw_y2 = y1;
82         }
83         else
84         {
85                 draw_x1 = x1;
86                 draw_y1 = y1;
87                 draw_x2 = x2;
88                 draw_y2 = y2;
89         }
91         unsigned char **rows = (unsigned char**)frame->get_rows();
93         if(draw_y2 != draw_y1)
94         {
95                 float slope = ((float)draw_x2 - draw_x1) / ((float)draw_y2 - draw_y1);
96                 int w = frame->get_w() - 1;
97                 int h = frame->get_h();
99                 for(float y = draw_y1; y < draw_y2; y++)
100                 {
101                         if(y >= 0 && y < h)
102                         {
103                                 int x = (int)((y - draw_y1) * slope + draw_x1);
104                                 int y_i = (int)y;
105                                 int x_i = CLIP(x, 0, w);
107                                 if(rows[y_i][x_i] == k)
108                                         rows[y_i][x_i] = 0;
109                                 else
110                                         rows[y_i][x_i] = k;
111                         }
112                 }
113         }
116 void MaskUnit::blur_strip(float *val_p, 
117         float *val_m, 
118         float *dst, 
119         float *src, 
120         int size,
121         int max)
123         float *sp_p = src;
124         float *sp_m = src + size - 1;
125         float *vp = val_p;
126         float *vm = val_m + size - 1;
127         float initial_p = sp_p[0];
128         float initial_m = sp_m[0];
130 //printf("MaskUnit::blur_strip %d\n", size);
131         for(int k = 0; k < size; k++)
132         {
133                 int terms = (k < 4) ? k : 4;
134                 int l;
135                 for(l = 0; l <= terms; l++)
136                 {
137                         *vp += n_p[l] * sp_p[-l] - d_p[l] * vp[-l];
138                         *vm += n_m[l] * sp_m[l] - d_m[l] * vm[l];
139                 }
141                 for( ; l <= 4; l++)
142                 {
143                         *vp += (n_p[l] - bd_p[l]) * initial_p;
144                         *vm += (n_m[l] - bd_m[l]) * initial_m;
145                 }
146                 sp_p++;
147                 sp_m--;
148                 vp++;
149                 vm--;
150         }
152         for(int i = 0; i < size; i++)
153         {
154                 float sum = val_p[i] + val_m[i];
155                 CLAMP(sum, 0, max);
156                 dst[i] = sum;
157         }
160 void MaskUnit::do_feather(VFrame *output,
161         VFrame *input, 
162         float feather, 
163         int start_out, 
164         int end_out)
166 //printf("MaskUnit::do_feather %f\n", feather);
167 // Get constants
168         double constants[8];
169         double div;
170         double std_dev = sqrt(-(double)(feather * feather) / (2 * log(1.0 / 255.0)));
171         div = sqrt(2 * M_PI) * std_dev;
172         constants[0] = -1.783 / std_dev;
173         constants[1] = -1.723 / std_dev;
174         constants[2] = 0.6318 / std_dev;
175         constants[3] = 1.997  / std_dev;
176         constants[4] = 1.6803 / div;
177         constants[5] = 3.735 / div;
178         constants[6] = -0.6803 / div;
179         constants[7] = -0.2598 / div;
181         n_p[0] = constants[4] + constants[6];
182         n_p[1] = exp(constants[1]) *
183                                 (constants[7] * sin(constants[3]) -
184                                 (constants[6] + 2 * constants[4]) * cos(constants[3])) +
185                                 exp(constants[0]) *
186                                 (constants[5] * sin(constants[2]) -
187                                 (2 * constants[6] + constants[4]) * cos(constants[2]));
189         n_p[2] = 2 * exp(constants[0] + constants[1]) *
190                                 ((constants[4] + constants[6]) * cos(constants[3]) * 
191                                 cos(constants[2]) - constants[5] * 
192                                 cos(constants[3]) * sin(constants[2]) -
193                                 constants[7] * cos(constants[2]) * sin(constants[3])) +
194                                 constants[6] * exp(2 * constants[0]) +
195                                 constants[4] * exp(2 * constants[1]);
197         n_p[3] = exp(constants[1] + 2 * constants[0]) *
198                                 (constants[7] * sin(constants[3]) - 
199                                 constants[6] * cos(constants[3])) +
200                                 exp(constants[0] + 2 * constants[1]) *
201                                 (constants[5] * sin(constants[2]) - constants[4] * 
202                                 cos(constants[2]));
203         n_p[4] = 0.0;
205         d_p[0] = 0.0;
206         d_p[1] = -2 * exp(constants[1]) * cos(constants[3]) -
207                                 2 * exp(constants[0]) * cos(constants[2]);
209         d_p[2] = 4 * cos(constants[3]) * cos(constants[2]) * 
210                                 exp(constants[0] + constants[1]) +
211                                 exp(2 * constants[1]) + exp (2 * constants[0]);
213         d_p[3] = -2 * cos(constants[2]) * exp(constants[0] + 2 * constants[1]) -
214                                 2 * cos(constants[3]) * exp(constants[1] + 2 * constants[0]);
216         d_p[4] = exp(2 * constants[0] + 2 * constants[1]);
218         for(int i = 0; i < 5; i++) d_m[i] = d_p[i];
220         n_m[0] = 0.0;
221         for(int i = 1; i <= 4; i++)
222                 n_m[i] = n_p[i] - d_p[i] * n_p[0];
224         double sum_n_p, sum_n_m, sum_d;
225         double a, b;
227         sum_n_p = 0.0;
228         sum_n_m = 0.0;
229         sum_d = 0.0;
230         for(int i = 0; i < 5; i++)
231         {
232                 sum_n_p += n_p[i];
233                 sum_n_m += n_m[i];
234                 sum_d += d_p[i];
235         }
237         a = sum_n_p / (1 + sum_d);
238         b = sum_n_m / (1 + sum_d);
240         for(int i = 0; i < 5; i++)
241         {
242                 bd_p[i] = d_p[i] * a;
243                 bd_m[i] = d_m[i] * b;
244         }
267 #define DO_FEATHER(type, max) \
268 { \
269         int frame_w = input->get_w(); \
270         int frame_h = input->get_h(); \
271         int size = MAX(frame_w, frame_h); \
272         float *src = new float[size]; \
273         float *dst = new float[size]; \
274         float *val_p = new float[size]; \
275         float *val_m = new float[size]; \
276         int start_in = start_out - (int)feather; \
277         int end_in = end_out + (int)feather; \
278         if(start_in < 0) start_in = 0; \
279         if(end_in > frame_h) end_in = frame_h; \
280         int strip_size = end_in - start_in; \
281         type **in_rows = (type**)input->get_rows(); \
282         type **out_rows = (type**)output->get_rows(); \
283         int j; \
285 /* printf("DO_FEATHER 1\n"); */ \
286         for(j = 0; j < frame_w; j++) \
287         { \
288 /* printf("DO_FEATHER 1.1 %d\n", j); */ \
289                 bzero(val_p, sizeof(float) * (end_in - start_in)); \
290                 bzero(val_m, sizeof(float) * (end_in - start_in)); \
291                 for(int l = 0, k = start_in; k < end_in; l++, k++) \
292                 { \
293                         src[l] = (float)in_rows[k][j]; \
294                 } \
296                 blur_strip(val_p, val_m, dst, src, strip_size, max); \
298                 for(int l = start_out - start_in, k = start_out; k < end_out; l++, k++) \
299                 { \
300                         out_rows[k][j] = (type)dst[l]; \
301                 } \
302         } \
304         for(j = start_out; j < end_out; j++) \
305         { \
306 /* printf("DO_FEATHER 2 %d\n", j); */ \
307                 bzero(val_p, sizeof(float) * frame_w); \
308                 bzero(val_m, sizeof(float) * frame_w); \
309                 for(int k = 0; k < frame_w; k++) \
310                 { \
311                         src[k] = (float)out_rows[j][k]; \
312                 } \
314                 blur_strip(val_p, val_m, dst, src, frame_w, max); \
316                 for(int k = 0; k < frame_w; k++) \
317                 { \
318                         out_rows[j][k] = (type)dst[k]; \
319                 } \
320         } \
322 /* printf("DO_FEATHER 3\n"); */ \
324         delete [] src; \
325         delete [] dst; \
326         delete [] val_p; \
327         delete [] val_m; \
328 /* printf("DO_FEATHER 4\n"); */ \
338 //printf("do_feather %d\n", frame->get_color_model());
339         switch(input->get_color_model())
340         {
341                 case BC_A8:
342                         DO_FEATHER(unsigned char, 0xff);
343                         break;
344                 
345                 case BC_A16:
346                         DO_FEATHER(uint16_t, 0xffff);
347                         break;
348                 
349                 case BC_A_FLOAT:
350                         DO_FEATHER(float, 1);
351                         break;
352         }
359 void MaskUnit::process_package(LoadPackage *package)
361         MaskPackage *ptr = (MaskPackage*)package;
363         if(engine->recalculate && ptr->part == RECALCULATE_PART)
364         {
365                 VFrame *mask;
366                 if(engine->feather > 0) 
367                         mask = engine->temp_mask;
368                 else
369                         mask = engine->mask;
371 // Generated oversampling frame
372                 int mask_w = mask->get_w();
373                 int mask_h = mask->get_h();
374                 int oversampled_package_w = mask_w * OVERSAMPLE;
375                 int oversampled_package_h = (ptr->row2 - ptr->row1) * OVERSAMPLE;
376 //printf("MaskUnit::process_package 1\n");
378                 if(temp && 
379                         (temp->get_w() != oversampled_package_w ||
380                         temp->get_h() != oversampled_package_h))
381                 {
382                         delete temp;
383                         temp = 0;
384                 }
385 //printf("MaskUnit::process_package 1\n");
387                 if(!temp)
388                 {
389                         temp = new VFrame(0, 
390                                 oversampled_package_w, 
391                                 oversampled_package_h,
392                                 BC_A8);
393                 }
395                 temp->clear_frame();
396 //printf("MaskUnit::process_package 1 %d\n", engine->point_sets.total);
399 // Draw oversampled region of polygons on temp
400                 for(int k = 0; k < engine->point_sets.total; k++)
401                 {
402                         int old_x, old_y;
403                         unsigned char max = k + 1;
404                         ArrayList<MaskPoint*> *points = engine->point_sets.values[k];
406                         if(points->total < 3) continue;
407 //printf("MaskUnit::process_package 2 %d %d\n", k, points->total);
408                         for(int i = 0; i < points->total; i++)
409                         {
410                                 MaskPoint *point1 = points->values[i];
411                                 MaskPoint *point2 = (i >= points->total - 1) ? 
412                                         points->values[0] : 
413                                         points->values[i + 1];
415                                 float x, y;
416                                 int segments = (int)(sqrt(SQR(point1->x - point2->x) + SQR(point1->y - point2->y)));
417                                 float x0 = point1->x;
418                                 float y0 = point1->y;
419                                 float x1 = point1->x + point1->control_x2;
420                                 float y1 = point1->y + point1->control_y2;
421                                 float x2 = point2->x + point2->control_x1;
422                                 float y2 = point2->y + point2->control_y1;
423                                 float x3 = point2->x;
424                                 float y3 = point2->y;
426                                 for(int j = 0; j <= segments; j++)
427                                 {
428                                         float t = (float)j / segments;
429                                         float tpow2 = t * t;
430                                         float tpow3 = t * t * t;
431                                         float invt = 1 - t;
432                                         float invtpow2 = invt * invt;
433                                         float invtpow3 = invt * invt * invt;
435                                         x = (        invtpow3 * x0
436                                                 + 3 * t     * invtpow2 * x1
437                                                 + 3 * tpow2 * invt     * x2 
438                                                 +     tpow3            * x3);
439                                         y = (        invtpow3 * y0 
440                                                 + 3 * t     * invtpow2 * y1
441                                                 + 3 * tpow2 * invt     * y2 
442                                                 +     tpow3            * y3);
444                                         y -= ptr->row1;
445                                         x *= OVERSAMPLE;
446                                         y *= OVERSAMPLE;
448                                         if(j > 0)
449                                         {
450                                                 draw_line_clamped(temp, old_x, old_y, (int)x, (int)y, max);
451                                         }
453                                         old_x = (int)x;
454                                         old_y = (int)y;
455                                 }
456                         }
458 //printf("MaskUnit::process_package 1\n");
464 // Fill in the polygon in the horizontal direction
465                         for(int i = 0; i < oversampled_package_h; i++)
466                         {
467                                 unsigned char *row = (unsigned char*)temp->get_rows()[i];
468                                 int value = 0x0;
469                                 int total = 0;
471                                 for(int j = 0; j < oversampled_package_w; j++)
472                                         if(row[j] == max) total++;
474                                 if(total > 1)
475                                 {
476                                         if(total & 0x1) total--;
477                                         for(int j = 0; j < oversampled_package_w; j++)
478                                         {
479                                                 if(row[j] == max && total > 0)
480                                                 {
481                                                         if(value)
482                                                                 value = 0x0;
483                                                         else
484                                                                 value = max;
485                                                         total--;
486                                                 }
487                                                 else
488                                                 {
489                                                         if(value) row[j] = value;
490                                                 }
491                                         }
492                                 }
493                         }
494                 }
502 #define DOWNSAMPLE(type, temp_type, value) \
503 for(int i = 0; i < ptr->row2 - ptr->row1; i++) \
504 { \
505         type *output_row = (type*)mask->get_rows()[i + ptr->row1]; \
506         unsigned char **input_rows = (unsigned char**)temp->get_rows() + i * OVERSAMPLE; \
509         for(int j = 0; j < mask_w; j++) \
510         { \
511                 temp_type total = 0; \
513 /* Accumulate pixel */ \
514                 for(int k = 0; k < OVERSAMPLE; k++) \
515                 { \
516                         unsigned char *input_vector = input_rows[k] + j * OVERSAMPLE; \
517                         for(int l = 0; l < OVERSAMPLE; l++) \
518                         { \
519                                 total += (input_vector[l] ? value : 0); \
520                         } \
521                 } \
523 /* Divide pixel */ \
524                 total /= OVERSAMPLE * OVERSAMPLE; \
526                 output_row[j] = total; \
527         } \
531 // Downsample polygon
532                 switch(mask->get_color_model())
533                 {
534                         case BC_A8:
535                         {
536                                 unsigned char value;
537                                 value = (int)((float)engine->value / 100 * 0xff);
538                                 DOWNSAMPLE(unsigned char, int64_t, value);
539                                 break;
540                         }
542                         case BC_A16:
543                         {
544                                 uint16_t value;
545                                 value = (int)((float)engine->value / 100 * 0xffff);
546                                 DOWNSAMPLE(uint16_t, int64_t, value);
547                                 break;
548                         }
550                         case BC_A_FLOAT:
551                         {
552                                 float value;
553                                 value = (float)engine->value / 100;
554                                 DOWNSAMPLE(float, double, value);
555                                 break;
556                         }
557                 }
558         }
561         if(ptr->part == RECALCULATE_PART)
562         {
563 // The feather could span more than one package so can't do it until
564 // all packages are drawn.
565                 if(get_package_number() >= engine->get_total_packages() / 2 - 1)
566                 {
567                         for(int i = engine->get_total_packages() / 2; 
568                                 i < engine->get_total_packages();
569                                 i++)
570                         {
571                                 MaskPackage *package = (MaskPackage*)engine->get_package(i);
572                                 package->apply_mutex->unlock();
573                         }
574                 }
576         }
579         if(ptr->part == APPLY_PART)
580         {
581 //printf("MaskUnit::process_package 2.1\n");
582                 ptr->apply_mutex->lock("MaskUnit::process_package");
583                 ptr->apply_mutex->unlock();
584 //printf("MaskUnit::process_package 2.2\n");
586                 if(engine->recalculate)
587                 {
588 // Feather polygon
589                         if(engine->feather > 0) do_feather(engine->mask, 
590                                 engine->temp_mask, 
591                                 engine->feather, 
592                                 ptr->row1, 
593                                 ptr->row2);
595                 }
596 //printf("MaskUnit::process_package 3 %f\n", engine->feather);
601 // Apply mask
602                 int mask_w = engine->mask->get_w();
605 #define APPLY_MASK_SUBTRACT_ALPHA(type, max, components, do_yuv) \
606 { \
607         type *output_row = (type*)engine->output->get_rows()[i]; \
608         type *mask_row = (type*)engine->mask->get_rows()[i]; \
609         int chroma_offset = (int)(max + 1) / 2; \
611         for(int j  = 0; j < mask_w; j++) \
612         { \
613                 if(components == 4) \
614                 { \
615                         output_row[j * 4 + 3] = output_row[j * 4 + 3] * (max - mask_row[j]) / max; \
616                 } \
617                 else \
618                 { \
619                         output_row[j * 3] = output_row[j * 3] * (max - mask_row[j]) / max; \
621                         output_row[j * 3 + 1] = output_row[j * 3 + 1] * (max - mask_row[j]) / max; \
622                         output_row[j * 3 + 2] = output_row[j * 3 + 2] * (max - mask_row[j]) / max; \
624                         if(do_yuv) \
625                         { \
626                                 output_row[j * 3 + 1] += chroma_offset * mask_row[j] / max; \
627                                 output_row[j * 3 + 2] += chroma_offset * mask_row[j] / max; \
628                         } \
629                 } \
630         } \
633 #define APPLY_MASK_MULTIPLY_ALPHA(type, max, components, do_yuv) \
634 { \
635         type *output_row = (type*)engine->output->get_rows()[i]; \
636         type *mask_row = (type*)engine->mask->get_rows()[i]; \
637         int chroma_offset = (int)(max + 1) / 2; \
639         for(int j  = 0; j < mask_w; j++) \
640         { \
641                 if(components == 4) \
642                 { \
643                         output_row[j * 4 + 3] = output_row[j * 4 + 3] * mask_row[j] / max; \
644                 } \
645                 else \
646                 { \
647                         output_row[j * 3] = output_row[j * 3] * mask_row[j] / max; \
649                         output_row[j * 3 + 1] = output_row[j * 3 + 1] * mask_row[j] / max; \
650                         output_row[j * 3 + 2] = output_row[j * 3 + 2] * mask_row[j] / max; \
652                         if(do_yuv) \
653                         { \
654                                 output_row[j * 3 + 1] += chroma_offset * (max - mask_row[j]) / max; \
655                                 output_row[j * 3 + 2] += chroma_offset * (max - mask_row[j]) / max; \
656                         } \
657                 } \
658         } \
664 //printf("MaskUnit::process_package 1 %d\n", engine->mode);
665                 for(int i = ptr->row1; i < ptr->row2; i++)
666                 {
667                         switch(engine->mode)
668                         {
669                                 case MASK_MULTIPLY_ALPHA:
670                                         switch(engine->output->get_color_model())
671                                         {
672                                                 case BC_RGB888:
673                                                         APPLY_MASK_MULTIPLY_ALPHA(unsigned char, 0xff, 3, 0);
674                                                         break;
675                                                 case BC_RGB_FLOAT:
676                                                         APPLY_MASK_MULTIPLY_ALPHA(float, 1.0, 3, 0);
677                                                         break;
678                                                 case BC_YUV888:
679                                                         APPLY_MASK_MULTIPLY_ALPHA(unsigned char, 0xff, 3, 1);
680                                                         break;
681                                                 case BC_RGBA_FLOAT:
682                                                         APPLY_MASK_MULTIPLY_ALPHA(float, 1.0, 4, 0);
683                                                         break;
684                                                 case BC_YUVA8888:
685                                                         APPLY_MASK_MULTIPLY_ALPHA(unsigned char, 0xff, 4, 1);
686                                                         break;
687                                                 case BC_RGBA8888:
688                                                         APPLY_MASK_MULTIPLY_ALPHA(unsigned char, 0xff, 4, 0);
689                                                         break;
690                                                 case BC_RGB161616:
691                                                         APPLY_MASK_MULTIPLY_ALPHA(uint16_t, 0xffff, 3, 0);
692                                                         break;
693                                                 case BC_YUV161616:
694                                                         APPLY_MASK_MULTIPLY_ALPHA(uint16_t, 0xffff, 3, 1);
695                                                         break;
696                                                 case BC_YUVA16161616:
697                                                         APPLY_MASK_MULTIPLY_ALPHA(uint16_t, 0xffff, 4, 1);
698                                                         break;
699                                                 case BC_RGBA16161616:
700                                                         APPLY_MASK_MULTIPLY_ALPHA(uint16_t, 0xffff, 4, 0);
701                                                         break;
702                                         }
703                                         break;
705                                 case MASK_SUBTRACT_ALPHA:
706                                         switch(engine->output->get_color_model())
707                                         {
708                                                 case BC_RGB888:
709                                                         APPLY_MASK_SUBTRACT_ALPHA(unsigned char, 0xff, 3, 0);
710                                                         break;
711                                                 case BC_RGB_FLOAT:
712                                                         APPLY_MASK_SUBTRACT_ALPHA(float, 1.0, 3, 0);
713                                                         break;
714                                                 case BC_RGBA_FLOAT:
715                                                         APPLY_MASK_SUBTRACT_ALPHA(float, 1.0, 4, 0);
716                                                         break;
717                                                 case BC_RGBA8888:
718                                                         APPLY_MASK_SUBTRACT_ALPHA(unsigned char, 0xff, 4, 0);
719                                                         break;
720                                                 case BC_YUV888:
721                                                         APPLY_MASK_SUBTRACT_ALPHA(unsigned char, 0xff, 3, 1);
722                                                         break;
723                                                 case BC_YUVA8888:
724                                                         APPLY_MASK_SUBTRACT_ALPHA(unsigned char, 0xff, 4, 1);
725                                                         break;
726                                                 case BC_RGB161616:
727                                                         APPLY_MASK_SUBTRACT_ALPHA(uint16_t, 0xffff, 3, 0);
728                                                         break;
729                                                 case BC_RGBA16161616:
730                                                         APPLY_MASK_SUBTRACT_ALPHA(uint16_t, 0xffff, 4, 0);
731                                                         break;
732                                                 case BC_YUV161616:
733                                                         APPLY_MASK_SUBTRACT_ALPHA(uint16_t, 0xffff, 3, 1);
734                                                         break;
735                                                 case BC_YUVA16161616:
736                                                         APPLY_MASK_SUBTRACT_ALPHA(uint16_t, 0xffff, 4, 1);
737                                                         break;
738                                         }
739                                         break;
740                         }
741                 }
742         }
749 MaskEngine::MaskEngine(int cpus)
750  : LoadServer(cpus, cpus * OVERSAMPLE * 2)
751 // : LoadServer(1, OVERSAMPLE * 2)
753         mask = 0;
756 MaskEngine::~MaskEngine()
758         if(mask) 
759         {
760                 delete mask;
761                 delete temp_mask;
762         }
763         point_sets.remove_all_objects();
766 int MaskEngine::points_equivalent(ArrayList<MaskPoint*> *new_points, 
767         ArrayList<MaskPoint*> *points)
769 //printf("MaskEngine::points_equivalent %d %d\n", new_points->total, points->total);
770         if(new_points->total != points->total) return 0;
771         
772         for(int i = 0; i < new_points->total; i++)
773         {
774                 if(!(*new_points->values[i] == *points->values[i])) return 0;
775         }
776         
777         return 1;
780 void MaskEngine::do_mask(VFrame *output, 
781         int64_t start_position,
782         double frame_rate,
783         double project_frame_rate,
784         MaskAutos *keyframe_set, 
785         int direction)
787         int64_t start_position_project = (int64_t)(start_position *
788                 project_frame_rate / 
789                 frame_rate);
790         Auto *current = 0;
791         MaskAuto *default_auto = (MaskAuto*)keyframe_set->default_auto;
792         MaskAuto *keyframe = (MaskAuto*)keyframe_set->get_prev_auto(start_position_project, 
793                 direction,
794                 current);
797         int total_points = 0;
798         for(int i = 0; i < keyframe->masks.total; i++)
799         {
800                 SubMask *mask = keyframe->get_submask(i);
801                 int submask_points = mask->points.total;
802                 if(submask_points > 1) total_points += submask_points;
803         }
805 //printf("MaskEngine::do_mask 1 %d %d\n", total_points, keyframe->value);
806 // Ignore certain masks
807         if(total_points < 2 || 
808                 (keyframe->value == 0 && default_auto->mode == MASK_SUBTRACT_ALPHA))
809         {
810                 return;
811         }
813 // Fake certain masks
814         if(keyframe->value == 0 && default_auto->mode == MASK_MULTIPLY_ALPHA)
815         {
816                 output->clear_frame();
817                 return;
818         }
820 //printf("MaskEngine::do_mask 1\n");
822         int new_color_model = 0;
823         recalculate = 0;
824         switch(output->get_color_model())
825         {
826                 case BC_RGB_FLOAT:
827                 case BC_RGBA_FLOAT:
828                         new_color_model = BC_A_FLOAT;
829                         break;
831                 case BC_RGB888:
832                 case BC_RGBA8888:
833                 case BC_YUV888:
834                 case BC_YUVA8888:
835                         new_color_model = BC_A8;
836                         break;
838                 case BC_RGB161616:
839                 case BC_RGBA16161616:
840                 case BC_YUV161616:
841                 case BC_YUVA16161616:
842                         new_color_model = BC_A16;
843                         break;
844         }
846 // Determine if recalculation is needed
848         if(mask && 
849                 (mask->get_w() != output->get_w() ||
850                 mask->get_h() != output->get_h() ||
851                 mask->get_color_model() != new_color_model))
852         {
853                 delete mask;
854                 delete temp_mask;
855                 mask = 0;
856                 recalculate = 1;
857         }
859         if(!recalculate)
860         {
861                 if(point_sets.total != keyframe_set->total_submasks(start_position_project, 
862                         direction))
863                         recalculate = 1;
864         }
866         if(!recalculate)
867         {
868                 for(int i = 0; 
869                         i < keyframe_set->total_submasks(start_position_project, 
870                                 direction) && !recalculate; 
871                         i++)
872                 {
873                         ArrayList<MaskPoint*> *new_points = new ArrayList<MaskPoint*>;
874                         keyframe_set->get_points(new_points, 
875                                 i, 
876                                 start_position_project, 
877                                 direction);
878                         if(!points_equivalent(new_points, point_sets.values[i])) recalculate = 1;
879                         new_points->remove_all_objects();
880                 }
881         }
883         if(recalculate ||
884                 !EQUIV(keyframe->feather, feather) ||
885                 !EQUIV(keyframe->value, value))
886         {
887                 recalculate = 1;
888                 if(!mask) 
889                 {
890                         mask = new VFrame(0, 
891                                         output->get_w(), 
892                                         output->get_h(),
893                                         new_color_model);
894                         temp_mask = new VFrame(0, 
895                                         output->get_w(), 
896                                         output->get_h(),
897                                         new_color_model);
898                 }
899                 if(keyframe->feather > 0)
900                         temp_mask->clear_frame();
901                 else
902                         mask->clear_frame();
903                 point_sets.remove_all_objects();
905                 for(int i = 0; 
906                         i < keyframe_set->total_submasks(start_position_project, 
907                                 direction); 
908                         i++)
909                 {
910                         ArrayList<MaskPoint*> *new_points = new ArrayList<MaskPoint*>;
911                         keyframe_set->get_points(new_points, 
912                                 i, 
913                                 start_position_project, 
914                                 direction);
915                         point_sets.append(new_points);
916                 }
917         }
921         this->output = output;
922         this->mode = default_auto->mode;
923         this->feather = keyframe->feather;
924         this->value = keyframe->value;
927 // Run units
928         process_packages();
933 void MaskEngine::init_packages()
935 //printf("MaskEngine::init_packages 1\n");
936         int division = (int)((float)output->get_h() / (total_packages / 2) + 0.5);
937         if(division < 1) division = 1;
939 // Always a multiple of 2 packages exist
940         for(int i = 0; i < get_total_packages() / 2; i++)
941         {
942                 MaskPackage *part1 = (MaskPackage*)packages[i];
943                 MaskPackage *part2 = (MaskPackage*)packages[i + total_packages / 2];
944                 part2->row1 = part1->row1 = division * i;
945                 part2->row2 = part1->row2 = division * i + division;
946                 part2->row1 = part1->row1 = MIN(output->get_h(), part1->row1);
947                 part2->row2 = part1->row2 = MIN(output->get_h(), part1->row2);
948                 
949                 if(i >= (total_packages / 2) - 1) 
950                 {
951                         part2->row2 = part1->row2 = output->get_h();
952                 }
954                 part2->apply_mutex->lock("MaskEngine::init_packages");
956                 part1->part = RECALCULATE_PART;
957                 part2->part = APPLY_PART;
958         }
959 //printf("MaskEngine::init_packages 2\n");
962 LoadClient* MaskEngine::new_client()
964         return new MaskUnit(this);
967 LoadPackage* MaskEngine::new_package()
969         return new MaskPackage;