remove whitespace at eol
[goodguy/history.git] / cinelerra-5.1 / guicast / xfer.C
1
2 // Compression coefficients straight out of jpeglib
3 #define R_TO_Y    0.29900
4 #define G_TO_Y    0.58700
5 #define B_TO_Y    0.11400
6
7 #define R_TO_U    -0.16874
8 #define G_TO_U    -0.33126
9 #define B_TO_U    0.50000
10
11 #define R_TO_V    0.50000
12 #define G_TO_V    -0.41869
13 #define B_TO_V    -0.08131
14
15 // Decompression coefficients straight out of jpeglib
16 #define V_TO_R    1.40200
17 #define V_TO_G    -0.71414
18
19 #define U_TO_G    -0.34414
20 #define U_TO_B    1.77200
21
22 int BC_Xfer::rtoy_tab[0x100], BC_Xfer::gtoy_tab[0x100], BC_Xfer::btoy_tab[0x100];
23 int BC_Xfer::rtou_tab[0x100], BC_Xfer::gtou_tab[0x100], BC_Xfer::btou_tab[0x100];
24 int BC_Xfer::rtov_tab[0x100], BC_Xfer::gtov_tab[0x100], BC_Xfer::btov_tab[0x100];
25 int BC_Xfer::vtor_tab[0x100], BC_Xfer::vtog_tab[0x100];
26 int BC_Xfer::utog_tab[0x100], BC_Xfer::utob_tab[0x100];
27 float BC_Xfer::vtor_float_tab[0x100], BC_Xfer::vtog_float_tab[0x100];
28 float BC_Xfer::utog_float_tab[0x100], BC_Xfer::utob_float_tab[0x100];
29 int BC_Xfer::rtoy_tab16[0x10000], BC_Xfer::gtoy_tab16[0x10000], BC_Xfer::btoy_tab16[0x10000];
30 int BC_Xfer::rtou_tab16[0x10000], BC_Xfer::gtou_tab16[0x10000], BC_Xfer::btou_tab16[0x10000];
31 int BC_Xfer::rtov_tab16[0x10000], BC_Xfer::gtov_tab16[0x10000], BC_Xfer::btov_tab16[0x10000];
32 int BC_Xfer::vtor_tab16[0x10000], BC_Xfer::vtog_tab16[0x10000];
33 int BC_Xfer::utog_tab16[0x10000], BC_Xfer::utob_tab16[0x10000];
34 float BC_Xfer::v16tor_float_tab[0x10000], BC_Xfer::v16tog_float_tab[0x10000];
35 float BC_Xfer::u16tog_float_tab[0x10000], BC_Xfer::u16tob_float_tab[0x10000];
36
37 BC_Xfer::Tables BC_Xfer::tables;
38
39 void BC_Xfer::init()
40 {
41         for( int i=0; i<0x100; ++i ) {
42                 rtoy_tab[i] = (int)(R_TO_Y * 0x10000 * i);
43                 rtou_tab[i] = (int)(R_TO_U * 0x10000 * i);
44                 rtov_tab[i] = (int)(R_TO_V * 0x10000 * i);
45
46                 gtoy_tab[i] = (int)(G_TO_Y * 0x10000 * i);
47                 gtou_tab[i] = (int)(G_TO_U * 0x10000 * i);
48                 gtov_tab[i] = (int)(G_TO_V * 0x10000 * i);
49
50                 btoy_tab[i] = (int)(B_TO_Y * 0x10000 * i);
51                 btou_tab[i] = (int)(B_TO_U * 0x10000 * i) + 0x800000;
52                 btov_tab[i] = (int)(B_TO_V * 0x10000 * i) + 0x800000;
53         }
54
55         for( int i=0; i<0x10000; ++i ) {
56                 rtoy_tab16[i] = (int)(R_TO_Y * 0x100 * i);
57                 rtou_tab16[i] = (int)(R_TO_U * 0x100 * i);
58                 rtov_tab16[i] = (int)(R_TO_V * 0x100 * i);
59
60                 gtoy_tab16[i] = (int)(G_TO_Y * 0x100 * i);
61                 gtou_tab16[i] = (int)(G_TO_U * 0x100 * i);
62                 gtov_tab16[i] = (int)(G_TO_V * 0x100 * i);
63
64                 btoy_tab16[i] = (int)(B_TO_Y * 0x100 * i);
65                 btou_tab16[i] = (int)(B_TO_U * 0x100 * i) + 0x800000;
66                 btov_tab16[i] = (int)(B_TO_V * 0x100 * i) + 0x800000;
67         }
68
69         for( int i=-0x80; i<0x80; ++i ) {
70                 vtor_tab[i+0x80] = (int)(V_TO_R * 0x10000 * i);
71                 vtog_tab[i+0x80] = (int)(V_TO_G * 0x10000 * i);
72                 utog_tab[i+0x80] = (int)(U_TO_G * 0x10000 * i);
73                 utob_tab[i+0x80] = (int)(U_TO_B * 0x10000 * i);
74         }
75
76         for( int i=-0x80; i<0x80; ++i ) {
77                 vtor_float_tab[i+0x80] = V_TO_R * i / 0xff;
78                 vtog_float_tab[i+0x80] = V_TO_G * i / 0xff;
79                 utog_float_tab[i+0x80] = U_TO_G * i / 0xff;
80                 utob_float_tab[i+0x80] = U_TO_B * i / 0xff;
81         }
82
83         for( int i=-0x8000; i<0x8000; ++i ) {
84                 vtor_tab16[i+0x8000] = (int)(V_TO_R * 0x100 * i);
85                 vtog_tab16[i+0x8000] = (int)(V_TO_G * 0x100 * i);
86                 utog_tab16[i+0x8000] = (int)(U_TO_G * 0x100 * i);
87                 utob_tab16[i+0x8000] = (int)(U_TO_B * 0x100 * i);
88         }
89
90         for( int i=-0x8000; i<0x8000; ++i ) {
91                 v16tor_float_tab[i+0x8000] = V_TO_R * i / 0xffff;
92                 v16tog_float_tab[i+0x8000] = V_TO_G * i / 0xffff;
93                 u16tog_float_tab[i+0x8000] = U_TO_G * i / 0xffff;
94                 u16tob_float_tab[i+0x8000] = U_TO_B * i / 0xffff;
95         }
96 }
97
98 void BC_Xfer::init(
99         uint8_t **output_rows, int out_colormodel, int out_x, int out_y, int out_w, int out_h,
100                 uint8_t *out_yp, uint8_t *out_up, uint8_t *out_vp, uint8_t *out_ap, int out_rowspan,
101         uint8_t **input_rows, int in_colormodel, int in_x, int in_y, int in_w, int in_h,
102                 uint8_t *in_yp, uint8_t *in_up, uint8_t *in_vp, uint8_t *in_ap, int in_rowspan,
103         int bg_color)
104 {
105         // prevent bounds errors on poorly dimensioned macro pixel formats
106         switch( in_colormodel ) {
107         case BC_UVY422:
108         case BC_YUV422:   in_w &= ~1;               break;  // 2x1
109         case BC_YUV420P:
110         case BC_YUV420PI: in_w &= ~1;  in_h &= ~1;  break;  // 2x2
111         case BC_YUV422P:  in_w &= ~1;               break;  // 2x1
112         case BC_YUV410P:  in_w &= ~3;  in_h &= ~3;  break;  // 4x4
113         case BC_YUV411P:  in_w &= ~3;               break;  // 4x1
114         }
115         switch( out_colormodel ) {
116         case BC_UVY422:
117         case BC_YUV422:  out_w &= ~1;               break;
118         case BC_YUV420P:
119         case BC_YUV420PI: out_w &= ~1; out_h &= ~1; break;
120         case BC_YUV422P: out_w &= ~1;               break;
121         case BC_YUV410P: out_w &= ~3; out_h &= ~3;  break;
122         case BC_YUV411P: out_w &= ~3;               break;
123         }
124         this->output_rows = output_rows;
125         this->input_rows = input_rows;
126         this->out_yp = out_yp;
127         this->out_up = out_up;
128         this->out_vp = out_vp;
129         this->out_ap = out_ap;
130         this->in_yp = in_yp;
131         this->in_up = in_up;
132         this->in_vp = in_vp;
133         this->in_ap = in_ap;
134         this->in_x = in_x;
135         this->in_y = in_y;
136         this->in_w = in_w;
137         this->in_h = in_h;
138         this->out_x = out_x;
139         this->out_y = out_y;
140         this->out_w = out_w;
141         this->out_h = out_h;
142         this->in_colormodel = in_colormodel;
143         switch( in_colormodel ) {
144         case BC_RGB_FLOATP:
145         case BC_RGBA_FLOATP:
146                 in_rowspan = in_w * sizeof(float);
147                 break;
148         }
149         this->total_in_w = in_rowspan;
150         this->out_colormodel = out_colormodel;
151         switch( out_colormodel ) {
152         case BC_RGB_FLOATP:
153         case BC_RGBA_FLOATP:
154                 out_rowspan = out_w * sizeof(float);
155                 break;
156         }
157         this->total_out_w = out_rowspan;
158         this->bg_color = bg_color;
159         this->bg_r = (bg_color>>16) & 0xff;
160         this->bg_g = (bg_color>>8) & 0xff;
161         this->bg_b = (bg_color>>0) & 0xff;
162
163         this->in_pixelsize = BC_CModels::calculate_pixelsize(in_colormodel);
164         this->out_pixelsize = BC_CModels::calculate_pixelsize(out_colormodel);
165         this->scale = (out_w != in_w) || (in_x != 0);
166
167 /* + 1 so we don't overflow when calculating in advance */
168         column_table = new int[out_w+1];
169         double hscale = (double)in_w/out_w;
170         for( int i=0; i<out_w; ++i ) {
171                         column_table[i] = ((int)(hscale * i) + in_x) * in_pixelsize;
172                         if( in_colormodel == BC_YUV422 || in_colormodel == BC_UVY422 )
173                                 column_table[i] &= ~3;
174         }
175         double vscale = (double)in_h/out_h;
176         row_table = new int[out_h];
177         for( int i=0; i<out_h; ++i )
178                 row_table[i] = (int)(vscale * i) + in_y;
179 }
180
181 BC_Xfer::BC_Xfer(uint8_t **output_rows, uint8_t **input_rows,
182         uint8_t *out_yp, uint8_t *out_up, uint8_t *out_vp,
183         uint8_t *in_yp, uint8_t *in_up, uint8_t *in_vp,
184         int in_x, int in_y, int in_w, int in_h, int out_x, int out_y, int out_w, int out_h,
185         int in_colormodel, int out_colormodel, int bg_color, int in_rowspan, int out_rowspan)
186 {
187         init(output_rows, out_colormodel, out_x, out_y, out_w, out_h,
188                 out_yp, out_up, out_vp, 0, out_rowspan,
189              input_rows, in_colormodel, in_x, in_y, in_w, in_h,
190                 in_yp, in_up, in_vp, 0, in_rowspan,  bg_color);
191 }
192
193 BC_Xfer::BC_Xfer(
194         uint8_t **output_ptrs, int out_colormodel,
195                 int out_x, int out_y, int out_w, int out_h, int out_rowspan,
196         uint8_t **input_ptrs, int in_colormodel,
197                 int in_x, int in_y, int in_w, int in_h, int in_rowspan,
198         int bg_color)
199 {
200         uint8_t *out_yp = 0, *out_up = 0, *out_vp = 0, *out_ap = 0;
201         uint8_t *in_yp = 0,  *in_up = 0,  *in_vp = 0,  *in_ap = 0;
202         if( BC_CModels::is_planar(in_colormodel) ) {
203                 in_yp = input_ptrs[0]; in_up = input_ptrs[1]; in_vp = input_ptrs[2];
204                 if( BC_CModels::has_alpha(in_colormodel) ) in_ap = input_ptrs[3];
205         }
206         if( BC_CModels::is_planar(out_colormodel) ) {
207                 out_yp = output_ptrs[0]; out_up = output_ptrs[1]; out_vp = output_ptrs[2];
208                 if( BC_CModels::has_alpha(out_colormodel) ) out_ap = output_ptrs[3];
209         }
210         init(output_ptrs, out_colormodel, out_x, out_y, out_w, out_h,
211                  out_yp, out_up, out_vp, out_ap, out_rowspan,
212              input_ptrs, in_colormodel, in_x, in_y, in_w, in_h,
213                  in_yp, in_up, in_vp, in_ap, in_rowspan,  bg_color);
214 }
215
216 BC_Xfer::~BC_Xfer()
217 {
218         delete [] column_table;
219         delete [] row_table;
220 }
221
222 void BC_CModels::transfer(unsigned char **output_rows, unsigned char **input_rows,
223         unsigned char *out_yp, unsigned char *out_up, unsigned char *out_vp,
224         unsigned char *in_yp, unsigned char *in_up, unsigned char *in_vp,
225         int in_x, int in_y, int in_w, int in_h, int out_x, int out_y, int out_w, int out_h,
226         int in_colormodel, int out_colormodel, int bg_color, int in_rowspan, int out_rowspan)
227 {
228         BC_Xfer xfer(output_rows, input_rows,
229                 out_yp, out_up, out_vp, in_yp, in_up, in_vp,
230                 in_x, in_y, in_w, in_h, out_x, out_y, out_w, out_h,
231                 in_colormodel, out_colormodel, bg_color, in_rowspan, out_rowspan);
232         xfer.xfer();
233 }
234
235 void BC_CModels::transfer(
236         uint8_t **output_ptrs, int out_colormodel,
237                 int out_x, int out_y, int out_w, int out_h, int out_rowspan,
238         uint8_t **input_ptrs, int in_colormodel,
239                 int in_x, int in_y, int in_w, int in_h, int in_rowspan,  int bg_color)
240 {
241         BC_Xfer xfer(
242                 output_ptrs, out_colormodel, out_x, out_y, out_w, out_h, out_rowspan,
243                 input_ptrs, in_colormodel, in_x, in_y, in_w, in_h, in_rowspan,  bg_color);
244         xfer.xfer();
245 }
246
247 // specialized functions
248
249 //  in bccmdl.py:  specialize("bc_rgba8888", "bc_transparency", "XFER_rgba8888_to_transparency")
250 void BC_Xfer::XFER_rgba8888_to_transparency(unsigned y0, unsigned y1)
251 {
252   for( unsigned i=y0; i<y1; ++i ) {
253     uint8_t *outp = output_rows[i + out_y] + out_x * out_pixelsize;
254     uint8_t *inp_row = input_rows[row_table[i]];
255     int bit_no = 0, bit_vec = 0;
256     for( unsigned j=0; j<out_w; ) {
257       uint8_t *inp = inp_row + column_table[j];
258       if( inp[3] < 127 ) bit_vec |= 0x01 << bit_no;
259       bit_no = ++j & 7;
260       if( !bit_no ) { *outp++ = bit_vec;  bit_vec = 0; }
261     }
262     if( bit_no ) *outp = bit_vec;
263   }
264 }
265
266 BC_Xfer::SlicerList BC_Xfer::slicers;
267
268 BC_Xfer::SlicerList::SlicerList()
269 {
270   count = 0;
271 }
272
273 BC_Xfer::SlicerList::~SlicerList()
274 {
275   reset();
276 }
277
278 void BC_Xfer::SlicerList::reset()
279 {
280   lock("BC_Xfer::SlicerList::reset");
281   while( last ) remove(last);
282   count = 0;
283   unlock();
284 }
285
286 BC_Xfer::Slicer *BC_Xfer::SlicerList::get_slicer(BC_Xfer *xp)
287 {
288   Slicer *slicer = first;
289   if( !slicer ) {
290     if( count < BC_Resources::machine_cpus ) {
291       slicer = new Slicer(xp);
292       ++count;
293     }
294   }
295   else
296     remove_pointer(slicer);
297   return slicer;
298 }
299
300 void BC_Xfer::xfer_slices(int slices)
301 {
302   if( !xfn ) return;
303   int max_slices = BC_Resources::machine_cpus/2;
304   if( slices > max_slices ) slices = max_slices;
305   if( slices < 1 ) slices = 1;
306   Slicer *active[slices];
307   unsigned y0 = 0, y1 = out_h;
308   int slices1 = slices-1;
309   if( slices1 > 0 ) {
310     slicers.lock("BC_Xfer::xfer_slices");
311     for( int i=0; i<slices1; y0=y1 ) {
312       Slicer *slicer = slicers.get_slicer(this);
313       if( !slicer ) { slices1 = i;  break; }
314       active[i] = slicer;
315       y1 = out_h * ++i / slices;
316       slicer->slice(this, y0, y1);
317     }
318     slicers.unlock();
319   }
320   (this->*xfn)(y0, out_h);
321   if( slices1 > 0 ) {
322     for( int i=0; i<slices1; ++i )
323       active[i]->complete->lock("BC_Xfer::xfer_slices");
324     slicers.lock("BC_Xfer::xfer_slices");
325     for( int i=0; i<slices1; ++i )
326       slicers.append(active[i]);
327     slicers.unlock();
328   }
329 }
330
331 BC_Xfer::Slicer::Slicer(BC_Xfer *xp)
332 {
333   this->xp = xp;
334   init = new Condition(0, "BC_Xfer::Slicer::init", 0);
335   complete = new Condition(0, "BC_Xfer::Slicer::complete", 0);
336   done = 0;
337   start();
338 }
339 BC_Xfer::Slicer::~Slicer()
340 {
341   done = 1;
342   init->unlock();
343   join();
344 }
345
346 void BC_Xfer::Slicer::slice(BC_Xfer *xp, unsigned y0, unsigned y1)
347 {
348   this->xp = xp;
349   this->y0 = y0;
350   this->y1 = y1;
351   init->unlock();
352 }
353
354 void BC_Xfer::Slicer::run()
355 {
356   while( !done ) {
357     init->lock("Slicer::run");
358     if( done ) break;
359     xfer_fn xfn = xp->xfn;
360     (xp->*xfn)(y0, y1);
361     complete->unlock();
362   }
363 }
364
365 void BC_CModels::bcxfer_stop_slicers()
366 {
367   BC_Xfer::slicers.reset();
368 }
369