8f6541ae6338bafd4191a32cffc7ad71514fe325
[goodguy/cinelerra.git] / cinelerra-5.1 / cinelerra / maskengine.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  */
21
22 #include "bcsignals.h"
23 #include "condition.h"
24 #include "clip.h"
25 #include "maskauto.h"
26 #include "maskautos.h"
27 #include "maskengine.h"
28 #include "mutex.h"
29 #include "track.h"
30 #include "transportque.inc"
31 #include "vframe.h"
32
33 #include <math.h>
34 #include <stdint.h>
35 #include <string.h>
36
37 void write_mask(VFrame *vfrm, const char *fmt, ...)
38 {
39   va_list ap;    va_start(ap, fmt);
40   char fn[256];  vsnprintf(fn, sizeof(fn), fmt, ap);
41   va_end(ap);
42   FILE *fp = !strcmp(fn,"-") ? stdout : fopen(fn,"w");
43   if( fp ) {
44     int w = vfrm->get_w(), h = vfrm->get_h();
45     int m = vfrm->get_color_model();
46     fprintf(fp,"P5\n%d %d\n%d\n",w,h,m==BC_A8? 0xff : 0xffff);
47     int bpp = m==BC_A8? 1 : 2;
48     fwrite(vfrm->get_data(),bpp*w,h,fp);  fflush(fp);
49     if( fp != stdout ) fclose(fp);
50   }
51 }
52
53 MaskPackage::MaskPackage()
54 {
55 }
56
57 MaskPackage::~MaskPackage()
58 {
59 }
60
61 MaskUnit::MaskUnit(MaskEngine *engine)
62  : LoadClient(engine)
63 {
64         this->engine = engine;
65         spot = 0;
66         r = 0;
67 }
68
69 MaskUnit::~MaskUnit()
70 {
71 }
72
73 void MaskUnit::draw_line(int v, int ix1, int iy1, int ix2, int iy2)
74 {
75         if( iy1 == iy2 ) return;
76         int x1 = iy1 < iy2 ? ix1 : ix2;
77         int y1 = iy1 < iy2 ? iy1 : iy2;
78         int x2 = iy1 < iy2 ? ix2 : ix1;
79         int y2 = iy1 < iy2 ? iy2 : iy1;
80         float slope = (float)(x2-x1) / (y2-y1);
81         int dy = y1 - start_y;
82         int i = dy < 0 ? (y1=start_y, -dy) : 0;
83         if( y2 > end_y ) y2 = end_y;
84         if( y2 < start_y || y1 >= end_y ) return;
85
86         VFrame *temp = engine->temp;
87         int w1 = temp->get_w()-1;
88         temp_t **rows = (temp_t **)temp->get_rows();
89         for( int y=y1; y<y2; ++i,++y ) {
90                 int x = (int)(i*slope + x1);
91                 bclamp(x, 0, w1);
92                 rows[y][x] = rows[y][x] == v ? 0 : v;
93         }
94 }
95
96 void MaskUnit::draw_fill(int v)
97 {
98         VFrame *temp = engine->temp;
99         int temp_w = temp->get_w();
100         temp_t **rows = (temp_t**)temp->get_rows();
101
102         for( int y=start_y; y<end_y; ++y ) {
103                 temp_t *row = rows[y];
104                 int value = 0, total = 0;
105                 for( int x=0; x<temp_w; ++x )
106                         if( row[x] == v ) ++total;
107                 if( total < 2 ) continue;
108                 if( total & 0x1 ) --total;
109                 for( int x=0; x<temp_w; ++x ) {
110                         if( row[x]==v && total>0 ) {
111                                 --total;
112                                 value = value ? 0 : v;
113                         }
114                         else if( value )
115                                 row[x] = value;
116                 }
117         }
118 }
119
120 void MaskUnit::draw_feather(int ix1,int iy1, int ix2,int iy2)
121 {
122         int x1 = iy1 < iy2 ? ix1 : ix2;
123         int y1 = iy1 < iy2 ? iy1 : iy2;
124         int x2 = iy1 < iy2 ? ix2 : ix1;
125         int y2 = iy1 < iy2 ? iy2 : iy1;
126         VFrame *temp = engine->temp;
127         int h = temp->get_h();
128         if( y2 < 0 || y1 >= h ) return;
129
130         int x = x1, y = y1;
131         int dx = x2-x1, dy = y2-y1;
132         int dx2 = 2*dx, dy2 = 2*dy;
133         if( dx < 0 ) dx = -dx;
134         int m = dx > dy ? dx : dy, n = m;
135         if( dy >= dx ) {
136                 if( dx2 >= 0 ) do {     /* +Y, +X */
137                         draw_spot(x, y++);
138                         if( (m -= dx2) < 0 ) { m += dy2;  ++x; }
139                 } while( --n >= 0 );
140                 else do {              /* +Y, -X */
141                         draw_spot(x, y++);
142                         if( (m += dx2) < 0 ) { m += dy2;  --x; }
143                 } while( --n >= 0 );
144         }
145         else {
146                 if( dx2 >= 0 ) do {     /* +X, +Y */
147                         draw_spot(x++, y);
148                         if( (m -= dy2) < 0 ) { m += dx2;  ++y; }
149                 } while( --n >= 0 );
150                 else do {              /* -X, +Y */
151                         draw_spot(x--, y);
152                         if( (m -= dy2) < 0 ) { m -= dx2;  ++y; }
153                 } while( --n >= 0 );
154         }
155 }
156
157 void MaskUnit::draw_spot(int ix, int iy)
158 {
159         int rr = r * r, n = abs(r), rv = r * v;
160         if( iy < start_y-n || iy >= end_y+n ) return;
161         VFrame *temp = engine->temp;
162         int w1 = temp->get_w()-1, h1 = temp->get_h()-1;
163         int xs = ix - n;  bclamp(xs, 0, w1);
164         int xn = ix + n;  bclamp(xn, 0, w1);
165         int ys = iy - n;  bclamp(ys, 0, h1);
166         int yn = iy + n;  bclamp(yn, 0, h1);
167
168         temp_t **rows = (temp_t**)temp->get_rows();
169         for( int y=ys ; y<=yn; ++y ) {
170                 temp_t *row = rows[y];
171                 for( int x=xs; x<=xn; ++x ) {
172                         int dx = x-ix, dy = y-iy;
173                         int dd = dx*dx + dy*dy;
174                         if( dd >= rr ) continue;
175                         temp_t *rp = &row[x], a = spot[dd];
176                         if( rv*(*rp-a) < 0 ) *rp = a;
177                 }
178         }
179 }
180
181 void MaskUnit::process_package(LoadPackage *package)
182 {
183         MaskPackage *ptr = (MaskPackage*)package;
184         start_y = ptr->start_y;
185         end_y = ptr->end_y;
186         if( start_y >= end_y ) return;
187         mask_model = engine->mask->get_color_model();
188         VFrame *temp = engine->temp;
189         if( engine->recalculate && engine->step == DO_MASK ) {
190 // Draw masked region of polygons on temp
191                 for( int k=0; k<engine->edges.size(); ++k ) {
192                         if( !engine->edges[k] ) continue;
193                         MaskEdge &edge = *engine->edges[k];
194                         if( edge.size() < 3 ) continue;
195                         int v = k + 1;
196                         for( int i=0; i<edge.size(); ++i ) {
197                                 MaskCoord a = edge[i];
198                                 MaskCoord b = i<edge.size()-1 ? edge[i+1] : edge[0];
199                                 draw_line(v, a.x,a.y, b.x,b.y);
200                         }
201                         draw_fill(v);
202                 }
203 // map temp to fader alpha
204                 int temp_w = temp->get_w();
205                 temp_t **rows = (temp_t**)temp->get_rows();
206                 temp_t *fade = engine->fade;
207                 for( int y=start_y; y<end_y; ++y ) {
208                         temp_t *tp = rows[y];
209                         for( int i=temp_w; --i>=0; ++tp ) *tp = fade[*tp];
210                 }
211         }
212         if( engine->recalculate && engine->step == DO_FEATHER ) {
213 // draw feather
214                 for( int k=0; k<engine->edges.size(); ++k ) {
215                         if( !(v = engine->faders[k]) ) continue;
216                         if( !(r = engine->feathers[k]) ) continue;
217                         MaskEdge &edge = *engine->edges[k];
218                         if( !edge.size() ) continue;
219                         float rv = r * v, vv = fabs(v);
220                         int fg = 0xffff * (rv >= 0 ? vv : 0);
221                         int bg = 0xffff * (rv >= 0 ? 0 : vv);
222                         int rr = r*r;  double dr = 1./rr;
223                         // gausian, rr is x**2, limit 1/255
224                         double sig2 = -log(255.0);
225                         temp_t psf[rr+1];  spot = psf;
226                         for( int i=0; i<=rr; ++i ) {
227                                 double d = exp(i*dr * sig2);
228                                 psf[i] = d*fg + (1-d)*bg;
229                         }
230                         int n = edge.size();
231                         for( int i=0; i<n; ++i ) {
232                                 MaskCoord &a = edge[i];
233                                 MaskCoord &b = i<edge.size()-1 ? edge[i+1] : edge[0];
234                                 draw_feather(a.x,a.y, b.x,b.y);
235                         }
236                 }
237
238 #define REMAP(cmodel, type, expr) case cmodel: { \
239 type **msk_rows = (type**)engine->mask->get_rows(); \
240 for( int y=start_y; y<end_y; ++y ) { \
241         temp_t *rp = rows[y]; \
242         type *mp = msk_rows[y]; \
243         for( int i=temp_w; --i>=0; ++rp,++mp ) *mp = expr; \
244 } } break
245 // map alpha to mask
246                 const float to_flt = 1/65535.;
247                 int temp_w = temp->get_w();
248                 temp_t **rows = (temp_t**)temp->get_rows();
249                 switch( mask_model ) {
250                 REMAP(BC_A8, uint8_t, *rp >> 8);
251                 REMAP(BC_A16, uint16_t, *rp);
252                 REMAP(BC_A_FLOAT, float, *rp * to_flt);
253                 }
254         }
255
256 // Apply mask
257         if( engine->step == DO_APPLY ) {
258                 int mask_w = engine->mask->get_w();
259                 uint8_t **out_rows = engine->output->get_rows();
260                 uint8_t **msk_rows = engine->mask->get_rows();
261 #define APPLY_MASK_ALPHA(cmodel, type, max, components, do_yuv) \
262 case cmodel: \
263 for( int y=ptr->start_y; y<ptr->end_y; ++y ) { \
264         type *out_row = (type*)out_rows[y]; \
265         type *msk_row = (type*)msk_rows[y]; \
266         type chroma_offset = (int)(max + 1) / 2; \
267         for( int x=0; x<mask_w; ++x ) { \
268                 type a = msk_row[x], b = max-a; \
269                 if( components == 4 ) { \
270                         out_row[x*4 + 3] = out_row[x*4 + 3]*b / max; \
271                 } \
272                 else { \
273                         out_row[x*3 + 0] = out_row[x*3 + 0]*b / max; \
274                         out_row[x*3 + 1] = out_row[x*3 + 1]*b / max; \
275                         out_row[x*3 + 2] = out_row[x*3 + 2]*b / max; \
276                         if( do_yuv ) { \
277                                 out_row[x*3 + 1] += chroma_offset*a / max; \
278                                 out_row[x*3 + 2] += chroma_offset*a / max; \
279                         } \
280                 } \
281         } \
282 } break
283
284                 switch( engine->output->get_color_model() ) { \
285                 APPLY_MASK_ALPHA(BC_RGB888, uint8_t, 0xff, 3, 0); \
286                 APPLY_MASK_ALPHA(BC_RGB_FLOAT, float, 1.0, 3, 0); \
287                 APPLY_MASK_ALPHA(BC_YUV888, uint8_t, 0xff, 3, 1); \
288                 APPLY_MASK_ALPHA(BC_RGBA_FLOAT, float, 1.0, 4, 0); \
289                 APPLY_MASK_ALPHA(BC_YUVA8888, uint8_t, 0xff, 4, 1); \
290                 APPLY_MASK_ALPHA(BC_RGBA8888, uint8_t, 0xff, 4, 0); \
291                 APPLY_MASK_ALPHA(BC_RGB161616, uint16_t, 0xffff, 3, 0); \
292                 APPLY_MASK_ALPHA(BC_YUV161616, uint16_t, 0xffff, 3, 1); \
293                 APPLY_MASK_ALPHA(BC_YUVA16161616, uint16_t, 0xffff, 4, 1); \
294                 APPLY_MASK_ALPHA(BC_RGBA16161616, uint16_t, 0xffff, 4, 0); \
295                 }
296         }
297 }
298
299
300 MaskEngine::MaskEngine(int cpus)
301  : LoadServer(cpus, 2*cpus)
302 // : LoadServer(1, 1)
303 {
304         mask = 0;
305         temp = 0;
306 }
307
308 MaskEngine::~MaskEngine()
309 {
310         delete mask;
311         delete temp;
312         for( int i = 0; i < point_sets.total; i++ )
313                 point_sets[i]->remove_all_objects();
314         point_sets.remove_all_objects();
315 }
316
317 int MaskEngine::points_equivalent(MaskPoints *new_points,
318         MaskPoints *points)
319 {
320 //printf("MaskEngine::points_equivalent %d %d\n", new_points->total, points->total);
321         if( new_points->total != points->total ) return 0;
322
323         for( int i = 0; i < new_points->total; i++ ) {
324                 if( !(*new_points->get(i) == *points->get(i)) ) return 0;
325         }
326
327         return 1;
328 }
329
330 void MaskEngine::do_mask(VFrame *output,
331         int64_t start_position_project,
332         MaskAutos *keyframe_set,
333         MaskAuto *keyframe,
334         MaskAuto *default_auto)
335 {
336         this->output = output;
337         recalculate = 0;
338         int mask_model = 0;
339
340         switch( output->get_color_model() ) {
341         case BC_RGB_FLOAT:
342         case BC_RGBA_FLOAT:
343                 mask_model = BC_A_FLOAT;
344                 break;
345
346         case BC_RGB888:
347         case BC_RGBA8888:
348         case BC_YUV888:
349         case BC_YUVA8888:
350                 mask_model = BC_A8;
351                 break;
352
353         case BC_RGB161616:
354         case BC_RGBA16161616:
355         case BC_YUV161616:
356         case BC_YUVA16161616:
357                 mask_model = BC_A16;
358                 break;
359         }
360
361 // Determine if recalculation is needed
362 SET_TRACE
363
364         int mask_w = output->get_w(), mask_h = output->get_h();
365         if( mask && ( mask->get_color_model() != mask_model ||
366             mask->get_w() != mask_w || mask->get_h() != mask_h ) ) {
367                 delete mask;  mask = 0;
368                 recalculate = 1;
369         }
370         if( temp && ( temp->get_w() != mask_w || temp->get_h() != mask_h ) ) {
371                 delete temp;  temp = 0;
372         }
373
374         total_submasks = keyframe_set->total_submasks(start_position_project, PLAY_FORWARD);
375         if( total_submasks != point_sets.size() )
376                 recalculate = 1;
377
378         for( int i=0; i<total_submasks && !recalculate; ++i ) {
379                 float new_fader = keyframe_set->get_fader(start_position_project, i, PLAY_FORWARD);
380                 if( new_fader != faders[i] ) { recalculate = 1;  break; }
381                 float new_feather = keyframe_set->get_feather(start_position_project, i, PLAY_FORWARD);
382                 if( new_feather != feathers[i] ) { recalculate = 1;  break; }
383                 MaskPoints new_points;
384                 keyframe_set->get_points(&new_points, i,
385                                 start_position_project, PLAY_FORWARD);
386                 if( !points_equivalent(&new_points, point_sets[i]) )
387                         recalculate = 1;
388         }
389
390         if( recalculate ) {
391                 for( int i = 0; i < point_sets.total; i++ ) {
392                         MaskPoints *points = point_sets[i];
393                         points->remove_all_objects();
394                 }
395                 point_sets.remove_all_objects();
396                 edges.remove_all_objects();
397                 faders.remove_all();
398                 feathers.remove_all();
399                 fade[0] = 0;
400
401                 int show_mask = keyframe_set->track->masks;
402                 for( int i=0; i<total_submasks; ++i ) {
403                         float fader = keyframe_set->get_fader(start_position_project, i, PLAY_FORWARD);
404                         float v = fader / 100;
405                         faders.append(v);
406                         temp_t t = fabs(v) * 0xffff;
407                         if( fader < 0 ) {
408                                 if( fade[0] < t ) fade[0] = t;
409                                 t = 0;
410                         }
411                         fade[i+1] = t;
412                         float feather = keyframe_set->get_feather(start_position_project, i, PLAY_FORWARD);
413                         feathers.append(feather);
414                         MaskPoints *new_points = new MaskPoints();
415                         keyframe_set->get_points(new_points, i, start_position_project, PLAY_FORWARD);
416                         point_sets.append(new_points);
417                         MaskEdge *edge = edges.append(new MaskEdge());
418                         if( !((show_mask>>i) & 1) ) continue;
419                         edge->load(*new_points, 0);
420                 }
421 // draw mask
422                 if( !mask ) mask = new VFrame(mask_w, mask_h, mask_model, 0);
423                 if( !temp ) temp = new VFrame(mask_w, mask_h, BC_A16, 0);
424                 mask->clear_frame();
425                 temp->clear_frame();
426                 step = DO_MASK;
427                 process_packages();
428                 step = DO_FEATHER;
429                 process_packages();
430         }
431 // Run units
432 SET_TRACE
433         step = DO_APPLY;
434         process_packages();
435 SET_TRACE
436 }
437
438 void MaskEngine::init_packages()
439 {
440 SET_TRACE
441 //printf("MaskEngine::init_packages 1\n");
442         int x0 = 0, y0 = 0, i = 0, n = get_total_packages();
443         int out_w = output->get_w(), out_h = output->get_h();
444 SET_TRACE
445         while( i < n ) {
446                 MaskPackage *ptr = (MaskPackage*)get_package(i++);
447                 int x1 = (out_w * i) / n, y1 = (out_h * i) / n;
448                 ptr->start_x = x0;  ptr->end_x = x1;
449                 ptr->start_y = y0;  ptr->end_y = y1;
450                 x0 = x1;  y0 = y1;
451         }
452 SET_TRACE
453 //printf("MaskEngine::init_packages 2\n");
454 }
455
456 LoadClient* MaskEngine::new_client()
457 {
458         return new MaskUnit(this);
459 }
460
461 LoadPackage* MaskEngine::new_package()
462 {
463         return new MaskPackage;
464 }
465