Main Page | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Class Members | File Members

maskengine.C

Go to the documentation of this file.
00001 #include "clip.h"
00002 #include "condition.h"
00003 #include "maskauto.h"
00004 #include "maskautos.h"
00005 #include "maskengine.h"
00006 #include "mutex.h"
00007 #include "vframe.h"
00008 
00009 #include <math.h>
00010 #include <stdint.h>
00011 #include <string.h>
00012 #include <limits.h>
00013 
00014 #include "feather.h"
00015 
00016 
00017 int64_t get_difference(struct timeval *start_time)
00018 {
00019         struct timeval new_time;
00020 
00021         gettimeofday(&new_time, 0);
00022 
00023         new_time.tv_usec -= start_time->tv_usec;
00024         new_time.tv_sec -= start_time->tv_sec;
00025         if(new_time.tv_usec < 0)
00026         {
00027                 new_time.tv_usec += 1000000;
00028                 new_time.tv_sec--;
00029         }
00030 
00031         return (int64_t)new_time.tv_sec * 1000000 + 
00032                 (int64_t)new_time.tv_usec;
00033 
00034 }
00035 
00036 
00037 
00038 MaskPackage::MaskPackage()
00039 {
00040 }
00041 
00042 MaskPackage::~MaskPackage()
00043 {
00044 }
00045 
00046 
00047 
00048 
00049 
00050 MaskUnit::MaskUnit(MaskEngine *engine)
00051  : LoadClient(engine)
00052 {
00053         this->engine = engine;
00054         row_spans_h = 0;
00055         row_spans = 0;
00056 }
00057 
00058 
00059 MaskUnit::~MaskUnit()
00060 {
00061         if (row_spans)
00062         {
00063                 for (int i = 0; i < row_spans_h; i++) 
00064                         free(row_spans[i]);
00065                 delete [] row_spans;
00066         }
00067 }
00068 
00069 #ifndef SQR
00070 #define SQR(x) ((x) * (x))
00071 #endif
00072 
00073 
00074 
00075 inline void MaskUnit::draw_line_clamped(
00076         int draw_x1, 
00077         int draw_y1, 
00078         int draw_x2, 
00079         int draw_y2,
00080         int w,
00081         int h,
00082         int hoffset)
00083 {
00084 //printf("MaskUnit::draw_line_clamped 1 %d %d %d %d\n", x1, y1, x2, y2);
00085         if (draw_y1 == draw_y2) return; 
00086 
00087         if(draw_y2 < draw_y1)
00088         { /* change the order */
00089                 int tmp;
00090                 tmp = draw_x1;
00091                 draw_x1 = draw_x2;
00092                 draw_x2 = tmp;
00093                 tmp = draw_y1;
00094                 draw_y1 = draw_y2;
00095                 draw_y2 = tmp;
00096         }
00097 
00098         float slope = ((float)draw_x2 - draw_x1) / ((float)draw_y2 - draw_y1); 
00099         w--;
00100         for(int y_i = draw_y1; y_i < draw_y2; y_i++) 
00101         { 
00102                 if (y_i >= h) 
00103                         return; // since y gets larger, there is no point in continuing
00104                 else if(y_i >= 0) 
00105                 { 
00106                         int x = (int)(slope * (y_i - draw_y1) + draw_x1); 
00107                         int x_i = CLIP(x, 0, w); 
00108 
00109                         /* now insert into span in order */
00110                         short *span = row_spans[y_i + hoffset]; 
00111                         if (span[0] >= span[1]) { /* do the reallocation */
00112                                 span[1] *= 2;
00113                                 span = row_spans[y_i + hoffset] = (short *) realloc (span, span[1] * sizeof(short)); /* be careful! row_spans has to be updated! */
00114                         };
00115 
00116                         short index = 2;
00117                         while (index < span[0]  && span[index] < x_i)
00118                                 index++;
00119                         for (int j = span[0]; j > index; j--) {       // move forward
00120                                 span[j] = span[j-1];
00121                         }
00122                         span[index] = x_i;
00123                         span[0] ++;
00124                 } 
00125         } 
00126 }
00127 
00128 void MaskUnit::blur_strip(float *val_p, 
00129         float *val_m, 
00130         float *dst, 
00131         float *src, 
00132         int size,
00133         int max)
00134 {
00135         float *sp_p = src;
00136         float *sp_m = src + size - 1;
00137         float *vp = val_p;
00138         float *vm = val_m + size - 1;
00139         float initial_p = sp_p[0];
00140         float initial_m = sp_m[0];
00141 
00142 //printf("MaskUnit::blur_strip %d\n", size);
00143         for(int k = 0; k < size; k++)
00144         {
00145                 int terms = (k < 4) ? k : 4;
00146                 int l;
00147                 for(l = 0; l <= terms; l++)
00148                 {
00149                         *vp += n_p[l] * sp_p[-l] - d_p[l] * vp[-l];
00150                         *vm += n_m[l] * sp_m[l] - d_m[l] * vm[l];
00151                 }
00152 
00153                 for( ; l <= 4; l++)
00154                 {
00155                         *vp += (n_p[l] - bd_p[l]) * initial_p;
00156                         *vm += (n_m[l] - bd_m[l]) * initial_m;
00157                 }
00158                 sp_p++;
00159                 sp_m--;
00160                 vp++;
00161                 vm--;
00162         }
00163 
00164         for(int i = 0; i < size; i++)
00165         {
00166                 float sum = val_p[i] + val_m[i];
00167                 CLAMP(sum, 0, max);
00168                 dst[i] = sum;
00169         }
00170 }
00171 
00172 
00173 
00174 int MaskUnit::do_feather_2(VFrame *output,
00175         VFrame *input, 
00176         float feather, 
00177         int start_out, 
00178         int end_out)
00179 {
00180         
00181         int fint = (int)feather;
00182         DO_FEATHER_N(unsigned char, uint32_t, 0xffff, fint);
00183 
00184 }
00185 
00186 
00187 void MaskUnit::do_feather(VFrame *output,
00188         VFrame *input, 
00189         float feather, 
00190         int start_out, 
00191         int end_out)
00192 {
00193 //printf("MaskUnit::do_feather %f\n", feather);
00194 // Get constants
00195         double constants[8];
00196         double div;
00197         double std_dev = sqrt(-(double)(feather * feather) / (2 * log(1.0 / 255.0)));
00198         div = sqrt(2 * M_PI) * std_dev;
00199         constants[0] = -1.783 / std_dev;
00200         constants[1] = -1.723 / std_dev;
00201         constants[2] = 0.6318 / std_dev;
00202         constants[3] = 1.997  / std_dev;
00203         constants[4] = 1.6803 / div;
00204         constants[5] = 3.735 / div;
00205         constants[6] = -0.6803 / div;
00206         constants[7] = -0.2598 / div;
00207 
00208         n_p[0] = constants[4] + constants[6];
00209         n_p[1] = exp(constants[1]) *
00210                                 (constants[7] * sin(constants[3]) -
00211                                 (constants[6] + 2 * constants[4]) * cos(constants[3])) +
00212                                 exp(constants[0]) *
00213                                 (constants[5] * sin(constants[2]) -
00214                                 (2 * constants[6] + constants[4]) * cos(constants[2]));
00215 
00216         n_p[2] = 2 * exp(constants[0] + constants[1]) *
00217                                 ((constants[4] + constants[6]) * cos(constants[3]) * 
00218                                 cos(constants[2]) - constants[5] * 
00219                                 cos(constants[3]) * sin(constants[2]) -
00220                                 constants[7] * cos(constants[2]) * sin(constants[3])) +
00221                                 constants[6] * exp(2 * constants[0]) +
00222                                 constants[4] * exp(2 * constants[1]);
00223 
00224         n_p[3] = exp(constants[1] + 2 * constants[0]) *
00225                                 (constants[7] * sin(constants[3]) - 
00226                                 constants[6] * cos(constants[3])) +
00227                                 exp(constants[0] + 2 * constants[1]) *
00228                                 (constants[5] * sin(constants[2]) - constants[4] * 
00229                                 cos(constants[2]));
00230         n_p[4] = 0.0;
00231 
00232         d_p[0] = 0.0;
00233         d_p[1] = -2 * exp(constants[1]) * cos(constants[3]) -
00234                                 2 * exp(constants[0]) * cos(constants[2]);
00235 
00236         d_p[2] = 4 * cos(constants[3]) * cos(constants[2]) * 
00237                                 exp(constants[0] + constants[1]) +
00238                                 exp(2 * constants[1]) + exp (2 * constants[0]);
00239 
00240         d_p[3] = -2 * cos(constants[2]) * exp(constants[0] + 2 * constants[1]) -
00241                                 2 * cos(constants[3]) * exp(constants[1] + 2 * constants[0]);
00242 
00243         d_p[4] = exp(2 * constants[0] + 2 * constants[1]);
00244 
00245         for(int i = 0; i < 5; i++) d_m[i] = d_p[i];
00246 
00247         n_m[0] = 0.0;
00248         for(int i = 1; i <= 4; i++)
00249                 n_m[i] = n_p[i] - d_p[i] * n_p[0];
00250 
00251         double sum_n_p, sum_n_m, sum_d;
00252         double a, b;
00253 
00254         sum_n_p = 0.0;
00255         sum_n_m = 0.0;
00256         sum_d = 0.0;
00257         for(int i = 0; i < 5; i++)
00258         {
00259                 sum_n_p += n_p[i];
00260                 sum_n_m += n_m[i];
00261                 sum_d += d_p[i];
00262         }
00263 
00264         a = sum_n_p / (1 + sum_d);
00265         b = sum_n_m / (1 + sum_d);
00266 
00267         for(int i = 0; i < 5; i++)
00268         {
00269                 bd_p[i] = d_p[i] * a;
00270                 bd_m[i] = d_m[i] * b;
00271         }
00272 
00273 
00274 
00275 
00276 
00277 
00278 
00279 
00280 
00281 
00282 
00283 
00284 
00285 
00286 
00287 
00288 
00289 
00290 
00291 
00292 
00293 
00294 #define DO_FEATHER(type, max) \
00295 { \
00296         int frame_w = input->get_w(); \
00297         int frame_h = input->get_h(); \
00298         int size = MAX(frame_w, frame_h); \
00299         float *src = new float[size]; \
00300         float *dst = new float[size]; \
00301         float *val_p = new float[size]; \
00302         float *val_m = new float[size]; \
00303         int start_in = start_out - (int)feather; \
00304         int end_in = end_out + (int)feather; \
00305         if(start_in < 0) start_in = 0; \
00306         if(end_in > frame_h) end_in = frame_h; \
00307         int strip_size = end_in - start_in; \
00308         type **in_rows = (type**)input->get_rows(); \
00309         type **out_rows = (type**)output->get_rows(); \
00310         int j; \
00311  \
00312 /* printf("DO_FEATHER 1\n"); */ \
00313         for(j = 0; j < frame_w; j++) \
00314         { \
00315 /* printf("DO_FEATHER 1.1 %d\n", j); */ \
00316                 bzero(val_p, sizeof(float) * (end_in - start_in)); \
00317                 bzero(val_m, sizeof(float) * (end_in - start_in)); \
00318                 for(int l = 0, k = start_in; k < end_in; l++, k++) \
00319                 { \
00320                         src[l] = (float)in_rows[k][j]; \
00321                 } \
00322  \
00323                 blur_strip(val_p, val_m, dst, src, strip_size, max); \
00324  \
00325                 for(int l = start_out - start_in, k = start_out; k < end_out; l++, k++) \
00326                 { \
00327                         out_rows[k][j] = (type)dst[l]; \
00328                 } \
00329         } \
00330  \
00331         for(j = start_out; j < end_out; j++) \
00332         { \
00333 /* printf("DO_FEATHER 2 %d\n", j); */ \
00334                 bzero(val_p, sizeof(float) * frame_w); \
00335                 bzero(val_m, sizeof(float) * frame_w); \
00336                 for(int k = 0; k < frame_w; k++) \
00337                 { \
00338                         src[k] = (float)out_rows[j][k]; \
00339                 } \
00340  \
00341                 blur_strip(val_p, val_m, dst, src, frame_w, max); \
00342  \
00343                 for(int k = 0; k < frame_w; k++) \
00344                 { \
00345                         out_rows[j][k] = (type)dst[k]; \
00346                 } \
00347         } \
00348  \
00349 /* printf("DO_FEATHER 3\n"); */ \
00350  \
00351         delete [] src; \
00352         delete [] dst; \
00353         delete [] val_p; \
00354         delete [] val_m; \
00355 /* printf("DO_FEATHER 4\n"); */ \
00356 }
00357 
00358 
00359 
00360 
00361 
00362 
00363 
00364 
00365 //printf("do_feather %d\n", frame->get_color_model());
00366         switch(input->get_color_model())
00367         {
00368                 case BC_A8:
00369                         DO_FEATHER(unsigned char, 0xff);
00370                         break;
00371                 
00372                 case BC_A16:
00373                         DO_FEATHER(uint16_t, 0xffff);
00374                         break;
00375         }
00376 
00377 
00378 
00379 
00380 }
00381 
00382 void MaskUnit::process_package(LoadPackage *package)
00383 {
00384         MaskPackage *ptr = (MaskPackage*)package;
00385         
00386         int start_row = SHRT_MIN;         // part for which mask exists
00387         int end_row;
00388         if(engine->recalculate)
00389         {
00390                 VFrame *mask;
00391 //printf("MaskUnit::process_package 1 %d\n", get_package_number());
00392                 if(engine->feather > 0) 
00393                         mask = engine->temp_mask;
00394                 else
00395                         mask = engine->mask;
00396 
00397                 int mask_w = mask->get_w();
00398                 int mask_h = mask->get_h();
00399                 int mask_color_model = mask->get_color_model();
00400                 int oversampled_package_w = mask_w * OVERSAMPLE;
00401                 int oversampled_package_h = (ptr->row2 - ptr->row1) * OVERSAMPLE;
00402                 int local_first_nonempty_rowspan = SHRT_MIN;
00403                 int local_last_nonempty_rowspan = SHRT_MIN;
00404 
00405                 if (!row_spans || row_spans_h != mask_h * OVERSAMPLE) {
00406                         int i;  
00407                         if (row_spans) {   /* size change */
00408                                 for (i = 0; i < row_spans_h; i++) 
00409                                         free(row_spans[i]);
00410                                 delete [] row_spans;
00411                         }
00412                         row_spans_h = mask_h * OVERSAMPLE;
00413                         row_spans = new short *[mask_h * OVERSAMPLE]; 
00414                         for (i= 0; i<mask_h * OVERSAMPLE; i++) {
00415                                 /* we use malloc so we can use realloc */
00416                                 row_spans[i] = (short *)malloc(sizeof(short) * NUM_SPANS);
00417                                 /* [0] is initialized later */
00418                                 row_spans[i][1] = NUM_SPANS;
00419                         }
00420                 }
00421                 
00422 //printf("MaskUnit::process_package 1 %d\n", engine->point_sets.total);
00423                 
00424 
00425 // Draw bezier curves onto span buffer
00426 //struct timeval start_time;
00427 //gettimeofday(&start_time, 0);
00428 
00429                 for(int k = 0; k < engine->point_sets.total; k++)
00430                 {               
00431                         int old_x, old_y;
00432                         old_x = SHRT_MIN; // sentinel
00433                         ArrayList<MaskPoint*> *points = engine->point_sets.values[k];
00434 
00435                         if(points->total < 2) continue;
00436 //printf("MaskUnit::process_package 2 %d %d\n", k, points->total);
00437                         for (int i = ptr->row1 * OVERSAMPLE; i < ptr->row2 * OVERSAMPLE; i++) 
00438                                 row_spans[i][0] = 2; /* initialize to zero */ 
00439                         (ptr->row1*OVERSAMPLE, ptr->row2*OVERSAMPLE); // init just my rows
00440                         for(int i = 0; i < points->total; i++)
00441                         {
00442                                 MaskPoint *point1 = points->values[i];
00443                                 MaskPoint *point2 = (i >= points->total - 1) ? 
00444                                         points->values[0] : 
00445                                         points->values[i + 1];
00446 
00447                                 float x0 = point1->x;
00448                                 float y0 = point1->y;
00449                                 float x1 = point1->x + point1->control_x2;
00450                                 float y1 = point1->y + point1->control_y2;
00451                                 float x2 = point2->x + point2->control_x1;
00452                                 float y2 = point2->y + point2->control_y1;
00453                                 float x3 = point2->x;
00454                                 float y3 = point2->y;
00455 
00456                                 // possible optimization here... since these coordinates are bounding box for curve
00457                                 // we can continue with next curve if they are out of our range
00458 
00459                                 // forward differencing bezier curves implementation taken from GPL code at
00460                                 // http://cvs.sourceforge.net/viewcvs.py/guliverkli/guliverkli/src/subtitles/Rasterizer.cpp?rev=1.3
00461 
00462 
00463 
00464                                 float cx3, cx2, cx1, cx0, cy3, cy2, cy1, cy0;
00465 
00466 
00467                                 // [-1 +3 -3 +1]
00468                                 // [+3 -6 +3  0]
00469                                 // [-3 +3  0  0]
00470                                 // [+1  0  0  0]
00471 
00472                                 cx3 = (-  x0 + 3*x1 - 3*x2 + x3) * OVERSAMPLE;
00473                                 cx2 = ( 3*x0 - 6*x1 + 3*x2) * OVERSAMPLE;
00474                                 cx1 = (-3*x0 + 3*x1) * OVERSAMPLE;
00475                                 cx0 = (   x0) * OVERSAMPLE;
00476 
00477                                 cy3 = (-  y0 + 3*y1 - 3*y2 + y3) * OVERSAMPLE;
00478                                 cy2 = ( 3*y0 - 6*y1 + 3*y2) * OVERSAMPLE;
00479                                 cy1 = (-3*y0 + 3*y1) * OVERSAMPLE;
00480                                 cy0 = (   y0 - ptr->row1) * OVERSAMPLE;
00481 
00482                                 float maxaccel1 = fabs(2*cy2) + fabs(6*cy3);
00483                                 float maxaccel2 = fabs(2*cx2) + fabs(6*cx3);
00484 
00485                                 float maxaccel = maxaccel1 > maxaccel2 ? maxaccel1 : maxaccel2;
00486                                 float h = 1.0;
00487 
00488                                 if(maxaccel > 8.0 * OVERSAMPLE) h = sqrt((8.0 * OVERSAMPLE) / maxaccel);
00489 
00490                                 for(float t = 0.0; t < 1.0; t += h)
00491                                 {
00492                                         int x = (int) (cx0 + t*(cx1 + t*(cx2 + t*cx3)));
00493                                         int y = (int) (cy0 + t*(cy1 + t*(cy2 + t*cy3)));
00494 
00495                                         if (old_x != SHRT_MIN) 
00496                                                 draw_line_clamped(old_x, old_y, x, y, oversampled_package_w, oversampled_package_h, ptr->row1 * OVERSAMPLE);
00497                                         old_x = x;
00498                                         old_y = y;
00499                                 }
00500 
00501                                 int x = (int)(x3 * OVERSAMPLE);
00502                                 int y = (int)((y3 - ptr->row1) * OVERSAMPLE);
00503                                 draw_line_clamped(old_x, old_y, x, y, oversampled_package_w, oversampled_package_h, ptr->row1 * OVERSAMPLE);
00504                                 old_x = (int)x;
00505                                 old_y = (int)y;
00506                 
00507                         }
00508 //printf("MaskUnit::process_package 1\n");
00509 
00510                         // Now we have ordered spans ready!
00511                         //printf("Segment : %i , row1: %i\n", oversampled_package_h, ptr->row1);
00512                         uint16_t value;
00513                         if (mask_color_model == BC_A8)
00514                                 value = (int)((float)engine->value / 100 * 0xff);
00515                         else
00516                                 value = (int)((float)engine->value / 100 * 0xffff);
00517 
00518                         /* Scaneline sampling, inspired by Graphics gems I, page 81 */
00519                         for (int i = ptr->row1; i < ptr->row2; i++) 
00520                         {
00521                                 short min_x = SHRT_MAX;
00522                                 short max_x = SHRT_MIN;
00523                                 int j;                          /* universal counter for 0..OVERSAMPLE-1 */
00524                                 short *span;                    /* current span - set inside loops with j */
00525                                 short span_p[OVERSAMPLE];       /* pointers to current positions in spans */
00526                                 #define P (span_p[j])           /* current span pointer */
00527                                 #define MAXP (span[0])          /* current span length */
00528                                 int num_empty_spans = 0;
00529                                 /* get the initial span pointers ready */
00530                                 for (j = 0; j < OVERSAMPLE; j++)
00531                                 {       
00532                                         span = row_spans[j + i * OVERSAMPLE];
00533                                         P = 2;              /* starting pointers to spans */
00534                                                 /* hypotetical hypotetical fix goes here: take care that there is maximum one empty span for every subpixel */ 
00535                                         if (MAXP != 2) {                                        /* if span is not empty */
00536                                                 if (span[2] < min_x) min_x = span[2];           /* take start of the first span */
00537                                                 if (span[MAXP-1] > max_x) max_x = span[MAXP-1]; /* and end of last */
00538                                         } else              
00539                                         {       /* span is empty */
00540                                                 num_empty_spans ++;     
00541                                         }       
00542                                 }
00543                                 if (num_empty_spans == OVERSAMPLE)
00544                                         continue; /* no work for us here */
00545                                 else 
00546                                 {       /* if we have engaged first nonempty rowspan... remember it to speed up mask applying */
00547                                         if (local_first_nonempty_rowspan < 0 || i < local_first_nonempty_rowspan) 
00548                                                 local_first_nonempty_rowspan = i;  
00549                                         if (i > local_last_nonempty_rowspan) local_last_nonempty_rowspan = i;
00550                                 }
00551                                 /* we have some pixels to fill, do coverage calculation for span */
00552 
00553                                 void *output_row = (unsigned char*)mask->get_rows()[i];
00554                                 min_x = min_x / OVERSAMPLE;
00555                                 max_x = (max_x + OVERSAMPLE - 1) / OVERSAMPLE;
00556                                 
00557                                 /* printf("row %i, pixel range: %i %i, spans0: %i\n", i, min_x, max_x, row_spans[i*OVERSAMPLE][0]-2); */
00558 
00559                                 /* this is not a full loop, since we jump trough h if possible */
00560                                 for (int h = min_x; h <= max_x; h++) 
00561                                 {
00562                                         short pixelleft = h * OVERSAMPLE;  /* leftmost subpixel of pixel*/
00563                                         short pixelright = pixelleft + OVERSAMPLE - 1; /* rightmost subpixel of pixel */
00564                                         uint32_t coverage = 0;
00565                                         int num_left = 0;               /* number of spans that have start left of the next pixel */
00566                                         short right_end = SHRT_MAX;     /* leftmost end of any span - right end of a full scanline */
00567                                         short right_start = SHRT_MAX;   /* leftmost start of any span - left end of empty scanline */
00568 
00569                                         for (j=0; j< OVERSAMPLE; j++) 
00570                                         {       
00571                                                 char chg = 1;
00572                                                 span = row_spans[j + i * OVERSAMPLE];
00573                                                 while (P < MAXP && chg)
00574                                                 {
00575                                                 //      printf("Sp: %i %i\n", span[P], span[P+1]);
00576                                                         if (span[P] == span[P+1])           /* ignore empty spans */
00577                                                         {
00578                                                                 P +=2;
00579                                                                 continue;
00580                                                         }
00581                                                         if (span[P] <= pixelright)          /* if span start is before the end of pixel */
00582                                                                 coverage += MIN(span[P+1], pixelright)  /* 'clip' the span to pixel */
00583                                                                           - MAX(span[P], pixelleft) + 1;
00584                                                         if (span[P+1] <= pixelright) 
00585                                                                 P += 2;
00586                                                         else 
00587                                                                 chg = 0;
00588                                                 } 
00589                                                 if (P == MAXP) 
00590                                                         num_left = -OVERSAMPLE; /* just take care that num_left cannot equal OVERSAMPLE or zero again */
00591                                                 else    
00592                                                 { 
00593                                                         if (span[P] <= pixelright)  /* if span starts before subpixel in the pixel on the right */
00594                                                         {    /* useful for determining filled space till next non-fully-filled pixel */
00595                                                                 num_left ++;                                            
00596                                                                 if (span[P+1] < right_end) right_end = span[P+1]; 
00597                                                         } else 
00598                                                         {    /* useful for determining empty space till next non-empty pixel */
00599                                                                 if (span[P] < right_start) right_start = span[P]; 
00600                                                         }
00601                                                 }
00602                                         }
00603                                         // calculate coverage
00604                                         coverage *= value;
00605                                         if(OVERSAMPLE == 8) coverage >>= 6; \
00606                                         else \
00607                                         if(OVERSAMPLE == 4) coverage >>= 2; \
00608                                         else \
00609                                         if(OVERSAMPLE == 2) coverage >>= 1; \
00610                                         else coverage /= OVERSAMPLE * OVERSAMPLE; \
00611 
00612                                         
00613                                         if (mask_color_model == BC_A8) 
00614                                         {
00615                                                 if (((unsigned char *) output_row)[h] < coverage) /* when we have multiple masks... we don't want aliasing inside areas */
00616                                                         ((unsigned char*)output_row)[h] = coverage;
00617                                         } else
00618                                         {
00619                                                 if (((uint16_t *) output_row)[h] < coverage) /* when we have multiple masks... we don't want aliasing inside areas */
00620                                                         ((uint16_t *) output_row)[h] = coverage;
00621                                         }
00622                                         /* possible optimization: do joining of multiple masks by span logics, not by bitmap logics*/
00623                                         
00624                                         if (num_left == OVERSAMPLE) 
00625                                         {
00626                                                 /* all current spans start more left than next pixel */
00627                                                 /* this means we can probably (if lucky) draw a longer horizontal line */
00628                                                 right_end = (right_end / OVERSAMPLE) - 1; /* last fully covered pixel */
00629                                                 if (right_end > h)
00630                                                 {
00631                                                         if (mask_color_model == BC_A8) 
00632                                                                 memset((char *)output_row + h + 1, value, right_end - h);
00633                                                         else {
00634                                                                 /* we are fucked, since there is no 16bit memset */
00635                                                                 for (int z = h +1; z <= right_end; z++)
00636                                                                         ((uint16_t *) output_row)[z] =  value;
00637                 
00638                                                         }
00639                                                         h = right_end;  
00640                                                 }
00641                                         } else 
00642                                         if (num_left == 0) 
00643                                         {
00644                                                 /* all current spans start right of next pixel */ 
00645                                                 /* this means we can probably (if lucky) skip some pixels */
00646                                                 right_start = (right_start / OVERSAMPLE) - 1; /* last fully empty pixel */
00647                                                 if (right_start > h)
00648                                                 {
00649                                                         h = right_start;
00650                                                 }
00651                                         }
00652                                 }
00653                                 
00654                         }                                       
00655                         
00656                 }
00657                 engine->protect_data.lock();
00658                 if (local_first_nonempty_rowspan < engine->first_nonempty_rowspan)
00659                         engine->first_nonempty_rowspan = local_first_nonempty_rowspan;
00660                 if (local_last_nonempty_rowspan > engine->last_nonempty_rowspan)
00661                         engine->last_nonempty_rowspan = local_last_nonempty_rowspan;
00662                 engine->protect_data.unlock();
00663         
00664 
00665 //              int64_t dif= get_difference(&start_time);
00666 //              printf("diff: %lli\n", dif);
00667         }       /* END OF RECALCULATION! */
00668 
00669 
00670         /* possible optimization: this could be useful for do_feather also */
00671 
00672         // Feather polygon
00673         if(engine->recalculate && engine->feather > 0) 
00674         {       
00675                 /* first take care that all packages are already drawn onto mask */
00676                 pthread_mutex_lock(&engine->stage1_finished_mutex);
00677                 engine->stage1_finished_count ++;
00678                 if (engine->stage1_finished_count == engine->get_total_packages())
00679                 {
00680                         // let others pass
00681                         pthread_cond_broadcast(&engine->stage1_finished_cond);
00682                 }
00683                 else
00684                 {
00685                         // wait until all are finished
00686                         while (engine->stage1_finished_count < engine->get_total_packages())
00687                                 pthread_cond_wait(&engine->stage1_finished_cond, &engine->stage1_finished_mutex);
00688                 }
00689                 pthread_mutex_unlock(&engine->stage1_finished_mutex);
00690                 
00691                 /* now do the feather */
00692 //printf("MaskUnit::process_package 3 %f\n", engine->feather);
00693 
00694         struct timeval start_time;
00695         gettimeofday(&start_time, 0);
00696 
00697         /* 
00698         {
00699         // EXPERIMENTAL CODE to find out how values between old and new do_feather map
00700         // create a testcase and find out the closest match between do_feather_2 at 3 and do_feather
00701         //                      2       3       4       5       6       7       8       10      13      15
00702         // do_feather_2         3       5       7       9       11      13      15      19      25      29
00703         // do_feather_1         2.683   3.401   4.139   4.768   5.315   5.819   6.271   7.093   8.170   8.844           
00704         // diff                         0.718   0.738   0.629   0.547   0.504   0.452
00705         // {(2,2.683),(3,3.401),(4,4.139),(5,4.768),(6,5.315),(7,5.819),(8,6.271),(10,7.093),(13,8.170),(15,8.844)}
00706         // use http://mss.math.vanderbilt.edu/cgi-bin/MSSAgent/~pscrooke/MSS/fitpoly.def
00707         // for calculating the coefficients
00708 
00709                 VFrame *df2 = new VFrame (*engine->mask);
00710                 VFrame *one_sample = new VFrame(*engine->mask);
00711                 do_feather_2(df2, 
00712                         engine->temp_mask, 
00713                         25, 
00714                         ptr->row1, 
00715                         ptr->row2);
00716                 float ftmp;
00717                 for (ftmp = 8.15; ftmp <8.18; ftmp += 0.001) 
00718                 {
00719                         do_feather(one_sample, 
00720                         engine->temp_mask, 
00721                         ftmp, 
00722                         ptr->row1, 
00723                         ptr->row2);
00724                         double squarediff = 0;
00725                         for (int i=0; i< engine->mask->get_h(); i++)
00726                                 for (int j = 0; j< engine->mask->get_w(); j++)
00727                                 {
00728                                         double v1= ((unsigned char *)one_sample->get_rows()[i])[j];
00729                                         double v2= ((unsigned char *)df2->get_rows()[i])[j];
00730                                         squarediff += (v1-v2)*(v1-v2);
00731                                 }
00732                         squarediff = sqrt(squarediff);
00733                         printf("for value 3: ftmp: %2.3f, squarediff: %f\n", ftmp, squarediff);
00734                 }
00735         }
00736         */      
00737         
00738                 int done = 0;
00739                 done = do_feather_2(engine->mask,        // try if we have super fast implementation ready
00740                                 engine->temp_mask,
00741                                 engine->feather * 2 - 1, 
00742                                 ptr->row1, 
00743                                 ptr->row2);
00744                 if (done) {
00745                         engine->realfeather = engine->feather;
00746                 }
00747                 if (!done)
00748                 {
00749                 //      printf("not done\n");
00750                         float feather = engine->feather;
00751                         engine->realfeather = 0.878441 + 0.988534*feather - 0.0490204 *feather*feather  + 0.0012359 *feather*feather*feather;
00752                         do_feather(engine->mask, 
00753                                 engine->temp_mask, 
00754                                 engine->realfeather, 
00755                                 ptr->row1, 
00756                                 ptr->row2); 
00757                 }
00758                 int64_t dif= get_difference(&start_time);
00759                 printf("diff: %lli\n", dif);
00760         } else
00761         if (engine->feather <= 0) {
00762                 engine->realfeather = 0;
00763         }
00764         start_row = MAX (ptr->row1, engine->first_nonempty_rowspan - (int)ceil(engine->realfeather)); 
00765         end_row = MIN (ptr->row2, engine->last_nonempty_rowspan + 1 + (int)ceil(engine->realfeather));
00766 
00767 
00768 
00769 // Apply mask
00770 
00771 
00772 /* use the info about first and last column that are coloured from rowspan!  */
00773 /* possible optimisation: also remember total spans */
00774 /* possible optimisation: lookup for  X * (max - *mask_row) / max, where max is known mask_row and X are variabiles */
00775 #define APPLY_MASK_SUBTRACT_ALPHA(type, max, components, do_yuv) \
00776 { \
00777         int chroma_offset = (max + 1) / 2; \
00778         for(int i = start_row; i < end_row; i++) \
00779         { \
00780         type *output_row = (type*)engine->output->get_rows()[i]; \
00781         type *mask_row = (type*)engine->mask->get_rows()[i]; \
00782         \
00783  \
00784         for(int j  = 0; j < mask_w; j++) \
00785         { \
00786                 if(components == 4) \
00787                 { \
00788                         output_row[3] = output_row[3] * (max - *mask_row) / max; \
00789                 } \
00790                 else \
00791                 { \
00792                         output_row[0] = output_row[0] * (max - *mask_row) / max; \
00793  \
00794                         output_row[1] = output_row[1] * (max - *mask_row) / max; \
00795                         output_row[2] = output_row[2] * (max - *mask_row) / max; \
00796  \
00797                         if(do_yuv) \
00798                         { \
00799                                 output_row[1] += chroma_offset * *mask_row / max; \
00800                                 output_row[2] += chroma_offset * *mask_row / max; \
00801                         } \
00802                 } \
00803                 output_row += components; \
00804                 mask_row += 1;           \
00805         } \
00806         } \
00807 }
00808 
00809 #define APPLY_MASK_MULTIPLY_ALPHA(type, max, components, do_yuv) \
00810 { \
00811         int chroma_offset = (max + 1) / 2; \
00812                 for(int i = ptr->row1; i < ptr->row2; i++) \
00813                 { \
00814         type *output_row = (type*)engine->output->get_rows()[i]; \
00815         type *mask_row = (type*)engine->mask->get_rows()[i]; \
00816  \
00817         if (components == 4) output_row += 3; \
00818         for(int j  = mask_w; j != 0;  j--) \
00819         { \
00820                 if(components == 4) \
00821                 { \
00822                         *output_row = *output_row * *mask_row / max; \
00823                 } \
00824                 else \
00825                 { \
00826                         output_row[0] = output_row[3] * *mask_row / max; \
00827  \
00828                         output_row[1] = output_row[1] * *mask_row / max; \
00829                         output_row[2] = output_row[2] * *mask_row / max; \
00830  \
00831                         if(do_yuv) \
00832                         { \
00833                                 output_row[1] += chroma_offset * (max - *mask_row) / max; \
00834                                 output_row[2] += chroma_offset * (max - *mask_row) / max; \
00835                         } \
00836                 } \
00837                 output_row += components; \
00838                 mask_row += 1;           \
00839         } \
00840         } \
00841 }
00842 
00843 
00844 //struct timeval start_time;
00845 //gettimeofday(&start_time, 0);
00846 
00847 //printf("MaskUnit::process_package 1 %d\n", engine->mode);
00848         int mask_w = engine->mask->get_w();
00849         switch(engine->mode)
00850         {
00851                 case MASK_MULTIPLY_ALPHA:
00852                         switch(engine->output->get_color_model())
00853                         {
00854                                 case BC_RGB888:
00855                                         APPLY_MASK_MULTIPLY_ALPHA(unsigned char, 0xff, 3, 0);
00856                                         break;
00857                                 case BC_YUV888:
00858                                         APPLY_MASK_MULTIPLY_ALPHA(unsigned char, 0xff, 3, 1);
00859                                         break;
00860                                 case BC_YUVA8888:
00861                                 case BC_RGBA8888:
00862                                         APPLY_MASK_MULTIPLY_ALPHA(unsigned char, 0xff, 4, 0);
00863                                         break;
00864                                 case BC_RGB161616:
00865                                         APPLY_MASK_MULTIPLY_ALPHA(uint16_t, 0xffff, 3, 0);
00866                                         break;
00867                                 case BC_YUV161616:
00868                                         APPLY_MASK_MULTIPLY_ALPHA(uint16_t, 0xffff, 3, 1);
00869                                         break;
00870                                 case BC_YUVA16161616:
00871                                 case BC_RGBA16161616:
00872                                         APPLY_MASK_MULTIPLY_ALPHA(uint16_t, 0xffff, 4, 0);
00873                                         break;
00874                         }
00875                         break;
00876 
00877                 case MASK_SUBTRACT_ALPHA:
00878                         switch(engine->output->get_color_model())
00879                         {
00880                                 case BC_RGB888:
00881                                         APPLY_MASK_SUBTRACT_ALPHA(unsigned char, 0xff, 3, 0);
00882                                         break;
00883                                 case BC_YUV888:
00884                                         APPLY_MASK_SUBTRACT_ALPHA(unsigned char, 0xff, 3, 1);
00885                                         break;
00886                                 case BC_YUVA8888:
00887                                 case BC_RGBA8888:
00888                                         APPLY_MASK_SUBTRACT_ALPHA(unsigned char, 0xff, 4, 0);
00889                                         break;
00890                                 case BC_RGB161616:
00891                                         APPLY_MASK_SUBTRACT_ALPHA(uint16_t, 0xffff, 3, 0);
00892                                         break;
00893                                 case BC_YUV161616:
00894                                         APPLY_MASK_SUBTRACT_ALPHA(uint16_t, 0xffff, 3, 1);
00895                                         break;
00896                                 case BC_YUVA16161616:
00897                                 case BC_RGBA16161616:
00898                                         APPLY_MASK_SUBTRACT_ALPHA(uint16_t, 0xffff, 4, 0);
00899                                         break;
00900                         }
00901                         break;
00902         }
00903 //      int64_t dif= get_difference(&start_time);
00904 //      printf("diff: %lli\n", dif);
00905 //printf("diff2: %lli\n", get_difference(&start_time));
00906 //printf("MaskUnit::process_package 4 %d\n", get_package_number());
00907 }
00908 
00909 
00910 
00911 
00912 
00913 MaskEngine::MaskEngine(int cpus)
00914  : LoadServer(cpus, cpus )      /* these two HAVE to be the same, since packages communicate  */
00915 // : LoadServer(1, 2)
00916 {
00917         mask = 0;
00918         pthread_mutex_init(&stage1_finished_mutex, NULL);
00919         pthread_cond_init(&stage1_finished_cond, NULL);
00920 }
00921 
00922 MaskEngine::~MaskEngine()
00923 {
00924         pthread_cond_destroy(&stage1_finished_cond);
00925         pthread_mutex_destroy(&stage1_finished_mutex);
00926         if(mask) 
00927         {
00928                 delete mask;
00929                 delete temp_mask;
00930         }
00931         point_sets.remove_all_objects();
00932 }
00933 
00934 int MaskEngine::points_equivalent(ArrayList<MaskPoint*> *new_points, 
00935         ArrayList<MaskPoint*> *points)
00936 {
00937 //printf("MaskEngine::points_equivalent %d %d\n", new_points->total, points->total);
00938         if(new_points->total != points->total) return 0;
00939         
00940         for(int i = 0; i < new_points->total; i++)
00941         {
00942                 if(!(*new_points->values[i] == *points->values[i])) return 0;
00943         }
00944         
00945         return 1;
00946 }
00947 
00948 void MaskEngine::do_mask(VFrame *output, 
00949         int64_t start_position,
00950         double frame_rate,
00951         double project_frame_rate,
00952         MaskAutos *keyframe_set, 
00953         int direction)
00954 {
00955         int64_t start_position_project = (int64_t)(start_position *
00956                 project_frame_rate / 
00957                 frame_rate);
00958         Auto *current = 0;
00959         MaskAuto *default_auto = (MaskAuto*)keyframe_set->default_auto;
00960         MaskAuto *keyframe = (MaskAuto*)keyframe_set->get_prev_auto(start_position_project, 
00961                 direction,
00962                 current);
00963 
00964 
00965         int total_points = 0;
00966         for(int i = 0; i < keyframe->masks.total; i++)
00967         {
00968                 SubMask *mask = keyframe->get_submask(i);
00969                 int submask_points = mask->points.total;
00970                 if(submask_points > 1) total_points += submask_points;
00971         }
00972 
00973 //printf("MaskEngine::do_mask 1 %d %d\n", total_points, keyframe->value);
00974 // Ignore certain masks
00975         if(total_points < 2 || 
00976                 (keyframe->value == 0 && default_auto->mode == MASK_SUBTRACT_ALPHA))
00977         {
00978                 return;
00979         }
00980 
00981 // Fake certain masks
00982         if(keyframe->value == 0 && default_auto->mode == MASK_MULTIPLY_ALPHA)
00983         {
00984                 output->clear_frame();
00985                 return;
00986         }
00987 
00988 //printf("MaskEngine::do_mask 1\n");
00989 
00990         int new_color_model = 0;
00991         recalculate = 0;
00992         switch(output->get_color_model())
00993         {
00994                 case BC_RGB888:
00995                 case BC_RGBA8888:
00996                 case BC_YUV888:
00997                 case BC_YUVA8888:
00998                         new_color_model = BC_A8;
00999                         break;
01000 
01001                 case BC_RGB161616:
01002                 case BC_RGBA16161616:
01003                 case BC_YUV161616:
01004                 case BC_YUVA16161616:
01005                         new_color_model = BC_A16;
01006                         break;
01007         }
01008 
01009 // Determine if recalculation is needed
01010 
01011         if(mask && 
01012                 (mask->get_w() != output->get_w() ||
01013                 mask->get_h() != output->get_h() ||
01014                 mask->get_color_model() != new_color_model))
01015         {
01016                 delete mask;
01017                 delete temp_mask;
01018                 mask = 0;
01019                 recalculate = 1;
01020         }
01021 
01022         if(!recalculate)
01023         {
01024                 if(point_sets.total != keyframe_set->total_submasks(start_position_project, 
01025                         direction))
01026                         recalculate = 1;
01027         }
01028 
01029         if(!recalculate)
01030         {
01031                 for(int i = 0; 
01032                         i < keyframe_set->total_submasks(start_position_project, 
01033                                 direction) && !recalculate; 
01034                         i++)
01035                 {
01036                         ArrayList<MaskPoint*> *new_points = new ArrayList<MaskPoint*>;
01037                         keyframe_set->get_points(new_points, 
01038                                 i, 
01039                                 start_position_project, 
01040                                 direction);
01041                         if(!points_equivalent(new_points, point_sets.values[i])) recalculate = 1;
01042                         new_points->remove_all_objects();
01043                 }
01044         }
01045 
01046         if(recalculate ||
01047                 !EQUIV(keyframe->feather, feather) ||
01048                 !EQUIV(keyframe->value, value))
01049         {
01050                 recalculate = 1;
01051                 if(!mask) 
01052                 {
01053                         mask = new VFrame(0, 
01054                                         output->get_w(), 
01055                                         output->get_h(),
01056                                         new_color_model);
01057                         temp_mask = new VFrame(0, 
01058                                         output->get_w(), 
01059                                         output->get_h(),
01060                                         new_color_model);
01061                 }
01062                 if(keyframe->feather > 0)
01063                         temp_mask->clear_frame();
01064                 else
01065                         mask->clear_frame();
01066                 point_sets.remove_all_objects();
01067 
01068                 for(int i = 0; 
01069                         i < keyframe_set->total_submasks(start_position_project, 
01070                                 direction); 
01071                         i++)
01072                 {
01073                         ArrayList<MaskPoint*> *new_points = new ArrayList<MaskPoint*>;
01074                         keyframe_set->get_points(new_points, 
01075                                 i, 
01076                                 start_position_project, 
01077                                 direction);
01078                         point_sets.append(new_points);
01079                 }
01080         }
01081 
01082 
01083 
01084         this->output = output;
01085         this->mode = default_auto->mode;
01086         this->feather = keyframe->feather;
01087         this->value = keyframe->value;
01088 
01089 
01090 // Run units
01091         process_packages();
01092 
01093 
01094 //printf("MaskEngine::do_mask 6\n");
01095 }
01096 
01097 void MaskEngine::init_packages()
01098 {
01099 //printf("MaskEngine::init_packages 1\n");
01100         int division = (int)((float)output->get_h() / (get_total_packages()) + 0.5);
01101         if(division < 1) division = 1;
01102 
01103         stage1_finished_count = 0;
01104         if (recalculate) {
01105                 last_nonempty_rowspan = SHRT_MIN;
01106                 first_nonempty_rowspan = SHRT_MAX;
01107         }
01108 // Always a multiple of 2 packages exist
01109         for(int i = 0; i < get_total_packages(); i++)
01110         {
01111                 MaskPackage *pkg = (MaskPackage*)packages[i];
01112                 pkg->row1 = division * i;
01113                 pkg->row2 = MIN (division * i + division, output->get_h());
01114                 
01115                 if(i == get_total_packages() - 1)  // last package
01116                 {
01117                         pkg->row2 = pkg->row2 = output->get_h();
01118                 }
01119 
01120         }
01121 //printf("MaskEngine::init_packages 2\n");
01122 }
01123 
01124 LoadClient* MaskEngine::new_client()
01125 {
01126         return new MaskUnit(this);
01127 }
01128 
01129 LoadPackage* MaskEngine::new_package()
01130 {
01131         return new MaskPackage;
01132 }
01133 

Generated on Sun Jan 8 13:38:57 2006 for Cinelerra-svn by  doxygen 1.4.4