no longer need ffmpeg patch0 which was for Termux
[goodguy/cinelerra.git] / cinelerra-5.1 / guicast / bcxfer.C
1
2 void BC_Xfer::init(
3         uint8_t **output_rows, int out_colormodel, int out_x, int out_y, int out_w, int out_h,
4                 uint8_t *out_yp, uint8_t *out_up, uint8_t *out_vp, uint8_t *out_ap, int out_rowspan,
5         uint8_t **input_rows, int in_colormodel, int in_x, int in_y, int in_w, int in_h,
6                 uint8_t *in_yp, uint8_t *in_up, uint8_t *in_vp, uint8_t *in_ap, int in_rowspan,
7         int bg_color, int bg_alpha)
8 {
9         if( bg_color >= 0 ) {
10                 this->bg_a = bg_alpha; // only used with init_color
11                 this->bg_r = (bg_color>>16) & 0xff;
12                 this->bg_g = (bg_color>>8) & 0xff;
13                 this->bg_b = (bg_color>>0) & 0xff;
14         }
15         else { // bg_color < 0, no src blending
16                 switch( in_colormodel ) {
17                 case BC_RGBA8888:       in_colormodel = BC_RGBX8888;            break;
18                 case BC_RGBA16161616:   in_colormodel = BC_RGBX16161616;        break;
19                 case BC_YUVA8888:       in_colormodel = BC_YUVX8888;            break;
20                 case BC_YUVA16161616:   in_colormodel = BC_YUVX16161616;        break;
21                 case BC_RGBA_FLOAT:     in_colormodel = BC_RGBX_FLOAT;          break;
22                 }
23                 this->bg_r = this->bg_g = this->bg_b = this->bg_a = 0;
24         }
25         int pmx = BC_CModels::calculate_max(out_colormodel);
26         switch( in_colormodel ) {
27         case BC_TRANSPARENCY:
28                 if( BC_CModels::is_yuv(out_colormodel) ) {
29                         int ry = this->bg_r, gu = this->bg_g, bv = this->bg_b;
30                         YUV::yuv.rgb_to_yuv_8(ry, gu, bv);
31                         this->bg_r = ry, this->bg_g = gu, this->bg_b = bv;
32                 }
33                 if( pmx > 0xff ) {
34                         this->bg_r <<= 8;
35                         this->bg_g <<= 8;
36                         this->bg_b <<= 8;
37                         this->bg_a <<= 8;
38                 }
39                 else
40                         pmx = 0xff;
41                 break;
42         // prevent bounds errors on poorly dimensioned macro pixel formats
43         case BC_UVY422:
44         case BC_YUV422:   in_w &= ~1;               break;  // 2x1
45         case BC_YUV420P:
46         case BC_YUV420PI: in_w &= ~1;  in_h &= ~1;  break;  // 2x2
47         case BC_YUV422P:  in_w &= ~1;               break;  // 2x1
48         case BC_YUV410P:  in_w &= ~3;  in_h &= ~3;  break;  // 4x4
49         case BC_YUV411P:  in_w &= ~3;               break;  // 4x1
50         }
51         switch( out_colormodel ) {
52         case BC_UVY422:
53         case BC_YUV422:  out_w &= ~1;               break;
54         case BC_YUV420P:
55         case BC_YUV420PI: out_w &= ~1; out_h &= ~1; break;
56         case BC_YUV422P: out_w &= ~1;               break;
57         case BC_YUV410P: out_w &= ~3; out_h &= ~3;  break;
58         case BC_YUV411P: out_w &= ~3;               break;
59         }
60         this->output_rows = output_rows;
61         this->input_rows = input_rows;
62         this->out_yp = out_yp;
63         this->out_up = out_up;
64         this->out_vp = out_vp;
65         this->out_ap = out_ap;
66         this->in_yp = in_yp;
67         this->in_up = in_up;
68         this->in_vp = in_vp;
69         this->in_ap = in_ap;
70         this->in_x = in_x;
71         this->in_y = in_y;
72         this->in_w = in_w;
73         this->in_h = in_h;
74         this->out_x = out_x;
75         this->out_y = out_y;
76         this->out_w = out_w;
77         this->out_h = out_h;
78         this->in_colormodel = in_colormodel;
79         switch( in_colormodel ) {
80         case BC_GBRP:
81                 in_rowspan = in_w * sizeof(uint8_t);
82                 break;
83         case BC_RGB_FLOATP:
84         case BC_RGBA_FLOATP:
85                 if( !BC_CModels::has_alpha(out_colormodel) )
86                         this->in_colormodel = BC_RGB_FLOATP;
87                 in_rowspan = in_w * sizeof(float);
88                 break;
89         }
90         this->total_in_w = in_rowspan;
91         this->out_colormodel = out_colormodel;
92         switch( out_colormodel ) {
93         case BC_GBRP:
94                 out_rowspan = out_w * sizeof(uint8_t);
95                 break;
96         case BC_RGB_FLOATP:
97         case BC_RGBA_FLOATP:
98                 out_rowspan = out_w * sizeof(float);
99                 break;
100         }
101         this->total_out_w = out_rowspan;
102         this->in_pixelsize = BC_CModels::calculate_pixelsize(in_colormodel);
103         this->out_pixelsize = BC_CModels::calculate_pixelsize(out_colormodel);
104         if( in_w ) {
105                 this->scale = (out_w != in_w) || (in_x != 0);
106 /* + 1 so we don't overflow when calculating in advance */
107                 column_table = new int[out_w+1];
108                 double hscale = (double)in_w/out_w;
109                 for( int i=0; i<out_w; ++i ) {
110                         column_table[i] = ((int)(hscale * i) + in_x) * in_pixelsize;
111                         if( in_colormodel == BC_YUV422 || in_colormodel == BC_UVY422 )
112                                 column_table[i] &= ~3;
113                 }
114                 double vscale = (double)in_h/out_h;
115                 row_table = new int[out_h];
116                 for( int i=0; i<out_h; ++i )
117                         row_table[i] = (int)(vscale * i) + in_y;
118         }
119         else {
120                 this->scale = 0;
121                 column_table = 0;
122                 row_table = 0;
123         }
124         this->bg_fa = (float)this->bg_a / pmx;
125         this->bg_fr = (float)this->bg_r / pmx;
126         this->bg_fg = (float)this->bg_g / pmx;
127         this->bg_fb = (float)this->bg_b / pmx;
128 }
129
130 BC_Xfer::BC_Xfer(uint8_t **output_rows, uint8_t **input_rows,
131         uint8_t *out_yp, uint8_t *out_up, uint8_t *out_vp,
132         uint8_t *in_yp, uint8_t *in_up, uint8_t *in_vp,
133         int in_x, int in_y, int in_w, int in_h, int out_x, int out_y, int out_w, int out_h,
134         int in_colormodel, int out_colormodel, int bg_color, int bg_alpha,
135         int in_rowspan, int out_rowspan)
136 {
137         init(output_rows, out_colormodel, out_x, out_y, out_w, out_h,
138                 out_yp, out_up, out_vp, 0, out_rowspan,
139              input_rows, in_colormodel, in_x, in_y, in_w, in_h,
140                 in_yp, in_up, in_vp, 0, in_rowspan, bg_color, bg_alpha);
141 }
142
143 BC_Xfer::BC_Xfer(
144         uint8_t **output_ptrs, int out_colormodel,
145                 int out_x, int out_y, int out_w, int out_h, int out_rowspan,
146         uint8_t **input_ptrs, int in_colormodel,
147                 int in_x, int in_y, int in_w, int in_h, int in_rowspan,
148         int bg_color, int bg_alpha)
149 {
150         uint8_t *out_yp = 0, *out_up = 0, *out_vp = 0, *out_ap = 0;
151         uint8_t *in_yp = 0,  *in_up = 0,  *in_vp = 0,  *in_ap = 0;
152         if( BC_CModels::is_planar(in_colormodel) ) {
153                 in_yp = input_ptrs[0]; in_up = input_ptrs[1]; in_vp = input_ptrs[2];
154                 if( BC_CModels::has_alpha(in_colormodel) ) in_ap = input_ptrs[3];
155         }
156         if( BC_CModels::is_planar(out_colormodel) ) {
157                 out_yp = output_ptrs[0]; out_up = output_ptrs[1]; out_vp = output_ptrs[2];
158                 if( BC_CModels::has_alpha(out_colormodel) ) out_ap = output_ptrs[3];
159         }
160         init(output_ptrs, out_colormodel, out_x, out_y, out_w, out_h,
161                  out_yp, out_up, out_vp, out_ap, out_rowspan,
162              input_ptrs, in_colormodel, in_x, in_y, in_w, in_h,
163                  in_yp, in_up, in_vp, in_ap, in_rowspan,  bg_color, bg_alpha);
164 }
165
166 BC_Xfer::~BC_Xfer()
167 {
168         delete [] column_table;
169         delete [] row_table;
170 }
171
172 void BC_CModels::transfer(unsigned char **output_rows, unsigned char **input_rows,
173         unsigned char *out_yp, unsigned char *out_up, unsigned char *out_vp,
174         unsigned char *in_yp, unsigned char *in_up, unsigned char *in_vp,
175         int in_x, int in_y, int in_w, int in_h, int out_x, int out_y, int out_w, int out_h,
176         int in_colormodel, int out_colormodel, int bg_color,
177         int in_rowspan, int out_rowspan)
178 {
179         int ret = 1;
180         if( in_w > 0 && in_h > 0 && out_w > 0 && out_h > 0 ) {
181                 BC_Xfer xfer(output_rows, input_rows,
182                         out_yp, out_up, out_vp, in_yp, in_up, in_vp,
183                         in_x, in_y, in_w, in_h, out_x, out_y, out_w, out_h,
184                         in_colormodel, out_colormodel, bg_color,0xff, in_rowspan, out_rowspan);
185                 ret = xfer.xfer();
186         }
187         if( ret )
188                 printf("BC_CModels::transfer failed:%d %d(%dx%d) to %d(%dx%d)\n", __LINE__,
189                         in_colormodel, in_w, in_h, out_colormodel, out_w, out_h);
190 }
191
192 void BC_CModels::transfer(
193         uint8_t **output_ptrs, int out_colormodel,
194                 int out_x, int out_y, int out_w, int out_h, int out_rowspan,
195         uint8_t **input_ptrs, int in_colormodel,
196                 int in_x, int in_y, int in_w, int in_h, int in_rowspan,
197         int bg_color)
198 {
199         int ret = 1;
200         if( in_w > 0 && in_h > 0 && out_w > 0 && out_h > 0 ) {
201                 BC_Xfer xfer(
202                         output_ptrs, out_colormodel, out_x, out_y, out_w, out_h, out_rowspan,
203                         input_ptrs, in_colormodel, in_x, in_y, in_w, in_h, in_rowspan,
204                         bg_color,0xff);
205                 ret = xfer.xfer();
206         }
207         if( ret )
208                 printf("BC_CModels::transfer failed:%d %d(%dx%d) to %d(%dx%d)\n", __LINE__,
209                         in_colormodel, in_w, in_h, out_colormodel, out_w, out_h);
210 }
211
212 // color is rgb
213 int BC_CModels::init_color(int color, int alpha,
214                 unsigned char **output_rows, int out_colormodel,
215                 unsigned char *out_yp, unsigned char *out_up, unsigned char *out_vp,
216                 int out_x, int out_y, int out_w, int out_h, int out_rowspan)
217 {
218         int ret = 1;
219         if( out_w > 0 && out_h > 0 ) {
220                 BC_Xfer xfer(output_rows, 0, out_yp,out_up,out_vp, 0,0,0,
221                         0,0,0,0, out_x,out_y,out_w,out_h, BC_TRANSPARENCY,
222                         out_colormodel, color,alpha, 0, out_rowspan);
223                 ret = xfer.xfer();
224         }
225         if( ret )
226                 printf("BC_CModels::init_color failed:%d(%dx%d)\n",
227                         out_colormodel, out_w, out_h);
228         return ret;
229 }
230
231 // specialized functions
232
233 //  in bccmdl.py:  specialize("bc_rgba8888", "bc_transparency", "XFER_rgba8888_to_transparency")
234 void BC_Xfer::XFER_rgba8888_to_transparency(unsigned y0, unsigned y1)
235 {
236   for( unsigned i=y0; i<y1; ++i ) {
237     uint8_t *outp = output_rows[i + out_y] + out_x * out_pixelsize;
238     uint8_t *inp_row = input_rows[row_table[i]];
239     int bit_no = 0, bit_vec = 0;
240     for( unsigned j=0; j<out_w; ) {
241       uint8_t *inp = inp_row + column_table[j];
242       if( inp[3] < 127 ) bit_vec |= 0x01 << bit_no;
243       bit_no = ++j & 7;
244       if( !bit_no ) { *outp++ = bit_vec;  bit_vec = 0; }
245     }
246     if( bit_no ) *outp = bit_vec;
247   }
248 }
249
250 BC_Xfer::SlicerList BC_Xfer::slicers;
251
252 BC_Xfer::SlicerList::SlicerList()
253 {
254   count = 0;
255 }
256
257 BC_Xfer::SlicerList::~SlicerList()
258 {
259   reset();
260 }
261
262 void BC_Xfer::SlicerList::reset()
263 {
264   lock("BC_Xfer::SlicerList::reset");
265   while( last ) remove(last);
266   count = 0;
267   unlock();
268 }
269
270 BC_Xfer::Slicer *BC_Xfer::SlicerList::get_slicer(BC_Xfer *xp)
271 {
272   Slicer *slicer = first;
273   if( !slicer ) {
274     if( count < BC_Resources::machine_cpus ) {
275       slicer = new Slicer(xp);
276       ++count;
277     }
278   }
279   else
280     remove_pointer(slicer);
281   return slicer;
282 }
283
284 int BC_Xfer::xfer_slices(int slices)
285 {
286   if( !xfn ) return 1;
287   int max_slices = BC_Resources::machine_cpus/2;
288   if( slices > max_slices ) slices = max_slices;
289   if( slices < 1 ) slices = 1;
290   Slicer *active[slices];
291   unsigned y0 = 0, y1 = out_h;
292   int slices1 = slices-1;
293   if( slices1 > 0 ) {
294     slicers.lock("BC_Xfer::xfer_slices");
295     for( int i=0; i<slices1; y0=y1 ) {
296       Slicer *slicer = slicers.get_slicer(this);
297       if( !slicer ) { slices1 = i;  break; }
298       active[i] = slicer;
299       y1 = out_h * ++i / slices;
300       slicer->slice(this, y0, y1);
301     }
302     slicers.unlock();
303   }
304   (this->*xfn)(y0, out_h);
305   if( slices1 > 0 ) {
306     for( int i=0; i<slices1; ++i )
307       active[i]->complete->lock("BC_Xfer::xfer_slices");
308     slicers.lock("BC_Xfer::xfer_slices");
309     for( int i=0; i<slices1; ++i )
310       slicers.append(active[i]);
311     slicers.unlock();
312   }
313   return 0;
314 }
315
316 BC_Xfer::Slicer::Slicer(BC_Xfer *xp)
317 {
318   this->xp = xp;
319   init = new Condition(0, "BC_Xfer::Slicer::init", 0);
320   complete = new Condition(0, "BC_Xfer::Slicer::complete", 0);
321   done = 0;
322   start();
323 }
324 BC_Xfer::Slicer::~Slicer()
325 {
326   done = 1;
327   init->unlock();
328   join();
329   delete complete;
330   delete init;
331 }
332
333 void BC_Xfer::Slicer::slice(BC_Xfer *xp, unsigned y0, unsigned y1)
334 {
335   this->xp = xp;
336   this->y0 = y0;
337   this->y1 = y1;
338   init->unlock();
339 }
340
341 void BC_Xfer::Slicer::run()
342 {
343   while( !done ) {
344     init->lock("Slicer::run");
345     if( done ) break;
346     xfer_fn xfn = xp->xfn;
347     (xp->*xfn)(y0, y1);
348     complete->unlock();
349   }
350 }
351
352 void BC_CModels::bcxfer_stop_slicers()
353 {
354   BC_Xfer::slicers.reset();
355 }
356