add libdav1d codec, add remap_a/v_codec option keywords
[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         if( start_y >= end_y ) return;
305         MaskEdge *edge = engine->edge;
306         float r = engine->r, v = engine->v;
307         VFrame *in = engine->in;
308         VFrame *out = engine->out;
309         VFrame *mask = engine->mask;
310         switch( engine->step ) {
311         case DO_MASK: {
312 // Draw masked region of polygons on in
313                 if( edge->size() < 3 ) break;
314                 bc = r>=0 ? 0 : 0xffff;
315                 fc = r>=0 ? 0xffff : 0;
316                 clear_mask(in, bc);
317                 if( bc == fc ) break;
318                 draw_filled_polygon(*edge);
319                 break; }
320         case DO_FEATHER_X: {
321                 feather_x(in, out);
322                 break; }
323         case DO_FEATHER_Y: {
324                 feather_y(out, in);
325                 break; }
326         case DO_MASK_BLEND: {
327                 mask_blend(in, mask, r, v);
328                 break; }
329         case DO_APPLY: {
330                 apply_mask_alpha(engine->output, mask);
331                 break; }
332         }
333 }
334
335
336 MaskEngine::MaskEngine(int cpus)
337  : LoadServer(cpus, 2*cpus)
338 // : LoadServer(1, 1)
339 {
340         mask = 0;
341         in = 0;
342         out = 0;
343 }
344
345 MaskEngine::~MaskEngine()
346 {
347         delete mask;
348         delete in;
349         delete out;
350 }
351
352 int MaskEngine::points_equivalent(MaskPoints *new_points,
353         MaskPoints *points)
354 {
355 //printf("MaskEngine::points_equivalent %d %d\n", new_points->total, points->total);
356         if( new_points->total != points->total ) return 0;
357
358         for( int i = 0; i < new_points->total; i++ ) {
359                 if( !(*new_points->get(i) == *points->get(i)) ) return 0;
360         }
361
362         return 1;
363 }
364
365 void MaskEngine::clear_mask(VFrame *msk, int a)
366 {
367         temp_t **mrows = (temp_t **)msk->get_rows();
368         int w = msk->get_w(), h = msk->get_h();
369         for( int y=0; y<h; ++y ) {
370                 temp_t *mrow = mrows[y];
371                 for( int x=0; x<w; ++x ) mrow[x] = a;
372         }
373 }
374 void MaskEngine::draw_point_spot(float r)
375 {
376         double sig2 = -log(255.0)/((double)r*r);
377         for( int i=0; i<psz; ++i )
378                 psf[i] = exp(i*i * sig2);
379 }
380
381 void MaskEngine::do_mask(VFrame *output,
382         int64_t start_position_project,
383         MaskAutos *keyframe_set,
384         MaskAuto *keyframe,
385         MaskAuto *default_auto)
386 {
387         this->output = output;
388         recalculate = 0;
389         int mask_model = 0;
390
391         switch( output->get_color_model() ) {
392         case BC_RGB_FLOAT:
393         case BC_RGBA_FLOAT:
394                 mask_model = BC_A_FLOAT;
395                 break;
396
397         case BC_RGB888:
398         case BC_RGBA8888:
399         case BC_YUV888:
400         case BC_YUVA8888:
401                 mask_model = BC_A8;
402                 break;
403
404         case BC_RGB161616:
405         case BC_RGBA16161616:
406         case BC_YUV161616:
407         case BC_YUVA16161616:
408                 mask_model = BC_A16;
409                 break;
410         }
411
412 // Determine if recalculation is needed
413         int mask_w = output->get_w(), mask_h = output->get_h();
414         if( mask && ( mask->get_color_model() != mask_model ||
415             mask->get_w() != mask_w || mask->get_h() != mask_h ) ) {
416                 delete mask;  mask = 0;
417                 recalculate = 1;
418         }
419         if( in && ( in->get_w() != mask_w || in->get_h() != mask_h ) ) {
420                 delete in;  in = 0;
421                 delete out; out = 0;
422         }
423
424         total_submasks = keyframe_set->total_submasks(start_position_project, PLAY_FORWARD);
425         if( total_submasks != point_sets.size() )
426                 recalculate = 1;
427
428         for( int i=0; i<total_submasks && !recalculate; ++i ) {
429                 float new_fader = keyframe_set->get_fader(start_position_project, i, PLAY_FORWARD);
430                 if( new_fader != faders[i] ) { recalculate = 1;  break; }
431                 float new_feather = keyframe_set->get_feather(start_position_project, i, PLAY_FORWARD);
432                 if( new_feather != feathers[i] ) { recalculate = 1;  break; }
433                 MaskPoints points;
434                 keyframe_set->get_points(&points, i,
435                                 start_position_project, PLAY_FORWARD);
436                 if( !points_equivalent(&points, point_sets[i]) )
437                         recalculate = 1;
438         }
439
440         if( recalculate ) {
441                 if( !in ) in = new VFrame(mask_w, mask_h, BC_A16, 0);
442                 if( !out ) out = new VFrame(mask_w, mask_h, BC_A16, 0);
443                 if( !mask ) mask = new VFrame(mask_w, mask_h, BC_A16, 0);
444                 for( int i = 0; i < point_sets.total; i++ ) {
445                         MaskPoints *points = point_sets[i];
446                         points->remove_all_objects();
447                 }
448                 point_sets.remove_all_objects();
449                 edges.remove_all_objects();
450                 faders.remove_all();
451                 feathers.remove_all();
452
453                 float cc = 1;
454                 int show_mask = keyframe_set->track->masks;
455                 for( int i=0; i<total_submasks; ++i ) {
456                         float fader = keyframe_set->get_fader(start_position_project, i, PLAY_FORWARD);
457                         float v = fader / 100;
458                         faders.append(v);
459                         float feather = keyframe_set->get_feather(start_position_project, i, PLAY_FORWARD);
460                         feathers.append(feather);
461                         MaskPoints *points = new MaskPoints();
462                         keyframe_set->get_points(points, i, start_position_project, PLAY_FORWARD);
463                         point_sets.append(points);
464                         MaskEdge &edge = *edges.append(new MaskEdge());
465                         if( !fader || !((show_mask>>i) & 1) || !points->size() ) continue;
466                         edge.load(*points, 0);
467                         if( v >= 0 ) continue;
468                         float vv = 1 + v;
469                         if( cc > vv ) cc = vv;
470                 }
471                 clear_mask(mask, cc*0xffff);
472 // draw mask
473                 for( int k=0; k<edges.size(); ++k ) {
474                         this->edge = edges[k];
475                         this->r = feathers[k];
476                         this->v = faders[k];
477                         if( !this->v ) continue;
478                         if( this->edge->size() < 3 ) continue;
479                         float rr = fabsf(r);
480                         if( rr > 1024 ) rr = 1024; // MAX
481                         psf = new float[psz = rr+1];
482                         draw_point_spot(r);
483 //write_mask(mask, "/tmp/mask%d.pgm", k);
484                         step = DO_MASK;
485                         process_packages();
486 //write_mask(in, "/tmp/in0%d.pgm", k);
487                         step = DO_FEATHER_X;
488                         process_packages();
489 //write_mask(out, "/tmp/out1%d.pgm", k);
490                         step = DO_FEATHER_Y;
491                         process_packages();
492                         step = DO_MASK_BLEND;
493                         process_packages();
494                         delete [] psf;  psf = 0;
495 //write_mask(in, "/tmp/in2%d.pgm", k);
496 //printf("edge %d\n",k);
497                 }
498         }
499 //write_mask(mask, "/tmp/mask.pgm");
500                 step = DO_APPLY;
501                 process_packages();
502 }
503
504 void MaskEngine::init_packages()
505 {
506 SET_TRACE
507 //printf("MaskEngine::init_packages 1\n");
508         int x1 = 0, y1 = 0, i = 0, n = get_total_packages();
509         int out_w = output->get_w(), out_h = output->get_h();
510 SET_TRACE
511         while( i < n ) {
512                 MaskPackage *pkg = (MaskPackage*)get_package(i++);
513                 int x2 = (out_w * i) / n, y2 = (out_h * i) / n;
514                 pkg->start_x = x1;  pkg->end_x = x2;
515                 pkg->start_y = y1;  pkg->end_y = y2;
516                 x1 = x2;  y1 = y2;
517         }
518 SET_TRACE
519 //printf("MaskEngine::init_packages 2\n");
520 }
521
522 LoadClient* MaskEngine::new_client()
523 {
524         return new MaskUnit(this);
525 }
526
527 LoadPackage* MaskEngine::new_package()
528 {
529         return new MaskPackage;
530 }
531