4 #include "maskengine.h"
12 MaskPackage::MaskPackage()
14 apply_mutex = new Mutex;
17 MaskPackage::~MaskPackage()
28 MaskUnit::MaskUnit(MaskEngine *engine)
31 this->engine = engine;
42 #define SQR(x) ((x) * (x))
59 #define DRAW_LINE_CLAMPED(type, value) \
61 type **rows = (type**)frame->get_rows(); \
63 if(draw_y2 != draw_y1) \
65 float slope = ((float)draw_x2 - draw_x1) / ((float)draw_y2 - draw_y1); \
66 int w = frame->get_w() - 1; \
67 int h = frame->get_h(); \
69 for(float y = draw_y1; y < draw_y2; y++) \
73 int x = (int)((y - draw_y1) * slope + draw_x1); \
75 int x_i = CLIP(x, 0, w); \
77 if(rows[y_i][x_i] == value) \
80 rows[y_i][x_i] = value; \
88 void MaskUnit::draw_line_clamped(VFrame *frame,
95 //printf("MaskUnit::draw_line_clamped 1 %d %d %d %d\n", x1, y1, x2, y2);
117 switch(frame->get_color_model())
120 DRAW_LINE_CLAMPED(unsigned char, k);
124 DRAW_LINE_CLAMPED(uint16_t, k);
129 void MaskUnit::blur_strip(float *val_p,
137 float *sp_m = src + size - 1;
139 float *vm = val_m + size - 1;
140 float initial_p = sp_p[0];
141 float initial_m = sp_m[0];
143 //printf("MaskUnit::blur_strip %d\n", size);
144 for(int k = 0; k < size; k++)
146 int terms = (k < 4) ? k : 4;
148 for(l = 0; l <= terms; l++)
150 *vp += n_p[l] * sp_p[-l] - d_p[l] * vp[-l];
151 *vm += n_m[l] * sp_m[l] - d_m[l] * vm[l];
156 *vp += (n_p[l] - bd_p[l]) * initial_p;
157 *vm += (n_m[l] - bd_m[l]) * initial_m;
165 for(int i = 0; i < size; i++)
167 float sum = val_p[i] + val_m[i];
173 void MaskUnit::do_feather(VFrame *output,
179 //printf("MaskUnit::do_feather %f\n", feather);
183 double std_dev = sqrt(-(double)(feather * feather) / (2 * log(1.0 / 255.0)));
184 div = sqrt(2 * M_PI) * std_dev;
185 constants[0] = -1.783 / std_dev;
186 constants[1] = -1.723 / std_dev;
187 constants[2] = 0.6318 / std_dev;
188 constants[3] = 1.997 / std_dev;
189 constants[4] = 1.6803 / div;
190 constants[5] = 3.735 / div;
191 constants[6] = -0.6803 / div;
192 constants[7] = -0.2598 / div;
194 n_p[0] = constants[4] + constants[6];
195 n_p[1] = exp(constants[1]) *
196 (constants[7] * sin(constants[3]) -
197 (constants[6] + 2 * constants[4]) * cos(constants[3])) +
199 (constants[5] * sin(constants[2]) -
200 (2 * constants[6] + constants[4]) * cos(constants[2]));
202 n_p[2] = 2 * exp(constants[0] + constants[1]) *
203 ((constants[4] + constants[6]) * cos(constants[3]) *
204 cos(constants[2]) - constants[5] *
205 cos(constants[3]) * sin(constants[2]) -
206 constants[7] * cos(constants[2]) * sin(constants[3])) +
207 constants[6] * exp(2 * constants[0]) +
208 constants[4] * exp(2 * constants[1]);
210 n_p[3] = exp(constants[1] + 2 * constants[0]) *
211 (constants[7] * sin(constants[3]) -
212 constants[6] * cos(constants[3])) +
213 exp(constants[0] + 2 * constants[1]) *
214 (constants[5] * sin(constants[2]) - constants[4] *
219 d_p[1] = -2 * exp(constants[1]) * cos(constants[3]) -
220 2 * exp(constants[0]) * cos(constants[2]);
222 d_p[2] = 4 * cos(constants[3]) * cos(constants[2]) *
223 exp(constants[0] + constants[1]) +
224 exp(2 * constants[1]) + exp (2 * constants[0]);
226 d_p[3] = -2 * cos(constants[2]) * exp(constants[0] + 2 * constants[1]) -
227 2 * cos(constants[3]) * exp(constants[1] + 2 * constants[0]);
229 d_p[4] = exp(2 * constants[0] + 2 * constants[1]);
231 for(int i = 0; i < 5; i++) d_m[i] = d_p[i];
234 for(int i = 1; i <= 4; i++)
235 n_m[i] = n_p[i] - d_p[i] * n_p[0];
237 double sum_n_p, sum_n_m, sum_d;
243 for(int i = 0; i < 5; i++)
250 a = sum_n_p / (1 + sum_d);
251 b = sum_n_m / (1 + sum_d);
253 for(int i = 0; i < 5; i++)
255 bd_p[i] = d_p[i] * a;
256 bd_m[i] = d_m[i] * b;
280 #define DO_FEATHER(type, max) \
282 int frame_w = input->get_w(); \
283 int frame_h = input->get_h(); \
284 int size = MAX(frame_w, frame_h); \
285 float *src = new float[size]; \
286 float *dst = new float[size]; \
287 float *val_p = new float[size]; \
288 float *val_m = new float[size]; \
289 int start_in = start_out - (int)feather; \
290 int end_in = end_out + (int)feather; \
291 if(start_in < 0) start_in = 0; \
292 if(end_in > frame_h) end_in = frame_h; \
293 int strip_size = end_in - start_in; \
294 type **in_rows = (type**)input->get_rows(); \
295 type **out_rows = (type**)output->get_rows(); \
298 /* printf("DO_FEATHER 1\n"); */ \
299 for(j = 0; j < frame_w; j++) \
301 /* printf("DO_FEATHER 1.1 %d\n", j); */ \
302 bzero(val_p, sizeof(float) * (end_in - start_in)); \
303 bzero(val_m, sizeof(float) * (end_in - start_in)); \
304 for(int l = 0, k = start_in; k < end_in; l++, k++) \
306 src[l] = (float)in_rows[k][j]; \
309 blur_strip(val_p, val_m, dst, src, strip_size, max); \
311 for(int l = start_out - start_in, k = start_out; k < end_out; l++, k++) \
313 out_rows[k][j] = (type)dst[l]; \
317 for(j = start_out; j < end_out; j++) \
319 /* printf("DO_FEATHER 2 %d\n", j); */ \
320 bzero(val_p, sizeof(float) * frame_w); \
321 bzero(val_m, sizeof(float) * frame_w); \
322 for(int k = 0; k < frame_w; k++) \
324 src[k] = (float)out_rows[j][k]; \
327 blur_strip(val_p, val_m, dst, src, frame_w, max); \
329 for(int k = 0; k < frame_w; k++) \
331 out_rows[j][k] = (type)dst[k]; \
335 /* printf("DO_FEATHER 3\n"); */ \
341 /* printf("DO_FEATHER 4\n"); */ \
351 //printf("do_feather %d\n", frame->get_color_model());
352 switch(input->get_color_model())
355 DO_FEATHER(unsigned char, 0xff);
359 DO_FEATHER(uint16_t, 0xffff);
368 void MaskUnit::process_package(LoadPackage *package)
370 MaskPackage *ptr = (MaskPackage*)package;
372 if(engine->recalculate && ptr->part == RECALCULATE_PART)
375 //printf("MaskUnit::process_package 1 %d\n", get_package_number());
376 if(engine->feather > 0)
377 mask = engine->temp_mask;
381 // Generated oversampling frame
382 int mask_w = mask->get_w();
383 int mask_h = mask->get_h();
384 int oversampled_package_w = mask_w * OVERSAMPLE;
385 int oversampled_package_h = (ptr->row2 - ptr->row1) * OVERSAMPLE;
386 //printf("MaskUnit::process_package 1\n");
389 (temp->get_w() != oversampled_package_w ||
390 temp->get_h() != oversampled_package_h))
395 //printf("MaskUnit::process_package 1\n");
400 oversampled_package_w,
401 oversampled_package_h,
406 //printf("MaskUnit::process_package 1 %d\n", engine->point_sets.total);
409 // Draw oversampled region of polygons on temp
410 for(int k = 0; k < engine->point_sets.total; k++)
413 unsigned char max = k + 1;
414 ArrayList<MaskPoint*> *points = engine->point_sets.values[k];
416 if(points->total < 3) continue;
417 //printf("MaskUnit::process_package 2 %d %d\n", k, points->total);
418 for(int i = 0; i < points->total; i++)
420 MaskPoint *point1 = points->values[i];
421 MaskPoint *point2 = (i >= points->total - 1) ?
423 points->values[i + 1];
426 int segments = (int)(sqrt(SQR(point1->x - point2->x) + SQR(point1->y - point2->y)));
427 float x0 = point1->x;
428 float y0 = point1->y;
429 float x1 = point1->x + point1->control_x2;
430 float y1 = point1->y + point1->control_y2;
431 float x2 = point2->x + point2->control_x1;
432 float y2 = point2->y + point2->control_y1;
433 float x3 = point2->x;
434 float y3 = point2->y;
436 for(int j = 0; j <= segments; j++)
438 float t = (float)j / segments;
440 float tpow3 = t * t * t;
442 float invtpow2 = invt * invt;
443 float invtpow3 = invt * invt * invt;
446 + 3 * t * invtpow2 * x1
447 + 3 * tpow2 * invt * x2
450 + 3 * t * invtpow2 * y1
451 + 3 * tpow2 * invt * y2
460 draw_line_clamped(temp, old_x, old_y, (int)x, (int)y, max);
468 //printf("MaskUnit::process_package 1\n");
474 #define FILL_ROWS(type) \
475 for(int i = 0; i < oversampled_package_h; i++) \
477 type *row = (type*)temp->get_rows()[i]; \
481 for(int j = 0; j < oversampled_package_w; j++) \
482 if(row[j] == max) total++; \
486 if(total & 0x1) total--; \
487 for(int j = 0; j < oversampled_package_w; j++) \
489 if(row[j] == max && total > 0) \
499 if(value) row[j] = value; \
506 // Fill in the polygon in the horizontal direction
507 switch(temp->get_color_model())
510 FILL_ROWS(unsigned char);
526 #define DOWNSAMPLE(type, value) \
527 for(int i = 0; i < ptr->row2 - ptr->row1; i++) \
529 type *output_row = (type*)mask->get_rows()[i + ptr->row1]; \
530 unsigned char **input_rows = (unsigned char**)temp->get_rows() + i * OVERSAMPLE; \
533 for(int j = 0; j < mask_w; j++) \
537 /* Accumulate pixel */ \
538 for(int k = 0; k < OVERSAMPLE; k++) \
540 unsigned char *input_vector = input_rows[k] + j * OVERSAMPLE; \
541 for(int l = 0; l < OVERSAMPLE; l++) \
543 total += (input_vector[l] ? value : 0); \
548 if(OVERSAMPLE == 8) \
551 if(OVERSAMPLE == 4) \
554 if(OVERSAMPLE == 2) \
557 total /= OVERSAMPLE * OVERSAMPLE; \
559 output_row[j] = total; \
564 // Downsample polygon
565 switch(mask->get_color_model())
570 value = (int)((float)engine->value / 100 * 0xff);
571 DOWNSAMPLE(unsigned char, value);
578 value = (int)((float)engine->value / 100 * 0xffff);
579 DOWNSAMPLE(uint16_t, value);
587 if(ptr->part == RECALCULATE_PART)
589 // The feather could span more than one package so can't do it until
590 // all packages are drawn.
591 if(get_package_number() >= engine->get_total_packages() / 2 - 1)
593 for(int i = engine->get_total_packages() / 2;
594 i < engine->get_total_packages();
597 MaskPackage *package = (MaskPackage*)engine->get_package(i);
598 package->apply_mutex->unlock();
604 //printf("MaskUnit::process_package 2\n");
606 if(ptr->part == APPLY_PART)
608 //printf("MaskUnit::process_package 2.1\n");
609 ptr->apply_mutex->lock();
610 ptr->apply_mutex->unlock();
611 //printf("MaskUnit::process_package 2.2\n");
613 if(engine->recalculate)
616 if(engine->feather > 0) do_feather(engine->mask,
623 //printf("MaskUnit::process_package 3 %f\n", engine->feather);
629 int mask_w = engine->mask->get_w();
632 #define APPLY_MASK_SUBTRACT_ALPHA(type, max, components, do_yuv) \
634 type *output_row = (type*)engine->output->get_rows()[i]; \
635 type *mask_row = (type*)engine->mask->get_rows()[i]; \
636 int chroma_offset = (max + 1) / 2; \
638 for(int j = 0; j < mask_w; j++) \
640 if(components == 4) \
642 output_row[j * 4 + 3] = output_row[j * 4 + 3] * (max - mask_row[j]) / max; \
646 output_row[j * 3] = output_row[j * 3] * (max - mask_row[j]) / max; \
648 output_row[j * 3 + 1] = output_row[j * 3 + 1] * (max - mask_row[j]) / max; \
649 output_row[j * 3 + 2] = output_row[j * 3 + 2] * (max - mask_row[j]) / max; \
653 output_row[j * 3 + 1] += chroma_offset * mask_row[j] / max; \
654 output_row[j * 3 + 2] += chroma_offset * mask_row[j] / max; \
660 #define APPLY_MASK_MULTIPLY_ALPHA(type, max, components, do_yuv) \
662 type *output_row = (type*)engine->output->get_rows()[i]; \
663 type *mask_row = (type*)engine->mask->get_rows()[i]; \
664 int chroma_offset = (max + 1) / 2; \
666 for(int j = 0; j < mask_w; j++) \
668 if(components == 4) \
670 output_row[j * 4 + 3] = output_row[j * 4 + 3] * mask_row[j] / max; \
674 output_row[j * 3] = output_row[j * 3] * mask_row[j] / max; \
676 output_row[j * 3 + 1] = output_row[j * 3 + 1] * mask_row[j] / max; \
677 output_row[j * 3 + 2] = output_row[j * 3 + 2] * mask_row[j] / max; \
681 output_row[j * 3 + 1] += chroma_offset * (max - mask_row[j]) / max; \
682 output_row[j * 3 + 2] += chroma_offset * (max - mask_row[j]) / max; \
691 //printf("MaskUnit::process_package 1 %d\n", engine->mode);
692 for(int i = ptr->row1; i < ptr->row2; i++)
696 case MASK_MULTIPLY_ALPHA:
697 switch(engine->output->get_color_model())
700 APPLY_MASK_MULTIPLY_ALPHA(unsigned char, 0xff, 3, 0);
703 APPLY_MASK_MULTIPLY_ALPHA(unsigned char, 0xff, 3, 1);
707 APPLY_MASK_MULTIPLY_ALPHA(unsigned char, 0xff, 4, 0);
710 APPLY_MASK_MULTIPLY_ALPHA(uint16_t, 0xffff, 3, 0);
713 APPLY_MASK_MULTIPLY_ALPHA(uint16_t, 0xffff, 3, 1);
715 case BC_YUVA16161616:
716 case BC_RGBA16161616:
717 APPLY_MASK_MULTIPLY_ALPHA(uint16_t, 0xffff, 4, 0);
722 case MASK_SUBTRACT_ALPHA:
723 switch(engine->output->get_color_model())
726 APPLY_MASK_SUBTRACT_ALPHA(unsigned char, 0xff, 3, 0);
729 APPLY_MASK_SUBTRACT_ALPHA(unsigned char, 0xff, 3, 1);
733 APPLY_MASK_SUBTRACT_ALPHA(unsigned char, 0xff, 4, 0);
736 APPLY_MASK_SUBTRACT_ALPHA(uint16_t, 0xffff, 3, 0);
739 APPLY_MASK_SUBTRACT_ALPHA(uint16_t, 0xffff, 3, 1);
741 case BC_YUVA16161616:
742 case BC_RGBA16161616:
743 APPLY_MASK_SUBTRACT_ALPHA(uint16_t, 0xffff, 4, 0);
750 //printf("MaskUnit::process_package 4 %d\n", get_package_number());
757 MaskEngine::MaskEngine(int cpus)
758 : LoadServer(cpus, cpus * OVERSAMPLE * 2)
759 // : LoadServer(1, 2)
764 MaskEngine::~MaskEngine()
771 point_sets.remove_all_objects();
774 int MaskEngine::points_equivalent(ArrayList<MaskPoint*> *new_points,
775 ArrayList<MaskPoint*> *points)
777 //printf("MaskEngine::points_equivalent %d %d\n", new_points->total, points->total);
778 if(new_points->total != points->total) return 0;
780 for(int i = 0; i < new_points->total; i++)
782 if(!(*new_points->values[i] == *points->values[i])) return 0;
788 void MaskEngine::do_mask(VFrame *output,
789 MaskAutos *keyframe_set,
793 //printf("MaskEngine::do_mask 1\n");
795 MaskAuto *default_auto = (MaskAuto*)keyframe_set->default_auto;
796 MaskAuto *keyframe = (MaskAuto*)keyframe_set->get_prev_auto(position,
801 // Nothing to be done
802 int total_points = 0;
803 for(int i = 0; i < keyframe->masks.total; i++)
805 SubMask *mask = keyframe->get_submask(i);
806 int submask_points = mask->points.total;
807 if(submask_points > 1) total_points += submask_points;
810 //printf("MaskEngine::do_mask 1 %d %d\n", total_points, keyframe->value);
811 // Ignore certain masks
812 if(total_points < 2 ||
813 (keyframe->value == 0 && default_auto->mode == MASK_SUBTRACT_ALPHA))
818 // Fake certain masks
819 if(keyframe->value == 0 && default_auto->mode == MASK_MULTIPLY_ALPHA)
821 output->clear_frame();
825 //printf("MaskEngine::do_mask 1\n");
827 int new_color_model = 0;
829 switch(output->get_color_model())
835 new_color_model = BC_A8;
839 case BC_RGBA16161616:
841 case BC_YUVA16161616:
842 new_color_model = BC_A16;
846 // Determine if recalculation is needed
848 //printf("MaskEngine::do_mask 1 %d\n", recalculate);
850 (mask->get_w() != output->get_w() ||
851 mask->get_h() != output->get_h() ||
852 mask->get_color_model() != new_color_model))
860 //printf("MaskEngine::do_mask %d\n", recalculate);
863 if(point_sets.total != keyframe_set->total_submasks(position, direction))
867 //printf("MaskEngine::do_mask %d\n", recalculate);
871 i < keyframe_set->total_submasks(position, direction) && !recalculate;
874 ArrayList<MaskPoint*> *new_points = new ArrayList<MaskPoint*>;
875 keyframe_set->get_points(new_points, i, position, direction);
876 if(!points_equivalent(new_points, point_sets.values[i])) recalculate = 1;
877 new_points->remove_all_objects();
881 //printf("MaskEngine::do_mask 3 %d\n", recalculate);
883 !EQUIV(keyframe->feather, feather) ||
884 !EQUIV(keyframe->value, value))
893 temp_mask = new VFrame(0,
898 if(keyframe->feather > 0)
899 temp_mask->clear_frame();
902 point_sets.remove_all_objects();
905 i < keyframe_set->total_submasks(position, direction);
908 ArrayList<MaskPoint*> *new_points = new ArrayList<MaskPoint*>;
909 keyframe_set->get_points(new_points, i, position, direction);
910 point_sets.append(new_points);
914 //printf("MaskEngine::do_mask 4 %d\n", recalculate);
917 this->output = output;
918 this->mode = default_auto->mode;
919 this->feather = keyframe->feather;
920 this->value = keyframe->value;
921 //printf("MaskEngine::do_mask 5\n");
928 //printf("MaskEngine::do_mask 6\n");
931 void MaskEngine::init_packages()
933 //printf("MaskEngine::init_packages 1\n");
934 int division = (int)((float)output->get_h() / (total_packages / 2) + 0.5);
935 if(division < 1) division = 1;
937 // Always a multiple of 2 packages exist
938 for(int i = 0; i < get_total_packages() / 2; i++)
940 MaskPackage *part1 = (MaskPackage*)packages[i];
941 MaskPackage *part2 = (MaskPackage*)packages[i + total_packages / 2];
942 part2->row1 = part1->row1 = division * i;
943 part2->row2 = part1->row2 = division * i + division;
944 part2->row1 = part1->row1 = MIN(output->get_h(), part1->row1);
945 part2->row2 = part1->row2 = MIN(output->get_h(), part1->row2);
947 if(i >= (total_packages / 2) - 1)
949 part2->row2 = part1->row2 = output->get_h();
952 part2->apply_mutex->lock();
954 part1->part = RECALCULATE_PART;
955 part2->part = APPLY_PART;
957 //printf("MaskEngine::init_packages 2\n");
960 LoadClient* MaskEngine::new_client()
962 return new MaskUnit(this);
965 LoadPackage* MaskEngine::new_package()
967 return new MaskPackage;