no longer need ffmpeg patch0 which was for Termux
[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     uint8_t **rows = (uint8_t**)vfrm->get_rows();
45     int w = vfrm->get_w(), h = vfrm->get_h();
46     int m = vfrm->get_color_model();
47     int bpp = m==BC_A8? 1 : 2;
48     fprintf(fp,"P5\n%d %d\n%d\n",w,h,255);
49     for( int y=0; y<h; ++y ) {
50       uint8_t *bp = rows[y];
51       for( int x=0; x<w; ++x,bp+=bpp ) {
52         int b = m==BC_A8 ? *(uint8_t*)bp : *(uint16_t*)bp>>8;
53         putc(b,fp);
54       }
55     }
56     fflush(fp);
57     if( fp != stdout ) fclose(fp);
58   }
59 }
60
61 MaskPackage::MaskPackage()
62 {
63 }
64
65 MaskPackage::~MaskPackage()
66 {
67 }
68
69 MaskUnit::MaskUnit(MaskEngine *engine)
70  : LoadClient(engine)
71 {
72         this->engine = engine;
73 }
74
75 MaskUnit::~MaskUnit()
76 {
77 }
78
79 void MaskUnit::clear_mask(VFrame *msk, int a)
80 {
81         temp_t **mrows = (temp_t **)msk->get_rows();
82         int w = msk->get_w();
83         for( int y=start_y; y<end_y; ++y ) {
84                 temp_t *mrow = mrows[y];
85                 for( int x=0; x<w; ++x ) mrow[x] = a;
86         }
87 }
88
89 void MaskUnit::draw_line(int ix1, int iy1, int ix2, int iy2)
90 {
91         if( iy1 == iy2 ) return;
92         int x1 = iy1 < iy2 ? ix1 : ix2;
93         int y1 = iy1 < iy2 ? iy1 : iy2;
94         int x2 = iy1 < iy2 ? ix2 : ix1;
95         int y2 = iy1 < iy2 ? iy2 : iy1;
96         float slope = (float)(x2-x1) / (y2-y1);
97         int dy = y1 - start_y;
98         int i = dy < 0 ? (y1=start_y, -dy) : 0;
99         if( y2 > end_y ) y2 = end_y;
100         if( y2 < start_y || y1 >= end_y ) return;
101
102         VFrame *in = engine->in;
103         int w1 = in->get_w()-1;
104         temp_t **irows = (temp_t **)in->get_rows();
105         for( int y=y1; y<y2; ++i,++y ) {
106                 int x = (int)(i*slope + x1);
107                 bclamp(x, 0, w1);
108                 irows[y][x] = irows[y][x] == fc ? bc : fc;
109         }
110 }
111 void MaskUnit::draw_fill()
112 {
113         VFrame *in = engine->in;
114         temp_t **irows = (temp_t**)in->get_rows();
115         int w = in->get_w();
116
117         for( int y=start_y; y<end_y; ++y ) {
118                 temp_t *irow = irows[y];
119                 int total = 0;
120                 for( int x=0; x<w; ++x )
121                         if( irow[x] == fc ) ++total;
122                 if( total < 2 ) continue;
123                 if( total & 0x1 ) --total;
124                 int inside = 0;
125                 for( int x=0; x<w; ++x ) {
126                         if( irow[x]==fc && total>0 ) {
127                                 --total;
128                                 inside = 1-inside;
129                         }
130                         else if( inside )
131                                 irow[x] = fc;
132                 }
133         }
134 }
135
136 void MaskUnit::draw_feather(int ix1,int iy1, int ix2,int iy2)
137 {
138         int x1 = iy1 < iy2 ? ix1 : ix2;
139         int y1 = iy1 < iy2 ? iy1 : iy2;
140         int x2 = iy1 < iy2 ? ix2 : ix1;
141         int y2 = iy1 < iy2 ? iy2 : iy1;
142         VFrame *in = engine->in;
143         int h = in->get_h();
144         if( y2 < 0 || y1 >= h ) return;
145
146         int x = x1, y = y1;
147         int dx = x2-x1, dy = y2-y1;
148         int dx2 = 2*dx, dy2 = 2*dy;
149         if( dx < 0 ) dx = -dx;
150         int m = dx > dy ? dx : dy, i = m;
151         if( dy >= dx ) {
152                 if( dx2 >= 0 ) do {     /* +Y, +X */
153                         draw_edge(x, y++);
154                         if( (m -= dx2) < 0 ) { m += dy2;  ++x; }
155                 } while( --i >= 0 );
156                 else do {              /* +Y, -X */
157                         draw_edge(x, y++);
158                         if( (m += dx2) < 0 ) { m += dy2;  --x; }
159                 } while( --i >= 0 );
160         }
161         else {
162                 if( dx2 >= 0 ) do {     /* +X, +Y */
163                         draw_edge(x++, y);
164                         if( (m -= dy2) < 0 ) { m += dx2;  ++y; }
165                 } while( --i >= 0 );
166                 else do {              /* -X, +Y */
167                         draw_edge(x--, y);
168                         if( (m -= dy2) < 0 ) { m -= dx2;  ++y; }
169                 } while( --i >= 0 );
170         }
171 }
172
173 void MaskUnit::draw_edge(int ix, int iy)
174 {
175         if( iy < start_y || iy >= end_y ) return;
176         VFrame *in = engine->in;
177         temp_t **irows = (temp_t **)in->get_rows();
178         irows[iy][ix] = fc;
179 }
180 void MaskUnit::draw_filled_polygon(MaskEdge &edge)
181 {
182         for( int i=0; i<edge.size(); ++i ) {
183                 MaskCoord a = edge[i];
184                 MaskCoord b = i<edge.size()-1 ? edge[i+1] : edge[0];
185                 draw_line(a.x,a.y, b.x,b.y);
186         }
187         draw_fill();
188 }
189
190 void MaskUnit::feather_x(VFrame *in, VFrame *out)
191 {
192         float *psf = engine->psf;  int psz = engine->psz;
193         temp_t **orows = (temp_t**)out->get_rows();
194         temp_t **irows = (temp_t**)in->get_rows();
195         int w = in->get_w(), w1 = w-1;
196         for( int y=start_y; y<end_y; ++y ) {
197                 temp_t *rp = irows[y]; 
198                 for( int x=0; x<w; ++x ) {
199                         temp_t c = rp[x], f = c * psf[0];
200                         for( int i=1; i<psz; ++i ) {
201                                 int l = x-i;    if( l < 0 ) l = 0;
202                                 int r = x+i;    if( r > w1 ) r = w1;
203                                 temp_t g = bmax(rp[l], rp[r]) * psf[i];
204                                 if( f < g ) f = g;
205                         }
206                         orows[y][x] = c > f ? c : f;
207                 }
208         }
209 }
210 void MaskUnit::feather_y(VFrame *in, VFrame *out)
211 {
212         float *psf = engine->psf;  int psz = engine->psz;
213         temp_t **orows = (temp_t**)out->get_rows();
214         temp_t **irows = (temp_t**)in->get_rows();
215         int h = in->get_h(), h1 = h-1;
216         for( int y=0; y<h; ++y ) {
217                 temp_t *rp = irows[y];
218                 for( int x=start_x; x<end_x; ++x ) {
219                         temp_t c = rp[x], f = c * psf[0];
220                         for( int i=1; i<psz; ++i ) {
221                                 int d = y-i;    if( d < 0 ) d = 0;
222                                 int u = y+i;    if( u > h1 ) u = h1;
223                                 temp_t *drow = irows[d], *urow = irows[u];
224                                 temp_t g = bmax(drow[x], urow[x]) * psf[i];
225                                 if( f < g ) f = g;
226                         }
227                         orows[y][x] = c > f ? c : f;
228                 }
229         }
230 }
231 void MaskUnit::mask_blend(VFrame *in, VFrame *mask, float r, float v)
232 {
233         temp_t **irows = (temp_t**)in->get_rows();
234         temp_t **mrows = (temp_t**)mask->get_rows();
235         const int mn = 0x0000, mx = 0xffff;
236         int iv = v>=0 ? 1 : -1;
237         float rr = r!=0 ? r : 1;
238         float rv = rr*v>=0. ? 1 : -1;;
239         int vv = (v>=0. ? 1.-v : 1.+v) * mx;
240         unsigned fg = rv>0. ? vv : mx;
241         unsigned bg = rv>0. ? mx : vv;
242         int w = in->get_w();
243         int b = r<0 ? mx : mn;
244         for( int y=start_y; y<end_y; ++y ) {
245                 temp_t *irow = irows[y], *mrow = mrows[y];
246                 for( int x=0; x<w; ++x ) {
247                         temp_t c = irow[x];
248                         if( c == b ) continue;
249                         temp_t a = (c*fg + (mx-c)*bg) / mx;
250                         temp_t *cp = mrow + x, color = *cp;
251                         if( iv*(color-a) > 0 ) *cp = a;
252                 }
253         }
254 }
255 void MaskUnit::apply_mask_alpha(VFrame *output, VFrame *mask)
256 {
257         int w = mask->get_w();
258         uint8_t **orows = output->get_rows();
259         temp_t **mrows = (temp_t **)mask->get_rows();
260 #define APPLY_MASK_ALPHA(cmodel, type, max, components, do_yuv) \
261 case cmodel: \
262 for( int y=start_y; y<end_y; ++y ) { \
263         type *orow = (type*)orows[y]; \
264         temp_t *mrow = mrows[y]; \
265         for( int x=0; x<w; ++x ) { \
266                 temp_t a = mrow[x]; \
267                 if( components == 4 ) { \
268                         orow[x*4 + 3] = orow[x*4 + 3]*a / 0xffff; \
269                 } \
270                 else { \
271                         orow[x*3 + 0] = orow[x*3 + 0]*a / 0xffff; \
272                         orow[x*3 + 1] = orow[x*3 + 1]*a / 0xffff; \
273                         orow[x*3 + 2] = orow[x*3 + 2]*a / 0xffff; \
274                         if( do_yuv ) { \
275                                 a = 0xffff-a; \
276                                 type chroma_offset = (int)(max + 1) / 2; \
277                                 orow[x*3 + 1] += chroma_offset*a / 0xffff; \
278                                 orow[x*3 + 2] += chroma_offset*a / 0xffff; \
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 void MaskUnit::process_package(LoadPackage *package)
300 {
301         pkg = (MaskPackage*)package;
302         start_x = pkg->start_x;  end_x = pkg->end_x;
303         start_y = pkg->start_y;  end_y = pkg->end_y;
304         MaskEdge *edge = engine->edge;
305         float r = engine->r, v = engine->v;
306         VFrame *in = engine->in;
307         VFrame *out = engine->out;
308         VFrame *mask = engine->mask;
309         switch( engine->step ) {
310         case DO_MASK: {
311 // Draw masked region of polygons on in
312                 if( edge->size() < 3 ) break;
313                 bc = r>=0 ? 0 : 0xffff;
314                 fc = r>=0 ? 0xffff : 0;
315                 clear_mask(in, bc);
316                 if( bc == fc ) break;
317                 draw_filled_polygon(*edge);
318                 break; }
319         case DO_FEATHER_X: {
320                 feather_x(in, out);
321                 break; }
322         case DO_FEATHER_Y: {
323                 feather_y(out, in);
324                 break; }
325         case DO_MASK_BLEND: {
326                 mask_blend(in, mask, r, v);
327                 break; }
328         case DO_APPLY: {
329                 apply_mask_alpha(engine->output, mask);
330                 break; }
331         }
332 }
333
334
335 MaskEngine::MaskEngine(int cpus)
336  : LoadServer(cpus, 2*cpus)
337 // : LoadServer(1, 1)
338 {
339         mask = 0;
340         in = 0;
341         out = 0;
342 }
343
344 MaskEngine::~MaskEngine()
345 {
346         delete mask;
347         delete in;
348         delete out;
349 }
350
351 int MaskEngine::points_equivalent(MaskPoints *new_points,
352         MaskPoints *points)
353 {
354 //printf("MaskEngine::points_equivalent %d %d\n", new_points->total, points->total);
355         if( new_points->total != points->total ) return 0;
356
357         for( int i = 0; i < new_points->total; i++ ) {
358                 if( !(*new_points->get(i) == *points->get(i)) ) return 0;
359         }
360
361         return 1;
362 }
363
364 void MaskEngine::clear_mask(VFrame *msk, int a)
365 {
366         temp_t **mrows = (temp_t **)msk->get_rows();
367         int w = msk->get_w(), h = msk->get_h();
368         for( int y=0; y<h; ++y ) {
369                 temp_t *mrow = mrows[y];
370                 for( int x=0; x<w; ++x ) mrow[x] = a;
371         }
372 }
373 void MaskEngine::draw_point_spot(float r)
374 {
375         double sig2 = -log(255.0)/((double)r*r);
376         for( int i=0; i<psz; ++i )
377                 psf[i] = exp(i*i * sig2);
378 }
379
380 void MaskEngine::do_mask(VFrame *output,
381         int64_t start_position_project,
382         MaskAutos *keyframe_set,
383         MaskAuto *keyframe,
384         MaskAuto *default_auto)
385 {
386         this->output = output;
387         recalculate = 0;
388         int mask_model = 0;
389
390         switch( output->get_color_model() ) {
391         case BC_RGB_FLOAT:
392         case BC_RGBA_FLOAT:
393                 mask_model = BC_A_FLOAT;
394                 break;
395
396         case BC_RGB888:
397         case BC_RGBA8888:
398         case BC_YUV888:
399         case BC_YUVA8888:
400                 mask_model = BC_A8;
401                 break;
402
403         case BC_RGB161616:
404         case BC_RGBA16161616:
405         case BC_YUV161616:
406         case BC_YUVA16161616:
407                 mask_model = BC_A16;
408                 break;
409         }
410
411 // Determine if recalculation is needed
412         int mask_w = output->get_w(), mask_h = output->get_h();
413         if( mask && ( mask->get_color_model() != mask_model ||
414             mask->get_w() != mask_w || mask->get_h() != mask_h ) ) {
415                 delete mask;  mask = 0;
416                 recalculate = 1;
417         }
418         if( in && ( in->get_w() != mask_w || in->get_h() != mask_h ) ) {
419                 delete in;  in = 0;
420                 delete out; out = 0;
421         }
422
423         total_submasks = keyframe_set->total_submasks(start_position_project, PLAY_FORWARD);
424         if( total_submasks != point_sets.size() )
425                 recalculate = 1;
426
427         for( int i=0; i<total_submasks && !recalculate; ++i ) {
428                 float new_fader = keyframe_set->get_fader(start_position_project, i, PLAY_FORWARD);
429                 if( new_fader != faders[i] ) { recalculate = 1;  break; }
430                 float new_feather = keyframe_set->get_feather(start_position_project, i, PLAY_FORWARD);
431                 if( new_feather != feathers[i] ) { recalculate = 1;  break; }
432                 MaskPoints points;
433                 keyframe_set->get_points(&points, i,
434                                 start_position_project, PLAY_FORWARD);
435                 if( !points_equivalent(&points, point_sets[i]) )
436                         recalculate = 1;
437         }
438
439         if( recalculate ) {
440                 if( !in ) in = new VFrame(mask_w, mask_h, BC_A16, 0);
441                 if( !out ) out = new VFrame(mask_w, mask_h, BC_A16, 0);
442                 if( !mask ) mask = new VFrame(mask_w, mask_h, BC_A16, 0);
443                 for( int i = 0; i < point_sets.total; i++ ) {
444                         MaskPoints *points = point_sets[i];
445                         points->remove_all_objects();
446                 }
447                 point_sets.remove_all_objects();
448                 edges.remove_all_objects();
449                 faders.remove_all();
450                 feathers.remove_all();
451
452                 float cc = 1;
453                 int show_mask = keyframe_set->track->masks;
454                 for( int i=0; i<total_submasks; ++i ) {
455                         float fader = keyframe_set->get_fader(start_position_project, i, PLAY_FORWARD);
456                         float v = fader / 100;
457                         faders.append(v);
458                         float feather = keyframe_set->get_feather(start_position_project, i, PLAY_FORWARD);
459                         feathers.append(feather);
460                         MaskPoints *points = new MaskPoints();
461                         keyframe_set->get_points(points, i, start_position_project, PLAY_FORWARD);
462                         point_sets.append(points);
463                         MaskEdge &edge = *edges.append(new MaskEdge());
464                         if( !fader || !((show_mask>>i) & 1) || !points->size() ) continue;
465                         edge.load(*points, 0);
466                         if( v >= 0 ) continue;
467                         float vv = 1 + v;
468                         if( cc > vv ) cc = vv;
469                 }
470                 clear_mask(mask, cc*0xffff);
471 // draw mask
472                 for( int k=0; k<edges.size(); ++k ) {
473                         this->edge = edges[k];
474                         this->r = feathers[k];
475                         this->v = faders[k];
476                         if( !this->v ) continue;
477                         if( this->edge->size() < 3 ) continue;
478                         float rr = fabsf(r);
479                         if( rr > 1024 ) rr = 1024; // MAX
480                         psf = new float[psz = rr+1];
481                         draw_point_spot(r);
482 //write_mask(mask, "/tmp/mask%d.pgm", k);
483                         step = DO_MASK;
484                         process_packages();
485 //write_mask(in, "/tmp/in0%d.pgm", k);
486                         step = DO_FEATHER_X;
487                         process_packages();
488 //write_mask(out, "/tmp/out1%d.pgm", k);
489                         step = DO_FEATHER_Y;
490                         process_packages();
491                         step = DO_MASK_BLEND;
492                         process_packages();
493                         delete [] psf;  psf = 0;
494 //write_mask(in, "/tmp/in2%d.pgm", k);
495 //printf("edge %d\n",k);
496                 }
497         }
498 //write_mask(mask, "/tmp/mask.pgm");
499                 step = DO_APPLY;
500                 process_packages();
501 }
502
503 void MaskEngine::init_packages()
504 {
505 SET_TRACE
506 //printf("MaskEngine::init_packages 1\n");
507         int x1 = 0, y1 = 0, i = 0, n = get_total_packages();
508         int out_w = output->get_w(), out_h = output->get_h();
509 SET_TRACE
510         while( i < n ) {
511                 MaskPackage *pkg = (MaskPackage*)get_package(i++);
512                 int x2 = (out_w * i) / n, y2 = (out_h * i) / n;
513                 pkg->start_x = x1;  pkg->end_x = x2;
514                 pkg->start_y = y1;  pkg->end_y = y2;
515                 x1 = x2;  y1 = y2;
516         }
517 SET_TRACE
518 //printf("MaskEngine::init_packages 2\n");
519 }
520
521 LoadClient* MaskEngine::new_client()
522 {
523         return new MaskUnit(this);
524 }
525
526 LoadPackage* MaskEngine::new_package()
527 {
528         return new MaskPackage;
529 }
530