LiVES  3.2.0
colourspace.c
Go to the documentation of this file.
1 // colourspace.c
2 // LiVES
3 // (c) G. Finch 2004 - 2020 <salsaman+lives@gmail.com>
4 // Released under the GPL 3 or later
5 // see file ../COPYING for licensing details
6 
7 // code for palette conversions
8 
9 /*
10  This program is free software; you can redistribute it and/or
11  modify it under the terms of the GNU General Public License
12  as published by the Free Software Foundation; either version 2
13  of the License, or (at your option) any later version.
14 
15  This program is distributed in the hope that it will be useful,
16  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  GNU General Public License for more details.
19 
20  You should have received a copy of the GNU General Public License
21  along with this program; if not, write to the Free Software
22  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 */
24 
25 // *
26 // TODO -
27 // - resizing of single plane (including bicubic) (maybe just triplicate the values and pretend it's RGB)
28 // - external plugins for palette conversion, resizing
29 // - RGB(A) float, YUV10, etc.
30 
31 #include <math.h>
32 
33 #include "main.h"
34 
35 boolean weed_palette_is_sane(int pal);
36 
37 #define USE_THREADS 1
38 
39 #ifdef USE_SWSCALE
40 
41 #ifdef FF_API_PIX_FMT
42 typedef enum PixelFormat swpixfmt;
43 #else
44 typedef enum AVPixelFormat swpixfmt;
45 #endif
46 
47 #if USE_THREADS
48 #include <pthread.h>
49 typedef struct {
50  volatile boolean in_use;
51  int num;
52  int offset;
53  int iwidth, iheight;
54  int irow[4];
55  swpixfmt ipixfmt;
56  int width, height;
57  int orow[4];
58  swpixfmt opixfmt;
59  int flags;
60  int subspace;
61  int iclamping, oclamp_hint;
62 } swsctx_block;
63 
64 #define MAX_SWS_BLOCKS 8192
65 #define MAX_SWS_CTX 65536
66 
67 static volatile int nb = 0;
68 static volatile int swctx_count = 0;
69 static swsctx_block bloxx[MAX_SWS_BLOCKS];
70 static struct SwsContext *swscalep[MAX_SWS_CTX];
71 static pthread_mutex_t ctxcnt_mutex = PTHREAD_MUTEX_INITIALIZER;
72 
73 static swsctx_block *sws_getblock(int nreq, int iwidth, int iheight, int *irow, swpixfmt ipixfmt, int width, int height,
74  int *orow, swpixfmt opixfmt, int flags, int subspace, int iclamping, int oclamp_hint) {
75  swsctx_block *block, *bestblock;
76  int max = MAX_THREADS + 1, minbnum = max, mingnum = minbnum, minanum = mingnum, num;
77  int i = -1, lastblock = THREADVAR(last_sws_block), j = 0, bestidx = -1;
78 
79  if (lastblock >= 0) j = lastblock;
80  else i = 0;
81 
82  pthread_mutex_lock(&ctxcnt_mutex);
83 
84  for (; i < nb; j = ++i) {
85  block = &bloxx[j];
86  if (!block->in_use && (num = block->num) >= nreq) {
87  if (iwidth == block->iwidth
88  && iheight == block->iheight
89  && ipixfmt == block->ipixfmt
90  && width == block->width
91  && height == block->height
92  && opixfmt == block->opixfmt
93  && flags == block->flags) {
94  if (subspace == block->subspace
95  && iclamping == block->iclamping
96  && oclamp_hint == block->oclamp_hint
97  && irow[0] == block->irow[0]
98  && irow[1] == block->irow[1]
99  && irow[2] == block->irow[2]
100  && irow[3] == block->irow[3]
101  && orow[0] == block->orow[0]
102  && orow[1] == block->orow[1]
103  && orow[2] == block->orow[2]
104  && orow[3] == block->orow[3]
105  ) {
106  if (num < minbnum) {
107  minbnum = num;
108  bestidx = j;
109  //g_print("%d is perfect match !\n", i);
110  if (num == nreq) {
111  //if (i == -1) g_print("BINGO !\n");
112  break;
113  }
114  }
115  } else {
116  if (minbnum == max) {
117  if (num < mingnum) {
118  bestidx = j;
119  mingnum = num;
120  // *INDENT-OFF*
121  }}}}
122  else {
123  if (minbnum == max && mingnum == max) {
124  if (num < minanum) {
125  bestidx = j;
126  minanum = num;
127  }}}}}
128  // *INDENT-ON*
129 
130  if (minbnum < max) {
131  bestblock = &bloxx[bestidx];
132  bestblock->in_use = TRUE;
133  pthread_mutex_unlock(&ctxcnt_mutex);
134  THREADVAR(last_sws_block) = bestidx;
135  } else {
136  int startctx = swctx_count, endctx = startctx + nreq;
137  if (endctx >= MAX_SWS_CTX
138  || nb >= MAX_SWS_BLOCKS - 1) {
139  if (bestidx == -1) abort();
140  bestblock = &bloxx[bestidx];
141  bestblock->in_use = TRUE;
142  pthread_mutex_unlock(&ctxcnt_mutex);
143  THREADVAR(last_sws_block) = bestidx;
144  } else {
145  bestblock = &bloxx[nb++];
146  bestblock->in_use = TRUE;
147  swctx_count = endctx;
148  pthread_mutex_unlock(&ctxcnt_mutex);
149 
150  bestblock->num = nreq;
151  bestblock->offset = startctx;
152  for (i = startctx; i < endctx; i++) swscalep[i] = NULL;
153  }
154 
155  bestblock->iwidth = iwidth;
156  bestblock->iheight = iheight;
157  bestblock->ipixfmt = ipixfmt;
158  bestblock->width = width;
159  bestblock->height = height;
160  bestblock->opixfmt = opixfmt;
161  bestblock->flags = flags;
162 
163  bestblock->subspace = subspace;
164  bestblock->iclamping = iclamping;
165  bestblock->oclamp_hint = oclamp_hint;
166  for (i = 0; i < 4; i++) {
167  bestblock->irow[i] = irow[i];
168  bestblock->orow[i] = orow[i];
169  }
170  }
171 
172  //g_print("NCTX = %d\n", swctx_count);
173  return bestblock;
174 }
175 
176 LIVES_LOCAL_INLINE void sws_freeblock(swsctx_block * block) {
177  block->in_use = FALSE;
178 }
179 
180 #else
181 static struct SwsContext *swscale = NULL;
182 #endif
183 
184 #endif // USE_SWSCALE
185 
186 #include "cvirtual.h"
187 #include "effects-weed.h"
188 
189 static boolean unal_inited = FALSE;
190 
191 #ifdef GUI_GTK
192 // from gdk-pixbuf.c
193 /* Always align rows to 32-bit boundaries */
194 # define get_pixbuf_rowstride_value(rowstride) ((rowstride + 3) & ~3)
195 #else
196 # define get_pixbuf_rowstride_value(rowstride) (rowstride)
197 #endif
198 
199 #ifdef GUI_GTK
200 // from gdkpixbuf
201 #define get_last_pixbuf_rowstride_value(width, nchans) (width * (((nchans << 3) + 7) >> 3))
202 #else
203 #define get_last_pixbuf_rowstride_value(width, nchans) (width * nchans)
204 #endif
205 
206 
207 static void lives_free_buffer(uint8_t *pixels, livespointer data) {
208  lives_free(pixels);
209 }
210 
211 #define CLAMP0255(a) ((unsigned char)((((-a) >> 31) & a) | (255 - a) >> 31) )
212 #define CLAMP0255f(a) (a > 255. ? 255.: a < 0. ? 0. : a)
213 #define CLAMP0255fi(a) ((int)(a > 255. ? 255.: a < 0. ? 0. : a))
214 
215 /* precomputed tables */
216 
217 // generic
218 static int *Y_R;
219 static int *Y_G;
220 static int *Y_B;
221 static int *Cb_R;
222 static int *Cb_G;
223 static int *Cb_B;
224 static int *Cr_R;
225 static int *Cr_G;
226 static int *Cr_B;
227 
228 // clamped Y'CbCr
229 static int Y_Rc[256];
230 static int Y_Gc[256];
231 static int Y_Bc[256];
232 static int Cb_Rc[256];
233 static int Cb_Gc[256];
234 static int Cb_Bc[256];
235 static int Cr_Rc[256];
236 static int Cr_Gc[256];
237 static int Cr_Bc[256];
238 
239 // unclamped Y'CbCr
240 static int Y_Ru[256];
241 static int Y_Gu[256];
242 static int Y_Bu[256];
243 static int Cb_Ru[256];
244 static int Cb_Gu[256];
245 static int Cb_Bu[256];
246 static int Cr_Ru[256];
247 static int Cr_Gu[256];
248 static int Cr_Bu[256];
249 
250 // clamped BT.709
251 static int HY_Rc[256];
252 static int HY_Gc[256];
253 static int HY_Bc[256];
254 static int HCb_Rc[256];
255 static int HCb_Gc[256];
256 static int HCb_Bc[256];
257 static int HCr_Rc[256];
258 static int HCr_Gc[256];
259 static int HCr_Bc[256];
260 
261 // unclamped BT.709
262 static int HY_Ru[256];
263 static int HY_Gu[256];
264 static int HY_Bu[256];
265 static int HCb_Ru[256];
266 static int HCb_Gu[256];
267 static int HCb_Bu[256];
268 static int HCr_Ru[256];
269 static int HCr_Gu[256];
270 static int HCr_Bu[256];
271 
272 static boolean conv_RY_inited = FALSE;
273 
274 // generic
275 static int *RGB_Y;
276 static int *R_Cr;
277 static int *G_Cb;
278 static int *G_Cr;
279 static int *B_Cb;
280 
281 // clamped Y'CbCr
282 static int RGB_Yc[256];
283 static int R_Crc[256];
284 static int G_Cbc[256];
285 static int G_Crc[256];
286 static int B_Cbc[256];
287 
288 // unclamped Y'CbCr
289 static int RGB_Yu[256];
290 static int R_Cru[256];
291 static int G_Cru[256];
292 static int G_Cbu[256];
293 static int B_Cbu[256];
294 
295 // clamped BT.709
296 static int HRGB_Yc[256];
297 static int HR_Crc[256];
298 static int HG_Crc[256];
299 static int HG_Cbc[256];
300 static int HB_Cbc[256];
301 
302 // unclamped BT.709
303 static int HRGB_Yu[256];
304 static int HR_Cru[256];
305 static int HG_Cru[256];
306 static int HG_Cbu[256];
307 static int HB_Cbu[256];
308 
309 static boolean conv_YR_inited = FALSE;
310 
311 static short min_Y, max_Y, min_UV, max_UV;
312 
313 // averaging
314 static uint8_t *cavg;
315 static uint8_t cavgc[256][256];
316 static uint8_t cavgu[256][256];
317 static uint8_t cavgrgb[256][256];
318 static boolean avg_inited = FALSE;
319 
320 // pre-post multiply alpha
321 static int unal[256][256];
322 static int al[256][256];
323 static int unalcy[256][256];
324 static int alcy[256][256];
325 static int unalcuv[256][256];
326 static int alcuv[256][256];
327 
328 // clamping and subspace converters
329 
330 // generic
331 static uint8_t *Y_to_Y;
332 static uint8_t *U_to_U;
333 static uint8_t *V_to_V;
334 
335 // same subspace, clamped to unclamped
336 static uint8_t Yclamped_to_Yunclamped[256];
337 static uint8_t UVclamped_to_UVunclamped[256];
338 
339 // same subspace, unclamped to clamped
340 static uint8_t Yunclamped_to_Yclamped[256];
341 static uint8_t UVunclamped_to_UVclamped[256];
342 
343 static boolean conv_YY_inited = FALSE;
344 
345 
346 // gamma correction
347 
349 // x <= b ? x * c : (a + 1) * powf(x, 1 / G) - a
350 
352 // inv: x < d ? x / c : powf((x + a) / (a + 1), G)
353 
355 
356 // for sRGB:
357 // a = 0.055, b = 0.0031308, c = 12.92, d = 0.04045, G = 2.4
358 
361 
362 static gamma_const_t gamma_tx[3];
363 
364 static uint8_t *gamma_s2l = NULL;
365 static uint8_t *gamma_l2s = NULL;
366 static uint8_t *gamma_b2l = NULL;
367 static uint8_t *gamma_l2b = NULL;
368 static uint8_t *gamma_s2b = NULL;
369 static uint8_t *gamma_b2s = NULL;
370 
371 static inline uint8_t *create_gamma_lut(double fileg, int gamma_from, int gamma_to) {
372  uint8_t *gamma_lut;
373  float inv_gamma = 0.;
374  float a, x = 0.;
375  int i;
376 
377  if (fileg == 1.0) {
378  if (gamma_to == WEED_GAMMA_UNKNOWN || gamma_from == WEED_GAMMA_UNKNOWN) return NULL;
379  if (gamma_from == WEED_GAMMA_LINEAR && gamma_to == WEED_GAMMA_SRGB && gamma_l2s) return gamma_l2s;
380  if (gamma_from == WEED_GAMMA_LINEAR && gamma_to == WEED_GAMMA_BT709 && gamma_l2b) return gamma_l2b;
381  if (gamma_from == WEED_GAMMA_SRGB && gamma_to == WEED_GAMMA_LINEAR && gamma_s2l) return gamma_s2l;
382  if (gamma_from == WEED_GAMMA_SRGB && gamma_to == WEED_GAMMA_BT709 && gamma_s2b) return gamma_s2b;
383  if (gamma_from == WEED_GAMMA_BT709 && gamma_to == WEED_GAMMA_LINEAR && gamma_b2l) return gamma_b2l;
384  if (gamma_from == WEED_GAMMA_BT709 && gamma_to == WEED_GAMMA_SRGB && gamma_b2s) return gamma_b2s;
385  }
386 
387  gamma_lut = lives_calloc(4, 64);
388  if (!gamma_lut) return NULL;
389 
390  if (gamma_to == WEED_GAMMA_MONITOR) {
391  inv_gamma = 1. / (float)prefs->screen_gamma;
392  }
393 
394  gamma_lut[0] = 0;
395 
396  for (i = 1; i < 256; ++i) {
397  if (gamma_from == gamma_to && fileg == 1.0) {
398  gamma_lut[i] = i;
399  continue;
400  }
401 
402  x = a = (float)i / 255.;
403 
404  if (fileg != 1.0) {
405  x = powf(a, fileg);
406  }
407 
408  if (1) {
409  switch (gamma_to) {
410  // simple power law transformation
411  case WEED_GAMMA_MONITOR:
412  case WEED_GAMMA_SRGB:
413  // sRGB gamma
414  switch (gamma_from) {
415  case WEED_GAMMA_BT709:
416  // conv to linear first
417  a = (a < gamma_tx[WEED_GAMMA_BT709].thresh) ? a / gamma_tx[WEED_GAMMA_BT709].lin
418  : powf((a + gamma_tx[WEED_GAMMA_BT709].offs) / (1. + gamma_tx[WEED_GAMMA_BT709].offs),
419  gamma_tx[WEED_GAMMA_BT709].pf);
420  case WEED_GAMMA_LINEAR:
421  x = (a < (gamma_tx[WEED_GAMMA_SRGB].thresh) / gamma_tx[WEED_GAMMA_SRGB].lin)
422  ? a * gamma_tx[WEED_GAMMA_SRGB].lin
423  : powf((1. + gamma_tx[WEED_GAMMA_SRGB].offs) * a,
424  1. / gamma_tx[WEED_GAMMA_SRGB].pf) - gamma_tx[WEED_GAMMA_SRGB].offs;
425 
426  if (gamma_to == WEED_GAMMA_MONITOR)
427  x = powf(a, inv_gamma);
428  break;
429  case WEED_GAMMA_MONITOR:
430  x = powf(a, prefs->screen_gamma);
431  break;
432  default:
433  break;
434  }
435  break;
436 
437  case WEED_GAMMA_LINEAR:
438  switch (gamma_from) {
439  case WEED_GAMMA_MONITOR:
440  x = powf(a, prefs->screen_gamma);
441  break;
442  case WEED_GAMMA_SRGB:
443  x = (a < gamma_tx[WEED_GAMMA_SRGB].thresh) ? a / gamma_tx[WEED_GAMMA_SRGB].lin
444  : powf((a + gamma_tx[WEED_GAMMA_SRGB].offs) / (1. + gamma_tx[WEED_GAMMA_SRGB].offs),
445  gamma_tx[WEED_GAMMA_SRGB].pf);
446  break;
447  case WEED_GAMMA_BT709:
448  x = (a < gamma_tx[WEED_GAMMA_BT709].thresh) ? a / gamma_tx[WEED_GAMMA_BT709].lin
449  : powf((a + gamma_tx[WEED_GAMMA_BT709].offs) / (1. + gamma_tx[WEED_GAMMA_BT709].offs),
450  gamma_tx[WEED_GAMMA_BT709].pf);
451  break;
452  default:
453  break;
454  }
455  // rec 709 gamma
456  case WEED_GAMMA_BT709:
457  switch (gamma_from) {
458  case WEED_GAMMA_MONITOR:
459  x = powf(a, prefs->screen_gamma);
460  break;
461  case WEED_GAMMA_SRGB:
462  // convert first to linear
463  a = (a < gamma_tx[WEED_GAMMA_SRGB].thresh) ? a / gamma_tx[WEED_GAMMA_SRGB].lin
464  : powf((a + gamma_tx[WEED_GAMMA_SRGB].offs) / (1. + gamma_tx[WEED_GAMMA_SRGB].offs),
465  gamma_tx[WEED_GAMMA_SRGB].pf);
466  case WEED_GAMMA_LINEAR:
467  x = (a < (gamma_tx[WEED_GAMMA_BT709].thresh) / gamma_tx[WEED_GAMMA_BT709].lin)
468  ? a * gamma_tx[WEED_GAMMA_BT709].lin
469  : powf((1. + gamma_tx[WEED_GAMMA_BT709].offs) * a,
470  1. / gamma_tx[WEED_GAMMA_BT709].pf) - gamma_tx[WEED_GAMMA_BT709].offs;
471  default:
472  break;
473  }
474  break;
475 
476  default:
477  break;
478  }
479  }
480  gamma_lut[i] = CLAMP0255((int32_t)(255. * x + .5));
481  }
482  if (gamma_from == WEED_GAMMA_LINEAR && gamma_to == WEED_GAMMA_SRGB && gamma_l2s)
483  gamma_l2s = gamma_lut;
484  if (gamma_from == WEED_GAMMA_LINEAR && gamma_to == WEED_GAMMA_BT709 && gamma_l2b)
485  gamma_l2b = gamma_lut;
486  if (gamma_from == WEED_GAMMA_SRGB && gamma_to == WEED_GAMMA_LINEAR && gamma_s2l)
487  gamma_s2l = gamma_lut;
488  if (gamma_from == WEED_GAMMA_SRGB && gamma_to == WEED_GAMMA_BT709 && gamma_s2b)
489  gamma_s2b = gamma_lut;
490  if (gamma_from == WEED_GAMMA_BT709 && gamma_to == WEED_GAMMA_LINEAR && gamma_b2l)
491  gamma_b2l = gamma_lut;
492  if (gamma_from == WEED_GAMMA_BT709 && gamma_to == WEED_GAMMA_SRGB && gamma_b2s)
493  gamma_b2s = gamma_lut;
494  return gamma_lut;
495 }
496 
497 static inline void lives_gamma_lut_free(uint8_t *lut) {
498  if (lut && lut != gamma_l2s && lut != gamma_l2b && lut != gamma_s2l && lut != gamma_s2b
499  && lut != gamma_b2s && lut != gamma_b2l) lives_free(lut);
500 }
501 
502 
503 static inline int32_t _spc_rnd(int32_t val, short quality) {
504  // if USE_EXTEND is defined,
505  // instead of shifting right by 16 bits, we multiplied x by scale_factor, ie., 0xFF -> 0xFFFFFF
506  // to convert back we can either shift right 16 bits (less accurate), or divide by scale_factor
507  // i.e divide by 65793 (the default)
508  // We note that 65793 == 241 * 273 = (256 - 16 + 1) * (256 + 16 + 1)
509  // val = x / (256 - 16 + 1) / (256 + 16 - 1)
510  // = x . (16 + 1) / ((256 - 16 + 1) . (16 + 1)) * (16 - 1) / ((256 + 16 + 1) . (16 - 1))
511  // = x. (16 + 1) / (256 . 16 + 256 - 256 - 16 + 16 + 1) * (16 - 1) / (256 * 16 - 256 + 256 - 16 + 16 - 1)
512  // (x . 16 + x) / (256 . 16 + 1) . (16 - 1) . (256 * 16 - 1) ~= ((x << 4) + x) >> 12 * (16 - 1) / 256 * 16
513 
514  // let a = (x << 4) + x
515 
516  // (((a >> 12) << 4) - a >> 12) >> 12
517  // ((((x >> 8 + x >> 12) << 4 - x >> 8 - x >> 12) >> 12
518 
519  // (x >> 4 + x >> 8 - x >> 8 - x >> 12) >> 12
520  // (x >> 4 - x >> 12) >> 12
521  // i.e (x - (x >> 8)) >> 16
522  // the net effect is that the highest bit is subtracted from the bit below the lsb.
523  // e.g. 0xFFFFFF -> 0XFFFFFF - 0X00FFFF >> 16 = 0xFF
524  // 0xA1B2C3 -> 0XA1B2C3 - 0x00A1B2 = 0XA11111 >> 16 = 0xA1
525  // but: 0xB1A1A1 -> 0xB1A1A1 - 0x00B1A1 = 0xB0F000 >> 16 = 0xB0
526  // i.e the lowest bit is rounded rather than simply truncated:
527  // if we are adding several factors we can do the conversion after the addition
528  // i.e the rounding error when converting from RGB to YUV goes from 1. / 255. ~= 0.4 % to half of that, i.e 0.2 %
529 
530  if (quality == PB_QUALITY_LOW) {
531  return val >> FP_BITS;
532  }
533  if (quality == PB_QUALITY_MED) {
534  uint32_t sig = val & 0x80000000;
535  return (((val - (val >> 8)) >> 16) | sig);
536  }
537  return ((float)val / SCALE_FACTOR + .5);
538 }
539 
540 
541 #define spc_rnd(val) (_spc_rnd((val), prefs ? prefs->pb_quality : PB_QUALITY_HIGH))
542 
543 
544 LIVES_GLOBAL_INLINE int32_t round_special(int32_t val) {
545  return spc_rnd(val);
546 }
547 
548 
549 double get_luma8(uint8_t r, uint8_t g, uint8_t b) {
551  short a = _spc_rnd(Y_Ru[r] + Y_Gu[g] + Y_Bu[b], PB_QUALITY_HIGH);
552  if (a > 255) a = 255;
553  return a < 0 ? 0. : (double)a / 255.;
554 }
555 
556 
557 double get_luma16(uint16_t r, uint16_t g, uint16_t b) {
559  return get_luma8(r >> 8, g >> 8, b >> 8);
560 }
561 
562 
563 static void init_RGB_to_YUV_tables(void) {
564  register int i;
565  // Digital Y'UV proper [ITU-R BT.601-5] for digital NTSC (NTSC analog uses YIQ I think)
566  // a.k.a CCIR 601, aka bt470bg (with gamma = 2.8 ?), bt470m (gamma = 2.2), aka SD
567  // uses Kr = 0.299 and Kb = 0.114
568  // offs U,V = 128
569 
570  // (I call this subspace YUV_SUBSPACE_YCBCR)
571 
572  // this is used for e.g. theora encoding, and for most video cards
573 
574  // input is linear RGB, output is gamma corrected Y'UV
575 
576  // bt.709 (HD)
577 
578  // input is linear RGB, output is gamma corrected Y'UV
579 
580  // except for bt2020 which gamma corrects the Y (only) after conversion (?)
581 
582  // there is also smpte 170 / smpte 240 (NTSC), bt.1886 (?), smpte2084, and bt2020
583 
584  // bt.1886 : gamma 2.4
585 
586  // bt2020: UHD, 10/12 bit colour
587 
588  double fac;
589 
590  for (i = 0; i < 256; i++) {
591  Y_Rc[i] = myround(KR_YCBCR * (double)i * CLAMP_FACTOR_Y * SCALE_FACTOR); // Kr
592  Y_Gc[i] = myround((1. - KR_YCBCR - KB_YCBCR) * (double)i * CLAMP_FACTOR_Y * SCALE_FACTOR); // Kb
593  Y_Bc[i] = myround((KB_YCBCR * (double)i * CLAMP_FACTOR_Y + YUV_CLAMP_MIN) * SCALE_FACTOR);
594 
595  fac = .5 / (1. - KB_YCBCR); // .564
596 
597  Cb_Rc[i] = myround(-fac * KR_YCBCR * (double)i * CLAMP_FACTOR_UV * SCALE_FACTOR); // -.16736
598  Cb_Gc[i] = myround(-fac * (1. - KB_YCBCR - KR_YCBCR) * (double)i * CLAMP_FACTOR_UV * SCALE_FACTOR); // -.331264
599  Cb_Bc[i] = myround((0.5 * (double)i * CLAMP_FACTOR_UV + UV_BIAS) * SCALE_FACTOR);
600 
601  fac = .5 / (1. - KR_YCBCR); // .713
602 
603  Cr_Rc[i] = myround((0.5 * (double)i * CLAMP_FACTOR_UV + UV_BIAS) * SCALE_FACTOR);
604  Cr_Gc[i] = myround(-fac * (1. - KB_YCBCR - KR_YCBCR) * (double)i * CLAMP_FACTOR_UV * SCALE_FACTOR);
605  Cr_Bc[i] = myround(-fac * KB_YCBCR * (double)i * CLAMP_FACTOR_UV * SCALE_FACTOR);
606  }
607 
608  for (i = 0; i < 256; i++) {
609  Y_Ru[i] = myround(KR_YCBCR * (double)i * SCALE_FACTOR); // Kr
610  Y_Gu[i] = myround((1. - KR_YCBCR - KB_YCBCR) * (double)i * SCALE_FACTOR); // Kb
611  Y_Bu[i] = myround(KB_YCBCR * (double)i * SCALE_FACTOR);
612 
613  fac = .5 / (1. - KB_YCBCR); // .564
614 
615  Cb_Ru[i] = myround(-fac * KR_YCBCR * (double)i * SCALE_FACTOR); // -.16736
616  Cb_Gu[i] = myround(-fac * (1. - KB_YCBCR - KR_YCBCR) * (double)i * SCALE_FACTOR); // -.331264
617  Cb_Bu[i] = myround((0.5 * (double)i + UV_BIAS) * SCALE_FACTOR);
618 
619  fac = .5 / (1. - KR_YCBCR); // .713
620 
621  Cr_Ru[i] = myround((0.5 * (double)i + UV_BIAS) * SCALE_FACTOR);
622  Cr_Gu[i] = myround(-fac * (1. - KB_YCBCR - KR_YCBCR) * (double)i * SCALE_FACTOR);
623  Cr_Bu[i] = myround(-fac * KB_YCBCR * (double)i * SCALE_FACTOR);
624  }
625 
626  // Different values are used for hdtv, I call this subspace YUV_SUBSPACE_BT709
627 
628  // Kr = 0.2126
629  // Kb = 0.0722
630 
631  // converting from one subspace to another is not recommended.
632 
633  for (i = 0; i < 256; i++) {
634  HY_Rc[i] = myround(KR_BT709 * (double)i * CLAMP_FACTOR_Y * SCALE_FACTOR); // Kr
635  HY_Gc[i] = myround((1. - KR_BT709 - KB_BT709) * (double)i * CLAMP_FACTOR_Y * SCALE_FACTOR); // Kb
636  HY_Bc[i] = myround((KB_BT709 * (double)i * CLAMP_FACTOR_Y + YUV_CLAMP_MIN) * SCALE_FACTOR);
637 
638  fac = .5 / (1. - KB_BT709);
639 
640  HCb_Rc[i] = myround(-fac * KR_BT709 * (double)i * CLAMP_FACTOR_UV * SCALE_FACTOR); // -.16736
641  HCb_Gc[i] = myround(-fac * (1. - KB_BT709 - KR_BT709) * (double)i * CLAMP_FACTOR_UV * SCALE_FACTOR); // -.331264
642  HCb_Bc[i] = myround((0.5 * (double)i * CLAMP_FACTOR_UV + UV_BIAS) * SCALE_FACTOR);
643 
644  fac = .5 / (1. - KR_BT709);
645 
646  HCr_Rc[i] = myround((0.5 * (double)i * CLAMP_FACTOR_UV + UV_BIAS) * SCALE_FACTOR);
647  HCr_Gc[i] = myround(-fac * (1. - KB_BT709 - KR_BT709) * (double)i * CLAMP_FACTOR_UV * SCALE_FACTOR);
648  HCr_Bc[i] = myround(-fac * KB_BT709 * (double)i * CLAMP_FACTOR_UV * SCALE_FACTOR);
649  }
650 
651  for (i = 0; i < 256; i++) {
652  HY_Ru[i] = myround(KR_BT709 * (double)i * SCALE_FACTOR); // Kr
653  HY_Gu[i] = myround((1. - KR_BT709 - KB_BT709) * (double)i * SCALE_FACTOR); // Kb
654  HY_Bu[i] = myround(KB_BT709 * (double)i * SCALE_FACTOR);
655 
656  fac = .5 / (1. - KB_BT709);
657 
658  HCb_Ru[i] = myround(-fac * KR_BT709 * (double)i * SCALE_FACTOR); // -.16736
659  HCb_Gu[i] = myround(-fac * (1. - KB_BT709 - KR_BT709) * (double)i * SCALE_FACTOR); // -.331264
660  HCb_Bu[i] = myround((0.5 * (double)i + UV_BIAS) * SCALE_FACTOR);
661 
662  fac = .5 / (1. - KR_BT709);
663 
664  HCr_Ru[i] = myround((0.5 * (double)i + UV_BIAS) * SCALE_FACTOR);
665  HCr_Gu[i] = myround(-fac * (1. - KB_BT709 - KR_BT709) * (double)i * SCALE_FACTOR);
666  HCr_Bu[i] = myround(-fac * KB_BT709 * (double)i * SCALE_FACTOR);
667  }
668 
669  conv_RY_inited = TRUE;
670 }
671 
672 static void init_YUV_to_RGB_tables(void) {
673  register int i;
674 
675  // These values are for what I call YUV_SUBSPACE_YCBCR
676 
677  /* clip Y values under 16 */
678  for (i = 0; i <= YUV_CLAMP_MINI; i++) RGB_Yc[i] = 0;
679 
680  for (; i < Y_CLAMP_MAXI; i++) {
681  RGB_Yc[i] = myround(((double)i - YUV_CLAMP_MIN) / (Y_CLAMP_MAX - YUV_CLAMP_MIN) * 255. * SCALE_FACTOR);
682  }
683  /* clip Y values above 235 */
684  for (; i < 256; i++) RGB_Yc[i] = 255 * SCALE_FACTOR;
685 
686  /* clip Cb/Cr values below 16 */
687  for (i = 0; i <= YUV_CLAMP_MINI; i++) R_Crc[i] = G_Crc[i] = G_Cbc[i] = B_Cbc[i] = 0;
688 
689  for (; i < UV_CLAMP_MAXI; i++) {
690  R_Crc[i] = myround(2. * (1. - KR_YCBCR) * ((((double)i - YUV_CLAMP_MIN) /
691  (UV_CLAMP_MAX - YUV_CLAMP_MIN) * 255.) - UV_BIAS) * SCALE_FACTOR); // 2*(1-Kr)
692 
693  G_Cbc[i] = myround(-.5 / (1. + KB_YCBCR + KR_YCBCR) * ((((double)i - YUV_CLAMP_MIN) /
695 
696  G_Crc[i] = myround(-.5 / (1. - KR_YCBCR) * ((((double)i - YUV_CLAMP_MIN) /
698 
699  B_Cbc[i] = myround(2. * (1. - KB_YCBCR) * ((((double)i - YUV_CLAMP_MIN) /
700  (UV_CLAMP_MAX - YUV_CLAMP_MIN) * 255.) - UV_BIAS) * SCALE_FACTOR); // 2*(1-Kb)
701  }
702  /* clip Cb/Cr values above 240 */
703  for (; i < 256; i++) {
704  R_Crc[i] = myround(2. * (1. - KR_YCBCR) * (((UV_CLAMP_MAX - YUV_CLAMP_MIN) /
705  (UV_CLAMP_MAX - YUV_CLAMP_MIN) * 255.) - UV_BIAS) * SCALE_FACTOR); // 2*(1-Kr)
706  G_Crc[i] = myround(-.5 / (1. - KR_YCBCR) * (((UV_CLAMP_MAX - YUV_CLAMP_MIN) /
708  G_Cbc[i] = myround(-.5 / (1. + KB_YCBCR + KR_YCBCR) * (((UV_CLAMP_MAX - YUV_CLAMP_MIN) /
710  B_Cbc[i] = myround(2. * (1. - KB_YCBCR) * (((UV_CLAMP_MAX - YUV_CLAMP_MIN) /
711  (UV_CLAMP_MAX - YUV_CLAMP_MIN) * 255.) - UV_BIAS) * SCALE_FACTOR); // 2*(1-Kb)
712  }
713 
714  // unclamped Y'CbCr
715  for (i = 0; i <= 255; i++) {
716  RGB_Yu[i] = i * SCALE_FACTOR;
717  }
718 
719  for (i = 0; i <= 255; i++) {
720  R_Cru[i] = myround(2. * (1. - KR_YCBCR) * ((double)i - UV_BIAS) * SCALE_FACTOR); // 2*(1-Kr)
721  G_Cru[i] = myround(-.5 / (1. - KR_YCBCR) * ((double)i - UV_BIAS) * SCALE_FACTOR);
722  G_Cbu[i] = myround(-.5 / (1. + KB_YCBCR + KR_YCBCR) * ((double)i - UV_BIAS) * SCALE_FACTOR);
723  B_Cbu[i] = myround(2. * (1. - KB_YCBCR) * ((double)i - UV_BIAS) * SCALE_FACTOR); // 2*(1-Kb)
724  }
725 
726  // These values are for what I call YUV_SUBSPACE_BT709
727 
728  /* clip Y values under 16 */
729  for (i = 0; i <= YUV_CLAMP_MINI; i++) HRGB_Yc[i] = 0;
730 
731  for (; i < Y_CLAMP_MAXI; i++) {
732  HRGB_Yc[i] = myround(((double)i - YUV_CLAMP_MIN) / (Y_CLAMP_MAX - YUV_CLAMP_MIN) * 255. * SCALE_FACTOR);
733  }
734 
735  /* clip Y values above 235 */
736  for (; i < 256; i++) HRGB_Yc[i] = 255 * SCALE_FACTOR;
737 
738  /* clip Cb/Cr values below 16 */
739  for (i = 0; i <= YUV_CLAMP_MINI; i++) HR_Crc[i] = HG_Crc[i] = HG_Cbc[i] = HB_Cbc[i] = 0;
740 
741  for (; i < UV_CLAMP_MAXI; i++) {
742  HR_Crc[i] = myround(2. * (1. - KR_BT709) * ((((double)i - YUV_CLAMP_MIN) /
743  (UV_CLAMP_MAX - YUV_CLAMP_MIN) * 255.) - UV_BIAS) * SCALE_FACTOR); // 2*(1-Kr)
744  HG_Crc[i] = myround(-.5 / (1. - KR_BT709) * ((((double)i - YUV_CLAMP_MIN) /
746  HG_Cbc[i] = myround(-.5 / (1. + KB_BT709 + KB_BT709) * ((((double)i - YUV_CLAMP_MIN) /
748  HB_Cbc[i] = myround(2. * (1. - KB_BT709) * ((((double)i - YUV_CLAMP_MIN) /
749  (UV_CLAMP_MAX - YUV_CLAMP_MIN) * 255.) - UV_BIAS) * SCALE_FACTOR); // 2*(1-Kb)
750  }
751  /* clip Cb/Cr values above 240 */
752  for (; i < 256; i++) {
753  HR_Crc[i] = myround(2. * (1. - KR_BT709) * (255. - UV_BIAS) * SCALE_FACTOR); // 2*(1-Kr)
754  HG_Crc[i] = myround(-.5 / (1. - KR_BT709) * (255. - UV_BIAS) * SCALE_FACTOR);
755  HG_Cbc[i] = myround(-.5 / (1. + KB_BT709 + KB_BT709) * (255. - UV_BIAS) * SCALE_FACTOR);
756  HB_Cbc[i] = myround(2. * (1. - KB_BT709) * (255. - UV_BIAS) * SCALE_FACTOR); // 2*(1-Kb)
757  }
758 
759  // unclamped Y'CbCr
760  for (i = 0; i <= 255; i++) HRGB_Yu[i] = i * SCALE_FACTOR;
761 
762  for (i = 0; i <= 255; i++) {
763  HR_Cru[i] = myround(2. * (1. - KR_BT709) * ((double)i - UV_BIAS) * SCALE_FACTOR); // 2*(1-Kr)
764  HG_Cru[i] = myround(-.5 / (1. - KR_BT709) * ((double)i - UV_BIAS) * SCALE_FACTOR);
765  HG_Cbu[i] = myround(-.5 / (1. + KB_BT709 + KB_BT709) * ((double)i - UV_BIAS) * SCALE_FACTOR);
766  HB_Cbu[i] = myround(2. * (1. - KB_BT709) * ((double)i - UV_BIAS) * SCALE_FACTOR); // 2*(1-Kb)
767  }
768  conv_YR_inited = TRUE;
769 }
770 
771 
772 static void init_YUV_to_YUV_tables(void) {
773  register int i;
774 
775  // init clamped -> unclamped, same subspace
776  for (i = 0; i <= YUV_CLAMP_MINI; i++) {
777  Yclamped_to_Yunclamped[i] = 0;
778  }
779  for (; i < Y_CLAMP_MAXI; i++) {
780  Yclamped_to_Yunclamped[i] = myround((i - YUV_CLAMP_MIN) * 255. / (Y_CLAMP_MAX - YUV_CLAMP_MIN));
781  }
782  for (; i < 256; i++) {
783  Yclamped_to_Yunclamped[i] = 255;
784  }
785 
786  for (i = 0; i < YUV_CLAMP_MINI; i++) {
787  UVclamped_to_UVunclamped[i] = 0;
788  }
789  for (; i < UV_CLAMP_MAXI; i++) {
790  UVclamped_to_UVunclamped[i] = myround((i - YUV_CLAMP_MIN) * 255. / (UV_CLAMP_MAX - YUV_CLAMP_MIN));
791  }
792  for (; i < 256; i++) {
793  UVclamped_to_UVunclamped[i] = 255;
794  }
795 
796  for (i = 0; i < 256; i++) {
797  Yunclamped_to_Yclamped[i] = myround((i / 255.) * (Y_CLAMP_MAX - YUV_CLAMP_MIN) + YUV_CLAMP_MIN);
798  UVunclamped_to_UVclamped[i] = myround((i / 255.) * (UV_CLAMP_MAX - YUV_CLAMP_MIN) + YUV_CLAMP_MIN);
799  }
800 
801  conv_YY_inited = TRUE;
802 }
803 
804 
805 static void init_average(void) {
806  for (int x = 0; x < 256; x++) {
807  float fa = (float)(x - 128.) * 255. / 244.;
808  short sa = (short)(x - 128);
809  for (int y = 0; y < 256; y++) {
810  float fb = (float)(y - 128.) * 255. / 244.;
811  short sb = (short)(y - 128);
812 #ifdef MULT_AVG
813  // values mixed in proportion to strength
814  float fc = (fa + fb - ((fa * fb) >> 8)) * 224. / 512. + 128.;
815  short c = (sa + sb - ((sa * sb) >> 8)) + 128;
816 #else
817  // values mixed equally
818  float fc = (fa + fb) * 224. / 512. + 128.;
819  short c = ((sa + sb) >> 1) + 128;
820 #endif
821  cavgc[x][y] = (uint8_t)(fc > 240. ? 240 : fc < 16. ? 16 : fc);
822  cavgrgb[x][y] = cavgu[x][y] = (uint8_t)(c > 255 ? 255 : c < 0 ? 0 : c);
823  }
824  }
825  avg_inited = TRUE;
826 }
827 
828 
829 static void init_unal(void) {
830  // premult to postmult and vice-versa
831  for (int i = 0; i < 256; i++) { //alpha val
832  for (int j = 0; j < 256; j++) { // val to be converted
833  unal[i][j] = (float)j * 255. / (float)i;
834  al[i][j] = (float)j * (float)i / 255.;
835 
836  // clamped versions
837  unalcy[i][j] = ((j - YUV_CLAMP_MIN) / (Y_CLAMP_MAX - YUV_CLAMP_MIN)) / (float)i;
838  alcy[i][j] = ((j - YUV_CLAMP_MIN) / (Y_CLAMP_MAX - YUV_CLAMP_MIN)) * (float)i;
839  unalcuv[i][j] = ((j - YUV_CLAMP_MIN) / (UV_CLAMP_MAX - YUV_CLAMP_MIN)) / (float)i;
840  alcuv[i][j] = ((j - YUV_CLAMP_MIN) / (UV_CLAMP_MAX - YUV_CLAMP_MIN)) * (float)i;
841  }
842  }
843  unal_inited = TRUE;
844 }
845 
846 
847 static void set_conversion_arrays(int clamping, int subspace) {
848  // set conversion arrays for RGB <-> YUV, also min/max YUV values
849  // depending on clamping and subspace
850 
851  switch (subspace) {
852  case WEED_YUV_SUBSPACE_YUV: // assume YCBCR
853  case WEED_YUV_SUBSPACE_YCBCR:
854  if (clamping == WEED_YUV_CLAMPING_CLAMPED) {
855  Y_R = Y_Rc;
856  Y_G = Y_Gc;
857  Y_B = Y_Bc;
858 
859  Cr_R = Cr_Rc;
860  Cr_G = Cr_Gc;
861  Cr_B = Cr_Bc;
862 
863  Cb_R = Cb_Rc;
864  Cb_G = Cb_Gc;
865  Cb_B = Cb_Bc;
866 
867  RGB_Y = RGB_Yc;
868 
869  R_Cr = R_Crc;
870  G_Cr = G_Crc;
871 
872  G_Cb = G_Cbc;
873  B_Cb = B_Cbc;
874  } else {
875  Y_R = Y_Ru;
876  Y_G = Y_Gu;
877  Y_B = Y_Bu;
878 
879  Cr_R = Cr_Ru;
880  Cr_G = Cr_Gu;
881  Cr_B = Cr_Bu;
882 
883  Cb_R = Cb_Ru;
884  Cb_G = Cb_Gu;
885  Cb_B = Cb_Bu;
886 
887  RGB_Y = RGB_Yu;
888 
889  R_Cr = R_Cru;
890  G_Cr = G_Cru;
891  G_Cb = G_Cbu;
892  B_Cb = B_Cbu;
893  }
894  break;
895  case WEED_YUV_SUBSPACE_BT709:
896  if (clamping == WEED_YUV_CLAMPING_CLAMPED) {
897  Y_R = HY_Rc;
898  Y_G = HY_Gc;
899  Y_B = HY_Bc;
900 
901  Cr_R = HCr_Rc;
902  Cr_G = HCr_Gc;
903  Cr_B = HCr_Bc;
904 
905  Cb_R = HCb_Rc;
906  Cb_G = HCb_Gc;
907  Cb_B = HCb_Bc;
908 
909  RGB_Y = HRGB_Yc;
910 
911  R_Cr = HR_Crc;
912  G_Cr = HG_Crc;
913  G_Cb = HG_Cbc;
914  B_Cb = HB_Cbc;
915  } else {
916  Y_R = HY_Ru;
917  Y_G = HY_Gu;
918  Y_B = HY_Bu;
919 
920  Cr_R = HCr_Ru;
921  Cr_G = HCr_Gu;
922  Cr_B = HCr_Bu;
923 
924  Cb_R = HCb_Ru;
925  Cb_G = HCb_Gu;
926  Cb_B = HCb_Bu;
927 
928  RGB_Y = HRGB_Yu;
929 
930  R_Cr = HR_Cru;
931  G_Cr = HG_Cru;
932  G_Cb = HG_Cbu;
933  B_Cb = HB_Cbu;
934  }
935  break;
936  }
937 
938  if (!avg_inited) init_average();
939 
940  if (clamping == WEED_YUV_CLAMPING_CLAMPED) {
941  min_Y = min_UV = YUV_CLAMP_MIN;
942  max_Y = Y_CLAMP_MAX;
943  max_UV = UV_CLAMP_MAX;
944  cavg = (uint8_t *)cavgc;
945  } else {
946  min_Y = min_UV = 0;
947  max_Y = max_UV = 255;
948  cavg = (uint8_t *)cavgu;
949  }
950 }
951 
952 
953 static void get_YUV_to_YUV_conversion_arrays(int iclamping, int isubspace, int oclamping, int osubspace) {
954  // get conversion arrays for YUV -> YUV depending on in/out clamping and subspace
955  // currently only clamped <-> unclamped conversions are catered for, subspace conversions are not yet done
956  char *errmsg = NULL;
957  if (!conv_YY_inited) init_YUV_to_YUV_tables();
958 
959  switch (isubspace) {
960  case WEED_YUV_SUBSPACE_YUV:
961  LIVES_WARN("YUV subspace input not specified, assuming Y'CbCr");
962  case WEED_YUV_SUBSPACE_YCBCR:
963  switch (osubspace) {
964  case WEED_YUV_SUBSPACE_YUV:
965  LIVES_WARN("YUV subspace output not specified, assuming Y'CbCr");
966  case WEED_YUV_SUBSPACE_YCBCR:
967  if (iclamping == WEED_YUV_CLAMPING_CLAMPED) {
968  //Y'CbCr clamped -> Y'CbCr unclamped
969  Y_to_Y = Yclamped_to_Yunclamped;
970  U_to_U = V_to_V = UVclamped_to_UVunclamped;
971  } else {
972  //Y'CbCr unclamped -> Y'CbCr clamped
973  Y_to_Y = Yunclamped_to_Yclamped;
974  U_to_U = V_to_V = UVunclamped_to_UVclamped;
975  }
976  break;
977  // TODO - other subspaces
978  default:
979  errmsg = lives_strdup_printf("Invalid YUV subspace conversion %d to %d", isubspace, osubspace);
980  LIVES_ERROR(errmsg);
981  }
982  break;
983  case WEED_YUV_SUBSPACE_BT709:
984  switch (osubspace) {
985  case WEED_YUV_SUBSPACE_YUV:
986  LIVES_WARN("YUV subspace output not specified, assuming BT709");
987  case WEED_YUV_SUBSPACE_BT709:
988  if (iclamping == WEED_YUV_CLAMPING_CLAMPED) {
989  //BT.709 clamped -> BT.709 unclamped
990  Y_to_Y = Yclamped_to_Yunclamped;
991  U_to_U = V_to_V = UVclamped_to_UVunclamped;
992  } else {
993  //BT.709 unclamped -> BT.709 clamped
994  Y_to_Y = Yunclamped_to_Yclamped;
995  U_to_U = V_to_V = UVunclamped_to_UVclamped;
996  }
997  break;
998  // TODO - other subspaces
999  default:
1000  errmsg = lives_strdup_printf("Invalid YUV subspace conversion %d to %d", isubspace, osubspace);
1001  LIVES_ERROR(errmsg);
1002  }
1003  break;
1004  default:
1005  errmsg = lives_strdup_printf("Invalid YUV subspace conversion %d to %d", isubspace, osubspace);
1006  LIVES_ERROR(errmsg);
1007  break;
1008  }
1009  if (errmsg) lives_free(errmsg);
1010 }
1011 
1012 
1013 void rgb2xyz(uint8_t r, uint8_t g, uint8_t b, double *x, double *y, double *z) {
1014  double rr = (double)r / 2.55, gg = (double)g / 2.55, bb = (double)b / 2.55;
1015  *x = rr * 0.4124 + gg * 0.3576 + bb * 0.1805;
1016  *y = rr * 0.2126 + gg * 0.7152 + bb * 0.0722;
1017  *z = rr * 0.0193 + gg * 0.1192 + bb * 0.9505;
1018 }
1019 
1020 // xyz and lab, thanks to
1021 // https://www.emanueleferonato.com/2009/09/08/color-difference-algorithm-part-2
1022 #define LAB0 0.008856
1023 #define LAB1 0.33333333333
1024 #define LAB2 7.787
1025 #define LAB3 0.13793103448 // 16. / 116.
1026 LIVES_LOCAL_INLINE double lab_conv(double a) {return a > LAB0 ? pow(a, LAB1) : a * LAB2 + LAB3;}
1027 
1028 void xyz2lab(double x, double y, double z, double *l, double *a, double *b) {
1029  x = lab_conv(x); y = lab_conv(y); z = lab_conv(z);
1030  if (l) {*l = 116. * y - 16.;} if (a) {*a = 500. * (x - y);} if (b) {*b = 200. * (y - z);}
1031 }
1032 
1033 #define KL 1.0 // 2.0 for textiles
1034 #define KC 1.0 // default
1035 #define KH 1.0 // default
1036 #define K1 0.045 // graphics arts, 0.048 textiles
1037 #define K2 0.015 // graphics arts, 0.014 textiles
1038 #define RNDFAC 0.0000000001
1039 static double cdist94lab(double l0, double a0, double b0, double l1, double a1, double b1) {
1040  // CIE94
1041  double dl = l0 - l1;
1042  double c0 = sqrt(a0 * a0 + b0 * b0), c1 = sqrt(a1 * a1 + b1 * b1);
1043  double dc = c0 - c1, da = a0 - a1, db = b0 - b1;
1044  double dh = sqrt(da * da + db * db - dc * dc + RNDFAC);
1045  //dl /= KL; // 1.0 default, 2.0 textiles
1046  dc /= (1. + K1 * c0);
1047  //dc /= KC; // 1.0 default
1048  dh /= (1. + K2 * c1);
1049  //dh /= KH; // 1.0 default
1050  return sqrt(dl * dl + dc * dc + dh * dh);
1051 }
1052 
1053 
1054 static uint8_t get_maxmin_diff(uint8_t a, uint8_t b, uint8_t c, uint8_t *max, uint8_t *min) {
1055  uint8_t lmax = a;
1056  uint8_t lmin = a;
1057  if (a > b) {
1058  if (b > c) lmin = c;
1059  else {
1060  lmin = b;
1061  if (c > a) lmax = c;
1062  }
1063  } else {
1064  if (b < c) lmax = c;
1065  else {
1066  lmax = b;
1067  if (c < a) lmin = c;
1068  }
1069  }
1070  if (max) *max = lmax;
1071  if (min) *min = lmin;
1072  return lmax - lmin;
1073 }
1074 
1075 double cdist94(uint8_t r0, uint8_t g0, uint8_t b0, uint8_t r1, uint8_t g1, uint8_t b1) {
1076  double dist;
1077  double x0 = 0., y0 = 0., z0 = 0.;
1078  double x1 = 0., y1 = 0., z1 = 0.;
1079  double L0 = 0., A0 = 0., B0 = 0.;
1080  double L1 = 0., A1 = 0., B1 = 0.;
1081  rgb2xyz(r0, g0, b0, &x0, &y0, &z0);
1082  rgb2xyz(r1, g1, b1, &x1, &y1, &z1);
1083  xyz2lab(x0, y0, z0, &L0, &A0, &B0);
1084  xyz2lab(x1, y1, z1, &L1, &A1, &B1);
1085  dist = cdist94lab(L0, A0, B0, L1, A1, B1);
1086  return dist;
1087 }
1088 
1089 
1090 void rgb2hsv(uint8_t r, uint8_t g, uint8_t b, double *h, double *s, double *v) {
1091  // h, s, v = hue, saturation, value
1092  uint8_t cmax = 0, cmin = 0;
1093  uint8_t diff = get_maxmin_diff(r, g, b, &cmax, &cmin);
1094  double ddiff = (double)diff, dcmax = (double)cmax;
1095  if (h) {*h = 0.;} if (s) {*s = 0.;} if (v) {*v = 0.;}
1096  if (h && cmax != cmin) {
1097  if (cmax == r) *h = ((double)g - (double)b) / ddiff;
1098  else if (cmax == g) *h = 2. + ((double)b - (double)r) / ddiff;
1099  else *h = 4. + ((double)r - (double)g) / ddiff;
1100  *h = 60. * (*h < 0. ? (*h + 6.) : *h >= 6. ? (*h - 6.) : *h);
1101  }
1102  if (s && cmax) *s = (ddiff / dcmax) * 100.;
1103  if (v) *v = dcmax / 2.55;
1104 
1105 #if CALC_HSL
1106  register short a;
1107  if ((a = spc_rnd(Y_Ru[r] + Y_Gu[g] + Y_Bu[b])) > 255) a = 255;
1108  if (v) *v = (double)(a < 0 ? 0 : a) / 255.;
1109 #endif
1110 
1111 }
1112 
1113 void hsv2rgb(double h, double s, double v, uint8_t *r, uint8_t *g, uint8_t *b) {
1114  if (s < 0.000001) {
1115  *r = *g = *b = (v * 255. + .5);
1116  return;
1117  } else {
1118  int i = (int)h;
1119  double f = h - (double)i;
1120  double p = v * (1. - s);
1121  double dr, dg, db;
1122  if (i & 1) {
1123  double q = v * (1. - (s * f));
1124  switch (i) {
1125  case 1: dr = q; dg = v; db = p; break;
1126  case 3: dr = p; dg = q; db = v; break;
1127  default: dr = v; dg = p; db = q; break;
1128  }
1129  } else {
1130  double t = v * (1. - (s * (1. - f)));
1131  switch (i) {
1132  case 0: dr = v; dg = t; db = p; break;
1133  case 2: dr = p; dg = v; db = t; break;
1134  default: dr = t; dg = p; db = v; break;
1135  }
1136  }
1137  *r = (uint8_t)(dr * 255. + .5); *g = (uint8_t)(dg * 255. + .5); *b = (uint8_t)(db * 255. + .5);
1138  }
1139 }
1140 
1141 
1142 boolean pick_nice_colour(uint8_t r0, uint8_t g0, uint8_t b0, uint8_t *r1, uint8_t *g1, uint8_t *b1,
1143  double max, double lmin, double lmax) {
1144  // given 2 colours a and b, calculate the cie94 distance (d) between them, then find a third colour
1145  // first calc the avg, calc d(a, b) with threshold > 1.
1146  // pick a random colour, the dist from avg must be approx. d(a, b) * max
1147  // da / db must be > ,9 and db / da also
1148  // finally luma should be between lmin and lmax
1149  // restrictions are gradually loosened
1150 
1151 #define DIST_THRESH 10.
1152 #define RAT_START .9
1153 #define RAT_TIO .9999999
1154 #define RAT_MIN .2
1155 
1156  volatile double gmm = 1. + lmax * 2., gmn = 1. + lmin;
1157  volatile uint8_t xr, xb, xg, ar, ag, ab;
1158  volatile uint8_t rmin = MIN(r0, *r1) / 1.5, gmin = MIN(g0, *g1) / gmm, bmin = MIN(b0, *b1) / 1.5;
1159  volatile uint8_t rmax = MAX(r0, *r1), gmax = MAX(g0, *g1), bmax = MAX(b0, *b1);
1160  volatile double da, db, z, rat = RAT_START, d = cdist94(r0, g0, b0, *r1, *g1, *b1);
1161  if (d < DIST_THRESH) d = DIST_THRESH;
1162  max *= d;
1163 
1164  ar = (volatile double)(r0 + *r1) / 2.;
1165  ag = (volatile double)(g0 + *g1) / 2.;
1166  ab = (volatile double)(b0 + *b1) / 2.;
1167 
1168  rmax = (rmax < 128 ? rmax << 1 : 255) - rmin;
1169  gmax = (gmax < 255 / gmn ? gmax *gmn : 255) - gmin;
1170  bmax = (bmax < 128 ? bmax << 1 : 255) - bmin;
1171 
1172  while ((z = rat * RAT_TIO) > RAT_MIN) {
1173  rat = z;
1175  xr = fastrand_int(bmax) + bmin;
1176  xg = fastrand_int(gmax) + gmin;
1177  xb = fastrand_int(bmax) + bmin;
1178 
1179  da = cdist94(ar, ag, ab, xr, xg, xb);
1180  if (max * rat > da) continue;
1181  da = cdist94(r0, g0, b0, xr, xg, xb);
1182  db = cdist94(*r1, *g1, *b1, xr, xg, xb);
1183  if (da * rat * lmax > db || db * rat > da * lmax) continue;
1184  else {
1185  double l = get_luma8(xr, xg, xb);
1186  if (l < lmin || l > lmax) continue;
1187  *r1 = xr; *g1 = xg; *b1 = xb;
1188  return TRUE;
1189  }
1190  }
1191  return FALSE;
1192 }
1193 
1194 
1196 // pixel conversions
1197 #ifdef WEED_ADVANCED_PALETTES
1198 
1199 static weed_macropixel_t advp[256];
1200 
1202  lives_memset(advp, 0, 256 * sizeof(weed_macropixel_t));
1203 
1204  advp[0] = (weed_macropixel_t) {
1205  WEED_PALETTE_RGB24,
1206  {WEED_VCHAN_red, WEED_VCHAN_green, WEED_VCHAN_blue}
1207  };
1208 
1209  advp[1] = (weed_macropixel_t) {
1210  WEED_PALETTE_BGR24,
1211  {WEED_VCHAN_blue, WEED_VCHAN_green, WEED_VCHAN_red}
1212  };
1213 
1214  advp[2] = (weed_macropixel_t) {
1215  WEED_PALETTE_RGBA32,
1216  {WEED_VCHAN_red, WEED_VCHAN_green, WEED_VCHAN_blue, WEED_VCHAN_alpha}
1217  };
1218 
1219  advp[3] = (weed_macropixel_t) {
1220  WEED_PALETTE_BGRA32,
1221  {WEED_VCHAN_blue, WEED_VCHAN_green, WEED_VCHAN_red, WEED_VCHAN_alpha}
1222  };
1223 
1224  advp[4] = (weed_macropixel_t) {
1225  WEED_PALETTE_ARGB32,
1226  {WEED_VCHAN_alpha, WEED_VCHAN_red, WEED_VCHAN_green, WEED_VCHAN_blue}
1227  };
1228 
1229  advp[5] = (weed_macropixel_t) {
1230  WEED_PALETTE_RGBFLOAT,
1231  {WEED_VCHAN_red, WEED_VCHAN_green, WEED_VCHAN_blue},
1232  WEED_VCHAN_DESC_FP, {0}, {0}, 1, {32, 32, 32}
1233  };
1234 
1235  advp[6] = (weed_macropixel_t) {
1236  WEED_PALETTE_RGBAFLOAT,
1237  {WEED_VCHAN_red, WEED_VCHAN_green, WEED_VCHAN_blue, WEED_VCHAN_alpha},
1238  WEED_VCHAN_DESC_FP, {0}, {0}, 1, {32, 32, 32, 32}
1239  };
1240 
1242  advp[7] = (weed_macropixel_t) {
1243  WEED_PALETTE_YUV420P,
1244  {WEED_VCHAN_Y, WEED_VCHAN_U, WEED_VCHAN_V},
1245  WEED_VCHAN_DESC_PLANAR, {1, 2, 2}, {1, 2, 2}
1246  };
1247 
1248  advp[8] = (weed_macropixel_t) {
1249  WEED_PALETTE_YVU420P,
1250  {WEED_VCHAN_Y, WEED_VCHAN_V, WEED_VCHAN_U},
1251  WEED_VCHAN_DESC_PLANAR, {1, 2, 2}, {1, 2, 2}
1252  };
1253 
1254  advp[9] = (weed_macropixel_t) {
1255  WEED_PALETTE_YUV422P,
1256  {WEED_VCHAN_Y, WEED_VCHAN_U, WEED_VCHAN_V},
1257  WEED_VCHAN_DESC_PLANAR, {1, 2, 2}, {1, 1, 1}
1258  };
1259 
1260  advp[10] = (weed_macropixel_t) {
1261  WEED_PALETTE_YUV444P,
1262  {WEED_VCHAN_Y, WEED_VCHAN_U, WEED_VCHAN_V}, WEED_VCHAN_DESC_PLANAR
1263  };
1264 
1265  advp[11] = (weed_macropixel_t) {
1266  WEED_PALETTE_YUVA4444P,
1267  {WEED_VCHAN_Y, WEED_VCHAN_U, WEED_VCHAN_V, WEED_VCHAN_alpha},
1268  WEED_VCHAN_DESC_PLANAR
1269  };
1270 
1272  advp[12] = (weed_macropixel_t) {
1273  WEED_PALETTE_UYVY,
1274  {WEED_VCHAN_U, WEED_VCHAN_Y, WEED_VCHAN_V, WEED_VCHAN_Y},
1275  0, {0}, {0}, 2
1276  };
1277 
1278  advp[13] = (weed_macropixel_t) {
1279  WEED_PALETTE_YUYV,
1280  {WEED_VCHAN_Y, WEED_VCHAN_U, WEED_VCHAN_Y, WEED_VCHAN_V},
1281  0, {0}, {0}, 2
1282  };
1283 
1284  advp[14] = (weed_macropixel_t) {WEED_PALETTE_YUV888, {WEED_VCHAN_Y, WEED_VCHAN_U, WEED_VCHAN_V}};
1285 
1286  advp[15] = (weed_macropixel_t) {
1287  WEED_PALETTE_YUVA8888,
1288  {WEED_VCHAN_Y, WEED_VCHAN_U, WEED_VCHAN_V, WEED_VCHAN_alpha}
1289  };
1290 
1291  advp[16] = (weed_macropixel_t) {
1292  WEED_PALETTE_YUV411, {
1293  WEED_VCHAN_U, WEED_VCHAN_Y, WEED_VCHAN_Y,
1294  WEED_VCHAN_V, WEED_VCHAN_Y, WEED_VCHAN_Y
1295  },
1296  0, {0}, {0}, 4
1297  };
1298 
1300  advp[17] = (weed_macropixel_t) {WEED_PALETTE_A8, {WEED_VCHAN_alpha}};
1301 
1302  advp[18] = (weed_macropixel_t) {WEED_PALETTE_A1, {WEED_VCHAN_alpha}, 0, {0}, {0}, 1, {1}};
1303 
1304  advp[19] = (weed_macropixel_t) {
1305  WEED_PALETTE_AFLOAT, {WEED_VCHAN_alpha},
1306  WEED_VCHAN_DESC_FP, {0}, {0}, 1, {32}
1307  };
1308 
1309  advp[20] = (weed_macropixel_t) {WEED_PALETTE_END};
1310 
1311  // custom palettes (designed for future use or for testing)
1312  advp[21] = (weed_macropixel_t) {
1313  LIVES_PALETTE_ABGR32,
1314  {WEED_VCHAN_alpha, WEED_VCHAN_blue, WEED_VCHAN_green, WEED_VCHAN_red}
1315  };
1316 
1317  advp[22] = (weed_macropixel_t) {
1318  LIVES_PALETTE_YVU422P,
1319  {WEED_VCHAN_Y, WEED_VCHAN_V, WEED_VCHAN_U},
1320  WEED_VCHAN_DESC_PLANAR, {1, 2, 2}, {1, 1, 1}
1321  };
1322 
1323  advp[23] = (weed_macropixel_t) {
1324  LIVES_PALETTE_YUVA420P,
1325  {WEED_VCHAN_Y, WEED_VCHAN_U, WEED_VCHAN_V, WEED_VCHAN_alpha},
1326  WEED_VCHAN_DESC_PLANAR, {1, 2, 2, 1}, {1, 2, 2, 1}
1327  };
1328 
1329  advp[24] = (weed_macropixel_t) {
1330  LIVES_PALETTE_AYUV8888,
1331  {WEED_VCHAN_alpha, WEED_VCHAN_Y, WEED_VCHAN_U, WEED_VCHAN_V}
1332  };
1333 
1334  advp[25] = (weed_macropixel_t) {
1335  LIVES_PALETTE_YUVFLOAT,
1336  {WEED_VCHAN_Y, WEED_VCHAN_U, WEED_VCHAN_V},
1337  WEED_VCHAN_DESC_FP, {0}, {0}, 1, {32, 32, 32}
1338  };
1339 
1340  advp[26] = (weed_macropixel_t) {
1341  LIVES_PALETTE_YUVAFLOAT,
1342  {WEED_VCHAN_Y, WEED_VCHAN_U, WEED_VCHAN_V, WEED_VCHAN_alpha},
1343  WEED_VCHAN_DESC_FP, {0}, {0}, 1, {32, 32, 32, 32}
1344  };
1345 
1346  advp[27] = (weed_macropixel_t) {
1347  LIVES_PALETTE_RGB48,
1348  {WEED_VCHAN_red, WEED_VCHAN_green, WEED_VCHAN_blue},
1349  0, {0}, {0}, 1, {16, 16, 16}
1350  };
1351 
1352  advp[28] = (weed_macropixel_t) {
1353  LIVES_PALETTE_RGBA64, {
1354  WEED_VCHAN_red, WEED_VCHAN_green,
1355  WEED_VCHAN_blue, WEED_VCHAN_alpha
1356  },
1357  0, {0}, {0}, 1, {16, 16, 16, 16}
1358  };
1359 
1360  advp[29] = (weed_macropixel_t) {
1361  LIVES_PALETTE_YUV121010,
1362  {WEED_VCHAN_Y, WEED_VCHAN_U, WEED_VCHAN_V},
1363  0, {0}, {0}, 1, {12, 10, 10}
1364  };
1365 }
1366 
1367 
1368 LIVES_GLOBAL_INLINE const weed_macropixel_t *get_advanced_palette(int weed_palette) {
1369  for (register int i = 0; advp[i].ext_ref != WEED_PALETTE_END; i++)
1370  if (advp[i].ext_ref == weed_palette) return &advp[i];
1371  return NULL;
1372 }
1373 
1375  return (get_advanced_palette(pal) != NULL);
1376 }
1377 
1378 LIVES_GLOBAL_INLINE int get_simple_palette(weed_macropixel_t *mpx) {
1379  if (mpx) return mpx->ext_ref;
1380  return WEED_PALETTE_NONE;
1381 }
1382 
1383 LIVES_LOCAL_INLINE boolean is_rgbchan(uint16_t ctype) {
1384  return (ctype == WEED_VCHAN_red || ctype == WEED_VCHAN_green || ctype == WEED_VCHAN_blue);
1385 }
1386 
1387 LIVES_LOCAL_INLINE boolean is_yuvchan(uint16_t ctype) {
1388  return (ctype == WEED_VCHAN_Y || ctype == WEED_VCHAN_U || ctype == WEED_VCHAN_V);
1389 }
1390 
1393  const weed_macropixel_t *mpx = get_advanced_palette(pal);
1394  if (!mpx) return 0;
1395  else {
1396  size_t psize = 0;
1397  for (register int i = 0; i < MAXPPLANES && mpx->chantype[i]; i++)
1398  psize += mpx->bitsize[i] == 0 ? 1 : mpx->bitsize[i] / 8;
1399  return psize;
1400  }
1401 }
1402 
1404  int npix = 0;
1405  const weed_macropixel_t *mpx = get_advanced_palette(pal);
1406  if (!mpx) return 0;
1407  npix = mpx->npixels;
1408  return !npix ? 1 : npix;
1409 }
1410 
1413  if (ppm) return pixel_size(pal) * 8;
1414  return 0;
1415 }
1416 
1418  const weed_macropixel_t *mpx = get_advanced_palette(pal);
1419  register int i = 0;
1420  if (mpx) {
1421  if (!(mpx->flags & WEED_VCHAN_DESC_PLANAR)) return 1;
1422  for (i = 0; i < MAXPPLANES && mpx->chantype[i]; i++);
1423  }
1424  return i;
1425 }
1426 
1428  const weed_macropixel_t *mpx = get_advanced_palette(pal);
1429  if (mpx && mpx->chantype[0] == WEED_VCHAN_alpha && !mpx->chantype[1]) return TRUE;
1430  return FALSE;
1431 }
1432 
1434  const weed_macropixel_t *mpx = get_advanced_palette(pal);
1435  if (mpx) {
1436  for (register int i = 0; i < MAXPPLANES && mpx->chantype[i]; i++) {
1437  if (mpx->chantype[i] == WEED_VCHAN_red) return TRUE;
1438  if (mpx->chantype[i] == WEED_VCHAN_blue) return FALSE;
1439  }
1440  }
1441  return FALSE;
1442 }
1443 
1444 LIVES_GLOBAL_INLINE boolean weed_palettes_rbswapped(int pal0, int pal1) {
1445  return weed_palette_red_first(pal0) != weed_palette_red_first(pal1);
1446 }
1447 
1449  const weed_macropixel_t *mpx = get_advanced_palette(pal);
1450  if (mpx) {
1451  for (register int i = 0; i < MAXPPLANES && mpx->chantype[i]; i++)
1452  if (is_rgbchan(mpx->chantype[i])) return TRUE;
1453  }
1454  return FALSE;
1455 }
1456 
1458  const weed_macropixel_t *mpx = get_advanced_palette(pal);
1459  if (mpx) {
1460  for (register int i = 0; i < MAXPPLANES && mpx->chantype[i]; i++)
1461  if (is_yuvchan(mpx->chantype[i])) return TRUE;
1462  }
1463  return FALSE;
1464 }
1465 
1467  const weed_macropixel_t *mpx = get_advanced_palette(pal);
1468  if (mpx) {
1469  for (register int i = 0; i < MAXPPLANES && mpx->chantype[i]; i++)
1470  if (mpx->chantype[i] == WEED_VCHAN_alpha) return TRUE;
1471  }
1472  return FALSE;
1473 }
1474 
1476  const weed_macropixel_t *mpx = get_advanced_palette(pal);
1477  return (mpx && (mpx->flags & WEED_VCHAN_DESC_FP));
1478 }
1479 
1481  uint8_t subsam = 0;
1482  const weed_macropixel_t *mpx = get_advanced_palette(pal);
1483  if (mpx) subsam = mpx->hsub[plane];
1484  if (subsam) return 1. / (double)(subsam);
1485  return 1.;
1486 }
1487 
1489  uint8_t subsam = 0;
1490  const weed_macropixel_t *mpx = get_advanced_palette(pal);
1491  if (mpx) subsam = mpx->vsub[plane];
1492  if (subsam) return 1. / (double)(subsam);
1493  return 1.;
1494 }
1495 
1497  const weed_macropixel_t *mpx = get_advanced_palette(pal);
1498  if (mpx) {
1499  for (register int i = 0; i < MAXPPLANES && mpx->chantype[i]; i++)
1500  if (mpx->chantype[i] == WEED_VCHAN_alpha) return i;
1501  }
1502  return -1;
1503 }
1504 
1506  if (weed_palette_is_planar(pal)) return _get_alpha(pal);
1507  return -1;
1508 }
1509 
1511  if (!weed_palette_is_planar(pal)) return _get_alpha(pal);
1512  return -1;
1513 }
1514 
1516  return _get_alpha(pal) == 0;
1517 }
1518 
1520  return _get_alpha(pal) == 3;
1521 }
1522 
1524  // first cpt must be alpha, red, blue, y, u, or v
1525  //
1526  // if first was alpha, 2nd must be NULL, red, blue or y, u, v
1527  // if first was red or blue, 2nd must be green
1528  // if first was y, 2nd must be y, u or v
1529  //
1530  // if second was green, 3rd must be blue or red, but != 1st
1531  // if second was y, u, or v, third must be y, u or v
1532  // if second was red or blue, 3rd must be green
1533  //
1534  // if third was red or blue, fourth may be alpha or NULL
1535  // if third was green, fourth must be red or blue but != 2nd
1536  // if third was y, u, or v, fourth may be y, u, v or alpha
1537  //
1538  // if fourth was red, blue or alpha, fifth must be NULL
1539  // if fourth was y, u, or v, fifth must be y, u, v or alpha
1540  //
1541  // if fifth was alpha, sixth must be NULL
1542  // if fifth was y, u, or v, sixth must be y, u, v or alpha
1543  //
1544  // etc. for 7 and 8
1545 
1546  // there must be some symmetry between u and v, e.g. yyuyyv is allowed but not yyuyv or yuy
1547  // 0, 1, or 2 y before / after a u or v, y numbers must match and u / v numbers too
1548 
1549  // future directions: allow single plane / cpt r, g, b or y
1550  boolean red = FALSE, blue = FALSE, alpha = FALSE;
1551  int nseqy = 0, nseqyu = 0, nseqyv = 0, nu = 0, nv = 0;
1552  const weed_macropixel_t *mpx = get_advanced_palette(pal);
1553  if (!mpx) return FALSE;
1554  for (register int i = 0; i < MAXPPLANES && mpx->chantype[i]; i++) {
1555  uint16_t ctype = mpx->chantype[i];
1556  if (i > 3 && alpha) return FALSE;
1557  switch (ctype) {
1558  case WEED_VCHAN_Y:
1559  if (red || blue) return FALSE;
1560  if (++nseqy > 2) return FALSE;
1561  break;
1562  case WEED_VCHAN_U:
1563  if (red || blue) return FALSE;
1564  if (nseqyv && nseqy && nseqy != nseqyv) return FALSE;
1565  nu++;
1566  nseqyu = nseqy;
1567  nseqy = nseqyv = 0;
1568  break;
1569  case WEED_VCHAN_V:
1570  if (red || blue) return FALSE;
1571  if (nseqyu && nseqy && nseqy != nseqyu) return FALSE;
1572  nv++;
1573  nseqyv = nseqy;
1574  nseqy = nseqyu = 0;
1575  break;
1576  default:
1577  switch (i) {
1578  case 0:
1579  switch (ctype) {
1580  case WEED_VCHAN_alpha: alpha = TRUE; break;
1581  case WEED_VCHAN_red: red = TRUE; break;
1582  case WEED_VCHAN_blue: blue = TRUE; break;
1583  default: return FALSE;
1584  }
1585  break;
1586  case 1:
1587  if (nu || nv || nseqy) return FALSE;
1588  switch (ctype) {
1589  case WEED_VCHAN_alpha: return FALSE;
1590  case WEED_VCHAN_green:
1591  if (!red && !blue) return FALSE;
1592  break;
1593  case WEED_VCHAN_red:
1594  if (!alpha) return FALSE;
1595  red = TRUE;
1596  break;
1597  case WEED_VCHAN_blue:
1598  if (!alpha) return FALSE;
1599  blue = TRUE;
1600  break;
1601  default: return FALSE;
1602  }
1603  break;
1604  case 2:
1605  if (nu || nv || nseqy) return FALSE;
1606  switch (ctype) {
1607  case WEED_VCHAN_alpha: return FALSE;
1608  case WEED_VCHAN_green:
1609  if (!red && !blue) return FALSE;
1610  break;
1611  case WEED_VCHAN_red:
1612  if (!blue) return FALSE;
1613  red = TRUE;
1614  break;
1615  case WEED_VCHAN_blue:
1616  if (!red) return FALSE;
1617  blue = TRUE;
1618  break;
1619  default: return FALSE;
1620  }
1621  break;
1622  case 3:
1623  switch (ctype) {
1624  case WEED_VCHAN_alpha:
1625  if (alpha) return FALSE;
1626  alpha = TRUE;
1627  break;
1628  case WEED_VCHAN_red:
1629  if (!blue) return FALSE;
1630  red = TRUE;
1631  break;
1632  case WEED_VCHAN_blue:
1633  if (!red) return FALSE;
1634  blue = TRUE;
1635  break;
1636  default: return FALSE;
1637  }
1638  break;
1639  default:
1640  if (ctype != WEED_VCHAN_alpha) return FALSE;
1641  alpha = TRUE;
1642  break;
1643  }
1644  break;
1645  }
1646  }
1647  if (red != blue || nv != nu || (nseqy != nseqyu && nseqy != nseqyv)) return FALSE;
1648  return TRUE;
1649 }
1650 #endif
1651 
1652 
1653 static void init_gamma_tx(void) {
1654  gamma_tx[WEED_GAMMA_SRGB] = (gamma_const_t) {0.055, 12.92, 0.04045, 2.4};
1655  gamma_tx[WEED_GAMMA_BT709] = (gamma_const_t) {0.099, 4.5, 0.081, 1. / .45};
1656 }
1657 
1658 static void rgb2yuv(uint8_t r0, uint8_t g0, uint8_t b0, uint8_t *y, uint8_t *u, uint8_t *v) GNU_HOT;
1659 static void yuv2rgb(uint8_t y, uint8_t u, uint8_t v, uint8_t *r, uint8_t *g, uint8_t *b) GNU_HOT;
1660 
1662  init_RGB_to_YUV_tables();
1663  init_YUV_to_RGB_tables();
1664  init_YUV_to_YUV_tables();
1665  init_average();
1666  init_unal();
1667  init_gamma_tx();
1669 #ifdef WEED_ADVANCED_PALETTES
1671 #endif
1672  //#define TEST_CONV
1673 #ifdef TEST_CONV
1674  if (1) {
1675  int cr, cg, cb;
1676  uint8_t r = 100, g, b, y, u, v, xr, xg, xb;;
1677  set_conversion_arrays(WEED_YUV_CLAMPING_UNCLAMPED, WEED_YUV_SUBSPACE_YCBCR);
1678  //prefs->pb_quality = PB_QUALITY_MED;
1679  for (cr = 100; cr < 256; cr++) {
1680  g = 0;
1681  for (cg = 0; cg < 256; cg++) {
1682  b = 0;
1683  for (cb = 0; cb < 256; cb++) {
1684  g_print("in: %d %d %d\n", r, g, b);
1685  rgb2yuv(r, g, b, &y, &u, &v);
1686  yuv2rgb(y, u, v, &xr, &xg, &xb);
1687  g_print("out: %d %d %d %d %d %d\n", y, u, v, xr, xg, xb);
1688  b++;
1689  }
1690  g++;
1691  }
1692  r++;
1693  }
1694  }
1695 #endif
1696 }
1697 
1698 // internal thread fns
1699 static void *convert_rgb_to_uyvy_frame_thread(void *cc_params);
1700 static void *convert_bgr_to_uyvy_frame_thread(void *cc_params);
1701 static void *convert_rgb_to_yuyv_frame_thread(void *cc_params);
1702 static void *convert_bgr_to_yuyv_frame_thread(void *cc_params);
1703 static void *convert_argb_to_uyvy_frame_thread(void *cc_params);
1704 static void *convert_argb_to_yuyv_frame_thread(void *cc_params);
1705 
1706 static void *convert_rgb_to_yuv_frame_thread(void *cc_params);
1707 static void *convert_bgr_to_yuv_frame_thread(void *cc_params);
1708 static void *convert_argb_to_yuv_frame_thread(void *cc_params);
1709 static void *convert_rgb_to_yuvp_frame_thread(void *cc_params);
1710 static void *convert_bgr_to_yuvp_frame_thread(void *cc_params);
1711 static void *convert_argb_to_yuvp_frame_thread(void *cc_params);
1712 
1713 static void *convert_uyvy_to_rgb_frame_thread(void *cc_params);
1714 static void *convert_uyvy_to_bgr_frame_thread(void *cc_params);
1715 static void *convert_uyvy_to_argb_frame_thread(void *cc_params);
1716 static void *convert_yuyv_to_rgb_frame_thread(void *cc_params);
1717 static void *convert_yuyv_to_bgr_frame_thread(void *cc_params);
1718 static void *convert_yuyv_to_argb_frame_thread(void *cc_params);
1719 
1720 static void *convert_yuv_planar_to_rgb_frame_thread(void *cc_params);
1721 static void *convert_yuv_planar_to_bgr_frame_thread(void *cc_params);
1722 static void *convert_yuv_planar_to_argb_frame_thread(void *cc_params);
1723 
1724 static void *convert_yuv420p_to_rgb_frame_thread(void *cc_params);
1725 static void *convert_yuv420p_to_bgr_frame_thread(void *cc_params);
1726 static void *convert_yuv420p_to_argb_frame_thread(void *cc_params);
1727 
1728 static void *convert_yuv888_to_rgb_frame_thread(void *cc_params);
1729 static void *convert_yuv888_to_bgr_frame_thread(void *cc_params);
1730 static void *convert_yuv888_to_argb_frame_thread(void *cc_params);
1731 static void *convert_yuva8888_to_rgba_frame_thread(void *cc_params);
1732 static void *convert_yuva8888_to_bgra_frame_thread(void *cc_params);
1733 static void *convert_yuva8888_to_argb_frame_thread(void *cc_params);
1734 
1735 static void *convert_swap3_frame_thread(void *cc_params);
1736 static void *convert_swap4_frame_thread(void *cc_params);
1737 static void *convert_swap3addpost_frame_thread(void *cc_params);
1738 static void *convert_swap3addpre_frame_thread(void *cc_params);
1739 static void *convert_swap3delpost_frame_thread(void *cc_params);
1740 static void *convert_swap3delpre_frame_thread(void *cc_params);
1741 static void *convert_addpre_frame_thread(void *cc_params);
1742 static void *convert_addpost_frame_thread(void *cc_params);
1743 static void *convert_delpre_frame_thread(void *cc_params);
1744 static void *convert_delpost_frame_thread(void *cc_params);
1745 static void *convert_swap3postalpha_frame_thread(void *cc_params);
1746 #ifdef WEED_ADVANCED_PALETTES
1747 static void *convert_swap3prealpha_frame_thread(void *cc_params);
1748 #endif
1749 static void *convert_swapprepost_frame_thread(void *cc_params);
1750 
1751 static void *convert_swab_frame_thread(void *cc_params);
1752 
1753 #if 0
1754 static void rgb2yuv_with_gamma(uint8_t r0, uint8_t g0, uint8_t b0, uint8_t *y, uint8_t *u, uint8_t *v, uint8_t *lut) GNU_HOT;
1755 #endif
1756 static void rgb2uyvy(uint8_t r0, uint8_t g0, uint8_t b0, uint8_t r1, uint8_t g1, uint8_t b1,
1758 static void rgb2uyvy_with_gamma(uint8_t r0, uint8_t g0, uint8_t b0, uint8_t r1, uint8_t g1, uint8_t b1,
1759  uyvy_macropixel *uyvy, uint8_t *lut) GNU_FLATTEN GNU_HOT;
1760 static void rgb16_2uyvy(uint16_t r0, uint16_t g0, uint16_t b0, uint16_t r1, uint16_t g1, uint16_t b1,
1762 #if 0
1763 static void rgb16_2uyvy_with_gamma(uint16_t r0, uint16_t g0, uint16_t b0, uint16_t r1, uint16_t g1, uint16_t b1,
1764  uyvy_macropixel *uyvy, uint8_t *lut) GNU_FLATTEN GNU_HOT;
1765 #endif
1766 
1767 static void rgb2yuyv(uint8_t r0, uint8_t g0, uint8_t b0, uint8_t r1, uint8_t g1, uint8_t b1,
1769 #if 0
1770 static void rgb2yuyv_with_gamma(uint8_t r0, uint8_t g0, uint8_t b0, uint8_t r1, uint8_t g1, uint8_t b1,
1771  yuyv_macropixel *yuyv, uint8_t *lut) GNU_FLATTEN GNU_HOT;
1772 #endif
1773 static void rgb2_411(uint8_t r0, uint8_t g0, uint8_t b0, uint8_t r1, uint8_t g1, uint8_t b1,
1774  uint8_t r2, uint8_t g2, uint8_t b2, uint8_t r3, uint8_t g3, uint8_t b3, yuv411_macropixel *yuv) GNU_HOT;
1775 
1776 static void yuv2rgb_with_gamma(uint8_t y, uint8_t u, uint8_t v, uint8_t *r, uint8_t *g, uint8_t *b, uint8_t *lut) GNU_HOT;
1777 static void uyvy2rgb(uyvy_macropixel *uyvy, uint8_t *r0, uint8_t *g0, uint8_t *b0,
1778  uint8_t *r1, uint8_t *g1, uint8_t *b1) GNU_FLATTEN GNU_HOT;
1779 static void yuyv2rgb(yuyv_macropixel *yuyv, uint8_t *r0, uint8_t *g0, uint8_t *b0,
1780  uint8_t *r1, uint8_t *g1, uint8_t *b1) GNU_FLATTEN GNU_HOT;
1781 static void yuv888_2_rgb(uint8_t *yuv, uint8_t *rgb, boolean add_alpha) GNU_FLATTEN GNU_HOT;
1782 static void yuva8888_2_rgba(uint8_t *yuva, uint8_t *rgba, boolean del_alpha) GNU_FLATTEN GNU_HOT;
1783 static void yuv888_2_bgr(uint8_t *yuv, uint8_t *bgr, boolean add_alpha) GNU_FLATTEN GNU_HOT;
1784 static void yuva8888_2_bgra(uint8_t *yuva, uint8_t *bgra, boolean del_alpha) GNU_FLATTEN GNU_HOT;
1785 static void yuv888_2_argb(uint8_t *yuv, uint8_t *argb) GNU_FLATTEN GNU_HOT;
1786 static void yuva8888_2_argb(uint8_t *yuva, uint8_t *argb) GNU_FLATTEN GNU_HOT;
1787 static void uyvy_2_yuv422(uyvy_macropixel *uyvy, uint8_t *y0, uint8_t *u0, uint8_t *v0, uint8_t *y1) GNU_HOT;
1788 static void yuyv_2_yuv422(yuyv_macropixel *yuyv, uint8_t *y0, uint8_t *u0, uint8_t *v0, uint8_t *y1) GNU_HOT;
1789 
1790 #define avg_chroma(x, y) ((uint8_t)(*(cavg + ((int)(x) << 8) + (int)(y))))
1791 #define avg_chroma_3_1(x, y) ((uint8_t)(avg_chroma(x, avg_chroma(x, y))))
1792 #define avg_chroma_1_3(x, y) ((uint8_t)(avg_chroma(avg_chroma(x, y), y)))
1793 
1794 static uint8_t (*avg_chromaf)(uint8_t x, uint8_t y);
1795 
1796 /* static uint8_t avg_chromaf_high(uint8_t x, uint8_t y) { */
1797 /* return (((float)(spc_rnd(((x) << 8) + ((y) << 8)))) * 128. + .5); */
1798 /* } */
1799 
1800 static uint8_t avg_chromaf_fast(uint8_t x, uint8_t y) {
1801  return avg_chroma(x, y);
1802 }
1803 
1805  avg_chromaf = avg_chromaf_fast;
1806  if (intent == LIVES_INTENTION_RENDER || intent == LIVES_INTENTION_TRANSCODE) {
1807  //avg_chromaf = avg_chromaf_high;
1810  // this ensures we render at the highest settings
1812  } else {
1814  }
1815 }
1816 
1817 #define avg_chroma_3_1f(x, y) ((uint8_t)(avg_chromaf(x, avg_chromaf(x, y))))
1818 #define avg_chroma_1_3f(x, y) ((uint8_t)(avg_chromaf(avg_chromaf(x, y), y)))
1819 
1820 LIVES_INLINE void rgb2yuv(uint8_t r0, uint8_t g0, uint8_t b0, uint8_t *y, uint8_t *u, uint8_t *v) {
1821  short a;
1822  if ((a = spc_rnd(Y_R[r0] + Y_G[g0] + Y_B[b0])) > max_Y) * y = max_Y;
1823  else *y = a < min_Y ? min_Y : a;
1824  if ((a = spc_rnd(Cb_R[r0] + Cb_G[g0] + Cb_B[b0])) > max_UV) * u = max_UV;
1825  else *u = a < min_UV ? min_UV : a;
1826  if ((a = spc_rnd(Cr_R[r0] + Cr_G[g0] + Cr_B[b0])) > max_UV) * v = max_UV;
1827  else *v = a < min_UV ? min_UV : a;
1828 }
1829 
1830 #define bgr2yuv(b0, g0, r0, y, u, v) rgb2yuv(r0, g0, b0, y, u, v)
1831 
1832 
1833 LIVES_INLINE void rgb2yuv_with_gamma(uint8_t r0, uint8_t g0, uint8_t b0, uint8_t *y, uint8_t *u, uint8_t *v, uint8_t *lut) {
1834  short a;
1835  if ((a = spc_rnd(Y_R[(r0 = lut[r0])] + Y_G[(g0 = lut[g0])] + Y_B[(b0 = lut[b0])])) > max_Y) * y = max_Y;
1836  else *y = a < min_Y ? min_Y : a;
1837  if ((a = spc_rnd(Cb_R[r0] + Cb_G[g0] + Cb_B[b0])) > max_UV) * u = max_UV;
1838  else *u = a < min_UV ? min_UV : a;
1839  if ((a = spc_rnd(Cr_R[r0] + Cr_G[g0] + Cr_B[b0])) > max_UV) * v = max_UV;
1840  else *v = a < min_UV ? min_UV : a;
1841 }
1842 
1843 
1844 #define bgr2yuv_with_gamma(b0, g0, r0, y, u, v) rgb2yuv(r0, g0, b0, y, u, v, lut)
1845 
1846 LIVES_INLINE void rgb2uyvy(uint8_t r0, uint8_t g0, uint8_t b0, uint8_t r1, uint8_t g1, uint8_t b1, uyvy_macropixel *uyvy) {
1847  short a;
1848  if ((a = spc_rnd(Cb_R[r0] + Cb_G[g0] + Cb_B[b0])) > max_UV) uyvy->u0 = max_UV;
1849  else uyvy->u0 = a < min_UV ? min_UV : a;
1850 
1851  if ((a = spc_rnd(Y_R[r0] + Y_G[g0] + Y_B[b0])) > max_Y) uyvy->y0 = max_Y;
1852  else uyvy->y0 = a < min_Y ? min_Y : a;
1853 
1854  if ((a = spc_rnd(Cr_R[r1] + Cr_G[g1] + Cr_B[b1])) > max_UV) uyvy->v0 = max_UV;
1855  else uyvy->v0 = a < min_UV ? min_UV : a;
1856 
1857  if ((a = spc_rnd(Y_R[r1] + Y_G[g1] + Y_B[b1])) > max_Y) uyvy->y1 = max_Y;
1858  else uyvy->y1 = a < min_Y ? min_Y : a;
1859 }
1860 
1861 LIVES_INLINE void rgb2uyvy_with_gamma(uint8_t r0, uint8_t g0, uint8_t b0, uint8_t r1, uint8_t g1, uint8_t b1,
1862  uyvy_macropixel *uyvy, uint8_t *lut) {
1863  short a;
1864  if ((a = spc_rnd(Cb_R[(r0 = lut[r0])] + Cb_G[(g0 = lut[g0])] + Cb_B[(b0 = lut[b0])])) > max_UV) uyvy->u0 = max_UV;
1865  else uyvy->u0 = a < min_UV ? min_UV : a;
1866 
1867  if ((a = spc_rnd(Y_R[r0] + Y_G[g0] + Y_B[b0])) > max_Y) uyvy->y0 = max_Y;
1868  else uyvy->y0 = a < min_Y ? min_Y : a;
1869 
1870  if ((a = spc_rnd(Cr_R[(r1 = lut[r1])] + Cr_G[(g1 = lut[g1])] + Cr_B[(b1 = lut[b1])])) > max_UV) uyvy->v0 = max_UV;
1871  else uyvy->v0 = a < min_UV ? min_UV : a;
1872 
1873  if ((a = spc_rnd(Y_R[r1] + Y_G[g1] + Y_B[b1])) > max_Y) uyvy->y1 = max_Y;
1874  else uyvy->y1 = a < min_Y ? min_Y : a;
1875 }
1876 
1877 LIVES_INLINE void rgb2yuyv(uint8_t r0, uint8_t g0, uint8_t b0, uint8_t r1, uint8_t g1, uint8_t b1, yuyv_macropixel *yuyv) {
1878  short a;
1879  if ((a = spc_rnd(Y_R[r0] + Y_G[g0] + Y_B[b0])) > max_Y) yuyv->y0 = max_Y;
1880  else yuyv->y0 = a < min_Y ? min_Y : a;
1881 
1882  if ((a = spc_rnd(Cb_R[r0] + Cb_G[g0] + Cb_B[b0])) > max_UV) yuyv->u0 = max_UV;
1883  yuyv->u0 = a < min_UV ? min_UV : a;
1884 
1885  if ((a = spc_rnd(Y_R[r1] + Y_G[g1] + Y_B[b1])) > max_Y) yuyv->y1 = max_Y;
1886  else yuyv->y1 = a < min_Y ? min_Y : a;
1887 
1888  if ((a = spc_rnd(Cr_R[r1] + Cr_G[g1] + Cr_B[b1])) > max_UV) yuyv->v0 = max_UV;
1889  yuyv->v0 = a < min_UV ? min_UV : a;
1890 }
1891 
1892 
1893 LIVES_INLINE void rgb2yuyv_with_gamma(uint8_t r0, uint8_t g0, uint8_t b0, uint8_t r1, uint8_t g1, uint8_t b1,
1894  yuyv_macropixel *yuyv, uint8_t *lut) {
1895  short a;
1896  if ((a = spc_rnd(Y_R[(r0 = lut[r0])] + Y_G[(g0 = lut[g0])] + Y_B[(b0 = lut[b0])])) > max_Y) yuyv->y0 = max_Y;
1897  else yuyv->y0 = a < min_Y ? min_Y : a;
1898 
1899  if ((a = spc_rnd(Cb_R[r0] + Cb_G[g0] + Cb_B[b0])) > max_UV) yuyv->u0 = max_UV;
1900  else yuyv->u0 = a < min_UV ? min_UV : a;
1901 
1902  if ((a = spc_rnd(Y_R[(r1 = lut[r1])] + Y_G[(g1 = lut[g1])] + Y_B[(b1 = lut[b1])])) > max_Y) yuyv->y1 = max_Y;
1903  else yuyv->y1 = a < min_Y ? min_Y : a;
1904 
1905  if ((a = spc_rnd(Cr_R[r1] + Cr_G[g1] + Cr_B[b1])) > max_UV) yuyv->v0 = max_UV;
1906  else yuyv->v0 = a < min_UV ? min_UV : a;
1907 }
1908 
1909 
1910 LIVES_INLINE void rgb16_2uyvy(uint16_t r0, uint16_t g0, uint16_t b0, uint16_t r1, uint16_t g1, uint16_t b1,
1911  uyvy_macropixel *uyvy) {
1912  register short a;
1913  uint8_t rfrac0, gfrac0, bfrac0, rfrac1, gfrac1, bfrac1;
1914  uint8_t rr0, bb0, gg0, rr1, gg1, bb1;
1915  uint8_t *bytes;
1916 
1917  bytes = (uint8_t *)&r0;
1918  rfrac0 = bytes[1];
1919  bytes = (uint8_t *)&g0;
1920  gfrac0 = bytes[1];
1921  bytes = (uint8_t *)&b0;
1922  bfrac0 = bytes[1];
1923  bytes = (uint8_t *)&r1;
1924  rfrac1 = bytes[1];
1925  bytes = (uint8_t *)&g1;
1926  gfrac1 = bytes[1];
1927  bytes = (uint8_t *)&b1;
1928  bfrac1 = bytes[1];
1929 
1930  rr0 = (r0 & 0xFF) == 0xFF ? Y_R[255] : (Y_R[r0 & 0xFF] * rfrac0 + Y_R[(r0 & 0xFF) + 1] * (255 - rfrac0)) >> 8;
1931  gg0 = (g0 & 0xFF) == 0xFF ? Y_G[255] : (Y_G[g0 & 0xFF] * gfrac0 + Y_G[(g0 & 0xFF) + 1] * (255 - gfrac0)) >> 8;
1932  bb0 = (b0 & 0xFF) == 0xFF ? Y_B[255] : (Y_B[b0 & 0xFF] * bfrac0 + Y_B[(b0 & 0xFF) + 1] * (255 - bfrac0)) >> 8;
1933 
1934  if ((a = spc_rnd(rr0 + gg0 + bb0)) > max_Y) uyvy->y0 = max_Y;
1935  else uyvy->y0 = a < min_Y ? min_Y : a;
1936 
1937  rr1 = (r1 & 0xFF) == 0xFF ? Y_R[255] : (Y_R[r1 & 0xFF] * rfrac1 + Y_R[(r1 & 0xFF) + 1] * (255 - rfrac1)) >> 8;
1938  gg1 = (g1 & 0xFF) == 0xFF ? Y_G[255] : (Y_G[g1 & 0xFF] * gfrac1 + Y_G[(g1 & 0xFF) + 1] * (255 - gfrac1)) >> 8;
1939  bb1 = (b1 & 0xFF) == 0xFF ? Y_B[255] : (Y_B[b1 & 0xFF] * bfrac1 + Y_B[(b1 & 0xFF) + 1] * (255 - bfrac1)) >> 8;
1940 
1941  if ((a = spc_rnd(rr0 + gg0 + bb0)) > max_Y) uyvy->y1 = max_Y;
1942  else uyvy->y1 = a < min_Y ? min_Y : a;
1943 
1944  rr0 = (r0 & 0xFF) == 0xFF ? Cb_R[255] : (Cb_R[r0 & 0xFF] * rfrac0 + Cb_R[(r0 & 0xFF) + 1] * (255 - rfrac0)) >> 8;
1945  gg0 = (g0 & 0xFF) == 0xFF ? Cb_G[255] : (Cb_G[g0 & 0xFF] * gfrac0 + Cb_G[(g0 & 0xFF) + 1] * (255 - gfrac0)) >> 8;
1946  bb0 = (b0 & 0xFF) == 0xFF ? Cb_B[255] : (Cb_B[b0 & 0xFF] * bfrac0 + Cb_B[(b0 & 0xFF) + 1] * (255 - bfrac0)) >> 8;
1947 
1948  rr1 = (r1 & 0xFF) == 0xFF ? Cb_R[255] : (Cb_R[r1 & 0xFF] * rfrac1 + Cb_R[(r1 & 0xFF) + 1] * (255 - rfrac1)) >> 8;
1949  gg1 = (g1 & 0xFF) == 0xFF ? Cb_G[255] : (Cb_G[g1 & 0xFF] * gfrac1 + Cb_G[(g1 & 0xFF) + 1] * (255 - gfrac1)) >> 8;
1950  bb1 = (b1 & 0xFF) == 0xFF ? Cb_B[255] : (Cb_B[b1 & 0xFF] * bfrac1 + Cb_B[(b1 & 0xFF) + 1] * (255 - bfrac1)) >> 8;
1951 
1952  uyvy->u0 = avg_chroma_3_1f(rr0 + gg0 + bb0, rr1 + gg1 + bb1);
1953 
1954  rr0 = (r0 & 0xFF) == 0xFF ? Cr_R[255] : (Cr_R[r0 & 0xFF] * rfrac0 + Cr_R[(r0 & 0xFF) + 1] * (255 - rfrac0)) >> 8;
1955  gg0 = (g0 & 0xFF) == 0xFF ? Cr_G[255] : (Cr_G[g0 & 0xFF] * gfrac0 + Cr_G[(g0 & 0xFF) + 1] * (255 - gfrac0)) >> 8;
1956  bb0 = (b0 & 0xFF) == 0xFF ? Cr_B[255] : (Cr_B[b0 & 0xFF] * bfrac0 + Cr_B[(b0 & 0xFF) + 1] * (255 - bfrac0)) >> 8;
1957 
1958  rr1 = (r1 & 0xFF) == 0xFF ? Cr_R[255] : (Cr_R[r1 & 0xFF] * rfrac1 + Cr_R[(r1 & 0xFF) + 1] * (255 - rfrac1)) >> 8;
1959  gg1 = (g1 & 0xFF) == 0xFF ? Cr_G[255] : (Cr_G[g1 & 0xFF] * gfrac1 + Cr_G[(g1 & 0xFF) + 1] * (255 - gfrac1)) >> 8;
1960  bb1 = (b1 & 0xFF) == 0xFF ? Cr_B[255] : (Cr_B[b1 & 0xFF] * bfrac1 + Cr_B[(b1 & 0xFF) + 1] * (255 - bfrac1)) >> 8;
1961 
1962  uyvy->v0 = avg_chroma_1_3f(rr0 + gg0 + bb0, rr1 + gg1 + bb1);
1963 }
1964 
1965 #if 0
1966 LIVES_INLINE void rgb16_2uyvy_with_gamma(uint16_t r0, uint16_t g0, uint16_t b0, uint16_t r1, uint16_t g1, uint16_t b1,
1967  uyvy_macropixel *uyvy, uint8_t *lut) {
1968  register short a;
1969  uint8_t rfrac0, gfrac0, bfrac0, rfrac1, gfrac1, bfrac1;
1970  uint8_t rr0, bb0, gg0, rr1, gg1, bb1;
1971  uint8_t *bytes;
1972 
1973  bytes = (uint8_t *)&r0;
1974  rfrac0 = bytes[1];
1975  bytes = (uint8_t *)&g0;
1976  gfrac0 = bytes[1];
1977  bytes = (uint8_t *)&b0;
1978  bfrac0 = bytes[1];
1979  bytes = (uint8_t *)&r1;
1980  rfrac1 = bytes[1];
1981  bytes = (uint8_t *)&g1;
1982  gfrac1 = bytes[1];
1983  bytes = (uint8_t *)&b1;
1984  bfrac1 = bytes[1];
1985 
1986  rr0 = lut[(r0 & 0xFF) == 0xFF ? Y_R[255] : (Y_R[r0 & 0xFF] * rfrac0 + Y_R[(r0 & 0xFF) + 1] * (255 - rfrac0)) >> 8];
1987  gg0 = lut[(g0 & 0xFF) == 0xFF ? Y_G[255] : (Y_G[g0 & 0xFF] * gfrac0 + Y_G[(g0 & 0xFF) + 1] * (255 - gfrac0)) >> 8];
1988  bb0 = lut[(b0 & 0xFF) == 0xFF ? Y_B[255] : (Y_B[b0 & 0xFF] * bfrac0 + Y_B[(b0 & 0xFF) + 1] * (255 - bfrac0)) >> 8];
1989 
1990  if ((a = spc_rnd(rr0 + gg0 + bb0)) > max_Y) uyvy->y0 = max_Y;
1991  else uyvy->y0 = a < min_Y ? min_Y : a;
1992 
1993  rr1 = lut[(r1 & 0xFF) == 0xFF ? Y_R[255] : (Y_R[r1 & 0xFF] * rfrac1 + Y_R[(r1 & 0xFF) + 1] * (255 - rfrac1)) >> 8];
1994  gg1 = lut[(g1 & 0xFF) == 0xFF ? Y_G[255] : (Y_G[g1 & 0xFF] * gfrac1 + Y_G[(g1 & 0xFF) + 1] * (255 - gfrac1)) >> 8];
1995  bb1 = lut[(b1 & 0xFF) == 0xFF ? Y_B[255] : (Y_B[b1 & 0xFF] * bfrac1 + Y_B[(b1 & 0xFF) + 1] * (255 - bfrac1)) >> 8];
1996 
1997  if ((a = spc_rnd(rr1 + gg1 + bb1)) > max_Y) uyvy->y1 = max_Y;
1998  else uyvy->y1 = a < min_Y ? min_Y : a;
1999 
2000  rr0 = lut[(r0 & 0xFF) == 0xFF ? Cb_R[255] : (Cb_R[r0 & 0xFF] * rfrac0 + Cb_R[(r0 & 0xFF) + 1] * (255 - rfrac0)) >> 8];
2001  gg0 = lut[(g0 & 0xFF) == 0xFF ? Cb_G[255] : (Cb_G[g0 & 0xFF] * gfrac0 + Cb_G[(g0 & 0xFF) + 1] * (255 - gfrac0)) >> 8];
2002  bb0 = lut[(b0 & 0xFF) == 0xFF ? Cb_B[255] : (Cb_B[b0 & 0xFF] * bfrac0 + Cb_B[(b0 & 0xFF) + 1] * (255 - bfrac0)) >> 8];
2003 
2004  rr1 = lut[(r1 & 0xFF) == 0xFF ? Cb_R[255] : (Cb_R[r1 & 0xFF] * rfrac1 + Cb_R[(r1 & 0xFF) + 1] * (255 - rfrac1)) >> 8];
2005  gg1 = lut[(g1 & 0xFF) == 0xFF ? Cb_G[255] : (Cb_G[g1 & 0xFF] * gfrac1 + Cb_G[(g1 & 0xFF) + 1] * (255 - gfrac1)) >> 8];
2006  bb1 = lut[(b1 & 0xFF) == 0xFF ? Cb_B[255] : (Cb_B[b1 & 0xFF] * bfrac1 + Cb_B[(b1 & 0xFF) + 1] * (255 - bfrac1)) >> 8];
2007 
2008  uyvy->u0 = avg_chroma_3_1f(rr0 + gg0 + bb0, rr1 + gg1 + bb1);
2009 
2010  rr0 = lut[(r0 & 0xFF) == 0xFF ? Cr_R[255] : (Cr_R[r0 & 0xFF] * rfrac0 + Cr_R[(r0 & 0xFF) + 1] * (255 - rfrac0)) >> 8];
2011  gg0 = lut[(g0 & 0xFF) == 0xFF ? Cr_G[255] : (Cr_G[g0 & 0xFF] * gfrac0 + Cr_G[(g0 & 0xFF) + 1] * (255 - gfrac0)) >> 8];
2012  bb0 = lut[(b0 & 0xFF) == 0xFF ? Cr_B[255] : (Cr_B[b0 & 0xFF] * bfrac0 + Cr_B[(b0 & 0xFF) + 1] * (255 - bfrac0)) >> 8];
2013 
2014  rr1 = lut[(r1 & 0xFF) == 0xFF ? Cr_R[255] : (Cr_R[r1 & 0xFF] * rfrac1 + Cr_R[(r1 & 0xFF) + 1] * (255 - rfrac1)) >> 8];
2015  gg1 = lut[(g1 & 0xFF) == 0xFF ? Cr_G[255] : (Cr_G[g1 & 0xFF] * gfrac1 + Cr_G[(g1 & 0xFF) + 1] * (255 - gfrac1)) >> 8];
2016  bb1 = lut[(b1 & 0xFF) == 0xFF ? Cr_B[255] : (Cr_B[b1 & 0xFF] * bfrac1 + Cr_B[(b1 & 0xFF) + 1] * (255 - bfrac1)) >> 8];
2017 
2018  uyvy->v0 = avg_chroma_1_3f(rr0 + gg0 + bb0, rr1 + gg1 + bb1);
2019 }
2020 #endif
2021 
2022 LIVES_INLINE void rgb2_411(uint8_t r0, uint8_t g0, uint8_t b0, uint8_t r1, uint8_t g1, uint8_t b1,
2023  uint8_t r2, uint8_t g2, uint8_t b2, uint8_t r3, uint8_t g3, uint8_t b3, yuv411_macropixel *yuv) {
2024  register int a;
2025  if ((a = ((Y_R[r0] + Y_G[g0] + Y_B[b0]) >> FP_BITS)) > max_Y) yuv->y0 = max_Y;
2026  else yuv->y0 = a < min_Y ? min_Y : a;
2027  if ((a = ((Y_R[r1] + Y_G[g1] + Y_B[b1]) >> FP_BITS)) > max_Y) yuv->y1 = max_Y;
2028  else yuv->y1 = a < min_Y ? min_Y : a;
2029  if ((a = ((Y_R[r2] + Y_G[g2] + Y_B[b2]) >> FP_BITS)) > max_Y) yuv->y2 = max_Y;
2030  else yuv->y2 = a < min_Y ? min_Y : a;
2031  if ((a = ((Y_R[r3] + Y_G[g3] + Y_B[b3]) >> FP_BITS)) > max_Y) yuv->y3 = max_Y;
2032  else yuv->y3 = a < min_Y ? min_Y : a;
2033 
2034  if ((a = ((((Cr_R[r0] + Cr_G[g0] + Cr_B[b0]) >> FP_BITS) + ((Cr_R[r1] + Cr_G[g1] + Cr_B[b1]) >> FP_BITS) +
2035  ((Cr_R[r2] + Cr_G[g2] + Cr_B[b2]) >> FP_BITS) + ((Cr_R[r3] + Cr_G[g3] + Cr_B[b3]) >> FP_BITS)) >> 2)) > max_UV)
2036  yuv->v2 = max_UV;
2037  else yuv->v2 = a < min_UV ? min_UV : a;
2038  if ((a = ((((Cb_R[r0] + Cb_G[g0] + Cb_B[b0]) >> FP_BITS) + ((Cb_R[r1] + Cb_G[g1] + Cb_B[b1]) >> FP_BITS) +
2039  ((Cb_R[r2] + Cb_G[g2] + Cb_B[b2]) >> FP_BITS) + ((Cb_R[r3] + Cb_G[g3] + Cb_B[b3]) >> FP_BITS)) >> 2)) > max_UV)
2040  yuv->u2 = max_UV;
2041  else yuv->u2 = a < min_UV ? min_UV : a;
2042 }
2043 
2044 LIVES_INLINE void yuv2rgb(uint8_t y, uint8_t u, uint8_t v, uint8_t *r, uint8_t *g, uint8_t *b) {
2045  *r = CLAMP0255f(spc_rnd(RGB_Y[y] + R_Cr[v]));
2046  *g = CLAMP0255f(spc_rnd(RGB_Y[y] + G_Cb[u] + G_Cr[v]));
2047  *b = CLAMP0255f(spc_rnd(RGB_Y[y] + B_Cb[u]));
2048 }
2049 
2050 #define yuv2bgr(y, u, v, b, g, r) yuv2rgb(y, u, v, r, g, b)
2051 
2052 LIVES_INLINE void yuv2rgb_with_gamma(uint8_t y, uint8_t u, uint8_t v, uint8_t *r, uint8_t *g, uint8_t *b, uint8_t *lut) {
2053  *r = lut[(int)CLAMP0255f(spc_rnd(RGB_Y[y] + R_Cr[v]))];
2054  *g = lut[(int)CLAMP0255f(spc_rnd(RGB_Y[y] + G_Cb[u] + G_Cr[v]))];
2055  *b = lut[(int)CLAMP0255f(spc_rnd(RGB_Y[y] + B_Cb[u]))];
2056 }
2057 
2058 #define yuv2bgr_with_gamma(y, u, v, b, g, r, lut) yuv2rgb_with_gamma(y, u, v, r, g, b, lut)
2059 
2060 LIVES_INLINE void uyvy2rgb(uyvy_macropixel *uyvy, uint8_t *r0, uint8_t *g0, uint8_t *b0,
2061  uint8_t *r1, uint8_t *g1, uint8_t *b1) {
2062  yuv2rgb(uyvy->y0, uyvy->u0, uyvy->v0, r0, g0, b0);
2063  yuv2rgb(uyvy->y1, uyvy->u0, uyvy->v0, r1, g1, b1);
2064  //if (uyvy->y0>240||uyvy->u0>240||uyvy->v0>240||uyvy->y1>240) lives_printerr("got unclamped !\n");
2065 }
2066 
2067 
2068 LIVES_INLINE void yuyv2rgb(yuyv_macropixel *yuyv, uint8_t *r0, uint8_t *g0, uint8_t *b0,
2069  uint8_t *r1, uint8_t *g1, uint8_t *b1) {
2070  yuv2rgb(yuyv->y0, yuyv->u0, yuyv->v0, r0, g0, b0);
2071  yuv2rgb(yuyv->y1, yuyv->u0, yuyv->v0, r1, g1, b1);
2072 }
2073 
2074 
2075 LIVES_INLINE void yuv888_2_rgb(uint8_t *yuv, uint8_t *rgb, boolean add_alpha) {
2076  yuv2rgb(yuv[0], yuv[1], yuv[2], &(rgb[0]), &(rgb[1]), &(rgb[2]));
2077  if (add_alpha) rgb[3] = 255;
2078 }
2079 
2080 
2081 LIVES_INLINE void yuva8888_2_rgba(uint8_t *yuva, uint8_t *rgba, boolean del_alpha) {
2082  yuv2rgb(yuva[0], yuva[1], yuva[2], &(rgba[0]), &(rgba[1]), &(rgba[2]));
2083  if (!del_alpha) rgba[3] = yuva[3];
2084 }
2085 
2086 
2087 LIVES_INLINE void yuv888_2_bgr(uint8_t *yuv, uint8_t *bgr, boolean add_alpha) {
2088  yuv2bgr(yuv[0], yuv[1], yuv[2], &(bgr[0]), &(bgr[1]), &(bgr[2]));
2089  if (add_alpha) bgr[3] = 255;
2090 }
2091 
2092 
2093 LIVES_INLINE void yuva8888_2_bgra(uint8_t *yuva, uint8_t *bgra, boolean del_alpha) {
2094  yuv2bgr(yuva[0], yuva[1], yuva[2], &(bgra[0]), &(bgra[1]), &(bgra[2]));
2095  if (!del_alpha) bgra[3] = yuva[3];
2096 }
2097 
2098 
2099 LIVES_INLINE void yuv888_2_argb(uint8_t *yuv, uint8_t *argb) {
2100  argb[0] = 255;
2101  yuv2rgb(yuv[0], yuv[1], yuv[2], &(argb[1]), &(argb[2]), &(argb[3]));
2102 }
2103 
2104 
2105 LIVES_INLINE void yuva8888_2_argb(uint8_t *yuva, uint8_t *argb) {
2106  argb[0] = yuva[3];
2107  yuv2rgb(yuva[0], yuva[1], yuva[2], &(argb[1]), &(argb[2]), &(argb[3]));
2108 }
2109 
2110 
2111 LIVES_INLINE void uyvy_2_yuv422(uyvy_macropixel *uyvy, uint8_t *y0, uint8_t *u0, uint8_t *v0, uint8_t *y1) {
2112  *u0 = uyvy->u0;
2113  *y0 = uyvy->y0;
2114  *v0 = uyvy->v0;
2115  *y1 = uyvy->y1;
2116 }
2117 
2118 
2119 LIVES_INLINE void yuyv_2_yuv422(yuyv_macropixel *yuyv, uint8_t *y0, uint8_t *u0, uint8_t *v0, uint8_t *y1) {
2120  *y0 = yuyv->y0;
2121  *u0 = yuyv->u0;
2122  *y1 = yuyv->y1;
2123  *v0 = yuyv->v0;
2124 }
2125 
2127 //utilities
2128 
2129 
2131 #ifdef LIVES_PAINTER_IS_CAIRO
2132  if (pal == WEED_PALETTE_A8 || pal == WEED_PALETTE_A1) return TRUE;
2133  if (capable->byte_order == LIVES_BIG_ENDIAN) {
2134  if (pal == WEED_PALETTE_ARGB32) return TRUE;
2135  } else {
2136  if (pal == WEED_PALETTE_BGRA32) return TRUE;
2137  }
2138 #endif
2139  return FALSE;
2140 }
2141 
2142 
2143 boolean weed_palette_is_lower_quality(int p1, int p2) {
2144  // return TRUE if p1 is lower quality than p2
2145  // we don't yet handle float palettes, or RGB or alpha properly
2146 
2147  // currently only works well for YUV palettes
2148 
2149  if ((weed_palette_is_alpha(p1) && !weed_palette_is_alpha(p2)) ||
2150  (weed_palette_is_alpha(p2) && !weed_palette_is_alpha(p1))) return TRUE; // invalid conversion
2151 
2152  if (weed_palette_is_rgb(p1) && weed_palette_is_rgb(p2)) return FALSE;
2153 
2154  switch (p2) {
2155  case WEED_PALETTE_YUVA8888:
2156  if (p1 != WEED_PALETTE_YUVA8888 && p1 != WEED_PALETTE_YUVA4444P) return TRUE;
2157  break;
2158  case WEED_PALETTE_YUVA4444P:
2159  if (p1 != WEED_PALETTE_YUVA8888 && p1 != WEED_PALETTE_YUVA4444P) return TRUE;
2160  break;
2161  case WEED_PALETTE_YUV888:
2162  if (p1 != WEED_PALETTE_YUVA8888 && p1 != WEED_PALETTE_YUVA4444P && p1 != WEED_PALETTE_YUV444P
2163  && p1 != WEED_PALETTE_YUVA4444P)
2164  return TRUE;
2165  break;
2166  case WEED_PALETTE_YUV444P:
2167  if (p1 != WEED_PALETTE_YUVA8888 && p1 != WEED_PALETTE_YUVA4444P && p1 != WEED_PALETTE_YUV444P
2168  && p1 != WEED_PALETTE_YUVA4444P)
2169  return TRUE;
2170  break;
2171 
2172  case WEED_PALETTE_YUV422P:
2173  case WEED_PALETTE_UYVY8888:
2174  case WEED_PALETTE_YUYV8888:
2175  if (p1 != WEED_PALETTE_YUVA8888 && p1 != WEED_PALETTE_YUVA4444P && p1 != WEED_PALETTE_YUV444P &&
2176  p1 != WEED_PALETTE_YUVA4444P && p1 != WEED_PALETTE_YUV422P && p1 != WEED_PALETTE_UYVY8888
2177  && p1 != WEED_PALETTE_YUYV8888)
2178  return TRUE;
2179  break;
2180 
2181  case WEED_PALETTE_YUV420P:
2182  case WEED_PALETTE_YVU420P:
2183  if (p1 == WEED_PALETTE_YUV411) return TRUE;
2184  break;
2185  case WEED_PALETTE_A8:
2186  if (p1 == WEED_PALETTE_A1) return TRUE;
2187  }
2188  return FALSE; // TODO
2189 }
2190 
2192 
2193 LIVES_GLOBAL_INLINE boolean lives_pixbuf_is_all_black(LiVESPixbuf *pixbuf) {
2194  int width = lives_pixbuf_get_width(pixbuf);
2195  int height = lives_pixbuf_get_height(pixbuf);
2196  int rstride = lives_pixbuf_get_rowstride(pixbuf);
2197  boolean has_alpha = lives_pixbuf_get_has_alpha(pixbuf);
2198  const uint8_t *pdata = lives_pixbuf_get_pixels_readonly(pixbuf);
2199  uint8_t a, b, c;
2200  int offs = 0;
2201  int psize = has_alpha ? 4 : 3;
2202  register int i, j;
2203 
2204  width *= psize;
2205 
2206  for (j = 0; j < height; j++) {
2207  for (i = offs; i < width; i += psize) {
2223  a = pdata[i];
2224  b = pdata[i + 1];
2225  c = pdata[i + 2];
2226 
2227  if (((a & 0x1F) ^ a) & ((c & 0x1F) ^ c) & (((b & 0x1F) ^ b) | ((((b << 1) & 0x1F) ^ (b << 1))
2228  & ((((b & 0x0F) << 2) & 0x1F) ^ ((b & 0x0F) << 2))))) return FALSE;
2229  }
2230  pdata += rstride;
2231  }
2232  return TRUE;
2233 }
2234 
2235 
2236 void pixel_data_planar_from_membuf(void **pixel_data, void *data, size_t size, int palette, boolean contig) {
2237  // convert contiguous memory block planes to planar data
2238  // size is the byte size of the Y plane (width*height in pixels)
2239 
2240  switch (palette) {
2241  case WEED_PALETTE_YUV444P:
2242  if (contig) lives_memcpy(pixel_data[0], data, size * 3);
2243  else {
2244  lives_memcpy(pixel_data[0], data, size);
2245  lives_memcpy(pixel_data[1], (uint8_t *)data + size, size);
2246  lives_memcpy(pixel_data[2], (uint8_t *)data + size * 2, size);
2247  }
2248  break;
2249  case WEED_PALETTE_YUVA4444P:
2250  if (contig) lives_memcpy(pixel_data[0], data, size * 4);
2251  else {
2252  lives_memcpy(pixel_data[0], data, size);
2253  lives_memcpy(pixel_data[1], (uint8_t *)data + size, size);
2254  lives_memcpy(pixel_data[2], (uint8_t *)data + size * 2, size);
2255  lives_memcpy(pixel_data[3], (uint8_t *)data + size * 2, size);
2256  }
2257  break;
2258  case WEED_PALETTE_YUV422P:
2259  if (contig) lives_memcpy(pixel_data[0], data, size * 2);
2260  else {
2261  lives_memcpy(pixel_data[0], data, size);
2262  lives_memcpy(pixel_data[1], (uint8_t *)data + size, size / 2);
2263  lives_memcpy(pixel_data[2], (uint8_t *)data + size * 3 / 2, size / 2);
2264  }
2265  break;
2266  case WEED_PALETTE_YUV420P:
2267  case WEED_PALETTE_YVU420P:
2268  if (contig) lives_memcpy(pixel_data[0], data, size * 3 / 2);
2269  else {
2270  lives_memcpy(pixel_data[0], data, size);
2271  lives_memcpy(pixel_data[1], (uint8_t *)data + size, size / 4);
2272  lives_memcpy(pixel_data[2], (uint8_t *)data + size * 5 / 4, size / 4);
2273  }
2274  break;
2275  }
2276 }
2277 
2278 
2280 // frame conversions
2281 
2282 static void convert_yuv888_to_rgb_frame(uint8_t *src, int hsize, int vsize, int irowstride,
2283  int orowstride, uint8_t *dest, boolean add_alpha, int clamping, int subspace, int thread_id) {
2284  int x, y, i;
2285  size_t offs = 3;
2286 
2287  if (LIVES_UNLIKELY(!conv_YR_inited)) init_YUV_to_RGB_tables();
2288 
2289  if (thread_id == -1) {
2290  set_conversion_arrays(clamping, subspace);
2291 
2292  if (prefs->nfx_threads > 1) {
2293  lives_thread_t threads[prefs->nfx_threads];
2294  uint8_t *end = src + vsize * irowstride;
2295  int nthreads = 1;
2296  int dheight, xdheight;
2298 
2299  xdheight = CEIL((double)vsize / (double)prefs->nfx_threads, 4);
2300  for (i = prefs->nfx_threads - 1; i >= 0; i--) {
2301  dheight = xdheight;
2302 
2303  if ((src + dheight * i * irowstride) < end) {
2304  ccparams[i].src = src + dheight * i * irowstride;
2305  ccparams[i].hsize = hsize;
2306  ccparams[i].dest = dest + dheight * i * orowstride;
2307 
2308  if (dheight * (i + 1) > (vsize - 4)) {
2309  dheight = vsize - (dheight * i);
2310  }
2311 
2312  ccparams[i].vsize = dheight;
2313 
2314  ccparams[i].irowstrides[0] = irowstride;
2315  ccparams[i].orowstrides[0] = orowstride;
2316  ccparams[i].out_alpha = add_alpha;
2317  ccparams[i].in_clamping = clamping;
2318  ccparams[i].in_subspace = subspace;
2319  ccparams[i].thread_id = i;
2320 
2321  if (i == 0) convert_yuv888_to_rgb_frame_thread(&ccparams[i]);
2322  else {
2323  lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_yuv888_to_rgb_frame_thread, &ccparams[i]);
2324  nthreads++;
2325  }
2326  }
2327  }
2328 
2329  for (i = 1; i < nthreads; i++) {
2330  lives_thread_join(threads[i], NULL);
2331  }
2332  lives_free(ccparams);
2333  return;
2334  }
2335  }
2336 
2337  if (add_alpha) offs = 4;
2338  orowstride -= offs * hsize;
2339  irowstride -= hsize * 3;
2340 
2341  for (y = 0; y < vsize; y++) {
2342  for (x = 0; x < hsize; x++) {
2343  yuv888_2_rgb(src, dest, add_alpha);
2344  src += 3;
2345  dest += offs;
2346  }
2347  dest += orowstride;
2348  src += irowstride;
2349  }
2350 }
2351 
2352 
2353 static void *convert_yuv888_to_rgb_frame_thread(void *data) {
2354  lives_cc_params *ccparams = (lives_cc_params *)data;
2355  convert_yuv888_to_rgb_frame((uint8_t *)ccparams->src, ccparams->hsize, ccparams->vsize, ccparams->irowstrides[0],
2356  ccparams->orowstrides[0], (uint8_t *)ccparams->dest, ccparams->out_alpha,
2357  ccparams->in_clamping, ccparams->in_subspace, ccparams->thread_id);
2358  return NULL;
2359 }
2360 
2361 
2362 static void convert_yuva8888_to_rgba_frame(uint8_t *src, int hsize, int vsize, int irowstride,
2363  int orowstride, uint8_t *dest, boolean del_alpha, int clamping, int subspace, int thread_id) {
2364  register int x, y, i;
2365 
2366  size_t offs = 4;
2367 
2368  if (LIVES_UNLIKELY(!conv_YR_inited)) init_YUV_to_RGB_tables();
2369 
2370  if (thread_id == -1)
2371  set_conversion_arrays(clamping, subspace);
2372 
2373  if (thread_id == -1 && prefs->nfx_threads > 1) {
2374  lives_thread_t threads[prefs->nfx_threads];
2375  uint8_t *end = src + vsize * irowstride;
2376  int nthreads = 1;
2377  int dheight, xdheight;
2379 
2380  xdheight = CEIL((double)vsize / (double)prefs->nfx_threads, 4);
2381  for (i = prefs->nfx_threads - 1; i >= 0; i--) {
2382  dheight = xdheight;
2383 
2384  if ((src + dheight * i * irowstride) < end) {
2385  ccparams[i].src = src + dheight * i * irowstride;
2386  ccparams[i].hsize = hsize;
2387  ccparams[i].dest = dest + dheight * i * orowstride;
2388 
2389  if (dheight * (i + 1) > (vsize - 4)) {
2390  dheight = vsize - (dheight * i);
2391  }
2392 
2393  ccparams[i].vsize = dheight;
2394 
2395  ccparams[i].irowstrides[0] = irowstride;
2396  ccparams[i].orowstrides[0] = orowstride;
2397  ccparams[i].out_alpha = !del_alpha;
2398  ccparams[i].in_clamping = clamping;
2399  ccparams[i].in_subspace = subspace;
2400  ccparams[i].thread_id = i;
2401 
2402  if (i == 0) convert_yuva8888_to_rgba_frame_thread(&ccparams[i]);
2403  else {
2404  lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_yuva8888_to_rgba_frame_thread, &ccparams[i]);
2405  nthreads++;
2406  }
2407  }
2408  }
2409 
2410  for (i = 1; i < nthreads; i++) {
2411  lives_thread_join(threads[i], NULL);
2412  }
2413  lives_free(ccparams);
2414  return;
2415  }
2416 
2417  if (del_alpha) offs = 3;
2418  orowstride -= offs * hsize;
2419  irowstride -= hsize * 4;
2420 
2421  for (y = 0; y < vsize; y++) {
2422  for (x = 0; x < hsize; x++) {
2423  yuva8888_2_rgba(src, dest, del_alpha);
2424  src += 4;
2425  dest += offs;
2426  }
2427  dest += orowstride;
2428  src += irowstride;
2429  }
2430 }
2431 
2432 
2433 static void *convert_yuva8888_to_rgba_frame_thread(void *data) {
2434  lives_cc_params *ccparams = (lives_cc_params *)data;
2435  convert_yuva8888_to_rgba_frame((uint8_t *)ccparams->src, ccparams->hsize, ccparams->vsize, ccparams->irowstrides[0],
2436  ccparams->orowstrides[0], (uint8_t *)ccparams->dest, !ccparams->out_alpha,
2437  ccparams->in_clamping, ccparams->in_subspace, ccparams->thread_id);
2438  return NULL;
2439 }
2440 
2441 
2442 static void convert_yuv888_to_bgr_frame(uint8_t *src, int hsize, int vsize, int irowstride,
2443  int orowstride, uint8_t *dest, boolean add_alpha, int clamping, int subspace, int thread_id) {
2444  register int x, y, i;
2445  size_t offs = 3;
2446 
2447  if (LIVES_UNLIKELY(!conv_YR_inited)) init_YUV_to_RGB_tables();
2448  if (thread_id == -1)
2449  set_conversion_arrays(clamping, subspace);
2450 
2451  if (thread_id == -1 && prefs->nfx_threads > 1) {
2452  lives_thread_t threads[prefs->nfx_threads];
2453  uint8_t *end = src + vsize * irowstride;
2454  int nthreads = 1;
2455  int dheight, xdheight;
2457 
2458  xdheight = CEIL((double)vsize / (double)prefs->nfx_threads, 4);
2459  for (i = prefs->nfx_threads - 1; i >= 0; i--) {
2460  dheight = xdheight;
2461 
2462  if ((src + dheight * i * irowstride) < end) {
2463  ccparams[i].src = src + dheight * i * irowstride;
2464  ccparams[i].hsize = hsize;
2465  ccparams[i].dest = dest + dheight * i * orowstride;
2466 
2467  if (dheight * (i + 1) > (vsize - 4)) {
2468  dheight = vsize - (dheight * i);
2469  }
2470 
2471  ccparams[i].vsize = dheight;
2472 
2473  ccparams[i].irowstrides[0] = irowstride;
2474  ccparams[i].orowstrides[0] = orowstride;
2475  ccparams[i].out_alpha = add_alpha;
2476  ccparams[i].in_clamping = clamping;
2477  ccparams[i].in_subspace = subspace;
2478  ccparams[i].thread_id = i;
2479 
2480  if (i == 0) convert_yuv888_to_bgr_frame_thread(&ccparams[i]);
2481  else {
2482  lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_yuv888_to_bgr_frame_thread, &ccparams[i]);
2483  nthreads++;
2484  }
2485  }
2486  }
2487 
2488  for (i = 1; i < nthreads; i++) {
2489  lives_thread_join(threads[i], NULL);
2490  }
2491  lives_free(ccparams);
2492  return;
2493  }
2494 
2495  if (add_alpha) offs = 4;
2496  orowstride -= offs * hsize;
2497  irowstride -= hsize * 3;
2498 
2499  for (y = 0; y < vsize; y++) {
2500  for (x = 0; x < hsize; x++) {
2501  yuv888_2_bgr(src, dest, add_alpha);
2502  src += 3;
2503  dest += offs;
2504  }
2505  dest += orowstride;
2506  src += irowstride;
2507  }
2508 }
2509 
2510 
2511 static void *convert_yuv888_to_bgr_frame_thread(void *data) {
2512  lives_cc_params *ccparams = (lives_cc_params *)data;
2513  convert_yuv888_to_bgr_frame((uint8_t *)ccparams->src, ccparams->hsize, ccparams->vsize, ccparams->irowstrides[0],
2514  ccparams->orowstrides[0], (uint8_t *)ccparams->dest, ccparams->out_alpha,
2515  ccparams->in_clamping, ccparams->in_subspace, ccparams->thread_id);
2516  return NULL;
2517 }
2518 
2519 
2520 static void convert_yuva8888_to_bgra_frame(uint8_t *src, int hsize, int vsize, int irowstride,
2521  int orowstride, uint8_t *dest, boolean del_alpha, int clamping, int subspace, int thread_id) {
2522  register int x, y, i;
2523 
2524  size_t offs = 4;
2525 
2526  if (LIVES_UNLIKELY(!conv_YR_inited)) init_YUV_to_RGB_tables();
2527  if (thread_id == -1)
2528  set_conversion_arrays(clamping, subspace);
2529 
2530  if (thread_id == -1 && prefs->nfx_threads > 1) {
2531  lives_thread_t threads[prefs->nfx_threads];
2532  uint8_t *end = src + vsize * irowstride;
2533  int nthreads = 1;
2534  int dheight, xdheight;
2536 
2537  xdheight = CEIL((double)vsize / (double)prefs->nfx_threads, 4);
2538  for (i = prefs->nfx_threads - 1; i >= 0; i--) {
2539  dheight = xdheight;
2540 
2541  if ((src + dheight * i * irowstride) < end) {
2542  ccparams[i].src = src + dheight * i * irowstride;
2543  ccparams[i].hsize = hsize;
2544  ccparams[i].dest = dest + dheight * i * orowstride;
2545 
2546  if (dheight * (i + 1) > (vsize - 4)) {
2547  dheight = vsize - (dheight * i);
2548  }
2549 
2550  ccparams[i].vsize = dheight;
2551 
2552  ccparams[i].irowstrides[0] = irowstride;
2553  ccparams[i].orowstrides[0] = orowstride;
2554  ccparams[i].out_alpha = !del_alpha;
2555  ccparams[i].in_clamping = clamping;
2556  ccparams[i].in_subspace = subspace;
2557  ccparams[i].thread_id = i;
2558 
2559  if (i == 0) convert_yuva8888_to_bgra_frame_thread(&ccparams[i]);
2560  else {
2561  lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_yuva8888_to_bgra_frame_thread, &ccparams[i]);
2562  nthreads++;
2563  }
2564  }
2565  }
2566 
2567  for (i = 1; i < nthreads; i++) {
2568  lives_thread_join(threads[i], NULL);
2569  }
2570  lives_free(ccparams);
2571  return;
2572  }
2573 
2574  if (del_alpha) offs = 3;
2575  orowstride -= offs * hsize;
2576  irowstride -= 4 * hsize;
2577 
2578  for (y = 0; y < vsize; y++) {
2579  for (x = 0; x < hsize; x++) {
2580  yuva8888_2_bgra(src, dest, del_alpha);
2581  src += 4;
2582  dest += offs;
2583  }
2584  dest += orowstride;
2585  src += irowstride;
2586  }
2587 }
2588 
2589 
2590 static void *convert_yuva8888_to_bgra_frame_thread(void *data) {
2591  lives_cc_params *ccparams = (lives_cc_params *)data;
2592  convert_yuva8888_to_bgra_frame((uint8_t *)ccparams->src, ccparams->hsize, ccparams->vsize, ccparams->irowstrides[0],
2593  ccparams->orowstrides[0], (uint8_t *)ccparams->dest, !ccparams->out_alpha,
2594  ccparams->in_clamping, ccparams->in_subspace, ccparams->thread_id);
2595  return NULL;
2596 }
2597 
2598 
2599 static void convert_yuv888_to_argb_frame(uint8_t *src, int hsize, int vsize, int irowstride,
2600  int orowstride, uint8_t *dest, int clamping, int subspace, int thread_id) {
2601  int x, y, i;
2602  size_t offs = 4;
2603 
2604  if (LIVES_UNLIKELY(!conv_YR_inited)) init_YUV_to_RGB_tables();
2605  if (thread_id == -1)
2606  set_conversion_arrays(clamping, subspace);
2607 
2608  if (thread_id == -1 && prefs->nfx_threads > 1) {
2609  lives_thread_t threads[prefs->nfx_threads];
2610  uint8_t *end = src + vsize * irowstride;
2611  int nthreads = 1;
2612  int dheight, xdheight;
2614 
2615  xdheight = CEIL((double)vsize / (double)prefs->nfx_threads, 4);
2616  for (i = prefs->nfx_threads - 1; i >= 0; i--) {
2617  dheight = xdheight;
2618 
2619  if ((src + dheight * i * irowstride) < end) {
2620  ccparams[i].src = src + dheight * i * irowstride;
2621  ccparams[i].hsize = hsize;
2622  ccparams[i].dest = dest + dheight * i * orowstride;
2623 
2624  if (dheight * (i + 1) > (vsize - 4)) {
2625  dheight = vsize - (dheight * i);
2626  }
2627 
2628  ccparams[i].vsize = dheight;
2629 
2630  ccparams[i].irowstrides[0] = irowstride;
2631  ccparams[i].orowstrides[0] = orowstride;
2632  ccparams[i].in_clamping = clamping;
2633  ccparams[i].in_subspace = subspace;
2634  ccparams[i].thread_id = i;
2635 
2636  if (i == 0) convert_yuv888_to_argb_frame_thread(&ccparams[i]);
2637  else {
2638  lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_yuv888_to_argb_frame_thread, &ccparams[i]);
2639  nthreads++;
2640  }
2641  }
2642  }
2643 
2644  for (i = 1; i < nthreads; i++) {
2645  lives_thread_join(threads[i], NULL);
2646  }
2647  lives_free(ccparams);
2648  return;
2649  }
2650 
2651  orowstride -= offs * hsize;
2652  irowstride -= hsize * 3;
2653 
2654  for (y = 0; y < vsize; y++) {
2655  for (x = 0; x < hsize; x++) {
2656  yuv888_2_argb(src, dest);
2657  src += 3;
2658  dest += 4;
2659  }
2660  dest += orowstride;
2661  src += irowstride;
2662  }
2663 }
2664 
2665 
2666 static void *convert_yuv888_to_argb_frame_thread(void *data) {
2667  lives_cc_params *ccparams = (lives_cc_params *)data;
2668  convert_yuv888_to_argb_frame((uint8_t *)ccparams->src, ccparams->hsize, ccparams->vsize, ccparams->irowstrides[0],
2669  ccparams->orowstrides[0], (uint8_t *)ccparams->dest,
2670  ccparams->in_clamping, ccparams->in_subspace, ccparams->thread_id);
2671  return NULL;
2672 }
2673 
2674 
2675 static void convert_yuva8888_to_argb_frame(uint8_t *src, int hsize, int vsize, int irowstride,
2676  int orowstride, uint8_t *dest, int clamping, int subspace, int thread_id) {
2677  int x, y, i;
2678 
2679  size_t offs = 4;
2680 
2681  if (LIVES_UNLIKELY(!conv_YR_inited)) init_YUV_to_RGB_tables();
2682  if (thread_id == -1)
2683  set_conversion_arrays(clamping, subspace);
2684 
2685  if (thread_id == -1 && prefs->nfx_threads > 1) {
2686  lives_thread_t threads[prefs->nfx_threads];
2687  uint8_t *end = src + vsize * irowstride;
2688  int nthreads = 1;
2689  int dheight, xdheight;
2691 
2692  xdheight = CEIL((double)vsize / (double)prefs->nfx_threads, 4);
2693  for (i = prefs->nfx_threads - 1; i >= 0; i--) {
2694  dheight = xdheight;
2695 
2696  if ((src + dheight * i * irowstride) < end) {
2697  ccparams[i].src = src + dheight * i * irowstride;
2698  ccparams[i].hsize = hsize;
2699  ccparams[i].dest = dest + dheight * i * orowstride;
2700 
2701  if (dheight * (i + 1) > (vsize - 4)) {
2702  dheight = vsize - (dheight * i);
2703  }
2704 
2705  ccparams[i].vsize = dheight;
2706 
2707  ccparams[i].irowstrides[0] = irowstride;
2708  ccparams[i].orowstrides[0] = orowstride;
2709  ccparams[i].in_clamping = clamping;
2710  ccparams[i].in_subspace = subspace;
2711  ccparams[i].thread_id = i;
2712 
2713  if (i == 0) convert_yuva8888_to_argb_frame_thread(&ccparams[i]);
2714  else {
2715  lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_yuva8888_to_rgba_frame_thread, &ccparams[i]);
2716  nthreads++;
2717  }
2718  }
2719  }
2720 
2721  for (i = 1; i < nthreads; i++) {
2722  lives_thread_join(threads[i], NULL);
2723  }
2724  lives_free(ccparams);
2725  return;
2726  }
2727 
2728  orowstride -= offs * hsize;
2729  irowstride -= hsize * 4;
2730 
2731  for (y = 0; y < vsize; y++) {
2732  for (x = 0; x < hsize; x++) {
2733  yuva8888_2_argb(src, dest);
2734  src += 4;
2735  dest += 4;
2736  }
2737  dest += orowstride;
2738  src += irowstride;
2739  }
2740 }
2741 
2742 
2743 static void *convert_yuva8888_to_argb_frame_thread(void *data) {
2744  lives_cc_params *ccparams = (lives_cc_params *)data;
2745  convert_yuva8888_to_argb_frame((uint8_t *)ccparams->src, ccparams->hsize, ccparams->vsize, ccparams->irowstrides[0],
2746  ccparams->orowstrides[0], (uint8_t *)ccparams->dest,
2747  ccparams->in_clamping, ccparams->in_subspace, ccparams->thread_id);
2748  return NULL;
2749 }
2750 
2751 
2752 static void convert_yuv420p_to_rgb_frame(uint8_t **src, int width, int height, boolean is_bottom, int *istrides, int orowstride,
2753  uint8_t *dest, boolean add_alpha, boolean is_422, int sampling, int clamping, int subspace,
2754  int gamma, int tgamma, uint8_t *gamma_lut, int thread_id) {
2755  int i, j;
2756  uint8_t *s_y = src[0], *s_u = src[1], *s_v = src[2];
2757  int opsize = 3;
2758  int irow = istrides[0] - width;
2759  boolean even = TRUE;
2760  size_t uv_offs = 0;
2761  uint8_t y, u, v, next_u, next_v, last_u, last_v;
2762 
2763  if (thread_id == -1) {
2764  if (LIVES_UNLIKELY(!conv_YR_inited)) init_YUV_to_RGB_tables();
2765 
2767  set_conversion_arrays(clamping, subspace);
2768 
2769  if (tgamma) gamma_lut = create_gamma_lut(1.0, gamma, tgamma);
2770  if (prefs->nfx_threads > 1) {
2771  lives_thread_t threads[prefs->nfx_threads];
2772  uint8_t *end = src[0] + height * istrides[0];
2773  int nthreads = 1;
2774  int dheight, xdheight;
2776 
2777  xdheight = CEIL((double)height / (double)prefs->nfx_threads, 4);
2778  for (i = prefs->nfx_threads - 1; i >= 0; i--) {
2779  dheight = xdheight;
2780 
2781  if ((src[0] + dheight * i * istrides[0]) < end) {
2782  ccparams[i].srcp[0] = src[0] + dheight * i * istrides[0];
2783  ccparams[i].srcp[1] = src[1] + dheight / 2 * i * istrides[1];
2784  ccparams[i].srcp[2] = src[2] + dheight / 2 * i * istrides[2];
2785  ccparams[i].hsize = width;
2786  ccparams[i].dest = dest + dheight * i * orowstride;
2787 
2788  if (dheight * (i + 1) > (height - 4)) {
2789  dheight = height - (dheight * i);
2790  }
2791 
2792  ccparams[i].vsize = dheight;
2793  if (i == prefs->nfx_threads - 1) {
2794  ccparams[i].is_bottom = TRUE;
2795  }
2796  ccparams[i].irowstrides[0] = istrides[0];
2797  ccparams[i].irowstrides[1] = istrides[1];
2798  ccparams[i].irowstrides[2] = istrides[2];
2799  ccparams[i].orowstrides[0] = orowstride;
2800  ccparams[i].out_alpha = add_alpha;
2801  ccparams[i].in_sampling = sampling;
2802  ccparams[i].in_clamping = clamping;
2803  ccparams[i].in_subspace = subspace;
2804  ccparams[i].is_422 = is_422;
2805  ccparams[i].lut = gamma_lut;
2806  ccparams[i].thread_id = i;
2807 
2808  if (i == 0) convert_yuv420p_to_rgb_frame_thread(&ccparams[i]);
2809  else {
2810  lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_yuv420p_to_rgb_frame_thread, &ccparams[i]);
2811  nthreads++;
2812  }
2813  }
2814  }
2815 
2816  for (i = 1; i < nthreads; i++) {
2817  lives_thread_join(threads[i], NULL);
2818  }
2819  lives_free(ccparams);
2820  if (gamma_lut) lives_gamma_lut_free(gamma_lut);
2821  return;
2822  }
2823  }
2824 
2825  if (add_alpha) opsize = 4;
2826  width *= opsize;
2827 
2828  for (i = 0; i < height; i++) {
2829  if (!is_422) {
2830  if (!(i & 1)) even = TRUE;
2831  else even = FALSE;
2832  }
2833 
2834  uv_offs = 0;
2835 
2836  for (j = 0; j < width; j += opsize) {
2837  // process two pixels at a time, and we average the first colour pixel with the last from the previous 2
2838  // we know we can do this because Y must be even width
2839  y = *(s_y++);
2841  if (j > 0) {
2843  u = avg_chroma_3_1(next_u, last_u);
2844  v = avg_chroma_3_1(next_v, last_v);
2845  last_u = next_u;
2846  last_v = next_v;
2847  } else {
2848  if (even) {
2849  last_u = next_u = u = s_u[uv_offs];
2850  last_v = next_v = v = s_v[uv_offs];
2851  } else {
2852  if (is_bottom && i == height - 1) {
2853  next_u = u = s_u[uv_offs];
2854  next_v = v = s_v[uv_offs];
2855  } else {
2856  next_u = u = avg_chromaf(s_u[uv_offs], s_u[uv_offs + istrides[1]]);
2857  next_v = v = avg_chromaf(s_v[uv_offs], s_v[uv_offs + istrides[2]]);
2858  }
2859  }
2860  }
2861  if (gamma_lut)
2862  yuv2rgb_with_gamma(y, u, v, &dest[j], &dest[j + 1], &dest[j + 2], gamma_lut);
2863  else
2864  yuv2rgb(y, u, v, &dest[j], &dest[j + 1], &dest[j + 2]);
2865  if (add_alpha) dest[j + 3] = 255;
2866 
2867  // second RGB pixel
2868  j += opsize;
2869  y = *(s_y++);
2870 
2871  last_u = next_u;
2872  last_v = next_v;
2873 
2874  if (j < width - 1) {
2875  if (even) {
2877  next_u = s_u[uv_offs];
2878  next_v = s_v[uv_offs];
2879  } else {
2880  if (is_bottom && i == height - 1) {
2881  next_u = u = s_u[uv_offs];
2882  next_v = v = s_v[uv_offs];
2883  } else {
2884  //g_print("vals %ld and %d %d %d\n", uv_offs, istrides[2], i, j);
2885  next_u = u = avg_chromaf(s_u[uv_offs], s_u[uv_offs + istrides[1]]);
2886  next_v = v = avg_chromaf(s_v[uv_offs], s_v[uv_offs + istrides[2]]);
2887  }
2888  }
2890  u = avg_chroma_3_1(next_u, last_u);
2891  v = avg_chroma_3_1(next_v, last_v);
2892  } else {
2893  u = last_u;
2894  v = last_v;
2895  }
2896  if (gamma_lut)
2897  yuv2rgb_with_gamma(y, u, v, &dest[j], &dest[j + 1], &dest[j + 2], gamma_lut);
2898  else
2899  yuv2rgb(y, u, v, &dest[j], &dest[j + 1], &dest[j + 2]);
2900  if (add_alpha) dest[j + 3] = 255;
2901  uv_offs++;
2902  }
2903  s_y += irow;
2904  dest += orowstride;
2905  if (is_422 || !even) {
2906  s_u += istrides[1];
2907  s_v += istrides[2];
2908  }
2909  }
2910 }
2911 
2912 static void *convert_yuv420p_to_rgb_frame_thread(void *data) {
2913  lives_cc_params *ccparams = (lives_cc_params *)data;
2914  convert_yuv420p_to_rgb_frame((uint8_t **)ccparams->srcp, ccparams->hsize, ccparams->vsize,
2915  ccparams->is_bottom, ccparams->irowstrides,
2916  ccparams->orowstrides[0], (uint8_t *)ccparams->dest,
2917  ccparams->out_alpha, ccparams->is_422, ccparams->in_sampling,
2918  ccparams->in_clamping, ccparams->in_subspace, 0, 0,
2919  ccparams->lut, ccparams->thread_id);
2920  return NULL;
2921 }
2922 
2923 
2924 static void convert_yuv420p_to_bgr_frame(uint8_t **src, int width, int height, boolean is_bottom, int *istrides, int orowstride,
2925  uint8_t *dest, boolean add_alpha, boolean is_422, int sampling, int clamping, int subspace,
2926  int gamma, int tgamma, uint8_t *gamma_lut, int thread_id) {
2927  int i, j;
2928  uint8_t *s_y = src[0], *s_u = src[1], *s_v = src[2];
2929  int opsize = 3;
2930  int irow = istrides[0] - width;
2931  boolean even = TRUE;
2932  uint8_t y, u, v, next_u, next_v, last_u, last_v;
2933  size_t uv_offs = 0;
2934 
2935  if (thread_id == -1) {
2936  if (LIVES_UNLIKELY(!conv_YR_inited)) init_YUV_to_RGB_tables();
2937 
2939  set_conversion_arrays(clamping, subspace);
2940 
2941  if (tgamma) gamma_lut = create_gamma_lut(1.0, gamma, tgamma);
2942  if (prefs->nfx_threads > 1) {
2943  lives_thread_t threads[prefs->nfx_threads];
2944  uint8_t *end = src[0] + height * istrides[0];
2945  int nthreads = 1;
2946  int dheight, xdheight;
2948 
2949  xdheight = CEIL((double)height / (double)prefs->nfx_threads, 4);
2950  for (i = prefs->nfx_threads - 1; i >= 0; i--) {
2951  dheight = xdheight;
2952 
2953  if ((src[0] + dheight * i * istrides[0]) < end) {
2954  ccparams[i].srcp[0] = src[0] + dheight * i * istrides[0];
2955  ccparams[i].srcp[1] = src[1] + dheight / 2 * i * istrides[1];
2956  ccparams[i].srcp[2] = src[2] + dheight / 2 * i * istrides[2];
2957  ccparams[i].hsize = width;
2958  ccparams[i].dest = dest + dheight * i * orowstride;
2959 
2960  if (dheight * (i + 1) > (height - 4)) {
2961  dheight = height - (dheight * i);
2962  }
2963 
2964  ccparams[i].vsize = dheight;
2965  if (i == prefs->nfx_threads - 1) ccparams->is_bottom = TRUE;
2966 
2967  ccparams[i].irowstrides[0] = istrides[0];
2968  ccparams[i].irowstrides[1] = istrides[1];
2969  ccparams[i].irowstrides[2] = istrides[2];
2970  ccparams[i].orowstrides[0] = orowstride;
2971  ccparams[i].out_alpha = add_alpha;
2972  ccparams[i].in_sampling = sampling;
2973  ccparams[i].in_clamping = clamping;
2974  ccparams[i].in_subspace = subspace;
2975  ccparams[i].is_422 = is_422;
2976  ccparams[i].lut = gamma_lut;
2977  ccparams[i].thread_id = i;
2978 
2979  if (i == 0) convert_yuv420p_to_bgr_frame_thread(&ccparams[i]);
2980  else {
2981  lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_yuv420p_to_bgr_frame_thread, &ccparams[i]);
2982  nthreads++;
2983  }
2984  }
2985  }
2986 
2987  for (i = 1; i < nthreads; i++) {
2988  lives_thread_join(threads[i], NULL);
2989  }
2990  lives_free(ccparams);
2991  if (gamma_lut) lives_gamma_lut_free(gamma_lut);
2992  return;
2993  }
2994  }
2995 
2996  if (add_alpha) opsize = 4;
2997  width *= opsize;
2998 
2999  for (i = 0; i < height; i++) {
3000  if (!is_422) {
3001  if (!(i & 1)) even = TRUE;
3002  else even = FALSE;
3003  }
3004 
3005  uv_offs = 0;
3006 
3007  for (j = 0; j < width; j += opsize) {
3008  // process two pixels at a time, and we average the first colour pixel with the last from the previous 2
3009  // we know we can do this because Y must be even width
3010  y = *(s_y++);
3012  if (j > 0) {
3014  u = avg_chroma_3_1(next_u, last_u);
3015  v = avg_chroma_3_1(next_v, last_v);
3016  last_u = next_u;
3017  last_v = next_v;
3018  } else {
3019  if (even) {
3020  next_u = u = s_u[uv_offs];
3021  next_v = v = s_v[uv_offs];
3022  } else {
3023  if (i == height - 1 && is_bottom) {
3024  next_u = u = s_u[uv_offs];
3025  next_v = v = s_v[uv_offs];
3026  } else {
3027  next_u = u = avg_chromaf(s_u[uv_offs], s_u[uv_offs + istrides[1]]);
3028  next_v = v = avg_chromaf(s_v[uv_offs], s_v[uv_offs + istrides[2]]);
3029  }
3030  }
3031  }
3032  if (gamma_lut)
3033  yuv2bgr_with_gamma(y, u, v, &dest[j], &dest[j + 1], &dest[j + 2], gamma_lut);
3034  else
3035  yuv2bgr(y, u, v, &dest[j], &dest[j + 1], &dest[j + 2]);
3036  if (add_alpha) dest[j + 3] = 255;
3037 
3038  // second RGB pixel
3039  j += opsize;
3040  y = *(s_y++);
3041  last_u = next_u;
3042  last_v = next_v;
3043 
3044  if (j < width - 1) {
3045  if (even) {
3047  next_u = s_u[uv_offs];
3048  next_v = s_v[uv_offs];
3049  } else {
3050  if (i == height - 1 && is_bottom) {
3051  next_u = u = s_u[uv_offs];
3052  next_v = v = s_v[uv_offs];
3053  } else {
3054  next_u = u = avg_chromaf(s_u[uv_offs], s_u[uv_offs + istrides[1]]);
3055  next_v = v = avg_chromaf(s_v[uv_offs], s_v[uv_offs + istrides[2]]);
3056  }
3057  }
3059  u = avg_chroma_3_1(next_u, last_u);
3060  v = avg_chroma_3_1(next_v, last_v);
3061  } else {
3062  u = last_u;
3063  v = last_v;
3064  }
3065  if (gamma_lut)
3066  yuv2bgr_with_gamma(y, u, v, &dest[j], &dest[j + 1], &dest[j + 2], gamma_lut);
3067  else
3068  yuv2bgr(y, u, v, &dest[j], &dest[j + 1], &dest[j + 2]);
3069  if (add_alpha) dest[j + 3] = 255;
3070  uv_offs++;
3071  }
3072  s_y += irow;
3073  dest += orowstride;
3074  if (is_422 || !even) {
3075  s_u += istrides[1];
3076  s_v += istrides[2];
3077  }
3078  }
3079 }
3080 
3081 static void *convert_yuv420p_to_bgr_frame_thread(void *data) {
3082  lives_cc_params *ccparams = (lives_cc_params *)data;
3083  convert_yuv420p_to_bgr_frame((uint8_t **)ccparams->srcp, ccparams->hsize, ccparams->vsize,
3084  ccparams->is_bottom, ccparams->irowstrides,
3085  ccparams->orowstrides[0], (uint8_t *)ccparams->dest,
3086  ccparams->out_alpha, ccparams->is_422, ccparams->in_sampling,
3087  ccparams->in_clamping, ccparams->in_subspace, 0, 0,
3088  ccparams->lut, ccparams->thread_id);
3089  return NULL;
3090 }
3091 
3092 
3093 static void convert_yuv420p_to_argb_frame(uint8_t **src, int width, int height, boolean is_bottom, int *istrides,
3094  int orowstride,
3095  uint8_t *dest, boolean is_422, int sampling, int clamping, int subspace,
3096  int gamma, int tgamma, uint8_t *gamma_lut, int thread_id) {
3097  int i, j;
3098  uint8_t *s_y = src[0], *s_u = src[1], *s_v = src[2];
3099  int opsize = 4;
3100  int irow = istrides[0] - width;
3101  boolean even = TRUE;
3102  uint8_t y, u, v, next_u = 0, next_v = 0, last_u = 0, last_v = 0;
3103  size_t uv_offs = 0;
3104 
3105  if (thread_id == -1) {
3106  if (LIVES_UNLIKELY(!conv_YR_inited)) init_YUV_to_RGB_tables();
3107 
3109  set_conversion_arrays(clamping, subspace);
3110 
3111  if (tgamma) gamma_lut = create_gamma_lut(1.0, gamma, tgamma);
3112  if (prefs->nfx_threads > 1) {
3113  lives_thread_t threads[prefs->nfx_threads];
3114  uint8_t *end = src[0] + height * istrides[0];
3115  int nthreads = 1;
3116  int dheight, xdheight;
3118 
3119  xdheight = CEIL((double)height / (double)prefs->nfx_threads, 4);
3120  for (i = prefs->nfx_threads - 1; i >= 0; i--) {
3121  dheight = xdheight;
3122 
3123  if ((src[0] + dheight * i * istrides[0]) < end) {
3124  ccparams[i].srcp[0] = src[0] + dheight * i * istrides[0];
3125  ccparams[i].srcp[1] = src[1] + dheight / 2 * i * istrides[1];
3126  ccparams[i].srcp[2] = src[2] + dheight / 2 * i * istrides[2];
3127  ccparams[i].hsize = width;
3128  ccparams[i].dest = dest + dheight * i * orowstride;
3129 
3130  if (dheight * (i + 1) > (height - 4)) {
3131  dheight = height - (dheight * i);
3132  }
3133 
3134  ccparams[i].vsize = dheight;
3135  if (i == prefs->nfx_threads - 1) ccparams->is_bottom = TRUE;
3136 
3137  ccparams[i].irowstrides[0] = istrides[0];
3138  ccparams[i].irowstrides[1] = istrides[1];
3139  ccparams[i].irowstrides[2] = istrides[2];
3140  ccparams[i].orowstrides[0] = orowstride;
3141  ccparams[i].in_sampling = sampling;
3142  ccparams[i].in_clamping = clamping;
3143  ccparams[i].in_subspace = subspace;
3144  ccparams[i].is_422 = is_422;
3145  ccparams[i].lut = gamma_lut;
3146  ccparams[i].thread_id = i;
3147 
3148  if (i == 0) convert_yuv420p_to_argb_frame_thread(&ccparams[i]);
3149  else {
3150  lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_yuv420p_to_argb_frame_thread, &ccparams[i]);
3151  nthreads++;
3152  }
3153  }
3154  }
3155 
3156  for (i = 1; i < nthreads; i++) {
3157  lives_thread_join(threads[i], NULL);
3158  }
3159  lives_free(ccparams);
3160  if (gamma_lut) lives_gamma_lut_free(gamma_lut);
3161  return;
3162  }
3163  }
3164 
3165  width *= opsize;
3166 
3167  for (i = 0; i < height; i++) {
3168  if (!is_422) {
3169  if (!(i & 1)) even = TRUE;
3170  else even = FALSE;
3171  }
3172 
3173  uv_offs = 0;
3174 
3175  for (j = 0; j < width; j += opsize) {
3176  // process two pixels at a time, and we average the first colour pixel with the last from the previous 2
3177  // we know we can do this because Y must be even width
3178  dest[j] = 255;
3179  y = *(s_y++);
3181  if (j > 0) {
3183  u = avg_chroma_3_1(next_u, last_u);
3184  v = avg_chroma_3_1(next_v, last_v);
3185  last_u = next_u;
3186  last_v = next_v;
3187  } else {
3188  if (even) {
3189  next_u = u = s_u[uv_offs];
3190  next_v = v = s_v[uv_offs];
3191  } else {
3192  if (i == height - 1 && is_bottom) {
3193  next_u = u = s_u[uv_offs];
3194  next_v = v = s_v[uv_offs];
3195  } else {
3196  next_u = u = avg_chromaf(s_u[uv_offs], s_u[uv_offs + istrides[1]]);
3197  next_v = v = avg_chromaf(s_v[uv_offs], s_v[uv_offs + istrides[2]]);
3198  }
3199  }
3200  }
3201  if (gamma_lut)
3202  yuv2rgb_with_gamma(y, u, v, &dest[j + 1], &dest[j + 2], &dest[j + 3], gamma_lut);
3203  else
3204  yuv2rgb(y, u, v, &dest[j + 1], &dest[j + 2], &dest[j + 3]);
3205 
3206  // second RGB pixel
3207  j += opsize;
3208  y = *(s_y++);
3209  last_u = next_u;
3210  last_v = next_v;
3211  dest[j] = 255;
3212 
3213  if (j < width - 1) {
3214  if (even) {
3216  next_u = s_u[uv_offs];
3217  next_v = s_v[uv_offs];
3218  } else {
3219  if (i == height - 1 && is_bottom) {
3220  next_u = u = s_u[uv_offs];
3221  next_v = v = s_v[uv_offs];
3222  } else {
3223  next_u = u = avg_chromaf(s_u[uv_offs], s_u[uv_offs + istrides[1]]);
3224  next_v = v = avg_chromaf(s_v[uv_offs], s_v[uv_offs + istrides[2]]);
3225  }
3226  }
3228  u = avg_chroma_3_1(next_u, last_u);
3229  v = avg_chroma_3_1(next_v, last_v);
3230  } else {
3231  u = last_u;
3232  v = last_v;
3233  }
3234  if (gamma_lut)
3235  yuv2rgb_with_gamma(y, u, v, &dest[j + 1], &dest[j + 2], &dest[j + 3], gamma_lut);
3236  else
3237  yuv2rgb(y, u, v, &dest[j + 1], &dest[j + 2], &dest[j + 3]);
3238  uv_offs++;
3239  }
3240  s_y += irow;
3241  dest += orowstride;
3242  if (is_422 || !even) {
3243  s_u += istrides[1];
3244  s_v += istrides[2];
3245  }
3246  }
3247 }
3248 
3249 static void *convert_yuv420p_to_argb_frame_thread(void *data) {
3250  lives_cc_params *ccparams = (lives_cc_params *)data;
3251  convert_yuv420p_to_argb_frame((uint8_t **)ccparams->srcp, ccparams->hsize, ccparams->vsize,
3252  ccparams->is_bottom, ccparams->irowstrides,
3253  ccparams->orowstrides[0], (uint8_t *)ccparams->dest,
3254  ccparams->is_422, ccparams->in_sampling,
3255  ccparams->in_clamping, ccparams->in_subspace, 0, 0,
3256  ccparams->lut, ccparams->thread_id);
3257  return NULL;
3258 }
3259 
3260 
3261 static void convert_rgb_to_uyvy_frame(uint8_t *rgbdata, int hsize, int vsize, int rowstride, int orowstride,
3262  uyvy_macropixel *u, boolean has_alpha, int clamping, uint8_t *gamma_lut, int thread_id) {
3263  // for odd sized widths, cut the rightmost pixel
3264  int hs3, ipsize = 3, ipsize2;
3265  uint8_t *end;
3266  int i;
3267 
3268  int x = 3, y = 4, z = 5;
3269  hsize = (hsize >> 1) << 1;
3270 
3271  if (thread_id == -1) {
3272  if (LIVES_UNLIKELY(!conv_RY_inited)) init_RGB_to_YUV_tables();
3273  set_conversion_arrays(clamping, WEED_YUV_SUBSPACE_YCBCR);
3274  }
3275 
3276  end = rgbdata + rowstride * vsize;
3277 
3278  if (thread_id == -1 && prefs->nfx_threads > 1) {
3279  lives_thread_t threads[prefs->nfx_threads];
3280  int nthreads = 1;
3281  int dheight, xdheight;
3283 
3284  xdheight = CEIL((double)vsize / (double)prefs->nfx_threads, 4);
3285  for (i = prefs->nfx_threads - 1; i >= 0; i--) {
3286  dheight = xdheight;
3287 
3288  if ((rgbdata + dheight * i * rowstride) < end) {
3289  ccparams[i].src = rgbdata + dheight * i * rowstride;
3290  ccparams[i].hsize = hsize;
3291  ccparams[i].dest = u + dheight * i * orowstride / 4;
3292 
3293  if (dheight * (i + 1) > (vsize - 4)) {
3294  dheight = vsize - (dheight * i);
3295  }
3296 
3297  ccparams[i].vsize = dheight;
3298 
3299  ccparams[i].irowstrides[0] = rowstride;
3300  ccparams[i].orowstrides[0] = orowstride;
3301  ccparams[i].in_alpha = has_alpha;
3302  ccparams[i].out_clamping = clamping;
3303  ccparams[i].lut = gamma_lut;
3304  ccparams[i].thread_id = i;
3305 
3306  if (i == 0) convert_rgb_to_uyvy_frame_thread(&ccparams[i]);
3307  else {
3308  lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_rgb_to_uyvy_frame_thread, &ccparams[i]);
3309  nthreads++;
3310  }
3311  }
3312  }
3313 
3314  for (i = 1; i < nthreads; i++) {
3315  lives_thread_join(threads[i], NULL);
3316  }
3317  lives_free(ccparams);
3318  if (gamma_lut) lives_gamma_lut_free(gamma_lut);
3319  return;
3320  }
3321 
3322  if (has_alpha) {
3323  z++;
3324  y++;
3325  x++;
3326  ipsize = 4;
3327  }
3328 
3329  ipsize2 = ipsize * 2;
3330  hs3 = hsize * ipsize;
3331  orowstride = orowstride / 2 - hsize;
3332  for (int k = 0; k < vsize; k++) {
3333  for (i = 0; i < hs3; i += ipsize2) {
3334  // convert 6 RGBRGB bytes to 4 UYVY bytes
3335  if (gamma_lut)
3336  rgb2uyvy_with_gamma(rgbdata[i], rgbdata[i + 1], rgbdata[i + 2], rgbdata[i + x], rgbdata[i + y],
3337  rgbdata[i + z], u++, gamma_lut);
3338  else
3339  rgb2uyvy(rgbdata[i], rgbdata[i + 1], rgbdata[i + 2], rgbdata[i + x], rgbdata[i + y], rgbdata[i + z], u++);
3340  }
3341  rgbdata += rowstride;
3342  u += orowstride;
3343  }
3344 }
3345 
3346 
3347 static void *convert_rgb_to_uyvy_frame_thread(void *data) {
3348  lives_cc_params *ccparams = (lives_cc_params *)data;
3349  convert_rgb_to_uyvy_frame((uint8_t *)ccparams->src, ccparams->hsize, ccparams->vsize, ccparams->irowstrides[0],
3350  ccparams->orowstrides[0],
3351  (uyvy_macropixel *)ccparams->dest, ccparams->in_alpha, ccparams->out_clamping, ccparams->lut,
3352  ccparams->thread_id);
3353  return NULL;
3354 }
3355 
3356 
3357 static void convert_rgb_to_yuyv_frame(uint8_t *rgbdata, int hsize, int vsize, int rowstride, int orowstride,
3358  yuyv_macropixel *u, boolean has_alpha, int clamping, uint8_t *gamma_lut, int thread_id) {
3359  // for odd sized widths, cut the rightmost pixel
3360  int hs3, ipsize = 3, ipsize2;
3361  uint8_t *end = rgbdata + rowstride * vsize;
3362  int i;
3363 
3364  int x = 3, y = 4, z = 5;
3365  hsize = (hsize >> 1) << 1;
3366 
3367  if (LIVES_UNLIKELY(!conv_RY_inited)) init_RGB_to_YUV_tables();
3368  if (thread_id == -1)
3369  set_conversion_arrays(clamping, WEED_YUV_SUBSPACE_YCBCR);
3370 
3371  if (thread_id == -1 && prefs->nfx_threads > 1) {
3372  lives_thread_t threads[prefs->nfx_threads];
3373  int nthreads = 1;
3374  int dheight, xdheight;
3376 
3377  xdheight = CEIL((double)vsize / (double)prefs->nfx_threads, 4);
3378  for (i = prefs->nfx_threads - 1; i >= 0; i--) {
3379  dheight = xdheight;
3380 
3381  if ((rgbdata + dheight * i * rowstride) < end) {
3382  ccparams[i].src = rgbdata + dheight * i * rowstride;
3383  ccparams[i].hsize = hsize;
3384  ccparams[i].dest = u + dheight * i * orowstride / 4;
3385 
3386  if (dheight * (i + 1) > (vsize - 4)) {
3387  dheight = vsize - (dheight * i);
3388  }
3389 
3390  ccparams[i].vsize = dheight;
3391 
3392  ccparams[i].irowstrides[0] = rowstride;
3393  ccparams[i].orowstrides[0] = orowstride;
3394  ccparams[i].in_alpha = has_alpha;
3395  ccparams[i].out_clamping = clamping;
3396  ccparams[i].lut = gamma_lut;
3397  ccparams[i].thread_id = i;
3398 
3399  if (i == 0) convert_rgb_to_yuyv_frame_thread(&ccparams[i]);
3400  else {
3401  lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_rgb_to_yuyv_frame_thread, &ccparams[i]);
3402  nthreads++;
3403  }
3404  }
3405  }
3406 
3407  for (i = 1; i < nthreads; i++) {
3408  lives_thread_join(threads[i], NULL);
3409  }
3410  lives_free(ccparams);
3411  if (gamma_lut) lives_gamma_lut_free(gamma_lut);
3412  return;
3413  }
3414 
3415  if (has_alpha) {
3416  z++;
3417  y++;
3418  x++;
3419  ipsize = 4;
3420  }
3421 
3422  ipsize2 = ipsize * 2;
3423  hs3 = hsize * ipsize;
3424  orowstride = orowstride / 2 - hsize;
3425 
3426  for (; rgbdata < end; rgbdata += rowstride) {
3427  for (i = 0; i < hs3; i += ipsize2) {
3428  // convert 6 RGBRGB bytes to 4 YUYV bytes
3429  if (gamma_lut)
3430  rgb2yuyv_with_gamma(rgbdata[i], rgbdata[i + 1], rgbdata[i + 2], rgbdata[i + x], rgbdata[i + y],
3431  rgbdata[i + z], u++, gamma_lut);
3432  else
3433  rgb2yuyv(rgbdata[i], rgbdata[i + 1], rgbdata[i + 2], rgbdata[i + x], rgbdata[i + y], rgbdata[i + z], u++);
3434  }
3435  u += orowstride;
3436  }
3437 }
3438 
3439 
3440 static void *convert_rgb_to_yuyv_frame_thread(void *data) {
3441  lives_cc_params *ccparams = (lives_cc_params *)data;
3442  convert_rgb_to_yuyv_frame((uint8_t *)ccparams->src, ccparams->hsize, ccparams->vsize, ccparams->irowstrides[0],
3443  ccparams->orowstrides[0],
3444  (yuyv_macropixel *)ccparams->dest, ccparams->in_alpha, ccparams->out_clamping, ccparams->lut, ccparams->thread_id);
3445  return NULL;
3446 }
3447 
3448 
3449 static void convert_bgr_to_uyvy_frame(uint8_t *rgbdata, int hsize, int vsize, int rowstride, int orowstride,
3450  uyvy_macropixel *u, boolean has_alpha, int clamping, uint8_t *gamma_lut, int thread_id) {
3451  // for odd sized widths, cut the rightmost pixel
3452  int hs3, ipsize = 3, ipsize2;
3453  uint8_t *end = rgbdata + rowstride * vsize;
3454  int i;
3455 
3456  int x = 3, y = 4, z = 5;
3457  hsize = (hsize >> 1) << 1;
3458 
3459  if (LIVES_UNLIKELY(!conv_RY_inited)) init_RGB_to_YUV_tables();
3460  if (thread_id == -1)
3461  set_conversion_arrays(clamping, WEED_YUV_SUBSPACE_YCBCR);
3462 
3463  if (thread_id == -1 && prefs->nfx_threads > 1) {
3464  lives_thread_t threads[prefs->nfx_threads];
3465  int nthreads = 1;
3466  int dheight, xdheight;
3468 
3469  xdheight = CEIL((double)vsize / (double)prefs->nfx_threads, 4);
3470  for (i = prefs->nfx_threads - 1; i >= 0; i--) {
3471  dheight = xdheight;
3472 
3473  if ((rgbdata + dheight * i * rowstride) < end) {
3474  ccparams[i].src = rgbdata + dheight * i * rowstride;
3475  ccparams[i].hsize = hsize;
3476  ccparams[i].dest = u + dheight * i * orowstride / 4;
3477 
3478  if (dheight * (i + 1) > (vsize - 4)) {
3479  dheight = vsize - (dheight * i);
3480  }
3481 
3482  ccparams[i].vsize = dheight;
3483 
3484  ccparams[i].irowstrides[0] = rowstride;
3485  ccparams[i].orowstrides[0] = orowstride;
3486  ccparams[i].in_alpha = has_alpha;
3487  ccparams[i].out_clamping = clamping;
3488  ccparams[i].lut = gamma_lut;
3489  ccparams[i].thread_id = i;
3490 
3491  if (i == 0) convert_bgr_to_uyvy_frame_thread(&ccparams[i]);
3492  else {
3493  lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_bgr_to_uyvy_frame_thread, &ccparams[i]);
3494  nthreads++;
3495  }
3496  }
3497  }
3498 
3499  for (i = 1; i < nthreads; i++) {
3500  lives_thread_join(threads[i], NULL);
3501  }
3502  lives_free(ccparams);
3503  if (gamma_lut) lives_gamma_lut_free(gamma_lut);
3504  return;
3505  }
3506 
3507  if (has_alpha) {
3508  z++;
3509  y++;
3510  x++;
3511  ipsize = 4;
3512  }
3513 
3514  ipsize2 = ipsize * 2;
3515  hs3 = hsize * ipsize;
3516  orowstride = orowstride / 2 - hsize;
3517 
3518  for (; rgbdata < end; rgbdata += rowstride) {
3519  for (i = 0; i < hs3; i += ipsize2) {
3520  //convert 6 RGBRGB bytes to 4 UYVY bytes
3521  if (gamma_lut)
3522  rgb2uyvy_with_gamma(rgbdata[i + 2], rgbdata[i + 1], rgbdata[i], rgbdata[i + z], rgbdata[i + y],
3523  rgbdata[i + x], u++, gamma_lut);
3524  else
3525  rgb2uyvy(rgbdata[i + 2], rgbdata[i + 1], rgbdata[i], rgbdata[i + z], rgbdata[i + y], rgbdata[i + x], u++);
3526  }
3527  u += orowstride;
3528  }
3529 }
3530 
3531 
3532 static void *convert_bgr_to_uyvy_frame_thread(void *data) {
3533  lives_cc_params *ccparams = (lives_cc_params *)data;
3534  convert_bgr_to_uyvy_frame((uint8_t *)ccparams->src, ccparams->hsize, ccparams->vsize, ccparams->irowstrides[0],
3535  ccparams->orowstrides[0],
3536  (uyvy_macropixel *)ccparams->dest, ccparams->in_alpha, ccparams->out_clamping, ccparams->lut, ccparams->thread_id);
3537  return NULL;
3538 }
3539 
3540 
3541 static void convert_bgr_to_yuyv_frame(uint8_t *rgbdata, int hsize, int vsize, int rowstride, int orowstride,
3542  yuyv_macropixel *u, boolean has_alpha, int clamping, uint8_t *gamma_lut, int thread_id) {
3543  // for odd sized widths, cut the rightmost pixel
3544  int hs3, ipsize = 3, ipsize2;
3545 
3546  uint8_t *end = rgbdata + rowstride * vsize;
3547  int i;
3548 
3549  int x = 3, y = 4, z = 5;
3550 
3551  hsize = (hsize >> 1) << 1;
3552 
3553  if (LIVES_UNLIKELY(!conv_RY_inited)) init_RGB_to_YUV_tables();
3554  if (thread_id == -1)
3555  set_conversion_arrays(clamping, WEED_YUV_SUBSPACE_YCBCR);
3556 
3557  if (thread_id == -1 && prefs->nfx_threads > 1) {
3558  lives_thread_t threads[prefs->nfx_threads];
3559  int nthreads = 1;
3560  int dheight, xdheight;
3562 
3563  xdheight = CEIL((double)vsize / (double)prefs->nfx_threads, 4);
3564  for (i = prefs->nfx_threads - 1; i >= 0; i--) {
3565  dheight = xdheight;
3566 
3567  if ((rgbdata + dheight * i * rowstride) < end) {
3568  ccparams[i].src = rgbdata + dheight * i * rowstride;
3569  ccparams[i].hsize = hsize;
3570  ccparams[i].dest = u + dheight * i * orowstride / 4;
3571 
3572  if (dheight * (i + 1) > (vsize - 4)) {
3573  dheight = vsize - (dheight * i);
3574  }
3575 
3576  ccparams[i].vsize = dheight;
3577 
3578  ccparams[i].irowstrides[0] = rowstride;
3579  ccparams[i].orowstrides[0] = orowstride;
3580  ccparams[i].in_alpha = has_alpha;
3581  ccparams[i].out_clamping = clamping;
3582  ccparams[i].lut = gamma_lut;
3583  ccparams[i].thread_id = i;
3584 
3585  if (i == 0) convert_bgr_to_yuyv_frame_thread(&ccparams[i]);
3586  else {
3587  lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_bgr_to_yuyv_frame_thread, &ccparams[i]);
3588  nthreads++;
3589  }
3590  }
3591  }
3592 
3593  for (i = 1; i < nthreads; i++) {
3594  lives_thread_join(threads[i], NULL);
3595  }
3596  lives_free(ccparams);
3597  if (gamma_lut) lives_gamma_lut_free(gamma_lut);
3598  return;
3599  }
3600 
3601  if (has_alpha) {
3602  z++;
3603  y++;
3604  x++;
3605  ipsize = 4;
3606  }
3607 
3608  ipsize2 = ipsize * 2;
3609  hs3 = hsize * ipsize;
3610  orowstride = orowstride / 2 - hsize;
3611 
3612  for (; rgbdata < end; rgbdata += rowstride) {
3613  for (i = 0; i < hs3; i += ipsize2) {
3614  // convert 6 RGBRGB bytes to 4 UYVY bytes
3615  if (gamma_lut)
3616  rgb2yuyv_with_gamma(rgbdata[i + 2], rgbdata[i + 1], rgbdata[i], rgbdata[i + z], rgbdata[i + y],
3617  rgbdata[i + x], u++, gamma_lut);
3618  else
3619  rgb2yuyv(rgbdata[i + 2], rgbdata[i + 1], rgbdata[i], rgbdata[i + z], rgbdata[i + y], rgbdata[i + x], u++);
3620  }
3621  u += orowstride;
3622  }
3623 }
3624 
3625 
3626 static void *convert_bgr_to_yuyv_frame_thread(void *data) {
3627  lives_cc_params *ccparams = (lives_cc_params *)data;
3628  convert_bgr_to_yuyv_frame((uint8_t *)ccparams->src, ccparams->hsize, ccparams->vsize, ccparams->irowstrides[0],
3629  ccparams->orowstrides[0],
3630  (yuyv_macropixel *)ccparams->dest, ccparams->in_alpha, ccparams->out_clamping, ccparams->lut, ccparams->thread_id);
3631  return NULL;
3632 }
3633 
3634 
3635 static void convert_argb_to_uyvy_frame(uint8_t *rgbdata, int hsize, int vsize, int rowstride, int orowstride,
3636  uyvy_macropixel *u, int clamping, uint8_t *gamma_lut, int thread_id) {
3637  // for odd sized widths, cut the rightmost pixel
3638  int hs3, ipsize = 4, ipsize2;
3639  uint8_t *end;
3640  int i;
3641 
3642  if (LIVES_UNLIKELY(!conv_RY_inited)) init_RGB_to_YUV_tables();
3643  if (thread_id == -1)
3644  set_conversion_arrays(clamping, WEED_YUV_SUBSPACE_YCBCR);
3645 
3646  end = rgbdata + rowstride * vsize;
3647  hsize = (hsize >> 1) << 1;
3648 
3649  if (thread_id == -1 && prefs->nfx_threads > 1) {
3650  lives_thread_t threads[prefs->nfx_threads];
3651  int nthreads = 1;
3652  int dheight, xdheight;
3654 
3655  xdheight = CEIL((double)vsize / (double)prefs->nfx_threads, 4);
3656  for (i = prefs->nfx_threads - 1; i >= 0; i--) {
3657  dheight = xdheight;
3658 
3659  if ((rgbdata + dheight * i * rowstride) < end) {
3660  ccparams[i].src = rgbdata + dheight * i * rowstride;
3661  ccparams[i].hsize = hsize;
3662  ccparams[i].dest = u + dheight * i * orowstride / 4;
3663 
3664  if (dheight * (i + 1) > (vsize - 4)) {
3665  dheight = vsize - (dheight * i);
3666  }
3667 
3668  ccparams[i].vsize = dheight;
3669 
3670  ccparams[i].irowstrides[0] = rowstride;
3671  ccparams[i].orowstrides[0] = orowstride;
3672  ccparams[i].out_clamping = clamping;
3673  ccparams[i].lut = gamma_lut;
3674  ccparams[i].thread_id = i;
3675 
3676  if (i == 0) convert_argb_to_uyvy_frame_thread(&ccparams[i]);
3677  else {
3678  lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_argb_to_uyvy_frame_thread, &ccparams[i]);
3679  nthreads++;
3680  }
3681  }
3682  }
3683 
3684  for (i = 1; i < nthreads; i++) {
3685  lives_thread_join(threads[i], NULL);
3686  }
3687  lives_free(ccparams);
3688  if (gamma_lut) lives_gamma_lut_free(gamma_lut);
3689  return;
3690  }
3691 
3692  ipsize2 = ipsize * 2;
3693  hs3 = hsize * ipsize;
3694  orowstride = orowstride / 2 - hsize;
3695 
3696  for (; rgbdata < end; rgbdata += rowstride) {
3697  for (i = 0; i < hs3; i += ipsize2) {
3698  // convert 6 RGBRGB bytes to 4 UYVY bytes
3699  if (gamma_lut)
3700  rgb2uyvy_with_gamma(rgbdata[i + 1], rgbdata[i + 2], rgbdata[i + 3], rgbdata[i + 5], rgbdata[i + 6],
3701  rgbdata[i + 7], u++, gamma_lut);
3702  else
3703  rgb2uyvy(rgbdata[i + 1], rgbdata[i + 2], rgbdata[i + 3], rgbdata[i + 5], rgbdata[i + 6], rgbdata[i + 7], u++);
3704  }
3705  u += orowstride;
3706  }
3707 }
3708 
3709 
3710 static void *convert_argb_to_uyvy_frame_thread(void *data) {
3711  lives_cc_params *ccparams = (lives_cc_params *)data;
3712  convert_argb_to_uyvy_frame((uint8_t *)ccparams->src, ccparams->hsize, ccparams->vsize, ccparams->irowstrides[0],
3713  ccparams->orowstrides[0],
3714  (uyvy_macropixel *)ccparams->dest, ccparams->out_clamping, ccparams->lut, ccparams->thread_id);
3715  return NULL;
3716 }
3717 
3718 
3719 static void convert_argb_to_yuyv_frame(uint8_t *rgbdata, int hsize, int vsize, int rowstride, int orowstride,
3720  yuyv_macropixel *u, int clamping, uint8_t *gamma_lut, int thread_id) {
3721  // for odd sized widths, cut the rightmost pixel
3722  int hs3, ipsize = 4, ipsize2;
3723  uint8_t *end;
3724  register int i;
3725 
3726  if (LIVES_UNLIKELY(!conv_RY_inited)) init_RGB_to_YUV_tables();
3727  if (thread_id == -1)
3728  set_conversion_arrays(clamping, WEED_YUV_SUBSPACE_YCBCR);
3729 
3730  end = rgbdata + rowstride * vsize;
3731  hsize = (hsize >> 1) << 1;
3732 
3733  if (thread_id == -1 && prefs->nfx_threads > 1) {
3734  lives_thread_t threads[prefs->nfx_threads];
3735  int nthreads = 1;
3736  int dheight, xdheight;
3738 
3739  xdheight = CEIL((double)vsize / (double)prefs->nfx_threads, 4);
3740  for (i = prefs->nfx_threads - 1; i >= 0; i--) {
3741  dheight = xdheight;
3742 
3743  if ((rgbdata + dheight * i * rowstride) < end) {
3744  ccparams[i].src = rgbdata + dheight * i * rowstride;
3745  ccparams[i].hsize = hsize;
3746  ccparams[i].dest = u + dheight * i * orowstride / 4;
3747 
3748  if (dheight * (i + 1) > (vsize - 4)) {
3749  dheight = vsize - (dheight * i);
3750  }
3751 
3752  ccparams[i].vsize = dheight;
3753 
3754  ccparams[i].irowstrides[0] = rowstride;
3755  ccparams[i].orowstrides[0] = orowstride;
3756  ccparams[i].out_clamping = clamping;
3757  ccparams[i].lut = gamma_lut;
3758  ccparams[i].thread_id = i;
3759 
3760  if (i == 0) convert_argb_to_yuyv_frame_thread(&ccparams[i]);
3761  else {
3762  lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_argb_to_yuyv_frame_thread, &ccparams[i]);
3763  nthreads++;
3764  }
3765  }
3766  }
3767 
3768  for (i = 1; i < nthreads; i++) {
3769  lives_thread_join(threads[i], NULL);
3770  }
3771  lives_free(ccparams);
3772  if (gamma_lut) lives_gamma_lut_free(gamma_lut);
3773  return;
3774  }
3775 
3776  ipsize2 = ipsize * 2;
3777  hs3 = hsize * ipsize;
3778  orowstride = orowstride / 2 - hsize;
3779  for (; rgbdata < end; rgbdata += rowstride) {
3780  for (i = 0; i < hs3; i += ipsize2) {
3781  // convert 6 RGBRGB bytes to 4 UYVY bytes
3782  if (gamma_lut)
3783  rgb2yuyv_with_gamma(rgbdata[i + 1], rgbdata[i + 2], rgbdata[i + 3], rgbdata[i + 5], rgbdata[i + 6],
3784  rgbdata[i + 7], u++, gamma_lut);
3785  else
3786  rgb2yuyv(rgbdata[i + 1], rgbdata[i + 2], rgbdata[i + 3], rgbdata[i + 5], rgbdata[i + 6], rgbdata[i + 7], u++);
3787  }
3788  u += orowstride;
3789  }
3790 }
3791 
3792 
3793 static void *convert_argb_to_yuyv_frame_thread(void *data) {
3794  lives_cc_params *ccparams = (lives_cc_params *)data;
3795  convert_argb_to_yuyv_frame((uint8_t *)ccparams->src, ccparams->hsize, ccparams->vsize, ccparams->irowstrides[0],
3796  ccparams->orowstrides[0],
3797  (yuyv_macropixel *)ccparams->dest, ccparams->out_clamping, ccparams->lut, ccparams->thread_id);
3798  return NULL;
3799 }
3800 
3801 
3802 static void convert_rgb_to_yuv_frame(uint8_t *rgbdata, int hsize, int vsize, int rowstride, int orow,
3803  uint8_t *u, boolean in_has_alpha, boolean out_has_alpha, int clamping, int thread_id) {
3804  int ipsize = 3, opsize = 3;
3805  int iwidth;
3806  uint8_t *end = rgbdata + (rowstride * vsize);
3807  register int i;
3808  uint8_t in_alpha = 255;
3809 
3810  if (LIVES_UNLIKELY(!conv_RY_inited)) init_RGB_to_YUV_tables();
3811  if (thread_id == -1)
3812  set_conversion_arrays(clamping, WEED_YUV_SUBSPACE_YCBCR);
3813 
3814  if (thread_id == -1 && prefs->nfx_threads > 1) {
3815  lives_thread_t threads[prefs->nfx_threads];
3816  int nthreads = 1;
3817  int dheight, xdheight;
3819 
3820  xdheight = CEIL((double)vsize / (double)prefs->nfx_threads, 4);
3821  for (i = prefs->nfx_threads - 1; i >= 0; i--) {
3822  dheight = xdheight;
3823 
3824  if ((rgbdata + dheight * i * rowstride) < end) {
3825  ccparams[i].src = rgbdata + dheight * i * rowstride;
3826  ccparams[i].hsize = hsize;
3827  ccparams[i].dest = u + dheight * i * orow;
3828 
3829  if (dheight * (i + 1) > (vsize - 4)) {
3830  dheight = vsize - (dheight * i);
3831  }
3832 
3833  ccparams[i].vsize = dheight;
3834 
3835  ccparams[i].irowstrides[0] = rowstride;
3836  ccparams[i].orowstrides[0] = orow;
3837  ccparams[i].in_alpha = in_has_alpha;
3838  ccparams[i].out_alpha = out_has_alpha;
3839  ccparams[i].out_clamping = clamping;
3840  ccparams[i].thread_id = i;
3841 
3842  if (i == 0) convert_rgb_to_yuv_frame_thread(&ccparams[i]);
3843  else {
3844  lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_rgb_to_yuv_frame_thread, &ccparams[i]);
3845  nthreads++;
3846  }
3847  }
3848  }
3849 
3850  for (i = 1; i < nthreads; i++) {
3851  lives_thread_join(threads[i], NULL);
3852  }
3853  lives_free(ccparams);
3854  return;
3855  }
3856 
3857  if (in_has_alpha) ipsize = 4;
3858  if (out_has_alpha) opsize = 4;
3859 
3860  hsize = (hsize >> 1) << 1;
3861  iwidth = hsize * ipsize;
3862  orow -= hsize * opsize;
3863 
3864  for (; rgbdata < end; rgbdata += rowstride) {
3865  for (i = 0; i < iwidth; i += ipsize) {
3866  if (in_has_alpha) in_alpha = rgbdata[i + 3];
3867  if (out_has_alpha) u[3] = in_alpha;
3868  rgb2yuv(rgbdata[i], rgbdata[i + 1], rgbdata[i + 2], &(u[0]), &(u[1]), &(u[2]));
3869  u += opsize;
3870  }
3871  u += orow;
3872  }
3873 }
3874 
3875 
3876 static void *convert_rgb_to_yuv_frame_thread(void *data) {
3877  lives_cc_params *ccparams = (lives_cc_params *)data;
3878  convert_rgb_to_yuv_frame((uint8_t *)ccparams->src, ccparams->hsize, ccparams->vsize, ccparams->irowstrides[0],
3879  ccparams->orowstrides[0],
3880  (uint8_t *)ccparams->dest, ccparams->in_alpha, ccparams->out_alpha, ccparams->out_clamping,
3881  ccparams->thread_id);
3882  return NULL;
3883 }
3884 
3885 
3886 static void convert_rgb_to_yuvp_frame(uint8_t *rgbdata, int hsize, int vsize, int rowstride, int orow,
3887  uint8_t **yuvp, boolean in_has_alpha, boolean out_has_alpha, int clamping, int thread_id) {
3888  int ipsize = 3;
3889  int iwidth;
3890  uint8_t *end = rgbdata + (rowstride * vsize);
3891  register int i;
3892  uint8_t in_alpha = 255, *a = NULL;
3893 
3894  uint8_t *y, *u, *v;
3895 
3896  if (LIVES_UNLIKELY(!conv_RY_inited)) init_RGB_to_YUV_tables();
3897  if (thread_id == -1)
3898  set_conversion_arrays(clamping, WEED_YUV_SUBSPACE_YCBCR);
3899 
3900  y = yuvp[0];
3901  u = yuvp[1];
3902  v = yuvp[2];
3903  if (out_has_alpha) a = yuvp[3];
3904 
3905  if (thread_id == -1 && prefs->nfx_threads > 1) {
3906  lives_thread_t threads[prefs->nfx_threads];
3907  int nthreads = 1;
3908  int dheight, xdheight;
3910 
3911  xdheight = CEIL((double)vsize / (double)prefs->nfx_threads, 4);
3912  for (i = prefs->nfx_threads - 1; i >= 0; i--) {
3913  dheight = xdheight;
3914 
3915  if ((rgbdata + dheight * i * rowstride) < end) {
3916  ccparams[i].src = rgbdata + dheight * i * rowstride;
3917  ccparams[i].hsize = hsize;
3918 
3919  ccparams[i].destp[0] = y + dheight * i * orow;
3920  ccparams[i].destp[1] = u + dheight * i * orow;
3921  ccparams[i].destp[2] = v + dheight * i * orow;
3922  if (out_has_alpha) ccparams[i].destp[3] = a + dheight * i * orow;
3923 
3924  if (dheight * (i + 1) > (vsize - 4)) {
3925  dheight = vsize - (dheight * i);
3926  }
3927 
3928  ccparams[i].vsize = dheight;
3929 
3930  ccparams[i].irowstrides[0] = rowstride;
3931  ccparams[i].orowstrides[0] = orow;
3932  ccparams[i].in_alpha = in_has_alpha;
3933  ccparams[i].out_alpha = out_has_alpha;
3934  ccparams[i].out_clamping = clamping;
3935  ccparams[i].thread_id = i;
3936 
3937  if (i == 0) convert_rgb_to_yuvp_frame_thread(&ccparams[i]);
3938  else {
3939  lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_rgb_to_yuvp_frame_thread, &ccparams[i]);
3940  nthreads++;
3941  }
3942  }
3943  }
3944 
3945  for (i = 1; i < nthreads; i++) {
3946  lives_thread_join(threads[i], NULL);
3947  }
3948  lives_free(ccparams);
3949  return;
3950  }
3951 
3952  if (in_has_alpha) ipsize = 4;
3953 
3954  hsize = (hsize >> 1) << 1;
3955  iwidth = hsize * ipsize;
3956  orow -= hsize;
3957 
3958  for (; rgbdata < end; rgbdata += rowstride) {
3959  for (i = 0; i < iwidth; i += ipsize) {
3960  if (in_has_alpha) in_alpha = rgbdata[i + 3];
3961  if (out_has_alpha) *(a++) = in_alpha;
3962  rgb2yuv(rgbdata[i], rgbdata[i + 1], rgbdata[i + 2], y, u, v);
3963  y++;
3964  u++;
3965  v++;
3966  }
3967  y += orow;
3968  u += orow;
3969  v += orow;
3970  if (out_has_alpha) a += orow;
3971  }
3972 }
3973 
3974 
3975 static void *convert_rgb_to_yuvp_frame_thread(void *data) {
3976  lives_cc_params *ccparams = (lives_cc_params *)data;
3977  convert_rgb_to_yuvp_frame((uint8_t *)ccparams->src, ccparams->hsize, ccparams->vsize, ccparams->irowstrides[0],
3978  ccparams->orowstrides[0],
3979  (uint8_t **)ccparams->destp, ccparams->in_alpha, ccparams->out_alpha, ccparams->out_clamping,
3980  ccparams->thread_id);
3981  return NULL;
3982 }
3983 
3984 
3985 static void convert_bgr_to_yuv_frame(uint8_t *rgbdata, int hsize, int vsize, int rowstride, int orow,
3986  uint8_t *u, boolean in_has_alpha, boolean out_has_alpha, int clamping, int thread_id) {
3987  int ipsize = 3, opsize = 3;
3988  int iwidth;
3989  uint8_t *end = rgbdata + (rowstride * vsize);
3990  register int i;
3991  uint8_t in_alpha = 255;
3992 
3993  if (LIVES_UNLIKELY(!conv_RY_inited)) init_RGB_to_YUV_tables();
3994  if (thread_id == -1)
3995  set_conversion_arrays(clamping, WEED_YUV_SUBSPACE_YCBCR);
3996 
3997  if (thread_id == -1 && prefs->nfx_threads > 1) {
3998  lives_thread_t threads[prefs->nfx_threads];
3999  int nthreads = 1;
4000  int dheight, xdheight;
4002 
4003  xdheight = CEIL((double)vsize / (double)prefs->nfx_threads, 4);
4004  for (i = prefs->nfx_threads - 1; i >= 0; i--) {
4005  dheight = xdheight;
4006 
4007  if ((rgbdata + dheight * i * rowstride) < end) {
4008  ccparams[i].src = rgbdata + dheight * i * rowstride;
4009  ccparams[i].hsize = hsize;
4010  ccparams[i].dest = u + dheight * i * orow;
4011 
4012  if (dheight * (i + 1) > (vsize - 4)) {
4013  dheight = vsize - (dheight * i);
4014  }
4015 
4016  ccparams[i].vsize = dheight;
4017 
4018  ccparams[i].irowstrides[0] = rowstride;
4019  ccparams[i].in_alpha = in_has_alpha;
4020  ccparams[i].out_alpha = out_has_alpha;
4021  ccparams[i].out_clamping = clamping;
4022  ccparams[i].thread_id = i;
4023 
4024  if (i == 0) convert_bgr_to_yuv_frame_thread(&ccparams[i]);
4025  else {
4026  lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_bgr_to_yuv_frame_thread, &ccparams[i]);
4027  nthreads++;
4028  }
4029  }
4030  }
4031 
4032  for (i = 1; i < nthreads; i++) {
4033  lives_thread_join(threads[i], NULL);
4034  }
4035  lives_free(ccparams);
4036  return;
4037  }
4038 
4039  if (in_has_alpha) ipsize = 4;
4040  if (out_has_alpha) opsize = 4;
4041 
4042  hsize = (hsize >> 1) << 1;
4043  iwidth = hsize * ipsize;
4044  orow -= hsize * opsize;
4045 
4046  for (; rgbdata < end; rgbdata += rowstride) {
4047  for (i = 0; i < iwidth; i += ipsize) {
4048  bgr2yuv(rgbdata[i], rgbdata[i + 1], rgbdata[i + 2], &(u[0]), &(u[1]), &(u[2]));
4049  if (in_has_alpha) in_alpha = rgbdata[i + 3];
4050  if (out_has_alpha) u[3] = in_alpha;
4051  u += opsize;
4052  }
4053  u += orow;
4054  }
4055 }
4056 
4057 
4058 static void *convert_bgr_to_yuv_frame_thread(void *data) {
4059  lives_cc_params *ccparams = (lives_cc_params *)data;
4060  convert_bgr_to_yuv_frame((uint8_t *)ccparams->src, ccparams->hsize, ccparams->vsize, ccparams->irowstrides[0],
4061  ccparams->orowstrides[0],
4062  (uint8_t *)ccparams->dest, ccparams->in_alpha, ccparams->out_alpha, ccparams->out_clamping, ccparams->thread_id);
4063  return NULL;
4064 }
4065 
4066 
4067 static void convert_bgr_to_yuvp_frame(uint8_t *rgbdata, int hsize, int vsize, int rowstride, int orow,
4068  uint8_t **yuvp, boolean in_has_alpha, boolean out_has_alpha, int clamping, int thread_id) {
4069  // TESTED !
4070 
4071  int ipsize = 3;
4072  int iwidth;
4073  uint8_t *end = rgbdata + (rowstride * vsize);
4074  register int i;
4075  uint8_t in_alpha = 255, *a = NULL;
4076 
4077  uint8_t *y, *u, *v;
4078 
4079  if (LIVES_UNLIKELY(!conv_RY_inited)) init_RGB_to_YUV_tables();
4080  if (thread_id == -1)
4081  set_conversion_arrays(clamping, WEED_YUV_SUBSPACE_YCBCR);
4082 
4083  y = yuvp[0];
4084  u = yuvp[1];
4085  v = yuvp[2];
4086  if (out_has_alpha) a = yuvp[3];
4087 
4088  if (thread_id == -1 && prefs->nfx_threads > 1) {
4089  lives_thread_t threads[prefs->nfx_threads];
4090  int nthreads = 1;
4091  int dheight, xdheight;
4093 
4094  xdheight = CEIL((double)vsize / (double)prefs->nfx_threads, 4);
4095  for (i = prefs->nfx_threads - 1; i >= 0; i--) {
4096  dheight = xdheight;
4097 
4098  if ((rgbdata + dheight * i * rowstride) < end) {
4099  ccparams[i].src = rgbdata + dheight * i * rowstride;
4100  ccparams[i].hsize = hsize;
4101 
4102  ccparams[i].destp[0] = y + dheight * i * orow;
4103  ccparams[i].destp[1] = u + dheight * i * orow;
4104  ccparams[i].destp[2] = v + dheight * i * orow;
4105  if (out_has_alpha) ccparams[i].destp[3] = a + dheight * i * orow;
4106 
4107  if (dheight * (i + 1) > (vsize - 4)) {
4108  dheight = vsize - (dheight * i);
4109  }
4110 
4111  ccparams[i].vsize = dheight;
4112 
4113  ccparams[i].irowstrides[0] = rowstride;
4114  ccparams[i].orowstrides[0] = orow;
4115  ccparams[i].in_alpha = in_has_alpha;
4116  ccparams[i].out_alpha = out_has_alpha;
4117  ccparams[i].out_clamping = clamping;
4118  ccparams[i].thread_id = i;
4119 
4120  if (i == 0) convert_bgr_to_yuvp_frame_thread(&ccparams[i]);
4121  else {
4122  lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_bgr_to_yuvp_frame_thread, &ccparams[i]);
4123  nthreads++;
4124  }
4125  }
4126  }
4127 
4128  for (i = 1; i < nthreads; i++) {
4129  lives_thread_join(threads[i], NULL);
4130  }
4131  lives_free(ccparams);
4132  return;
4133  }
4134 
4135  if (in_has_alpha) ipsize = 4;
4136 
4137  hsize = (hsize >> 1) << 1;
4138  iwidth = hsize * ipsize;
4139  orow -= hsize;
4140 
4141  for (; rgbdata < end; rgbdata += rowstride) {
4142  for (i = 0; i < iwidth; i += ipsize) {
4143  bgr2yuv(rgbdata[i], rgbdata[i + 1], rgbdata[i + 2], &(y[0]), &(u[0]), &(v[0]));
4144  if (in_has_alpha) in_alpha = rgbdata[i + 3];
4145  if (out_has_alpha) *(a++) = in_alpha;
4146  y++;
4147  u++;
4148  v++;
4149  }
4150  y += orow;
4151  u += orow;
4152  v += orow;
4153  if (out_has_alpha) a += orow;
4154  }
4155 }
4156 
4157 
4158 static void *convert_bgr_to_yuvp_frame_thread(void *data) {
4159  lives_cc_params *ccparams = (lives_cc_params *)data;
4160  convert_bgr_to_yuvp_frame((uint8_t *)ccparams->src, ccparams->hsize, ccparams->vsize, ccparams->irowstrides[0],
4161  ccparams->orowstrides[0],
4162  (uint8_t **)ccparams->destp, ccparams->in_alpha, ccparams->out_alpha, ccparams->out_clamping,
4163  ccparams->thread_id);
4164  return NULL;
4165 }
4166 
4167 
4168 static void convert_argb_to_yuv_frame(uint8_t *rgbdata, int hsize, int vsize, int rowstride, int orow,
4169  uint8_t *u, boolean out_has_alpha, int clamping, int thread_id) {
4170  int ipsize = 4, opsize = 3;
4171  int iwidth;
4172  uint8_t *end = rgbdata + (rowstride * vsize);
4173  register int i;
4174 
4175  if (LIVES_UNLIKELY(!conv_RY_inited)) init_RGB_to_YUV_tables();
4176  if (thread_id == -1)
4177  set_conversion_arrays(clamping, WEED_YUV_SUBSPACE_YCBCR);
4178 
4179  if (thread_id == -1 && prefs->nfx_threads > 1) {
4180  lives_thread_t threads[prefs->nfx_threads];
4181  int nthreads = 1;
4182  int dheight, xdheight;
4184 
4185  xdheight = CEIL((double)vsize / (double)prefs->nfx_threads, 4);
4186  for (i = prefs->nfx_threads - 1; i >= 0; i--) {
4187  dheight = xdheight;
4188 
4189  if ((rgbdata + dheight * i * rowstride) < end) {
4190  ccparams[i].src = rgbdata + dheight * i * rowstride;
4191  ccparams[i].hsize = hsize;
4192 
4193  ccparams[i].dest = u + dheight * i * orow;
4194 
4195  if (dheight * (i + 1) > (vsize - 4)) {
4196  dheight = vsize - (dheight * i);
4197  }
4198 
4199  ccparams[i].vsize = dheight;
4200 
4201  ccparams[i].irowstrides[0] = rowstride;
4202  ccparams[i].orowstrides[0] = orow;
4203  ccparams[i].out_alpha = out_has_alpha;
4204  ccparams[i].out_clamping = clamping;
4205  ccparams[i].thread_id = i;
4206 
4207  if (i == 0) convert_rgb_to_yuv_frame_thread(&ccparams[i]);
4208  else {
4209  lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_argb_to_yuv_frame_thread, &ccparams[i]);
4210  nthreads++;
4211  }
4212  }
4213  }
4214 
4215  for (i = 1; i < nthreads; i++) {
4216  lives_thread_join(threads[i], NULL);
4217  }
4218  lives_free(ccparams);
4219  return;
4220  }
4221 
4222  if (out_has_alpha) opsize = 4;
4223 
4224  hsize = (hsize >> 1) << 1;
4225  iwidth = hsize * ipsize;
4226  orow -= hsize * opsize;
4227 
4228  for (; rgbdata < end; rgbdata += rowstride) {
4229  for (i = 0; i < iwidth; i += ipsize) {
4230  if (out_has_alpha) u[3] = rgbdata[i];
4231  rgb2yuv(rgbdata[i + 1], rgbdata[i + 2], rgbdata[i + 3], &(u[0]), &(u[1]), &(u[2]));
4232  u += opsize;
4233  }
4234  u += orow;
4235  }
4236 }
4237 
4238 
4239 static void *convert_argb_to_yuv_frame_thread(void *data) {
4240  lives_cc_params *ccparams = (lives_cc_params *)data;
4241  convert_argb_to_yuv_frame((uint8_t *)ccparams->src, ccparams->hsize, ccparams->vsize, ccparams->irowstrides[0],
4242  ccparams->orowstrides[0],
4243  (uint8_t *)ccparams->dest, ccparams->out_alpha, ccparams->out_clamping, ccparams->thread_id);
4244  return NULL;
4245 }
4246 
4247 
4248 static void convert_argb_to_yuvp_frame(uint8_t *rgbdata, int hsize, int vsize, int rowstride, int orow,
4249  uint8_t **yuvp, boolean out_has_alpha, int clamping, int thread_id) {
4250  int ipsize = 4;
4251  int iwidth;
4252  uint8_t *end = rgbdata + (rowstride * vsize);
4253  register int i;
4254  uint8_t *a = NULL;
4255  uint8_t *y, *u, *v;
4256 
4257  if (LIVES_UNLIKELY(!conv_RY_inited)) init_RGB_to_YUV_tables();
4258  if (thread_id == -1)
4259  set_conversion_arrays(clamping, WEED_YUV_SUBSPACE_YCBCR);
4260 
4261  y = yuvp[0];
4262  u = yuvp[1];
4263  v = yuvp[2];
4264  if (out_has_alpha) a = yuvp[3];
4265 
4266  if (thread_id == -1 && prefs->nfx_threads > 1) {
4267  lives_thread_t threads[prefs->nfx_threads];
4268  int nthreads = 1;
4269  int dheight, xdheight;
4271 
4272  xdheight = CEIL((double)vsize / (double)prefs->nfx_threads, 4);
4273  for (i = prefs->nfx_threads - 1; i >= 0; i--) {
4274  dheight = xdheight;
4275 
4276  if ((rgbdata + dheight * i * rowstride) < end) {
4277  ccparams[i].src = rgbdata + dheight * i * rowstride;
4278  ccparams[i].hsize = hsize;
4279 
4280  ccparams[i].destp[0] = y + dheight * i * orow;
4281  ccparams[i].destp[1] = u + dheight * i * orow;
4282  ccparams[i].destp[2] = v + dheight * i * orow;
4283  if (out_has_alpha) ccparams[i].destp[3] = a + dheight * i * orow;
4284 
4285  if (dheight * (i + 1) > (vsize - 4)) {
4286  dheight = vsize - (dheight * i);
4287  }
4288 
4289  ccparams[i].vsize = dheight;
4290 
4291  ccparams[i].irowstrides[0] = rowstride;
4292  ccparams[i].orowstrides[0] = orow;
4293  ccparams[i].out_alpha = out_has_alpha;
4294  ccparams[i].out_clamping = clamping;
4295  ccparams[i].thread_id = i;
4296 
4297  if (i == 0) convert_argb_to_yuvp_frame_thread(&ccparams[i]);
4298  else {
4299  lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_argb_to_yuvp_frame_thread, &ccparams[i]);
4300  nthreads++;
4301  }
4302  }
4303  }
4304 
4305  for (i = 1; i < nthreads; i++) {
4306  lives_thread_join(threads[i], NULL);
4307  }
4308  lives_free(ccparams);
4309  return;
4310  }
4311 
4312  hsize = (hsize >> 1) << 1;
4313  iwidth = hsize * ipsize;
4314  orow -= hsize;
4315 
4316  for (; rgbdata < end; rgbdata += rowstride) {
4317  for (i = 0; i < iwidth; i += ipsize) {
4318  if (out_has_alpha) *(a++) = rgbdata[i];
4319  rgb2yuv(rgbdata[i + 1], rgbdata[i + 2], rgbdata[i + 3], y, u, v);
4320  y++;
4321  u++;
4322  v++;
4323  }
4324  y += orow;
4325  u += orow;
4326  v += orow;
4327  if (out_has_alpha) a += orow;
4328  }
4329 }
4330 
4331 
4332 static void *convert_argb_to_yuvp_frame_thread(void *data) {
4333  lives_cc_params *ccparams = (lives_cc_params *)data;
4334  convert_argb_to_yuvp_frame((uint8_t *)ccparams->src, ccparams->hsize, ccparams->vsize, ccparams->irowstrides[0],
4335  ccparams->orowstrides[0],
4336  (uint8_t **)ccparams->destp, ccparams->out_alpha, ccparams->out_clamping,
4337  ccparams->thread_id);
4338  return NULL;
4339 }
4340 
4341 
4342 static void convert_rgb_to_yuv420_frame(uint8_t *rgbdata, int hsize, int vsize, int rowstride, int *ostrides,
4343  uint8_t **dest, boolean is_422, boolean has_alpha, int subspace, int clamping) {
4344  // for odd sized widths, cut the rightmost pixel
4345  // TODO - handle different out sampling types
4346  uint16_t *rgbdata16 = NULL;
4347  uint8_t *y, *Cb, *Cr;
4348  uyvy_macropixel u;
4349  boolean chroma_row = TRUE;
4350  size_t hhsize;
4351  int hs3;
4352  int ipsize = 3, ipsize2;
4353  boolean is16bit = FALSE;
4354  register int i, j;
4355 
4356  if (LIVES_UNLIKELY(!conv_RY_inited)) init_RGB_to_YUV_tables();
4357 
4358  set_conversion_arrays(clamping, subspace);
4359 
4360  if (has_alpha) ipsize = 4;
4361  if (hsize < 0) {
4362  is16bit = TRUE;
4363  hsize = -hsize;
4364  rgbdata16 = (uint16_t *)rgbdata;
4365  }
4366 
4367  // ensure width and height are both divisible by two
4368  hsize = (hsize >> 1) << 1;
4369  vsize = (vsize >> 1) << 1;
4370 
4371  y = dest[0];
4372  Cb = dest[1];
4373  Cr = dest[2];
4374 
4375  hhsize = hsize >> 1;
4376  ipsize2 = ipsize * 2;
4377  hs3 = (hsize * ipsize) - (ipsize2 - 1);
4378 
4379  for (i = 0; i < vsize; i++) {
4380  for (j = 0; j < hs3; j += ipsize2) {
4381  // mpeg style, Cb and Cr are co-located
4382  // convert 6 RGBRGB bytes to 4 UYVY bytes
4383 
4384  // TODO: for mpeg use rgb2yuv and write alternate u and v
4385  if (is16bit) {
4386  rgb16_2uyvy(rgbdata16[j], rgbdata16[j + 1], rgbdata16[j + 2], rgbdata16[j + ipsize], rgbdata16[j + ipsize + 1],
4387  rgbdata16[j + ipsize + 2], &u);
4388  } else rgb2uyvy(rgbdata[j], rgbdata[j + 1], rgbdata[j + 2], rgbdata[j + ipsize], rgbdata[j + ipsize + 1],
4389  rgbdata[j + ipsize + 2], &u);
4390 
4391  *(y++) = u.y0;
4392  *(y++) = u.y1;
4393  *(Cb++) = u.u0;
4394  *(Cr++) = u.v0;
4395 
4396  if (!is_422 && chroma_row && i > 0) {
4397  // average two rows
4398  Cb[-1 - ostrides[1]] = avg_chromaf(Cb[-1], Cb[-1 - ostrides[1]]);
4399  Cr[-1 - ostrides[1]] = avg_chromaf(Cr[-1], Cr[-1 - ostrides[1]]);
4400  }
4401 
4402  }
4403  if (!is_422) {
4404  if (chroma_row) {
4405  Cb -= hhsize;
4406  Cr -= hhsize;
4407  }
4408  chroma_row = !chroma_row;
4409  }
4410  rgbdata += rowstride;
4411  }
4412 }
4413 
4414 
4415 static void convert_argb_to_yuv420_frame(uint8_t *rgbdata, int hsize, int vsize, int rowstride, int *ostrides,
4416  uint8_t **dest, boolean is_422, int subspace, int clamping) {
4417  // for odd sized widths, cut the rightmost pixel
4418  // TODO - handle different out sampling types
4419  int hs3;
4420 
4421  uint8_t *y, *Cb, *Cr;
4422  uyvy_macropixel u;
4423  register int i, j;
4424  boolean chroma_row = TRUE;
4425 
4426  int ipsize = 4, ipsize2;
4427 
4428  if (LIVES_UNLIKELY(!conv_RY_inited)) init_RGB_to_YUV_tables();
4429 
4430  set_conversion_arrays(clamping, subspace);
4431 
4432  // ensure width and height are both divisible by two
4433  hsize = (hsize >> 1) << 1;
4434  vsize = (vsize >> 1) << 1;
4435 
4436  y = dest[0];
4437  Cb = dest[1];
4438  Cr = dest[2];
4439 
4440  ipsize2 = ipsize * 2;
4441  hs3 = (hsize * ipsize) - (ipsize2 - 1);
4442 
4443  for (i = 0; i < vsize; i++) {
4444  for (j = 0; j < hs3; j += ipsize2) {
4445  // mpeg style, Cb and Cr are co-located
4446  // convert 6 RGBRGB bytes to 4 UYVY bytes
4447 
4448  // TODO: for mpeg use rgb2yuv and write alternate u and v
4449 
4450  rgb2uyvy(rgbdata[j + 1], rgbdata[j + 2], rgbdata[j + 3], rgbdata[j + 1 + ipsize], rgbdata[j + 2 + ipsize + 1],
4451  rgbdata[j + 3 + ipsize + 2], &u);
4452 
4453  *(y++) = u.y0;
4454  *(y++) = u.y1;
4455  *(Cb++) = u.u0;
4456  *(Cr++) = u.v0;
4457 
4458  if (!is_422 && chroma_row && i > 0) {
4459  // average two rows
4460  Cb[-1 - ostrides[1]] = avg_chromaf(Cb[-1], Cb[-1 - ostrides[1]]);
4461  Cr[-1 - ostrides[2]] = avg_chromaf(Cr[-1], Cr[-1 - ostrides[2]]);
4462  }
4463 
4464  }
4465  if (!is_422) {
4466  if (chroma_row) {
4467  Cb -= ostrides[1];
4468  Cr -= ostrides[2];
4469  }
4470  chroma_row = !chroma_row;
4471  }
4472  rgbdata += rowstride;
4473  }
4474 }
4475 
4476 
4477 static void convert_bgr_to_yuv420_frame(uint8_t *rgbdata, int hsize, int vsize, int rowstride, int *ostrides,
4478  uint8_t **dest, boolean is_422, boolean has_alpha, int subspace, int clamping) {
4479  // for odd sized widths, cut the rightmost pixel
4480  // TODO - handle different out sampling types
4481  int hs3;
4482 
4483  uint8_t *y, *Cb, *Cr;
4484  uyvy_macropixel u;
4485  register int i, j;
4486  int chroma_row = TRUE;
4487  int ipsize = 3, ipsize2;
4488 
4489  if (LIVES_UNLIKELY(!conv_RY_inited)) init_RGB_to_YUV_tables();
4490 
4491  set_conversion_arrays(clamping, subspace);
4492 
4493  if (has_alpha) ipsize = 4;
4494 
4495  // ensure width and height are both divisible by two
4496  hsize = (hsize >> 1) << 1;
4497  vsize = (vsize >> 1) << 1;
4498 
4499  y = dest[0];
4500  Cb = dest[1];
4501  Cr = dest[2];
4502 
4503  ipsize2 = ipsize * 2;
4504  hs3 = (hsize * ipsize) - (ipsize2 - 1);
4505  for (i = 0; i < vsize; i++) {
4506  for (j = 0; j < hs3; j += ipsize2) {
4507  // convert 6 RGBRGB bytes to 4 UYVY bytes
4508  rgb2uyvy(rgbdata[j + 2], rgbdata[j + 1], rgbdata[j], rgbdata[j + ipsize + 2],
4509  rgbdata[j + ipsize + 1], rgbdata[j + ipsize], &u);
4510 
4511  *(y++) = u.y0;
4512  *(y++) = u.y1;
4513  *(Cb++) = u.u0;
4514  *(Cr++) = u.v0;
4515 
4516  if (!is_422 && chroma_row && i > 0) {
4517  // average two rows
4518  Cb[-1 - ostrides[1]] = avg_chromaf(Cb[-1], Cb[-1 - ostrides[1]]);
4519  Cr[-1 - ostrides[2]] = avg_chromaf(Cr[-1], Cr[-1 - ostrides[2]]);
4520  }
4521  }
4522  if (!is_422) {
4523  if (chroma_row) {
4524  Cb -= ostrides[1];
4525  Cr -= ostrides[1];
4526  }
4527  chroma_row = !chroma_row;
4528  }
4529  rgbdata += rowstride;
4530  }
4531 }
4532 
4533 
4534 static void convert_yuv422p_to_uyvy_frame(uint8_t **src, int width, int height, int *irows, int orow, uint8_t *dest) {
4535  // TODO - handle different in sampling types
4536  uint8_t *src_y = src[0];
4537  uint8_t *src_u = src[1];
4538  uint8_t *src_v = src[2];
4539  int i, j;
4540 
4541  irows[0] -= width;
4542  irows[1] -= width >> 1;
4543  irows[2] -= width >> 1;
4544  orow -= width * 4;
4545 
4546  for (i = 0; i < height; i++) {
4547  for (j = 0; j < width; j++) {
4548  *(dest++) = *(src_u++);
4549  *(dest++) = *(src_y++);
4550  *(dest++) = *(src_v++);
4551  *(dest++) = *(src_y++);
4552  }
4553  src_y += irows[0];
4554  src_u += irows[1];
4555  src_v += irows[2];
4556  dest += orow;
4557  }
4558 }
4559 
4560 
4561 static void convert_yuv422p_to_yuyv_frame(uint8_t **src, int width, int height, int *irows, int orow, uint8_t *dest) {
4562  // TODO - handle different in sampling types
4563 
4564  uint8_t *src_y = src[0];
4565  uint8_t *src_u = src[1];
4566  uint8_t *src_v = src[2];
4567  int i, j;
4568 
4569  irows[0] -= width;
4570  irows[1] -= width >> 1;
4571  irows[2] -= width >> 1;
4572  orow -= width * 4;
4573 
4574  for (i = 0; i < height; i++) {
4575  for (j = 0; j < width; j++) {
4576  *(dest++) = *(src_y++);
4577  *(dest++) = *(src_u++);
4578  *(dest++) = *(src_y++);
4579  *(dest++) = *(src_v++);
4580  }
4581  src_y += irows[0];
4582  src_u += irows[1];
4583  src_v += irows[2];
4584  dest += orow;
4585  }
4586 }
4587 
4588 
4589 static void convert_rgb_to_yuv411_frame(uint8_t *rgbdata, int hsize, int vsize, int rowstride,
4590  yuv411_macropixel *u, boolean has_alpha, int clamping) {
4591  // for odd sized widths, cut the rightmost one, two or three pixels. Widths should be divisible by 4.
4592  // TODO - handle different out sampling types
4593  int hs3 = (int)(hsize >> 2) * 12, ipstep = 12;
4594 
4595  uint8_t *end;
4596  register int i;
4597 
4598  int x = 3, y = 4, z = 5, a = 6, b = 7, c = 8, d = 9, e = 10, f = 11;
4599 
4600  if (LIVES_UNLIKELY(!conv_RY_inited)) init_RGB_to_YUV_tables();
4601 
4602  set_conversion_arrays(clamping, WEED_YUV_SUBSPACE_YCBCR);
4603 
4604  if (has_alpha) {
4605  z++;
4606  y++;
4607  x++;
4608  a += 2;
4609  b += 2;
4610  c += 2;
4611  d += 3;
4612  e += 3;
4613  f += 3;
4614  hs3 = (int)(hsize >> 2) * 16;
4615  ipstep = 16;
4616  }
4617  end = rgbdata + (rowstride * vsize) + 1 - ipstep;
4618  hs3 -= (ipstep - 1);
4619 
4620  for (; rgbdata < end; rgbdata += rowstride) {
4621  for (i = 0; i < hs3; i += ipstep) {
4622  // convert 12 RGBRGBRGBRGB bytes to 6 UYYVYY bytes
4623  rgb2_411(rgbdata[i], rgbdata[i + 1], rgbdata[i + 2], rgbdata[i + x], rgbdata[i + y], rgbdata[i + z], rgbdata[i + a],
4624  rgbdata[i + b],
4625  rgbdata[i + c], rgbdata[i + d],
4626  rgbdata[i + e], rgbdata[i + f], u++);
4627  }
4628  }
4629 }
4630 
4631 
4632 static void convert_bgr_to_yuv411_frame(uint8_t *rgbdata, int hsize, int vsize, int rowstride,
4633  yuv411_macropixel *u, boolean has_alpha, int clamping) {
4634  // for odd sized widths, cut the rightmost one, two or three pixels
4635  // TODO - handle different out sampling types
4636  int hs3 = (int)(hsize >> 2) * 12, ipstep = 12;
4637 
4638  uint8_t *end;
4639  register int i;
4640 
4641  int x = 3, y = 4, z = 5, a = 6, b = 7, c = 8, d = 9, e = 10, f = 11;
4642 
4643  if (LIVES_UNLIKELY(!conv_RY_inited)) init_RGB_to_YUV_tables();
4644 
4645  set_conversion_arrays(clamping, WEED_YUV_SUBSPACE_YCBCR);
4646 
4647  if (has_alpha) {
4648  z++;
4649  y++;
4650  x++;
4651  a += 2;
4652  b += 2;
4653  c += 2;
4654  d += 3;
4655  e += 3;
4656  f += 3;
4657  hs3 = (int)(hsize >> 2) * 16;
4658  ipstep = 16;
4659  }
4660  end = rgbdata + (rowstride * vsize) + 1 - ipstep;
4661  hs3 -= (ipstep - 1);
4662 
4663  for (; rgbdata < end; rgbdata += rowstride) {
4664  for (i = 0; i < hs3; i += ipstep) {
4665  // convert 12 RGBRGBRGBRGB bytes to 6 UYYVYY bytes
4666  rgb2_411(rgbdata[i + 2], rgbdata[i + 1], rgbdata[i], rgbdata[i + z], rgbdata[i + y], rgbdata[i + x], rgbdata[i + c],
4667  rgbdata[i + b],
4668  rgbdata[i + a], rgbdata[i + f],
4669  rgbdata[i + e], rgbdata[i + d], u++);
4670  }
4671  }
4672 }
4673 
4674 
4675 static void convert_argb_to_yuv411_frame(uint8_t *rgbdata, int hsize, int vsize, int rowstride,
4676  yuv411_macropixel *u, int clamping) {
4677  // for odd sized widths, cut the rightmost one, two or three pixels. Widths should be divisible by 4.
4678  // TODO - handle different out sampling types
4679  int hs3 = (int)(hsize >> 2) * 12, ipstep = 12;
4680 
4681  uint8_t *end;
4682  register int i;
4683 
4684  if (LIVES_UNLIKELY(!conv_RY_inited)) init_RGB_to_YUV_tables();
4685 
4686  set_conversion_arrays(clamping, WEED_YUV_SUBSPACE_YCBCR);
4687 
4688  hs3 = (int)(hsize >> 2) * 16;
4689  ipstep = 16;
4690 
4691  end = rgbdata + (rowstride * vsize) + 1 - ipstep;
4692  hs3 -= (ipstep - 1);
4693 
4694  for (; rgbdata < end; rgbdata += rowstride) {
4695  for (i = 0; i < hs3; i += ipstep) {
4696  // convert 12 RGBRGBRGBRGB bytes to 6 UYYVYY bytes
4697  rgb2_411(rgbdata[i + 1], rgbdata[i + 2], rgbdata[i + 3], rgbdata[i + 5], rgbdata[i + 6], rgbdata[i + 7], rgbdata[i + 9],
4698  rgbdata[i + 10],
4699  rgbdata[i + 11],
4700  rgbdata[i + 13], rgbdata[i + 14], rgbdata[i + 15], u++);
4701  }
4702  }
4703 }
4704 
4705 
4706 static void convert_uyvy_to_rgb_frame(uyvy_macropixel *src, int width, int height, int irow, int orowstride,
4707  uint8_t *dest, boolean add_alpha, int clamping, int subspace, int thread_id) {
4708  register int i, j;
4709  int psize = 6;
4710  int a = 3, b = 4, c = 5;
4711 
4712  if (LIVES_UNLIKELY(!conv_YR_inited)) init_YUV_to_RGB_tables();
4713  if (thread_id == -1)
4714  set_conversion_arrays(clamping, subspace);
4715 
4716  if (thread_id == -1 && prefs->nfx_threads > 1) {
4717  lives_thread_t threads[prefs->nfx_threads];
4718  int nthreads = 1;
4719  int dheight, xdheight;
4721 
4722  xdheight = CEIL((double)height / (double)prefs->nfx_threads, 4);
4723  for (i = prefs->nfx_threads - 1; i >= 0; i--) {
4724  dheight = xdheight;
4725 
4726  if ((dheight * i) < height) {
4727  ccparams[i].src = src + dheight * i * irow / 4;
4728  ccparams[i].hsize = width;
4729  ccparams[i].dest = dest + dheight * i * orowstride;
4730 
4731  if (dheight * (i + 1) > (height - 4)) {
4732  dheight = height - (dheight * i);
4733  }
4734 
4735  ccparams[i].vsize = dheight;
4736 
4737  ccparams[i].irowstrides[0] = irow;
4738  ccparams[i].orowstrides[0] = orowstride;
4739  ccparams[i].out_alpha = add_alpha;
4740  ccparams[i].in_clamping = clamping;
4741  ccparams[i].in_subspace = subspace;
4742  ccparams[i].thread_id = i;
4743 
4744  if (i == 0) convert_uyvy_to_rgb_frame_thread(&ccparams[i]);
4745  else {
4746  lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_uyvy_to_rgb_frame_thread, &ccparams[i]);
4747  nthreads++;
4748  }
4749  }
4750  }
4751 
4752  for (i = 1; i < nthreads; i++) {
4753  lives_thread_join(threads[i], NULL);
4754  }
4755  lives_free(ccparams);
4756  return;
4757  }
4758 
4759  if (add_alpha) {
4760  psize = 8;
4761  a = 4;
4762  b = 5;
4763  c = 6;
4764  }
4765 
4766  orowstride -= width * psize;
4767  irow = irow / 4 - width;
4768  for (i = 0; i < height; i++) {
4769  for (j = 0; j < width; j++) {
4770  uyvy2rgb(src, &dest[0], &dest[1], &dest[2], &dest[a], &dest[b], &dest[c]);
4771  if (add_alpha) dest[3] = dest[7] = 255;
4772  dest += psize;
4773  src++;
4774  }
4775  src += irow;
4776  dest += orowstride;
4777  }
4778 }
4779 
4780 
4781 static void *convert_uyvy_to_rgb_frame_thread(void *data) {
4782  lives_cc_params *ccparams = (lives_cc_params *)data;
4783  convert_uyvy_to_rgb_frame((uyvy_macropixel *)ccparams->src, ccparams->hsize, ccparams->vsize,
4784  ccparams->irowstrides[0], ccparams->orowstrides[0],
4785  (uint8_t *)ccparams->dest, ccparams->out_alpha, ccparams->in_clamping,
4786  ccparams->in_subspace, ccparams->thread_id);
4787  return NULL;
4788 }
4789 
4790 
4791 static void convert_uyvy_to_bgr_frame(uyvy_macropixel *src, int width, int height, int irow, int orowstride,
4792  uint8_t *dest, boolean add_alpha, int clamping, int thread_id) {
4793  register int i, j;
4794  int psize = 6;
4795 
4796  int a = 3, b = 4, c = 5;
4797 
4798  if (LIVES_UNLIKELY(!conv_YR_inited)) init_YUV_to_RGB_tables();
4799  if (thread_id == -1)
4800  set_conversion_arrays(clamping, WEED_YUV_SUBSPACE_YCBCR);
4801 
4802  if (thread_id == -1 && prefs->nfx_threads > 1) {
4803  lives_thread_t threads[prefs->nfx_threads];
4804  int nthreads = 1;
4805  int dheight, xdheight;
4807 
4808  xdheight = CEIL((double)height / (double)prefs->nfx_threads, 4);
4809  for (i = prefs->nfx_threads - 1; i >= 0; i--) {
4810  dheight = xdheight;
4811 
4812  if ((dheight * i) < height) {
4813  ccparams[i].src = src + dheight * i * irow / 4;
4814  ccparams[i].hsize = width;
4815  ccparams[i].dest = dest + dheight * i * orowstride;
4816 
4817  if (dheight * (i + 1) > (height - 4)) {
4818  dheight = height - (dheight * i);
4819  }
4820 
4821  ccparams[i].vsize = dheight;
4822 
4823  ccparams[i].irowstrides[0] = irow;
4824  ccparams[i].orowstrides[0] = orowstride;
4825  ccparams[i].out_alpha = add_alpha;
4826  ccparams[i].in_clamping = clamping;
4827  ccparams[i].thread_id = i;
4828 
4829  if (i == 0) convert_uyvy_to_bgr_frame_thread(&ccparams[i]);
4830  else {
4831  lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_uyvy_to_bgr_frame_thread, &ccparams[i]);
4832  nthreads++;
4833  }
4834  }
4835  }
4836 
4837  for (i = 1; i < nthreads; i++) {
4838  lives_thread_join(threads[i], NULL);
4839  }
4840  lives_free(ccparams);
4841  return;
4842  }
4843 
4844  if (add_alpha) {
4845  psize = 8;
4846  a = 4;
4847  b = 5;
4848  c = 6;
4849  }
4850 
4851  orowstride -= width * psize;
4852  irow = irow / 4 - width;
4853  for (i = 0; i < height; i++) {
4854  for (j = 0; j < width; j++) {
4855  uyvy2rgb(src, &dest[2], &dest[1], &dest[0], &dest[c], &dest[b], &dest[a]);
4856  if (add_alpha) dest[3] = dest[7] = 255;
4857  dest += psize;
4858  src++;
4859  }
4860  src += irow;
4861  dest += orowstride;
4862  }
4863 }
4864 
4865 
4866 static void *convert_uyvy_to_bgr_frame_thread(void *data) {
4867  lives_cc_params *ccparams = (lives_cc_params *)data;
4868  convert_uyvy_to_bgr_frame((uyvy_macropixel *)ccparams->src, ccparams->hsize, ccparams->vsize,
4869  ccparams->irowstrides[0], ccparams->orowstrides[0],
4870  (uint8_t *)ccparams->dest, ccparams->out_alpha, ccparams->in_clamping, ccparams->thread_id);
4871  return NULL;
4872 }
4873 
4874 
4875 static void convert_uyvy_to_argb_frame(uyvy_macropixel *src, int width, int height, int irow, int orowstride,
4876  uint8_t *dest, int clamping, int thread_id) {
4877  register int i, j;
4878  int psize = 8;
4879 
4880  if (LIVES_UNLIKELY(!conv_YR_inited)) init_YUV_to_RGB_tables();
4881  if (thread_id == -1)
4882  set_conversion_arrays(clamping, WEED_YUV_SUBSPACE_YCBCR);
4883 
4884  if (thread_id == -1 && prefs->nfx_threads > 1) {
4885  lives_thread_t threads[prefs->nfx_threads];
4886  int nthreads = 1;
4887  int dheight, xdheight;
4889 
4890  xdheight = CEIL((double)height / (double)prefs->nfx_threads, 4);
4891  for (i = prefs->nfx_threads - 1; i >= 0; i--) {
4892  dheight = xdheight;
4893 
4894  if ((dheight * i) < height) {
4895  ccparams[i].src = src + dheight * i * irow / 4;
4896  ccparams[i].hsize = width;
4897  ccparams[i].dest = dest + dheight * i * orowstride;
4898 
4899  if (dheight * (i + 1) > (height - 4)) {
4900  dheight = height - (dheight * i);
4901  }
4902 
4903  ccparams[i].vsize = dheight;
4904 
4905  ccparams[i].irowstrides[0] = irow;
4906  ccparams[i].orowstrides[0] = orowstride;
4907  ccparams[i].in_clamping = clamping;
4908  ccparams[i].thread_id = i;
4909 
4910  if (i == 0) convert_uyvy_to_argb_frame_thread(&ccparams[i]);
4911  else {
4912  lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_uyvy_to_argb_frame_thread, &ccparams[i]);
4913  nthreads++;
4914  }
4915  }
4916  }
4917 
4918  for (i = 1; i < nthreads; i++) {
4919  lives_thread_join(threads[i], NULL);
4920  }
4921  lives_free(ccparams);
4922  return;
4923  }
4924 
4925  orowstride -= width * psize;
4926  irow = irow / 4 - width;
4927  for (i = 0; i < height; i++) {
4928  for (j = 0; j < width; j++) {
4929  uyvy2rgb(src, &dest[1], &dest[2], &dest[3], &dest[5], &dest[6], &dest[7]);
4930  dest[0] = dest[4] = 255;
4931  dest += psize;
4932  src++;
4933  }
4934  src += irow;
4935  dest += orowstride;
4936  }
4937 }
4938 
4939 
4940 static void *convert_uyvy_to_argb_frame_thread(void *data) {
4941  lives_cc_params *ccparams = (lives_cc_params *)data;
4942  convert_uyvy_to_argb_frame((uyvy_macropixel *)ccparams->src, ccparams->hsize, ccparams->vsize,
4943  ccparams->irowstrides[0], ccparams->orowstrides[0],
4944  (uint8_t *)ccparams->dest, ccparams->in_clamping, ccparams->thread_id);
4945  return NULL;
4946 }
4947 
4948 
4949 static void convert_yuyv_to_rgb_frame(yuyv_macropixel *src, int width, int height, int irow, int orowstride,
4950  uint8_t *dest, boolean add_alpha, int clamping, int thread_id) {
4951  register int i, j;
4952  int psize = 6;
4953  int a = 3, b = 4, c = 5;
4954 
4955  if (LIVES_UNLIKELY(!conv_YR_inited)) init_YUV_to_RGB_tables();
4956  if (thread_id == -1)
4957  set_conversion_arrays(clamping, WEED_YUV_SUBSPACE_YCBCR);
4958 
4959  if (thread_id == -1 && prefs->nfx_threads > 1) {
4960  lives_thread_t threads[prefs->nfx_threads];
4961  int nthreads = 1;
4962  int dheight, xdheight;
4964 
4965  xdheight = CEIL((double)height / (double)prefs->nfx_threads, 4);
4966  for (i = prefs->nfx_threads - 1; i >= 0; i--) {
4967  dheight = xdheight;
4968 
4969  if ((dheight * i) < height) {
4970  ccparams[i].src = src + dheight * i * irow / 4;
4971  ccparams[i].hsize = width;
4972  ccparams[i].dest = dest + dheight * i * orowstride;
4973 
4974  if (dheight * (i + 1) > (height - 4)) {
4975  dheight = height - (dheight * i);
4976  }
4977 
4978  ccparams[i].vsize = dheight;
4979  ccparams[i].irowstrides[0] = irow;
4980  ccparams[i].orowstrides[0] = orowstride;
4981  ccparams[i].out_alpha = add_alpha;
4982  ccparams[i].in_clamping = clamping;
4983  ccparams[i].thread_id = i;
4984 
4985  if (i == 0) convert_yuyv_to_rgb_frame_thread(&ccparams[i]);
4986  else {
4987  lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_yuyv_to_rgb_frame_thread, &ccparams[i]);
4988  nthreads++;
4989  }
4990  }
4991  }
4992 
4993  for (i = 1; i < nthreads; i++) {
4994  lives_thread_join(threads[i], NULL);
4995  }
4996  lives_free(ccparams);
4997  return;
4998  }
4999 
5000  if (add_alpha) {
5001  psize = 8;
5002  a = 4;
5003  b = 5;
5004  c = 6;
5005  }
5006 
5007  orowstride -= width * psize;
5008  irow = irow / 4 - width;
5009  for (i = 0; i < height; i++) {
5010  for (j = 0; j < width; j++) {
5011  yuyv2rgb(src, &dest[0], &dest[1], &dest[2], &dest[a], &dest[b], &dest[c]);
5012  if (add_alpha) dest[3] = dest[7] = 255;
5013  dest += psize;
5014  src++;
5015  }
5016  src += irow;
5017  dest += orowstride;
5018  }
5019 }
5020 
5021 
5022 static void *convert_yuyv_to_rgb_frame_thread(void *data) {
5023  lives_cc_params *ccparams = (lives_cc_params *)data;
5024  convert_yuyv_to_rgb_frame((yuyv_macropixel *)ccparams->src, ccparams->hsize, ccparams->vsize,
5025  ccparams->irowstrides[0], ccparams->orowstrides[0],
5026  (uint8_t *)ccparams->dest, ccparams->out_alpha, ccparams->in_clamping, ccparams->thread_id);
5027  return NULL;
5028 }
5029 
5030 
5031 static void convert_yuyv_to_bgr_frame(yuyv_macropixel *src, int width, int height, int irow, int orowstride,
5032  uint8_t *dest, boolean add_alpha, int clamping, int thread_id) {
5033  register int i, j;
5034  int psize = 6;
5035  int a = 3, b = 4, c = 5;
5036 
5037  if (LIVES_UNLIKELY(!conv_YR_inited)) init_YUV_to_RGB_tables();
5038  if (thread_id == -1)
5039  set_conversion_arrays(clamping, WEED_YUV_SUBSPACE_YCBCR);
5040 
5041  if (thread_id == -1 && prefs->nfx_threads > 1) {
5042  lives_thread_t threads[prefs->nfx_threads];
5043  int nthreads = 1;
5044  int dheight, xdheight;
5046 
5047  xdheight = CEIL((double)height / (double)prefs->nfx_threads, 4);
5048  for (i = prefs->nfx_threads - 1; i >= 0; i--) {
5049  dheight = xdheight;
5050 
5051  if ((dheight * i) < height) {
5052  ccparams[i].src = src + dheight * i * irow / 4;
5053  ccparams[i].hsize = width;
5054  ccparams[i].dest = dest + dheight * i * orowstride;
5055 
5056  if (dheight * (i + 1) > (height - 4)) {
5057  dheight = height - (dheight * i);
5058  }
5059 
5060  ccparams[i].vsize = dheight;
5061 
5062  ccparams[i].irowstrides[0] = irow;
5063  ccparams[i].orowstrides[0] = orowstride;
5064  ccparams[i].out_alpha = add_alpha;
5065  ccparams[i].in_clamping = clamping;
5066  ccparams[i].thread_id = i;
5067 
5068  if (i == 0) convert_yuyv_to_bgr_frame_thread(&ccparams[i]);
5069  else {
5070  lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_yuyv_to_bgr_frame_thread, &ccparams[i]);
5071  nthreads++;
5072  }
5073  }
5074  }
5075 
5076  for (i = 1; i < nthreads; i++) {
5077  lives_thread_join(threads[i], NULL);
5078  }
5079  lives_free(ccparams);
5080  return;
5081  }
5082 
5083  if (add_alpha) {
5084  psize = 8;
5085  a = 4;
5086  b = 5;
5087  c = 6;
5088  }
5089 
5090  orowstride -= width * psize;
5091  irow = irow / 4 - width;
5092  for (i = 0; i < height; i++) {
5093  for (j = 0; j < width; j++) {
5094  yuyv2rgb(src, &dest[2], &dest[1], &dest[0], &dest[c], &dest[b], &dest[a]);
5095  if (add_alpha) dest[3] = dest[7] = 255;
5096  dest += psize;
5097  src++;
5098  }
5099  src += irow;
5100  dest += orowstride;
5101  }
5102 }
5103 
5104 
5105 static void *convert_yuyv_to_bgr_frame_thread(void *data) {
5106  lives_cc_params *ccparams = (lives_cc_params *)data;
5107  convert_yuyv_to_bgr_frame((yuyv_macropixel *)ccparams->src, ccparams->hsize, ccparams->vsize,
5108  ccparams->irowstrides[0], ccparams->orowstrides[0],
5109  (uint8_t *)ccparams->dest, ccparams->out_alpha, ccparams->in_clamping, ccparams->thread_id);
5110  return NULL;
5111 }
5112 
5113 
5114 static void convert_yuyv_to_argb_frame(yuyv_macropixel *src, int width, int height, int irow, int orowstride,
5115  uint8_t *dest, int clamping, int thread_id) {
5116  register int i, j;
5117  int psize = 8;
5118 
5119  if (LIVES_UNLIKELY(!conv_YR_inited)) init_YUV_to_RGB_tables();
5120  if (thread_id == -1)
5121  set_conversion_arrays(clamping, WEED_YUV_SUBSPACE_YCBCR);
5122 
5123  if (thread_id == -1 && prefs->nfx_threads > 1) {
5124  lives_thread_t threads[prefs->nfx_threads];
5125  int nthreads = 1;
5126  int dheight, xdheight;
5128 
5129  xdheight = CEIL((double)height / (double)prefs->nfx_threads, 4);
5130  for (i = prefs->nfx_threads - 1; i >= 0; i--) {
5131  dheight = xdheight;
5132 
5133  if ((dheight * i) < height) {
5134  ccparams[i].src = src + dheight * i * irow / 4;
5135  ccparams[i].hsize = width;
5136  ccparams[i].dest = dest + dheight * i * orowstride;
5137 
5138  if (dheight * (i + 1) > (height - 4)) {
5139  dheight = height - (dheight * i);
5140  }
5141 
5142  ccparams[i].vsize = dheight;
5143 
5144  ccparams[i].irowstrides[0] = irow;
5145  ccparams[i].orowstrides[0] = orowstride;
5146  ccparams[i].in_clamping = clamping;
5147  ccparams[i].thread_id = i;
5148 
5149  if (i == 0) convert_yuyv_to_argb_frame_thread(&ccparams[i]);
5150  else {
5151  lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_yuyv_to_argb_frame_thread, &ccparams[i]);
5152  nthreads++;
5153  }
5154  }
5155  }
5156 
5157  for (i = 1; i < nthreads; i++) {
5158  lives_thread_join(threads[i], NULL);
5159  }
5160  lives_free(ccparams);
5161  return;
5162  }
5163 
5164  orowstride -= width * psize;
5165  irow = irow / 4 - width;
5166  for (i = 0; i < height; i++) {
5167  for (j = 0; j < width; j++) {
5168  yuyv2rgb(src, &dest[1], &dest[2], &dest[3], &dest[5], &dest[6], &dest[7]);
5169  dest[0] = dest[4] = 255;
5170  dest += psize;
5171  src++;
5172  }
5173  src += irow;
5174  dest += orowstride;
5175  }
5176 }
5177 
5178 
5179 static void *convert_yuyv_to_argb_frame_thread(void *data) {
5180  lives_cc_params *ccparams = (lives_cc_params *)data;
5181  convert_yuyv_to_argb_frame((yuyv_macropixel *)ccparams->src, ccparams->hsize, ccparams->vsize,
5182  ccparams->irowstrides[0], ccparams->orowstrides[0],
5183  (uint8_t *)ccparams->dest, ccparams->in_clamping, ccparams->thread_id);
5184  return NULL;
5185 }
5186 
5187 
5188 static void convert_yuv420_to_uyvy_frame(uint8_t **src, int width, int height, int *irows, int orow,
5189  uyvy_macropixel *dest, int clamping) {
5190  register int i = 0, j;
5191  uint8_t *y, *u, *v, *end;
5192  int hwidth = width >> 1;
5193  boolean chroma = TRUE;
5194 
5195  // TODO - hasndle different in sampling types
5196  if (!avg_inited) init_average();
5197 
5198  y = src[0];
5199  u = src[1];
5200  v = src[2];
5201 
5202  end = y + height * irows[0];
5203  orow = orow / 4 - hwidth;
5204  irows[0] -= width;
5205 
5206  set_conversion_arrays(clamping, WEED_YUV_SUBSPACE_YCBCR);
5207 
5208  while (y < end) {
5209  for (j = 0; j < hwidth; j++) {
5210  dest->u0 = u[0];
5211  dest->y0 = y[0];
5212  dest->v0 = v[0];
5213  dest->y1 = y[1];
5214 
5215  if (chroma && i > 0) {
5216  dest[-hwidth].u0 = avg_chromaf(dest[-hwidth].u0, u[0]);
5217  dest[-hwidth].v0 = avg_chromaf(dest[-hwidth].v0, v[0]);
5218  }
5219 
5220  dest++;
5221  y += 2;
5222  u++;
5223  v++;
5224  }
5225  if (chroma) {
5226  u -= irows[1];
5227  v -= irows[2];
5228  }
5229  chroma = !chroma;
5230  y += irows[0];
5231  dest += orow;
5232  }
5233 }
5234 
5235 
5236 static void convert_yuv420_to_yuyv_frame(uint8_t **src, int width, int height, int *irows, int orow, yuyv_macropixel *dest,
5237  int clamping) {
5238  register int i = 0, j;
5239  uint8_t *y, *u, *v, *end;
5240  int hwidth = width >> 1;
5241  boolean chroma = TRUE;
5242 
5243  // TODO - handle different in sampling types
5244  if (!avg_inited) init_average();
5245 
5246  y = src[0];
5247  u = src[1];
5248  v = src[2];
5249 
5250  end = y + height * irows[0];
5251  orow = orow / 4 - hwidth;
5252  irows[0] -= width;
5253 
5254  set_conversion_arrays(clamping, WEED_YUV_SUBSPACE_YCBCR);
5255 
5256  while (y < end) {
5257  for (j = 0; j < hwidth; j++) {
5258  dest->y0 = y[0];
5259  dest->u0 = u[0];
5260  dest->y1 = y[1];
5261  dest->v0 = v[0];
5262 
5263  if (chroma && i > 0) {
5264  dest[-hwidth].u0 = avg_chromaf(dest[-hwidth].u0, u[0]);
5265  dest[-hwidth].v0 = avg_chromaf(dest[-hwidth].v0, v[0]);
5266  }
5267 
5268  dest++;
5269  y += 2;
5270  u++;
5271  v++;
5272  }
5273  if (chroma) {
5274  u -= irows[1];
5275  v -= irows[2];
5276  }
5277  chroma = !chroma;
5278  dest += orow;
5279  }
5280 }
5281 
5282 
5283 static void convert_yuv_planar_to_rgb_frame(uint8_t **src, int width, int height, int irowstride, int orowstride, uint8_t *dest,
5284  boolean in_alpha, boolean out_alpha, int clamping, int thread_id) {
5285  uint8_t *y = src[0];
5286  uint8_t *u = src[1];
5287  uint8_t *v = src[2];
5288  uint8_t *a = NULL;
5289 
5290  uint8_t *end = y + irowstride * height;
5291 
5292  size_t opstep = 3;
5293  register int i, j;
5294 
5295  if (LIVES_UNLIKELY(!conv_YR_inited)) init_YUV_to_RGB_tables();
5296  if (thread_id == -1)
5297  set_conversion_arrays(clamping, WEED_YUV_SUBSPACE_YCBCR);
5298 
5299  if (in_alpha) a = src[3];
5300 
5301  if (thread_id == -1 && prefs->nfx_threads > 1) {
5302  lives_thread_t threads[prefs->nfx_threads];
5303  int nthreads = 1;
5304  int dheight, xdheight;
5306 
5307  xdheight = CEIL((double)height / (double)prefs->nfx_threads, 4);
5308  for (i = prefs->nfx_threads - 1; i >= 0; i--) {
5309  dheight = xdheight;
5310 
5311  if ((y + dheight * i * irowstride) < end) {
5312  ccparams[i].hsize = width;
5313 
5314  ccparams[i].srcp[0] = y + dheight * i * irowstride;
5315  ccparams[i].srcp[1] = u + dheight * i * irowstride;
5316  ccparams[i].srcp[2] = v + dheight * i * irowstride;
5317  if (in_alpha) ccparams[i].srcp[3] = a + dheight * i * irowstride;
5318 
5319  ccparams[i].dest = dest + dheight * i * orowstride;
5320 
5321  if (dheight * (i + 1) > (height - 4)) {
5322  dheight = height - (dheight * i);
5323  }
5324 
5325  ccparams[i].vsize = dheight;
5326 
5327  ccparams[i].irowstrides[0] = irowstride;
5328  ccparams[i].orowstrides[0] = orowstride;
5329  ccparams[i].in_alpha = in_alpha;
5330  ccparams[i].out_alpha = out_alpha;
5331  ccparams[i].out_clamping = clamping;
5332  ccparams[i].thread_id = i;
5333 
5334  if (i == 0) convert_yuv_planar_to_rgb_frame_thread(&ccparams[i]);
5335  else {
5336  lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_yuv_planar_to_rgb_frame_thread, &ccparams[i]);
5337  nthreads++;
5338  }
5339  }
5340  }
5341 
5342  for (i = 1; i < nthreads; i++) {
5343  lives_thread_join(threads[i], NULL);
5344  }
5345  lives_free(ccparams);
5346  return;
5347  }
5348 
5349  if (out_alpha) opstep = 4;
5350 
5351  orowstride -= width * opstep;
5352  irowstride -= width;
5353 
5354  for (i = 0; i < height; i++) {
5355  for (j = 0; j < width; j++) {
5356  yuv2rgb(*(y++), *(u++), *(v++), &dest[0], &dest[1], &dest[2]);
5357  if (out_alpha) {
5358  if (in_alpha) {
5359  dest[3] = *(a++);
5360  } else dest[3] = 255;
5361  }
5362  dest += opstep;
5363  }
5364  dest += orowstride;
5365  y += irowstride;
5366  u += irowstride;
5367  v += irowstride;
5368  if (a) a += irowstride;
5369  }
5370 }
5371 
5372 
5373 static void *convert_yuv_planar_to_rgb_frame_thread(void *data) {
5374  lives_cc_params *ccparams = (lives_cc_params *)data;
5375  convert_yuv_planar_to_rgb_frame((uint8_t **)ccparams->srcp, ccparams->hsize, ccparams->vsize, ccparams->irowstrides[0],
5376  ccparams->orowstrides[0],
5377  (uint8_t *)ccparams->dest, ccparams->in_alpha, ccparams->out_alpha,
5378  ccparams->in_clamping, ccparams->thread_id);
5379  return NULL;
5380 }
5381 
5382 
5383 static void convert_yuv_planar_to_bgr_frame(uint8_t **src, int width, int height, int irowstride, int orowstride, uint8_t *dest,
5384  boolean in_alpha, boolean out_alpha, int clamping, int thread_id) {
5385  uint8_t *y = src[0];
5386  uint8_t *u = src[1];
5387  uint8_t *v = src[2];
5388  uint8_t *a = NULL;
5389 
5390  uint8_t *end = y + irowstride * height;
5391 
5392  size_t opstep = 4;
5393  int i, j;
5394 
5395  if (LIVES_UNLIKELY(!conv_YR_inited)) init_YUV_to_RGB_tables();
5396  if (thread_id == -1)
5397  set_conversion_arrays(clamping, WEED_YUV_SUBSPACE_YCBCR);
5398 
5399  if (in_alpha) a = src[3];
5400 
5401  if (thread_id == -1 && prefs->nfx_threads > 1) {
5402  lives_thread_t threads[prefs->nfx_threads];
5403  int nthreads = 1;
5404  int dheight, xdheight;
5406 
5407  xdheight = CEIL((double)height / (double)prefs->nfx_threads, 4);
5408 
5409  for (i = prefs->nfx_threads - 1; i >= 0; i--) {
5410  dheight = xdheight;
5411 
5412  if ((y + dheight * i * irowstride) < end) {
5413  ccparams[i].hsize = width;
5414 
5415  ccparams[i].srcp[0] = y + dheight * i * irowstride;
5416  ccparams[i].srcp[1] = u + dheight * i * irowstride;
5417  ccparams[i].srcp[2] = v + dheight * i * irowstride;
5418  if (in_alpha) ccparams[i].srcp[3] = a + dheight * i * irowstride;
5419 
5420  ccparams[i].dest = dest + dheight * i * orowstride;
5421 
5422  if (dheight * (i + 1) > (height - 4)) {
5423  dheight = height - (dheight * i);
5424  }
5425 
5426  ccparams[i].vsize = dheight;
5427 
5428  ccparams[i].irowstrides[0] = irowstride;
5429  ccparams[i].orowstrides[0] = orowstride;
5430  ccparams[i].in_alpha = in_alpha;
5431  ccparams[i].out_alpha = out_alpha;
5432  ccparams[i].out_clamping = clamping;
5433  ccparams[i].thread_id = i;
5434 
5435  if (i == 0) convert_yuv_planar_to_bgr_frame_thread(&ccparams[i]);
5436  else {
5437  lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_yuv_planar_to_bgr_frame_thread, &ccparams[i]);
5438  nthreads++;
5439  }
5440  }
5441  }
5442 
5443  for (i = 1; i < nthreads; i++) {
5444  lives_thread_join(threads[i], NULL);
5445  }
5446  lives_free(ccparams);
5447  return;
5448  }
5449 
5450  orowstride -= width * opstep;
5451  irowstride -= width;
5452 
5453  for (i = 0; i < height; i++) {
5454  for (j = 0; j < width; j++) {
5455  yuv2bgr(*(y++), *(u++), *(v++), &dest[0], &dest[1], &dest[2]);
5456  if (out_alpha) {
5457  if (in_alpha) {
5458  dest[3] = *(a++);
5459  } else dest[3] = 255;
5460  }
5461  dest += opstep;
5462  }
5463  dest += orowstride;
5464  y += irowstride;
5465  u += irowstride;
5466  v += irowstride;
5467  if (a) a += irowstride;
5468  }
5469 }
5470 
5471 
5472 static void *convert_yuv_planar_to_bgr_frame_thread(void *data) {
5473  lives_cc_params *ccparams = (lives_cc_params *)data;
5474  convert_yuv_planar_to_bgr_frame((uint8_t **)ccparams->srcp, ccparams->hsize, ccparams->vsize, ccparams->irowstrides[0],
5475  ccparams->orowstrides[0],
5476  (uint8_t *)ccparams->dest, ccparams->in_alpha, ccparams->out_alpha,
5477  ccparams->in_clamping, ccparams->thread_id);
5478  return NULL;
5479 }
5480 
5481 
5482 static void convert_yuv_planar_to_argb_frame(uint8_t **src, int width, int height, int irowstride, int orowstride,
5483  uint8_t *dest,
5484  boolean in_alpha, int clamping, int thread_id) {
5485  uint8_t *y = src[0];
5486  uint8_t *u = src[1];
5487  uint8_t *v = src[2];
5488  uint8_t *a = NULL;
5489 
5490  uint8_t *end = y + irowstride * height;
5491 
5492  size_t opstep = 4;
5493  register int i, j;
5494 
5495  if (LIVES_UNLIKELY(!conv_YR_inited)) init_YUV_to_RGB_tables();
5496 
5497  if (in_alpha) a = src[3];
5498 
5499  if (thread_id == -1 && prefs->nfx_threads > 1) {
5500  lives_thread_t threads[prefs->nfx_threads];
5501  int nthreads = 1;
5502  int dheight, xdheight;
5504 
5505  xdheight = CEIL((double)height / (double)prefs->nfx_threads, 4);
5506  for (i = prefs->nfx_threads - 1; i >= 0; i--) {
5507  dheight = xdheight;
5508 
5509  if ((y + dheight * i * irowstride) < end) {
5510  ccparams[i].hsize = width;
5511 
5512  ccparams[i].srcp[0] = y + dheight * i * irowstride;
5513  ccparams[i].srcp[1] = u + dheight * i * irowstride;
5514  ccparams[i].srcp[2] = v + dheight * i * irowstride;
5515  if (in_alpha) ccparams[i].srcp[3] = a + dheight * i * irowstride;
5516 
5517  ccparams[i].dest = dest + dheight * i * orowstride;
5518 
5519  if (dheight * (i + 1) > (height - 4)) {
5520  dheight = height - (dheight * i);
5521  }
5522 
5523  ccparams[i].vsize = dheight;
5524 
5525  ccparams[i].irowstrides[0] = irowstride;
5526  ccparams[i].orowstrides[0] = orowstride;
5527  ccparams[i].in_alpha = in_alpha;
5528  ccparams[i].out_clamping = clamping;
5529  ccparams[i].thread_id = i;
5530 
5531  if (i == 0) convert_yuv_planar_to_argb_frame_thread(&ccparams[i]);
5532  else {
5533  lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_yuv_planar_to_argb_frame_thread, &ccparams[i]);
5534  nthreads++;
5535  }
5536  }
5537  }
5538 
5539  for (i = 1; i < nthreads; i++) {
5540  lives_thread_join(threads[i], NULL);
5541  }
5542  lives_free(ccparams);
5543  return;
5544  }
5545 
5546  orowstride -= width * opstep;
5547  orowstride -= width;
5548 
5549  for (i = 0; i < height; i++) {
5550  for (j = 0; j < width; j++) {
5551  yuv2rgb(*(y++), *(u++), *(v++), &dest[1], &dest[2], &dest[3]);
5552  if (in_alpha) {
5553  dest[0] = *(a++);
5554  } else dest[0] = 255;
5555  dest += opstep;
5556  }
5557  dest += orowstride;
5558  y += irowstride;
5559  u += irowstride;
5560  v += irowstride;
5561  if (a) a += irowstride;
5562  }
5563 }
5564 
5565 
5566 static void *convert_yuv_planar_to_argb_frame_thread(void *data) {
5567  lives_cc_params *ccparams = (lives_cc_params *)data;
5568  convert_yuv_planar_to_argb_frame((uint8_t **)ccparams->srcp, ccparams->hsize, ccparams->vsize, ccparams->irowstrides[0],
5569  ccparams->orowstrides[0],
5570  (uint8_t *)ccparams->dest, ccparams->in_alpha, ccparams->in_clamping, ccparams->thread_id);
5571  return NULL;
5572 }
5573 
5574 
5575 static void convert_yuv_planar_to_uyvy_frame(uint8_t **src, int width, int height, int irowstride, int orowstride,
5576  uyvy_macropixel *uyvy, int clamping) {
5577  register int x, k;
5578  int size = (width * height) >> 1;
5579 
5580  uint8_t *y = src[0];
5581  uint8_t *u = src[1];
5582  uint8_t *v = src[2];
5583 
5584  set_conversion_arrays(clamping, WEED_YUV_SUBSPACE_YCBCR);
5585 
5586  if (irowstride == width && orowstride == width << 1) {
5587  for (x = 0; x < size; x++) {
5588  // subsample two u pixels
5589  uyvy->u0 = avg_chromaf(u[0], u[1]);
5590  u += 2;
5591  uyvy->y0 = *(y++);
5592  // subsample 2 v pixels
5593  uyvy->v0 = avg_chromaf(v[0], v[1]);
5594  v += 2;
5595  uyvy->y1 = *(y++);
5596  uyvy++;
5597  }
5598  return;
5599  }
5600  irowstride -= width;
5601  orowstride -= width << 1;
5602  for (k = 0; k < height; k++) {
5603  for (x = 0; x < width; x++) {
5604  // subsample two u pixels
5605  uyvy->u0 = avg_chromaf(u[0], u[1]);
5606  u += 2;
5607  uyvy->y0 = *(y++);
5608  // subsample 2 v pixels
5609  uyvy->v0 = avg_chromaf(v[0], v[1]);
5610  v += 2;
5611  uyvy->y1 = *(y++);
5612  uyvy++;
5613  }
5614  y += irowstride;
5615  u += irowstride;
5616  v += irowstride;
5617  uyvy += orowstride;
5618  }
5619 }
5620 
5621 
5622 static void convert_yuv_planar_to_yuyv_frame(uint8_t **src, int width, int height, int irowstride, int orowstride,
5623  yuyv_macropixel *yuyv, int clamping) {
5624  register int x, k;
5625  int hsize = (width * height) >> 1;
5626 
5627  uint8_t *y = src[0];
5628  uint8_t *u = src[1];
5629  uint8_t *v = src[2];
5630 
5631  set_conversion_arrays(clamping, WEED_YUV_SUBSPACE_YCBCR);
5632 
5633  if (irowstride == width && orowstride == (width << 1)) {
5634  for (x = 0; x < hsize; x++) {
5635  yuyv->y0 = *(y++);
5636  yuyv->u0 = avg_chromaf(u[0], u[1]);
5637  u += 2;
5638  yuyv->y1 = *(y++);
5639  yuyv->v0 = avg_chromaf(v[0], v[1]);
5640  v += 2;
5641  yuyv++;
5642  }
5643  return;
5644  }
5645 
5646  irowstride -= width;
5647  orowstride = orowstride / 4 - width;
5648  for (k = 0; k < height; k++) {
5649  for (x = 0; x < width; x++) {
5650  yuyv->y0 = *(y++);
5651  yuyv->u0 = avg_chromaf(u[0], u[1]);
5652  u += 2;
5653  yuyv->y1 = *(y++);
5654  yuyv->v0 = avg_chromaf(v[0], v[1]);
5655  v += 2;
5656  yuyv++;
5657  }
5658  y += irowstride;
5659  u += irowstride;
5660  v += irowstride;
5661  yuyv += orowstride;
5662  }
5663 }
5664 
5665 
5666 static void convert_combineplanes_frame(uint8_t **src, int width, int height, int irowstride,
5667  int orowstride, uint8_t *dest, boolean in_alpha, boolean out_alpha) {
5668  // turn 3 or 4 planes into packed pixels, src and dest can have alpha
5669 
5670  // e.g yuv444(4)p to yuv888(8)
5671 
5672  int size = width * height;
5673 
5674  uint8_t *y = src[0];
5675  uint8_t *u = src[1];
5676  uint8_t *v = src[2];
5677  uint8_t *a = NULL;
5678  int opsize = 3;
5679  register int x, k;
5680 
5681  if (in_alpha) a = src[3];
5682  if (out_alpha) opsize = 4;
5683 
5684  if (irowstride == width && orowstride == width * opsize) {
5685  for (x = 0; x < size; x++) {
5686  *(dest++) = *(y++);
5687  *(dest++) = *(u++);
5688  *(dest++) = *(v++);
5689  if (out_alpha) {
5690  if (in_alpha) *(dest++) = *(a++);
5691  else *(dest++) = 255;
5692  }
5693  }
5694  } else {
5695  irowstride -= width;
5696  orowstride -= width * opsize;
5697  for (k = 0; k < height; k++) {
5698  for (x = 0; x < width; x++) {
5699  *(dest++) = *(y++);
5700  *(dest++) = *(u++);
5701  *(dest++) = *(v++);
5702  if (out_alpha) {
5703  if (in_alpha) *(dest++) = *(a++);
5704  else *(dest++) = 255;
5705  }
5706  }
5707  dest += orowstride;
5708  y += irowstride;
5709  u += irowstride;
5710  v += irowstride;
5711  }
5712  }
5713 }
5714 
5715 
5716 static void convert_yuvap_to_yuvp_frame(uint8_t **src, int width, int height, int irowstride, int orowstride, uint8_t **dest) {
5717  size_t size = irowstride * height;
5718 
5719  uint8_t *ys = src[0];
5720  uint8_t *us = src[1];
5721  uint8_t *vs = src[2];
5722 
5723  uint8_t *yd = dest[0];
5724  uint8_t *ud = dest[1];
5725  uint8_t *vd = dest[2];
5726 
5727  register int y;
5728 
5729  if (orowstride == irowstride) {
5730  if (yd != ys) lives_memcpy(yd, ys, size);
5731  if (ud != us) lives_memcpy(ud, us, size);
5732  if (vd != vs) lives_memcpy(vd, vs, size);
5733  return;
5734  }
5735  for (y = 0; y < height; y++) {
5736  if (yd != ys) {
5737  lives_memcpy(yd, ys, width);
5738  yd += orowstride;
5739  ys += irowstride;
5740  }
5741  if (ud != us) {
5742  lives_memcpy(ud, us, width);
5743  ud += orowstride;
5744  us += irowstride;
5745  }
5746  if (vd != vs) {
5747  lives_memcpy(vd, vs, width);
5748  vd += orowstride;
5749  vs += irowstride;
5750  }
5751  }
5752 }
5753 
5754 
5755 static void convert_yuvp_to_yuvap_frame(uint8_t **src, int width, int height, int irowstride, int orowstride, uint8_t **dest) {
5756  convert_yuvap_to_yuvp_frame(src, width, height, irowstride, orowstride, dest);
5757  lives_memset(dest[3], 255, orowstride * height);
5758 }
5759 
5760 
5761 static void convert_yuvp_to_yuv420_frame(uint8_t **src, int width, int height, int *irows, int *orows, uint8_t **dest,
5762  int clamping) {
5763  // halve the chroma samples vertically and horizontally, with sub-sampling
5764 
5765  // convert 444p to 420p
5766 
5767  // TODO - handle different output sampling types
5768 
5769  // y-plane should be copied before entering here
5770 
5771  register int i, j;
5772  uint8_t *d_u, *d_v, *s_u = src[1], *s_v = src[2];
5773  register short x_u, x_v;
5774  boolean chroma = FALSE;
5775 
5776  int hwidth = width >> 1;
5777 
5778  set_conversion_arrays(clamping, WEED_YUV_SUBSPACE_YCBCR);
5779 
5780  if (dest[0] != src[0]) {
5781  if (irows[0] == orows[0]) {
5782  lives_memcpy(dest[0], src[0], irows[0] * height);
5783  } else {
5784  uint8_t *d_y = dest[0];
5785  uint8_t *s_y = src[0];
5786  for (i = 0; i < height; i++) {
5787  lives_memcpy(d_y, s_y, width);
5788  d_y += orows[0];
5789  s_y += irows[0];
5790  }
5791  }
5792  }
5793 
5794  d_u = dest[1];
5795  d_v = dest[2];
5796 
5797  for (i = 0; i < height; i++) {
5798  for (j = 0; j < hwidth; j++) {
5799  if (!chroma) {
5800  // pass 1, copy row
5801  // average two dest pixels
5802  d_u[j] = avg_chromaf(s_u[j * 2], s_u[j * 2 + 1]);
5803  d_v[j] = avg_chromaf(s_v[j * 2], s_v[j * 2 + 1]);
5804  } else {
5805  // pass 2
5806  // average two dest pixels
5807  x_u = avg_chromaf(s_u[j * 2], s_u[j * 2 + 1]);
5808  x_v = avg_chromaf(s_v[j * 2], s_v[j * 2 + 1]);
5809  // average two dest rows
5810  d_u[j] = avg_chromaf(d_u[j], x_u);
5811  d_v[j] = avg_chromaf(d_v[j], x_v);
5812  }
5813  }
5814  if (chroma) {
5815  d_u += orows[1];
5816  d_v += orows[2];
5817  }
5818  chroma = !chroma;
5819  s_u += irows[1];
5820  s_v += irows[2];
5821  }
5822 }
5823 
5824 
5825 static void convert_yuvp_to_yuv411_frame(uint8_t **src, int width, int height, int irowstride,
5826  yuv411_macropixel *yuv, int clamping) {
5827  // quarter the chroma samples horizontally, with sub-sampling
5828 
5829  // convert 444p to 411 packed
5830  // TODO - handle different output sampling types
5831 
5832  register int i, j;
5833  uint8_t *s_y = src[0], *s_u = src[1], *s_v = src[2];
5834  register short x_u, x_v;
5835 
5836  int widtha = (width >> 1) << 1; // cut rightmost odd bytes
5837  int cbytes = width - widtha;
5838 
5839  irowstride -= width + cbytes;
5840 
5841  set_conversion_arrays(clamping, WEED_YUV_SUBSPACE_YCBCR);
5842 
5843  for (i = 0; i < height; i++) {
5844  for (j = 0; j < widtha; j += 4) {
5845  // average four dest pixels
5846  yuv->u2 = avg_chromaf(s_u[0], s_u[1]);
5847  x_u = avg_chromaf(s_u[2], s_u[3]);
5848  yuv->u2 = avg_chromaf(yuv->u2, x_u);
5849 
5850  s_u += 4;
5851 
5852  yuv->y0 = *(s_y++);
5853  yuv->y1 = *(s_y++);
5854 
5855  yuv->v2 = avg_chromaf(s_v[0], s_v[1]);
5856  x_v = avg_chromaf(s_v[2], s_v[3]);
5857  yuv->v2 = avg_chromaf(yuv->v2, x_v);
5858 
5859  s_v += 4;
5860 
5861  yuv->y2 = *(s_y++);
5862  yuv->y3 = *(s_y++);
5863  }
5864  s_u += irowstride;
5865  s_v += irowstride;
5866  }
5867 }
5868 
5869 
5870 static void convert_uyvy_to_yuvp_frame(uyvy_macropixel *uyvy, int width, int height, int irow, int *orow, uint8_t **dest,
5871  boolean add_alpha) {
5872  // TODO - avg_chroma
5873 
5874  uint8_t *y = dest[0];
5875  uint8_t *u = dest[1];
5876  uint8_t *v = dest[2];
5877 
5878  irow /= 4;
5879 
5880  for (int k = 0; k < height; k++) {
5881  for (int x = 0, x1 = 0; x < width; x++, x1 += 2) {
5882  u[k * orow[0] + x1] = u[k * orow[0] + x1 + 1] = uyvy[k * irow + x].u0;
5883  y[k * orow[1] + x1] = uyvy[k * irow + x].y0;
5884  v[k * orow[2] + x1] = v[k * orow[2] + x1 + 1] = uyvy[k * irow + x].v0;
5885  y[k * orow[0] + x1 + 1] = uyvy[k * irow + x].y1;
5886  }
5887  }
5888  if (add_alpha) lives_memset(dest[3], 255, orow[3] * height);
5889 }
5890 
5891 
5892 static void convert_yuyv_to_yuvp_frame(yuyv_macropixel *yuyv, int width, int height, int irow, int *orow,
5893  uint8_t **dest, boolean add_alpha) {
5894  // TODO - avg_chroma
5895 
5896  uint8_t *y = dest[0];
5897  uint8_t *u = dest[1];
5898  uint8_t *v = dest[2];
5899 
5900  irow /= 4;
5901 
5902  for (int k = 0; k < height; k++) {
5903  for (int x = 0, x1 = 0; x < width; x++, x1 += 2) {
5904  y[k * orow[1] + x1] = yuyv[k * irow + x].y0;
5905  u[k * orow[0] + x1] = u[k * orow[0] + x1 + 1] = yuyv[k * irow + x].u0;
5906  y[k * orow[0] + x1 + 1] = yuyv[k * irow + x].y1;
5907  v[k * orow[2] + x1] = v[k * orow[2] + x1 + 1] = yuyv[k * irow + x].v0;
5908  }
5909  }
5910  if (add_alpha) lives_memset(dest[3], 255, orow[3] * height);
5911 }
5912 
5913 
5914 static void convert_uyvy_to_yuv888_frame(uyvy_macropixel *uyvy, int width, int height, int irow, int orow,
5915  uint8_t *yuv, boolean add_alpha) {
5916  // no subsampling : TODO
5917 
5918  irow /= 4;
5919 
5920  for (int y = 0; y < height; y++) {
5921  for (int x = 0, x1 = 0; x < width; x++) {
5922  yuv[y * orow + x1++] = uyvy[y * irow + x].y0;
5923  yuv[y * orow + x1++] = uyvy[y * irow + x].u0;
5924  yuv[y * orow + x1++] = uyvy[y * irow + x].v0;
5925  if (add_alpha) yuv[y * orow + x1++] = 255;
5926  yuv[y * orow + x1++] = uyvy[y * irow + x].y1;
5927  yuv[y * orow + x1++] = uyvy[y * irow + x].u0;
5928  yuv[y * orow + x1++] = uyvy[y * irow + x].v0;
5929  if (add_alpha) yuv[y * orow + x1++] = 255;
5930  }
5931  }
5932 }
5933 
5934 
5935 static void convert_yuyv_to_yuv888_frame(yuyv_macropixel *yuyv, int width, int height, int irow, int orow,
5936  uint8_t *yuv, boolean add_alpha) {
5937  // no subsampling : TODO
5938 
5939  irow /= 4;
5940 
5941  for (int y = 0; y < height; y++) {
5942  for (int x = 0, x1 = 0; x < width; x++) {
5943  yuv[y * orow + x1++] = yuyv[y * irow + x].y0;
5944  yuv[y * orow + x1++] = yuyv[y * irow + x].u0;
5945  yuv[y * orow + x1++] = yuyv[y * irow + x].v0;
5946  if (add_alpha) yuv[y * orow + x1++] = 255;
5947  yuv[y * orow + x1++] = yuyv[y * irow + x].y1;
5948  yuv[y * orow + x1++] = yuyv[y * irow + x].u0;
5949  yuv[y * orow + x1++] = yuyv[y * irow + x].v0;
5950  if (add_alpha) yuv[y * orow + x1++] = 255;
5951  }
5952  }
5953 }
5954 
5955 
5956 static void convert_uyvy_to_yuv420_frame(uyvy_macropixel *uyvy, int width, int height, uint8_t **yuv, int clamping) {
5957  // subsample vertically
5958 
5959  // TODO - handle different sampling types
5960 
5961  register int j;
5962 
5963  uint8_t *y = yuv[0];
5964  uint8_t *u = yuv[1];
5965  uint8_t *v = yuv[2];
5966 
5967  boolean chroma = TRUE;
5968 
5969  uint8_t *end = y + width * height * 2;
5970 
5971  set_conversion_arrays(clamping, WEED_YUV_SUBSPACE_YCBCR);
5972 
5973  while (y < end) {
5974  for (j = 0; j < width; j++) {
5975  if (chroma) *(u++) = uyvy->u0;
5976  else {
5977  *u = avg_chromaf(*u, uyvy->u0);
5978  u++;
5979  }
5980  *(y++) = uyvy->y0;
5981  if (chroma) *(v++) = uyvy->v0;
5982  else {
5983  *v = avg_chromaf(*v, uyvy->v0);
5984  v++;
5985  }
5986  *(y++) = uyvy->y1;
5987  uyvy++;
5988  }
5989  if (chroma) {
5990  u -= width;
5991  v -= width;
5992  }
5993  chroma = !chroma;
5994  }
5995 }
5996 
5997 
5998 static void convert_yuyv_to_yuv420_frame(yuyv_macropixel *yuyv, int width, int height, uint8_t **yuv, int clamping) {
5999  // subsample vertically
6000 
6001  // TODO - handle different sampling types
6002 
6003  register int j;
6004 
6005  uint8_t *y = yuv[0];
6006  uint8_t *u = yuv[1];
6007  uint8_t *v = yuv[2];
6008 
6009  boolean chroma = TRUE;
6010 
6011  uint8_t *end = y + width * height * 2;
6012 
6013  set_conversion_arrays(clamping, WEED_YUV_SUBSPACE_YCBCR);
6014 
6015  while (y < end) {
6016  for (j = 0; j < width; j++) {
6017  *(y++) = yuyv->y0;
6018  if (chroma) *(u++) = yuyv->u0;
6019  else {
6020  *u = avg_chromaf(*u, yuyv->u0);
6021  u++;
6022  }
6023  *(y++) = yuyv->y1;
6024  if (chroma) *(v++) = yuyv->v0;
6025  else {
6026  *v = avg_chromaf(*v, yuyv->v0);
6027  v++;
6028  }
6029  yuyv++;
6030  }
6031  if (chroma) {
6032  u -= width;
6033  v -= width;
6034  }
6035  chroma = !chroma;
6036  }
6037 }
6038 
6039 
6040 static void convert_uyvy_to_yuv411_frame(uyvy_macropixel *uyvy, int width, int height, yuv411_macropixel *yuv, int clamping) {
6041  // subsample chroma horizontally
6042 
6043  uyvy_macropixel *end = uyvy + width * height;
6044  register int x;
6045 
6046  int widtha = (width << 1) >> 1;
6047  size_t cbytes = width - widtha;
6048 
6049  set_conversion_arrays(clamping, WEED_YUV_SUBSPACE_YCBCR);
6050 
6051  for (; uyvy < end; uyvy += cbytes) {
6052  for (x = 0; x < widtha; x += 2) {
6053  yuv->u2 = avg_chromaf(uyvy[0].u0, uyvy[1].u0);
6054 
6055  yuv->y0 = uyvy[0].y0;
6056  yuv->y1 = uyvy[0].y1;
6057 
6058  yuv->v2 = avg_chromaf(uyvy[0].v0, uyvy[1].v0);
6059 
6060  yuv->y2 = uyvy[1].y0;
6061  yuv->y3 = uyvy[1].y1;
6062 
6063  uyvy += 2;
6064  yuv++;
6065  }
6066  }
6067 }
6068 
6069 
6070 static void convert_yuyv_to_yuv411_frame(yuyv_macropixel *yuyv, int width, int height, yuv411_macropixel *yuv, int clamping) {
6071  // subsample chroma horizontally
6072 
6073  // TODO - handle different sampling types
6074 
6075  yuyv_macropixel *end = yuyv + width * height;
6076  register int x;
6077 
6078  int widtha = (width << 1) >> 1;
6079  size_t cybtes = width - widtha;
6080 
6081  set_conversion_arrays(clamping, WEED_YUV_SUBSPACE_YCBCR);
6082 
6083  for (; yuyv < end; yuyv += cybtes) {
6084  for (x = 0; x < widtha; x += 2) {
6085  yuv->u2 = avg_chromaf(yuyv[0].u0, yuyv[1].u0);
6086 
6087  yuv->y0 = yuyv[0].y0;
6088  yuv->y1 = yuyv[0].y1;
6089 
6090  yuv->v2 = avg_chromaf(yuyv[0].v0, yuyv[1].v0);
6091 
6092  yuv->y2 = yuyv[1].y0;
6093  yuv->y3 = yuyv[1].y1;
6094 
6095  yuyv += 2;
6096  yuv++;
6097  }
6098  }
6099 }
6100 
6101 
6102 static void convert_yuv888_to_yuv420_frame(uint8_t *yuv8, int width, int height, int irowstride, int *orows,
6103  uint8_t **yuv4, boolean src_alpha, int clamping) {
6104  // subsample vertically and horizontally
6105 
6106  //
6107 
6108  // yuv888(8) packed to 420p
6109 
6110  // TODO - handle different sampling types
6111 
6112  // TESTED !
6113 
6114  register int j;
6115  register short x_u, x_v;
6116 
6117  uint8_t *d_y, *d_u, *d_v, *end;
6118 
6119  boolean chroma = TRUE;
6120 
6121  size_t ipsize = 3, ipsize2;
6122  int widthx;
6123 
6124  set_conversion_arrays(clamping, WEED_YUV_SUBSPACE_YCBCR);
6125 
6126  if (src_alpha) ipsize = 4;
6127 
6128  d_y = yuv4[0];
6129  d_u = yuv4[1];
6130  d_v = yuv4[2];
6131 
6132  end = d_y + width * height;
6133  ipsize2 = ipsize * 2;
6134  widthx = width * ipsize;
6135 
6136  while (d_y < end) {
6137  for (j = 0; j < widthx; j += ipsize2) {
6138  *(d_y++) = yuv8[j];
6139  *(d_y++) = yuv8[j + ipsize];
6140  if (chroma) {
6141  *(d_u++) = avg_chromaf(yuv8[j + 1], yuv8[j + 1 + ipsize]);
6142  *(d_v++) = avg_chromaf(yuv8[j + 2], yuv8[j + 2 + ipsize]);
6143  } else {
6144  x_u = avg_chromaf(yuv8[j + 1], yuv8[j + 1 + ipsize]);
6145  *d_u = avg_chromaf(*d_u, x_u);
6146  d_u++;
6147  x_v = avg_chromaf(yuv8[j + 2], yuv8[j + 2 + ipsize]);
6148  *d_v = avg_chromaf(*d_v, x_v);
6149  d_v++;
6150  }
6151  }
6152  if (chroma) {
6153  d_u -= orows[1];
6154  d_v -= orows[2];
6155  }
6156  chroma = !chroma;
6157  yuv8 += irowstride;
6158  }
6159 }
6160 
6161 
6162 static void convert_uyvy_to_yuv422_frame(uyvy_macropixel *uyvy, int width, int height, uint8_t **yuv) {
6163  int size = width * height; // y is twice this, u and v are equal
6164 
6165  uint8_t *y = yuv[0];
6166  uint8_t *u = yuv[1];
6167  uint8_t *v = yuv[2];
6168 
6169  register int x;
6170 
6171  for (x = 0; x < size; x++) {
6172  uyvy_2_yuv422(uyvy, y, u, v, y + 1);
6173  y += 2;
6174  u++;
6175  v++;
6176  }
6177 }
6178 
6179 
6180 static void convert_yuyv_to_yuv422_frame(yuyv_macropixel *yuyv, int width, int height, uint8_t **yuv) {
6181  int size = width * height; // y is twice this, u and v are equal
6182 
6183  uint8_t *y = yuv[0];
6184  uint8_t *u = yuv[1];
6185  uint8_t *v = yuv[2];
6186 
6187  register int x;
6188 
6189  for (x = 0; x < size; x++) {
6190  yuyv_2_yuv422(yuyv, y, u, v, y + 1);
6191  y += 2;
6192  u++;
6193  v++;
6194  }
6195 }
6196 
6197 
6198 static void convert_yuv888_to_yuv422_frame(uint8_t *yuv8, int width, int height, int irowstride, int *ostrides,
6199  uint8_t **yuv4, boolean has_alpha, int clamping) {
6200  // 888(8) packed to 422p
6201 
6202  // TODO - handle different sampling types
6203 
6204  int size = width * height; // y is equal this, u and v are half, chroma subsampled horizontally
6205 
6206  uint8_t *y = yuv4[0];
6207  uint8_t *u = yuv4[1];
6208  uint8_t *v = yuv4[2];
6209 
6210  register int x, i, j;
6211 
6212  int offs = 0;
6213  size_t ipsize;
6214 
6215  set_conversion_arrays(clamping, WEED_YUV_SUBSPACE_YCBCR);
6216 
6217  if (has_alpha) offs = 1;
6218 
6219  ipsize = (3 + offs) << 1;
6220 
6221  if ((irowstride << 1) == width * ipsize && ostrides[0] == width && ostrides[1] == (width >> 1)) {
6222  for (x = 0; x < size; x += 2) {
6223  *(y++) = yuv8[0];
6224  *(y++) = yuv8[3 + offs];
6225  *(u++) = avg_chromaf(yuv8[1], yuv8[4 + offs]);
6226  *(v++) = avg_chromaf(yuv8[2], yuv8[5 + offs]);
6227  yuv8 += ipsize;
6228  }
6229  } else {
6230  width >>= 1;
6231  irowstride -= width * ipsize;
6232  ostrides[0] -= width;
6233  ostrides[1] -= width >> 1;
6234  ostrides[2] -= width >> 1;
6235 
6236  for (i = 0; i < height; i++) {
6237  for (j = 0; j < width; j++) {
6238  *(y++) = yuv8[0];
6239  *(y++) = yuv8[3 + offs];
6240  *(u++) = avg_chromaf(yuv8[1], yuv8[4 + offs]);
6241  *(v++) = avg_chromaf(yuv8[2], yuv8[5 + offs]);
6242  yuv8 += ipsize;
6243  }
6244  yuv8 += irowstride;
6245  y += ostrides[0];
6246  u += ostrides[1];
6247  v += ostrides[2];
6248  }
6249  }
6250 }
6251 
6252 
6253 static void convert_yuv888_to_uyvy_frame(uint8_t *yuv, int width, int height, int irowstride, int orow,
6254  uyvy_macropixel *uyvy, boolean has_alpha, int clamping) {
6255  int size = width * height;
6256 
6257  register int x, i, j;
6258 
6259  int offs = 0;
6260  size_t ipsize;
6261 
6262  set_conversion_arrays(clamping, WEED_YUV_SUBSPACE_YCBCR);
6263 
6264  if (has_alpha) offs = 1;
6265 
6266  ipsize = (3 + offs) << 1;
6267 
6268  if ((irowstride << 1) == width * ipsize && (width << 1) == orow) {
6269  for (x = 0; x < size; x += 2) {
6270  uyvy->u0 = avg_chromaf(yuv[1], yuv[4 + offs]);
6271  uyvy->y0 = yuv[0];
6272  uyvy->v0 = avg_chromaf(yuv[2], yuv[5 + offs]);
6273  uyvy->y1 = yuv[3 + offs];
6274  yuv += ipsize;
6275  uyvy++;
6276  }
6277  } else {
6278  orow -= width << 1;
6279  width >>= 1;
6280  irowstride -= width * ipsize;
6281  for (i = 0; i < height; i++) {
6282  for (j = 0; j < width; j++) {
6283  uyvy->u0 = avg_chromaf(yuv[1], yuv[4 + offs]);
6284  uyvy->y0 = yuv[0];
6285  uyvy->v0 = avg_chromaf(yuv[2], yuv[5 + offs]);
6286  uyvy->y1 = yuv[3 + offs];
6287  yuv += ipsize;
6288  uyvy++;
6289  }
6290  uyvy += orow;
6291  yuv += irowstride;
6292  }
6293  }
6294 }
6295 
6296 
6297 static void convert_yuv888_to_yuyv_frame(uint8_t *yuv, int width, int height, int irowstride, int orow,
6298  yuyv_macropixel *yuyv, boolean has_alpha, int clamping) {
6299  int size = width * height;
6300 
6301  register int x, i, j;
6302 
6303  int offs = 0;
6304  size_t ipsize;
6305 
6306  set_conversion_arrays(clamping, WEED_YUV_SUBSPACE_YCBCR);
6307 
6308  if (has_alpha) offs = 1;
6309 
6310  ipsize = (3 + offs) << 1;
6311 
6312  if (irowstride << 1 == width * ipsize && (width << 1) == orow) {
6313  for (x = 0; x < size; x += 2) {
6314  yuyv->y0 = yuv[0];
6315  yuyv->u0 = avg_chromaf(yuv[1], yuv[4 + offs]);
6316  yuyv->y1 = yuv[3 + offs];
6317  yuyv->v0 = avg_chromaf(yuv[2], yuv[5 + offs]);
6318  yuv += ipsize;
6319  yuyv++;
6320  }
6321  } else {
6322  orow -= width << 1;
6323  width >>= 1;
6324  irowstride -= width * ipsize;
6325  for (i = 0; i < height; i++) {
6326  for (j = 0; j < width; j++) {
6327  yuyv->y0 = yuv[0];
6328  yuyv->u0 = avg_chromaf(yuv[1], yuv[4 + offs]);
6329  yuyv->y1 = yuv[3 + offs];
6330  yuyv->v0 = avg_chromaf(yuv[2], yuv[5 + offs]);
6331  yuv += ipsize;
6332  yuyv++;
6333  }
6334  yuyv += orow;
6335  yuv += irowstride;
6336  }
6337  }
6338 }
6339 
6340 
6341 static void convert_yuv888_to_yuv411_frame(uint8_t *yuv8, int width, int height, int irowstride,
6342  yuv411_macropixel *yuv411, boolean has_alpha) {
6343  // yuv 888(8) packed to yuv411. Chroma pixels are averaged.
6344 
6345  // TODO - handle different sampling types
6346 
6347  uint8_t *end = yuv8 + width * height;
6348  register int x;
6349  size_t ipsize = 3;
6350  int widtha = (width >> 1) << 1; // cut rightmost odd bytes
6351  int cbytes = width - widtha;
6352 
6353  if (has_alpha) ipsize = 4;
6354 
6355  irowstride -= widtha * ipsize;
6356 
6357  for (; yuv8 < end; yuv8 += cbytes) {
6358  for (x = 0; x < widtha; x += 4) { // process 4 input pixels for one output macropixel
6359  yuv411->u2 = (yuv8[1] + yuv8[ipsize + 1] + yuv8[2 * ipsize + 1] + yuv8[3 * ipsize + 1]) >> 2;
6360  yuv411->y0 = yuv8[0];
6361  yuv411->y1 = yuv8[ipsize];
6362  yuv411->v2 = (yuv8[2] + yuv8[ipsize + 2] + yuv8[2 * ipsize + 2] + yuv8[3 * ipsize + 2]) >> 2;
6363  yuv411->y2 = yuv8[ipsize * 2];
6364  yuv411->y3 = yuv8[ipsize * 3];
6365 
6366  yuv411++;
6367  yuv8 += ipsize * 4;
6368  }
6369  yuv8 += irowstride;
6370  }
6371 }
6372 
6373 
6374 static void convert_yuv411_to_rgb_frame(yuv411_macropixel *yuv411, int width, int height, int orowstride,
6375  uint8_t *dest, boolean add_alpha, int clamping) {
6376  uyvy_macropixel uyvy;
6377  int m = 3, n = 4, o = 5;
6378  uint8_t u, v, h_u, h_v, q_u, q_v, y0, y1;
6379  register int j;
6380  yuv411_macropixel *end = yuv411 + width * height;
6381  size_t psize = 3, psize2;
6382 
6383  if (LIVES_UNLIKELY(!conv_YR_inited)) init_YUV_to_RGB_tables();
6384 
6385  set_conversion_arrays(clamping, WEED_YUV_SUBSPACE_YCBCR);
6386 
6387  if (add_alpha) {
6388  m = 4;
6389  n = 5;
6390  o = 6;
6391  psize = 4;
6392  }
6393 
6394  orowstride -= width * 4 * psize;
6395  psize2 = psize << 1;
6396 
6397  while (yuv411 < end) {
6398  // write 2 RGB pixels
6399  if (add_alpha) dest[3] = dest[7] = 255;
6400 
6401  uyvy.y0 = yuv411[0].y0;
6402  uyvy.y1 = yuv411[0].y1;
6403  uyvy.u0 = yuv411[0].u2;
6404  uyvy.v0 = yuv411[0].v2;
6405  uyvy2rgb(&uyvy, &dest[0], &(dest[1]), &dest[2], &dest[m], &dest[n], &dest[o]);
6406  dest += psize2;
6407 
6408  for (j = 1; j < width; j++) {
6409  // convert 6 yuv411 bytes to 4 rgb(a) pixels
6410 
6411  // average first 2 RGB pixels of this block and last 2 RGB pixels of previous block
6412 
6413  y0 = yuv411[j - 1].y2;
6414  y1 = yuv411[j - 1].y3;
6415 
6416  h_u = avg_chromaf(yuv411[j - 1].u2, yuv411[j].u2);
6417  h_v = avg_chromaf(yuv411[j - 1].v2, yuv411[j].v2);
6418 
6419  // now we have 1/2, 1/2
6420 
6421  // average last pixel again to get 1/4, 1/2
6422 
6423  q_u = avg_chromaf(h_u, yuv411[j - 1].u2);
6424  q_v = avg_chromaf(h_v, yuv411[j - 1].v2);
6425 
6426  // average again to get 1/8, 3/8
6427 
6428  u = avg_chromaf(q_u, yuv411[j - 1].u2);
6429  v = avg_chromaf(q_v, yuv411[j - 1].v2);
6430 
6431  yuv2rgb(y0, u, v, &dest[0], &dest[1], &dest[2]);
6432 
6433  u = avg_chromaf(q_u, yuv411[j].u2);
6434  v = avg_chromaf(q_v, yuv411[j].v2);
6435 
6436  yuv2rgb(y1, u, v, &dest[m], &dest[n], &dest[o]);
6437 
6438  dest += psize2;
6439 
6440  // set first 2 RGB pixels of this block
6441 
6442  y0 = yuv411[j].y0;
6443  y1 = yuv411[j].y1;
6444 
6445  // avg to get 3/4, 1/2
6446 
6447  q_u = avg_chromaf(h_u, yuv411[j].u2);
6448  q_v = avg_chromaf(h_v, yuv411[j].v2);
6449 
6450  // average again to get 5/8, 7/8
6451 
6452  u = avg_chromaf(q_u, yuv411[j - 1].u2);
6453  v = avg_chromaf(q_v, yuv411[j - 1].v2);
6454 
6455  yuv2rgb(y0, u, v, &dest[0], &dest[1], &dest[2]);
6456 
6457  u = avg_chromaf(q_u, yuv411[j].u2);
6458  v = avg_chromaf(q_v, yuv411[j].v2);
6459 
6460  yuv2rgb(y1, u, v, &dest[m], &dest[n], &dest[o]);
6461 
6462  if (add_alpha) dest[3] = dest[7] = 255;
6463  dest += psize2;
6464 
6465  }
6466  // write last 2 pixels
6467 
6468  if (add_alpha) dest[3] = dest[7] = 255;
6469 
6470  uyvy.y0 = yuv411[j - 1].y2;
6471  uyvy.y1 = yuv411[j - 1].y3;
6472  uyvy.u0 = yuv411[j - 1].u2;
6473  uyvy.v0 = yuv411[j - 1].v2;
6474  uyvy2rgb(&uyvy, &dest[0], &(dest[1]), &dest[2], &dest[m], &dest[n], &dest[o]);
6475 
6476  dest += psize2 + orowstride;
6477  yuv411 += width;
6478  }
6479 }
6480 
6481 
6482 static void convert_yuv411_to_bgr_frame(yuv411_macropixel *yuv411, int width, int height, int orowstride,
6483  uint8_t *dest, boolean add_alpha, int clamping) {
6484  uyvy_macropixel uyvy;
6485  int m = 3, n = 4, o = 5;
6486  uint8_t u, v, h_u, h_v, q_u, q_v, y0, y1;
6487  register int j;
6488  yuv411_macropixel *end = yuv411 + width * height;
6489  size_t psize = 3, psize2;
6490 
6491  if (LIVES_UNLIKELY(!conv_YR_inited)) init_YUV_to_RGB_tables();
6492 
6493  set_conversion_arrays(clamping, WEED_YUV_SUBSPACE_YCBCR);
6494 
6495  if (add_alpha) {
6496  m = 4;
6497  n = 5;
6498  o = 6;
6499  psize = 4;
6500  }
6501 
6502  orowstride -= width * 4 * psize;
6503 
6504  psize2 = psize << 1;
6505 
6506  while (yuv411 < end) {
6507  // write 2 RGB pixels
6508  if (add_alpha) dest[3] = dest[7] = 255;
6509 
6510  uyvy.y0 = yuv411[0].y0;
6511  uyvy.y1 = yuv411[0].y1;
6512  uyvy.u0 = yuv411[0].u2;
6513  uyvy.v0 = yuv411[0].v2;
6514  uyvy2rgb(&uyvy, &dest[0], &(dest[1]), &dest[2], &dest[o], &dest[n], &dest[m]);
6515  dest += psize2;
6516 
6517  for (j = 1; j < width; j++) {
6518  // convert 6 yuv411 bytes to 4 rgb(a) pixels
6519 
6520  // average first 2 RGB pixels of this block and last 2 RGB pixels of previous block
6521 
6522  y0 = yuv411[j - 1].y2;
6523  y1 = yuv411[j - 1].y3;
6524 
6525  h_u = avg_chromaf(yuv411[j - 1].u2, yuv411[j].u2);
6526  h_v = avg_chromaf(yuv411[j - 1].v2, yuv411[j].v2);
6527 
6528  // now we have 1/2, 1/2
6529 
6530  // average last pixel again to get 1/4, 1/2
6531 
6532  q_u = avg_chromaf(h_u, yuv411[j - 1].u2);
6533  q_v = avg_chromaf(h_v, yuv411[j - 1].v2);
6534 
6535  // average again to get 1/8, 3/8
6536 
6537  u = avg_chromaf(q_u, yuv411[j - 1].u2);
6538  v = avg_chromaf(q_v, yuv411[j - 1].v2);
6539 
6540  yuv2bgr(y0, u, v, &dest[0], &dest[1], &dest[2]);
6541 
6542  u = avg_chromaf(q_u, yuv411[j].u2);
6543  v = avg_chromaf(q_v, yuv411[j].v2);
6544 
6545  yuv2bgr(y1, u, v, &dest[m], &dest[n], &dest[o]);
6546 
6547  dest += psize2;
6548 
6549  // set first 2 RGB pixels of this block
6550 
6551  y0 = yuv411[j].y0;
6552  y1 = yuv411[j].y1;
6553 
6554  // avg to get 3/4, 1/2
6555 
6556  q_u = avg_chromaf(h_u, yuv411[j].u2);
6557  q_v = avg_chromaf(h_v, yuv411[j].v2);
6558 
6559  // average again to get 5/8, 7/8
6560 
6561  u = avg_chromaf(q_u, yuv411[j - 1].u2);
6562  v = avg_chromaf(q_v, yuv411[j - 1].v2);
6563 
6564  yuv2bgr(y0, u, v, &dest[0], &dest[1], &dest[2]);
6565 
6566  u = avg_chromaf(q_u, yuv411[j].u2);
6567  v = avg_chromaf(q_v, yuv411[j].v2);
6568 
6569  yuv2bgr(y1, u, v, &dest[m], &dest[n], &dest[o]);
6570 
6571  if (add_alpha) dest[3] = dest[7] = 255;
6572  dest += psize2;
6573 
6574  }
6575  // write last 2 pixels
6576 
6577  if (add_alpha) dest[3] = dest[7] = 255;
6578 
6579  uyvy.y0 = yuv411[j - 1].y2;
6580  uyvy.y1 = yuv411[j - 1].y3;
6581  uyvy.u0 = yuv411[j - 1].u2;
6582  uyvy.v0 = yuv411[j - 1].v2;
6583  uyvy2rgb(&uyvy, &dest[0], &(dest[1]), &dest[2], &dest[m], &dest[n], &dest[o]);
6584 
6585  dest += psize2 + orowstride;
6586  yuv411 += width;
6587  }
6588 }
6589 
6590 
6591 static void convert_yuv411_to_argb_frame(yuv411_macropixel *yuv411, int width, int height, int orowstride,
6592  uint8_t *dest, int clamping) {
6593  uyvy_macropixel uyvy;
6594  uint8_t u, v, h_u, h_v, q_u, q_v, y0, y1;
6595  register int j;
6596  yuv411_macropixel *end = yuv411 + width * height;
6597  size_t psize = 4, psize2;
6598 
6599  if (LIVES_UNLIKELY(!conv_YR_inited)) init_YUV_to_RGB_tables();
6600 
6601  set_conversion_arrays(clamping, WEED_YUV_SUBSPACE_YCBCR);
6602 
6603  orowstride -= width * 4 * psize;
6604  psize2 = psize << 1;
6605 
6606  while (yuv411 < end) {
6607  // write 2 ARGB pixels
6608  dest[0] = dest[4] = 255;
6609 
6610  uyvy.y0 = yuv411[0].y0;
6611  uyvy.y1 = yuv411[0].y1;
6612  uyvy.u0 = yuv411[0].u2;
6613  uyvy.v0 = yuv411[0].v2;
6614  uyvy2rgb(&uyvy, &dest[1], &(dest[2]), &dest[3], &dest[5], &dest[6], &dest[7]);
6615  dest += psize2;
6616 
6617  for (j = 1; j < width; j++) {
6618  // convert 6 yuv411 bytes to 4 argb pixels
6619 
6620  // average first 2 ARGB pixels of this block and last 2 ARGB pixels of previous block
6621 
6622  y0 = yuv411[j - 1].y2;
6623  y1 = yuv411[j - 1].y3;
6624 
6625  h_u = avg_chromaf(yuv411[j - 1].u2, yuv411[j].u2);
6626  h_v = avg_chromaf(yuv411[j - 1].v2, yuv411[j].v2);
6627 
6628  // now we have 1/2, 1/2
6629 
6630  // average last pixel again to get 1/4, 1/2
6631 
6632  q_u = avg_chromaf(h_u, yuv411[j - 1].u2);
6633  q_v = avg_chromaf(h_v, yuv411[j - 1].v2);
6634 
6635  // average again to get 1/8, 3/8
6636 
6637  u = avg_chromaf(q_u, yuv411[j - 1].u2);
6638  v = avg_chromaf(q_v, yuv411[j - 1].v2);
6639 
6640  yuv2rgb(y0, u, v, &dest[1], &dest[2], &dest[3]);
6641 
6642  u = avg_chromaf(q_u, yuv411[j].u2);
6643  v = avg_chromaf(q_v, yuv411[j].v2);
6644 
6645  yuv2rgb(y1, u, v, &dest[5], &dest[6], &dest[7]);
6646 
6647  dest += psize2;
6648 
6649  // set first 2 ARGB pixels of this block
6650 
6651  y0 = yuv411[j].y0;
6652  y1 = yuv411[j].y1;
6653 
6654  // avg to get 3/4, 1/2
6655 
6656  q_u = avg_chromaf(h_u, yuv411[j].u2);
6657  q_v = avg_chromaf(h_v, yuv411[j].v2);
6658 
6659  // average again to get 5/8, 7/8
6660 
6661  u = avg_chromaf(q_u, yuv411[j - 1].u2);
6662  v = avg_chromaf(q_v, yuv411[j - 1].v2);
6663 
6664  yuv2rgb(y0, u, v, &dest[1], &dest[2], &dest[3]);
6665 
6666  u = avg_chromaf(q_u, yuv411[j].u2);
6667  v = avg_chromaf(q_v, yuv411[j].v2);
6668 
6669  yuv2rgb(y1, u, v, &dest[5], &dest[6], &dest[7]);
6670 
6671  dest[0] = dest[4] = 255;
6672  dest += psize2;
6673 
6674  }
6675  // write last 2 pixels
6676 
6677  dest[0] = dest[4] = 255;
6678 
6679  uyvy.y0 = yuv411[j - 1].y2;
6680  uyvy.y1 = yuv411[j - 1].y3;
6681  uyvy.u0 = yuv411[j - 1].u2;
6682  uyvy.v0 = yuv411[j - 1].v2;
6683  uyvy2rgb(&uyvy, &dest[1], &(dest[2]), &dest[3], &dest[5], &dest[6], &dest[7]);
6684 
6685  dest += psize2 + orowstride;
6686  yuv411 += width;
6687  }
6688 }
6689 
6690 
6691 static void convert_yuv411_to_yuv888_frame(yuv411_macropixel *yuv411, int width, int height,
6692  uint8_t *dest, boolean add_alpha, int clamping) {
6693  size_t psize = 3;
6694  register int j;
6695  yuv411_macropixel *end = yuv411 + width * height;
6696  uint8_t u, v, h_u, h_v, q_u, q_v, y0, y1;
6697 
6698  set_conversion_arrays(clamping, WEED_YUV_SUBSPACE_YCBCR);
6699 
6700  if (add_alpha) psize = 4;
6701 
6702  while (yuv411 < end) {
6703  // write 2 RGB pixels
6704  if (add_alpha) dest[3] = dest[7] = 255;
6705 
6706  // write first 2 pixels
6707  dest[0] = yuv411[0].y0;
6708  dest[1] = yuv411[0].u2;
6709  dest[2] = yuv411[0].v2;
6710  dest += psize;
6711 
6712  dest[0] = yuv411[0].y1;
6713  dest[1] = yuv411[0].u2;
6714  dest[2] = yuv411[0].v2;
6715  dest += psize;
6716 
6717  for (j = 1; j < width; j++) {
6718  // convert 6 yuv411 bytes to 4 rgb(a) pixels
6719 
6720  // average first 2 RGB pixels of this block and last 2 RGB pixels of previous block
6721 
6722  y0 = yuv411[j - 1].y2;
6723  y1 = yuv411[j - 1].y3;
6724 
6725  h_u = avg_chromaf(yuv411[j - 1].u2, yuv411[j].u2);
6726  h_v = avg_chromaf(yuv411[j - 1].v2, yuv411[j].v2);
6727 
6728  // now we have 1/2, 1/2
6729 
6730  // average last pixel again to get 1/4, 1/2
6731 
6732  q_u = avg_chromaf(h_u, yuv411[j - 1].u2);
6733  q_v = avg_chromaf(h_v, yuv411[j - 1].v2);
6734 
6735  // average again to get 1/8, 3/8
6736 
6737  u = avg_chromaf(q_u, yuv411[j - 1].u2);
6738  v = avg_chromaf(q_v, yuv411[j - 1].v2);
6739 
6740  dest[0] = y0;
6741  dest[1] = u;
6742  dest[2] = v;
6743  if (add_alpha) dest[3] = 255;
6744 
6745  dest += psize;
6746 
6747  u = avg_chromaf(q_u, yuv411[j].u2);
6748  v = avg_chromaf(q_v, yuv411[j].v2);
6749 
6750  dest[0] = y1;
6751  dest[1] = u;
6752  dest[2] = v;
6753  if (add_alpha) dest[3] = 255;
6754 
6755  dest += psize;
6756 
6757  // set first 2 RGB pixels of this block
6758 
6759  y0 = yuv411[j].y0;
6760  y1 = yuv411[j].y1;
6761 
6762  // avg to get 3/4, 1/2
6763 
6764  q_u = avg_chromaf(h_u, yuv411[j].u2);
6765  q_v = avg_chromaf(h_v, yuv411[j].v2);
6766 
6767  // average again to get 5/8, 7/8
6768 
6769  u = avg_chromaf(q_u, yuv411[j - 1].u2);
6770  v = avg_chromaf(q_v, yuv411[j - 1].v2);
6771 
6772  dest[0] = y0;
6773  dest[1] = u;
6774  dest[2] = v;
6775 
6776  if (add_alpha) dest[3] = 255;
6777  dest += psize;
6778 
6779  u = avg_chromaf(q_u, yuv411[j].u2);
6780  v = avg_chromaf(q_v, yuv411[j].v2);
6781 
6782  dest[0] = y1;
6783  dest[1] = u;
6784  dest[2] = v;
6785 
6786  if (add_alpha) dest[3] = 255;
6787  dest += psize;
6788  }
6789  // write last 2 pixels
6790 
6791  if (add_alpha) dest[3] = dest[7] = 255;
6792 
6793  dest[0] = yuv411[j - 1].y2;
6794  dest[1] = yuv411[j - 1].u2;
6795  dest[2] = yuv411[j - 1].v2;
6796  dest += psize;
6797 
6798  dest[0] = yuv411[j - 1].y3;
6799  dest[1] = yuv411[j - 1].u2;
6800  dest[2] = yuv411[j - 1].v2;
6801 
6802  dest += psize;
6803  yuv411 += width;
6804  }
6805 }
6806 
6807 
6808 static void convert_yuv411_to_yuvp_frame(yuv411_macropixel *yuv411, int width, int height, uint8_t **dest,
6809  boolean add_alpha, int clamping) {
6810  register int j;
6811  yuv411_macropixel *end = yuv411 + width * height;
6812  uint8_t u, v, h_u, h_v, q_u, q_v, y0;
6813 
6814  uint8_t *d_y = dest[0];
6815  uint8_t *d_u = dest[1];
6816  uint8_t *d_v = dest[2];
6817  uint8_t *d_a = dest[3];
6818 
6819  set_conversion_arrays(clamping, WEED_YUV_SUBSPACE_YCBCR);
6820 
6821  while (yuv411 < end) {
6822  // write first 2 pixels
6823  *(d_y++) = yuv411[0].y0;
6824  *(d_u++) = yuv411[0].u2;
6825  *(d_v++) = yuv411[0].v2;
6826  if (add_alpha) *(d_a++) = 255;
6827 
6828  *(d_y++) = yuv411[0].y0;
6829  *(d_u++) = yuv411[0].u2;
6830  *(d_v++) = yuv411[0].v2;
6831  if (add_alpha) *(d_a++) = 255;
6832 
6833  for (j = 1; j < width; j++) {
6834  // convert 6 yuv411 bytes to 4 rgb(a) pixels
6835 
6836  // average first 2 RGB pixels of this block and last 2 RGB pixels of previous block
6837 
6838  y0 = yuv411[j - 1].y2;
6839 
6840  h_u = avg_chromaf(yuv411[j - 1].u2, yuv411[j].u2);
6841  h_v = avg_chromaf(yuv411[j - 1].v2, yuv411[j].v2);
6842 
6843  // now we have 1/2, 1/2
6844 
6845  // average last pixel again to get 1/4, 1/2
6846 
6847  q_u = avg_chromaf(h_u, yuv411[j - 1].u2);
6848  q_v = avg_chromaf(h_v, yuv411[j - 1].v2);
6849 
6850  // average again to get 1/8, 3/8
6851 
6852  u = avg_chromaf(q_u, yuv411[j - 1].u2);
6853  v = avg_chromaf(q_v, yuv411[j - 1].v2);
6854 
6855  *(d_y++) = y0;
6856  *(d_u++) = u;
6857  *(d_v++) = v;
6858  if (add_alpha) *(d_a++) = 255;
6859 
6860  u = avg_chromaf(q_u, yuv411[j].u2);
6861  v = avg_chromaf(q_v, yuv411[j].v2);
6862 
6863  *(d_y++) = y0;
6864  *(d_u++) = u;
6865  *(d_v++) = v;
6866  if (add_alpha) *(d_a++) = 255;
6867 
6868  // set first 2 RGB pixels of this block
6869 
6870  y0 = yuv411[j].y0;
6871 
6872  // avg to get 3/4, 1/2
6873 
6874  q_u = avg_chromaf(h_u, yuv411[j].u2);
6875  q_v = avg_chromaf(h_v, yuv411[j].v2);
6876 
6877  // average again to get 5/8, 7/8
6878 
6879  u = avg_chromaf(q_u, yuv411[j - 1].u2);
6880  v = avg_chromaf(q_v, yuv411[j - 1].v2);
6881 
6882  *(d_y++) = y0;
6883  *(d_u++) = u;
6884  *(d_v++) = v;
6885  if (add_alpha) *(d_a++) = 255;
6886 
6887  u = avg_chromaf(q_u, yuv411[j].u2);
6888  v = avg_chromaf(q_v, yuv411[j].v2);
6889 
6890  *(d_y++) = y0;
6891  *(d_u++) = u;
6892  *(d_v++) = v;
6893  if (add_alpha) *(d_a++) = 255;
6894  }
6895  // write last 2 pixels
6896  *(d_y++) = yuv411[j - 1].y2;
6897  *(d_u++) = yuv411[j - 1].u2;
6898  *(d_v++) = yuv411[j - 1].v2;
6899  if (add_alpha) *(d_a++) = 255;
6900 
6901  *(d_y++) = yuv411[j - 1].y3;
6902  *(d_u++) = yuv411[j - 1].u2;
6903  *(d_v++) = yuv411[j - 1].v2;
6904  if (add_alpha) *(d_a++) = 255;
6905 
6906  yuv411 += width;
6907  }
6908 }
6909 
6910 
6911 static void convert_yuv411_to_uyvy_frame(yuv411_macropixel *yuv411, int width, int height,
6912  uyvy_macropixel *uyvy, int clamping) {
6913  register int j;
6914  yuv411_macropixel *end = yuv411 + width * height;
6915  uint8_t u, v, h_u, h_v, y0;
6916 
6917  set_conversion_arrays(clamping, WEED_YUV_SUBSPACE_YCBCR);
6918 
6919  while (yuv411 < end) {
6920  // write first uyvy pixel
6921  uyvy->u0 = yuv411->u2;
6922  uyvy->y0 = yuv411->y0;
6923  uyvy->v0 = yuv411->v2;
6924  uyvy->y1 = yuv411->y1;
6925 
6926  uyvy++;
6927 
6928  for (j = 1; j < width; j++) {
6929  // convert 6 yuv411 bytes to 2 uyvy macro pixels
6930 
6931  // average first 2 RGB pixels of this block and last 2 RGB pixels of previous block
6932 
6933  y0 = yuv411[j - 1].y2;
6934 
6935  h_u = avg_chromaf(yuv411[j - 1].u2, yuv411[j].u2);
6936  h_v = avg_chromaf(yuv411[j - 1].v2, yuv411[j].v2);
6937 
6938  // now we have 1/2, 1/2
6939 
6940  // average last pixel again to get 1/4
6941 
6942  u = avg_chromaf(h_u, yuv411[j - 1].u2);
6943  v = avg_chromaf(h_v, yuv411[j - 1].v2);
6944 
6945  uyvy->u0 = u;
6946  uyvy->y0 = y0;
6947  uyvy->v0 = v;
6948  uyvy->y1 = y0;
6949 
6950  uyvy++;
6951 
6952  // average last pixel again to get 3/4
6953 
6954  u = avg_chromaf(h_u, yuv411[j].u2);
6955  v = avg_chromaf(h_v, yuv411[j].v2);
6956 
6957  // set first uyvy macropixel of this block
6958 
6959  y0 = yuv411[j].y0;
6960 
6961  uyvy->u0 = u;
6962  uyvy->y0 = y0;
6963  uyvy->v0 = v;
6964  uyvy->y1 = y0;
6965 
6966  uyvy++;
6967  }
6968  // write last uyvy macro pixel
6969  uyvy->u0 = yuv411[j - 1].u2;
6970  uyvy->y0 = yuv411[j - 1].y2;
6971  uyvy->v0 = yuv411[j - 1].v2;
6972  uyvy->y1 = yuv411[j - 1].y3;
6973 
6974  uyvy++;
6975 
6976  yuv411 += width;
6977  }
6978 }
6979 
6980 
6981 static void convert_yuv411_to_yuyv_frame(yuv411_macropixel *yuv411, int width, int height, yuyv_macropixel *yuyv,
6982  int clamping) {
6983  register int j;
6984  yuv411_macropixel *end = yuv411 + width * height;
6985  uint8_t u, v, h_u, h_v, y0;
6986 
6987  set_conversion_arrays(clamping, WEED_YUV_SUBSPACE_YCBCR);
6988 
6989  while (yuv411 < end) {
6990  // write first yuyv pixel
6991  yuyv->y0 = yuv411->y0;
6992  yuyv->u0 = yuv411->u2;
6993  yuyv->y1 = yuv411->y1;
6994  yuyv->v0 = yuv411->v2;
6995 
6996  yuyv++;
6997 
6998  for (j = 1; j < width; j++) {
6999  // convert 6 yuv411 bytes to 2 yuyv macro pixels
7000 
7001  // average first 2 RGB pixels of this block and last 2 RGB pixels of previous block
7002 
7003  y0 = yuv411[j - 1].y2;
7004 
7005  h_u = avg_chromaf(yuv411[j - 1].u2, yuv411[j].u2);
7006  h_v = avg_chromaf(yuv411[j - 1].v2, yuv411[j].v2);
7007 
7008  // now we have 1/2, 1/2
7009 
7010  // average last pixel again to get 1/4
7011 
7012  u = avg_chromaf(h_u, yuv411[j - 1].u2);
7013  v = avg_chromaf(h_v, yuv411[j - 1].v2);
7014 
7015  yuyv->y0 = y0;
7016  yuyv->u0 = u;
7017  yuyv->y1 = y0;
7018  yuyv->v0 = v;
7019 
7020  yuyv++;
7021 
7022  // average last pixel again to get 3/4
7023 
7024  u = avg_chromaf(h_u, yuv411[j].u2);
7025  v = avg_chromaf(h_v, yuv411[j].v2);
7026 
7027  // set first yuyv macropixel of this block
7028 
7029  y0 = yuv411[j].y0;
7030 
7031  yuyv->y0 = y0;
7032  yuyv->u0 = u;
7033  yuyv->y1 = y0;
7034  yuyv->v0 = v;
7035 
7036  yuyv++;
7037  }
7038  // write last yuyv macro pixel
7039  yuyv->y0 = yuv411[j - 1].y2;
7040  yuyv->u0 = yuv411[j - 1].u2;
7041  yuyv->y1 = yuv411[j - 1].y3;
7042  yuyv->v0 = yuv411[j - 1].v2;
7043 
7044  yuyv++;
7045 
7046  yuv411 += width;
7047  }
7048 }
7049 
7050 
7051 static void convert_yuv411_to_yuv422_frame(yuv411_macropixel *yuv411, int width, int height, uint8_t **dest, int clamping) {
7052  register int j;
7053  yuv411_macropixel *end = yuv411 + width * height;
7054  uint8_t h_u, h_v;
7055 
7056  uint8_t *d_y = dest[0];
7057  uint8_t *d_u = dest[1];
7058  uint8_t *d_v = dest[2];
7059 
7060  set_conversion_arrays(clamping, WEED_YUV_SUBSPACE_YCBCR);
7061 
7062  while (yuv411 < end) {
7063  // write first 2 y and 1 uv pixel
7064  *(d_y++) = yuv411->y0;
7065  *(d_y++) = yuv411->y1;
7066  *(d_u++) = yuv411->u2;
7067  *(d_v++) = yuv411->v2;
7068 
7069  for (j = 1; j < width; j++) {
7070  // convert 6 yuv411 bytes to 2 yuyv macro pixels
7071 
7072  // average first 2 RGB pixels of this block and last 2 RGB pixels of previous block
7073 
7074  *(d_y++) = yuv411[j - 1].y2;
7075  *(d_y++) = yuv411[j - 1].y3;
7076 
7077  h_u = avg_chromaf(yuv411[j - 1].u2, yuv411[j].u2);
7078  h_v = avg_chromaf(yuv411[j - 1].v2, yuv411[j].v2);
7079 
7080  // now we have 1/2, 1/2
7081 
7082  // average last pixel again to get 1/4
7083 
7084  *(d_u++) = avg_chromaf(h_u, yuv411[j - 1].u2);
7085  *(d_v++) = avg_chromaf(h_v, yuv411[j - 1].v2);
7086 
7087  // average first pixel to get 3/4
7088 
7089  *(d_y++) = yuv411[j].y0;
7090  *(d_y++) = yuv411[j].y1;
7091 
7092  *(d_u++) = avg_chromaf(h_u, yuv411[j].u2);
7093  *(d_v++) = avg_chromaf(h_v, yuv411[j].v2);
7094 
7095  }
7096  // write last pixels
7097  *(d_y++) = yuv411[j - 1].y2;
7098  *(d_y++) = yuv411[j - 1].y3;
7099  *(d_u++) = yuv411[j - 1].u2;
7100  *(d_v++) = yuv411[j - 1].v2;
7101 
7102  yuv411 += width;
7103  }
7104 }
7105 
7106 
7107 static void convert_yuv411_to_yuv420_frame(yuv411_macropixel *yuv411, int width, int height, uint8_t **dest,
7108  boolean is_yvu, int clamping) {
7109  register int j;
7110  yuv411_macropixel *end = yuv411 + width * height;
7111  uint8_t h_u, h_v, u, v;
7112 
7113  uint8_t *d_y = dest[0];
7114  uint8_t *d_u;
7115  uint8_t *d_v;
7116 
7117  boolean chroma = FALSE;
7118 
7119  size_t width2 = width << 1;
7120 
7121  if (!is_yvu) {
7122  d_u = dest[1];
7123  d_v = dest[2];
7124  } else {
7125  d_u = dest[2];
7126  d_v = dest[1];
7127  }
7128 
7129  set_conversion_arrays(clamping, WEED_YUV_SUBSPACE_YCBCR);
7130 
7131  while (yuv411 < end) {
7132  // write first 2 y and 1 uv pixel
7133  *(d_y++) = yuv411->y0;
7134  *(d_y++) = yuv411->y1;
7135 
7136  u = yuv411->u2;
7137  v = yuv411->v2;
7138 
7139  if (!chroma) {
7140  *(d_u++) = u;
7141  *(d_v++) = v;
7142  } else {
7143  *d_u = avg_chromaf(*d_u, u);
7144  *d_v = avg_chromaf(*d_v, v);
7145  }
7146 
7147  for (j = 1; j < width; j++) {
7148  // convert 6 yuv411 bytes to 2 yuyv macro pixels
7149 
7150  // average first 2 RGB pixels of this block and last 2 RGB pixels of previous block
7151 
7152  *(d_y++) = yuv411[j - 1].y2;
7153  *(d_y++) = yuv411[j - 1].y3;
7154 
7155  h_u = avg_chromaf(yuv411[j - 1].u2, yuv411[j].u2);
7156  h_v = avg_chromaf(yuv411[j - 1].v2, yuv411[j].v2);
7157 
7158  // now we have 1/2, 1/2
7159 
7160  // average last pixel again to get 1/4
7161 
7162  u = avg_chromaf(h_u, yuv411[j - 1].u2);
7163  v = avg_chromaf(h_v, yuv411[j - 1].v2);
7164 
7165  if (!chroma) {
7166  *(d_u++) = u;
7167  *(d_v++) = v;
7168  } else {
7169  *d_u = avg_chromaf(*d_u, u);
7170  *d_v = avg_chromaf(*d_v, v);
7171  }
7172 
7173  // average first pixel to get 3/4
7174 
7175  *(d_y++) = yuv411[j].y0;
7176  *(d_y++) = yuv411[j].y1;
7177 
7178  u = avg_chromaf(h_u, yuv411[j].u2);
7179  v = avg_chromaf(h_v, yuv411[j].v2);
7180 
7181  if (!chroma) {
7182  *(d_u++) = u;
7183  *(d_v++) = v;
7184  } else {
7185  *d_u = avg_chromaf(*d_u, u);
7186  *d_v = avg_chromaf(*d_v, v);
7187  }
7188 
7189  }
7190 
7191  // write last pixels
7192  *(d_y++) = yuv411[j - 1].y2;
7193  *(d_y++) = yuv411[j - 1].y3;
7194 
7195  u = yuv411[j - 1].u2;
7196  v = yuv411[j - 1].v2;
7197 
7198  if (!chroma) {
7199  *(d_u++) = u;
7200  *(d_v++) = v;
7201 
7202  d_u -= width2;
7203  d_v -= width2;
7204 
7205  } else {
7206  *d_u = avg_chromaf(*d_u, u);
7207  *d_v = avg_chromaf(*d_v, v);
7208  }
7209 
7210  chroma = !chroma;
7211  yuv411 += width;
7212  }
7213 }
7214 
7215 
7216 static void convert_yuv420_to_yuv411_frame(uint8_t **src, int hsize, int vsize, yuv411_macropixel *dest,
7217  boolean is_422, int clamping) {
7218  // TODO -handle various sampling types
7219 
7220  register int i = 0, j;
7221  uint8_t *y, *u, *v, *end;
7222  boolean chroma = TRUE;
7223 
7224  size_t qwidth, hwidth;
7225 
7226  // TODO - handle different in sampling types
7227  set_conversion_arrays(clamping, WEED_YUV_SUBSPACE_YCBCR);
7228 
7229  y = src[0];
7230  u = src[1];
7231  v = src[2];
7232 
7233  end = y + hsize * vsize;
7234 
7235  hwidth = hsize >> 1;
7236  qwidth = hwidth >> 1;
7237 
7238  while (y < end) {
7239  for (j = 0; j < qwidth; j++) {
7240  dest->u2 = avg_chromaf(u[0], u[1]);
7241  dest->y0 = y[0];
7242  dest->y1 = y[1];
7243  dest->v2 = avg_chromaf(v[0], v[1]);
7244  dest->y2 = y[2];
7245  dest->y3 = y[3];
7246 
7247  if (!is_422 && chroma && i > 0) {
7248  dest[-qwidth].u2 = avg_chromaf(dest[-qwidth].u2, dest->u2);
7249  dest[-qwidth].v2 = avg_chromaf(dest[-qwidth].v2, dest->v2);
7250  }
7251  dest++;
7252  y += 4;
7253  u += 2;
7254  v += 2;
7255  }
7256  chroma = !chroma;
7257  if (!chroma && !is_422) {
7258  u -= hwidth;
7259  v -= hwidth;
7260  }
7261  i++;
7262  }
7263 }
7264 
7265 
7266 static void convert_splitplanes_frame(uint8_t *src, int width, int height, int irowstride, int *orowstrides,
7267  uint8_t **dest, boolean src_alpha, boolean dest_alpha) {
7268  // TODO - orowstrides
7269  // convert 888(8) packed to 444(4)P planar
7270  size_t size = width * height;
7271  int ipsize = 3;
7272 
7273  uint8_t *y = dest[0];
7274  uint8_t *u = dest[1];
7275  uint8_t *v = dest[2];
7276  uint8_t *a = dest_alpha ? dest[3] : NULL;
7277 
7278  uint8_t *end;
7279 
7280  register int i, j;
7281 
7282  if (src_alpha) ipsize = 4;
7283 
7284  if (irowstride == ipsize * width && irowstride == orowstrides[0] && irowstride == orowstrides[1]
7285  && irowstride == orowstrides[2] && (!dest_alpha || irowstride == orowstrides[3])) {
7286  for (end = src + size * ipsize; src < end;) {
7287  *(y++) = *(src++);
7288  *(u++) = *(src++);
7289  *(v++) = *(src++);
7290  if (dest_alpha) {
7291  if (src_alpha) *(a++) = *(src++);
7292  else *(a++) = 255;
7293  }
7294  }
7295  } else {
7296  orowstrides[0] -= width;
7297  orowstrides[1] -= width;
7298  orowstrides[2] -= width;
7299  width *= ipsize;
7300  irowstride -= width;
7301  if (dest_alpha) orowstrides[3] -= width;
7302  for (i = 0; i < height; i++) {
7303  for (j = 0; j < width; j += ipsize) {
7304  *(y++) = *(src++);
7305  *(u++) = *(src++);
7306  *(v++) = *(src++);
7307  if (dest_alpha) {
7308  if (src_alpha) *(a++) = *(src++);
7309  else *(a++) = 255;
7310  }
7311  }
7312  y += orowstrides[0];
7313  u += orowstrides[1];
7314  v += orowstrides[2];
7315  if (dest_alpha) {
7316  a += orowstrides[3];
7317  }
7318  src += irowstride;
7319  }
7320  }
7321 }
7322 
7323 
7325 // RGB palette conversions
7326 
7327 static void convert_swap3_frame(uint8_t *src, int width, int height, int irowstride, int orowstride,
7328  uint8_t *dest, uint8_t *gamma_lut, int thread_id) {
7329  // swap 3 byte palette
7330  uint8_t *end = src + height * irowstride;
7331  register int i;
7332 
7333  if (thread_id == -1 && prefs->nfx_threads > 1) {
7334  lives_thread_t threads[prefs->nfx_threads];
7335  int nthreads = 1;
7336  int dheight, xdheight;
7338 
7339  xdheight = CEIL((double)height / (double)prefs->nfx_threads, 4);
7340  for (i = prefs->nfx_threads - 1; i >= 0; i--) {
7341  dheight = xdheight;
7342 
7343  if ((src + dheight * i * irowstride) < end) {
7344  ccparams[i].src = src + dheight * i * irowstride;
7345  ccparams[i].hsize = width;
7346  ccparams[i].dest = dest + dheight * i * orowstride;
7347 
7348  if (dheight * (i + 1) > (height - 4)) {
7349  dheight = height - (dheight * i);
7350  }
7351 
7352  ccparams[i].vsize = dheight;
7353 
7354  ccparams[i].irowstrides[0] = irowstride;
7355  ccparams[i].orowstrides[0] = orowstride;
7356  ccparams[i].lut = gamma_lut;
7357  ccparams[i].thread_id = i;
7358 
7359  if (i == 0) convert_swap3_frame_thread(&ccparams[i]);
7360  else {
7361  lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_swap3_frame_thread, &ccparams[i]);
7362  nthreads++;
7363  }
7364  }
7365  }
7366 
7367  for (i = 1; i < nthreads; i++) {
7368  lives_thread_join(threads[i], NULL);
7369  }
7370  lives_free(ccparams);
7371  if (gamma_lut) lives_gamma_lut_free(gamma_lut);
7372  return;
7373  }
7374 
7375  if (src == dest) {
7376  uint8_t tmp;
7377  int width3 = width * 3;
7378  orowstride -= width3;
7379  for (; src < end; src += irowstride) {
7380  for (i = 0; i < width3; i += 3) {
7381  tmp = src[i];
7382  if (!gamma_lut) {
7383  dest[0] = src[i + 2]; // red
7384  dest[2] = tmp; // blue
7385  } else {
7386  dest[0] = gamma_lut[src[i + 2]]; // red
7387  dest[1] = gamma_lut[src[i + 1]]; // red
7388  dest[2] = gamma_lut[tmp]; // blue
7389  }
7390  dest += 3;
7391  }
7392  dest += orowstride;
7393  }
7394  return;
7395  }
7396 
7397  if ((irowstride == width * 3) && (orowstride == irowstride)) {
7398  // quick version
7399 #ifdef ENABLE_OIL
7400  if (!gamma_lut) {
7401  oil_rgb2bgr(dest, src, width * height);
7402  return;
7403  }
7404 #endif
7405  for (; src < end; src += 3) {
7406  if (!gamma_lut) {
7407  *(dest++) = src[2]; // red
7408  *(dest++) = src[1]; // green
7409  *(dest++) = src[0]; // blue
7410  } else {
7411  *(dest++) = gamma_lut[src[2]]; // red
7412  *(dest++) = gamma_lut[src[1]]; // green
7413  *(dest++) = gamma_lut[src[0]]; // blue
7414  }
7415  }
7416  } else {
7417  int width3 = width * 3;
7418  orowstride -= width3;
7419  for (; src < end; src += irowstride) {
7420  for (i = 0; i < width3; i += 3) {
7421  if (!gamma_lut) {
7422  *(dest++) = src[i + 2]; // red
7423  *(dest++) = src[i + 1]; // green
7424  *(dest++) = src[i]; // blue
7425  } else {
7426  *(dest++) = gamma_lut[src[2]]; // red
7427  *(dest++) = gamma_lut[src[1]]; // green
7428  *(dest++) = gamma_lut[src[0]]; // blue
7429  }
7430  }
7431  dest += orowstride;
7432  }
7433  }
7434 }
7435 
7436 
7437 static void *convert_swap3_frame_thread(void *data) {
7438  lives_cc_params *ccparams = (lives_cc_params *)data;
7439  convert_swap3_frame((uint8_t *)ccparams->src, ccparams->hsize, ccparams->vsize, ccparams->irowstrides[0],
7440  ccparams->orowstrides[0], (uint8_t *)ccparams->dest, ccparams->lut, ccparams->thread_id);
7441  return NULL;
7442 }
7443 
7444 
7445 static void convert_swap4_frame(uint8_t *src, int width, int height, int irowstride, int orowstride,
7446  uint8_t *dest, int thread_id) {
7447  // swap 4 byte palette
7448  uint8_t *end = src + height * irowstride;
7449  register int i;
7450 
7451  if (thread_id == -1 && prefs->nfx_threads > 1) {
7452  lives_thread_t threads[prefs->nfx_threads];
7453  int nthreads = 1;
7454  int dheight, xdheight;
7456 
7457  xdheight = CEIL((double)height / (double)prefs->nfx_threads, 4);
7458  for (i = prefs->nfx_threads - 1; i >= 0; i--) {
7459  dheight = xdheight;
7460 
7461  if ((src + dheight * i * irowstride) < end) {
7462  ccparams[i].src = src + dheight * i * irowstride;
7463  ccparams[i].hsize = width;
7464  ccparams[i].dest = dest + dheight * i * orowstride;
7465 
7466  if ((height - dheight * i) < dheight) dheight = height - (dheight * i);
7467 
7468  ccparams[i].vsize = dheight;
7469 
7470  ccparams[i].irowstrides[0] = irowstride;
7471  ccparams[i].orowstrides[0] = orowstride;
7472  ccparams[i].thread_id = i;
7473 
7474  if (i == 0) convert_swap4_frame_thread(&ccparams[i]);
7475  else {
7476  lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_swap4_frame_thread, &ccparams[i]);
7477  nthreads++;
7478  }
7479  }
7480  }
7481 
7482  for (i = 1; i < nthreads; i++) {
7483  lives_thread_join(threads[i], NULL);
7484  }
7485  lives_free(ccparams);
7486  return;
7487  }
7488 
7489  if (src == dest) {
7490  uint8_t tmp[4];
7491  int width4 = width * 4;
7492  orowstride -= width4;
7493  for (; src < end; src += irowstride) {
7494  for (i = 0; i < width4; i += 4) {
7495  tmp[0] = src[i + 3]; // alpha
7496  tmp[1] = src[i + 2]; // red
7497  tmp[2] = src[i + 1]; // green
7498  tmp[3] = src[i]; // blue
7499  lives_memcpy(dest, tmp, 4);
7500  dest += 4;
7501  }
7502  dest += orowstride;
7503  }
7504  return;
7505  }
7506 
7507  if ((irowstride == width * 4) && (orowstride == irowstride)) {
7508  // quick version
7509  for (; src < end; src += 4) {
7510  *(dest++) = src[3]; // alpha
7511  *(dest++) = src[2]; // red
7512  *(dest++) = src[1]; // green
7513  *(dest++) = src[0]; // blue
7514  }
7515  } else {
7516  int width4 = width * 4;
7517  orowstride -= width4;
7518  for (; src < end; src += irowstride) {
7519  for (i = 0; i < width4; i += 4) {
7520  *(dest++) = src[i + 3]; // alpha
7521  *(dest++) = src[i + 2]; // red
7522  *(dest++) = src[i + 1]; // green
7523  *(dest++) = src[i]; // blue
7524  }
7525  dest += orowstride;
7526  }
7527  }
7528 }
7529 
7530 
7531 static void *convert_swap4_frame_thread(void *data) {
7532  lives_cc_params *ccparams = (lives_cc_params *)data;
7533  convert_swap4_frame((uint8_t *)ccparams->src, ccparams->hsize, ccparams->vsize, ccparams->irowstrides[0],
7534  ccparams->orowstrides[0], (uint8_t *)ccparams->dest, ccparams->thread_id);
7535  return NULL;
7536 }
7537 
7538 
7539 static void convert_swap3addpost_frame(uint8_t *src, int width, int height, int irowstride, int orowstride,
7540  uint8_t *dest, int thread_id) {
7541  // swap 3 bytes, add post alpha
7542  uint8_t *end = src + height * irowstride;
7543  register int i;
7544 
7545  if (thread_id == -1 && prefs->nfx_threads > 1) {
7546  lives_thread_t threads[prefs->nfx_threads];
7547  int nthreads = 1;
7548  int dheight, xdheight;
7550 
7551  xdheight = CEIL((double)height / (double)prefs->nfx_threads, 4);
7552  for (i = prefs->nfx_threads - 1; i >= 0; i--) {
7553  dheight = xdheight;
7554 
7555  if ((src + dheight * i * irowstride) < end) {
7556  ccparams[i].src = src + dheight * i * irowstride;
7557  ccparams[i].hsize = width;
7558  ccparams[i].dest = dest + dheight * i * orowstride;
7559 
7560  if (dheight * (i + 1) > (height - 4)) {
7561  dheight = height - (dheight * i);
7562  }
7563 
7564  ccparams[i].vsize = dheight;
7565 
7566  ccparams[i].irowstrides[0] = irowstride;
7567  ccparams[i].orowstrides[0] = orowstride;
7568  ccparams[i].thread_id = i;
7569 
7570  if (i == 0) convert_swap3addpost_frame_thread(&ccparams[i]);
7571  else {
7572  lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_swap3addpost_frame_thread, &ccparams[i]);
7573  nthreads++;
7574  }
7575  }
7576  }
7577 
7578  for (i = 1; i < nthreads; i++) {
7579  lives_thread_join(threads[i], NULL);
7580  }
7581  lives_free(ccparams);
7582  return;
7583  }
7584 
7585  if ((irowstride == width * 3) && (orowstride == width * 4)) {
7586  // quick version
7587  for (; src < end; src += 3) {
7588  *(dest++) = src[2]; // red
7589  *(dest++) = src[1]; // green
7590  *(dest++) = src[0]; // blue
7591  *(dest++) = 255; // alpha
7592  }
7593  } else {
7594  int width3 = width * 3;
7595  orowstride -= width * 4;
7596  for (; src < end; src += irowstride) {
7597  for (i = 0; i < width3; i += 3) {
7598  *(dest++) = src[i + 2]; // red
7599  *(dest++) = src[i + 1]; // green
7600  *(dest++) = src[i]; // blue
7601  *(dest++) = 255; // alpha
7602  }
7603  dest += orowstride;
7604  }
7605  }
7606 }
7607 
7608 
7609 static void *convert_swap3addpost_frame_thread(void *data) {
7610  lives_cc_params *ccparams = (lives_cc_params *)data;
7611  convert_swap3addpost_frame((uint8_t *)ccparams->src, ccparams->hsize, ccparams->vsize, ccparams->irowstrides[0],
7612  ccparams->orowstrides[0], (uint8_t *)ccparams->dest, ccparams->thread_id);
7613  return NULL;
7614 }
7615 
7616 
7617 static void convert_swap3addpre_frame(uint8_t *src, int width, int height, int irowstride, int orowstride,
7618  uint8_t *dest, int thread_id) {
7619  // swap 3 bytes, add pre alpha
7620  uint8_t *end = src + height * irowstride;
7621  register int i;
7622 
7623  if (thread_id == -1 && prefs->nfx_threads > 1) {
7624  lives_thread_t threads[prefs->nfx_threads];
7625  int nthreads = 1;
7626  int dheight, xdheight;
7628 
7629  xdheight = CEIL((double)height / (double)prefs->nfx_threads, 4);
7630  for (i = prefs->nfx_threads - 1; i >= 0; i--) {
7631  dheight = xdheight;
7632 
7633  if ((src + dheight * i * irowstride) < end) {
7634  ccparams[i].src = src + dheight * i * irowstride;
7635  ccparams[i].hsize = width;
7636  ccparams[i].dest = dest + dheight * i * orowstride;
7637 
7638  if (dheight * (i + 1) > (height - 4)) {
7639  dheight = height - (dheight * i);
7640  }
7641 
7642  ccparams[i].vsize = dheight;
7643 
7644  ccparams[i].irowstrides[0] = irowstride;
7645  ccparams[i].orowstrides[0] = orowstride;
7646  ccparams[i].thread_id = i;
7647 
7648  if (i == 0) convert_swap3addpre_frame_thread(&ccparams[i]);
7649  else {
7650  lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_swap3addpre_frame_thread, &ccparams[i]);
7651  nthreads++;
7652  }
7653  }
7654  }
7655 
7656  for (i = 1; i < nthreads; i++) {
7657  lives_thread_join(threads[i], NULL);
7658  }
7659  lives_free(ccparams);
7660  return;
7661  }
7662  if ((irowstride == width * 3) && (orowstride == width * 4)) {
7663  // quick version
7664  for (; src < end; src += 3) {
7665  *(dest++) = 255; // alpha
7666  *(dest++) = src[2]; // red
7667  *(dest++) = src[1]; // green
7668  *(dest++) = src[0]; // blue
7669  }
7670  } else {
7671  int width3 = width * 3;
7672  orowstride -= width * 4;
7673  for (; src < end; src += irowstride) {
7674  for (i = 0; i < width3; i += 3) {
7675  *(dest++) = 255; // alpha
7676  *(dest++) = src[i + 2]; // red
7677  *(dest++) = src[i + 1]; // green
7678  *(dest++) = src[i]; // blue
7679  }
7680  dest += orowstride;
7681  }
7682  }
7683 }
7684 
7685 
7686 static void *convert_swap3addpre_frame_thread(void *data) {
7687  lives_cc_params *ccparams = (lives_cc_params *)data;
7688  convert_swap3addpre_frame((uint8_t *)ccparams->src, ccparams->hsize, ccparams->vsize, ccparams->irowstrides[0],
7689  ccparams->orowstrides[0], (uint8_t *)ccparams->dest, ccparams->thread_id);
7690  return NULL;
7691 }
7692 
7693 
7694 static void convert_swap3postalpha_frame(uint8_t *src, int width, int height, int rowstride,
7695  int thread_id) {
7696  // swap 3 bytes, leave alpha
7697  uint8_t *end = src + height * rowstride, tmp;
7698  register int i;
7699 
7700  if (thread_id == -1 && prefs->nfx_threads > 1) {
7701  lives_thread_t threads[prefs->nfx_threads];
7702  int nthreads = 1;
7703  int dheight, xdheight;
7705 
7706  xdheight = CEIL((double)height / (double)prefs->nfx_threads, 4);
7707  for (i = prefs->nfx_threads - 1; i >= 0; i--) {
7708  dheight = xdheight;
7709 
7710  if ((src + dheight * i * rowstride) < end) {
7711  ccparams[i].src = src + dheight * i * rowstride;
7712  ccparams[i].hsize = width;
7713 
7714  if (dheight * (i + 1) > (height - 4)) {
7715  dheight = height - (dheight * i);
7716  }
7717 
7718  ccparams[i].vsize = dheight;
7719 
7720  ccparams[i].irowstrides[0] = rowstride;
7721  ccparams[i].thread_id = i;
7722 
7723  if (i == 0) convert_swap3postalpha_frame_thread(&ccparams[i]);
7724  else {
7725  lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_swap3postalpha_frame_thread, &ccparams[i]);
7726  nthreads++;
7727  }
7728  }
7729  }
7730 
7731  for (i = 1; i < nthreads; i++) {
7732  lives_thread_join(threads[i], NULL);
7733  }
7734  lives_free(ccparams);
7735  return;
7736  }
7737 
7738  rowstride -= width << 2;
7739  for (; src < end; src += rowstride) {
7740  for (i = 0; i < width; i++) {
7741  tmp = src[0];
7742  src[0] = src[2];
7743  src[2] = tmp;
7744  src += 4;
7745  }
7746  }
7747 }
7748 
7749 
7750 static void *convert_swap3postalpha_frame_thread(void *data) {
7751  lives_cc_params *ccparams = (lives_cc_params *)data;
7752  convert_swap3postalpha_frame((uint8_t *)ccparams->src, ccparams->hsize, ccparams->vsize, ccparams->irowstrides[0],
7753  ccparams->thread_id);
7754  return NULL;
7755 }
7756 
7757 #ifdef WEED_ADVANCED_PALETTES
7758 static void convert_swap3prealpha_frame(uint8_t *src, int width, int height, int rowstride,
7759  int thread_id) {
7760  // swap 3 bytes, leave alpha
7761  uint8_t *end = src + height * rowstride, tmp;
7762  register int i;
7763 
7764  if (thread_id == -1 && prefs->nfx_threads > 1) {
7765  lives_thread_t threads[prefs->nfx_threads];
7766  int nthreads = 1;
7767  int dheight, xdheight;
7769 
7770  xdheight = CEIL((double)height / (double)prefs->nfx_threads, 4);
7771  for (i = prefs->nfx_threads - 1; i >= 0; i--) {
7772  dheight = xdheight;
7773 
7774  if ((src + dheight * i * rowstride) < end) {
7775  ccparams[i].src = src + dheight * i * rowstride;
7776  ccparams[i].hsize = width;
7777 
7778  if (dheight * (i + 1) > (height - 4)) {
7779  dheight = height - (dheight * i);
7780  }
7781 
7782  ccparams[i].vsize = dheight;
7783 
7784  ccparams[i].irowstrides[0] = rowstride;
7785  ccparams[i].thread_id = i;
7786 
7787  if (i == 0) convert_swap3prealpha_frame_thread(&ccparams[i]);
7788  else {
7789  lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_swap3prealpha_frame_thread, &ccparams[i]);
7790  nthreads++;
7791  }
7792  }
7793  }
7794 
7795  for (i = 1; i < nthreads; i++) {
7796  lives_thread_join(threads[i], NULL);
7797  }
7798  lives_free(ccparams);
7799  return;
7800  }
7801 
7802  rowstride -= width << 2;
7803 
7804  for (; src < end; src += rowstride) {
7805  for (i = 0; i < width; i++) {
7806  tmp = src[1];
7807  src[1] = src[3];
7808  src[3] = tmp;
7809  src += 4;
7810  }
7811  }
7812 }
7813 
7814 
7815 static void *convert_swap3prealpha_frame_thread(void *data) {
7816  lives_cc_params *ccparams = (lives_cc_params *)data;
7817  convert_swap3prealpha_frame((uint8_t *)ccparams->src, ccparams->hsize, ccparams->vsize,
7818  ccparams->irowstrides[0], ccparams->thread_id);
7819  return NULL;
7820 }
7821 #endif
7822 
7823 static void convert_addpost_frame(uint8_t *src, int width, int height, int irowstride, int orowstride,
7824  uint8_t *dest, uint8_t *gamma_lut, int thread_id) {
7825  // add post alpha
7826  uint8_t *end = src + height * irowstride;
7827  register int i;
7828 
7829  if (thread_id == -1 && prefs->nfx_threads > 1) {
7830  lives_thread_t threads[prefs->nfx_threads];
7831  int nthreads = 1;
7832  int dheight, xdheight;
7834 
7835  xdheight = CEIL((double)height / (double)prefs->nfx_threads, 4);
7836  for (i = prefs->nfx_threads - 1; i >= 0; i--) {
7837  dheight = xdheight;
7838 
7839  if ((src + dheight * i * irowstride) < end) {
7840  ccparams[i].src = src + dheight * i * irowstride;
7841  ccparams[i].hsize = width;
7842  ccparams[i].dest = dest + dheight * i * orowstride;
7843 
7844  if (dheight * (i + 1) > (height - 4)) {
7845  dheight = height - (dheight * i);
7846  }
7847 
7848  ccparams[i].vsize = dheight;
7849 
7850  ccparams[i].irowstrides[0] = irowstride;
7851  ccparams[i].orowstrides[0] = orowstride;
7852  ccparams[i].lut = gamma_lut;
7853  ccparams[i].thread_id = i;
7854 
7855  if (i == 0) convert_addpost_frame_thread(&ccparams[i]);
7856  else {
7857  lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_addpost_frame_thread, &ccparams[i]);
7858  nthreads++;
7859  }
7860  }
7861  }
7862 
7863  for (i = 1; i < nthreads; i++) {
7864  lives_thread_join(threads[i], NULL);
7865  }
7866  lives_free(ccparams);
7867  if (gamma_lut) lives_gamma_lut_free(gamma_lut);
7868  return;
7869  }
7870 
7871  if ((irowstride == width * 3) && (orowstride == width * 4)) {
7872  // quick version
7873 #ifdef ENABLE_OIL
7874  if (!gamma_lut) {
7875  oil_rgb2rgba(dest, src, width * height);
7876  return;
7877  }
7878 #endif
7879  for (; src < end; src += 3) {
7880  if (!gamma_lut) {
7881  lives_memcpy(dest, src, 3);
7882  dest += 3;
7883  } else {
7884  *(dest++) = gamma_lut[src[0]];
7885  *(dest++) = gamma_lut[src[1]];
7886  *(dest++) = gamma_lut[src[2]];
7887  }
7888  *(dest++) = 255; // alpha
7889  }
7890  } else {
7891  int width3 = width * 3;
7892  orowstride -= width * 4;
7893  for (; src < end; src += irowstride) {
7894  for (i = 0; i < width3; i += 3) {
7895  if (!gamma_lut) {
7896  lives_memcpy(dest, src + i, 3);
7897  dest += 3;
7898  } else {
7899  *(dest++) = gamma_lut[src[i]];
7900  *(dest++) = gamma_lut[src[i + 1]];
7901  *(dest++) = gamma_lut[src[i + 2]];
7902  }
7903  *(dest++) = 255; // alpha
7904  }
7905  dest += orowstride;
7906  }
7907  }
7908 }
7909 
7910 
7911 static void *convert_addpost_frame_thread(void *data) {
7912  lives_cc_params *ccparams = (lives_cc_params *)data;
7913  convert_addpost_frame((uint8_t *)ccparams->src, ccparams->hsize, ccparams->vsize, ccparams->irowstrides[0],
7914  ccparams->orowstrides[0], (uint8_t *)ccparams->dest, ccparams->lut, ccparams->thread_id);
7915  return NULL;
7916 }
7917 
7918 
7919 static void convert_addpre_frame(uint8_t *src, int width, int height, int irowstride, int orowstride,
7920  uint8_t *dest, int thread_id) {
7921  // add pre alpha
7922  uint8_t *end = src + height * irowstride;
7923  register int i;
7924 
7925  if (thread_id == -1 && prefs->nfx_threads > 1) {
7926  lives_thread_t threads[prefs->nfx_threads];
7927  int nthreads = 1;
7928  int dheight, xdheight;
7930 
7931  xdheight = CEIL((double)height / (double)prefs->nfx_threads, 4);
7932  for (i = prefs->nfx_threads - 1; i >= 0; i--) {
7933  dheight = xdheight;
7934 
7935  if ((src + dheight * i * irowstride) < end) {
7936  ccparams[i].src = src + dheight * i * irowstride;
7937  ccparams[i].hsize = width;
7938  ccparams[i].dest = dest + dheight * i * orowstride;
7939 
7940  if (dheight * (i + 1) > (height - 4)) {
7941  dheight = height - (dheight * i);
7942  }
7943 
7944  ccparams[i].vsize = dheight;
7945 
7946  ccparams[i].irowstrides[0] = irowstride;
7947  ccparams[i].orowstrides[0] = orowstride;
7948  ccparams[i].thread_id = i;
7949 
7950  if (i == 0) convert_addpre_frame_thread(&ccparams[i]);
7951  else {
7952  lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_addpre_frame_thread, &ccparams[i]);
7953  nthreads++;
7954  }
7955  }
7956  }
7957 
7958  for (i = 1; i < nthreads; i++) {
7959  lives_thread_join(threads[i], NULL);
7960  }
7961  lives_free(ccparams);
7962  return;
7963  }
7964 
7965  if ((irowstride == width * 3) && (orowstride == width * 4)) {
7966  // quick version
7967  for (; src < end; src += 3) {
7968  *(dest++) = 255; // alpha
7969  lives_memcpy(dest, src, 3);
7970  dest += 3;
7971  }
7972  } else {
7973  int width3 = width * 3;
7974  orowstride -= width * 4;
7975  for (; src < end; src += irowstride) {
7976  for (i = 0; i < width3; i += 3) {
7977  *(dest++) = 255; // alpha
7978  lives_memcpy(dest, src + i, 3);
7979  dest += 3;
7980  }
7981  dest += orowstride;
7982  }
7983  }
7984 }
7985 
7986 
7987 static void *convert_addpre_frame_thread(void *data) {
7988  lives_cc_params *ccparams = (lives_cc_params *)data;
7989  convert_addpre_frame((uint8_t *)ccparams->src, ccparams->hsize, ccparams->vsize, ccparams->irowstrides[0],
7990  ccparams->orowstrides[0], (uint8_t *)ccparams->dest, ccparams->thread_id);
7991  return NULL;
7992 }
7993 
7994 
7995 static void convert_swap3delpost_frame(uint8_t *src, int width, int height, int irowstride, int orowstride,
7996  uint8_t *dest, int thread_id) {
7997  // swap 3 bytes, delete post alpha
7998  uint8_t *end = src + height * irowstride;
7999  register int i;
8000 
8001  if (thread_id == -1 && prefs->nfx_threads > 1) {
8002  lives_thread_t threads[prefs->nfx_threads];
8003  int nthreads = 1;
8004  int dheight, xdheight;
8006 
8007  xdheight = CEIL((double)height / (double)prefs->nfx_threads, 4);
8008  for (i = prefs->nfx_threads - 1; i >= 0; i--) {
8009  dheight = xdheight;
8010 
8011  if ((src + dheight * i * irowstride) < end) {
8012  ccparams[i].src = src + dheight * i * irowstride;
8013  ccparams[i].hsize = width;
8014  ccparams[i].dest = dest + dheight * i * orowstride;
8015 
8016  if (dheight * (i + 1) > (height - 4)) {
8017  dheight = height - (dheight * i);
8018  }
8019 
8020  ccparams[i].vsize = dheight;
8021 
8022  ccparams[i].irowstrides[0] = irowstride;
8023  ccparams[i].orowstrides[0] = orowstride;
8024  ccparams[i].thread_id = i;
8025 
8026  if (i == 0) convert_swap3delpost_frame_thread(&ccparams[i]);
8027  else {
8028  lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_swap3delpost_frame_thread, &ccparams[i]);
8029  nthreads++;
8030  }
8031  }
8032  }
8033 
8034  for (i = 1; i < nthreads; i++) {
8035  lives_thread_join(threads[i], NULL);
8036  }
8037  lives_free(ccparams);
8038  return;
8039  }
8040 
8041  if ((irowstride == width * 4) && (orowstride == width * 3)) {
8042  // quick version
8043  for (; src < end; src += 4) {
8044  *(dest++) = src[2]; // red
8045  *(dest++) = src[1]; // green
8046  *(dest++) = src[0]; // blue
8047  }
8048  } else {
8049  int width4 = width * 4;
8050  orowstride -= width * 3;
8051  for (; src < end; src += irowstride) {
8052  for (i = 0; i < width4; i += 4) {
8053  *(dest++) = src[i + 2]; // red
8054  *(dest++) = src[i + 1]; // green
8055  *(dest++) = src[i]; // blue
8056  }
8057  dest += orowstride;
8058  }
8059  }
8060 }
8061 
8062 
8063 static void *convert_swap3delpost_frame_thread(void *data) {
8064  lives_cc_params *ccparams = (lives_cc_params *)data;
8065  convert_swap3delpost_frame((uint8_t *)ccparams->src, ccparams->hsize, ccparams->vsize, ccparams->irowstrides[0],
8066  ccparams->orowstrides[0], (uint8_t *)ccparams->dest, ccparams->thread_id);
8067  return NULL;
8068 }
8069 
8070 
8071 static void convert_delpost_frame(uint8_t *src, int width, int height, int irowstride, int orowstride,
8072  uint8_t *dest, uint8_t *gamma_lut, int thread_id) {
8073  // delete post alpha
8074  uint8_t *end = src + height * irowstride;
8075  register int i;
8076 
8077  if (thread_id == -1 && prefs->nfx_threads > 1) {
8078  lives_thread_t threads[prefs->nfx_threads];
8079  int nthreads = 1;
8080  int dheight, xdheight;
8082 
8083  xdheight = CEIL((double)height / (double)prefs->nfx_threads, 4);
8084  for (i = prefs->nfx_threads - 1; i >= 0; i--) {
8085  dheight = xdheight;
8086 
8087  if ((src + dheight * i * irowstride) < end) {
8088  ccparams[i].src = src + dheight * i * irowstride;
8089  ccparams[i].hsize = width;
8090  ccparams[i].dest = dest + dheight * i * orowstride;
8091 
8092  if (dheight * (i + 1) > (height - 4)) {
8093  dheight = height - (dheight * i);
8094  }
8095 
8096  ccparams[i].vsize = dheight;
8097 
8098  ccparams[i].irowstrides[0] = irowstride;
8099  ccparams[i].orowstrides[0] = orowstride;
8100  ccparams[i].lut = gamma_lut;
8101  ccparams[i].thread_id = i;
8102 
8103  if (i == 0) convert_delpost_frame_thread(&ccparams[i]);
8104  else {
8105  lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_delpost_frame_thread, &ccparams[i]);
8106  nthreads++;
8107  }
8108  }
8109  }
8110 
8111  for (i = 1; i < nthreads; i++) {
8112  lives_thread_join(threads[i], NULL);
8113  }
8114  lives_free(ccparams);
8115  if (gamma_lut) lives_gamma_lut_free(gamma_lut);
8116  return;
8117  }
8118 
8119  if ((irowstride == width * 4) && (orowstride == width * 3)) {
8120  // quick version
8121  for (; src < end; src += 4) {
8122  if (!gamma_lut) {
8123  lives_memcpy(dest, src, 3);
8124  dest += 3;
8125  } else {
8126  *(dest++) = gamma_lut[src[0]];
8127  *(dest++) = gamma_lut[src[1]];
8128  *(dest++) = gamma_lut[src[2]];
8129  }
8130  }
8131  } else {
8132  int width4 = width * 4;
8133  orowstride -= width * 3;
8134  for (; src < end; src += irowstride) {
8135  for (i = 0; i < width4; i += 4) {
8136  if (!gamma_lut) {
8137  lives_memcpy(dest, src + i, 3);
8138  dest += 3;
8139  } else {
8140  *(dest++) = gamma_lut[src[i]];
8141  *(dest++) = gamma_lut[src[i + 1]];
8142  *(dest++) = gamma_lut[src[i + 2]];
8143  }
8144  }
8145  dest += orowstride;
8146  }
8147  }
8148 }
8149 
8150 
8151 static void *convert_delpost_frame_thread(void *data) {
8152  lives_cc_params *ccparams = (lives_cc_params *)data;
8153  convert_delpost_frame((uint8_t *)ccparams->src, ccparams->hsize, ccparams->vsize, ccparams->irowstrides[0],
8154  ccparams->orowstrides[0], (uint8_t *)ccparams->dest, ccparams->lut, ccparams->thread_id);
8155  return NULL;
8156 }
8157 
8158 
8159 static void convert_delpre_frame(uint8_t *src, int width, int height, int irowstride, int orowstride,
8160  uint8_t *dest, int thread_id) {
8161  // delete pre alpha
8162  uint8_t *end = src + height * irowstride;
8163  register int i;
8164 
8165  if (thread_id == -1 && prefs->nfx_threads > 1) {
8166  lives_thread_t threads[prefs->nfx_threads];
8167  int nthreads = 1;
8168  int dheight, xdheight;
8170 
8171  xdheight = CEIL((double)height / (double)prefs->nfx_threads, 4);
8172  for (i = prefs->nfx_threads - 1; i >= 0; i--) {
8173  dheight = xdheight;
8174 
8175  if ((src + dheight * i * irowstride) < end) {
8176  ccparams[i].src = src + dheight * i * irowstride;
8177  ccparams[i].hsize = width;
8178  ccparams[i].dest = dest + dheight * i * orowstride;
8179 
8180  if (dheight * (i + 1) > (height - 4)) {
8181  dheight = height - (dheight * i);
8182  }
8183 
8184  ccparams[i].vsize = dheight;
8185 
8186  ccparams[i].irowstrides[0] = irowstride;
8187  ccparams[i].orowstrides[0] = orowstride;
8188  ccparams[i].thread_id = i;
8189 
8190  if (i == 0) convert_delpre_frame_thread(&ccparams[i]);
8191  else {
8192  lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_delpre_frame_thread, &ccparams[i]);
8193  nthreads++;
8194  }
8195  }
8196  }
8197 
8198  for (i = 1; i < nthreads; i++) {
8199  lives_thread_join(threads[i], NULL);
8200  }
8201  lives_free(ccparams);
8202  return;
8203  }
8204 
8205  src++;
8206 
8207  if ((irowstride == width * 4) && (orowstride == width * 3)) {
8208  // quick version
8209  for (; src < end; src += 4) {
8210  lives_memcpy(dest, src, 3);
8211  dest += 3;
8212  }
8213  } else {
8214  int width4 = width * 4;
8215  orowstride -= width * 3;
8216  for (; src < end; src += irowstride) {
8217  for (i = 0; i < width4; i += 4) {
8218  lives_memcpy(dest, src + i, 3);
8219  dest += 3;
8220  }
8221  dest += orowstride;
8222  }
8223  }
8224 }
8225 
8226 
8227 static void *convert_delpre_frame_thread(void *data) {
8228  lives_cc_params *ccparams = (lives_cc_params *)data;
8229  convert_delpre_frame((uint8_t *)ccparams->src, ccparams->hsize, ccparams->vsize, ccparams->irowstrides[0],
8230  ccparams->orowstrides[0], (uint8_t *)ccparams->dest, ccparams->thread_id);
8231  return NULL;
8232 }
8233 
8234 
8235 static void convert_swap3delpre_frame(uint8_t *src, int width, int height, int irowstride, int orowstride,
8236  uint8_t *dest, int thread_id) {
8237  // delete pre alpha, swap last 3
8238  uint8_t *end = src + height * irowstride;
8239  register int i;
8240 
8241  if (thread_id == -1 && prefs->nfx_threads > 1) {
8242  lives_thread_t threads[prefs->nfx_threads];
8243  int nthreads = 1;
8244  int dheight, xdheight;
8246 
8247  xdheight = CEIL((double)height / (double)prefs->nfx_threads, 4);
8248  for (i = prefs->nfx_threads - 1; i >= 0; i--) {
8249  dheight = xdheight;
8250 
8251  if ((src + dheight * i * irowstride) < end) {
8252  ccparams[i].src = src + dheight * i * irowstride;
8253  ccparams[i].hsize = width;
8254  ccparams[i].dest = dest + dheight * i * orowstride;
8255 
8256  if (dheight * (i + 1) > (height - 4)) {
8257  dheight = height - (dheight * i);
8258  }
8259 
8260  ccparams[i].vsize = dheight;
8261 
8262  ccparams[i].irowstrides[0] = irowstride;
8263  ccparams[i].orowstrides[0] = orowstride;
8264  ccparams[i].thread_id = i;
8265 
8266  if (i == 0) convert_swap3delpre_frame_thread(&ccparams[i]);
8267  else {
8268  lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_swap3delpre_frame_thread, &ccparams[i]);
8269  nthreads++;
8270  }
8271  }
8272  }
8273 
8274  for (i = 1; i < nthreads; i++) {
8275  lives_thread_join(threads[i], NULL);
8276  }
8277  lives_free(ccparams);
8278  return;
8279  }
8280 
8281  if ((irowstride == width * 4) && (orowstride == width * 3)) {
8282  // quick version
8283  for (; src < end; src += 4) {
8284  *(dest++) = src[3]; // red
8285  *(dest++) = src[2]; // green
8286  *(dest++) = src[1]; // blue
8287  }
8288  } else {
8289  int width4 = width * 4;
8290  orowstride -= width * 3;
8291  for (; src < end; src += irowstride) {
8292  for (i = 0; i < width4; i += 4) {
8293  *(dest++) = src[i + 3]; // red
8294  *(dest++) = src[i + 2]; // green
8295  *(dest++) = src[i + 1]; // blue
8296  }
8297  dest += orowstride;
8298  }
8299  }
8300 }
8301 
8302 
8303 static void *convert_swap3delpre_frame_thread(void *data) {
8304  lives_cc_params *ccparams = (lives_cc_params *)data;
8305  convert_swap3delpre_frame((uint8_t *)ccparams->src, ccparams->hsize, ccparams->vsize, ccparams->irowstrides[0],
8306  ccparams->orowstrides[0], (uint8_t *)ccparams->dest, ccparams->thread_id);
8307  return NULL;
8308 }
8309 
8310 
8311 static void convert_swapprepost_frame(uint8_t *src, int width, int height, int irowstride, int orowstride,
8312  uint8_t *dest, int thread_id) {
8313  // swap first and last bytes in a 4 byte palette
8314  uint64_t *uup;
8315  uint8_t *end = src + height * irowstride;
8316  register int i;
8317 
8318  if (thread_id == -1 && prefs->nfx_threads > 1) {
8319  lives_thread_t threads[prefs->nfx_threads];
8320  int nthreads = 1;
8321  int dheight, xdheight;
8323 
8324  xdheight = CEIL((double)height / (double)prefs->nfx_threads, 4);
8325  for (i = prefs->nfx_threads - 1; i >= 0; i--) {
8326  dheight = xdheight;
8327 
8328  if ((src + dheight * i * irowstride) < end) {
8329  ccparams[i].src = src + dheight * i * irowstride;
8330  ccparams[i].hsize = width;
8331  ccparams[i].dest = dest + dheight * i * orowstride;
8332 
8333  if (dheight * (i + 1) > (height - 4)) {
8334  dheight = height - (dheight * i);
8335  }
8336 
8337  ccparams[i].vsize = dheight;
8338 
8339  ccparams[i].irowstrides[0] = irowstride;
8340  ccparams[i].orowstrides[0] = orowstride;
8341  ccparams[i].thread_id = i;
8342 
8343  if (i == 0) convert_swapprepost_frame_thread(&ccparams[i]);
8344  else {
8345  lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_swapprepost_frame_thread, &ccparams[i]);
8346  nthreads++;
8347  }
8348  }
8349  }
8350 
8351  for (i = 1; i < nthreads; i++) {
8352  lives_thread_join(threads[i], NULL);
8353  }
8354  lives_free(ccparams);
8355  return;
8356  }
8357 
8358  uup = (uint64_t *)src;
8359  if ((void *)uup == (void *)src) {
8360  uint64_t uu;
8361  int width8 = width >> 3;
8362  orowstride -= width * 4;
8363  for (; src < end; src += irowstride) {
8364  for (i = 0; i < width8; i++) {
8365  uu = ((*uup & 0xFF000000FF000000) >> 24);
8366  uu |= ((*uup & 0x00FFFFFF00FFFFFF) << 8);
8367  lives_memcpy(dest, &uu, 8);
8368  dest += 8;
8369  uup++;
8370  }
8371  dest += orowstride;
8372  }
8373  return;
8374  }
8375 
8376  if (src == dest) {
8377  uint8_t tmp;
8378  int width4 = width << 2;
8379  orowstride -= width4;
8380  for (; src < end; src += irowstride) {
8381  for (i = 0; i < width4; i += 4) {
8382  tmp = dest[i];
8383  lives_memmove(&dest[i], &dest[i + 1], 3);
8384  dest[i + 3] = tmp;
8385  }
8386  dest += orowstride;
8387  }
8388  return;
8389  } else {
8390  uint8_t tmp;
8391  int width4 = width << 2;
8392  orowstride -= width4;
8393  for (; src < end; src += irowstride) {
8394  for (i = 0; i < width4; i += 4) {
8395  tmp = src[i];
8396  lives_memcpy(&dest[i], &src[i + 1], 3);
8397  dest[i + 3] = tmp;
8398  }
8399  dest += orowstride;
8400  }
8401  }
8402 }
8403 
8404 
8405 static void *convert_swapprepost_frame_thread(void *data) {
8406  lives_cc_params *ccparams = (lives_cc_params *)data;
8407  convert_swapprepost_frame((uint8_t *)ccparams->src, ccparams->hsize, ccparams->vsize, ccparams->irowstrides[0],
8408  ccparams->orowstrides[0], (uint8_t *)ccparams->dest, ccparams->thread_id);
8409  return NULL;
8410 }
8411 
8412 
8414 // genric YUV
8415 
8416 static void convert_swab_frame(uint8_t *src, int width, int height, int irow, int orow, uint8_t *dest, int thread_id) {
8417  register int i;
8418  int width4 = width * 4;
8419  uint8_t *end = src + height * irow;
8420 
8421  if (thread_id == -1 && prefs->nfx_threads > 1) {
8422  lives_thread_t threads[prefs->nfx_threads];
8423  int nthreads = 1;
8424  int dheight, xdheight;
8426 
8427  xdheight = CEIL((double)height / (double)prefs->nfx_threads, 4);
8428  for (i = prefs->nfx_threads - 1; i >= 0; i--) {
8429  dheight = xdheight;
8430 
8431  if ((src + dheight * i * width4) < end) {
8432  ccparams[i].src = src + dheight * i * irow;
8433  ccparams[i].hsize = width;
8434  ccparams[i].dest = dest + dheight * i * orow;
8435 
8436  if (dheight * (i + 1) > (height - 4)) {
8437  dheight = height - (dheight * i);
8438  }
8439 
8440  ccparams[i].vsize = dheight;
8441  ccparams[i].irowstrides[0] = irow;
8442  ccparams[i].orowstrides[0] = orow;
8443 
8444  ccparams[i].thread_id = i;
8445 
8446  if (i == 0) convert_swab_frame_thread(&ccparams[i]);
8447  else {
8448  lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_swab_frame_thread, &ccparams[i]);
8449  nthreads++;
8450  }
8451  }
8452  }
8453 
8454  for (i = 1; i < nthreads; i++) {
8455  lives_thread_join(threads[i], NULL);
8456  }
8457  lives_free(ccparams);
8458  return;
8459  }
8460 
8461  for (; src < end; src += irow) {
8462  for (i = 0; i < width4; i += 4) {
8463  swab4(&src[i], &dest[i], 1);
8464  }
8465  dest += orow;
8466  }
8467 }
8468 
8469 
8470 static void *convert_swab_frame_thread(void *data) {
8471  lives_cc_params *ccparams = (lives_cc_params *)data;
8472  convert_swab_frame((uint8_t *)ccparams->src, ccparams->hsize, ccparams->vsize,
8473  ccparams->irowstrides[0], ccparams->orowstrides[0],
8474  (uint8_t *)ccparams->dest, ccparams->thread_id);
8475  return NULL;
8476 }
8477 
8478 
8479 static void convert_halve_chroma(uint8_t **src, int width, int height, int *istrides, int *ostrides, uint8_t **dest,
8480  int clamping) {
8481  // width and height here are width and height of src *chroma* planes, in bytes
8482 
8483  // halve the chroma samples vertically, with sub-sampling, e.g. 422p to 420p
8484 
8485  // TODO : handle different sampling methods in and out
8486 
8487  register int i, j;
8488  uint8_t *d_u = dest[1], *d_v = dest[2], *s_u = src[1], *s_v = src[2];
8489  boolean chroma = FALSE;
8490 
8491  set_conversion_arrays(clamping, WEED_YUV_SUBSPACE_YCBCR);
8492 
8493  for (i = 0; i < height; i++) {
8494  for (j = 0; j < width; j++) {
8495  if (!chroma) {
8496  // pass 1, copy row
8497  lives_memcpy(d_u, s_u, width);
8498  lives_memcpy(d_v, s_v, width);
8499  } else {
8500  // pass 2
8501  // average two dest rows
8502  d_u[j] = avg_chromaf(d_u[j], s_u[j]);
8503  d_v[j] = avg_chromaf(d_v[j], s_v[j]);
8504  }
8505  }
8506  if (chroma) {
8507  d_u += ostrides[1];
8508  d_v += ostrides[2];
8509  }
8510  chroma = !chroma;
8511  s_u += istrides[1];
8512  s_v += istrides[2];
8513  }
8514 }
8515 
8516 
8517 static void convert_double_chroma(uint8_t **src, int width, int height, int *istrides, int *ostrides, uint8_t **dest,
8518  int clamping) {
8519  // width and height here are width and height of src *chroma* planes, in bytes
8520  // double two chroma planes vertically, with interpolation: eg: 420p to 422p
8521 
8522  register int i, j;
8523  uint8_t *d_u = dest[1], *d_v = dest[2], *s_u = src[1], *s_v = src[2];
8524  boolean chroma = FALSE;
8525  int height2 = height << 1;
8526 
8527  set_conversion_arrays(clamping, WEED_YUV_SUBSPACE_YCBCR);
8528 
8529  for (i = 0; i < height2; i++) {
8530  for (j = 0; j < width; j++) {
8531  lives_memcpy(d_u, s_u, width);
8532  lives_memcpy(d_v, s_v, width);
8533 
8534  if (!chroma && i > 0) {
8535  // pass 2
8536  // average two src rows
8537  d_u[j - ostrides[1]] = avg_chromaf(s_u[j], d_u[j - ostrides[1]]);
8538  d_v[j - ostrides[2]] = avg_chromaf(s_v[j], d_v[j - ostrides[2]]);
8539  }
8540  }
8541  if (chroma) {
8542  s_u += istrides[1];
8543  s_v += istrides[2];
8544  }
8545  chroma = !chroma;
8546  d_u += ostrides[1];
8547  d_v += ostrides[2];
8548  }
8549 }
8550 
8551 
8552 static void convert_quad_chroma(uint8_t **src, int width, int height, int *istrides, int ostride, uint8_t **dest,
8553  boolean add_alpha, int sampling, int clamping) {
8554  // width and height here are width and height of dest chroma planes, in bytes
8555  // double the chroma samples vertically and horizontally, with interpolation
8556  // output to planes, eg. 420p to 444p
8557 
8558  register int i, j;
8559  uint8_t *d_u = dest[1], *d_v = dest[2], *s_u = src[1], *s_v = src[2];
8560  int uv_offs, lastrow;
8561 
8562  set_conversion_arrays(clamping, WEED_YUV_SUBSPACE_YCBCR);
8563 
8564  width = (width >> 1) << 1;
8565  lastrow = (height >> 1) << 1;
8566 
8567  for (i = 0; i < height; i++) {
8568  uv_offs = 0;
8569  for (j = 0; j < width; j++) {
8570  if (!(i & 1) || i == lastrow) {
8571  if (uv_offs > 0) {
8572  // uv supersampling
8573  if (sampling == WEED_YUV_SAMPLING_JPEG) {
8574  d_u[j] = avg_chromaf(s_u[uv_offs - 1], s_u[uv_offs]);
8575  d_v[j] = avg_chromaf(s_v[uv_offs - 1], s_v[uv_offs]);
8576  } else {
8577  d_u[j] = avg_chroma_3_1f(s_u[uv_offs - 1], s_u[uv_offs]);
8578  d_v[j] = avg_chroma_1_3f(s_v[uv_offs - 1], s_v[uv_offs]);
8579  }
8580  } else {
8581  d_u[j] = s_u[uv_offs];
8582  d_v[j] = s_v[uv_offs];
8583  }
8584  ++uv_offs;
8585  j++;
8586  if (sampling == WEED_YUV_SAMPLING_JPEG) {
8587  d_u[j] = avg_chromaf(s_u[uv_offs - 1], s_u[uv_offs]);
8588  d_v[j] = avg_chromaf(s_v[uv_offs - 1], s_v[uv_offs]);
8589  } else {
8590  d_u[j] = avg_chroma_1_3f(s_u[uv_offs - 1], s_u[uv_offs]);
8591  d_v[j] = avg_chroma_3_1f(s_v[uv_offs - 1], s_v[uv_offs]);
8592  }
8593  } else if (i > 1) {
8594  // on odd rows we average row - 1 with row - 3 ==> row - 2
8595  int jj = j - (ostride << 1);
8596  d_u[jj] = avg_chromaf(d_u[jj + ostride], d_u[jj - ostride]);
8597  d_v[jj] = avg_chromaf(d_v[jj + ostride], d_v[jj - ostride]);
8598  jj++;
8599  d_u[jj] = avg_chromaf(d_u[jj + ostride], d_u[jj - ostride]);
8600  d_v[jj] = avg_chromaf(d_v[jj + ostride], d_v[jj - ostride]);
8601  }
8602  }
8603 
8604  if (i & 1) {
8605  // after an odd row we advance u, v
8606  s_u += istrides[1];
8607  s_v += istrides[2];
8608  }
8609  d_u += ostride;
8610  d_v += ostride;
8611 
8612  }
8613  if (i > lastrow) {
8614  // TRUE if we finished on an even row
8615  for (j = 0; j < width; j++) {
8616  d_u[j - ostride * 2] = avg_chromaf(d_u[j - ostride * 3], d_u[j - ostride]);
8617  d_v[j - ostride * 2] = avg_chromaf(d_v[j - ostride * 3], d_v[j - ostride]);
8618  }
8619  }
8620  if (add_alpha) lives_memset(dest[3], 255, ostride * height);
8621 }
8622 
8623 
8624 static void convert_quad_chroma_packed(uint8_t **src, int width, int height, int *istrides, int ostride,
8625  uint8_t *dest, boolean add_alpha, int sampling, int clamping) {
8626  // width and height here are width and height of dest chroma planes, in bytes
8627  // stretch (double) the chroma samples vertically and horizontally, with interpolation
8628  // ouput to packed pixels
8629 
8630  // e.g: 420p to 888(8)
8631 
8632  int i, j;
8633  int irow = istrides[0] - width;
8634  uint8_t *s_y = src[0], *s_u = src[1], *s_v = src[2];
8635  int opsize = 3, uv_offs;
8636  int lastrow = (height >> 1) << 1; // height if even, height - 1 if odd
8637 
8638  //int count;
8639  set_conversion_arrays(clamping, WEED_YUV_SUBSPACE_YCBCR);
8640 
8641  if (add_alpha) opsize = 4;
8642 
8643  width = ((width >> 1) << 1) * opsize;
8644 
8645  for (i = 0; i < height; i++) {
8646  uv_offs = 0;
8647  for (j = 0; j < width; j += opsize) {
8648  // implements jpeg / mpeg style subsampling : TODO - dvpal style
8649  if (!(i & 1) || i == lastrow) {
8650  // even rows (0, 2, 4, ...) are normal
8651  dest[j] = *(s_y++);
8652  if (uv_offs > 0) {
8653  // uv supersampling
8654  if (sampling == WEED_YUV_SAMPLING_JPEG) {
8655  dest[j + 1] = avg_chromaf(s_u[uv_offs - 1], s_u[uv_offs]);
8656  dest[j + 2] = avg_chromaf(s_v[uv_offs - 1], s_v[uv_offs]);
8657  } else {
8658  dest[j + 1] = avg_chroma_3_1f(s_u[uv_offs - 1], s_u[uv_offs]);
8659  dest[j + 2] = avg_chroma_1_3f(s_v[uv_offs - 1], s_v[uv_offs]);
8660  }
8661  } else {
8662  dest[j + 1] = s_u[uv_offs];
8663  dest[j + 2] = s_v[uv_offs];
8664  }
8665 
8666  if (add_alpha) dest[j + 3] = 255;
8667  ++uv_offs;
8668  j += opsize;
8669  dest[j] = *(s_y++);
8670 
8671  if (sampling == WEED_YUV_SAMPLING_JPEG) {
8672  dest[j + 1] = avg_chromaf(s_u[uv_offs - 1], s_u[uv_offs]);
8673  dest[j + 2] = avg_chromaf(s_v[uv_offs - 1], s_v[uv_offs]);
8674  } else {
8675  dest[j + 1] = avg_chroma_1_3f(s_u[uv_offs - 1], s_u[uv_offs]);
8676  dest[j + 2] = avg_chroma_3_1f(s_v[uv_offs - 1], s_v[uv_offs]);
8677  }
8678  if (add_alpha) dest[j + 3] = 255;
8679  } else {
8680  int jj = j - (ostride << 1);
8681  // y part is normal
8682  dest[j] = *(s_y++);
8683  if (i > 1) { // i >= 3
8684  // chroma part:
8685  // on odd rows we average row - 1 with row - 3 ==> row - 2
8686  dest[jj + 1] = avg_chroma(dest[jj + 1 + ostride], dest[jj + 1 - ostride]);
8687  dest[jj + 2] = avg_chroma(dest[jj + 2 + ostride], dest[jj + 2 - ostride]);
8688  jj += opsize;
8689  }
8690  j += opsize;
8691  dest[j] = *(s_y++);
8692  if (i > 1) {
8693  dest[jj + 1] = avg_chroma(dest[jj + 1 + ostride], dest[jj + 1 - ostride]);
8694  dest[jj + 2] = avg_chroma(dest[jj + 2 + ostride], dest[jj + 2 - ostride]);
8695  }
8696  }
8697  }
8698 
8699  if (i & 1) {
8700  // after an odd row we advance u, v
8701  s_u += istrides[1];
8702  s_v += istrides[2];
8703  }
8704  // y advances on every row
8705  s_y += irow;
8706  dest += ostride;
8707  }
8708  if (i > lastrow) {
8709  // TRUE if we finished on an even row
8710  for (j = 0; j < width; j += opsize) {
8711  // we would have done this on the next row, but there is no next row
8712  int jj = j - ostride;
8713  dest[jj + 1] = avg_chromaf(dest[jj + 1 + ostride], dest[jj + 1 - ostride]);
8714  dest[jj + 2] = avg_chromaf(dest[jj + 2 + ostride], dest[jj + 2 - ostride]);
8715  }
8716  }
8717 }
8718 
8719 
8720 static void convert_double_chroma_packed(uint8_t **src, int width, int height, int *istrides, int ostride, uint8_t *dest,
8721  boolean add_alpha, int sampling, int clamping) {
8722  // width and height here are width and height of dest chroma planes, in bytes
8723  // double the chroma samples horizontally, with interpolation
8724 
8725  // output to packed pixels
8726 
8727  // e.g 422p to 888(8)
8728 
8729  int i, j;
8730  uint8_t *s_y = src[0], *s_u = src[1], *s_v = src[2];
8731  int irow = istrides[0] - width;
8732  int opsize = 3, uv_offs;
8733 
8734  set_conversion_arrays(clamping, WEED_YUV_SUBSPACE_YCBCR);
8735 
8736  if (add_alpha) opsize = 4;
8737  width *= opsize;
8738 
8739  for (i = 0; i < height; i++) {
8740  uv_offs = 0;
8741  for (j = 0; j < width; j += opsize) {
8742  dest[j] = *(s_y++);
8743  if (uv_offs > 0) {
8744  // uv supersampling
8745  if (sampling == WEED_YUV_SAMPLING_JPEG) {
8746  dest[j + 1] = avg_chromaf(s_u[uv_offs - 1], s_u[uv_offs]);
8747  dest[j + 2] = avg_chromaf(s_v[uv_offs - 1], s_v[uv_offs]);
8748  } else {
8749  dest[j + 1] = avg_chroma_3_1f(s_u[uv_offs - 1], s_u[uv_offs]);
8750  dest[j + 2] = avg_chroma_1_3f(s_v[uv_offs - 1], s_v[uv_offs]);
8751  }
8752  } else {
8753  dest[j + 1] = s_u[uv_offs];
8754  dest[j + 2] = s_v[uv_offs];
8755  }
8756  if (add_alpha) dest[j + 3] = 255;
8757 
8758  j += opsize;
8759  ++uv_offs;
8760 
8761  dest[j] = *(s_y++);
8762  if (uv_offs > 0) {
8763  // uv supersampling
8764  if (sampling == WEED_YUV_SAMPLING_JPEG) {
8765  dest[j + 1] = avg_chromaf(s_u[uv_offs - 1], s_u[uv_offs]);
8766  dest[j + 2] = avg_chromaf(s_v[uv_offs - 1], s_v[uv_offs]);
8767  } else {
8768  dest[j + 1] = avg_chroma_3_1f(s_u[uv_offs - 1], s_u[uv_offs]);
8769  dest[j + 2] = avg_chroma_1_3f(s_v[uv_offs - 1], s_v[uv_offs]);
8770  }
8771  } else {
8772  dest[j + 1] = s_u[uv_offs];
8773  dest[j + 2] = s_v[uv_offs];
8774  }
8775  }
8776  s_y += irow;
8777  s_u += istrides[1];
8778  s_v += istrides[2];
8779  dest += ostride;
8780  }
8781 }
8782 
8783 
8784 static void switch_yuv_sampling(weed_layer_t *layer) {
8785  int sampling, clamping, subspace;
8786  int palette = weed_layer_get_palette_yuv(layer, &clamping, &sampling, &subspace);
8787  int width = weed_layer_get_width(layer) >> 1;
8788  int height = weed_layer_get_height(layer) >> 1;
8789  unsigned char **pixel_data, *dst;
8790  register int i, j, k;
8791 
8792  if (palette != WEED_PALETTE_YUV420P) return;
8793 
8794  pixel_data = (unsigned char **)weed_layer_get_pixel_data(layer, NULL);
8795 
8796  if (sampling == WEED_YUV_SAMPLING_MPEG) {
8797  // jpeg is located centrally between Y, mpeg(2) and some flv are located on the left Y
8798  // so here we just set dst[0]=avg(src[0],src[1]), dst[1]=avg(src[1],src[2]), etc.
8799  // the last value is repeated once
8800 
8801  // however, I think the values alternate so u : 0, 2, 4....v: 1, 3, 5...
8802  // and we want u = 0.5, 2.5, 4.5....
8803  // so, starting from 0 u = 3/4 x + 1 /4 x + 1
8804  // and v = 1/4 x + 3/4 x + 1
8805 
8806  width--;
8807  for (k = 1; k < 3; k++) {
8808  dst = pixel_data[k];
8809  for (j = 0; j < height; j++) {
8810  for (i = 0; i < width; i++) {
8811  if (k == 1) dst[i] = avg_chroma_3_1f(dst[i], avg_chromaf(dst[i], dst[i + 1]));
8812  else dst[i] = avg_chroma_1_3f(avg_chromaf(dst[i], dst[i + 1]), dst[i + 1]);
8813  }
8814  dst += width + 1;
8815  }
8816  }
8817  weed_set_int_value(layer, WEED_LEAF_YUV_SAMPLING, WEED_YUV_SAMPLING_JPEG);
8818  } else if (sampling == WEED_YUV_SAMPLING_JPEG) {
8819  // the other way round is just the inverse
8820  width--;
8821  for (k = 1; k < 3; k++) {
8822  dst = pixel_data[k];
8823  for (j = 0; j < height; j++) {
8824  for (i = 0; i < width; i++) {
8825  if (k == 2) dst[i] = avg_chromaf(dst[i], avg_chromaf(dst[i], dst[i + 1]));
8826  else dst[i] = avg_chromaf(avg_chromaf(dst[i], dst[i + 1]), dst[i + 1]);
8827  }
8828  dst += width + 1;
8829  }
8830  }
8831  weed_set_int_value(layer, WEED_LEAF_YUV_SAMPLING, WEED_YUV_SAMPLING_MPEG);
8832  }
8833  lives_free(pixel_data);
8834 }
8835 
8836 
8837 static void switch_yuv_clamping_and_subspace(weed_layer_t *layer, int oclamping, int osubspace) {
8838  // currently subspace conversions are not performed - TODO
8839  // we assume subspace Y'CbCr
8840  int iclamping = weed_get_int_value(layer, WEED_LEAF_YUV_CLAMPING, NULL);
8841  int isubspace = weed_get_int_value(layer, WEED_LEAF_YUV_SUBSPACE, NULL);
8842 
8843  int palette = weed_get_int_value(layer, WEED_LEAF_CURRENT_PALETTE, NULL);
8844  int height = weed_get_int_value(layer, WEED_LEAF_HEIGHT, NULL);
8845  int rowstride = weed_layer_get_rowstride(layer);
8846  void **pixel_data = weed_get_voidptr_array(layer, WEED_LEAF_PIXEL_DATA, NULL);
8847 
8848  uint8_t *src, *src1, *src2, *end;
8849 
8850  get_YUV_to_YUV_conversion_arrays(iclamping, isubspace, oclamping, osubspace);
8851 
8852  switch (palette) {
8853  case WEED_PALETTE_YUVA8888:
8854  src = (uint8_t *)pixel_data[0];
8855  end = src + height * rowstride;
8856  while (src < end) {
8857  *src = Y_to_Y[*src];
8858  src++;
8859  *src = U_to_U[*src];
8860  src++;
8861  *src = V_to_V[*src];
8862  src += 2;
8863  }
8864  break;
8865  case WEED_PALETTE_YUV888:
8866  src = (uint8_t *)pixel_data[0];
8867  end = src + height * rowstride;
8868  while (src < end) {
8869  *src = Y_to_Y[*src];
8870  src++;
8871  *src = U_to_U[*src];
8872  src++;
8873  *src = V_to_V[*src];
8874  src++;
8875  }
8876  break;
8877  case WEED_PALETTE_YUVA4444P:
8878  case WEED_PALETTE_YUV444P:
8879  src = (uint8_t *)pixel_data[0];
8880  src1 = (uint8_t *)pixel_data[1];
8881  src2 = (uint8_t *)pixel_data[2];
8882  end = src + height * rowstride;
8883  while (src < end) {
8884  *src = Y_to_Y[*src];
8885  src++;
8886  *src1 = U_to_U[*src1];
8887  src1++;
8888  *src2 = V_to_V[*src2];
8889  src2++;
8890  }
8891  break;
8892  case WEED_PALETTE_UYVY:
8893  src = (uint8_t *)pixel_data[0];
8894  end = src + height * rowstride;
8895  while (src < end) {
8896  *src = U_to_U[*src];
8897  src++;
8898  *src = Y_to_Y[*src];
8899  src++;
8900  *src = V_to_V[*src];
8901  src++;
8902  *src = Y_to_Y[*src];
8903  src++;
8904  }
8905  break;
8906  case WEED_PALETTE_YUYV:
8907  src = (uint8_t *)pixel_data[0];
8908  end = src + height * rowstride;
8909  while (src < end) {
8910  *src = Y_to_Y[*src];
8911  src++;
8912  *src = U_to_U[*src];
8913  src++;
8914  *src = Y_to_Y[*src];
8915  src++;
8916  *src = V_to_V[*src];
8917  src++;
8918  }
8919  break;
8920  case WEED_PALETTE_YUV422P:
8921  src = (uint8_t *)pixel_data[0];
8922  src1 = (uint8_t *)pixel_data[1];
8923  src2 = (uint8_t *)pixel_data[2];
8924  end = src + height * rowstride;
8925  // TODO: u, v rowstrides
8926  while (src < end) {
8927  *src = Y_to_Y[*src];
8928  src++;
8929  *src = Y_to_Y[*src];
8930  src++;
8931  *src1 = U_to_U[*src1];
8932  src1++;
8933  *src2 = V_to_V[*src2];
8934  src2++;
8935  }
8936  break;
8937  case WEED_PALETTE_YVU420P:
8938  src = (uint8_t *)pixel_data[0];
8939  src1 = (uint8_t *)pixel_data[2];
8940  src2 = (uint8_t *)pixel_data[1];
8941  end = src + height * rowstride;
8942  // TODO: u, v rowstrides
8943  while (src < end) {
8944  *src = Y_to_Y[*src];
8945  src++;
8946  *src = Y_to_Y[*src];
8947  src++;
8948  *src = Y_to_Y[*src];
8949  src++;
8950  *src = Y_to_Y[*src];
8951  src++;
8952  *src1 = U_to_U[*src1];
8953  src1++;
8954  *src2 = V_to_V[*src2];
8955  src2++;
8956  }
8957  break;
8958  case WEED_PALETTE_YUV420P:
8959  src = (uint8_t *)pixel_data[0];
8960  src1 = (uint8_t *)pixel_data[1];
8961  src2 = (uint8_t *)pixel_data[2];
8962  end = src + height * rowstride;
8963  // TODO: u, v rowstrides
8964  while (src < end) {
8965  *src = Y_to_Y[*src];
8966  src++;
8967  *src = Y_to_Y[*src];
8968  src++;
8969  *src = Y_to_Y[*src];
8970  src++;
8971  *src = Y_to_Y[*src];
8972  src++;
8973  *src1 = U_to_U[*src1];
8974  src1++;
8975  *src2 = V_to_V[*src2];
8976  src2++;
8977  }
8978  break;
8979  case WEED_PALETTE_YUV411:
8980  src = (uint8_t *)pixel_data[0];
8981  end = src + height * rowstride;
8982  while (src < end) {
8983  *src = U_to_U[*src];
8984  src++;
8985  *src = Y_to_Y[*src];
8986  src++;
8987  *src = Y_to_Y[*src];
8988  src++;
8989  *src = V_to_V[*src];
8990  src++;
8991  *src = Y_to_Y[*src];
8992  src++;
8993  *src = Y_to_Y[*src];
8994  src++;
8995  }
8996  break;
8997  }
8998  weed_set_int_value(layer, WEED_LEAF_YUV_CLAMPING, oclamping);
8999  lives_free(pixel_data);
9000 }
9001 
9002 
9004 // TODO - move into layers.c
9005 
9019 LIVES_INLINE void fill_plane(uint8_t *ptr, int psize, int width, int height, int rowstride, unsigned char *bpix) {
9020  register int i, j;
9021  uint8_t *ptr2 = ptr;
9022  for (j = width; j > 0; j--) {
9023  lives_memcpy(ptr2, bpix, psize);
9024  ptr2 += psize;
9025  }
9026  ptr2 += rowstride - width * psize;
9027  for (i = height - 1; i > 0; i--) {
9028  lives_memcpy(ptr2, ptr, rowstride);
9029  ptr += rowstride;
9030  ptr2 += rowstride;
9031  }
9032 }
9033 
9034 #define SHIFTVAL sbits
9035 #define ALIGN_SIZE (1 << SHIFTVAL)
9036 
9058 boolean create_empty_pixel_data(weed_layer_t *layer, boolean black_fill, boolean may_contig) {
9059  int palette = weed_layer_get_palette(layer);
9060  int width = weed_layer_get_width(layer);
9061  int height = weed_layer_get_height(layer);
9062  int rowstride, *rowstrides;
9063  int *fixed_rs = NULL;
9064 
9065  uint32_t pflags;
9066  int clamping = WEED_YUV_CLAMPING_CLAMPED;
9067  boolean compact = FALSE;
9068 
9069  uint8_t *pixel_data = NULL;
9070  uint8_t *memblock;
9071  uint8_t **pd_array;
9072 
9073  unsigned char black[6] = {0, 0, 0, 255, 255, 255};
9074  unsigned char yuv_black[6] = {16, 128, 128, 255, 255, 255};
9075  float blackf[4] = {0., 0., 0., 1.};
9076 
9077  size_t framesize, framesize2;
9078 
9079  // max is 128 min is 32, and it must be a power of 2 (i.e 32, 64, 128)
9080  int sbits = 7, al, r;
9081  int rowstride_alignment = 16;
9082 
9083  if (width <= 0 || height <= 0) return FALSE;
9084 
9085  if (!weed_plant_has_leaf(layer, WEED_LEAF_NATURAL_SIZE)) {
9086  int nsize[2];
9087  // set "natural_size" in case a filter needs it
9088  nsize[0] = width;
9089  nsize[1] = height;
9090  weed_set_int_array(layer, WEED_LEAF_NATURAL_SIZE, 2, nsize);
9091  }
9092 
9093  if (weed_leaf_get_flags(layer, WEED_LEAF_ROWSTRIDES) & LIVES_FLAG_MAINTAIN_VALUE) {
9095  fixed_rs = weed_layer_get_rowstrides(layer, NULL);
9096  } else {
9097  if (THREADVAR(rowstride_alignment) < ALIGN_DEF) THREADVAR(rowstride_alignment) = ALIGN_DEF;
9098  rowstride_alignment = THREADVAR(rowstride_alignment);
9099 
9100  if (THREADVAR(rowstride_alignment_hint) > 0) {
9101  r = rowstride_alignment = THREADVAR(rowstride_alignment_hint);
9102  for (al = 1 << sbits; (al > ALIGN_MIN && !(al & r)); al >>= 1) sbits--;
9103  rowstride_alignment = al;
9104  }
9105  if (THREADVAR(rowstride_alignment_hint) < 0 || (weed_palette_is_alpha(palette) && THREADVAR(rowstride_alignment_hint) == 0)) {
9106  compact = TRUE;
9107  rowstride_alignment = 1;
9108  }
9109  THREADVAR(rowstride_alignment_hint) = 0;
9110 
9111  for (sbits = 7; (1 << sbits) > rowstride_alignment; sbits--);
9112  }
9113 
9114  if (weed_plant_has_leaf(layer, WEED_LEAF_HOST_PIXBUF_SRC)) {
9115  weed_leaf_delete(layer, WEED_LEAF_HOST_PIXBUF_SRC);
9116  }
9117  if (weed_plant_has_leaf(layer, WEED_LEAF_HOST_SURFACE_SRC)) {
9118  weed_leaf_delete(layer, WEED_LEAF_HOST_SURFACE_SRC);
9119  }
9120  if (weed_plant_has_leaf(layer, WEED_LEAF_HOST_SURFACE_SRC)) {
9121  weed_leaf_delete(layer, WEED_LEAF_HOST_SURFACE_SRC);
9122  }
9123  pflags = weed_leaf_get_flags(layer, WEED_LEAF_PIXEL_DATA);
9124  weed_leaf_set_flags(layer, WEED_LEAF_PIXEL_DATA, pflags & ~LIVES_FLAG_MAINTAIN_VALUE);
9125 
9126  if (black_fill) {
9127  if (weed_plant_has_leaf(layer, WEED_LEAF_YUV_CLAMPING))
9128  clamping = weed_get_int_value(layer, WEED_LEAF_YUV_CLAMPING, NULL);
9129  if (clamping != WEED_YUV_CLAMPING_CLAMPED) yuv_black[0] = 0;
9130  }
9131 
9132  switch (palette) {
9133  case WEED_PALETTE_RGBA32:
9134  case WEED_PALETTE_BGRA32:
9135  case WEED_PALETTE_ARGB32:
9136  if (fixed_rs) rowstride = fixed_rs[0];
9137  else {
9138  rowstride = width * 4;
9139  if (!compact) rowstride = ALIGN_CEIL(rowstride, rowstride_alignment);
9140  }
9141  framesize = ALIGN_CEIL(rowstride * height, ALIGN_SIZE) + EXTRA_BYTES;
9142  pixel_data = (uint8_t *)lives_calloc(framesize >> SHIFTVAL, ALIGN_SIZE);
9143  if (!pixel_data) return FALSE;
9144  weed_set_int_value(layer, WEED_LEAF_ROWSTRIDES, rowstride);
9145  weed_set_voidptr_value(layer, WEED_LEAF_PIXEL_DATA, pixel_data);
9146  if (black_fill) {
9147  if (palette == WEED_PALETTE_ARGB32) {
9148  black[3] = black[0];
9149  black[0] = 255;
9150  }
9151  fill_plane(pixel_data, 4, width, height, rowstride, black);
9152  }
9153  weed_set_int_value(layer, WEED_LEAF_ROWSTRIDES, rowstride);
9154  weed_set_voidptr_value(layer, WEED_LEAF_PIXEL_DATA, pixel_data);
9155  break;
9156 
9157  case WEED_PALETTE_RGB24:
9158  case WEED_PALETTE_BGR24:
9159  if (fixed_rs) rowstride = fixed_rs[0];
9160  else {
9161  rowstride = width * 3;
9162  if (!compact) rowstride = ALIGN_CEIL(rowstride, rowstride_alignment);
9163  }
9164  framesize = ALIGN_CEIL(rowstride * height, ALIGN_SIZE) + EXTRA_BYTES;
9165  pixel_data = (uint8_t *)lives_calloc(framesize >> SHIFTVAL, ALIGN_SIZE);
9166  if (!pixel_data) return FALSE;
9167  weed_set_voidptr_value(layer, WEED_LEAF_PIXEL_DATA, pixel_data);
9168  weed_set_int_value(layer, WEED_LEAF_ROWSTRIDES, rowstride);
9169  break;
9170 
9171  case WEED_PALETTE_YUV888:
9172  if (fixed_rs) rowstride = fixed_rs[0];
9173  else {
9174  rowstride = width * 3;
9175  if (!compact) rowstride = ALIGN_CEIL(rowstride, rowstride_alignment);
9176  }
9177  framesize = ALIGN_CEIL(rowstride * height, ALIGN_SIZE) + EXTRA_BYTES;
9178  pixel_data = (uint8_t *)lives_calloc(framesize >> SHIFTVAL, ALIGN_SIZE);
9179  if (!pixel_data) return FALSE;
9180  if (black_fill) fill_plane(pixel_data, 3, width, height, rowstride, yuv_black);
9181  weed_set_int_value(layer, WEED_LEAF_ROWSTRIDES, rowstride);
9182  weed_set_voidptr_value(layer, WEED_LEAF_PIXEL_DATA, pixel_data);
9183  break;
9184 
9185  case WEED_PALETTE_YUVA8888:
9186  if (fixed_rs) rowstride = fixed_rs[0];
9187  else {
9188  rowstride = width * 4;
9189  if (!compact) rowstride = ALIGN_CEIL(rowstride, rowstride_alignment);
9190  }
9191  framesize = ALIGN_CEIL(rowstride * height, ALIGN_SIZE) + EXTRA_BYTES;
9192  pixel_data = (uint8_t *)lives_calloc(framesize >> SHIFTVAL, ALIGN_SIZE);
9193  if (!pixel_data) return FALSE;
9194  if (black_fill) fill_plane(pixel_data, 4, width, height, rowstride, yuv_black);
9195  weed_set_int_value(layer, WEED_LEAF_ROWSTRIDES, rowstride);
9196  weed_set_voidptr_value(layer, WEED_LEAF_PIXEL_DATA, pixel_data);
9197  break;
9198 
9199  case WEED_PALETTE_UYVY:
9200  if (fixed_rs) rowstride = fixed_rs[0];
9201  else {
9202  rowstride = width * 4;
9203  if (!compact) rowstride = ALIGN_CEIL(rowstride, rowstride_alignment);
9204  }
9205  framesize = ALIGN_CEIL(rowstride * height, ALIGN_SIZE) + EXTRA_BYTES;
9206  pixel_data = (uint8_t *)lives_calloc(framesize >> SHIFTVAL, ALIGN_SIZE);
9207  if (!pixel_data) return FALSE;
9208  if (black_fill) {
9209  yuv_black[1] = yuv_black[3] = yuv_black[0];
9210  yuv_black[0] = yuv_black[2];
9211  fill_plane(pixel_data, 4, width, height, rowstride, yuv_black);
9212  }
9213  weed_set_int_value(layer, WEED_LEAF_ROWSTRIDES, rowstride);
9214  weed_set_voidptr_value(layer, WEED_LEAF_PIXEL_DATA, pixel_data);
9215  break;
9216 
9217  case WEED_PALETTE_YUYV:
9218  if (fixed_rs) rowstride = fixed_rs[0];
9219  else {
9220  rowstride = width * 4;
9221  if (!compact) rowstride = ALIGN_CEIL(rowstride, rowstride_alignment);
9222  }
9223  framesize = ALIGN_CEIL(rowstride * height, ALIGN_SIZE) + EXTRA_BYTES;
9224  pixel_data = (uint8_t *)lives_calloc(framesize >> SHIFTVAL, ALIGN_SIZE);
9225  if (!pixel_data) return FALSE;
9226  if (black_fill) {
9227  yuv_black[2] = yuv_black[0];
9228  black[3] = yuv_black[1];
9229  fill_plane(pixel_data, 4, width, height, rowstride, yuv_black);
9230  }
9231  weed_set_int_value(layer, WEED_LEAF_ROWSTRIDES, rowstride);
9232  weed_set_voidptr_value(layer, WEED_LEAF_PIXEL_DATA, pixel_data);
9233  break;
9234 
9235  case WEED_PALETTE_YUV420P:
9236  case WEED_PALETTE_YVU420P:
9237  width = (width >> 1) << 1;
9238  height = (height >> 1) << 1;
9239  weed_layer_set_size(layer, width, height);
9240  if (fixed_rs) rowstride = fixed_rs[0];
9241  else {
9242  rowstride = width;
9243  if (!compact) rowstride = ALIGN_CEIL(rowstride, rowstride_alignment);
9244  }
9245  framesize = ALIGN_CEIL(rowstride * height, ALIGN_SIZE);
9246  rowstrides = (int *)lives_malloc(sizint * 3);
9247  if (fixed_rs) {
9248  rowstrides[0] = fixed_rs[0];
9249  rowstride = rowstrides[1] = fixed_rs[1];
9250  rowstrides[2] = fixed_rs[2];
9251  } else {
9252  rowstrides[0] = rowstride;
9253  rowstride >>= 1;
9254  rowstrides[1] = rowstrides[2] = rowstride;
9255  }
9256  //if (!compact) rowstride = ALIGN_CEIL(rowstride, rowstride_alignment);
9257  framesize2 = ALIGN_CEIL(rowstride * (height >> 1), ALIGN_SIZE);
9258  weed_set_int_array(layer, WEED_LEAF_ROWSTRIDES, 3, rowstrides);
9259  lives_free(rowstrides);
9260 
9261  pd_array = (uint8_t **)lives_malloc(3 * sizeof(uint8_t *));
9262 
9263  if (!may_contig) {
9264  weed_leaf_delete(layer, WEED_LEAF_HOST_PIXEL_DATA_CONTIGUOUS);
9265  pd_array[0] = (uint8_t *)lives_calloc((framesize + EXTRA_BYTES) >> SHIFTVAL, ALIGN_SIZE);
9266  if (!pd_array[0]) {
9267  lives_free(pd_array);
9268  return FALSE;
9269  }
9270  pd_array[1] = (uint8_t *)lives_calloc((framesize2 + EXTRA_BYTES) >> SHIFTVAL, ALIGN_SIZE);
9271  if (!pd_array[1]) {
9272  lives_free(pd_array[0]);
9273  lives_free(pd_array);
9274  return FALSE;
9275  }
9276  pd_array[2] = (uint8_t *)lives_calloc((framesize2 + EXTRA_BYTES) >> SHIFTVAL, ALIGN_SIZE);
9277  if (!pd_array[2]) {
9278  lives_free(pd_array[1]);
9279  lives_free(pd_array[0]);
9280  lives_free(pd_array);
9281  return FALSE;
9282  }
9283  } else {
9284  weed_set_boolean_value(layer, WEED_LEAF_HOST_PIXEL_DATA_CONTIGUOUS, WEED_TRUE);
9285  memblock = (uint8_t *)lives_calloc((framesize + framesize2 * 2 + EXTRA_BYTES) >> SHIFTVAL, ALIGN_SIZE);
9286  if (!memblock) return FALSE;
9287  pd_array[0] = (uint8_t *)memblock;
9288  pd_array[1] = (uint8_t *)(memblock + framesize);
9289  pd_array[2] = (uint8_t *)(memblock + framesize + framesize2);
9290  }
9291  if (black_fill) {
9292  if (yuv_black[0] != 0) lives_memset(pd_array[0], yuv_black[0], framesize);
9293  if (may_contig) {
9294  lives_memset(pd_array[1], yuv_black[1], framesize2 * 2); // fill both planes
9295  } else {
9296  lives_memset(pd_array[1], yuv_black[1], framesize2);
9297  lives_memset(pd_array[2], yuv_black[2], framesize2);
9298  }
9299  }
9300 
9301  weed_set_voidptr_array(layer, WEED_LEAF_PIXEL_DATA, 3, (void **)pd_array);
9302  lives_free(pd_array);
9303  break;
9304 
9305  case WEED_PALETTE_YUV422P:
9306  width = (width >> 1) << 1;
9307  weed_layer_set_width(layer, width);
9308  if (fixed_rs) rowstride = fixed_rs[0];
9309  else {
9310  rowstride = width;
9311  if (!compact) rowstride = ALIGN_CEIL(rowstride, rowstride_alignment);
9312  }
9313  framesize = ALIGN_CEIL(rowstride * height, ALIGN_SIZE);
9314  rowstrides = (int *)lives_malloc(sizint * 3);
9315  if (fixed_rs) rowstride = fixed_rs[1];
9316  else {
9317  rowstrides[0] = rowstride;
9318  rowstride = width >> 1;
9319  if (!compact) rowstride = ALIGN_CEIL(rowstride, rowstride_alignment);
9320  }
9321  framesize2 = ALIGN_CEIL(rowstride * height, ALIGN_SIZE);
9322  if (fixed_rs) {
9323  rowstrides[0] = fixed_rs[0];
9324  rowstrides[1] = fixed_rs[1];
9325  rowstrides[2] = fixed_rs[2];
9326  } else rowstrides[1] = rowstrides[2] = rowstride;
9327  weed_set_int_array(layer, WEED_LEAF_ROWSTRIDES, 3, rowstrides);
9328  lives_free(rowstrides);
9329  pd_array = (uint8_t **)lives_malloc(3 * sizeof(uint8_t *));
9330 
9331  if (!may_contig) {
9332  weed_leaf_delete(layer, WEED_LEAF_HOST_PIXEL_DATA_CONTIGUOUS);
9333  pd_array[0] = (uint8_t *)lives_calloc(framesize >> SHIFTVAL, ALIGN_SIZE);
9334  if (!pd_array[0]) {
9335  lives_free(pd_array);
9336  return FALSE;
9337  }
9338  pd_array[1] = (uint8_t *)lives_calloc(framesize2 >> SHIFTVAL, ALIGN_SIZE);
9339  if (!pd_array[1]) {
9340  lives_free(pd_array[0]);
9341  lives_free(pd_array);
9342  return FALSE;
9343  }
9344  pd_array[2] = (uint8_t *)lives_calloc((framesize2 + EXTRA_BYTES) >> SHIFTVAL, ALIGN_SIZE);
9345  if (!pd_array[2]) {
9346  lives_free(pd_array[1]);
9347  lives_free(pd_array[0]);
9348  lives_free(pd_array);
9349  return FALSE;
9350  }
9351  } else {
9352  weed_set_boolean_value(layer, WEED_LEAF_HOST_PIXEL_DATA_CONTIGUOUS, WEED_TRUE);
9353  memblock = (uint8_t *)lives_calloc((framesize + framesize2 * 2 + EXTRA_BYTES) >> SHIFTVAL, ALIGN_SIZE);
9354  if (!memblock) return FALSE;
9355  pd_array[0] = (uint8_t *)memblock;
9356  pd_array[1] = (uint8_t *)(memblock + framesize);
9357  pd_array[2] = (uint8_t *)(memblock + framesize + framesize2);
9358  }
9359  if (black_fill) {
9360  if (yuv_black[0] != 0) lives_memset(pd_array[0], yuv_black[0], framesize);
9361  if (may_contig) {
9362  lives_memset(pd_array[1], yuv_black[1], framesize2 * 2);
9363  } else {
9364  lives_memset(pd_array[1], yuv_black[1], framesize2);
9365  lives_memset(pd_array[2], yuv_black[2], framesize2);
9366  }
9367  }
9368  weed_set_voidptr_array(layer, WEED_LEAF_PIXEL_DATA, 3, (void **)pd_array);
9369  lives_free(pd_array);
9370  break;
9371 
9372  case WEED_PALETTE_YUV444P:
9373  if (!fixed_rs) {
9374  rowstride = width;
9375  if (!compact) rowstride = ALIGN_CEIL(rowstride, rowstride_alignment);
9376  }
9377  rowstrides = (int *)lives_malloc(sizint * 3);
9378  if (fixed_rs) {
9379  rowstride = rowstrides[0] = fixed_rs[0];
9380  rowstrides[1] = fixed_rs[1];
9381  rowstrides[2] = fixed_rs[2];
9382  } else rowstrides[0] = rowstrides[1] = rowstrides[2] = rowstride;
9383  weed_set_int_array(layer, WEED_LEAF_ROWSTRIDES, 3, rowstrides);
9384  lives_free(rowstrides);
9385  pd_array = (uint8_t **)lives_malloc(3 * sizeof(uint8_t *));
9386  framesize = ALIGN_CEIL(rowstride * height, ALIGN_SIZE);
9387 
9388  if (!may_contig) {
9389  weed_leaf_delete(layer, WEED_LEAF_HOST_PIXEL_DATA_CONTIGUOUS);
9390  pd_array[0] = (uint8_t *)lives_calloc(framesize >> SHIFTVAL, ALIGN_SIZE);
9391  if (!pd_array[0]) {
9392  lives_free(pd_array);
9393  return FALSE;
9394  }
9395  pd_array[1] = (uint8_t *)lives_calloc(framesize >> SHIFTVAL, ALIGN_SIZE);
9396  if (!pd_array[1]) {
9397  lives_free(pd_array[0]);
9398  lives_free(pd_array);
9399  return FALSE;
9400  }
9401  pd_array[2] = (uint8_t *)lives_calloc((framesize + EXTRA_BYTES) >> SHIFTVAL, ALIGN_SIZE);
9402  if (!pd_array[2]) {
9403  lives_free(pd_array[1]);
9404  lives_free(pd_array[0]);
9405  lives_free(pd_array);
9406  return FALSE;
9407  }
9408  } else {
9409  weed_set_boolean_value(layer, WEED_LEAF_HOST_PIXEL_DATA_CONTIGUOUS, WEED_TRUE);
9410  memblock = (uint8_t *)lives_calloc((framesize * 3 + EXTRA_BYTES) >> SHIFTVAL, ALIGN_SIZE);
9411  if (!memblock) return FALSE;
9412  pd_array[0] = memblock;
9413  pd_array[1] = memblock + framesize;
9414  pd_array[2] = memblock + framesize * 2;
9415  }
9416  if (black_fill) {
9417  if (yuv_black[0] != 0) lives_memset(pd_array[0], yuv_black[0], framesize);
9418  if (may_contig) {
9419  lives_memset(pd_array[1], yuv_black[1], framesize * 2);
9420  } else {
9421  lives_memset(pd_array[1], yuv_black[1], framesize);
9422  lives_memset(pd_array[2], yuv_black[2], framesize);
9423  }
9424  }
9425  weed_set_voidptr_array(layer, WEED_LEAF_PIXEL_DATA, 3, (void **)pd_array);
9426  lives_free(pd_array);
9427  break;
9428 
9429  case WEED_PALETTE_YUVA4444P:
9430  if (!fixed_rs) {
9431  rowstride = width;
9432  if (!compact) rowstride = ALIGN_CEIL(rowstride, rowstride_alignment);
9433  }
9434  rowstrides = (int *)lives_malloc(sizint * 4);
9435  if (fixed_rs) {
9436  rowstride = rowstrides[0] = fixed_rs[0];
9437  rowstrides[1] = fixed_rs[1];
9438  rowstrides[2] = fixed_rs[2];
9439  rowstrides[3] = fixed_rs[3];
9440  } else rowstrides[0] = rowstrides[1] = rowstrides[2] = rowstrides[3] = rowstride;
9441  weed_set_int_array(layer, WEED_LEAF_ROWSTRIDES, 4, rowstrides);
9442  lives_free(rowstrides);
9443  pd_array = (uint8_t **)lives_malloc(4 * sizeof(uint8_t *));
9444  framesize = ALIGN_CEIL(rowstride * height, ALIGN_SIZE);
9445 
9446  if (!may_contig) {
9447  weed_leaf_delete(layer, WEED_LEAF_HOST_PIXEL_DATA_CONTIGUOUS);
9448  pd_array[0] = (uint8_t *)lives_calloc((framesize + EXTRA_BYTES) >> SHIFTVAL, ALIGN_SIZE);
9449  if (!pd_array[0]) {
9450  lives_free(pd_array);
9451  return FALSE;
9452  }
9453  pd_array[1] = (uint8_t *)lives_calloc((framesize + EXTRA_BYTES) >> SHIFTVAL, ALIGN_SIZE);
9454  if (!pd_array[1]) {
9455  lives_free(pd_array[0]);
9456  lives_free(pd_array);
9457  return FALSE;
9458  }
9459  pd_array[2] = (uint8_t *)lives_calloc((framesize + EXTRA_BYTES) >> SHIFTVAL, ALIGN_SIZE);
9460  if (!pd_array[2]) {
9461  lives_free(pd_array[1]);
9462  lives_free(pd_array[0]);
9463  lives_free(pd_array);
9464  return FALSE;
9465  }
9466  pd_array[3] = (uint8_t *)lives_calloc((framesize + EXTRA_BYTES) >> SHIFTVAL, ALIGN_SIZE);
9467  if (!pd_array[3]) {
9468  lives_free(pd_array[2]);
9469  lives_free(pd_array[1]);
9470  lives_free(pd_array[0]);
9471  lives_free(pd_array);
9472  return FALSE;
9473  }
9474  } else {
9475  weed_set_boolean_value(layer, WEED_LEAF_HOST_PIXEL_DATA_CONTIGUOUS, WEED_TRUE);
9476  memblock = (uint8_t *)lives_calloc((framesize * 4 + EXTRA_BYTES) >> SHIFTVAL, ALIGN_SIZE);
9477  if (!memblock) return FALSE;
9478  pd_array[0] = memblock;
9479  pd_array[1] = memblock + framesize;
9480  pd_array[2] = memblock + framesize * 2;
9481  pd_array[3] = memblock + framesize * 3;
9482  }
9483  if (black_fill) {
9484  if (yuv_black[0] != 0) {
9485  lives_memset(pd_array[0], yuv_black[0], framesize * 2);
9486  }
9487  if (may_contig) {
9488  lives_memset(pd_array[1], yuv_black[1], framesize * 2);
9489  } else {
9490  lives_memset(pd_array[1], yuv_black[1], framesize);
9491  lives_memset(pd_array[2], yuv_black[2], framesize);
9492  }
9493  lives_memset(pd_array[3], 255, framesize);
9494  }
9495  weed_set_voidptr_array(layer, WEED_LEAF_PIXEL_DATA, 4, (void **)pd_array);
9496  lives_free(pd_array);
9497  break;
9498 
9499  case WEED_PALETTE_YUV411:
9500  if (fixed_rs) rowstride = fixed_rs[0];
9501  else {
9502  rowstride = width * 6; // a macro-pixel is 6 bytes, and contains 4 real pixels
9503  if (!compact) rowstride = ALIGN_CEIL(rowstride, rowstride_alignment);
9504  }
9505  weed_layer_set_width(layer, width);
9506  framesize = ALIGN_CEIL(rowstride * height, ALIGN_SIZE);
9507  pixel_data = (uint8_t *)lives_calloc((framesize + EXTRA_BYTES) >> SHIFTVAL, ALIGN_SIZE);
9508  if (!pixel_data) return FALSE;
9509  if (black_fill) {
9510  yuv_black[3] = yuv_black[1];
9511  yuv_black[1] = yuv_black[2] = yuv_black[4] = yuv_black[5] = yuv_black[0];
9512  yuv_black[0] = yuv_black[3];
9513  pixel_data = (uint8_t *)lives_calloc((framesize + EXTRA_BYTES) >> SHIFTVAL, ALIGN_SIZE);
9514  if (black_fill) {
9515  fill_plane(pixel_data, 6, width, height, rowstride, black);
9516  }
9517  }
9518  if (!pixel_data) return FALSE;
9519  weed_set_voidptr_value(layer, WEED_LEAF_PIXEL_DATA, pixel_data);
9520  weed_set_int_value(layer, WEED_LEAF_ROWSTRIDES, rowstride);
9521  break;
9522 
9523  case WEED_PALETTE_RGBFLOAT:
9524  if (fixed_rs) rowstride = fixed_rs[0];
9525  else {
9526  rowstride = width * 3 * sizeof(float);
9527  if (!compact) rowstride = ALIGN_CEIL(rowstride, rowstride_alignment);
9528  }
9529  pixel_data = (uint8_t *)lives_calloc((rowstride * height + EXTRA_BYTES) >> SHIFTVAL, ALIGN_SIZE);
9530  if (!pixel_data) return FALSE;
9531  weed_set_voidptr_value(layer, WEED_LEAF_PIXEL_DATA, pixel_data);
9532  weed_set_int_value(layer, WEED_LEAF_ROWSTRIDES, rowstride);
9533  break;
9534 
9535  case WEED_PALETTE_RGBAFLOAT:
9536  if (fixed_rs) rowstride = fixed_rs[0];
9537  else {
9538  rowstride = width * 4 * sizeof(float);
9539  if (!compact) rowstride = ALIGN_CEIL(rowstride, rowstride_alignment);
9540  }
9541  pixel_data = (uint8_t *)lives_calloc((rowstride * height + EXTRA_BYTES), ALIGN_SIZE);
9542  if (black_fill) {
9543  fill_plane(pixel_data, 4 * sizeof(float), width, height, rowstride, (uint8_t *)blackf);
9544  }
9545  if (!pixel_data) return FALSE;
9546  weed_set_voidptr_value(layer, WEED_LEAF_PIXEL_DATA, pixel_data);
9547  weed_set_int_value(layer, WEED_LEAF_ROWSTRIDES, rowstride);
9548  break;
9549 
9550  case WEED_PALETTE_AFLOAT:
9551  if (fixed_rs) rowstride = fixed_rs[0];
9552  else {
9553  rowstride = width * sizeof(float);
9554  if (!compact) rowstride = ALIGN_CEIL(rowstride, rowstride_alignment);
9555  }
9556  pixel_data = (uint8_t *)lives_calloc((width * height + EXTRA_BYTES) >> SHIFTVAL, ALIGN_SIZE);
9557  if (!pixel_data) return FALSE;
9558  if (black_fill) {
9559  blackf[0] = 1.;
9560  fill_plane(pixel_data, sizeof(float), width, height, rowstride, (uint8_t *)blackf);
9561  }
9562  weed_set_voidptr_value(layer, WEED_LEAF_PIXEL_DATA, pixel_data);
9563  weed_set_int_value(layer, WEED_LEAF_ROWSTRIDES, rowstride);
9564  break;
9565 
9566  case WEED_PALETTE_A8:
9567  if (fixed_rs) rowstride = fixed_rs[0];
9568  else {
9569  rowstride = width;
9570  if (!compact) rowstride = ALIGN_CEIL(rowstride, rowstride_alignment);
9571  }
9572  framesize = ALIGN_CEIL((rowstride * height + EXTRA_BYTES), ALIGN_SIZE);
9573  pixel_data = (uint8_t *)lives_calloc(framesize >> SHIFTVAL, ALIGN_SIZE);
9574  if (!pixel_data) return FALSE;
9575  if (black_fill) {
9576  lives_memset(pixel_data, 255, rowstride * height);
9577  }
9578  if (!pixel_data) return FALSE;
9579  weed_set_voidptr_value(layer, WEED_LEAF_PIXEL_DATA, pixel_data);
9580  weed_set_int_value(layer, WEED_LEAF_ROWSTRIDES, rowstride);
9581  break;
9582 
9583  case WEED_PALETTE_A1:
9584  if (fixed_rs) rowstride = fixed_rs[0];
9585  else rowstride = (width + 7) >> 3;
9586  framesize = ALIGN_CEIL(rowstride * height, ALIGN_SIZE);
9587  pixel_data = (uint8_t *)lives_calloc((framesize + EXTRA_BYTES) >> SHIFTVAL, ALIGN_SIZE);
9588  if (!pixel_data) return FALSE;
9589  lives_memset(pixel_data, 255, rowstride * height);
9590  weed_set_voidptr_value(layer, WEED_LEAF_PIXEL_DATA, pixel_data);
9591  weed_set_int_value(layer, WEED_LEAF_ROWSTRIDES, rowstride);
9592  break;
9593 
9594  default:
9595  lives_printerr("Warning: asked to create empty pixel_data for palette %d !\n", palette);
9596  break_me("create_empty_pixel_data w. unknown pal");
9597  }
9598  return TRUE;
9599 }
9600 
9601 
9611 weed_layer_t *create_blank_layer(weed_layer_t *layer, const char *image_ext, int width, int height, int target_palette) {
9612  if (!layer) layer = weed_layer_new(WEED_LAYER_TYPE_VIDEO);
9613  else {
9614  if (!width) width = weed_layer_get_width(layer);
9615  if (!height) height = weed_layer_get_height(layer);
9616  if (!width || !height) {
9617  int clip = lives_layer_get_clip(layer);
9618  if (clip && IS_VALID_CLIP(clip)) {
9619  width = mainw->files[clip]->hsize;
9620  height = mainw->files[clip]->vsize;
9621  }
9622  }
9623  }
9624  if (width == 0) width = DEF_FRAME_HSIZE_UNSCALED;
9625  if (height == 0) height = DEF_FRAME_VSIZE_UNSCALED;
9626  weed_layer_set_size(layer, width, height);
9627  if (!weed_plant_has_leaf(layer, WEED_LEAF_CURRENT_PALETTE)) {
9628  if (target_palette != WEED_PALETTE_END) weed_layer_set_palette(layer, target_palette);
9629  else {
9630  if (!image_ext || !strcmp(image_ext, LIVES_FILE_EXT_JPG))
9631  weed_layer_set_palette(layer, WEED_PALETTE_RGB24);
9632  else weed_layer_set_palette(layer, WEED_PALETTE_RGBA32);
9633  }
9634  }
9636  if (!weed_plant_has_leaf(layer, WEED_LEAF_GAMMA_TYPE)) {
9637  int clip = lives_layer_get_clip(layer);
9638  if (clip && IS_VALID_CLIP(clip))
9639  weed_layer_set_gamma(layer, mainw->files[clip]->gamma_type);
9640  else
9641  weed_layer_set_gamma(layer, WEED_GAMMA_SRGB);
9642  }
9643  return layer;
9644 }
9645 
9646 
9647 LIVES_GLOBAL_INLINE boolean rowstrides_differ(int n1, int *n1_array, int n2, int *n2_array) {
9648  // returns TRUE if the rowstrides differ
9649  if (!n1_array || !n2_array || n1 != n2) return TRUE;
9650  for (int i = 0; i < n1; i++) if (n1_array[i] != n2_array[i]) return TRUE;
9651  return FALSE;
9652 }
9653 
9654 
9656  weed_layer_t *layer = weed_plant_new(WEED_PLANT_LAYER);
9657  weed_set_int_value(layer, WEED_LEAF_LAYER_TYPE, layer_type);
9658  weed_set_int_value(layer, WEED_LEAF_HOST_REFS, 1);
9659  return layer;
9660 }
9661 
9662 
9664  if (!layer || !WEED_IS_LAYER(layer)) return WEED_LAYER_TYPE_NONE;
9665  return weed_get_int_value(layer, WEED_LEAF_LAYER_TYPE, NULL);
9666 }
9667 
9668 
9670  if (layer && WEED_IS_LAYER(layer) && weed_layer_get_type(layer) == WEED_LAYER_TYPE_VIDEO) return WEED_TRUE;
9671  return WEED_FALSE;
9672 }
9673 
9674 
9676  if (layer && WEED_IS_LAYER(layer) && weed_layer_get_type(layer) == WEED_LAYER_TYPE_AUDIO) return WEED_TRUE;
9677  return WEED_FALSE;
9678 }
9679 
9680 
9682  int arate, int naudchans, weed_size_t nsamps) {
9683  if (!layer || !WEED_IS_LAYER(layer)) return NULL;
9684  weed_set_voidptr_array(layer, WEED_LEAF_AUDIO_DATA, naudchans, (void **)data);
9685  weed_set_int_value(layer, WEED_LEAF_AUDIO_RATE, arate);
9686  weed_set_int_value(layer, WEED_LEAF_AUDIO_DATA_LENGTH, nsamps);
9687  weed_set_int_value(layer, WEED_LEAF_AUDIO_CHANNELS, naudchans);
9688  return layer;
9689 }
9690 
9691 
9693  if (!layer || !WEED_IS_LAYER(layer)) return NULL;
9694  weed_set_int_value(layer, WEED_LEAF_FLAGS, flags);
9695  return layer;
9696 }
9697 
9698 
9700  if (!layer || !WEED_IS_LAYER(layer)) return 0;
9701  return weed_get_int_value(layer, WEED_LEAF_FLAGS, NULL);
9702 }
9703 
9704 
9706  if (!layer || !WEED_IS_LAYER(layer)) return 0;
9707  return weed_get_int_value(layer, WEED_LEAF_CLIP, NULL);
9708 }
9709 
9710 
9712  if (!layer || !WEED_IS_LAYER(layer)) return 0;
9713  return weed_get_int_value(layer, WEED_LEAF_FRAME, NULL);
9714 }
9715 
9716 
9718  if (!layer || !WEED_IS_LAYER(layer)) return NULL;
9719  weed_set_int_value(layer, WEED_LEAF_WIDTH, width);
9720  return layer;
9721 }
9722 
9723 
9725  if (!layer || !WEED_IS_LAYER(layer)) return NULL;
9726  weed_set_int_value(layer, WEED_LEAF_HEIGHT, height);
9727  return layer;
9728 }
9729 
9730 
9732  if (!layer || !WEED_IS_LAYER(layer)) return NULL;
9733  weed_layer_set_width(layer, width);
9734  weed_layer_set_height(layer, height);
9735  return layer;
9736 }
9737 
9738 
9740  if (!layer || !WEED_IS_LAYER(layer)) return NULL;
9741  weed_set_voidptr_array(layer, WEED_LEAF_PIXEL_DATA, nplanes, pixel_data);
9742  return layer;
9743 }
9744 
9745 
9747  if (!layer || !WEED_IS_LAYER(layer)) return NULL;
9748  weed_set_voidptr_value(layer, WEED_LEAF_PIXEL_DATA, pixel_data);
9749  return layer;
9750 }
9751 
9752 
9754  if (!layer || !WEED_IS_LAYER(layer)) return NULL;
9755  weed_set_voidptr_array(layer, WEED_LEAF_PIXEL_DATA, 0, NULL);
9756  weed_leaf_delete(layer, WEED_LEAF_HOST_PIXEL_DATA_CONTIGUOUS);
9757  weed_leaf_delete(layer, WEED_LEAF_HOST_PIXBUF_SRC);
9758  weed_leaf_delete(layer, WEED_LEAF_HOST_SURFACE_SRC);
9759  return layer;
9760 }
9761 
9762 
9764  if (!layer || !WEED_IS_LAYER(layer)) return NULL;
9765  weed_set_int_array(layer, WEED_LEAF_ROWSTRIDES, nplanes, rowstrides);
9766  return layer;
9767 }
9768 
9769 
9771  if (!layer || !WEED_IS_LAYER(layer)) return NULL;
9772  weed_set_int_value(layer, WEED_LEAF_ROWSTRIDES, rowstride);
9773  return layer;
9774 }
9775 
9776 
9778  if (!layer || !WEED_IS_LAYER(layer)) return NULL;
9779  weed_set_int_value(layer, WEED_LEAF_CURRENT_PALETTE, palette);
9780  return layer;
9781 }
9782 
9783 
9785  if (!layer || !WEED_IS_LAYER(layer)) return NULL;
9786  weed_set_int_value(layer, WEED_LEAF_GAMMA_TYPE, gamma_type);
9787  return layer;
9788 }
9789 
9790 
9792  if (!layer || !WEED_IS_LAYER(layer)) return NULL;
9793  weed_set_int_value(layer, WEED_LEAF_YUV_CLAMPING, clamping);
9794  return layer;
9795 }
9796 
9797 
9799  if (!layer || !WEED_IS_LAYER(layer)) return NULL;
9800  weed_set_int_value(layer, WEED_LEAF_YUV_SAMPLING, sampling);
9801  return layer;
9802 }
9803 
9804 
9806  if (!layer || !WEED_IS_LAYER(layer)) return NULL;
9807  weed_set_int_value(layer, WEED_LEAF_YUV_SUBSPACE, subspace);
9808  return layer;
9809 }
9810 
9811 
9813  int clamping, int sampling, int subspace) {
9814  if (!weed_layer_set_palette(layer, palette)) return NULL;
9815  weed_layer_set_yuv_clamping(layer, clamping);
9816  weed_layer_set_yuv_sampling(layer, sampling);
9817  weed_layer_set_yuv_subspace(layer, subspace);
9818  return layer;
9819 }
9820 
9821 
9823  // TODO -> int64
9824  weed_set_int_value(layer, WEED_LEAF_FRAME, frame);
9825 }
9826 
9827 
9829  weed_set_int_value(layer, WEED_LEAF_CLIP, clip);
9830 }
9831 
9832 
9834  // create a layer ready to receive a frame from a clip
9836  lives_layer_set_clip(layer, clip);
9837  lives_layer_set_frame(layer, frame);
9838  return layer;
9839 }
9840 
9841 
9842 // returns TRUE on success
9843 boolean copy_pixel_data(weed_layer_t *layer, weed_layer_t *old_layer, size_t alignment) {
9844  // copy (deep) old_layer -> layer
9845 
9846  int numplanes, xheight, xwidth;
9847  int *orowstrides = weed_layer_get_rowstrides(old_layer, &numplanes), *rowstrides;
9848  void **pixel_data, **npixel_data;
9849  int pal = weed_layer_get_palette(layer);
9850  int width = weed_layer_get_width(layer);
9851  int height = weed_layer_get_height(layer);
9852  int psize = pixel_size(pal);
9853  int i = numplanes, j;
9854  boolean newdata = FALSE;
9855 
9856  if (alignment != 0 && !old_layer) {
9857  while (i > 0) if (orowstrides[--i] % alignment != 0) i = -1;
9858  if (i == 0) return TRUE;
9859  }
9860 
9861  if (!old_layer) {
9862  newdata = TRUE;
9864  weed_layer_copy(old_layer, layer);
9865  }
9866  pixel_data = weed_layer_get_pixel_data(old_layer, &numplanes);
9867  if (!pixel_data || !pixel_data[0]) {
9868  if (newdata) {
9869  weed_layer_nullify_pixel_data(old_layer);
9870  weed_layer_free(old_layer);
9871  }
9872  return FALSE;
9873  }
9874 
9876 
9877  if (alignment != 0) THREADVAR(rowstride_alignment_hint) = alignment;
9878 
9879  if (!create_empty_pixel_data(layer, FALSE, TRUE)) {
9880  if (newdata) {
9881  weed_layer_copy(layer, old_layer);
9882  weed_layer_nullify_pixel_data(old_layer);
9883  weed_layer_free(old_layer);
9884  }
9885  return FALSE;
9886  }
9887 
9888  rowstrides = weed_layer_get_rowstrides(layer, &numplanes);
9889  npixel_data = weed_layer_get_pixel_data(layer, &numplanes);
9890  width = weed_layer_get_width(layer);
9891  height = weed_layer_get_height(layer);
9892 
9893  for (i = 0; i < numplanes; i++) {
9894  xheight = height * weed_palette_get_plane_ratio_vertical(pal, i);
9895  if (rowstrides[i] == orowstrides[i])
9896  lives_memcpy(npixel_data[i], pixel_data[i], xheight * rowstrides[i]);
9897  else {
9898  uint8_t *dst = (uint8_t *)npixel_data[i];
9899  uint8_t *src = (uint8_t *)pixel_data[i];
9900  xwidth = width * psize * weed_palette_get_plane_ratio_horizontal(pal, i);
9901  for (j = 0; j < xheight; j++) {
9902  lives_memcpy(dst, src, xwidth);
9903  src += orowstrides[i];
9904  dst += rowstrides[i];
9905  }
9906  }
9907  }
9908 
9909  weed_leaf_dup(layer, old_layer, WEED_LEAF_NATURAL_SIZE);
9910 
9911  if (newdata) weed_layer_free(old_layer);
9912  lives_freep((void **)&npixel_data);
9913  lives_freep((void **)&pixel_data);
9914  lives_freep((void **)&orowstrides);
9915  lives_freep((void **)&rowstrides);
9916  return TRUE;
9917 }
9918 
9919 
9923 void alpha_unpremult(weed_layer_t *layer, boolean un) {
9925  int error;
9926  int aoffs, coffs, psize, psizel, widthx;
9927  int alpha;
9928  int flags = 0;
9929  int width = weed_get_int_value(layer, WEED_LEAF_WIDTH, NULL);
9930  int height = weed_get_int_value(layer, WEED_LEAF_HEIGHT, NULL);
9931  int rowstride = weed_get_int_value(layer, WEED_LEAF_ROWSTRIDES, NULL);
9932  int pal = weed_get_int_value(layer, WEED_LEAF_CURRENT_PALETTE, NULL);
9933 
9934  int *rows;
9935 
9936  unsigned char *ptr;
9937  unsigned char **ptrp;
9938 
9939  boolean clamped;
9940 
9941  int i, j, p;
9942 
9943  if (!unal_inited) init_unal();
9944 
9945  if (weed_plant_has_leaf(layer, WEED_LEAF_YUV_CLAMPING))
9946  clamped = (weed_get_int_value(layer, WEED_LEAF_YUV_CLAMPING, &error) == WEED_YUV_CLAMPING_CLAMPED);
9947  else clamped = TRUE;
9948 
9949  switch (pal) {
9950  case WEED_PALETTE_RGBA32:
9951  case WEED_PALETTE_BGRA32:
9952  clamped = FALSE;
9953  case WEED_PALETTE_YUVA8888:
9954  widthx = width * 4;
9955  psize = 4;
9956  psizel = 3;
9957  coffs = 0;
9958  aoffs = 3;
9959  break;
9960  case WEED_PALETTE_ARGB32:
9961  widthx = width * 4;
9962  psize = 4;
9963  psizel = 4;
9964  coffs = 1;
9965  aoffs = 0;
9966  clamped = FALSE;
9967  break;
9968  case WEED_PALETTE_YUVA4444P:
9970  ptrp = (unsigned char **)weed_get_voidptr_array(layer, WEED_LEAF_PIXEL_DATA, &error);
9971  rows = weed_get_int_array(layer, WEED_LEAF_ROWSTRIDES, &error);
9972 
9973  if (!clamped) {
9974  if (un) {
9975  for (i = 0; i < height; i++) {
9976  for (j = 0; j < width; j++) {
9977  alpha = ptrp[3][j];
9978  for (p = 0; p < 3; p++) {
9979  ptrp[p][j] = unal[alpha][ptrp[p][j]];
9980  }
9981  }
9982  for (p = 0; p < 4; p++) {
9983  ptrp[p] += rows[p];
9984  }
9985  }
9986  } else {
9987  for (i = 0; i < height; i++) {
9988  for (j = 0; j < width; j++) {
9989  alpha = ptrp[3][j];
9990  for (p = 0; p < 3; p++) {
9991  ptrp[p][j] = al[alpha][ptrp[p][j]];
9992  }
9993  }
9994  for (p = 0; p < 4; p++) {
9995  ptrp[p] += rows[p];
9996  }
9997  }
9998  }
9999  } else {
10000  if (un) {
10001  for (i = 0; i < height; i++) {
10002  for (j = 0; j < width; j++) {
10003  alpha = ptrp[3][j];
10004  ptrp[0][j] = unalcy[alpha][ptrp[0][j]];
10005  ptrp[1][j] = unalcuv[alpha][ptrp[0][j]];
10006  ptrp[2][j] = unalcuv[alpha][ptrp[0][j]];
10007  }
10008  for (p = 0; p < 4; p++) {
10009  ptrp[p] += rows[p];
10010  }
10011  }
10012  } else {
10013  for (i = 0; i < height; i++) {
10014  for (j = 0; j < width; j++) {
10015  alpha = ptrp[3][j];
10016  ptrp[0][j] = alcy[alpha][ptrp[0][j]];
10017  ptrp[1][j] = alcuv[alpha][ptrp[0][j]];
10018  ptrp[2][j] = alcuv[alpha][ptrp[0][j]];
10019  }
10020  for (p = 0; p < 4; p++) {
10021  ptrp[p] += rows[p];
10022  // *INDENT-OFF*
10023  }}}}
10024  // *INDENT-ON*
10025 
10026  return;
10027  default:
10028  return;
10029  }
10030 
10031  ptr = (unsigned char *)weed_get_voidptr_value(layer, WEED_LEAF_PIXEL_DATA, &error);
10032 
10033  if (!clamped) {
10034  if (un) {
10035  for (i = 0; i < height; i++) {
10036  for (j = 0; j < widthx; j += psize) {
10037  alpha = ptr[j + aoffs];
10038  for (p = coffs; p < psizel; p++) {
10039  ptr[j + p] = unal[alpha][ptr[j + p]];
10040  }
10041  }
10042  ptr += rowstride;
10043  }
10044  } else {
10045  for (i = 0; i < height; i++) {
10046  for (j = 0; j < widthx; j += psize) {
10047  alpha = ptr[j + aoffs];
10048  for (p = coffs; p < psizel; p++) {
10049  ptr[j + p] = al[alpha][ptr[j + p]];
10050  }
10051  }
10052  ptr += rowstride;
10053  }
10054  }
10055  } else {
10057  if (un) {
10058  for (i = 0; i < height; i++) {
10059  for (j = 0; j < widthx; j += psize) {
10060  alpha = ptr[j + 3];
10061  ptr[j] = unalcy[alpha][ptr[j]];
10062  ptr[j + 1] = unalcuv[alpha][ptr[j]];
10063  ptr[j + 2] = unalcuv[alpha][ptr[j]];
10064  }
10065  ptr += rowstride;
10066  }
10067  } else {
10068  for (i = 0; i < height; i++) {
10069  for (j = 0; j < widthx; j += psize) {
10070  alpha = ptr[j + 3];
10071  ptr[j] = alcy[alpha][ptr[j]];
10072  ptr[j + 1] = alcuv[alpha][ptr[j]];
10073  ptr[j + 2] = alcuv[alpha][ptr[j]];
10074  }
10075  ptr += rowstride;
10076  }
10077  }
10078  }
10079 
10080  flags = weed_layer_get_flags(layer);
10081 
10082  if (!un) flags |= WEED_LAYER_ALPHA_PREMULT;
10083  else if (flags & WEED_LAYER_ALPHA_PREMULT) flags ^= WEED_LAYER_ALPHA_PREMULT;
10084 
10085  if (flags == 0) weed_leaf_delete(layer, WEED_LEAF_FLAGS);
10086  else weed_set_int_value(layer, WEED_LEAF_FLAGS, flags);
10087 }
10088 
10089 
10090 static void swap_chroma_planes(weed_layer_t *layer) {
10091  int nplanes;
10092  void **pd_array = weed_layer_get_pixel_data(layer, &nplanes);
10093  int *rowstrides, rtmp;
10094  uint8_t *tmp;
10095  if (nplanes < 3) return;
10096  tmp = pd_array[1];
10097  pd_array[1] = pd_array[2];
10098  pd_array[2] = tmp;
10099  weed_layer_set_pixel_data(layer, pd_array, nplanes);
10100  lives_free(pd_array);
10101  rowstrides = weed_layer_get_rowstrides(layer, NULL);
10102  rtmp = rowstrides[1];
10103  rowstrides[1] = rowstrides[2];
10104  rowstrides[2] = rtmp;
10105 }
10106 
10107 
10108 LIVES_LOCAL_INLINE boolean can_inline_gamma(int inpl, int opal) {
10109  // TODO: rgb <-> bgra, bgr <-> rgba,
10110  if (inpl == WEED_PALETTE_YUV420P || inpl == WEED_PALETTE_YUV420P || inpl == WEED_PALETTE_YUV420P) {
10111  if (opal == WEED_PALETTE_RGB24 || opal == WEED_PALETTE_BGR24 || opal == WEED_PALETTE_RGBA32
10112  || opal == WEED_PALETTE_ARGB32) return TRUE;
10113  }
10114  if (opal == WEED_PALETTE_UYVY || opal == WEED_PALETTE_YUYV) {
10115  if (inpl == WEED_PALETTE_RGB24 || inpl == WEED_PALETTE_RGBA32
10116  || inpl == WEED_PALETTE_BGR24 || inpl == WEED_PALETTE_BGRA32
10117  || inpl == WEED_PALETTE_ARGB32
10118  ) return TRUE;
10119  }
10120 
10121  if ((inpl == WEED_PALETTE_RGB24 && opal == WEED_PALETTE_BGR24) || (inpl == WEED_PALETTE_BGR24
10122  && opal == WEED_PALETTE_RGB24)) return TRUE;
10123  if ((inpl == WEED_PALETTE_RGB24 && opal == WEED_PALETTE_RGBA32) || (inpl == WEED_PALETTE_BGR24
10124  && opal == WEED_PALETTE_BGRA32)) return TRUE;
10125  if ((inpl == WEED_PALETTE_RGBA32 && opal == WEED_PALETTE_RGB24) || (inpl == WEED_PALETTE_BGRA32
10126  && opal == WEED_PALETTE_BGR24)) return TRUE;
10127 
10128  return FALSE;
10129 }
10130 
10131 
10160 boolean convert_layer_palette_full(weed_layer_t *layer, int outpl, int oclamping, int osampling, int osubspace, int tgamma) {
10161  // TODO: allow plugin candidates/delegates
10162  weed_layer_t *orig_layer;
10163  uint8_t *gusrc = NULL, **gusrc_array = NULL, *gudest = NULL, **gudest_array = NULL, *tmp;
10164  int width, height, orowstride, irowstride, *istrides, *ostrides = NULL;
10165  int nplanes;
10166  int error, inpl, flags = 0;
10167  int isampling, isubspace;
10168  int new_gamma_type = WEED_GAMMA_UNKNOWN;
10169  int iclamping;
10170  boolean contig = FALSE;
10171 
10172  if (!layer || !weed_layer_get_pixel_data_packed(layer)) return FALSE;
10173 
10174  inpl = weed_layer_get_palette(layer);
10175 
10176  if (weed_plant_has_leaf(layer, WEED_LEAF_YUV_SAMPLING))
10177  isampling = weed_layer_get_yuv_sampling(layer);
10178  else isampling = WEED_YUV_SAMPLING_DEFAULT;
10179 
10180  if (weed_plant_has_leaf(layer, WEED_LEAF_YUV_CLAMPING))
10181  iclamping = weed_layer_get_yuv_clamping(layer);
10182  else iclamping = oclamping;
10183 
10184  if (weed_plant_has_leaf(layer, WEED_LEAF_YUV_SUBSPACE))
10185  isubspace = weed_layer_get_yuv_subspace(layer);
10186  else isubspace = WEED_YUV_SUBSPACE_YUV;
10187 
10188  width = weed_layer_get_width(layer);
10189  height = weed_layer_get_height(layer);
10190 
10191  // #define DEBUG_PCONV
10192 #ifdef DEBUG_PCONV
10193  g_print("converting %d X %d palette %s(%s) to %s(%s)\n", width, height, weed_palette_get_name(inpl),
10194  weed_yuv_clamping_get_name(iclamping),
10195  weed_palette_get_name(outpl),
10196  weed_yuv_clamping_get_name(oclamping));
10197 #endif
10198 
10199  istrides = weed_layer_get_rowstrides(layer, &nplanes);
10200  if (!istrides) return FALSE;
10201 
10202  if (weed_palette_is_yuv(inpl) && weed_palette_is_yuv(outpl) && (iclamping != oclamping || isubspace != osubspace)) {
10203  if (isubspace == osubspace) {
10204 #ifdef DEBUG_PCONV
10205  lives_printerr("converting clamping %d to %d\n", iclamping, oclamping);
10206 #endif
10207  switch_yuv_clamping_and_subspace(layer, oclamping, osubspace);
10208  iclamping = oclamping;
10209  } else {
10210  // convert first to RGB(A)
10211  if (weed_palette_has_alpha(inpl)) {
10212  if (!convert_layer_palette(layer, WEED_PALETTE_RGBA32, 0)) goto memfail;
10213  } else {
10214  if (!convert_layer_palette(layer, WEED_PALETTE_RGB24, 0)) goto memfail;
10215  }
10216  inpl = weed_layer_get_palette(layer);
10217  isubspace = osubspace;
10218  isampling = osampling;
10219  iclamping = oclamping;
10220 #ifdef DEBUG_PCONV
10221  g_print("subspace conversion via palette %s\n", weed_palette_get_name(inpl));
10222 #endif
10223  }
10224  }
10225 
10226  if (inpl == outpl) {
10227 #ifdef DEBUG_PCONV
10228  lives_printerr("not converting palette\n");
10229 #endif
10230  if (!weed_palette_is_yuv(inpl) || (isampling == osampling &&
10231  (isubspace == osubspace || (osubspace != WEED_YUV_SUBSPACE_BT709)))) {
10232  if (inpl == WEED_PALETTE_YUV420P && ((isampling == WEED_YUV_SAMPLING_JPEG
10233  && osampling == WEED_YUV_SAMPLING_MPEG) ||
10234  (isampling == WEED_YUV_SAMPLING_MPEG && osampling == WEED_YUV_SAMPLING_JPEG))) {
10235  switch_yuv_sampling(layer);
10236  } else {
10237  char *tmp2 = lives_strdup_printf("Switch sampling types (%d %d) or subspace(%d %d): (%d) conversion not yet written !\n",
10238  isampling, osampling, isubspace, osubspace, inpl);
10239  LIVES_DEBUG(tmp2);
10240  lives_free(tmp2);
10241  lives_free(istrides);
10242  return TRUE;
10243  }
10244  }
10245  }
10246 
10247  flags = weed_layer_get_flags(layer);
10248 
10249  if (prefs->alpha_post) {
10250  if ((flags & WEED_LAYER_ALPHA_PREMULT) &&
10251  (weed_palette_has_alpha(inpl) && !(weed_palette_has_alpha(outpl)))) {
10252  // if we have pre-multiplied alpha, remove it when removing alpha channel
10253  alpha_unpremult(layer, TRUE);
10254  }
10255  } else {
10256  if (!weed_palette_has_alpha(inpl) && weed_palette_has_alpha(outpl)) {
10257  flags |= WEED_LAYER_ALPHA_PREMULT;
10258  weed_set_int_value(layer, WEED_LEAF_FLAGS, flags);
10259  }
10260  }
10261 
10262  if (weed_palette_has_alpha(inpl) && !(weed_palette_has_alpha(outpl)) && (flags & WEED_LAYER_ALPHA_PREMULT)) {
10263  flags ^= WEED_LAYER_ALPHA_PREMULT;
10264  if (flags == 0) weed_leaf_delete(layer, WEED_LEAF_FLAGS);
10265  else weed_set_int_value(layer, WEED_LEAF_FLAGS, flags);
10266  }
10267 
10268  if (weed_get_boolean_value(layer, WEED_LEAF_HOST_PIXEL_DATA_CONTIGUOUS, &error) == WEED_TRUE)
10269  contig = TRUE;
10270 
10271  width = weed_layer_get_width(layer);
10272  height = weed_layer_get_height(layer);
10273 
10274  if (prefs->apply_gamma) {
10275  // gamma correction
10276  if (tgamma != WEED_GAMMA_UNKNOWN) {
10277  new_gamma_type = tgamma;
10278  } else {
10279  if (weed_palette_is_rgb(inpl) && !weed_palette_is_rgb(outpl)) {
10280  // gamma correction
10281  if (osubspace == WEED_YUV_SUBSPACE_BT709) {
10282  new_gamma_type = WEED_GAMMA_BT709;
10283  } else new_gamma_type = WEED_GAMMA_SRGB;
10284  } else new_gamma_type = weed_layer_get_gamma(layer);
10285  }
10286  if (weed_palette_is_rgb(inpl) && !weed_palette_is_rgb(outpl)) {
10287  if (!can_inline_gamma(inpl, outpl)) {
10288  gamma_convert_layer(new_gamma_type, layer);
10289  new_gamma_type = WEED_GAMMA_UNKNOWN;
10290  }
10291  }
10292  }
10293 
10294  lives_free(istrides);
10295  istrides = weed_layer_get_rowstrides(layer, &nplanes);
10296  if (!istrides) return FALSE;
10297 
10298  irowstride = istrides[0];
10299  weed_layer_set_palette(layer, outpl);
10301  / weed_palette_get_pixels_per_macropixel(outpl), height);
10302  // TODO: rowstrides for uyvy, yuyv, 422P, 411
10303 
10305 #ifdef WEED_ADVANCED_PALETTES
10306  if (!weed_palette_is_sane(inpl) || !weed_palette_is_sane(outpl)) {
10307  if (!weed_palette_is_sane(outpl)) g_print("BAD pal %d\n", outpl);
10308  if (!weed_palette_is_sane(inpl)) g_print("BAD pal %d\n", inpl);
10309  return FALSE;
10310  }
10311  if (get_advanced_palette(inpl)->chantype[1] == WEED_VCHAN_V) swap_chroma_planes(layer);
10312 #else
10313  if (inpl == WEED_PALETTE_YVU420P) swap_chroma_planes(layer);
10314 #endif
10315 
10316  orig_layer = weed_layer_new(WEED_LAYER_TYPE_VIDEO);
10317  weed_layer_copy(orig_layer, layer);
10318 
10319 #ifdef WEED_ADVANCED_PALETTES
10320  if (weed_palette_is_rgb(inpl) && weed_palette_is_rgb(outpl)) {
10321  gusrc = weed_layer_get_pixel_data_packed(layer);
10322  if (!weed_palette_has_alpha_first(inpl)) {
10323  if (!weed_palette_has_alpha_last(inpl)) {
10324  if (!weed_palette_has_alpha_first(outpl)) {
10325  if (!weed_palette_has_alpha_last(outpl)) {
10326  convert_swap3_frame(gusrc, width, height, irowstride, irowstride, gusrc,
10327  create_gamma_lut(1.0, weed_layer_get_gamma(layer), new_gamma_type),
10328  -USE_THREADS);
10329  weed_layer_nullify_pixel_data(orig_layer);
10330  } else {
10331  // add post
10332  if (weed_palettes_rbswapped(inpl, outpl)) {
10333  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10334  orowstride = weed_layer_get_rowstride(layer);
10335  gudest = weed_layer_get_pixel_data_packed(layer);
10336  convert_swap3addpost_frame(gusrc, width, height, irowstride, orowstride, gudest,
10337  -USE_THREADS);
10338  } else {
10339  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10340  orowstride = weed_layer_get_rowstride(layer);
10341  gudest = weed_layer_get_pixel_data_packed(layer);
10342  convert_addpost_frame(gusrc, width, height, irowstride, orowstride, gudest,
10343  create_gamma_lut(1.0, weed_layer_get_gamma(layer), new_gamma_type),
10344  -USE_THREADS);
10345  }
10346  }
10347  } else {
10349  if (weed_palettes_rbswapped(inpl, outpl)) {
10350  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10351  orowstride = weed_layer_get_rowstride(layer);
10352  gudest = weed_layer_get_pixel_data_packed(layer);
10353  convert_swap3addpre_frame(gusrc, width, height, irowstride, orowstride, gudest,
10354  -USE_THREADS);
10355  } else {
10356  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10357  orowstride = weed_layer_get_rowstride(layer);
10358  gudest = weed_layer_get_pixel_data_packed(layer);
10359  convert_addpre_frame(gusrc, width, height, irowstride, orowstride, gudest, -USE_THREADS);
10360  }
10361  }
10362  } else {
10364  if (!weed_palette_has_alpha_first(outpl)) {
10365  if (!weed_palette_has_alpha_last(outpl)) {
10366  if (weed_palettes_rbswapped(inpl, outpl)) {
10367  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10368  orowstride = weed_layer_get_rowstride(layer);
10369  gudest = weed_layer_get_pixel_data_packed(layer);
10370  convert_swap3delpost_frame(gusrc, width, height, irowstride, orowstride, gudest,
10371  -USE_THREADS);
10372  } else {
10373  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10374  orowstride = weed_layer_get_rowstride(layer);
10375  gudest = weed_layer_get_pixel_data_packed(layer);
10376  convert_delpost_frame(gusrc, width, height, irowstride, orowstride, gudest,
10377  create_gamma_lut(1.0, weed_layer_get_gamma(layer), new_gamma_type),
10378  -USE_THREADS);
10379  }
10380  } else {
10382  convert_swap3postalpha_frame(gusrc, width, height, irowstride, -USE_THREADS);
10383  weed_layer_nullify_pixel_data(orig_layer);
10384  }
10385  } else {
10387  if (weed_palettes_rbswapped(inpl, outpl)) {
10388  convert_swap4_frame(gusrc, width, height, irowstride, irowstride, gusrc, -USE_THREADS);
10389  weed_layer_nullify_pixel_data(orig_layer);
10390  } else {
10391  convert_swapprepost_frame(gusrc, width, height, irowstride, irowstride, gusrc,
10392  -USE_THREADS);
10393  weed_layer_nullify_pixel_data(orig_layer);
10394  }
10395  }
10396  }
10397  } else {
10398  // inpl has pre
10399  if (!weed_palette_has_alpha_first(outpl)) {
10400  if (!weed_palette_has_alpha_last(outpl)) {
10401  if (weed_palettes_rbswapped(inpl, outpl)) {
10402  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10403  orowstride = weed_layer_get_rowstride(layer);
10404  gudest = weed_layer_get_pixel_data_packed(layer);
10405  convert_swap3delpre_frame(gusrc, width, height, irowstride, orowstride, gudest,
10406  -USE_THREADS);
10407  } else {
10408  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10409  orowstride = weed_layer_get_rowstride(layer);
10410  gudest = weed_layer_get_pixel_data_packed(layer);
10411  convert_delpre_frame(gusrc, width, height, irowstride, orowstride, gudest, -USE_THREADS);
10412  }
10413  } else {
10415  if (weed_palettes_rbswapped(inpl, outpl)) {
10416  convert_swap4_frame(gusrc, width, height, irowstride, irowstride, gusrc, -USE_THREADS);
10417  weed_layer_nullify_pixel_data(orig_layer);
10418  } else {
10419  convert_swapprepost_frame(gusrc, width, height, irowstride, irowstride, gusrc,
10420  -USE_THREADS);
10421  weed_layer_nullify_pixel_data(orig_layer);
10422  }
10423  }
10424  } else {
10426  convert_swap3prealpha_frame(gusrc, width, height, irowstride, -USE_THREADS);
10427  weed_layer_nullify_pixel_data(orig_layer);
10428  }
10429  }
10430  goto conv_done;
10431  }
10432 #endif
10433 
10434  switch (inpl) {
10435  case WEED_PALETTE_BGR24:
10436  gusrc = weed_layer_get_pixel_data_packed(layer);
10437  switch (outpl) {
10438  case WEED_PALETTE_RGBA32:
10439  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10440  orowstride = weed_layer_get_rowstride(layer);
10441  gudest = weed_layer_get_pixel_data_packed(layer);
10442  convert_swap3addpost_frame(gusrc, width, height, irowstride, orowstride, gudest, -USE_THREADS);
10443  break;
10444  case WEED_PALETTE_RGB24:
10445  convert_swap3_frame(gusrc, width, height, irowstride, irowstride, gusrc,
10446  create_gamma_lut(1.0, weed_layer_get_gamma(layer), new_gamma_type),
10447  -USE_THREADS);
10448  weed_layer_nullify_pixel_data(orig_layer);
10449  break;
10450  case WEED_PALETTE_BGRA32:
10451  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10452  orowstride = weed_layer_get_rowstride(layer);
10453  gudest = weed_layer_get_pixel_data_packed(layer);
10454  convert_addpost_frame(gusrc, width, height, irowstride, orowstride, gudest,
10455  create_gamma_lut(1.0, weed_layer_get_gamma(layer), new_gamma_type),
10456  -USE_THREADS);
10457  break;
10458  case WEED_PALETTE_ARGB32:
10459  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10460  orowstride = weed_layer_get_rowstride(layer);
10461  gudest = weed_layer_get_pixel_data_packed(layer);
10462  convert_swap3addpre_frame(gusrc, width, height, irowstride, orowstride, gudest, -USE_THREADS);
10463  break;
10464  case WEED_PALETTE_UYVY8888:
10465  weed_set_int_value(layer, WEED_LEAF_WIDTH, width >> 1);
10466  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10467  orowstride = weed_layer_get_rowstride(layer);
10468  gudest = weed_layer_get_pixel_data_packed(layer);
10469  convert_bgr_to_uyvy_frame(gusrc, width, height, irowstride, orowstride,
10470  (uyvy_macropixel *)gudest, FALSE, oclamping,
10471  create_gamma_lut(1.0, weed_layer_get_gamma(layer), new_gamma_type),
10472  -USE_THREADS);
10473  break;
10474  case WEED_PALETTE_YUYV8888:
10475  weed_set_int_value(layer, WEED_LEAF_WIDTH, width >> 1);
10476  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10477  orowstride = weed_layer_get_rowstride(layer);
10478  gudest = weed_layer_get_pixel_data_packed(layer);
10479  convert_bgr_to_yuyv_frame(gusrc, width, height, irowstride, orowstride,
10480  (yuyv_macropixel *)gudest, FALSE, oclamping,
10481  create_gamma_lut(1.0, weed_layer_get_gamma(layer), new_gamma_type),
10482  -USE_THREADS);
10483  break;
10484  case WEED_PALETTE_YUV888:
10485  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10486  gudest = weed_layer_get_pixel_data_packed(layer);
10487  orowstride = weed_layer_get_rowstride(layer);
10488  convert_bgr_to_yuv_frame(gusrc, width, height, irowstride, orowstride, gudest, FALSE, FALSE,
10489  oclamping, -USE_THREADS);
10490  break;
10491  case WEED_PALETTE_YUVA8888:
10492  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10493  gudest = weed_layer_get_pixel_data_packed(layer);
10494  orowstride = weed_layer_get_rowstride(layer);
10495  convert_bgr_to_yuv_frame(gusrc, width, height, irowstride, orowstride, gudest, FALSE, TRUE,
10496  oclamping, -USE_THREADS);
10497  break;
10498  case WEED_PALETTE_YUV422P:
10499  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10500  gudest_array = (uint8_t **)weed_get_voidptr_array(layer, WEED_LEAF_PIXEL_DATA, &error);
10501  ostrides = weed_layer_get_rowstrides(layer, NULL);
10502  convert_bgr_to_yuv420_frame(gusrc, width, height, irowstride, ostrides, gudest_array, TRUE,
10503  FALSE, WEED_YUV_SAMPLING_DEFAULT, oclamping);
10504  weed_set_int_value(layer, WEED_LEAF_YUV_SAMPLING, WEED_YUV_SAMPLING_DEFAULT);
10505  break;
10506  case WEED_PALETTE_YVU420P:
10507  case WEED_PALETTE_YUV420P:
10508  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10509  gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
10510  ostrides = weed_layer_get_rowstrides(layer, NULL);
10511  convert_bgr_to_yuv420_frame(gusrc, width, height, irowstride, ostrides, gudest_array, FALSE,
10512  FALSE, osubspace, oclamping);
10513  weed_set_int_value(layer, WEED_LEAF_YUV_SAMPLING, WEED_YUV_SAMPLING_DEFAULT);
10514  break;
10515  case WEED_PALETTE_YUV444P:
10516  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10517  gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
10518  orowstride = weed_layer_get_rowstride(layer);
10519  convert_bgr_to_yuvp_frame(gusrc, width, height, irowstride, orowstride, gudest_array, FALSE,
10520  FALSE, oclamping, -USE_THREADS);
10521  break;
10522  case WEED_PALETTE_YUVA4444P:
10523  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10524  gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
10525  orowstride = weed_layer_get_rowstride(layer);
10526  convert_bgr_to_yuvp_frame(gusrc, width, height, irowstride, orowstride, gudest_array, FALSE,
10527  TRUE, oclamping, -USE_THREADS);
10528  break;
10529  case WEED_PALETTE_YUV411:
10530  weed_set_int_value(layer, WEED_LEAF_WIDTH, width >> 2);
10531  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10532  gudest = weed_layer_get_pixel_data_packed(layer);
10533  convert_bgr_to_yuv411_frame(gusrc, width, height, irowstride, (yuv411_macropixel *)gudest,
10534  FALSE, oclamping);
10535  break;
10536  default:
10537  lives_printerr("Invalid palette conversion: %s to %s not written yet !!\n",
10538  weed_palette_get_name(inpl),
10539  weed_palette_get_name(outpl));
10540  goto memfail;
10541  }
10542  break;
10543  case WEED_PALETTE_RGBA32:
10544  gusrc = weed_layer_get_pixel_data_packed(layer);
10545  switch (outpl) {
10546  case WEED_PALETTE_BGR24:
10547  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10548  orowstride = weed_layer_get_rowstride(layer);
10549  gudest = weed_layer_get_pixel_data_packed(layer);
10550  convert_swap3delpost_frame(gusrc, width, height, irowstride, orowstride, gudest, -USE_THREADS);
10551  break;
10552  case WEED_PALETTE_RGB24:
10553  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10554  orowstride = weed_layer_get_rowstride(layer);
10555  gudest = weed_layer_get_pixel_data_packed(layer);
10556  convert_delpost_frame(gusrc, width, height, irowstride, orowstride, gudest,
10557  create_gamma_lut(1.0, weed_layer_get_gamma(layer), new_gamma_type),
10558  -USE_THREADS);
10559  break;
10560  case WEED_PALETTE_BGRA32:
10561  convert_swap3postalpha_frame(gusrc, width, height, irowstride, -USE_THREADS);
10562  weed_layer_nullify_pixel_data(orig_layer);
10563  break;
10564  case WEED_PALETTE_ARGB32:
10565  convert_swapprepost_frame(gusrc, width, height, irowstride, irowstride, gusrc, -USE_THREADS);
10566  weed_layer_nullify_pixel_data(orig_layer);
10567  break;
10568  case WEED_PALETTE_UYVY8888:
10569  weed_set_int_value(layer, WEED_LEAF_WIDTH, width >> 1);
10570  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10571  orowstride = weed_layer_get_rowstride(layer);
10572  gudest = weed_layer_get_pixel_data_packed(layer);
10573  convert_rgb_to_uyvy_frame(gusrc, width, height, irowstride, orowstride, (uyvy_macropixel *)gudest, TRUE,
10574  oclamping, create_gamma_lut(1.0, weed_layer_get_gamma(layer), new_gamma_type), -USE_THREADS);
10575  break;
10576  case WEED_PALETTE_YUYV8888:
10577  weed_set_int_value(layer, WEED_LEAF_WIDTH, width >> 1);
10578  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10579  orowstride = weed_layer_get_rowstride(layer);
10580  gudest = weed_layer_get_pixel_data_packed(layer);
10581  convert_rgb_to_yuyv_frame(gusrc, width, height, irowstride, orowstride, (yuyv_macropixel *)gudest, TRUE,
10582  oclamping,
10583  create_gamma_lut(1.0, weed_layer_get_gamma(layer), new_gamma_type),
10584  -USE_THREADS);
10585  break;
10586  case WEED_PALETTE_YUV888:
10587  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10588  gudest = weed_layer_get_pixel_data_packed(layer);
10589  orowstride = weed_layer_get_rowstride(layer);
10590  convert_rgb_to_yuv_frame(gusrc, width, height, irowstride, orowstride, gudest, TRUE, FALSE, oclamping, -USE_THREADS);
10591  break;
10592  case WEED_PALETTE_YUVA8888:
10593  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10594  gudest = weed_layer_get_pixel_data_packed(layer);
10595  orowstride = weed_layer_get_rowstride(layer);
10596  convert_rgb_to_yuv_frame(gusrc, width, height, irowstride, orowstride, gudest, TRUE, TRUE, oclamping, -USE_THREADS);
10597  break;
10598  case WEED_PALETTE_YUV422P:
10599  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10600  gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
10601  ostrides = weed_layer_get_rowstrides(layer, NULL);
10602  convert_rgb_to_yuv420_frame(gusrc, width, height, irowstride, ostrides, gudest_array, TRUE, TRUE,
10603  WEED_YUV_SAMPLING_DEFAULT, oclamping);
10604  weed_set_int_value(layer, WEED_LEAF_YUV_SAMPLING, WEED_YUV_SAMPLING_DEFAULT);
10605  break;
10606  case WEED_PALETTE_YUV420P:
10607  case WEED_PALETTE_YVU420P:
10608  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10609  gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
10610  ostrides = weed_layer_get_rowstrides(layer, NULL);
10611  convert_rgb_to_yuv420_frame(gusrc, width, height, irowstride, ostrides, gudest_array, FALSE, TRUE, osubspace, oclamping);
10612  weed_set_int_value(layer, WEED_LEAF_YUV_SAMPLING, WEED_YUV_SAMPLING_DEFAULT);
10613  break;
10614  case WEED_PALETTE_YUV444P:
10615  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10616  gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
10617  orowstride = weed_layer_get_rowstride(layer);
10618  convert_rgb_to_yuvp_frame(gusrc, width, height, irowstride, orowstride, gudest_array, TRUE, FALSE, oclamping, -USE_THREADS);
10619  break;
10620  case WEED_PALETTE_YUVA4444P:
10621  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10622  gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
10623  orowstride = weed_layer_get_rowstride(layer);
10624  convert_rgb_to_yuvp_frame(gusrc, width, height, irowstride, orowstride, gudest_array, TRUE, TRUE, oclamping, -USE_THREADS);
10625  break;
10626  case WEED_PALETTE_YUV411:
10627  weed_set_int_value(layer, WEED_LEAF_WIDTH, width >> 2);
10628  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10629  gudest = weed_layer_get_pixel_data_packed(layer);
10630  convert_rgb_to_yuv411_frame(gusrc, width, height, irowstride, (yuv411_macropixel *)gudest, TRUE, oclamping);
10631  break;
10632  default:
10633  lives_printerr("Invalid palette conversion: %s to %s not written yet !!\n", weed_palette_get_name(inpl),
10634  weed_palette_get_name(outpl));
10635  goto memfail;
10636  }
10637  break;
10638  case WEED_PALETTE_RGB24:
10639  gusrc = weed_layer_get_pixel_data_packed(layer);
10640  switch (outpl) {
10641  case WEED_PALETTE_BGR24:
10642  convert_swap3_frame(gusrc, width, height, irowstride, irowstride, gusrc,
10643  create_gamma_lut(1.0, weed_layer_get_gamma(layer), new_gamma_type), -USE_THREADS);
10644  weed_layer_nullify_pixel_data(orig_layer);
10645  break;
10646  case WEED_PALETTE_RGBA32:
10647  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10648  orowstride = weed_layer_get_rowstride(layer);
10649  gudest = weed_layer_get_pixel_data_packed(layer);
10650  convert_addpost_frame(gusrc, width, height, irowstride, orowstride, gudest,
10651  create_gamma_lut(1.0, weed_layer_get_gamma(layer), new_gamma_type), -USE_THREADS);
10652  break;
10653  case WEED_PALETTE_BGRA32:
10654  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10655  orowstride = weed_layer_get_rowstride(layer);
10656  gudest = weed_layer_get_pixel_data_packed(layer);
10657  convert_swap3addpost_frame(gusrc, width, height, irowstride, orowstride, gudest, -USE_THREADS);
10658  break;
10659  case WEED_PALETTE_ARGB32:
10660  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10661  orowstride = weed_layer_get_rowstride(layer);
10662  gudest = weed_layer_get_pixel_data_packed(layer);
10663  convert_addpre_frame(gusrc, width, height, irowstride, orowstride, gudest, -USE_THREADS);
10664  break;
10665  case WEED_PALETTE_UYVY8888:
10666  weed_set_int_value(layer, WEED_LEAF_WIDTH, width >> 1);
10667  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10668  orowstride = weed_layer_get_rowstride(layer);
10669  gudest = weed_layer_get_pixel_data_packed(layer);
10670  convert_rgb_to_uyvy_frame(gusrc, width, height, irowstride, orowstride, (uyvy_macropixel *)gudest, FALSE,
10671  oclamping,
10672  create_gamma_lut(1.0, weed_layer_get_gamma(layer), new_gamma_type),
10673  -USE_THREADS);
10674  break;
10675  case WEED_PALETTE_YUYV8888:
10676  weed_set_int_value(layer, WEED_LEAF_WIDTH, width >> 1);
10677  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10678  orowstride = weed_layer_get_rowstride(layer);
10679  gudest = weed_layer_get_pixel_data_packed(layer);
10680  convert_rgb_to_yuyv_frame(gusrc, width, height, irowstride, orowstride, (yuyv_macropixel *)gudest, FALSE,
10681  oclamping,
10682  create_gamma_lut(1.0, weed_layer_get_gamma(layer), new_gamma_type),
10683  -USE_THREADS);
10684  break;
10685  case WEED_PALETTE_YUV888:
10686  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10687  gudest = weed_layer_get_pixel_data_packed(layer);
10688  orowstride = weed_layer_get_rowstride(layer);
10689  convert_rgb_to_yuv_frame(gusrc, width, height, irowstride, orowstride, gudest, FALSE, FALSE, oclamping, -USE_THREADS);
10690  break;
10691  case WEED_PALETTE_YUVA8888:
10692  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10693  gudest = weed_layer_get_pixel_data_packed(layer);
10694  orowstride = weed_layer_get_rowstride(layer);
10695  convert_rgb_to_yuv_frame(gusrc, width, height, irowstride, orowstride, gudest, FALSE, TRUE, oclamping, -USE_THREADS);
10696  break;
10697  case WEED_PALETTE_YUV422P:
10698  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10699  gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
10700  ostrides = weed_layer_get_rowstrides(layer, NULL);
10701  convert_rgb_to_yuv420_frame(gusrc, width, height, irowstride, ostrides, gudest_array, TRUE, FALSE, osubspace, oclamping);
10702  break;
10703  case WEED_PALETTE_YUV420P:
10704  case WEED_PALETTE_YVU420P:
10705  if (weed_get_int_value(layer, WEED_LEAF_PIXEL_BITS, NULL) == 16) width >>= 1;
10706  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10707  gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
10708  ostrides = weed_layer_get_rowstrides(layer, NULL);
10709  if (weed_get_int_value(layer, WEED_LEAF_PIXEL_BITS, NULL) == 16) width = -width;
10710  convert_rgb_to_yuv420_frame(gusrc, width, height, irowstride, ostrides, gudest_array, FALSE,
10711  FALSE, WEED_YUV_SAMPLING_DEFAULT, oclamping);
10712  weed_set_int_value(layer, WEED_LEAF_YUV_SAMPLING, WEED_YUV_SAMPLING_DEFAULT);
10713  break;
10714  case WEED_PALETTE_YUV444P:
10715  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10716  gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
10717  orowstride = weed_layer_get_rowstride(layer);
10718  convert_rgb_to_yuvp_frame(gusrc, width, height, irowstride, orowstride, gudest_array, FALSE, FALSE, oclamping, -USE_THREADS);
10719  break;
10720  case WEED_PALETTE_YUVA4444P:
10721  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10722  gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
10723  orowstride = weed_layer_get_rowstride(layer);
10724  convert_rgb_to_yuvp_frame(gusrc, width, height, irowstride, orowstride, gudest_array, FALSE, TRUE, oclamping, -USE_THREADS);
10725  break;
10726  case WEED_PALETTE_YUV411:
10727  weed_set_int_value(layer, WEED_LEAF_WIDTH, width >> 2);
10728  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10729  gudest = weed_layer_get_pixel_data_packed(layer);
10730  convert_rgb_to_yuv411_frame(gusrc, width, height, irowstride, (yuv411_macropixel *)gudest, FALSE, oclamping);
10731  break;
10732  default:
10733  lives_printerr("Invalid palette conversion: %s to %s not written yet !!\n", weed_palette_get_name(inpl),
10734  weed_palette_get_name(outpl));
10735  goto memfail;
10736  }
10737  break;
10738  case WEED_PALETTE_BGRA32:
10739  gusrc = weed_layer_get_pixel_data_packed(layer);
10740  switch (outpl) {
10741  case WEED_PALETTE_BGR24:
10742  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10743  orowstride = weed_layer_get_rowstride(layer);
10744  gudest = weed_layer_get_pixel_data_packed(layer);
10745  convert_delpost_frame(gusrc, width, height, irowstride, orowstride, gudest,
10746  create_gamma_lut(1.0, weed_layer_get_gamma(layer), new_gamma_type), -USE_THREADS);
10747  break;
10748  case WEED_PALETTE_RGB24:
10749  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10750  orowstride = weed_layer_get_rowstride(layer);
10751  gudest = weed_layer_get_pixel_data_packed(layer);
10752  convert_swap3delpost_frame(gusrc, width, height, irowstride, orowstride, gudest, -USE_THREADS);
10753  break;
10754  case WEED_PALETTE_RGBA32:
10755  convert_swap3postalpha_frame(gusrc, width, height, irowstride, -USE_THREADS);
10756  weed_layer_nullify_pixel_data(orig_layer);
10757  break;
10758  case WEED_PALETTE_ARGB32:
10759  convert_swap4_frame(gusrc, width, height, irowstride, irowstride, gusrc, -USE_THREADS);
10760  weed_layer_nullify_pixel_data(orig_layer);
10761  break;
10762  case WEED_PALETTE_UYVY8888:
10763  weed_set_int_value(layer, WEED_LEAF_WIDTH, width >> 1);
10764  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10765  orowstride = weed_layer_get_rowstride(layer);
10766  gudest = weed_layer_get_pixel_data_packed(layer);
10767  convert_bgr_to_uyvy_frame(gusrc, width, height, irowstride, orowstride, (uyvy_macropixel *)gudest, TRUE,
10768  oclamping,
10769  create_gamma_lut(1.0, weed_layer_get_gamma(layer), new_gamma_type),
10770  -USE_THREADS);
10771  break;
10772  case WEED_PALETTE_YUYV8888:
10773  weed_set_int_value(layer, WEED_LEAF_WIDTH, width >> 1);
10774  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10775  orowstride = weed_layer_get_rowstride(layer);
10776  gudest = weed_layer_get_pixel_data_packed(layer);
10777  convert_bgr_to_yuyv_frame(gusrc, width, height, irowstride, orowstride, (yuyv_macropixel *)gudest, TRUE,
10778  oclamping,
10779  create_gamma_lut(1.0, weed_layer_get_gamma(layer), new_gamma_type),
10780  -USE_THREADS);
10781  break;
10782  case WEED_PALETTE_YUV888:
10783  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10784  gudest = weed_layer_get_pixel_data_packed(layer);
10785  orowstride = weed_layer_get_rowstride(layer);
10786  convert_bgr_to_yuv_frame(gusrc, width, height, irowstride, orowstride, gudest, TRUE, FALSE, oclamping, -USE_THREADS);
10787  break;
10788  case WEED_PALETTE_YUVA8888:
10789  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10790  gudest = weed_layer_get_pixel_data_packed(layer);
10791  orowstride = weed_layer_get_rowstride(layer);
10792  convert_bgr_to_yuv_frame(gusrc, width, height, irowstride, orowstride, gudest, TRUE, TRUE, oclamping, -USE_THREADS);
10793  break;
10794  case WEED_PALETTE_YUV422P:
10795  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10796  gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
10797  ostrides = weed_layer_get_rowstrides(layer, NULL);
10798  convert_bgr_to_yuv420_frame(gusrc, width, height, irowstride, ostrides, gudest_array, TRUE, TRUE,
10799  WEED_YUV_SAMPLING_DEFAULT, oclamping);
10800  weed_set_int_value(layer, WEED_LEAF_YUV_SAMPLING, WEED_YUV_SAMPLING_DEFAULT);
10801  break;
10802  case WEED_PALETTE_YVU420P:
10803  case WEED_PALETTE_YUV420P:
10804  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10805  gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
10806  ostrides = weed_layer_get_rowstrides(layer, NULL);
10807  convert_bgr_to_yuv420_frame(gusrc, width, height, irowstride, ostrides, gudest_array, FALSE, TRUE, osubspace, oclamping);
10808  weed_set_int_value(layer, WEED_LEAF_YUV_SAMPLING, WEED_YUV_SAMPLING_DEFAULT);
10809  break;
10810  case WEED_PALETTE_YUV444P:
10811  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10812  gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
10813  orowstride = weed_layer_get_rowstride(layer);
10814  convert_bgr_to_yuvp_frame(gusrc, width, height, irowstride, orowstride, gudest_array, TRUE, FALSE, oclamping, -USE_THREADS);
10815  break;
10816  case WEED_PALETTE_YUVA4444P:
10817  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10818  gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
10819  orowstride = weed_layer_get_rowstride(layer);
10820  convert_bgr_to_yuvp_frame(gusrc, width, height, irowstride, orowstride, gudest_array, TRUE, TRUE, oclamping, -USE_THREADS);
10821  break;
10822  case WEED_PALETTE_YUV411:
10823  weed_set_int_value(layer, WEED_LEAF_WIDTH, width >> 2);
10824  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10825  gudest = weed_layer_get_pixel_data_packed(layer);
10826  convert_bgr_to_yuv411_frame(gusrc, width, height, irowstride, (yuv411_macropixel *)gudest, TRUE, oclamping);
10827  break;
10828  default:
10829  lives_printerr("Invalid palette conversion: %s to %s not written yet !!\n", weed_palette_get_name(inpl),
10830  weed_palette_get_name(outpl));
10831  goto memfail;
10832  }
10833  break;
10834  case WEED_PALETTE_ARGB32:
10835  gusrc = weed_layer_get_pixel_data_packed(layer);
10836  switch (outpl) {
10837  case WEED_PALETTE_BGR24:
10838  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10839  orowstride = weed_layer_get_rowstride(layer);
10840  gudest = weed_layer_get_pixel_data_packed(layer);
10841  convert_swap3delpre_frame(gusrc, width, height, irowstride, orowstride, gudest, -USE_THREADS);
10842  break;
10843  case WEED_PALETTE_RGB24:
10844  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10845  orowstride = weed_layer_get_rowstride(layer);
10846  gudest = weed_layer_get_pixel_data_packed(layer);
10847  convert_delpre_frame(gusrc, width, height, irowstride, orowstride, gudest, -USE_THREADS);
10848  break;
10849  case WEED_PALETTE_RGBA32:
10850  convert_swapprepost_frame(gusrc, width, height, irowstride, irowstride, gusrc, -USE_THREADS);
10851  weed_layer_nullify_pixel_data(orig_layer);
10852  break;
10853  case WEED_PALETTE_BGRA32:
10854  convert_swap4_frame(gusrc, width, height, irowstride, irowstride, gusrc, -USE_THREADS);
10855  weed_layer_nullify_pixel_data(orig_layer);
10856  break;
10857  case WEED_PALETTE_UYVY8888:
10858  weed_set_int_value(layer, WEED_LEAF_WIDTH, width >> 1);
10859  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10860  orowstride = weed_layer_get_rowstride(layer);
10861  gudest = weed_layer_get_pixel_data_packed(layer);
10862  convert_argb_to_uyvy_frame(gusrc, width, height, irowstride, orowstride, (uyvy_macropixel *)gudest, oclamping,
10863  create_gamma_lut(1.0, weed_layer_get_gamma(layer), new_gamma_type),
10864  -USE_THREADS);
10865  break;
10866  case WEED_PALETTE_YUYV8888:
10867  weed_set_int_value(layer, WEED_LEAF_WIDTH, width >> 1);
10868  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10869  orowstride = weed_layer_get_rowstride(layer);
10870  gudest = weed_layer_get_pixel_data_packed(layer);
10871  convert_argb_to_yuyv_frame(gusrc, width, height, irowstride, orowstride, (yuyv_macropixel *)gudest, oclamping,
10872  create_gamma_lut(1.0, weed_layer_get_gamma(layer), new_gamma_type),
10873  -USE_THREADS);
10874  break;
10875  case WEED_PALETTE_YUV888:
10876  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10877  gudest = weed_layer_get_pixel_data_packed(layer);
10878  orowstride = weed_layer_get_rowstride(layer);
10879  convert_argb_to_yuv_frame(gusrc, width, height, irowstride, orowstride, gudest, FALSE, oclamping, -USE_THREADS);
10880  break;
10881  case WEED_PALETTE_YUVA8888:
10882  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10883  gudest = weed_layer_get_pixel_data_packed(layer);
10884  orowstride = weed_layer_get_rowstride(layer);
10885  convert_argb_to_yuv_frame(gusrc, width, height, irowstride, orowstride, gudest, TRUE, oclamping, -USE_THREADS);
10886  break;
10887  case WEED_PALETTE_YUV444P:
10888  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10889  gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
10890  orowstride = weed_layer_get_rowstride(layer);
10891  convert_argb_to_yuvp_frame(gusrc, width, height, irowstride, orowstride, gudest_array, FALSE, oclamping, -USE_THREADS);
10892  break;
10893  case WEED_PALETTE_YUVA4444P:
10894  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10895  gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
10896  orowstride = weed_layer_get_rowstride(layer);
10897  convert_argb_to_yuvp_frame(gusrc, width, height, irowstride, orowstride, gudest_array, TRUE, oclamping, -USE_THREADS);
10898  break;
10899  case WEED_PALETTE_YUV422P:
10900  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10901  gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
10902  ostrides = weed_layer_get_rowstrides(layer, NULL);
10903  convert_argb_to_yuv420_frame(gusrc, width, height, irowstride, ostrides, gudest_array, TRUE,
10904  WEED_YUV_SAMPLING_DEFAULT, oclamping);
10905  weed_set_int_value(layer, WEED_LEAF_YUV_SAMPLING, WEED_YUV_SAMPLING_DEFAULT);
10906  break;
10907  case WEED_PALETTE_YUV420P:
10908  case WEED_PALETTE_YVU420P:
10909  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10910  gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
10911  ostrides = weed_layer_get_rowstrides(layer, NULL);
10912  convert_argb_to_yuv420_frame(gusrc, width, height, irowstride, ostrides, gudest_array, FALSE, osubspace, oclamping);
10913  weed_set_int_value(layer, WEED_LEAF_YUV_SAMPLING, WEED_YUV_SAMPLING_DEFAULT);
10914  break;
10915  case WEED_PALETTE_YUV411:
10916  weed_set_int_value(layer, WEED_LEAF_WIDTH, width >> 2);
10917  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10918  gudest = weed_layer_get_pixel_data_packed(layer);
10919  convert_argb_to_yuv411_frame(gusrc, width, height, irowstride, (yuv411_macropixel *)gudest, oclamping);
10920  break;
10921  default:
10922  lives_printerr("Invalid palette conversion: %s to %s not written yet !!\n", weed_palette_get_name(inpl),
10923  weed_palette_get_name(outpl));
10924  goto memfail;
10925  }
10926  break;
10927  case WEED_PALETTE_YUV444P:
10928  gusrc_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
10929  switch (outpl) {
10930  case WEED_PALETTE_YUV422P:
10931  if (!create_empty_pixel_data(layer, FALSE, FALSE)) goto memfail;
10932  gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
10933  lives_free(gudest_array[0]);
10934  gudest_array[0] = gusrc_array[0];
10935  weed_set_voidptr_array(layer, WEED_LEAF_PIXEL_DATA, 3, (void **)gudest_array);
10936  ostrides = weed_layer_get_rowstrides(layer, NULL);
10937  convert_halve_chroma(gusrc_array, width, height, istrides, ostrides, gudest_array, iclamping);
10938  gusrc_array[0] = NULL;
10939  weed_layer_set_pixel_data(orig_layer, (void **)gusrc_array, 3);
10940  break;
10941  case WEED_PALETTE_RGB24:
10942  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10943  orowstride = weed_layer_get_rowstride(layer);
10944  gudest = weed_layer_get_pixel_data_packed(layer);
10945  convert_yuv_planar_to_rgb_frame(gusrc_array, width, height, irowstride, orowstride, gudest, FALSE, FALSE, iclamping,
10946  -USE_THREADS);
10947  break;
10948  case WEED_PALETTE_RGBA32:
10949  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10950  orowstride = weed_layer_get_rowstride(layer);
10951  gudest = weed_layer_get_pixel_data_packed(layer);
10952  convert_yuv_planar_to_rgb_frame(gusrc_array, width, height, irowstride, orowstride, gudest, FALSE, TRUE, iclamping,
10953  -USE_THREADS);
10954  break;
10955  case WEED_PALETTE_BGR24:
10956  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10957  orowstride = weed_layer_get_rowstride(layer);
10958  gudest = weed_layer_get_pixel_data_packed(layer);
10959  convert_yuv_planar_to_bgr_frame(gusrc_array, width, height, irowstride, orowstride, gudest, FALSE, FALSE, iclamping,
10960  -USE_THREADS);
10961  break;
10962  case WEED_PALETTE_BGRA32:
10963  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10964  orowstride = weed_layer_get_rowstride(layer);
10965  gudest = weed_layer_get_pixel_data_packed(layer);
10966  convert_yuv_planar_to_bgr_frame(gusrc_array, width, height, irowstride, orowstride, gudest, FALSE, TRUE, iclamping,
10967  -USE_THREADS);
10968  break;
10969  case WEED_PALETTE_ARGB32:
10970  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10971  orowstride = weed_layer_get_rowstride(layer);
10972  gudest = weed_layer_get_pixel_data_packed(layer);
10973  convert_yuv_planar_to_argb_frame(gusrc_array, width, height, irowstride, orowstride, gudest, FALSE, iclamping, -USE_THREADS);
10974  break;
10975  case WEED_PALETTE_UYVY8888:
10976  weed_set_int_value(layer, WEED_LEAF_WIDTH, width >> 1);
10977  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10978  orowstride = weed_layer_get_rowstride(layer);
10979  gudest = weed_layer_get_pixel_data_packed(layer);
10980  convert_yuv_planar_to_uyvy_frame(gusrc_array, width, height, irowstride, orowstride, (uyvy_macropixel *)gudest, iclamping);
10981  break;
10982  case WEED_PALETTE_YUYV8888:
10983  weed_set_int_value(layer, WEED_LEAF_WIDTH, width >> 1);
10984  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10985  orowstride = weed_layer_get_rowstride(layer);
10986  gudest = weed_layer_get_pixel_data_packed(layer);
10987  convert_yuv_planar_to_yuyv_frame(gusrc_array, width, height, irowstride, orowstride, (yuyv_macropixel *)gudest, iclamping);
10988  break;
10989  case WEED_PALETTE_YUV888:
10990  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10991  gudest = weed_layer_get_pixel_data_packed(layer);
10992  orowstride = weed_layer_get_rowstride(layer);
10993  convert_combineplanes_frame(gusrc_array, width, height, irowstride, orowstride, gudest, FALSE, FALSE);
10994  break;
10995  case WEED_PALETTE_YUVA8888:
10996  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10997  gudest = weed_layer_get_pixel_data_packed(layer);
10998  orowstride = weed_layer_get_rowstride(layer);
10999  convert_combineplanes_frame(gusrc_array, width, height, irowstride, orowstride, gudest, FALSE, TRUE);
11000  break;
11001  case WEED_PALETTE_YUVA4444P:
11002  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11003  gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
11004  orowstride = weed_layer_get_rowstride(layer);
11005  convert_yuvp_to_yuvap_frame(gusrc_array, width, height, irowstride, orowstride, gudest_array);
11006  break;
11007  case WEED_PALETTE_YUV420P:
11008  case WEED_PALETTE_YVU420P:
11009  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11010  gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
11011  ostrides = weed_layer_get_rowstrides(layer, NULL);
11012  convert_yuvp_to_yuv420_frame(gusrc_array, width, height, istrides, ostrides, gudest_array, iclamping);
11013  weed_set_int_value(layer, WEED_LEAF_YUV_SAMPLING, WEED_YUV_SAMPLING_DEFAULT);
11014  break;
11015  case WEED_PALETTE_YUV411:
11016  weed_set_int_value(layer, WEED_LEAF_WIDTH, width >> 2);
11017  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11018  gudest = weed_layer_get_pixel_data_packed(layer);
11019  convert_yuvp_to_yuv411_frame(gusrc_array, width, height, irowstride, (yuv411_macropixel *)gudest, iclamping);
11020  break;
11021  default:
11022  lives_printerr("Invalid palette conversion: %s to %s not written yet !!\n", weed_palette_get_name(inpl),
11023  weed_palette_get_name(outpl));
11024  goto memfail;
11025  }
11026  break;
11027  case WEED_PALETTE_YUVA4444P:
11028  gusrc_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
11029  switch (outpl) {
11030  case WEED_PALETTE_YUV422P:
11031  if (!create_empty_pixel_data(layer, FALSE, FALSE)) goto memfail;
11032  gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
11033  lives_free(gudest_array[0]);
11034  gudest_array[0] = gusrc_array[0];
11035  weed_set_voidptr_array(layer, WEED_LEAF_PIXEL_DATA, 3, (void **)gudest_array);
11036  ostrides = weed_layer_get_rowstrides(layer, NULL);
11037  convert_halve_chroma(gusrc_array, width, height, istrides, ostrides, gudest_array, iclamping);
11038  gusrc_array[0] = NULL;
11039  weed_layer_set_pixel_data(orig_layer, (void **)gusrc_array, 4);
11040  break;
11041  case WEED_PALETTE_RGB24:
11042  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11043  orowstride = weed_layer_get_rowstride(layer);
11044  gudest = weed_layer_get_pixel_data_packed(layer);
11045  convert_yuv_planar_to_rgb_frame(gusrc_array, width, height, irowstride, orowstride, gudest, TRUE, FALSE, iclamping,
11046  -USE_THREADS);
11047  break;
11048  case WEED_PALETTE_RGBA32:
11049  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11050  orowstride = weed_layer_get_rowstride(layer);
11051  gudest = weed_layer_get_pixel_data_packed(layer);
11052  convert_yuv_planar_to_rgb_frame(gusrc_array, width, height, irowstride, orowstride, gudest, TRUE, TRUE, iclamping,
11053  -USE_THREADS);
11054  break;
11055  case WEED_PALETTE_BGR24:
11056  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11057  orowstride = weed_layer_get_rowstride(layer);
11058  gudest = weed_layer_get_pixel_data_packed(layer);
11059  convert_yuv_planar_to_bgr_frame(gusrc_array, width, height, irowstride, orowstride, gudest, TRUE, FALSE, iclamping,
11060  -USE_THREADS);
11061  break;
11062  case WEED_PALETTE_BGRA32:
11063  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11064  orowstride = weed_layer_get_rowstride(layer);
11065  gudest = weed_layer_get_pixel_data_packed(layer);
11066  convert_yuv_planar_to_bgr_frame(gusrc_array, width, height, irowstride, orowstride, gudest, TRUE, TRUE, iclamping,
11067  -USE_THREADS);
11068  break;
11069  case WEED_PALETTE_ARGB32:
11070  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11071  orowstride = weed_layer_get_rowstride(layer);
11072  gudest = weed_layer_get_pixel_data_packed(layer);
11073  convert_yuv_planar_to_argb_frame(gusrc_array, width, height, irowstride, orowstride, gudest, TRUE, iclamping, -USE_THREADS);
11074  break;
11075  case WEED_PALETTE_UYVY8888:
11076  weed_set_int_value(layer, WEED_LEAF_WIDTH, width >> 1);
11077  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11078  orowstride = weed_layer_get_rowstride(layer);
11079  gudest = weed_layer_get_pixel_data_packed(layer);
11080  convert_yuv_planar_to_uyvy_frame(gusrc_array, width, height, irowstride, orowstride, (uyvy_macropixel *)gudest, iclamping);
11081  break;
11082  case WEED_PALETTE_YUYV8888:
11083  weed_set_int_value(layer, WEED_LEAF_WIDTH, width >> 1);
11084  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11085  orowstride = weed_layer_get_rowstride(layer);
11086  gudest = weed_layer_get_pixel_data_packed(layer);
11087  convert_yuv_planar_to_yuyv_frame(gusrc_array, width, height, irowstride, orowstride, (yuyv_macropixel *)gudest, iclamping);
11088  break;
11089  case WEED_PALETTE_YUV888:
11090  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11091  gudest = weed_layer_get_pixel_data_packed(layer);
11092  orowstride = weed_layer_get_rowstride(layer);
11093  convert_combineplanes_frame(gusrc_array, width, height, irowstride, orowstride, gudest, TRUE, FALSE);
11094  break;
11095  case WEED_PALETTE_YUVA8888:
11096  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11097  gudest = weed_layer_get_pixel_data_packed(layer);
11098  orowstride = weed_layer_get_rowstride(layer);
11099  convert_combineplanes_frame(gusrc_array, width, height, irowstride, orowstride, gudest, TRUE, TRUE);
11100  break;
11101  case WEED_PALETTE_YUV444P:
11102  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11103  gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
11104  orowstride = weed_layer_get_rowstride(layer);
11105  convert_yuvap_to_yuvp_frame(gusrc_array, width, height, irowstride, orowstride, gudest_array);
11106  break;
11107  case WEED_PALETTE_YUV420P:
11108  case WEED_PALETTE_YVU420P:
11109  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11110  gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
11111  ostrides = weed_layer_get_rowstrides(layer, NULL);
11112  convert_yuvp_to_yuv420_frame(gusrc_array, width, height, istrides, ostrides, gudest_array, iclamping);
11113  weed_set_int_value(layer, WEED_LEAF_YUV_SAMPLING, WEED_YUV_SAMPLING_DEFAULT);
11114  break;
11115  case WEED_PALETTE_YUV411:
11116  weed_set_int_value(layer, WEED_LEAF_WIDTH, width >> 2);
11117  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11118  gudest = weed_layer_get_pixel_data_packed(layer);
11119  convert_yuvp_to_yuv411_frame(gusrc_array, width, height, irowstride, (yuv411_macropixel *)gudest, iclamping);
11120  break;
11121  default:
11122  lives_printerr("Invalid palette conversion: %s to %s not written yet !!\n", weed_palette_get_name(inpl),
11123  weed_palette_get_name(outpl));
11124  goto memfail;
11125  }
11126  break;
11127  case WEED_PALETTE_UYVY8888:
11128  gusrc = weed_layer_get_pixel_data_packed(layer);
11129  switch (outpl) {
11130  case WEED_PALETTE_YUYV8888:
11131  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11132  orowstride = weed_layer_get_rowstride(layer);
11133  gudest = weed_layer_get_pixel_data_packed(layer);
11134  convert_swab_frame(gusrc, width, height, irowstride, orowstride, gudest, -USE_THREADS);
11135  break;
11136  case WEED_PALETTE_YUV422P:
11137  weed_set_int_value(layer, WEED_LEAF_WIDTH, width << 1);
11138  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11139  gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
11140  convert_uyvy_to_yuv422_frame((uyvy_macropixel *)gusrc, width, height, gudest_array);
11141  break;
11142  case WEED_PALETTE_RGB24:
11143  //weed_set_int_value(layer, WEED_LEAF_WIDTH, width << 1);
11144  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11145  gudest = weed_layer_get_pixel_data_packed(layer);
11146  orowstride = weed_layer_get_rowstride(layer);
11147  convert_uyvy_to_rgb_frame((uyvy_macropixel *)gusrc, width, height, irowstride, orowstride, gudest,
11148  FALSE, iclamping, isubspace, -USE_THREADS);
11149  break;
11150  case WEED_PALETTE_RGBA32:
11151  weed_set_int_value(layer, WEED_LEAF_WIDTH, width << 1);
11152  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11153  gudest = weed_layer_get_pixel_data_packed(layer);
11154  orowstride = weed_layer_get_rowstride(layer);
11155  convert_uyvy_to_rgb_frame((uyvy_macropixel *)gusrc, width, height, irowstride, orowstride, gudest,
11156  TRUE, iclamping, isampling, -USE_THREADS);
11157  break;
11158  case WEED_PALETTE_BGR24:
11159  weed_set_int_value(layer, WEED_LEAF_WIDTH, width << 1);
11160  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11161  gudest = weed_layer_get_pixel_data_packed(layer);
11162  orowstride = weed_layer_get_rowstride(layer);
11163  convert_uyvy_to_bgr_frame((uyvy_macropixel *)gusrc, width, height, irowstride, orowstride, gudest,
11164  FALSE, iclamping, -USE_THREADS);
11165  break;
11166  case WEED_PALETTE_BGRA32:
11167  weed_set_int_value(layer, WEED_LEAF_WIDTH, width << 1);
11168  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11169  gudest = weed_layer_get_pixel_data_packed(layer);
11170  orowstride = weed_layer_get_rowstride(layer);
11171  convert_uyvy_to_bgr_frame((uyvy_macropixel *)gusrc, width, height, irowstride, orowstride, gudest,
11172  TRUE, iclamping, -USE_THREADS);
11173  break;
11174  case WEED_PALETTE_ARGB32:
11175  weed_set_int_value(layer, WEED_LEAF_WIDTH, width << 1);
11176  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11177  gudest = weed_layer_get_pixel_data_packed(layer);
11178  orowstride = weed_layer_get_rowstride(layer);
11179  convert_uyvy_to_argb_frame((uyvy_macropixel *)gusrc, width, height, irowstride, orowstride,
11180  gudest, iclamping, -USE_THREADS);
11181  break;
11182  case WEED_PALETTE_YUV444P:
11183  weed_set_int_value(layer, WEED_LEAF_WIDTH, width << 1);
11184  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11185  gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
11186  ostrides = weed_layer_get_rowstrides(layer, NULL);
11187  convert_uyvy_to_yuvp_frame((uyvy_macropixel *)gusrc, width, height, irowstride, ostrides, gudest_array, FALSE);
11188  break;
11189  case WEED_PALETTE_YUVA4444P:
11190  weed_set_int_value(layer, WEED_LEAF_WIDTH, width << 1);
11191  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11192  gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
11193  ostrides = weed_layer_get_rowstrides(layer, NULL);
11194  convert_uyvy_to_yuvp_frame((uyvy_macropixel *)gusrc, width, height, irowstride, ostrides, gudest_array, TRUE);
11195  break;
11196  case WEED_PALETTE_YUV888:
11197  weed_set_int_value(layer, WEED_LEAF_WIDTH, width << 1);
11198  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11199  gudest = weed_layer_get_pixel_data_packed(layer);
11200  orowstride = weed_layer_get_rowstride(layer);
11201  convert_uyvy_to_yuv888_frame((uyvy_macropixel *)gusrc, width, height, irowstride, orowstride, gudest, FALSE);
11202  break;
11203  case WEED_PALETTE_YUVA8888:
11204  weed_set_int_value(layer, WEED_LEAF_WIDTH, width << 1);
11205  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11206  gudest = weed_layer_get_pixel_data_packed(layer);
11207  orowstride = weed_layer_get_rowstride(layer);
11208  convert_uyvy_to_yuv888_frame((uyvy_macropixel *)gusrc, width, height, irowstride, orowstride, gudest, TRUE);
11209  break;
11210  case WEED_PALETTE_YUV420P:
11211  case WEED_PALETTE_YVU420P:
11212  weed_set_int_value(layer, WEED_LEAF_WIDTH, width << 1);
11213  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11214  gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
11215  convert_uyvy_to_yuv420_frame((uyvy_macropixel *)gusrc, width, height, gudest_array, iclamping);
11216  weed_set_int_value(layer, WEED_LEAF_YUV_SAMPLING, WEED_YUV_SAMPLING_DEFAULT);
11217  break;
11218  case WEED_PALETTE_YUV411:
11219  weed_set_int_value(layer, WEED_LEAF_WIDTH, width >> 1);
11220  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11221  gudest = weed_layer_get_pixel_data_packed(layer);
11222  convert_uyvy_to_yuv411_frame((uyvy_macropixel *)gusrc, width, height, (yuv411_macropixel *)gudest, iclamping);
11223  break;
11224  default:
11225  lives_printerr("Invalid palette conversion: %s to %s not written yet !!\n", weed_palette_get_name(inpl),
11226  weed_palette_get_name(outpl));
11227  goto memfail;
11228  }
11229  break;
11230  case WEED_PALETTE_YUYV8888:
11231  gusrc = weed_layer_get_pixel_data_packed(layer);
11232  switch (outpl) {
11233  case WEED_PALETTE_UYVY8888:
11234  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11235  orowstride = weed_layer_get_rowstride(layer);
11236  gudest = weed_layer_get_pixel_data_packed(layer);
11237  convert_swab_frame(gusrc, width, height, irowstride, orowstride, gudest, -USE_THREADS);
11238  break;
11239  case WEED_PALETTE_YUV422P:
11240  weed_set_int_value(layer, WEED_LEAF_WIDTH, width << 1);
11241  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11242  gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
11243  convert_yuyv_to_yuv422_frame((yuyv_macropixel *)gusrc, width, height, gudest_array);
11244  break;
11245  case WEED_PALETTE_RGB24:
11246  weed_set_int_value(layer, WEED_LEAF_WIDTH, width << 1);
11247  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11248  gudest = weed_layer_get_pixel_data_packed(layer);
11249  orowstride = weed_layer_get_rowstride(layer);
11250  convert_yuyv_to_rgb_frame((yuyv_macropixel *)gusrc, width, height, irowstride, orowstride, gudest,
11251  FALSE, iclamping, -USE_THREADS);
11252  break;
11253  case WEED_PALETTE_RGBA32:
11254  weed_set_int_value(layer, WEED_LEAF_WIDTH, width << 1);
11255  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11256  gudest = weed_layer_get_pixel_data_packed(layer);
11257  orowstride = weed_layer_get_rowstride(layer);
11258  convert_yuyv_to_rgb_frame((yuyv_macropixel *)gusrc, width, height, irowstride, orowstride, gudest,
11259  TRUE, iclamping, -USE_THREADS);
11260  break;
11261  case WEED_PALETTE_BGR24:
11262  weed_set_int_value(layer, WEED_LEAF_WIDTH, width << 1);
11263  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11264  gudest = weed_layer_get_pixel_data_packed(layer);
11265  orowstride = weed_layer_get_rowstride(layer);
11266  convert_yuyv_to_bgr_frame((yuyv_macropixel *)gusrc, width, height, irowstride, orowstride, gudest,
11267  FALSE, iclamping, -USE_THREADS);
11268  break;
11269  case WEED_PALETTE_BGRA32:
11270  weed_set_int_value(layer, WEED_LEAF_WIDTH, width << 1);
11271  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11272  gudest = weed_layer_get_pixel_data_packed(layer);
11273  orowstride = weed_layer_get_rowstride(layer);
11274  convert_yuyv_to_bgr_frame((yuyv_macropixel *)gusrc, width, height, irowstride, orowstride, gudest,
11275  TRUE, iclamping, -USE_THREADS);
11276  break;
11277  case WEED_PALETTE_ARGB32:
11278  weed_set_int_value(layer, WEED_LEAF_WIDTH, width << 1);
11279  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11280  gudest = weed_layer_get_pixel_data_packed(layer);
11281  orowstride = weed_layer_get_rowstride(layer);
11282  convert_yuyv_to_argb_frame((yuyv_macropixel *)gusrc, width, height, irowstride, orowstride,
11283  gudest, iclamping, -USE_THREADS);
11284  break;
11285  case WEED_PALETTE_YUV444P:
11286  weed_set_int_value(layer, WEED_LEAF_WIDTH, width << 1);
11287  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11288  gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
11289  ostrides = weed_layer_get_rowstrides(layer, NULL);
11290  convert_yuyv_to_yuvp_frame((yuyv_macropixel *)gusrc, width, height, irowstride, ostrides, gudest_array, FALSE);
11291  break;
11292  case WEED_PALETTE_YUVA4444P:
11293  weed_set_int_value(layer, WEED_LEAF_WIDTH, width << 1);
11294  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11295  gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
11296  ostrides = weed_layer_get_rowstrides(layer, NULL);
11297  convert_yuyv_to_yuvp_frame((yuyv_macropixel *)gusrc, width, height, irowstride, ostrides, gudest_array, TRUE);
11298  break;
11299  case WEED_PALETTE_YUV888:
11300  weed_set_int_value(layer, WEED_LEAF_WIDTH, width << 1);
11301  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11302  gudest = weed_layer_get_pixel_data_packed(layer);
11303  orowstride = weed_layer_get_rowstride(layer);
11304  convert_yuyv_to_yuv888_frame((yuyv_macropixel *)gusrc, width, height, irowstride, orowstride, gudest, FALSE);
11305  break;
11306  case WEED_PALETTE_YUVA8888:
11307  weed_set_int_value(layer, WEED_LEAF_WIDTH, width << 1);
11308  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11309  gudest = weed_layer_get_pixel_data_packed(layer);
11310  orowstride = weed_layer_get_rowstride(layer);
11311  convert_yuyv_to_yuv888_frame((yuyv_macropixel *)gusrc, width, height, irowstride, orowstride, gudest, TRUE);
11312  break;
11313  case WEED_PALETTE_YUV420P:
11314  case WEED_PALETTE_YVU420P:
11315  weed_set_int_value(layer, WEED_LEAF_WIDTH, width << 1);
11316  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11317  gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
11318  convert_yuyv_to_yuv420_frame((yuyv_macropixel *)gusrc, width, height, gudest_array, iclamping);
11319  weed_set_int_value(layer, WEED_LEAF_YUV_SAMPLING, WEED_YUV_SAMPLING_DEFAULT);
11320  break;
11321  case WEED_PALETTE_YUV411:
11322  weed_set_int_value(layer, WEED_LEAF_WIDTH, width >> 1);
11323  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11324  gudest = weed_layer_get_pixel_data_packed(layer);
11325  convert_yuyv_to_yuv411_frame((yuyv_macropixel *)gusrc, width, height, (yuv411_macropixel *)gudest, iclamping);
11326  break;
11327  default:
11328  lives_printerr("Invalid palette conversion: %s to %s not written yet !!\n", weed_palette_get_name(inpl),
11329  weed_palette_get_name(outpl));
11330  goto memfail;
11331  }
11332  break;
11333  case WEED_PALETTE_YUV888:
11334  // need to check rowstrides (may have been resized)
11335  gusrc = weed_layer_get_pixel_data_packed(layer);
11336  switch (outpl) {
11337  case WEED_PALETTE_YUVA8888:
11338  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11339  gudest = weed_layer_get_pixel_data_packed(layer);
11340  orowstride = weed_layer_get_rowstride(layer);
11341  convert_addpost_frame(gusrc, width, height, irowstride, orowstride, gudest, NULL, -USE_THREADS);
11342  break;
11343  case WEED_PALETTE_YUV444P:
11344  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11345  gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
11346  ostrides = weed_layer_get_rowstrides(layer, NULL);
11347  convert_splitplanes_frame(gusrc, width, height, irowstride, ostrides, gudest_array, FALSE, FALSE);
11348  break;
11349  case WEED_PALETTE_YUVA4444P:
11350  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11351  gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
11352  ostrides = weed_layer_get_rowstrides(layer, NULL);
11353  convert_splitplanes_frame(gusrc, width, height, irowstride, ostrides, gudest_array, FALSE, TRUE);
11354  break;
11355  case WEED_PALETTE_RGB24:
11356  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11357  orowstride = weed_layer_get_rowstride(layer);
11358  gudest = weed_layer_get_pixel_data_packed(layer);
11359  convert_yuv888_to_rgb_frame(gusrc, width, height, irowstride, orowstride, gudest, FALSE, iclamping, isampling, -USE_THREADS);
11360  break;
11361  case WEED_PALETTE_RGBA32:
11362  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11363  orowstride = weed_layer_get_rowstride(layer);
11364  gudest = weed_layer_get_pixel_data_packed(layer);
11365  convert_yuv888_to_rgb_frame(gusrc, width, height, irowstride, orowstride, gudest, TRUE, iclamping, isampling, -USE_THREADS);
11366  break;
11367  case WEED_PALETTE_BGR24:
11368  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11369  orowstride = weed_layer_get_rowstride(layer);
11370  gudest = weed_layer_get_pixel_data_packed(layer);
11371  convert_yuv888_to_bgr_frame(gusrc, width, height, irowstride, orowstride, gudest, FALSE, iclamping, isampling, -USE_THREADS);
11372  break;
11373  case WEED_PALETTE_BGRA32:
11374  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11375  orowstride = weed_layer_get_rowstride(layer);
11376  gudest = weed_layer_get_pixel_data_packed(layer);
11377  convert_yuv888_to_bgr_frame(gusrc, width, height, irowstride, orowstride, gudest, TRUE, iclamping, isampling, -USE_THREADS);
11378  break;
11379  case WEED_PALETTE_ARGB32:
11380  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11381  orowstride = weed_layer_get_rowstride(layer);
11382  gudest = weed_layer_get_pixel_data_packed(layer);
11383  convert_yuv888_to_argb_frame(gusrc, width, height, irowstride, orowstride, gudest, iclamping, isampling, -USE_THREADS);
11384  break;
11385  case WEED_PALETTE_YVU420P:
11386  case WEED_PALETTE_YUV420P:
11387  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11388  gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
11389  ostrides = weed_get_int_array(layer, WEED_LEAF_ROWSTRIDES, &error);
11390  convert_yuv888_to_yuv420_frame(gusrc, width, height, irowstride, ostrides, gudest_array, FALSE, iclamping);
11391  weed_set_int_value(layer, WEED_LEAF_YUV_SAMPLING, WEED_YUV_SAMPLING_DEFAULT);
11392  //weed_set_int_value(layer,WEED_LEAF_YUV_SAMPLING,osampling);
11393  break;
11394  case WEED_PALETTE_YUV422P:
11395  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11396  gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
11397  ostrides = weed_get_int_array(layer, WEED_LEAF_ROWSTRIDES, &error);
11398  convert_yuv888_to_yuv422_frame(gusrc, width, height, irowstride, ostrides, gudest_array, FALSE, iclamping);
11399  break;
11400  case WEED_PALETTE_UYVY8888:
11401  weed_set_int_value(layer, WEED_LEAF_WIDTH, width >> 1);
11402  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11403  orowstride = weed_layer_get_rowstride(layer);
11404  gudest = weed_layer_get_pixel_data_packed(layer);
11405  convert_yuv888_to_uyvy_frame(gusrc, width, height, irowstride, orowstride, (uyvy_macropixel *)gudest, FALSE, iclamping);
11406  break;
11407  case WEED_PALETTE_YUYV8888:
11408  weed_set_int_value(layer, WEED_LEAF_WIDTH, width >> 1);
11409  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11410  orowstride = weed_layer_get_rowstride(layer);
11411  gudest = weed_layer_get_pixel_data_packed(layer);
11412  convert_yuv888_to_yuyv_frame(gusrc, width, height, irowstride, orowstride, (yuyv_macropixel *)gudest, FALSE, iclamping);
11413  break;
11414  case WEED_PALETTE_YUV411:
11415  weed_set_int_value(layer, WEED_LEAF_WIDTH, width >> 2);
11416  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11417  gudest = weed_layer_get_pixel_data_packed(layer);
11418  convert_yuv888_to_yuv411_frame(gusrc, width, height, irowstride, (yuv411_macropixel *)gudest, FALSE);
11419  break;
11420  default:
11421  lives_printerr("Invalid palette conversion: %s to %s not written yet !!\n", weed_palette_get_name(inpl),
11422  weed_palette_get_name(outpl));
11423  goto memfail;
11424  }
11425  break;
11426  case WEED_PALETTE_YUVA8888:
11427  gusrc = weed_layer_get_pixel_data_packed(layer);
11428  switch (outpl) {
11429  case WEED_PALETTE_YUV888:
11430  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11431  gudest = weed_layer_get_pixel_data_packed(layer);
11432  orowstride = weed_layer_get_rowstride(layer);
11433  convert_delpost_frame(gusrc, width, height, irowstride, orowstride, gudest, NULL, -USE_THREADS);
11434  break;
11435  case WEED_PALETTE_YUVA4444P:
11436  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11437  gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
11438  ostrides = weed_layer_get_rowstrides(layer, NULL);
11439  convert_splitplanes_frame(gusrc, width, height, irowstride, ostrides, gudest_array, TRUE, TRUE);
11440  break;
11441  case WEED_PALETTE_YUV444P:
11442  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11443  gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
11444  ostrides = weed_layer_get_rowstrides(layer, NULL);
11445  convert_splitplanes_frame(gusrc, width, height, irowstride, ostrides, gudest_array, TRUE, FALSE);
11446  break;
11447  case WEED_PALETTE_RGB24:
11448  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11449  orowstride = weed_layer_get_rowstride(layer);
11450  gudest = weed_layer_get_pixel_data_packed(layer);
11451  convert_yuva8888_to_rgba_frame(gusrc, width, height, irowstride, orowstride, gudest, TRUE, iclamping, isampling, -USE_THREADS);
11452  break;
11453  case WEED_PALETTE_RGBA32:
11454  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11455  orowstride = weed_layer_get_rowstride(layer);
11456  gudest = weed_layer_get_pixel_data_packed(layer);
11457  convert_yuva8888_to_rgba_frame(gusrc, width, height, irowstride, orowstride, gudest, FALSE, iclamping, isampling, -USE_THREADS);
11458  break;
11459  case WEED_PALETTE_BGR24:
11460  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11461  orowstride = weed_layer_get_rowstride(layer);
11462  gudest = weed_layer_get_pixel_data_packed(layer);
11463  convert_yuva8888_to_bgra_frame(gusrc, width, height, irowstride, orowstride, gudest, TRUE, iclamping, isampling, -USE_THREADS);
11464  break;
11465  case WEED_PALETTE_BGRA32:
11466  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11467  orowstride = weed_layer_get_rowstride(layer);
11468  gudest = weed_layer_get_pixel_data_packed(layer);
11469  convert_yuva8888_to_bgra_frame(gusrc, width, height, irowstride, orowstride, gudest, FALSE, iclamping, isampling, -USE_THREADS);
11470  break;
11471  case WEED_PALETTE_ARGB32:
11472  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11473  orowstride = weed_layer_get_rowstride(layer);
11474  gudest = weed_layer_get_pixel_data_packed(layer);
11475  convert_yuva8888_to_argb_frame(gusrc, width, height, irowstride, orowstride, gudest, iclamping, isampling, -USE_THREADS);
11476  break;
11477  case WEED_PALETTE_YUV420P:
11478  case WEED_PALETTE_YVU420P:
11479  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11480  gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
11481  ostrides = weed_layer_get_rowstrides(layer, NULL);
11482  convert_yuv888_to_yuv420_frame(gusrc, width, height, irowstride, ostrides, gudest_array, TRUE, iclamping);
11483  weed_set_int_value(layer, WEED_LEAF_YUV_SAMPLING, WEED_YUV_SAMPLING_DEFAULT);
11484  //weed_set_int_value(layer,WEED_LEAF_YUV_SAMPLING,osampling);
11485  break;
11486  case WEED_PALETTE_YUV422P:
11487  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11488  gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
11489  ostrides = weed_layer_get_rowstrides(layer, NULL);
11490  convert_yuv888_to_yuv422_frame(gusrc, width, height, irowstride, ostrides, gudest_array, TRUE, iclamping);
11491  break;
11492  case WEED_PALETTE_UYVY8888:
11493  weed_set_int_value(layer, WEED_LEAF_WIDTH, width >> 1);
11494  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11495  orowstride = weed_layer_get_rowstride(layer);
11496  gudest = weed_layer_get_pixel_data_packed(layer);
11497  convert_yuv888_to_uyvy_frame(gusrc, width, height, irowstride, orowstride, (uyvy_macropixel *)gudest, TRUE, iclamping);
11498  break;
11499  case WEED_PALETTE_YUYV8888:
11500  weed_set_int_value(layer, WEED_LEAF_WIDTH, width >> 1);
11501  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11502  orowstride = weed_layer_get_rowstride(layer);
11503  gudest = weed_layer_get_pixel_data_packed(layer);
11504  convert_yuv888_to_yuyv_frame(gusrc, width, height, irowstride, orowstride, (yuyv_macropixel *)gudest, TRUE, iclamping);
11505  break;
11506  case WEED_PALETTE_YUV411:
11507  weed_set_int_value(layer, WEED_LEAF_WIDTH, width >> 2);
11508  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11509  gudest = weed_layer_get_pixel_data_packed(layer);
11510  convert_yuv888_to_yuv411_frame(gusrc, width, height, irowstride, (yuv411_macropixel *)gudest, TRUE);
11511  break;
11512  default:
11513  lives_printerr("Invalid palette conversion: %s to %s not written yet !!\n", weed_palette_get_name(inpl),
11514  weed_palette_get_name(outpl));
11515  goto memfail;
11516  }
11517  break;
11518  case WEED_PALETTE_YVU420P:
11519  case WEED_PALETTE_YUV420P:
11520  gusrc_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
11521  switch (outpl) {
11522  case WEED_PALETTE_RGB24:
11523  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11524  orowstride = weed_layer_get_rowstride(layer);
11525  gudest = weed_layer_get_pixel_data_packed(layer);
11526  convert_yuv420p_to_rgb_frame(gusrc_array, width, height, TRUE, istrides, orowstride, gudest, FALSE, FALSE,
11527  isampling, iclamping, isubspace, weed_layer_get_gamma(layer), new_gamma_type, NULL, -USE_THREADS);
11528  break;
11529  case WEED_PALETTE_RGBA32:
11530  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11531  orowstride = weed_layer_get_rowstride(layer);
11532  gudest = weed_layer_get_pixel_data_packed(layer);
11533  convert_yuv420p_to_rgb_frame(gusrc_array, width, height, TRUE, istrides, orowstride, gudest, TRUE, FALSE,
11534  isampling, iclamping, isubspace, weed_layer_get_gamma(layer), new_gamma_type, NULL, -USE_THREADS);
11535  break;
11536  case WEED_PALETTE_BGR24:
11537  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11538  orowstride = weed_layer_get_rowstride(layer);
11539  gudest = weed_layer_get_pixel_data_packed(layer);
11540  convert_yuv420p_to_bgr_frame(gusrc_array, width, height, TRUE, istrides, orowstride, gudest, FALSE, FALSE,
11541  isampling, iclamping, isubspace, weed_layer_get_gamma(layer), new_gamma_type, NULL, -USE_THREADS);
11542  break;
11543  case WEED_PALETTE_BGRA32:
11544  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11545  orowstride = weed_layer_get_rowstride(layer);
11546  gudest = weed_layer_get_pixel_data_packed(layer);
11547  convert_yuv420p_to_bgr_frame(gusrc_array, width, height, TRUE, istrides, orowstride, gudest, TRUE, FALSE,
11548  isampling, iclamping, isubspace, weed_layer_get_gamma(layer), new_gamma_type, NULL, -USE_THREADS);
11549  break;
11550  case WEED_PALETTE_ARGB32:
11551  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11552  orowstride = weed_layer_get_rowstride(layer);
11553  gudest = weed_layer_get_pixel_data_packed(layer);
11554  convert_yuv420p_to_argb_frame(gusrc_array, width, height, TRUE, istrides, orowstride, gudest, FALSE,
11555  isampling, iclamping, isubspace, weed_layer_get_gamma(layer), new_gamma_type, NULL, -USE_THREADS);
11556  break;
11557  case WEED_PALETTE_UYVY8888:
11558  weed_set_int_value(layer, WEED_LEAF_WIDTH, width >> 1);
11559  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11560  orowstride = weed_layer_get_rowstride(layer);
11561  gudest = weed_layer_get_pixel_data_packed(layer);
11562  convert_yuv420_to_uyvy_frame(gusrc_array, width, height, istrides, orowstride, (uyvy_macropixel *)gudest, iclamping);
11563  break;
11564  case WEED_PALETTE_YUYV8888:
11565  weed_set_int_value(layer, WEED_LEAF_WIDTH, width >> 1);
11566  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11567  orowstride = weed_layer_get_rowstride(layer);
11568  gudest = weed_layer_get_pixel_data_packed(layer);
11569  convert_yuv420_to_yuyv_frame(gusrc_array, width, height, istrides, orowstride, (yuyv_macropixel *)gudest, iclamping);
11570  break;
11571  case WEED_PALETTE_YUV422P:
11573  gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
11574  lives_free(gudest_array[0]);
11575  gudest_array[0] = gusrc_array[0];
11576  weed_set_voidptr_array(layer, WEED_LEAF_PIXEL_DATA, 3, (void **)gudest_array);
11577  ostrides = weed_layer_get_rowstrides(layer, NULL);
11578  convert_double_chroma(gusrc_array, width >> 1, height >> 1, istrides, ostrides, gudest_array, iclamping);
11579  gusrc_array[0] = NULL;
11580  weed_layer_set_pixel_data(orig_layer, (void **)gusrc_array, 3);
11581  break;
11582  case WEED_PALETTE_YUV444P:
11584  gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
11585  lives_free(gudest_array[0]);
11586  gudest_array[0] = gusrc_array[0];
11587  weed_set_voidptr_array(layer, WEED_LEAF_PIXEL_DATA, 3, (void **)gudest_array);
11588  orowstride = weed_layer_get_rowstride(layer);
11589  convert_quad_chroma(gusrc_array, width, height, istrides, orowstride, gudest_array, FALSE, isampling, iclamping);
11590  gusrc_array[0] = NULL;
11591  weed_layer_set_pixel_data(orig_layer, (void **)gusrc_array, 3);
11592  break;
11593  case WEED_PALETTE_YUVA4444P:
11595  gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
11596  lives_free(gudest_array[0]);
11597  gudest_array[0] = gusrc_array[0];
11598  weed_set_voidptr_array(layer, WEED_LEAF_PIXEL_DATA, 4, (void **)gudest_array);
11599  orowstride = weed_layer_get_rowstride(layer);
11600  convert_quad_chroma(gusrc_array, width, height, istrides, orowstride, gudest_array, TRUE, isampling, iclamping);
11601  gusrc_array[0] = NULL;
11602  weed_layer_set_pixel_data(orig_layer, (void **)gusrc_array, 3);
11603  break;
11604  case WEED_PALETTE_YVU420P:
11605  case WEED_PALETTE_YUV420P:
11606  if (contig && istrides[1] != istrides[2]) {
11607  uint8_t *gd0, *gd1, *gd2, *gs0 = gusrc_array[0], *gs1 = gusrc_array[1], *gs2 = gusrc_array[2];
11608  size_t hwidth = width >> 1;
11609  size_t ir0 = istrides[0] - width, ir1 = istrides[1] - hwidth, ir2 = istrides[2] - hwidth, or0, or1, or2;
11610  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11611  ostrides = weed_layer_get_rowstrides(layer, NULL);
11612  or0 = ostrides[0] - width;
11613  or1 = ostrides[1] - hwidth;
11614  or2 = ostrides[2] - hwidth;
11615  gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
11616  gd0 = gudest_array[0];
11617  gd1 = gudest_array[1];
11618  gd2 = gudest_array[2];
11619  for (int i = 0; i < height; i++) {
11620  lives_memcpy(gd0, gs0, width);
11621  gd0 += or0;
11622  gs0 += ir0;
11623  lives_memcpy(gd1, gs1, hwidth);
11624  gd1 += or1;
11625  gs1 += ir1;
11626  lives_memcpy(gd2, gs2, hwidth);
11627  gd2 += or2;
11628  gs2 += ir2;
11629  i++;
11630  lives_memcpy(gd0, gs0, width);
11631  gd0 += or0;
11632  gs0 += ir0;
11633  }
11634  break;
11635  } else {
11637  size_t frmsz = istrides[1] * (height >> 1);
11639  swap_chroma_planes(layer);
11640  if (!(tmp = lives_calloc_safety(frmsz, 1))) goto memfail;
11642  lives_memcpy(tmp, (void **)gusrc_array[1], frmsz); // v plane
11643  lives_memcpy(gusrc_array[1], (void **)gusrc_array[2], frmsz); //u -> v
11644  lives_memcpy(gusrc_array[2], tmp, frmsz); // v -> u
11645  lives_free(tmp);
11646  }
11647  break;
11648  case WEED_PALETTE_YUV888:
11649  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11650  gudest = weed_layer_get_pixel_data_packed(layer);
11651  orowstride = weed_layer_get_rowstride(layer);
11652  convert_quad_chroma_packed(gusrc_array, width, height, istrides, orowstride, gudest, FALSE, isampling, iclamping);
11653  break;
11654  case WEED_PALETTE_YUVA8888:
11655  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11656  gudest = weed_layer_get_pixel_data_packed(layer);
11657  orowstride = weed_layer_get_rowstride(layer);
11658  convert_quad_chroma_packed(gusrc_array, width, height, istrides, orowstride, gudest, TRUE, isampling, iclamping);
11659  break;
11660  case WEED_PALETTE_YUV411:
11661  weed_set_int_value(layer, WEED_LEAF_WIDTH, width >> 2);
11662  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11663  gudest = weed_layer_get_pixel_data_packed(layer);
11664  convert_yuv420_to_yuv411_frame(gusrc_array, width, height, (yuv411_macropixel *)gudest, FALSE, iclamping);
11665  break;
11666  default:
11667  lives_printerr("Invalid palette conversion: %s to %s not written yet !!\n", weed_palette_get_name(inpl),
11668  weed_palette_get_name(outpl));
11669  goto memfail;
11670  }
11671  break;
11672  case WEED_PALETTE_YUV422P:
11673  gusrc_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
11674  switch (outpl) {
11675  case WEED_PALETTE_RGB24:
11676  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11677  orowstride = weed_layer_get_rowstride(layer);
11678  gudest = weed_layer_get_pixel_data_packed(layer);
11679  convert_yuv420p_to_rgb_frame(gusrc_array, width, height, TRUE, istrides, orowstride, gudest, FALSE, TRUE,
11680  isampling, iclamping, isubspace, weed_layer_get_gamma(layer), new_gamma_type, NULL, -USE_THREADS);
11681  break;
11682  case WEED_PALETTE_RGBA32:
11683  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11684  orowstride = weed_layer_get_rowstride(layer);
11685  gudest = weed_layer_get_pixel_data_packed(layer);
11686  convert_yuv420p_to_rgb_frame(gusrc_array, width, height, TRUE, istrides, orowstride, gudest, TRUE, TRUE,
11687  isampling, iclamping, isubspace, weed_layer_get_gamma(layer), new_gamma_type, NULL, -USE_THREADS);
11688  break;
11689  case WEED_PALETTE_BGR24:
11690  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11691  orowstride = weed_layer_get_rowstride(layer);
11692  gudest = weed_layer_get_pixel_data_packed(layer);
11693  convert_yuv420p_to_bgr_frame(gusrc_array, width, height, TRUE, istrides, orowstride, gudest, FALSE, TRUE,
11694  isampling, iclamping, isubspace, weed_layer_get_gamma(layer), new_gamma_type, NULL, -USE_THREADS);
11695  break;
11696  case WEED_PALETTE_BGRA32:
11697  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11698  orowstride = weed_layer_get_rowstride(layer);
11699  gudest = weed_layer_get_pixel_data_packed(layer);
11700  convert_yuv420p_to_bgr_frame(gusrc_array, width, height, TRUE, istrides, orowstride, gudest, TRUE, TRUE,
11701  isampling, iclamping, isubspace, weed_layer_get_gamma(layer), new_gamma_type, NULL, -USE_THREADS);
11702  break;
11703  case WEED_PALETTE_ARGB32:
11704  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11705  orowstride = weed_layer_get_rowstride(layer);
11706  gudest = weed_layer_get_pixel_data_packed(layer);
11707  convert_yuv420p_to_argb_frame(gusrc_array, width, height, TRUE, istrides, orowstride, gudest, TRUE,
11708  isampling, iclamping, isubspace, weed_layer_get_gamma(layer), new_gamma_type, NULL, -USE_THREADS);
11709  break;
11710  case WEED_PALETTE_UYVY8888:
11711  weed_set_int_value(layer, WEED_LEAF_WIDTH, width >> 1);
11712  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11713  orowstride = weed_layer_get_rowstride(layer);
11714  gudest = weed_layer_get_pixel_data_packed(layer);
11715  convert_yuv422p_to_uyvy_frame(gusrc_array, width, height, istrides, orowstride, gudest);
11716  break;
11717  case WEED_PALETTE_YUYV8888:
11718  weed_set_int_value(layer, WEED_LEAF_WIDTH, width >> 1);
11719  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11720  orowstride = weed_layer_get_rowstride(layer);
11721  gudest = weed_layer_get_pixel_data_packed(layer);
11722  convert_yuv422p_to_yuyv_frame(gusrc_array, width, height, istrides, orowstride, gudest);
11723  break;
11724  case WEED_PALETTE_YUV420P:
11725  case WEED_PALETTE_YVU420P:
11727  gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
11728  lives_free(gudest_array[0]);
11729  gudest_array[0] = gusrc_array[0];
11730  weed_set_voidptr_array(layer, WEED_LEAF_PIXEL_DATA, 3, (void **)gudest_array);
11731  ostrides = weed_layer_get_rowstrides(layer, NULL);
11732  convert_halve_chroma(gusrc_array, width >> 1, height >> 1, istrides, ostrides, gudest_array, iclamping);
11733  gusrc_array[0] = NULL;
11734  weed_layer_set_pixel_data(orig_layer, (void **)gusrc_array, 3);
11735  weed_set_int_value(layer, WEED_LEAF_YUV_SAMPLING, isampling);
11736  break;
11737  case WEED_PALETTE_YUV444P:
11739  gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
11740  lives_free(gudest_array[0]);
11741  gudest_array[0] = gusrc_array[0];
11742  weed_set_voidptr_array(layer, WEED_LEAF_PIXEL_DATA, 3, (void **)gudest_array);
11743  ostrides = weed_layer_get_rowstrides(layer, NULL);
11744  convert_double_chroma(gusrc_array, width >> 1, height >> 1, istrides, ostrides, gudest_array, iclamping);
11745  gusrc_array[0] = NULL;
11746  weed_layer_set_pixel_data(orig_layer, (void **)gusrc_array, 3);
11747  break;
11748  case WEED_PALETTE_YUVA4444P:
11750  gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
11751  lives_free(gudest_array[0]);
11752  gudest_array[0] = gusrc_array[0];
11753  weed_set_voidptr_array(layer, WEED_LEAF_PIXEL_DATA, 4, (void **)gudest_array);
11754  ostrides = weed_layer_get_rowstrides(layer, NULL);
11755  convert_double_chroma(gusrc_array, width >> 1, height >> 1, istrides, ostrides, gudest_array, iclamping);
11756  lives_memset(gudest_array[3], 255, width * height);
11757  gusrc_array[0] = NULL;
11758  weed_layer_set_pixel_data(orig_layer, (void **)gusrc_array, 3);
11759  break;
11760  case WEED_PALETTE_YUV888:
11761  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11762  gudest = weed_layer_get_pixel_data_packed(layer);
11763  orowstride = weed_layer_get_rowstride(layer);
11764  convert_double_chroma_packed(gusrc_array, width, height, istrides, orowstride, gudest, FALSE, isampling, iclamping);
11765  break;
11766  case WEED_PALETTE_YUVA8888:
11767  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11768  gudest = weed_layer_get_pixel_data_packed(layer);
11769  orowstride = weed_layer_get_rowstride(layer);
11770  convert_double_chroma_packed(gusrc_array, width, height, istrides, orowstride, gudest, TRUE, isampling, iclamping);
11771  break;
11772  case WEED_PALETTE_YUV411:
11773  weed_set_int_value(layer, WEED_LEAF_WIDTH, width >> 2);
11774  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11775  gudest = weed_layer_get_pixel_data_packed(layer);
11776  convert_yuv420_to_yuv411_frame(gusrc_array, width, height, (yuv411_macropixel *)gudest, TRUE, iclamping);
11777  break;
11778  default:
11779  lives_printerr("Invalid palette conversion: %s to %s not written yet !!\n", weed_palette_get_name(inpl),
11780  weed_palette_get_name(outpl));
11781  goto memfail;
11782  }
11783  break;
11784  case WEED_PALETTE_YUV411:
11785  gusrc = weed_layer_get_pixel_data_packed(layer);
11786  switch (outpl) {
11787  case WEED_PALETTE_RGB24:
11788  weed_set_int_value(layer, WEED_LEAF_WIDTH, width << 2);
11789  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11790  orowstride = weed_layer_get_rowstride(layer);
11791  gudest = weed_layer_get_pixel_data_packed(layer);
11792  convert_yuv411_to_rgb_frame((yuv411_macropixel *)gusrc, width, height, orowstride, gudest, FALSE, iclamping);
11793  break;
11794  case WEED_PALETTE_RGBA32:
11795  weed_set_int_value(layer, WEED_LEAF_WIDTH, width << 2);
11796  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11797  orowstride = weed_layer_get_rowstride(layer);
11798  gudest = weed_layer_get_pixel_data_packed(layer);
11799  convert_yuv411_to_rgb_frame((yuv411_macropixel *)gusrc, width, height, orowstride, gudest, TRUE, iclamping);
11800  break;
11801  case WEED_PALETTE_BGR24:
11802  weed_set_int_value(layer, WEED_LEAF_WIDTH, width << 2);
11803  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11804  orowstride = weed_layer_get_rowstride(layer);
11805  gudest = weed_layer_get_pixel_data_packed(layer);
11806  convert_yuv411_to_bgr_frame((yuv411_macropixel *)gusrc, width, height, orowstride, gudest, FALSE, iclamping);
11807  break;
11808  case WEED_PALETTE_BGRA32:
11809  weed_set_int_value(layer, WEED_LEAF_WIDTH, width << 2);
11810  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11811  orowstride = weed_layer_get_rowstride(layer);
11812  gudest = weed_layer_get_pixel_data_packed(layer);
11813  convert_yuv411_to_bgr_frame((yuv411_macropixel *)gusrc, width, height, orowstride, gudest, TRUE, iclamping);
11814  break;
11815  case WEED_PALETTE_ARGB32:
11816  weed_set_int_value(layer, WEED_LEAF_WIDTH, width << 2);
11817  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11818  orowstride = weed_layer_get_rowstride(layer);
11819  gudest = weed_layer_get_pixel_data_packed(layer);
11820  convert_yuv411_to_argb_frame((yuv411_macropixel *)gusrc, width, height, orowstride, gudest, iclamping);
11821  break;
11822  case WEED_PALETTE_YUV888:
11823  weed_set_int_value(layer, WEED_LEAF_WIDTH, width << 2);
11824  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11825  gudest = weed_layer_get_pixel_data_packed(layer);
11826  convert_yuv411_to_yuv888_frame((yuv411_macropixel *)gusrc, width, height, gudest, FALSE, iclamping);
11827  break;
11828  case WEED_PALETTE_YUVA8888:
11829  weed_set_int_value(layer, WEED_LEAF_WIDTH, width << 2);
11830  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11831  gudest = weed_layer_get_pixel_data_packed(layer);
11832  convert_yuv411_to_yuv888_frame((yuv411_macropixel *)gusrc, width, height, gudest, TRUE, iclamping);
11833  break;
11834  case WEED_PALETTE_YUV444P:
11835  weed_set_int_value(layer, WEED_LEAF_WIDTH, width << 2);
11836  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11837  gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
11838  convert_yuv411_to_yuvp_frame((yuv411_macropixel *)gusrc, width, height, gudest_array, FALSE, iclamping);
11839  break;
11840  case WEED_PALETTE_YUVA4444P:
11841  weed_set_int_value(layer, WEED_LEAF_WIDTH, width << 2);
11842  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11843  gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
11844  convert_yuv411_to_yuvp_frame((yuv411_macropixel *)gusrc, width, height, gudest_array, TRUE, iclamping);
11845  break;
11846  case WEED_PALETTE_UYVY8888:
11847  weed_set_int_value(layer, WEED_LEAF_WIDTH, width << 1);
11848  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11849  gudest = weed_layer_get_pixel_data_packed(layer);
11850  convert_yuv411_to_uyvy_frame((yuv411_macropixel *)gusrc, width, height, (uyvy_macropixel *)gudest, iclamping);
11851  break;
11852  case WEED_PALETTE_YUYV8888:
11853  weed_set_int_value(layer, WEED_LEAF_WIDTH, width << 1);
11854  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11855  gudest = weed_layer_get_pixel_data_packed(layer);
11856  convert_yuv411_to_yuyv_frame((yuv411_macropixel *)gusrc, width, height, (yuyv_macropixel *)gudest, iclamping);
11857  break;
11858  case WEED_PALETTE_YUV422P:
11859  weed_set_int_value(layer, WEED_LEAF_WIDTH, width << 2);
11860  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11861  gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
11862  convert_yuv411_to_yuv422_frame((yuv411_macropixel *)gusrc, width, height, gudest_array, iclamping);
11863  break;
11864  case WEED_PALETTE_YUV420P:
11865  weed_set_int_value(layer, WEED_LEAF_WIDTH, width << 2);
11866  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11867  gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
11868  convert_yuv411_to_yuv420_frame((yuv411_macropixel *)gusrc, width, height, gudest_array, FALSE, iclamping);
11869  break;
11870  case WEED_PALETTE_YVU420P:
11871  weed_set_int_value(layer, WEED_LEAF_WIDTH, width << 2);
11872  if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11873  gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
11874  convert_yuv411_to_yuv420_frame((yuv411_macropixel *)gusrc, width, height, gudest_array, TRUE, iclamping);
11875  break;
11876  default:
11877  lives_printerr("Invalid palette conversion: %s to %s not written yet !!\n", weed_palette_get_name(inpl),
11878  weed_palette_get_name(outpl));
11879  goto memfail;
11880  }
11881  break;
11882  default:
11883  lives_printerr("Invalid palette conversion: %s to %s not written yet !!\n", weed_palette_get_name(inpl),
11884  weed_palette_get_name(outpl));
11885  goto memfail;
11886  }
11887 
11888 #ifdef WEED_ADVANCED_PALETTES
11889 conv_done:
11890 #endif
11891 
11892  lives_freep((void **)&ostrides);
11893  lives_freep((void **)&gusrc_array);
11894 
11895  //lives_freep((void **)&gudest_array);
11896 
11897  if (orig_layer) weed_layer_free(orig_layer);
11898 
11899  if (new_gamma_type != WEED_GAMMA_UNKNOWN && can_inline_gamma(inpl, outpl)) {
11900  weed_layer_set_gamma(layer, new_gamma_type);
11901  }
11902 
11903  if (weed_palette_is_rgb(outpl)) {
11904  weed_leaf_delete(layer, WEED_LEAF_YUV_CLAMPING);
11905  weed_leaf_delete(layer, WEED_LEAF_YUV_SUBSPACE);
11906  weed_leaf_delete(layer, WEED_LEAF_YUV_SAMPLING);
11907  } else {
11908  weed_set_int_value(layer, WEED_LEAF_YUV_CLAMPING, oclamping);
11909  if (weed_palette_is_rgb(inpl)) {
11910  if (weed_layer_get_gamma(layer) == WEED_GAMMA_BT709)
11911  weed_set_int_value(layer, WEED_LEAF_YUV_SUBSPACE, WEED_YUV_SUBSPACE_BT709);
11912  else
11913  weed_set_int_value(layer, WEED_LEAF_YUV_SUBSPACE, WEED_YUV_SUBSPACE_YCBCR);
11914  }
11915  if (!weed_plant_has_leaf(layer, WEED_LEAF_YUV_SAMPLING)) weed_set_int_value(layer,
11916  WEED_LEAF_YUV_SAMPLING, WEED_YUV_SAMPLING_DEFAULT);
11917  }
11918 
11920 #ifdef WEED_ADVANCED_PALETTES
11921  if (get_advanced_palette(outpl)->chantype[1] == WEED_VCHAN_V) swap_chroma_planes(layer);
11922 #else
11923  if (outpl == WEED_PALETTE_YVU420P) swap_chroma_planes(layer);
11924 #endif
11925 
11926  lives_free(istrides);
11927  return TRUE;
11928 
11929 memfail:
11930  lives_freep((void **)&gudest_array);
11931  weed_layer_set_palette(layer, inpl);
11932  weed_layer_set_size(layer, width, height);
11933  if (gusrc) {
11934  weed_layer_set_pixel_data_packed(layer, gusrc);
11935  weed_layer_set_rowstride(layer, istrides[0]);
11936  } else if (gusrc_array) {
11937  weed_layer_set_pixel_data(layer, (void **)gusrc_array, nplanes);
11938  weed_layer_set_rowstrides(layer, istrides, nplanes);
11939  }
11940  lives_free(istrides);
11941  return FALSE;
11942 }
11943 
11944 
11945 boolean convert_layer_palette(weed_layer_t *layer, int outpl, int op_clamping) {
11946  return convert_layer_palette_full(layer, outpl, op_clamping, WEED_YUV_SAMPLING_DEFAULT, WEED_YUV_SUBSPACE_YUV,
11947  WEED_GAMMA_UNKNOWN);
11948 }
11949 
11951 
11952 
11953 LiVESPixbuf *lives_pixbuf_new_blank(int width, int height, int palette) {
11954  LiVESPixbuf *pixbuf;
11955  int rowstride;
11956  uint8_t *pixels;
11957  size_t size;
11958 
11959  switch (palette) {
11960  case WEED_PALETTE_RGB24:
11961  case WEED_PALETTE_BGR24:
11962  pixbuf = lives_pixbuf_new(FALSE, width, height);
11963  rowstride = lives_pixbuf_get_rowstride(pixbuf);
11964  pixels = lives_pixbuf_get_pixels(pixbuf);
11965  size = rowstride * (height - 1) + get_last_pixbuf_rowstride_value(width, 3);
11966  lives_memset(pixels, 0, size);
11967  break;
11968  case WEED_PALETTE_RGBA32:
11969  case WEED_PALETTE_BGRA32:
11970  pixbuf = lives_pixbuf_new(TRUE, width, height);
11971  rowstride = lives_pixbuf_get_rowstride(pixbuf);
11972  pixels = lives_pixbuf_get_pixels(pixbuf);
11973  size = rowstride * (height - 1) + get_last_pixbuf_rowstride_value(width, 4);
11974  lives_memset(pixels, 0, size);
11975  break;
11976  case WEED_PALETTE_ARGB32:
11977  pixbuf = lives_pixbuf_new(TRUE, width, height);
11978  rowstride = lives_pixbuf_get_rowstride(pixbuf);
11979  pixels = lives_pixbuf_get_pixels(pixbuf);
11980  size = rowstride * (height - 1) + get_last_pixbuf_rowstride_value(width, 4);
11981  lives_memset(pixels, 0, size);
11982  break;
11983  default:
11984  return NULL;
11985  }
11986  return pixbuf;
11987 }
11988 
11989 
11990 LIVES_INLINE LiVESPixbuf *lives_pixbuf_cheat(boolean has_alpha, int width, int height, uint8_t *buf) {
11991  // we can cheat if our buffer is correctly sized
11992  LiVESPixbuf *pixbuf;
11993  int channels = has_alpha ? 4 : 3;
11994  int rowstride = get_pixbuf_rowstride_value(width * channels);
11995 
11996  pixbuf = lives_pixbuf_new_from_data(buf, has_alpha, width, height, rowstride,
11997  (LiVESPixbufDestroyNotify)lives_free_buffer, NULL);
11998  return pixbuf;
11999 }
12000 
12001 
12003  int gamma_type = WEED_GAMMA_UNKNOWN;
12004  int error;
12005  if (prefs->apply_gamma) {
12006  if (weed_plant_has_leaf(layer, WEED_LEAF_GAMMA_TYPE)) {
12007  gamma_type = weed_get_int_value(layer, WEED_LEAF_GAMMA_TYPE, &error);
12008  }
12009  if (gamma_type == WEED_GAMMA_UNKNOWN) {
12010  break_me("weed_layer_get_gamma with unk. gamma");
12011  LIVES_WARN("Layer with unknown gamma !!");
12012  gamma_type = WEED_GAMMA_SRGB;
12013  }
12014  }
12015  return gamma_type;
12016 }
12017 
12018 
12019 void gamma_conv_params(int gamma_type, weed_layer_t *inst, boolean is_in) {
12020  if (!prefs->apply_gamma) return;
12021  else {
12022  // convert colour param values to gamma_type (only integer values)
12023  weed_layer_t **params;
12024  weed_layer_t *ptmpl, *param;
12025  uint8_t *gamma_lut = NULL;
12026  const char *type = is_in ? WEED_LEAF_IN_PARAMETERS : WEED_LEAF_OUT_PARAMETERS;
12027 
12028  int *ivals;
12029  int ogamma_type, oogamma_type = WEED_GAMMA_UNKNOWN;
12030  int pptype, pcspace, ptype, nvals, qvals;
12031  int nparms;
12032 
12033  if (!inst) return;
12034  params = weed_get_plantptr_array_counted(inst, type, &nparms);
12035  if (!nparms) return;
12036 
12037  for (int i = 0; i < nparms; i++) {
12038  param = params[i];
12039  if (!(nvals = weed_leaf_num_elements(param, WEED_LEAF_VALUE))) continue;
12040  ptmpl = weed_get_plantptr_value(param, WEED_LEAF_TEMPLATE, NULL);
12041  pptype = weed_paramtmpl_get_type(ptmpl);
12042  if (pptype != WEED_PARAM_COLOR) continue;
12043 
12044  ptype = weed_leaf_seed_type(ptmpl, WEED_LEAF_DEFAULT);
12045 
12046  if (ptype != WEED_SEED_INT) gamma_type = WEED_GAMMA_SRGB;
12047 
12048  if (!prefs->apply_gamma || !weed_plant_has_leaf(param, WEED_LEAF_GAMMA_TYPE)) {
12049  ogamma_type = WEED_GAMMA_SRGB;
12050  } else {
12051  ogamma_type = weed_get_int_value(param, WEED_LEAF_GAMMA_TYPE, NULL);
12052  }
12053 
12054  if (ogamma_type != oogamma_type && gamma_type != ogamma_type) {
12055  if (gamma_lut) lives_gamma_lut_free(gamma_lut);
12056  gamma_lut = create_gamma_lut(1.0, ogamma_type, gamma_type);
12057  if (!gamma_lut) break;
12058  oogamma_type = ogamma_type;
12059  }
12060 
12061  weed_set_int_value(param, WEED_LEAF_GAMMA_TYPE, gamma_type);
12062  weed_leaf_set_flags(param, WEED_LEAF_GAMMA_TYPE, (weed_leaf_get_flags(param, WEED_LEAF_GAMMA_TYPE) |
12063  WEED_FLAG_IMMUTABLE | WEED_FLAG_UNDELETABLE));
12064 
12065  // no change needed
12066  if (gamma_type == ogamma_type) continue;
12067 
12068  qvals = 3;
12069  pcspace = weed_get_int_value(ptmpl, WEED_LEAF_COLORSPACE, NULL);
12070  if (pcspace == WEED_COLORSPACE_RGBA) qvals = 4;
12071  ivals = weed_get_int_array(param, WEED_LEAF_VALUE, NULL);
12072  if (gamma_lut) {
12073  for (int j = 0; j < nvals; j += qvals) {
12074  for (int k = 0; k < 3; k++) {
12075  ivals[j + k] = gamma_lut[ivals[j + k]];
12076  }
12077  }
12078  lives_gamma_lut_free(gamma_lut);
12079  weed_set_int_array(param, WEED_LEAF_VALUE, nvals, ivals);
12080  lives_free(ivals);
12081  weed_set_int_value(param, WEED_LEAF_GAMMA_TYPE, gamma_type);
12082  weed_leaf_set_flags(param, WEED_LEAF_GAMMA_TYPE, (weed_leaf_get_flags(param, WEED_LEAF_GAMMA_TYPE) |
12083  WEED_FLAG_IMMUTABLE | WEED_FLAG_UNDELETABLE));
12084  }
12085  }
12086  lives_free(params);
12087  if (gamma_lut) lives_gamma_lut_free(gamma_lut);
12088  }
12089 }
12090 
12091 
12092 static void *gamma_convert_layer_thread(void *data) {
12093  lives_cc_params *ccparams = (lives_cc_params *)data;
12094  uint8_t *pixels = (uint8_t *)ccparams->src;
12095  int rowstride = ccparams->orowstrides[0];
12096  uint8_t *end = pixels + ccparams->vsize * rowstride;
12097  int psize = ccparams->psize, px = 3;
12098  int widthx = ccparams->hsize * psize;
12099  int start = ccparams->xoffset;
12100  uint8_t *gamma_lut = ccparams->lut;
12101  if (!gamma_lut) return NULL;
12102 
12103  if (psize < px) px = psize;
12104 
12105  if (ccparams->alpha_first) start += 1;
12106  for (; pixels < end; pixels += rowstride) {
12107  //g_print("\n");
12108  for (int j = start; j < widthx; j += psize) {
12109  for (int k = 0; k < px; k++) {
12110  //g_print(" PX %p + %d , %d = %d\t", pixels, j + k, pixels[j + k], gamma_lut[pixels[k + j]]);
12111  pixels[j + k] = gamma_lut[pixels[j + k]];
12112  }
12113  //g_print("\n");
12114  }
12115  }
12116  return NULL;
12117 }
12118 
12119 
12124 boolean gamma_convert_sub_layer(int gamma_type, double fileg, weed_layer_t *layer, int x, int y, int width, int height,
12125  boolean may_thread) {
12126  if (!prefs->apply_gamma) return TRUE;
12127  else {
12128  // convert layer from current gamma to target
12129  int pal = weed_layer_get_palette(layer);
12130  if (!weed_palette_is_rgb(pal)) return FALSE; // dont know how to convert in yuv space
12131  else {
12132  int lgamma_type = weed_layer_get_gamma(layer);
12133  //g_print("gam from %d to %d with fileg %f\n", lgamma_type, gamma_type, fileg);
12134  if (gamma_type == lgamma_type && fileg == 1.0) return TRUE;
12135  else {
12136  lives_thread_t threads[prefs->nfx_threads];
12137  int nfx_threads = may_thread ? prefs->nfx_threads : 1;
12138  uint8_t *pixels = weed_layer_get_pixel_data_packed(layer);
12139  uint8_t *gamma_lut;
12140  int orowstride = weed_layer_get_rowstride(layer);
12141  int nthreads = 1;
12142  int dheight;
12143  int psize = pixel_size(pal);
12144  lives_cc_params *ccparams = (lives_cc_params *)lives_calloc(nfx_threads,
12145  sizeof(lives_cc_params));
12146  int xdheight = CEIL((double)height / (double)nfx_threads, 4);
12147  uint8_t *end = pixels + (y + height) * orowstride;
12148 
12149  pixels += y * orowstride;
12150 
12151  if (gamma_type == WEED_GAMMA_VARIANT)
12152  gamma_lut = create_gamma_lut(fileg, lgamma_type, gamma_type);
12153  else
12154  gamma_lut = create_gamma_lut(1.0, lgamma_type, gamma_type);
12155 
12156  //for (int i = nfx_threads - 1; i >= 0; i--) {
12157  for (int i = nfx_threads - 1; i >= 0; i--) {
12158  dheight = xdheight;
12159 
12160  if ((pixels + dheight * i * orowstride) < end) {
12161  ccparams[i].src = pixels + dheight * i * orowstride;
12162  ccparams[i].hsize = width;
12163  ccparams[i].xoffset = x * psize;
12164 
12165  if (dheight * (i + 1) > (height - 4)) {
12166  dheight = height - (dheight * i);
12167  }
12168  ccparams[i].vsize = dheight;
12169  ccparams[i].psize = psize;
12170  ccparams[i].orowstrides[0] = orowstride;
12171  if (pal == WEED_PALETTE_ARGB32) ccparams->alpha_first = TRUE;
12172  ccparams[i].lut = (void *)gamma_lut;
12173  ccparams[i].thread_id = i;
12174  if (i == 0) gamma_convert_layer_thread(&ccparams[i]);
12175  else {
12176  lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, gamma_convert_layer_thread, &ccparams[i]);
12177  nthreads++;
12178  }
12179  }
12180  }
12181  for (int i = 1; i < nthreads; i++) {
12182  lives_thread_join(threads[i], NULL);
12183  }
12184  lives_free(ccparams);
12185  lives_gamma_lut_free(gamma_lut);
12186  if (gamma_type != WEED_GAMMA_VARIANT)
12187  weed_set_int_value(layer, WEED_LEAF_GAMMA_TYPE, gamma_type);
12188  return TRUE;
12189  // *INDENT-OFF*
12190  }}}
12191  // *INDENT-ON*
12192 }
12193 
12194 
12195 LIVES_GLOBAL_INLINE boolean gamma_convert_layer(int gamma_type, weed_layer_t *layer) {
12196  int width = weed_layer_get_width(layer);
12197  int height = weed_layer_get_height(layer);
12198  return gamma_convert_sub_layer(gamma_type, 1.0, layer, 0, 0, width, height, TRUE);
12199 }
12200 
12201 
12202 LIVES_GLOBAL_INLINE boolean gamma_convert_layer_variant(double file_gamma, int tgamma, weed_layer_t *layer) {
12203  int width = weed_layer_get_width(layer);
12204  int height = weed_layer_get_height(layer);
12205  weed_set_int_value(layer, WEED_LEAF_GAMMA_TYPE, WEED_GAMMA_LINEAR);
12206  return gamma_convert_sub_layer(tgamma, file_gamma, layer, 0, 0, width, height, TRUE);
12207 }
12208 
12209 
12210 LiVESPixbuf *layer_to_pixbuf(weed_layer_t *layer, boolean realpalette, boolean fordisplay) {
12211  // create a gdkpixbuf from a weed layer
12212  // layer "pixel_data" is then either copied to the pixbuf pixels, or the contents shared with the pixbuf and array value set to NULL
12213  // layer may safely be passed to weed_layer_free() since if the pixel data is shared then it will be set to NULL in the layer.
12214  // pixbuf should be unreffed after use as per normal
12215 
12216  LiVESPixbuf *pixbuf;
12217 
12218  uint8_t *pixel_data, *pixels, *end;
12219 
12220  boolean cheat = FALSE, done;
12221 
12222  int palette, xpalette;
12223  int width;
12224  int height;
12225  int irowstride;
12226  int rowstride, orowstride;
12227  int n_channels;
12228 
12229  if (!layer) return NULL;
12230 
12232 
12233  if (weed_plant_has_leaf(layer, WEED_LEAF_HOST_PIXBUF_SRC) && (!realpalette || weed_palette_is_pixbuf_palette(palette))) {
12234  // our layer pixel_data originally came from a pixbuf, so just free the layer and return the pixbuf
12235  pixbuf = (LiVESPixbuf *)weed_get_voidptr_value(layer, WEED_LEAF_HOST_PIXBUF_SRC, NULL);
12237  weed_leaf_delete(layer, WEED_LEAF_HOST_PIXBUF_SRC);
12238  return pixbuf;
12239  }
12240 
12241  // otherwise we need to steal or copy the pixel_data
12242 
12243  if (!weed_layer_get_pixel_data_packed(layer)) {
12244  layer = create_blank_layer(layer, NULL, 0, 0, WEED_PALETTE_END);
12245  }
12246 
12247  do {
12249  height = weed_layer_get_height(layer);
12250  irowstride = weed_layer_get_rowstride(layer);
12251  pixel_data = (uint8_t *)weed_get_voidptr_value(layer, WEED_LEAF_PIXEL_DATA, NULL);
12252  done = TRUE;
12253  xpalette = palette;
12254  if (realpalette) {
12256  // force conversion to RGB24 or RGBA32
12257  xpalette = WEED_PALETTE_END;
12258  } else {
12259  if (prefs->apply_gamma) {
12260  gamma_convert_layer(WEED_GAMMA_SRGB, layer);
12261  if (fordisplay && prefs->use_screen_gamma)
12263  }
12264  }
12265  }
12266  switch (xpalette) {
12267  case WEED_PALETTE_RGB24:
12268  case WEED_PALETTE_BGR24:
12269  case WEED_PALETTE_YUV888:
12270 #ifndef GUI_QT
12271  if (irowstride == get_pixbuf_rowstride_value(width * 3)) {
12272  // rowstrides are OK, we can just steal the pixel_data
12273  pixbuf = lives_pixbuf_cheat(FALSE, width, height, pixel_data);
12275  cheat = TRUE;
12276  } else {
12277 #endif
12278  // otherwise we need to copy the data
12279  pixbuf = lives_pixbuf_new(FALSE, width, height);
12280  }
12281  n_channels = 3;
12282  break;
12283  case WEED_PALETTE_RGBA32:
12284  case WEED_PALETTE_BGRA32:
12285 #ifdef USE_SWSCALE
12286  case WEED_PALETTE_ARGB32:
12287 #else
12288 #ifdef GUI_QT
12289  case WEED_PALETTE_ARGB32:
12290 #endif
12291 #endif
12292  case WEED_PALETTE_YUVA8888:
12293 #ifndef GUI_QT
12294  if (irowstride == get_pixbuf_rowstride_value(width * 4)) {
12295  // rowstrides are OK, we can just steal the pixel_data
12296  pixbuf = lives_pixbuf_cheat(TRUE, width, height, pixel_data);
12298  cheat = TRUE;
12299  } else
12300 #endif
12301  // otherwise we need to copy the data
12302  pixbuf = lives_pixbuf_new(TRUE, width, height);
12303  n_channels = 4;
12304  break;
12305  default:
12307  if (!convert_layer_palette(layer, WEED_PALETTE_RGBA32, 0)) return NULL;
12308  palette = WEED_PALETTE_RGBA32;
12309  } else {
12310  if (!convert_layer_palette(layer, WEED_PALETTE_RGB24, 0)) return NULL;
12311  palette = WEED_PALETTE_RGB24;
12312  }
12313  done = FALSE;
12314  }
12315  } while (!done);
12316 
12317  if (!cheat && LIVES_IS_PIXBUF(pixbuf)) {
12318  // copy the pixel data
12319  boolean done = FALSE;
12320  pixels = lives_pixbuf_get_pixels(pixbuf);
12321  orowstride = lives_pixbuf_get_rowstride(pixbuf);
12322 
12323  if (irowstride > orowstride) rowstride = orowstride;
12324  else rowstride = irowstride;
12325  end = pixels + orowstride * height;
12326 
12327  for (; pixels < end && !done; pixels += orowstride) {
12328  if (pixels + orowstride >= end) {
12329  orowstride = rowstride = get_last_pixbuf_rowstride_value(width, n_channels);
12330  done = TRUE;
12331  }
12332  lives_memcpy(pixels, pixel_data, rowstride);
12333  if (rowstride < orowstride) lives_memset(pixels + rowstride, 255, orowstride - rowstride);
12334  pixel_data += irowstride;
12335  }
12337  }
12338 
12339  return pixbuf;
12340 }
12341 
12342 
12343 LIVES_INLINE boolean weed_palette_is_resizable(int pal, int clamped, boolean in_out) {
12344  // in_out is TRUE for input, FALSE for output
12345 
12346  // in future we may also have resize candidates/delegates for other palettes
12347  // we will need to check for these
12348 
12349  if (pal == WEED_PALETTE_YUV888 && clamped == WEED_YUV_CLAMPING_UNCLAMPED) pal = WEED_PALETTE_RGB24;
12350  if (pal == WEED_PALETTE_YUVA8888 && clamped == WEED_YUV_CLAMPING_UNCLAMPED) pal = WEED_PALETTE_RGBA32;
12351 
12352 #ifdef USE_SWSCALE
12353  if (in_out && sws_isSupportedInput(weed_palette_to_avi_pix_fmt(pal, &clamped))) return TRUE;
12354  else if (sws_isSupportedOutput(weed_palette_to_avi_pix_fmt(pal, &clamped))) return TRUE;
12355 #endif
12356  if (pal == WEED_PALETTE_RGB24 || pal == WEED_PALETTE_RGBA32 || pal == WEED_PALETTE_BGR24 ||
12357  pal == WEED_PALETTE_BGRA32) return TRUE;
12358  return FALSE;
12359 }
12360 
12361 
12362 void lives_pixbuf_set_opaque(LiVESPixbuf * pixbuf) {
12363  unsigned char *pdata = lives_pixbuf_get_pixels(pixbuf);
12364  int row = lives_pixbuf_get_rowstride(pixbuf);
12365  int height = lives_pixbuf_get_height(pixbuf);
12366  int offs;
12367 #ifdef GUI_GTK
12368  offs = 3;
12369 #endif
12370 
12371 #ifdef GUI_QT
12372  offs = 0;
12373 #endif
12374 
12375  register int i, j;
12376  for (i = 0; i < height; i++) {
12377  for (j = offs; j < row; j += 4) {
12378  pdata[j] = 255;
12379  }
12380  pdata += row;
12381  }
12382 }
12383 
12384 
12386  int offs;
12387  boolean planar = FALSE;
12388  int pal = weed_layer_get_palette(layer);
12389  if (weed_palette_is_planar(pal)) {
12390  offs = weed_palette_get_alpha_plane(pal);
12391  planar = TRUE;
12392  } else offs = weed_palette_get_alpha_offset(pal);
12393 
12394  if (offs >= 0) {
12395  int width = weed_layer_get_width(layer);
12396  int height = weed_layer_get_height(layer);
12397  int rowstride;
12398 
12399  if (planar) {
12400  int *rowstrides = weed_layer_get_rowstrides(layer, NULL);
12401  void **pixel_data = weed_layer_get_pixel_data(layer, NULL);
12402  rowstride = rowstrides[offs];
12403  height *= weed_palette_get_plane_ratio_vertical(pal, offs);
12404  lives_memset(pixel_data, 255, rowstride * height);
12405  lives_free(rowstrides);
12406  lives_free(pixel_data);
12407  } else {
12408  ssize_t frsize, psize = pixel_size(pal);
12409  uint8_t *pixel_data = weed_layer_get_pixel_data_packed(layer);
12410  rowstride = weed_layer_get_rowstride(layer);
12411  frsize = height * rowstride;
12412  width *= psize;
12413  for (register int i = 0; i < frsize; i += rowstride) {
12414  for (register int j = offs; j < width; j += psize) {
12415  pixel_data[i + j] = 255;
12416  // *INDENT-OFF*
12417  }}}}
12418  // *INDENT-ON*
12419 }
12420 
12421 
12423  // remove any extra padding after the image data
12424  weed_layer_t *old_layer;
12425  void **pixel_data, **new_pixel_data;
12426  int *rowstrides = weed_layer_get_rowstrides(layer, NULL), *orows;
12427  int pal = weed_layer_get_palette(layer);
12428  int width = weed_layer_get_width(layer);
12429  int height = weed_layer_get_height(layer);
12430  int xheight;
12431  int crow = width * weed_palette_get_bits_per_macropixel(pal) / 8;
12432  int cxrow;
12433  int nplanes;
12434  boolean needs_change = FALSE;
12435  register int i, j;
12436 
12437  pixel_data = weed_layer_get_pixel_data(layer, &nplanes);
12438 
12439  for (i = 0; i < nplanes; i++) {
12440  cxrow = crow * weed_palette_get_plane_ratio_horizontal(pal, i);
12441  if (cxrow != rowstrides[i]) {
12442  // nth plane has extra padding
12443  needs_change = TRUE;
12444  }
12445  }
12446 
12447  if (!needs_change) {
12448  lives_free(pixel_data);
12449  lives_free(rowstrides);
12450  return TRUE;
12451  }
12452 
12454  if (!old_layer) return FALSE;
12455  if (!weed_layer_copy(old_layer, layer)) return FALSE;
12456 
12457  THREADVAR(rowstride_alignment_hint) = -1;
12459 
12460  if (!create_empty_pixel_data(layer, FALSE, TRUE)) {
12461  weed_layer_copy(layer, old_layer);
12462  weed_layer_nullify_pixel_data(old_layer);
12463  weed_layer_free(old_layer);
12464  return FALSE;
12465  }
12466 
12467  new_pixel_data = weed_layer_get_pixel_data(layer, &nplanes);
12468 
12469  if (!new_pixel_data) {
12470  weed_layer_free(old_layer);
12471  lives_free(pixel_data);
12472  lives_free(rowstrides);
12473  return FALSE;
12474  }
12475 
12476  orows = weed_layer_get_rowstrides(layer, NULL);
12477 
12478  for (i = 0; i < nplanes; i++) {
12479  xheight = height * weed_palette_get_plane_ratio_vertical(pal, i);
12480  cxrow = orows[i];
12481  for (j = 0; j < xheight; j++) {
12482  lives_memcpy((uint8_t *)new_pixel_data[i] + j * cxrow, (uint8_t *)pixel_data[i] + j * rowstrides[i], cxrow);
12483  //for (int k = 3; k < cxrow; k += 4) ((uint8_t *)new_pixel_data[i])[j * cxrow + k] = 0;
12484  }
12485  }
12486 
12487  if (nplanes > 1) weed_set_boolean_value(layer, WEED_LEAF_HOST_PIXEL_DATA_CONTIGUOUS, WEED_TRUE);
12488  weed_layer_free(old_layer);
12489  lives_free(pixel_data);
12490  lives_free(new_pixel_data);
12491  lives_free(rowstrides);
12492  lives_free(orows);
12493  return TRUE;
12494 }
12495 
12496 
12497 #ifdef USE_SWSCALE
12498 #if USE_THREADS
12499 static void *swscale_threadfunc(void *arg) {
12500  lives_sw_params *swparams = (lives_sw_params *)arg;
12501 #ifdef USE_RESTHREAD
12502  int scan = 0;
12503  if (swparams->layer) {
12504  int last = swparams->iheight * (swparams->thread_id + 1);
12505  while ((scan = weed_get_int_value(swparams->layer, WEED_LEAF_PROGSCAN, NULL)) > 0
12506  && scan < last) {
12507  lives_nanosleep(100);
12508  }
12509  }
12510 #endif
12511  swparams->ret = sws_scale(swparams->swscale, (const uint8_t *const *)swparams->ipd, swparams->irw,
12512  0, swparams->iheight, (uint8_t *const *)swparams->opd, swparams->orw);
12513 
12514  if (swparams->file_gamma != 1.) {
12515  gamma_convert_sub_layer(WEED_GAMMA_SRGB, 1. / swparams->file_gamma, swparams->layer, 0, 0, swparams->width,
12516  swparams->ret, FALSE);
12517  }
12518 
12519  return NULL;
12520 }
12521 #endif
12522 #endif
12523 
12537 boolean resize_layer(weed_layer_t *layer, int width, int height, LiVESInterpType interp, int opal_hint, int oclamp_hint) {
12538  // TODO ** - see if there is a resize plugin candidate/delegate which supports this palette :
12539  // this allows e.g libabl or a hardware rescaler
12540  LiVESPixbuf *pixbuf = NULL;
12541  LiVESPixbuf *new_pixbuf = NULL;
12542 
12543  boolean retval = TRUE;
12544 
12545  int palette = weed_layer_get_palette(layer);
12546 
12547  // original width and height (in pixels)
12548  int iwidth = weed_layer_get_width_pixels(layer);
12549  int iheight = weed_layer_get_height(layer);
12550  int iclamping = weed_layer_get_yuv_clamping(layer);
12551  int new_gamma_type = weed_layer_get_gamma(layer);
12552 
12553 #ifdef USE_SWSCALE
12554  boolean resolved = FALSE;
12555  int xpalette, xopal_hint;
12556 #endif
12557 #ifdef USE_RESTHREAD
12558  boolean progscan = FALSE;
12559  if (weed_get_int_value(layer, WEED_LEAF_PROGSCAN, NULL) > 0) progscan = TRUE;
12560 #endif
12561  if (!weed_plant_has_leaf(layer, WEED_LEAF_PIXEL_DATA)) {
12562  weed_layer_set_size(layer, width / weed_palette_get_pixels_per_macropixel(opal_hint), height);
12563  weed_layer_set_palette(layer, opal_hint);
12564  weed_layer_set_yuv_clamping(layer, oclamp_hint);
12565  return FALSE;
12566  }
12567 
12568  if (width <= 0 || height <= 0) {
12569  char *msg = lives_strdup_printf("unable to scale layer to %d x %d for palette %d\n", width, height, palette);
12570  LIVES_DEBUG(msg);
12571  lives_free(msg);
12572  return FALSE;
12573  }
12574  // #define DEBUG_RESIZE
12575 #ifdef DEBUG_RESIZE
12576  g_print("resizing layer size %d X %d with palette %s to %d X %d, hinted %s\n", iwidth, iheight,
12578  iclamping, 0), width, height, weed_palette_get_name_full(opal_hint, oclamp_hint, 0));
12579 #endif
12580 
12581  iwidth = (iwidth >> 1) << 1;
12582  iheight = (iheight >> 1) << 1;
12583 
12584  if (width < 4) width = 4;
12585  if (height < 4) height = 4;
12586 
12587  if (iwidth != width || iheight != height) {
12588  // prevent a crash in swscale
12589  width = (width >> 1) << 1;
12590  height = (height >> 1) << 1;
12591  }
12592  if (iwidth == width && iheight == height) return TRUE; // no resize needed
12593 
12594  // if in palette is a YUV palette which we cannot scale, convert to YUV888 (unclamped) or YUVA8888 (unclamped)
12595  // we can always scale these by pretending they are RGB24 and RGBA32 respectively
12597  if (!weed_palette_is_resizable(palette, iclamping, TRUE)) {
12598  if (opal_hint == WEED_PALETTE_END || weed_palette_is_yuv(opal_hint)) {
12600  convert_layer_palette(layer, WEED_PALETTE_YUVA8888, WEED_YUV_CLAMPING_UNCLAMPED);
12601  } else {
12602  convert_layer_palette(layer, WEED_PALETTE_YUV888, WEED_YUV_CLAMPING_UNCLAMPED);
12603  }
12604  oclamp_hint = iclamping = (weed_get_int_value(layer, WEED_LEAF_YUV_CLAMPING, NULL));
12605  } else {
12607  convert_layer_palette(layer, WEED_PALETTE_RGBA32, 0);
12608  } else {
12609  convert_layer_palette(layer, WEED_PALETTE_RGB24, 0);
12610  }
12611  }
12613  iwidth = weed_layer_get_width_pixels(layer);
12614  iheight = weed_layer_get_height(layer);
12615  if (iwidth == width && iheight == height) return TRUE; // no resize needed
12616 #ifdef DEBUG_RESIZE
12617  g_print("intermediate conversion 1 to %s\n", weed_palette_get_name_full(palette, iclamping, 0));
12618 #endif
12619  }
12620  }
12621 
12622  // check if we can also convert to the output palette
12623 #ifdef USE_SWSCALE
12624  // only swscale can convert and resize together
12625  if (opal_hint == WEED_PALETTE_END || !weed_palette_is_resizable(opal_hint, oclamp_hint, FALSE)) {
12626 #endif
12627  opal_hint = palette;
12628  oclamp_hint = iclamping;
12629 #ifdef USE_SWSCALE
12630  }
12631 #endif
12632 
12633  // check if we can convert to the target palette/clamping
12634  if (!weed_palette_is_resizable(opal_hint, oclamp_hint, FALSE)) {
12635  opal_hint = palette;
12636  oclamp_hint = iclamping;
12637  }
12638 
12639 #ifdef USE_SWSCALE
12640  // sws doesn't understand YUV888 or YUVA888, but if the output palette is also YUV888 or YUVA8888
12641  // then we can use unclamped values and pretend they are RGB24 and RGBA32.
12642  // Otherwise we need to convert to YUV444P and YUVA4444P.
12643 
12644  // lookup values for av_pix_fmt
12645  xpalette = palette;
12646  xopal_hint = opal_hint;
12647 
12648  if (palette == WEED_PALETTE_YUV888) {
12649  if (opal_hint == WEED_PALETTE_YUV888 || opal_hint == WEED_PALETTE_YUVA8888) {
12650  if (iclamping == WEED_YUV_CLAMPING_CLAMPED) {
12651  convert_layer_palette(layer, WEED_PALETTE_YUV888, WEED_YUV_CLAMPING_UNCLAMPED);
12652  palette = weed_layer_get_palette_yuv(layer, &iclamping, NULL, NULL);
12653 #ifdef DEBUG_RESIZE
12654  g_print("intermediate conversion 2 to %s\n", weed_palette_get_name_full(palette, iclamping, 0));
12655 #endif
12656  }
12657  if (iclamping == WEED_YUV_CLAMPING_UNCLAMPED) {
12658  xpalette = WEED_PALETTE_RGB24;
12659  oclamp_hint = WEED_YUV_CLAMPING_UNCLAMPED;
12660  resolved = TRUE;
12661  if (opal_hint == WEED_PALETTE_YUV888) {
12662  xopal_hint = WEED_PALETTE_RGB24;
12663  } else {
12664  xopal_hint = WEED_PALETTE_RGBA32;
12665  }
12666 #ifdef DEBUG_RESIZE
12667  g_print("masquerading as %s\n", weed_palette_get_name_full(xpalette, oclamp_hint, 0));
12668 #endif
12669  }
12670  }
12671  if (!resolved) {
12672  convert_layer_palette(layer, WEED_PALETTE_YUV444P, iclamping);
12673  xpalette = palette = weed_layer_get_palette_yuv(layer, &iclamping, NULL, NULL);
12674 #ifdef DEBUG_RESIZE
12675  g_print("intermediate conversion 3 to %s\n", weed_palette_get_name_full(xpalette, iclamping, 0));
12676 #endif
12677  }
12678  } else if (palette == WEED_PALETTE_YUVA8888) {
12679  if (opal_hint == WEED_PALETTE_YUV888 || opal_hint == WEED_PALETTE_YUVA8888) {
12680  if (iclamping == WEED_YUV_CLAMPING_CLAMPED) {
12681  convert_layer_palette(layer, WEED_PALETTE_YUVA8888, WEED_YUV_CLAMPING_UNCLAMPED);
12682  xpalette = palette = weed_layer_get_palette_yuv(layer, &iclamping, NULL, NULL);
12683  }
12684  if (iclamping == WEED_YUV_CLAMPING_UNCLAMPED) {
12685  xpalette = WEED_PALETTE_RGBA32;
12686  oclamp_hint = WEED_YUV_CLAMPING_UNCLAMPED;
12687  resolved = TRUE;
12688  if (opal_hint == WEED_PALETTE_YUVA8888) {
12689  xopal_hint = WEED_PALETTE_RGBA32;
12690  } else {
12691  xopal_hint = WEED_PALETTE_RGB24;
12692  }
12693 #ifdef DEBUG_RESIZE
12694  g_print("masquerading as %s\n", weed_palette_get_name_full(xpalette, oclamp_hint, 0));
12695 #endif
12696  }
12697  }
12698  if (!resolved) {
12699  convert_layer_palette(layer, WEED_PALETTE_YUVA4444P, iclamping);
12700  xpalette = palette = weed_layer_get_palette_yuv(layer, &iclamping, NULL, NULL);
12701 #ifdef DEBUG_RESIZE
12702  g_print("intermediate conversion 4 to %s\n", weed_palette_get_name_full(xpalette, iclamping, 0));
12703 #endif
12704  }
12705  }
12706 
12707  // reget these after conversion, convert width from macropixels to pixels
12709  iheight = weed_layer_get_height(layer);
12710  if (iwidth == width && iheight == height) return TRUE; // no resize needed
12711 
12712  if (opal_hint == WEED_PALETTE_YUV888) opal_hint = xopal_hint = WEED_PALETTE_YUV444P;
12713  else if (opal_hint == WEED_PALETTE_YUVA8888) opal_hint = xopal_hint = WEED_PALETTE_YUVA4444P;
12714 
12715  if (iwidth > 1 && iheight > 1 && weed_palette_is_resizable(palette, iclamping, TRUE) &&
12716  weed_palette_is_resizable(xopal_hint, oclamp_hint, FALSE)) {
12717  weed_layer_t *old_layer;
12718 
12719  void **in_pixel_data, **out_pixel_data;
12720 
12721  int *irowstrides, *orowstrides;
12722 
12723  //boolean store_ctx = FALSE;
12724 
12725  swpixfmt ipixfmt, opixfmt;
12726 
12727  int flags;
12728 
12729  const uint8_t *ipd[4], *opd[4];
12730  int irw[4], orw[4];
12731 
12732  int i;
12733 #if USE_THREADS
12734  lives_sw_params *swparams;
12735  lives_thread_t threads[prefs->nfx_threads];
12736  swsctx_block *ctxblock;
12737  int offset;
12738  int nthrds = 1;
12739 #else
12740  int scan;
12741 #endif
12742  int subspace = WEED_YUV_SUBSPACE_YUV;
12743  int inplanes, oplanes;
12744 
12747 
12748  // get current values
12749  in_pixel_data = weed_layer_get_pixel_data(layer, &inplanes);
12750  irowstrides = weed_layer_get_rowstrides(layer, NULL);
12751 
12753  weed_layer_copy(old_layer, layer);
12754 
12755  av_log_set_level(AV_LOG_FATAL);
12756 
12757  THREADVAR(rowstride_alignment_hint) = 16;
12758 
12759  if (interp == LIVES_INTERP_BEST) {
12760  if (width > iwidth || height > iheight)
12761  flags = SWS_LANCZOS; // other opts SINC, LANCZOS, SPLINE; ACCURATE_RND, BITEXACT. ERROR_DIFFUSION
12762  else
12763  flags = SWS_BICUBIC;
12764  } else if (interp == LIVES_INTERP_FAST) flags = SWS_FAST_BILINEAR;
12765  else flags = SWS_BILINEAR;
12766 
12767  ipixfmt = weed_palette_to_avi_pix_fmt(xpalette, &iclamping);
12768  opixfmt = weed_palette_to_avi_pix_fmt(xopal_hint, &oclamp_hint);
12769 
12770  for (i = 0; i < 4; i++) {
12771  // swscale always likes 4 elements, even if fewer planes are used
12772  if (i < inplanes) {
12773  ipd[i] = in_pixel_data[i];
12774  irw[i] = irowstrides[i];
12775  } else {
12776  ipd[i] = NULL;
12777  irw[i] = 0;
12778  }
12779  }
12780 
12781  if (weed_palette_is_rgb(palette) && !weed_palette_is_rgb(opal_hint) &&
12782  weed_layer_get_gamma(layer) == WEED_GAMMA_LINEAR) {
12783  // gamma correction
12784  if (prefs->apply_gamma) {
12785  gamma_convert_layer(WEED_GAMMA_SRGB, layer);
12786  }
12787  }
12788  new_gamma_type = weed_layer_get_gamma(layer);
12789 
12790  // set new values
12791 
12792  if (palette != opal_hint) {
12793  weed_layer_set_palette(layer, opal_hint);
12794  }
12795 
12796  if (weed_palette_is_yuv(opal_hint)) weed_layer_set_yuv_clamping(layer, oclamp_hint);
12797  //weed_layer_set_size(layer, width, height);
12798  weed_layer_set_size(layer, width / weed_palette_get_pixels_per_macropixel(opal_hint), height);
12800 
12801  if (!create_empty_pixel_data(layer, FALSE, TRUE)) {
12802  weed_layer_copy(layer, old_layer);
12803  weed_layer_nullify_pixel_data(old_layer);
12804  weed_layer_free(old_layer);
12805  return FALSE;
12806  }
12807 
12808  weed_layer_set_gamma(layer, new_gamma_type);
12809  out_pixel_data = weed_layer_get_pixel_data(layer, &oplanes);
12810  orowstrides = weed_layer_get_rowstrides(layer, NULL);
12811 
12813  if (new_gamma_type == WEED_GAMMA_BT709) subspace = WEED_YUV_SUBSPACE_BT709;
12814  } else if (weed_palette_is_yuv(palette)) {
12815  if (new_gamma_type == WEED_GAMMA_BT709 || weed_layer_get_yuv_subspace(old_layer) == WEED_YUV_SUBSPACE_BT709)
12816  subspace = WEED_YUV_SUBSPACE_BT709;
12817  }
12818 
12819  for (i = 0; i < 4; i++) {
12820  // swscale always likes 4 elements, even if fewer planes are used
12821  if (i < oplanes) {
12822  opd[i] = out_pixel_data[i];
12823  orw[i] = orowstrides[i];
12824  } else {
12825  opd[i] = NULL;
12826  orw[i] = 0;
12827  }
12828  }
12829 
12830  //width /= weed_palette_get_pixels_per_macropixel(palette);
12831 
12832 #if USE_THREADS
12833  while ((nthrds << 1) <= prefs->nfx_threads) {
12834  if ((height | iheight) & 3) break;
12835  nthrds <<= 1;
12836  iheight >>= 1;
12837  height >>= 1;
12838  }
12839  swparams = (lives_sw_params *)lives_calloc(nthrds, sizeof(lives_sw_params));
12840 #else
12841  // TODO - can we set the gamma ?
12842  //g_print("iht is %d, height = %d\n", iheight, height);
12843  swscale = sws_getCachedContext(swscale, iwidth, iheight, ipixfmt, width, height, opixfmt, flags, NULL, NULL, NULL);
12844  sws_setColorspaceDetails(swscale, sws_getCoefficients((subspace == WEED_YUV_SUBSPACE_BT709)
12845  ? SWS_CS_ITU709 : SWS_CS_ITU601), iclamping,
12846  sws_getCoefficients((subspace == WEED_YUV_SUBSPACE_BT709)
12847  ? SWS_CS_ITU709 : SWS_CS_ITU601), oclamp_hint, 0, 1 << 16, 1 << 16);
12848 
12849  if (!swscale) {
12850  LIVES_DEBUG("swscale is NULL !!");
12851  } else {
12852 #endif
12853 
12854 #ifdef DEBUG_RESIZE
12855  g_print("before resize with swscale: layer size %d X %d with palette %s to %d X %d, hinted %s,\n"
12856  "masquerading as %s (avpixfmt %d to avpixfmt %d)\n",
12857  iwidth, iheight, weed_palette_get_name_full(palette, iclamping, 0), width, height,
12858  weed_palette_get_name_full(opal_hint,
12859  oclamp_hint, 0),
12860  weed_palette_get_name_full(xopal_hint, oclamp_hint, 0), ipixfmt, opixfmt);
12861 #endif
12862 #if USE_THREADS
12863  ctxblock = sws_getblock(nthrds, iwidth, iheight, irw, ipixfmt, width, height, orw, opixfmt, flags,
12864  subspace, iclamping, oclamp_hint);
12865  offset = ctxblock->offset;
12866  for (int sl = 0; sl < nthrds; sl++) {
12867  swparams[sl].thread_id = sl;
12868  swparams[sl].iheight = iheight;
12869  swparams[sl].width = width;
12870  swparams[sl].file_gamma = 1.;
12871  swparams[sl].swscale = swscalep[sl + offset] =
12872  sws_getCachedContext(swscalep[sl + offset], iwidth, iheight, ipixfmt, width,
12873  height, opixfmt, flags, NULL, NULL, NULL);
12874 
12875  if (!swparams[sl].swscale) {
12876  LIVES_DEBUG("swscale is NULL !!");
12877  } else {
12878  //if (progscan) {
12879  swparams[sl].layer = layer;
12880  swparams[sl].file_gamma = weed_get_double_value(layer, "file_gamma", NULL);
12881  if (swparams[sl].file_gamma == 0.) swparams[sl].file_gamma = 1.;
12882  //} else swparams[sl].layer = NULL;
12883  sws_setColorspaceDetails(swparams[sl].swscale,
12884  sws_getCoefficients((subspace == WEED_YUV_SUBSPACE_BT709)
12885  ? SWS_CS_ITU709 : SWS_CS_ITU601), iclamping,
12886  sws_getCoefficients((subspace == WEED_YUV_SUBSPACE_BT709)
12887  ? SWS_CS_ITU709 : SWS_CS_ITU601), oclamp_hint, 0, 65536, 65536);
12888  for (i = 0; i < 4; i++) {
12889  if (i < inplanes)
12890  swparams[sl].ipd[i] =
12891  ipd[i] + (size_t)(sl * irw[i] * iheight
12893  else
12894  swparams[sl].ipd[i] = NULL;
12895 
12896  if (i < oplanes)
12897  swparams[sl].opd[i] =
12898  opd[i] + (size_t)(sl * orw[i] * height
12899  * weed_palette_get_plane_ratio_vertical(opal_hint, i));
12900  else
12901  swparams[sl].opd[i] = NULL;
12902  }
12903  swparams[sl].irw = irw;
12904  swparams[sl].orw = orw;
12905  if (sl < nthrds - 1) lives_thread_create(&threads[sl], LIVES_THRDATTR_NONE, swscale_threadfunc, &swparams[sl]);
12906  else swscale_threadfunc(&swparams[sl]);
12907  }
12908  }
12909  iheight = height;
12910  // height = 0;
12911  for (int sl = 0; sl < nthrds - 1; sl++) {
12912  if (swparams[sl].swscale) {
12913  lives_thread_join(threads[sl], NULL);
12914  height += swparams[sl].ret;
12915  } else height += iheight;
12916  }
12917 
12918  sws_freeblock(ctxblock);
12919  lives_free(swparams);
12920 
12921 #else
12922 #ifdef USE_RESTHREAD
12923  if (progscan)
12924  while ((scan = weed_get_int_value(layer, WEED_LEAF_PROGSCAN, NULL)) > 0 && scan < iheight)
12925  lives_nanosleep(100);
12926 #endif
12927  height = sws_scale(swscale, (const uint8_t *const *)ipd, irw, 0, iheight,
12928  (uint8_t *const *)opd, orw);
12929  }
12930 #endif
12931 
12932 #ifdef DEBUG_RESIZE
12933  g_print("after resize with swscale: layer size %d X %d, palette %s (assumed succesful)\n",
12934  width, height, weed_palette_get_name_full(opal_hint, oclamp_hint, 0));
12935 #endif
12936  //if (store_ctx) swscale_add_context(iwidth, iheight, width, height, ipixfmt, opixfmt, flags, swscale);
12937  //weed_layer_set_width(layer, width);
12938  weed_layer_set_height(layer, height);
12939 
12940  /* for (int gg = 0; gg < height; gg++) { */
12941  /* memset(&((uint8_t *)out_pixel_data[0])[gg * orowstrides[0]], 255, width * 3 / 2); */
12942  /* } */
12943 
12944  // this will properly free() in_pixel_data
12945  weed_layer_free(old_layer);
12946  lives_free(out_pixel_data);
12947  lives_free(orowstrides);
12948  lives_free(irowstrides);
12949  lives_free(in_pixel_data);
12950  return TRUE;
12951  }
12952 #endif
12953 
12954  // reget these after conversion, convert width from macropixels to pixels
12956  iheight = weed_layer_get_height(layer);
12957  if (iwidth == width && iheight == height) return TRUE; // no resize needed
12958 
12959  switch (palette) {
12960  // anything with 3 or 4 channels (alpha must be last)
12961 
12962  case WEED_PALETTE_YUV888:
12963  case WEED_PALETTE_YUVA8888:
12964  if (iclamping == WEED_YUV_CLAMPING_CLAMPED) {
12966  convert_layer_palette(layer, WEED_PALETTE_YUVA8888, WEED_YUV_CLAMPING_UNCLAMPED);
12967  } else {
12968  convert_layer_palette(layer, WEED_PALETTE_YUV888, WEED_YUV_CLAMPING_UNCLAMPED);
12969  }
12970  }
12971 
12972  case WEED_PALETTE_RGB24:
12973  case WEED_PALETTE_BGR24:
12974  case WEED_PALETTE_RGBA32:
12975  case WEED_PALETTE_BGRA32:
12976 
12977  // create a new pixbuf
12978  //gamma_convert_layer(cfile->gamma_type, layer);
12979  pixbuf = layer_to_pixbuf(layer, FALSE, FALSE);
12980 
12982  new_pixbuf = lives_pixbuf_scale_simple(pixbuf, width, height, interp);
12984  if (new_pixbuf) {
12985  weed_layer_set_size(layer, lives_pixbuf_get_width(new_pixbuf), lives_pixbuf_get_height(new_pixbuf));
12987  }
12988 
12989  lives_widget_object_unref(pixbuf);
12990 
12991  break;
12992  default:
12993  lives_printerr("Warning: resizing unknown palette %d\n", palette);
12994  break_me("resize_layer with unk. pal");
12995  retval = FALSE;
12996  }
12997 
12998  if (!new_pixbuf || (width != weed_layer_get_width(layer) ||
12999  height != weed_layer_get_height(layer))) {
13000  lives_printerr("unable to scale layer to %d x %d for palette %d\n", width, height, palette);
13001  retval = FALSE;
13002  } else {
13003  if (weed_plant_has_leaf(layer, WEED_LEAF_HOST_ORIG_PDATA))
13004  weed_leaf_delete(layer, WEED_LEAF_HOST_ORIG_PDATA);
13005  }
13006 
13007  if (new_pixbuf) {
13008  if (!pixbuf_to_layer(layer, new_pixbuf)) lives_widget_object_unref(new_pixbuf);
13009  }
13010 
13011  return retval;
13012 }
13013 
13014 
13015 boolean letterbox_layer(weed_layer_t *layer, int nwidth, int nheight, int width, int height,
13016  LiVESInterpType interp, int tpal, int tclamp) {
13017  // stretch or shrink layer to width/height, then overlay it in a black rectangle size nwidth/nheight
13018  // width, nwidth should be in pixels
13019  weed_layer_t *old_layer;
13020  int *rowstrides, *irowstrides;
13021  void **pixel_data;
13022  void **new_pixel_data;
13023  uint8_t *dst, *src;
13024  int lwidth, lheight;
13025  int offs_x = 0, offs_y = 0;
13026  int pal;
13027 
13028  int i;
13029 
13030  if (!width || !height || !nwidth || !nheight) return TRUE;
13031  if (nwidth < width) nwidth = width;
13032  if (nheight < height) nheight = height;
13033 
13035  if (nheight == height && nwidth == width) {
13036  resize_layer(layer, width, height, interp, tpal, tclamp);
13037  return TRUE;
13038  }
13039 
13040  pal = weed_layer_get_palette(layer);
13041  lwidth = weed_layer_get_width_pixels(layer);
13042  lheight = weed_layer_get_height(layer);
13043 
13044  if (lwidth != width || lheight != height) {
13046  if (!resize_layer(layer, width, height, interp, tpal, tclamp)) return FALSE;
13047  pal = weed_layer_get_palette(layer);
13048  lwidth = weed_layer_get_width_pixels(layer);
13049  lheight = weed_layer_get_height(layer);
13050  }
13051 
13052  // old layer will hold pointers to the original pixel data for layer
13054 
13055  if (!old_layer) return FALSE;
13056  if (!weed_layer_copy(old_layer, layer)) return FALSE;
13057 
13058  pixel_data = weed_layer_get_pixel_data(old_layer, NULL);
13059 
13060  if (!pixel_data) {
13061  weed_layer_free(old_layer);
13062  return FALSE;
13063  }
13064 
13065  width = lwidth;
13066  height = lheight;
13067  irowstrides = weed_layer_get_rowstrides(layer, NULL);
13068 
13070  weed_layer_set_size(layer, nwidth / weed_palette_get_pixels_per_macropixel(pal), nheight);
13072  if (!create_empty_pixel_data(layer, TRUE, TRUE)) goto memfail2;
13073 
13074  new_pixel_data = weed_layer_get_pixel_data(layer, NULL);
13075 
13078  nheight = weed_layer_get_height(layer);
13079 
13080  if (nwidth < width || nheight < height || !new_pixel_data) {
13082  goto memfail2;
13083  }
13084 
13085  offs_x = (nwidth - width + 1) >> 1;
13086  offs_y = (nheight - height + 1) >> 1;
13087 
13088  rowstrides = weed_layer_get_rowstrides(layer, NULL);
13089 
13090  switch (pal) {
13091  // 3 byte pixels, packed
13092  case WEED_PALETTE_RGB24:
13093  case WEED_PALETTE_BGR24:
13094  case WEED_PALETTE_YUV888:
13095  width *= 3;
13096  dst = (uint8_t *)new_pixel_data[0] + offs_y * rowstrides[0] + offs_x * 3;
13097  src = (uint8_t *)pixel_data[0];
13098  for (i = 0; i < height; i++) {
13099  lives_memcpy(dst, src, width);
13100  dst += rowstrides[0];
13101  src += irowstrides[0];
13102  }
13103  break;
13104 
13105  // 4 byte pixels, packed
13106  case WEED_PALETTE_UYVY:
13107  case WEED_PALETTE_YUYV:
13108  offs_x >>= 1;
13109  width >>= 1;
13110 
13111  case WEED_PALETTE_RGBA32:
13112  case WEED_PALETTE_BGRA32:
13113  case WEED_PALETTE_ARGB32:
13114  case WEED_PALETTE_YUVA8888:
13115 
13116  width *= 4;
13117  dst = (uint8_t *)new_pixel_data[0] + offs_y * rowstrides[0] + offs_x * 4;
13118  src = (uint8_t *)pixel_data[0];
13119  for (i = 0; i < height; i++) {
13120  lives_memcpy(dst, src, width);
13121  dst += rowstrides[0];
13122  src += irowstrides[0];
13123  }
13124  break;
13125 
13126  case WEED_PALETTE_YUV411:
13127  width *= 6;
13128  dst = (uint8_t *)new_pixel_data[0] + offs_y * rowstrides[0] + offs_x * 6;
13129  src = (uint8_t *)pixel_data[0];
13130  for (i = 0; i < height; i++) {
13131  lives_memcpy(dst, src, width);
13132  dst += rowstrides[0];
13133  src += irowstrides[0];
13134  }
13135  break;
13136 
13137  case WEED_PALETTE_YUV444P:
13138  dst = (uint8_t *)new_pixel_data[0] + offs_y * rowstrides[0] + offs_x;
13139  src = (uint8_t *)pixel_data[0];
13140  for (i = 0; i < height; i++) {
13141  lives_memcpy(dst, src, width);
13142  dst += rowstrides[0];
13143  src += irowstrides[0];
13144  }
13145  dst = (uint8_t *)new_pixel_data[1] + offs_y * rowstrides[1] + offs_x;
13146  src = (uint8_t *)pixel_data[1];
13147  for (i = 0; i < height; i++) {
13148  lives_memcpy(dst, src, width);
13149  dst += rowstrides[1];
13150  src += irowstrides[1];
13151  }
13152  dst = (uint8_t *)new_pixel_data[2] + offs_y * rowstrides[2] + offs_x;
13153  src = (uint8_t *)pixel_data[2];
13154  for (i = 0; i < height; i++) {
13155  lives_memcpy(dst, src, width);
13156  dst += rowstrides[2];
13157  src += irowstrides[2];
13158  }
13159  break;
13160 
13161  case WEED_PALETTE_YUVA4444P:
13162  dst = (uint8_t *)new_pixel_data[0] + offs_y * rowstrides[0] + offs_x;
13163  src = (uint8_t *)pixel_data[0];
13164  for (i = 0; i < height; i++) {
13165  lives_memcpy(dst, src, width);
13166  dst += rowstrides[0];
13167  src += irowstrides[0];
13168  }
13169  dst = (uint8_t *)new_pixel_data[1] + offs_y * rowstrides[1] + offs_x;
13170  src = (uint8_t *)pixel_data[1];
13171  for (i = 0; i < height; i++) {
13172  lives_memcpy(dst, src, width);
13173  dst += rowstrides[1];
13174  src += irowstrides[1];
13175  }
13176  dst = (uint8_t *)new_pixel_data[2] + offs_y * rowstrides[2] + offs_x;
13177  src = (uint8_t *)pixel_data[2];
13178  for (i = 0; i < height; i++) {
13179  lives_memcpy(dst, src, width);
13180  dst += rowstrides[2];
13181  src += irowstrides[2];
13182  }
13183  dst = (uint8_t *)new_pixel_data[3] + offs_y * rowstrides[3] + offs_x;
13184  src = (uint8_t *)pixel_data[3];
13185  for (i = 0; i < height; i++) {
13186  lives_memcpy(dst, src, width);
13187  dst += rowstrides[3];
13188  src += irowstrides[3];
13189  }
13190  break;
13191 
13192  case WEED_PALETTE_YUV422P:
13193  dst = (uint8_t *)new_pixel_data[0] + offs_y * rowstrides[0] + offs_x;
13194  src = (uint8_t *)pixel_data[0];
13195  for (i = 0; i < height; i++) {
13196  lives_memcpy(dst, src, width);
13197  dst += rowstrides[0];
13198  src += irowstrides[0];
13199  }
13200  height >>= 1;
13201  offs_x >>= 1;
13202  dst = (uint8_t *)new_pixel_data[1] + offs_y * rowstrides[1] + offs_x;
13203  src = (uint8_t *)pixel_data[1];
13204  for (i = 0; i < height; i++) {
13205  lives_memcpy(dst, src, width);
13206  dst += rowstrides[1];
13207  src += irowstrides[1];
13208  }
13209  dst = (uint8_t *)new_pixel_data[2] + offs_y * rowstrides[2] + offs_x;
13210  src = (uint8_t *)pixel_data[2];
13211  for (i = 0; i < height; i++) {
13212  lives_memcpy(dst, src, width);
13213  dst += rowstrides[2];
13214  src += irowstrides[2];
13215  }
13216  break;
13217 
13218  case WEED_PALETTE_YUV420P:
13219  case WEED_PALETTE_YVU420P:
13220  dst = (uint8_t *)new_pixel_data[0] + offs_y * rowstrides[0] + offs_x;
13221  src = (uint8_t *)pixel_data[0];
13222  for (i = 0; i < height; i++) {
13223  lives_memcpy(dst, src, width);
13224  dst += rowstrides[0];
13225  src += irowstrides[0];
13226  }
13227  height >>= 1;
13228  offs_x >>= 1;
13229  width >>= 1;
13230  offs_y >>= 1;
13231  dst = (uint8_t *)new_pixel_data[1] + offs_y * rowstrides[1] + offs_x;
13232  src = (uint8_t *)pixel_data[1];
13233  for (i = 0; i < height; i++) {
13234  lives_memcpy(dst, src, width);
13235  dst += rowstrides[1];
13236  src += irowstrides[1];
13237  }
13238  dst = (uint8_t *)new_pixel_data[2] + offs_y * rowstrides[2] + offs_x;
13239  src = (uint8_t *)pixel_data[2];
13240  for (i = 0; i < height; i++) {
13241  lives_memcpy(dst, src, width);
13242  dst += rowstrides[2];
13243  src += irowstrides[2];
13244  }
13245  break;
13246 
13247  case WEED_PALETTE_RGBFLOAT:
13248  width *= 3 * sizeof(float);
13249  dst = (uint8_t *)new_pixel_data[0] + offs_y * rowstrides[0] + offs_x * 3 * sizeof(float);
13250  src = (uint8_t *)pixel_data[0];
13251  for (i = 0; i < height; i++) {
13252  lives_memcpy(dst, src, width);
13253  dst += rowstrides[0];
13254  src += irowstrides[0];
13255  }
13256  break;
13257 
13258  case WEED_PALETTE_RGBAFLOAT:
13259  width *= 4 * sizeof(float);
13260  dst = (uint8_t *)new_pixel_data[0] + offs_y * rowstrides[0] + offs_x * 4 * sizeof(float);
13261  src = (uint8_t *)pixel_data[0];
13262  for (i = 0; i < height; i++) {
13263  lives_memcpy(dst, src, width);
13264  dst += rowstrides[0];
13265  src += irowstrides[0];
13266  }
13267  break;
13268 
13269  case WEED_PALETTE_AFLOAT:
13270  width *= sizeof(float);
13271  dst = (uint8_t *)new_pixel_data[0] + offs_y * rowstrides[0] + offs_x * sizeof(float);
13272  src = (uint8_t *)pixel_data[0];
13273  for (i = 0; i < height; i++) {
13274  lives_memcpy(dst, src, width);
13275  dst += rowstrides[0];
13276  src += irowstrides[0];
13277  }
13278  break;
13279 
13280  case WEED_PALETTE_A8:
13281  dst = (uint8_t *)new_pixel_data[0] + offs_y * rowstrides[0] + offs_x;
13282  src = (uint8_t *)pixel_data[0];
13283  for (i = 0; i < height; i++) {
13284  lives_memcpy(dst, src, width);
13285  dst += rowstrides[0];
13286  src += irowstrides[0];
13287  }
13288  break;
13289 
13290  // assume offs_x and width is a multiple of 8
13291  case WEED_PALETTE_A1:
13292  width >>= 3;
13293  dst = (uint8_t *)new_pixel_data[0] + offs_y * rowstrides[0] + (offs_x >> 3);
13294  src = (uint8_t *)pixel_data[0];
13295  for (i = 0; i < height; i++) {
13296  lives_memcpy(dst, src, width);
13297  dst += rowstrides[0];
13298  src += irowstrides[0];
13299  }
13300  break;
13301  }
13302 
13305  weed_layer_nullify_pixel_data(old_layer);
13306  }
13308  weed_layer_free(old_layer);
13309  lives_free(pixel_data);
13310  lives_free(new_pixel_data);
13311  lives_free(irowstrides);
13312  lives_free(rowstrides);
13313  return TRUE;
13314 
13315 memfail2:
13317  weed_layer_copy(layer, old_layer);
13318  weed_layer_nullify_pixel_data(old_layer);
13319  weed_layer_free(old_layer);
13320  lives_free(pixel_data);
13321  lives_free(irowstrides);
13322  return FALSE;
13323 }
13324 
13325 
13347 boolean pixbuf_to_layer(weed_layer_t *layer, LiVESPixbuf * pixbuf) {
13348  size_t framesize;
13349  void *pixel_data;
13350  void *in_pixel_data;
13351  int rowstride;
13352  int width;
13353  int height;
13354  int nchannels, palette;
13355 
13356  if (!LIVES_IS_PIXBUF(pixbuf)) {
13357  weed_layer_set_size(layer, 0, 0);
13358  weed_set_int_value(layer, WEED_LEAF_ROWSTRIDES, 0);
13360  return FALSE;
13361  }
13362 
13363  rowstride = lives_pixbuf_get_rowstride(pixbuf);
13364  width = lives_pixbuf_get_width(pixbuf);
13365  height = lives_pixbuf_get_height(pixbuf);
13366  nchannels = lives_pixbuf_get_n_channels(pixbuf);
13367 
13368  weed_layer_set_width(layer, width);
13369  weed_layer_set_height(layer, height);
13370  weed_set_int_value(layer, WEED_LEAF_ROWSTRIDES, rowstride);
13371 
13372  if (!weed_plant_has_leaf(layer, WEED_LEAF_CURRENT_PALETTE)) {
13373 #ifdef GUI_GTK
13374  if (nchannels == 4) weed_set_int_value(layer, WEED_LEAF_CURRENT_PALETTE, WEED_PALETTE_RGBA32);
13375  else weed_set_int_value(layer, WEED_LEAF_CURRENT_PALETTE, WEED_PALETTE_RGB24);
13376 #endif
13377  }
13378 
13379  if (rowstride == get_last_pixbuf_rowstride_value(width, nchannels)) {
13380  in_pixel_data = (void *)lives_pixbuf_get_pixels(pixbuf);
13382  weed_set_voidptr_value(layer, WEED_LEAF_PIXEL_DATA, in_pixel_data);
13383  weed_set_voidptr_value(layer, WEED_LEAF_HOST_PIXBUF_SRC, pixbuf);
13384  palette = weed_get_int_value(layer, WEED_LEAF_CURRENT_PALETTE, NULL);
13385  if (weed_palette_is_rgb(palette)) weed_set_int_value(layer, WEED_LEAF_GAMMA_TYPE, WEED_GAMMA_SRGB);
13386  return TRUE;
13387  }
13388 
13389  framesize = ALIGN_CEIL(rowstride * height, 32);
13390  pixel_data = lives_calloc(framesize >> 5, 32);
13391 
13392  if (pixel_data) {
13393  in_pixel_data = (void *)lives_pixbuf_get_pixels_readonly(pixbuf);
13394  lives_memcpy(pixel_data, in_pixel_data, rowstride * (height - 1));
13395  // this part is needed because layers always have a memory size height*rowstride, whereas gdkpixbuf can have
13396  // a shorter last row
13397  lives_memcpy((uint8_t *)pixel_data + rowstride * (height - 1), (uint8_t *)in_pixel_data + rowstride * (height - 1),
13398  get_last_pixbuf_rowstride_value(width, nchannels));
13399  }
13400 
13402  weed_set_voidptr_value(layer, WEED_LEAF_PIXEL_DATA, pixel_data);
13403 
13404  palette = weed_get_int_value(layer, WEED_LEAF_CURRENT_PALETTE, NULL);
13405  if (weed_palette_is_rgb(palette)) weed_set_int_value(layer, WEED_LEAF_GAMMA_TYPE, WEED_GAMMA_SRGB);
13406 
13407  return FALSE;
13408 }
13409 
13410 
13412  if (pal == WEED_PALETTE_RGB24) return WEED_PALETTE_BGR24;
13413  if (pal == WEED_PALETTE_RGBA32) return WEED_PALETTE_BGRA32;
13414  if (pal == WEED_PALETTE_BGR24) return WEED_PALETTE_RGB24;
13415  if (pal == WEED_PALETTE_BGRA32) return WEED_PALETTE_RGBA32;
13416  return WEED_PALETTE_END;
13417 }
13418 
13427 boolean consider_swapping(int *inpal, int *outpal) {
13428  if (*inpal == *outpal) return FALSE;
13429  if (!weed_palette_is_rgb(*inpal) || !weed_palette_is_rgb(*outpal)) return FALSE;
13430  switch (*inpal) {
13431  case WEED_PALETTE_RGB24:
13432  case WEED_PALETTE_RGBA32:
13433  switch (*outpal) {
13434  case WEED_PALETTE_BGR24:
13435  case WEED_PALETTE_BGRA32:
13436  *inpal = swap_red_blue(*inpal);
13437  return TRUE;
13438  default: return FALSE;
13439  }
13440  case WEED_PALETTE_BGR24:
13441  case WEED_PALETTE_BGRA32:
13442  switch (*outpal) {
13443  case WEED_PALETTE_RGB24:
13444  case WEED_PALETTE_RGBA32:
13445  case WEED_PALETTE_ARGB32:
13446  *inpal = swap_red_blue(*inpal);
13447  return TRUE;
13448  default: return FALSE;
13449  }
13450  case WEED_PALETTE_ARGB32:
13452  switch (*outpal) {
13453  case WEED_PALETTE_BGR24:
13454  case WEED_PALETTE_BGRA32:
13455  *outpal = swap_red_blue(*outpal);
13456  return TRUE;
13457  default: return FALSE;
13458  }
13459  default:
13460  break;
13461  }
13462  return FALSE;
13463 }
13464 
13465 
13466 
13467 #ifdef GUI_GTK
13468 
13473 lives_painter_t *layer_to_lives_painter(weed_layer_t *layer) {
13474  lives_painter_surface_t *surf;
13475  lives_painter_t *cairo;
13476  lives_painter_format_t cform;
13477  uint8_t *src, *dst, *pixel_data;
13478 
13479  int irowstride, orowstride;
13480  int width, widthx;
13481  int height, pal;
13482 
13483  register int i;
13484 
13485  if (weed_plant_has_leaf(layer, WEED_LEAF_HOST_SURFACE_SRC)) {
13486  surf = (lives_painter_surface_t *)weed_get_voidptr_value(layer, WEED_LEAF_HOST_SURFACE_SRC, NULL);
13487  } else {
13488  width = weed_layer_get_width(layer);
13489  pal = weed_layer_get_palette(layer);
13490  if (pal == WEED_PALETTE_A8) {
13491  cform = LIVES_PAINTER_FORMAT_A8;
13492  widthx = width;
13493  } else if (pal == WEED_PALETTE_A1) {
13494  cform = LIVES_PAINTER_FORMAT_A1;
13495  widthx = width >> 3;
13496  } else {
13497  cform = LIVES_PAINTER_COLOR_PALETTE(capable->byte_order);
13498  convert_layer_palette(layer, cform, 0);
13499  cform = LIVES_PAINTER_FORMAT_ARGB32;
13500  widthx = width << 2;
13501  }
13502 
13503  height = weed_layer_get_height(layer);
13504  irowstride = weed_layer_get_rowstride(layer);
13505  orowstride = lives_painter_format_stride_for_width(cform, width);
13506  src = (uint8_t *)weed_layer_get_pixel_data_packed(layer);
13507 
13508  if (irowstride == orowstride && !weed_plant_has_leaf(layer, WEED_LEAF_HOST_PIXBUF_SRC) &&
13509  !weed_plant_has_leaf(layer, WEED_LEAF_HOST_ORIG_PDATA)) {
13510  pixel_data = src;
13511  } else {
13512  dst = pixel_data = (uint8_t *)lives_calloc(1, height * orowstride);
13513  if (!pixel_data) return NULL;
13514  for (i = 0; i < height; i++) {
13515  lives_memcpy(dst, src, widthx);
13516  dst += orowstride;
13517  src += irowstride;
13518  }
13520  weed_layer_set_pixel_data_packed(layer, pixel_data);
13521  weed_layer_set_rowstride(layer, orowstride);
13522  }
13523 
13524  if (weed_palette_has_alpha(pal)) {
13525  int flags = weed_get_int_value(layer, WEED_LEAF_FLAGS, NULL);
13526  if (!(flags & WEED_LAYER_ALPHA_PREMULT)) {
13527  // if we have post-multiplied alpha, pre multiply
13528  alpha_unpremult(layer, FALSE);
13529  flags |= WEED_LAYER_ALPHA_PREMULT;
13530  weed_set_int_value(layer, WEED_LEAF_FLAGS, flags);
13531  }
13532  }
13533  surf = lives_painter_image_surface_create_for_data(pixel_data, cform, width, height, orowstride);
13534  }
13535  if (!surf) return NULL;
13536 
13537  cairo = lives_painter_create_from_surface(surf); // surf is refcounted
13538 #ifdef DEBUG_CAIRO_SURFACE
13539  g_print("VALaa1 = %d %p\n", cairo_surface_get_reference_count(surf), surf);
13540 #endif
13541  weed_set_voidptr_value(layer, WEED_LEAF_PIXEL_DATA, lives_painter_image_surface_get_data(surf));
13542  weed_set_voidptr_value(layer, WEED_LEAF_HOST_SURFACE_SRC, surf);
13543  return cairo;
13544 }
13545 
13546 
13549 boolean lives_painter_to_layer(lives_painter_t *cr, weed_layer_t *layer) {
13550  // updates a weed_layer from a cr
13551  void *src;
13552  lives_painter_surface_t *surface = lives_painter_get_target(cr), *xsurface = NULL;
13553  lives_painter_format_t cform;
13554 
13555  int width, height, rowstride;
13556 
13558  lives_painter_surface_flush(surface);
13559 
13560  if (weed_plant_has_leaf(layer, WEED_LEAF_HOST_SURFACE_SRC)) {
13561  xsurface = (lives_painter_surface_t *)weed_get_voidptr_value(layer, WEED_LEAF_HOST_SURFACE_SRC, NULL);
13562  }
13563  if (xsurface != surface) weed_layer_pixel_data_free(layer);
13564 
13565  src = lives_painter_image_surface_get_data(surface);
13566 
13568  weed_set_voidptr_value(layer, WEED_LEAF_HOST_SURFACE_SRC, surface);
13569 
13570 #ifdef DEBUG_CAIRO_SURFACE
13571  g_print("VALaa2 = %d %p\n", cairo_surface_get_reference_count(surface), surface);
13572 #endif
13575 
13576  width = lives_painter_image_surface_get_width(surface);
13577  height = lives_painter_image_surface_get_height(surface);
13578  rowstride = lives_painter_image_surface_get_stride(surface);
13579 
13580  weed_layer_set_rowstride(layer, rowstride);
13581  weed_layer_set_size(layer, width, height);
13582 
13583  cform = lives_painter_image_surface_get_format(surface);
13584 
13585  switch (cform) {
13586  case LIVES_PAINTER_FORMAT_ARGB32:
13587  if (capable->byte_order == LIVES_BIG_ENDIAN) {
13588  weed_layer_set_palette(layer, WEED_PALETTE_ARGB32);
13589  } else {
13590  weed_layer_set_palette(layer, WEED_PALETTE_BGRA32);
13591  }
13592  weed_layer_set_gamma(layer, WEED_GAMMA_SRGB);
13593 
13594  if (prefs->alpha_post) {
13596  alpha_unpremult(layer, TRUE);
13597  } else {
13598  int flags = weed_layer_get_flags(layer);
13599  flags |= WEED_LAYER_ALPHA_PREMULT;
13600  weed_layer_set_flags(layer, flags);
13601  }
13602  break;
13603 
13604  case LIVES_PAINTER_FORMAT_A8:
13605  weed_layer_set_palette(layer, WEED_PALETTE_A8);
13606  break;
13607 
13608  case LIVES_PAINTER_FORMAT_A1:
13609  weed_layer_set_palette(layer, WEED_PALETTE_A1);
13610  break;
13611 
13612  default:
13613  break;
13614  }
13615 
13616  return TRUE;
13617 }
13618 
13619 #endif
13620 
13621 
13622 int resize_all(int fileno, int width, int height, lives_img_type_t imgtype, boolean do_back, int *nbad, int *nmiss) {
13623  LiVESPixbuf *pixbuf;
13624  LiVESError *error = NULL;
13625  lives_clip_t *sfile;
13626  lives_img_type_t ximgtype;
13627  weed_layer_t *layer;
13628  char *fname;
13629  int miss = 0, bad = 0;
13630  int nimty = (int)N_IMG_TYPES;
13631  int j, nres = 0;
13632 
13634  if (!IS_VALID_CLIP(fileno)) return 0;
13635  sfile = mainw->files[fileno];
13636  for (int i = 0; i < sfile->frames; i++) {
13637  threaded_dialog_spin((double)i / (double)sfile->frames);
13638  if (mainw->cancelled) return nres;
13639  if (sfile->frame_index && sfile->frame_index[i] != -1) continue;
13640  ximgtype = imgtype;
13641  fname = make_image_file_name(sfile, i + 1, get_image_ext_for_type(ximgtype));
13642  if (!lives_file_test(fname, LIVES_FILE_TEST_EXISTS)) {
13643  // check all img_types
13644  for (j = 1; j < nimty; j++) {
13645  ximgtype = (lives_img_type_t)j;
13646  if (ximgtype == imgtype) continue;
13647  lives_free(fname);
13648  fname = make_image_file_name(sfile, i + 1, get_image_ext_for_type(ximgtype));
13649  if (lives_file_test(fname, LIVES_FILE_TEST_EXISTS)) break;
13650  }
13651  if (j == nimty) {
13652  miss++;
13653  lives_free(fname);
13654  continue;
13655  } else bad++;
13656  }
13658  weed_set_int_value(layer, WEED_LEAF_HOST_FLAGS, LIVES_LAYER_LOAD_IF_NEEDS_RESIZE);
13659  if (!weed_layer_create_from_file_progressive(layer, fname, width, height, WEED_PALETTE_END,
13660  get_image_ext_for_type(ximgtype))) {
13661  lives_free(fname);
13662  miss++;
13663  continue;
13664  }
13665 
13666  if (weed_layer_get_width(layer) == width
13667  && weed_layer_get_height(layer) == height) {
13668  weed_layer_free(layer);
13669  lives_free(fname);
13670  continue;
13671  }
13672 
13673  if (!resize_layer(layer, width, height, LIVES_INTERP_BEST, WEED_PALETTE_END,
13674  WEED_YUV_CLAMPING_UNCLAMPED)) {
13675  weed_layer_free(layer);
13676  lives_free(fname);
13677  continue;
13678  }
13679  pixbuf = layer_to_pixbuf(layer, TRUE, FALSE);
13680  weed_layer_free(layer);
13681  if (pixbuf) {
13682  if (do_back) {
13683  char *fname_bak = make_image_file_name(sfile, i + 1, LIVES_FILE_EXT_BAK);
13684  if (lives_file_test(fname_bak, LIVES_FILE_TEST_EXISTS)) lives_rm(fname_bak);
13685  lives_mv(fname, fname_bak);
13686  }
13687  lives_pixbuf_save(pixbuf, fname, ximgtype, 100 - prefs->ocp, width, height, &error);
13688  lives_widget_object_unref(pixbuf);
13689  if (error) {
13690  lives_error_free(error);
13691  error = NULL;
13692  lives_free(fname);
13693  miss++;
13694  continue;
13695  }
13696  nres++;
13697  }
13698  lives_free(fname);
13699  }
13700  if (nbad) *nbad = bad;
13701  if (nmiss) *nmiss = miss;
13702  return nres;
13703 }
13704 
13705 
13708 weed_layer_t *weed_layer_create(int width, int height, int *rowstrides, int palette) {
13710 
13711  weed_layer_set_width(layer, width);
13712  weed_layer_set_height(layer, height);
13713 
13714  if (palette != WEED_PALETTE_END) {
13716  if (rowstrides) weed_layer_set_rowstrides(layer, rowstrides, weed_palette_get_nplanes(palette));
13717  }
13718  return layer;
13719 }
13720 
13721 
13722 weed_layer_t *weed_layer_create_full(int width, int height, int *rowstrides, int palette,
13723  int YUV_clamping, int YUV_sampling, int YUV_subspace, int gamma_type) {
13724  weed_layer_t *layer = weed_layer_create(width, height, rowstrides, palette);
13725  weed_layer_set_palette_yuv(layer, palette, YUV_clamping, YUV_sampling, YUV_subspace);
13726  weed_layer_set_gamma(layer, gamma_type);
13727  return layer;
13728 }
13729 
13730 
13740  weed_layer_t *layer;
13741  void **pd_array = NULL;
13742 
13743  if (!slayer || (!WEED_IS_LAYER(slayer) && !WEED_PLANT_IS_CHANNEL(slayer))) return NULL;
13744 
13745  if (dlayer) {
13746  if (!WEED_IS_LAYER(dlayer) && !WEED_PLANT_IS_CHANNEL(dlayer)) return NULL;
13747  layer = dlayer;
13748  }
13749 
13750  pd_array = weed_layer_get_pixel_data(slayer, NULL);
13751 
13752  if (!dlayer) {
13754  int height = weed_layer_get_height(slayer);
13755  int width = weed_layer_get_width(slayer);
13756  int palette = weed_layer_get_palette(slayer);
13757  int *rowstrides = weed_layer_get_rowstrides(slayer, NULL);
13758  if (height <= 0 || width < 0 || !rowstrides || !weed_palette_is_valid(palette)) {
13759  if (pd_array) lives_free(pd_array);
13760  return NULL;
13761  } else {
13762  layer = weed_layer_create(width, height, rowstrides, palette);
13763  if (!pd_array) weed_layer_nullify_pixel_data(layer);
13764  else copy_pixel_data(layer, slayer, 0);
13765  lives_free(rowstrides);
13766  }
13767  } else {
13769  weed_leaf_dup(layer, slayer, WEED_LEAF_ROWSTRIDES);
13770  weed_leaf_dup(layer, slayer, WEED_LEAF_PIXEL_DATA);
13771  weed_leaf_dup(layer, slayer, WEED_LEAF_NATURAL_SIZE);
13772  weed_leaf_copy_or_delete(layer, WEED_LEAF_HEIGHT, slayer);
13773  weed_leaf_copy_or_delete(layer, WEED_LEAF_WIDTH, slayer);
13774  weed_leaf_copy_or_delete(layer, WEED_LEAF_CURRENT_PALETTE, slayer);
13775  if (pd_array) {
13780  }
13781  if (pd_array) {
13782  if (weed_leaf_set_flags(layer, WEED_LEAF_PIXEL_DATA,
13783  weed_leaf_get_flags(slayer, WEED_LEAF_PIXEL_DATA)));
13784  }
13785  }
13786 
13787  weed_leaf_copy_or_delete(layer, WEED_LEAF_GAMMA_TYPE, slayer);
13788  weed_leaf_copy_or_delete(layer, WEED_LEAF_FLAGS, slayer);
13789  weed_leaf_copy_or_delete(layer, WEED_LEAF_YUV_CLAMPING, slayer);
13790  weed_leaf_copy_or_delete(layer, WEED_LEAF_YUV_SUBSPACE, slayer);
13791  weed_leaf_copy_or_delete(layer, WEED_LEAF_YUV_SAMPLING, slayer);
13792  weed_leaf_copy_or_delete(layer, WEED_LEAF_PIXEL_ASPECT_RATIO, slayer);
13793 
13794  if (pd_array) lives_free(pd_array);
13795  return layer;
13796 }
13797 
13798 
13800  int refs;
13801  if (!layer) return 0;
13802  refs = weed_get_int_value(layer, WEED_LEAF_HOST_REFS, NULL);
13803  return refs;
13804 }
13805 
13806 
13820  void **pixel_data;
13821  int pd_elements;
13822 
13823  if (!layer) return;
13824 
13825  if (weed_leaf_get_flags(layer, WEED_LEAF_PIXEL_DATA) & LIVES_FLAG_MAINTAIN_VALUE)
13826  return;
13827 
13828  if (weed_get_boolean_value(layer, WEED_LEAF_HOST_ORIG_PDATA, NULL) == WEED_TRUE)
13829  return;
13830 
13831  if (weed_layer_count_refs(layer) > 1) {
13833  return;
13834  }
13835 
13836  if ((pixel_data = weed_layer_get_pixel_data(layer, &pd_elements)) != NULL) {
13837  if (pd_elements > 0) {
13838  if (weed_plant_has_leaf(layer, WEED_LEAF_HOST_PIXBUF_SRC)) {
13839  LiVESPixbuf *pixbuf = (LiVESPixbuf *)weed_get_voidptr_value(layer, WEED_LEAF_HOST_PIXBUF_SRC, NULL);
13840  if (pixbuf) lives_widget_object_unref(pixbuf);
13841  } else {
13842  if (weed_plant_has_leaf(layer, WEED_LEAF_HOST_SURFACE_SRC)) {
13843  lives_painter_surface_t *surface = (lives_painter_surface_t *)weed_get_voidptr_value(layer,
13845  if (surface) {
13846  // this is where most surfaces die, as we convert from BGRA -> RGB
13847  uint8_t *pdata = lives_painter_image_surface_get_data(surface);
13848 #ifdef DEBUG_CAIRO_SURFACE
13849  g_print("VALaa23rrr = %d %p\n", cairo_surface_get_reference_count(surface), surface);
13850 #endif
13851  // call twice to remove our extra ref.
13854  lives_free(pdata);
13855  }
13856  } else {
13857  if (weed_get_boolean_value(layer, WEED_LEAF_HOST_PIXEL_DATA_CONTIGUOUS, NULL) == WEED_TRUE) {
13858  pd_elements = 1;
13859  }
13860  for (int i = 0; i < pd_elements; i++) {
13861  if (pixel_data[i]) lives_free(pixel_data[i]);
13862  }
13863  }
13864  }
13865  lives_free(pixel_data);
13867  }
13868  }
13869 
13870  weed_leaf_delete(layer, WEED_LEAF_HOST_PIXEL_DATA_CONTIGUOUS);
13871  weed_leaf_delete(layer, WEED_LEAF_HOST_PIXBUF_SRC);
13872  weed_leaf_delete(layer, WEED_LEAF_HOST_SURFACE_SRC);
13873 }
13874 
13875 
13884  if (weed_layer_unref(layer)) return layer;
13885  return NULL;
13886 }
13887 
13889  int refs;
13890  if (!layer) return 0;
13891  refs = weed_get_int_value(layer, WEED_LEAF_HOST_REFS, NULL) - 1;
13892  weed_set_int_value(layer, WEED_LEAF_HOST_REFS, refs);
13893  if (refs > 0) return refs;
13895  weed_plant_free(layer);
13896  return 0;
13897 }
13898 
13900  int refs;
13901  if (!layer) return 0;
13902  refs = weed_get_int_value(layer, WEED_LEAF_HOST_REFS, NULL);
13903  weed_set_int_value(layer, WEED_LEAF_HOST_REFS, ++refs);
13904  return refs;
13905 }
13906 
13907 
13909  if (nplanes) *nplanes = 0;
13910  if (!layer) return NULL;
13911  return weed_get_voidptr_array_counted(layer, WEED_LEAF_PIXEL_DATA, nplanes);
13912 }
13913 
13914 
13916  if (!layer) return NULL;
13917  return (uint8_t *)weed_get_voidptr_value(layer, WEED_LEAF_PIXEL_DATA, NULL);
13918 }
13919 
13920 
13922  if (naudchans) *naudchans = 0;
13923  if (!layer) return NULL;
13924  return (float **)weed_get_voidptr_array_counted(layer, WEED_LEAF_AUDIO_DATA, naudchans);
13925 }
13926 
13927 
13929  if (nplanes) *nplanes = 0;
13930  if (!layer) return NULL;
13931  return weed_get_int_array_counted(layer, WEED_LEAF_ROWSTRIDES, nplanes);
13932 }
13933 
13934 
13936  if (!layer) return 0;
13937  return weed_get_int_value(layer, WEED_LEAF_ROWSTRIDES, NULL);
13938 }
13939 
13940 
13942  if (!layer) return -1;
13943  return weed_get_int_value(layer, WEED_LEAF_WIDTH, NULL);
13944 }
13945 
13946 
13948  if (!layer) return -1;
13950 }
13951 
13952 
13954  if (!layer) return -1;
13955  return weed_get_int_value(layer, WEED_LEAF_HEIGHT, NULL);
13956 }
13957 
13958 
13960  if (!layer) return 0;
13961  return weed_get_int_value(layer, WEED_LEAF_YUV_CLAMPING, NULL);
13962 }
13963 
13964 
13966  if (!layer) return 0;
13967  return weed_get_int_value(layer, WEED_LEAF_YUV_SAMPLING, NULL);
13968 }
13969 
13970 
13972  if (!layer) return 0;
13973  return weed_get_int_value(layer, WEED_LEAF_YUV_SUBSPACE, NULL);
13974 }
13975 
13976 
13978  if (!layer) return WEED_PALETTE_END;
13979  return weed_get_int_value(layer, WEED_LEAF_CURRENT_PALETTE, NULL);
13980 }
13981 
13982 
13983 LIVES_GLOBAL_INLINE int weed_layer_get_palette_yuv(weed_layer_t *layer, int *clamping, int *sampling, int *subspace) {
13984  if (!layer) return WEED_PALETTE_END;
13985  if (clamping) *clamping = weed_layer_get_yuv_clamping(layer);
13986  if (sampling) *sampling = weed_layer_get_yuv_sampling(layer);
13987  if (subspace) *subspace = weed_layer_get_yuv_subspace(layer);
13988  return weed_get_int_value(layer, WEED_LEAF_CURRENT_PALETTE, NULL);
13989 }
13990 
13991 
13993  if (!WEED_IS_LAYER(layer)) return 0;
13994  return weed_get_int_value(layer, WEED_LEAF_AUDIO_RATE, NULL);
13995 }
13996 
13997 
13999  if (!WEED_IS_LAYER(layer)) return 0;
14000  return weed_get_int_value(layer, WEED_LEAF_AUDIO_CHANNELS, NULL);
14001 }
14002 
14003 
14005  if (!WEED_IS_LAYER(layer)) return 0;
14006  return weed_get_int_value(layer, WEED_LEAF_AUDIO_DATA_LENGTH, NULL);
14007 }
14008 
lives_painter_format_stride_for_width
WIDGET_HELPER_GLOBAL_INLINE int lives_painter_format_stride_for_width(lives_painter_format_t form, int width)
Definition: widget-helper.c:723
LIVES_DEBUG
#define LIVES_DEBUG(x)
Definition: main.h:1848
lives_freep
boolean lives_freep(void **ptr)
Definition: utils.c:1411
lives_painter_get_target
WIDGET_HELPER_GLOBAL_INLINE lives_painter_surface_t * lives_painter_get_target(lives_painter_t *cr)
Definition: widget-helper.c:711
LIVES_LAYER_LOAD_IF_NEEDS_RESIZE
#define LIVES_LAYER_LOAD_IF_NEEDS_RESIZE
private flags
Definition: colourspace.h:259
LIVES_GLOBAL_INLINE
#define LIVES_GLOBAL_INLINE
Definition: main.h:239
SHIFTVAL
#define SHIFTVAL
Definition: colourspace.c:9034
gamma_const_t::lin
float lin
Definition: colourspace.h:76
lives_cc_params::srcp
void * srcp[4]
Definition: colourspace.h:104
uyvy_macropixel::u0
uint8_t u0
Definition: colourspace.h:80
LIVES_LOCAL_INLINE
#define LIVES_LOCAL_INLINE
Definition: main.h:246
EFFORT_RANGE_MAX
#define EFFORT_RANGE_MAX
if set to TRUE during playback then a new frame (or possibly the current one) will be displayed ASAP
Definition: mainwindow.h:1770
yuyv_macropixel
Definition: colourspace.h:86
lives_painter_image_surface_get_height
WIDGET_HELPER_GLOBAL_INLINE int lives_painter_image_surface_get_height(lives_painter_surface_t *surf)
Definition: widget-helper.c:759
pixel_data_planar_from_membuf
void pixel_data_planar_from_membuf(void **pixel_data, void *data, size_t size, int palette, boolean contig)
Definition: colourspace.c:2236
lives_layer_set_clip
LIVES_GLOBAL_INLINE void lives_layer_set_clip(weed_layer_t *layer, int clip)
Definition: colourspace.c:9828
lives_img_type_t
lives_img_type_t
Definition: main.h:774
UV_BIAS
#define UV_BIAS
Definition: colourspace.h:67
gamma_convert_layer_variant
LIVES_GLOBAL_INLINE boolean gamma_convert_layer_variant(double file_gamma, int tgamma, weed_layer_t *layer)
Definition: colourspace.c:12202
can_inline_gamma
LIVES_LOCAL_INLINE boolean can_inline_gamma(int inpl, int opal)
Definition: colourspace.c:10108
fastrand_int
LIVES_GLOBAL_INLINE uint32_t fastrand_int(uint32_t range)
pick a pseudo random uint between 0 and range (inclusive)
Definition: machinestate.c:54
lives_thread_create
int lives_thread_create(lives_thread_t *thread, lives_thread_attr_t attr, lives_funcptr_t func, void *arg)
Definition: machinestate.c:2318
uyvy_macropixel::v0
uint8_t v0
Definition: colourspace.h:82
lives_free
#define lives_free
Definition: machinestate.h:52
pick_nice_colour
boolean pick_nice_colour(uint8_t r0, uint8_t g0, uint8_t b0, uint8_t *r1, uint8_t *g1, uint8_t *b1, double max, double lmin, double lmax)
Definition: colourspace.c:1142
LIVES_WARN
#define LIVES_WARN(x)
Definition: main.h:1862
LIVES_FLAG_MAINTAIN_VALUE
#define LIVES_FLAG_MAINTAIN_VALUE
soft flag, like immutable / deletable for host
Definition: effects-weed.h:109
lives_malloc
#define lives_malloc
Definition: machinestate.h:46
rowstrides_differ
LIVES_GLOBAL_INLINE boolean rowstrides_differ(int n1, int *n1_array, int n2, int *n2_array)
Definition: colourspace.c:9647
GNU_FLATTEN
#define GNU_FLATTEN
Definition: main.h:87
lives_layer_set_frame
LIVES_GLOBAL_INLINE void lives_layer_set_frame(weed_layer_t *layer, frames_t frame)
Definition: colourspace.c:9822
break_me
void break_me(const char *brkstr)
Definition: main.c:159
weed_layer_is_video
LIVES_GLOBAL_INLINE int weed_layer_is_video(weed_layer_t *layer)
Definition: colourspace.c:9669
WEED_LEAF_HOST_FLAGS
#define WEED_LEAF_HOST_FLAGS
Definition: colourspace.h:24
lives_pixbuf_scale_simple
WIDGET_HELPER_GLOBAL_INLINE LiVESPixbuf * lives_pixbuf_scale_simple(const LiVESPixbuf *src, int dest_width, int dest_height, LiVESInterpType interp_type)
Definition: widget-helper.c:3173
is_rgbchan
LIVES_LOCAL_INLINE boolean is_rgbchan(uint16_t ctype)
Definition: colourspace.c:1383
weed_layer_new
LIVES_GLOBAL_INLINE weed_layer_t * weed_layer_new(int layer_type)
Definition: colourspace.c:9655
N_IMG_TYPES
@ N_IMG_TYPES
Definition: main.h:778
weed_layer_set_yuv_subspace
LIVES_GLOBAL_INLINE weed_layer_t * weed_layer_set_yuv_subspace(weed_layer_t *layer, int subspace)
Definition: colourspace.c:9805
get_simple_palette
LIVES_GLOBAL_INLINE int get_simple_palette(weed_macropixel_t *mpx)
Definition: colourspace.c:1378
CLAMP_FACTOR_Y
#define CLAMP_FACTOR_Y
Definition: colourspace.h:64
lives_painter_image_surface_create_for_data
WIDGET_HELPER_GLOBAL_INLINE lives_painter_surface_t * lives_painter_image_surface_create_for_data(uint8_t *data, lives_painter_format_t format, int width, int height, int stride)
Definition: widget-helper.c:660
lives_cc_params::out_clamping
boolean out_clamping
Definition: colourspace.h:117
yuv411_macropixel::y1
uint8_t y1
Definition: colourspace.h:96
weed_layer_set_pixel_data
LIVES_GLOBAL_INLINE weed_layer_t * weed_layer_set_pixel_data(weed_layer_t *layer, void **pixel_data, int nplanes)
Definition: colourspace.c:9739
IS_VALID_CLIP
#define IS_VALID_CLIP(clip)
Definition: main.h:808
lives_pixbuf_get_width
WIDGET_HELPER_GLOBAL_INLINE int lives_pixbuf_get_width(const LiVESPixbuf *pixbuf)
Definition: widget-helper.c:3107
WEED_LEAF_PIXEL_BITS
#define WEED_LEAF_PIXEL_BITS
Definition: colourspace.h:23
init_advanced_palettes
void init_advanced_palettes(void)
Definition: colourspace.c:1201
_prefs::use_screen_gamma
boolean use_screen_gamma
Definition: preferences.h:452
weed_layer_get_naudchans
LIVES_GLOBAL_INLINE int weed_layer_get_naudchans(weed_layer_t *layer)
Definition: colourspace.c:13998
DEF_FRAME_VSIZE_UNSCALED
#define DEF_FRAME_VSIZE_UNSCALED
Definition: mainwindow.h:144
weed_palette_get_nplanes
LIVES_GLOBAL_INLINE int weed_palette_get_nplanes(int pal)
Definition: colourspace.c:1417
weed_layer_get_width
LIVES_GLOBAL_INLINE int weed_layer_get_width(weed_layer_t *layer)
Definition: colourspace.c:13941
GNU_HOT
#define GNU_HOT
Definition: main.h:88
KB_YCBCR
#define KB_YCBCR
Definition: colourspace.h:44
weed_layer_get_type
LIVES_GLOBAL_INLINE int weed_layer_get_type(weed_layer_t *layer)
Definition: colourspace.c:9663
LIVES_ERROR
#define LIVES_ERROR(x)
Definition: main.h:1870
lives_clip_t::frames
frames_t frames
number of video frames
Definition: main.h:890
cvirtual.h
weed_palette_get_alpha_offset
LIVES_GLOBAL_INLINE int weed_palette_get_alpha_offset(int pal)
Definition: colourspace.c:1510
prefs
_prefs * prefs
Definition: preferences.h:847
lives_cc_params::dest
void * dest
Definition: colourspace.h:112
lab_conv
LIVES_LOCAL_INLINE double lab_conv(double a)
Definition: colourspace.c:1026
lives_painter_surface_reference
WIDGET_HELPER_GLOBAL_INLINE lives_painter_surface_t * lives_painter_surface_reference(lives_painter_surface_t *surf)
Definition: widget-helper.c:470
CLAMP_FACTOR_UV
#define CLAMP_FACTOR_UV
Definition: colourspace.h:65
pixel_size
LIVES_GLOBAL_INLINE size_t pixel_size(int pal)
Definition: colourspace.c:1391
yuv411_macropixel::y3
uint8_t y3
Definition: colourspace.h:99
LIVES_FILE_EXT_JPG
#define LIVES_FILE_EXT_JPG
Definition: mainwindow.h:488
lives_layer_set_opaque
void lives_layer_set_opaque(weed_layer_t *layer)
Definition: colourspace.c:12385
get_last_pixbuf_rowstride_value
#define get_last_pixbuf_rowstride_value(width, nchans)
Definition: colourspace.c:201
mainwindow::frame_layer
weed_plant_t * frame_layer
Definition: mainwindow.h:948
PB_QUALITY_HIGH
#define PB_QUALITY_HIGH
Definition: preferences.h:34
WEED_LAYER_TYPE_NONE
#define WEED_LAYER_TYPE_NONE
Definition: colourspace.h:220
weed_palette_get_name_full
char * weed_palette_get_name_full(int pal, int clamping, int subspace)
Definition: weed-effects-utils.c:764
WEED_LEAF_HOST_ORIG_PDATA
#define WEED_LEAF_HOST_ORIG_PDATA
Definition: effects-weed.h:60
lives_pixbuf_get_pixels
WIDGET_HELPER_GLOBAL_INLINE unsigned char * lives_pixbuf_get_pixels(const LiVESPixbuf *pixbuf)
Definition: widget-helper.c:3140
weed_palette_is_lower_quality
boolean weed_palette_is_lower_quality(int p1, int p2)
Definition: colourspace.c:2143
LAB2
#define LAB2
Definition: colourspace.c:1024
avg_chroma
#define avg_chroma(x, y)
Definition: colourspace.c:1790
weed_palette_is_alpha
LIVES_GLOBAL_INLINE boolean weed_palette_is_alpha(int pal)
Definition: colourspace.c:1427
weed_palette_is_resizable
LIVES_INLINE boolean weed_palette_is_resizable(int pal, int clamped, boolean in_out)
Definition: colourspace.c:12343
weed_layer_get_palette_yuv
LIVES_GLOBAL_INLINE int weed_layer_get_palette_yuv(weed_layer_t *layer, int *clamping, int *sampling, int *subspace)
Definition: colourspace.c:13983
lives_pixbuf_is_all_black
LIVES_GLOBAL_INLINE boolean lives_pixbuf_is_all_black(LiVESPixbuf *pixbuf)
Definition: colourspace.c:2193
weed_layer_get_height
LIVES_GLOBAL_INLINE int weed_layer_get_height(weed_layer_t *layer)
Definition: colourspace.c:13953
lives_cc_params::is_bottom
boolean is_bottom
Definition: colourspace.h:107
weed_layer_count_refs
LIVES_GLOBAL_INLINE int weed_layer_count_refs(weed_layer_t *layer)
Definition: colourspace.c:13799
uyvy_macropixel
Definition: colourspace.h:79
weed_layer_create
weed_layer_t * weed_layer_create(int width, int height, int *rowstrides, int palette)
create a layer, setting the most important properties
Definition: colourspace.c:13708
round_special
LIVES_GLOBAL_INLINE int32_t round_special(int32_t val)
Definition: colourspace.c:544
uyvy_macropixel::y1
uint8_t y1
Definition: colourspace.h:83
EXTRA_BYTES
#define EXTRA_BYTES
TODO - split into: memory, files, sysops, threads.
Definition: machinestate.h:16
weed_layer_nullify_pixel_data
LIVES_GLOBAL_INLINE weed_layer_t * weed_layer_nullify_pixel_data(weed_layer_t *layer)
Definition: colourspace.c:9753
lives_thread_join
uint64_t lives_thread_join(lives_thread_t work, void **retval)
Definition: machinestate.c:2376
swap_red_blue
LIVES_LOCAL_INLINE int swap_red_blue(int pal)
Definition: colourspace.c:13411
_prefs::apply_gamma
boolean apply_gamma
Definition: preferences.h:451
lives_cc_params::alpha_first
boolean alpha_first
Definition: colourspace.h:122
lives_cc_params::irowstrides
int irowstrides[4]
Definition: colourspace.h:110
copy_pixel_data
boolean copy_pixel_data(weed_layer_t *layer, weed_layer_t *old_layer, size_t alignment)
Definition: colourspace.c:9843
lives_nanosleep
#define lives_nanosleep(nanosec)
Definition: machinestate.h:307
letterbox_layer
boolean letterbox_layer(weed_layer_t *layer, int nwidth, int nheight, int width, int height, LiVESInterpType interp, int tpal, int tclamp)
Definition: colourspace.c:13015
yuv2bgr
#define yuv2bgr(y, u, v, b, g, r)
Definition: colourspace.c:2050
lives_painter_surface_destroy
WIDGET_HELPER_GLOBAL_INLINE boolean lives_painter_surface_destroy(lives_painter_surface_t *surf)
Definition: widget-helper.c:457
lives_pixbuf_set_opaque
void lives_pixbuf_set_opaque(LiVESPixbuf *pixbuf)
Definition: colourspace.c:12362
is_yuvchan
LIVES_LOCAL_INLINE boolean is_yuvchan(uint16_t ctype)
Definition: colourspace.c:1387
WEED_LEAF_FRAME
#define WEED_LEAF_FRAME
Definition: colourspace.h:19
weed_palette_get_alpha_plane
LIVES_GLOBAL_INLINE int weed_palette_get_alpha_plane(int pal)
Definition: colourspace.c:1505
weed_palette_red_first
LIVES_GLOBAL_INLINE boolean weed_palette_red_first(int pal)
Definition: colourspace.c:1433
_prefs::screen_gamma
double screen_gamma
Definition: preferences.h:442
weed_layer_set_height
LIVES_GLOBAL_INLINE weed_layer_t * weed_layer_set_height(weed_layer_t *layer, int height)
Definition: colourspace.c:9724
WEED_LAYER_TYPE_VIDEO
#define WEED_LAYER_TYPE_VIDEO
Definition: colourspace.h:221
FP_BITS
#define FP_BITS
Definition: colourspace.h:35
threaded_dialog_spin
void threaded_dialog_spin(double fraction)
Definition: dialogs.c:3823
weed_layer_set_palette
LIVES_GLOBAL_INLINE weed_layer_t * weed_layer_set_palette(weed_layer_t *layer, int palette)
functions all return the input layer for convenience; no checking for valid values is done if layer i...
Definition: colourspace.c:9777
lives_cc_params::in_subspace
int in_subspace
Definition: colourspace.h:118
yuv411_macropixel::v2
uint8_t v2
Definition: colourspace.h:97
lives_cc_params::vsize
size_t vsize
Definition: colourspace.h:106
TRUE
#define TRUE
Definition: videoplugin.h:59
gamma_const_t::thresh
float thresh
Definition: colourspace.h:76
sizint
ssize_t sizint
type sizes
Definition: main.c:102
lives_cc_params::is_422
boolean is_422
Definition: colourspace.h:123
_prefs::nfx_threads
int nfx_threads
Definition: preferences.h:356
Y_CLAMP_MAX
#define Y_CLAMP_MAX
Definition: colourspace.h:58
DIST_THRESH
#define DIST_THRESH
lives_memset
#define lives_memset
Definition: machinestate.h:61
yuv411_macropixel::y0
uint8_t y0
Definition: colourspace.h:95
weed_palette_is_yuv
LIVES_GLOBAL_INLINE boolean weed_palette_is_yuv(int pal)
Definition: colourspace.c:1457
yuyv_macropixel::y0
uint8_t y0
Definition: colourspace.h:87
lives_cc_params::lut
void * lut
Definition: colourspace.h:124
THREADVAR
#define THREADVAR(var)
Definition: machinestate.h:531
weed_layer_get_rowstrides
LIVES_GLOBAL_INLINE int * weed_layer_get_rowstrides(weed_layer_t *layer, int *nplanes)
Definition: colourspace.c:13928
weed_layer_pixel_data_free
void weed_layer_pixel_data_free(weed_layer_t *layer)
free pixel_data from layer
Definition: colourspace.c:13819
weed_palette_is_valid
LIVES_GLOBAL_INLINE boolean weed_palette_is_valid(int pal)
Definition: colourspace.c:1374
mainwindow::cancelled
volatile lives_cancel_t cancelled
Definition: mainwindow.h:798
UV_CLAMP_MAXI
#define UV_CLAMP_MAXI
Definition: colourspace.h:62
LIVES_FILE_EXT_BAK
#define LIVES_FILE_EXT_BAK
Definition: mainwindow.h:495
lives_cc_params::thread_id
int thread_id
Definition: colourspace.h:125
Y_CLAMP_MAXI
#define Y_CLAMP_MAXI
Definition: colourspace.h:59
weed_palette_is_rgb
LIVES_GLOBAL_INLINE boolean weed_palette_is_rgb(int pal)
Definition: colourspace.c:1448
rgb2yuyv_with_gamma
LIVES_INLINE void rgb2yuyv_with_gamma(uint8_t r0, uint8_t g0, uint8_t b0, uint8_t r1, uint8_t g1, uint8_t b1, yuyv_macropixel *yuyv, uint8_t *lut)
Definition: colourspace.c:1893
_prefs::ocp
int ocp
open_compression_percent : get/set in prefs
Definition: preferences.h:217
gamma_const_t
Definition: colourspace.h:75
capable
capability * capable
Definition: main.h:627
KR_YCBCR
#define KR_YCBCR
Definition: colourspace.h:43
get_advanced_palette
LIVES_GLOBAL_INLINE const weed_macropixel_t * get_advanced_palette(int weed_palette)
Definition: colourspace.c:1368
weed_palette_is_painter_palette
LIVES_GLOBAL_INLINE boolean weed_palette_is_painter_palette(int pal)
Definition: colourspace.c:2130
weed_layer_set_width
LIVES_GLOBAL_INLINE weed_layer_t * weed_layer_set_width(weed_layer_t *layer, int width)
width in macropixels of the layer palette
Definition: colourspace.c:9717
weed_palette_is_float
LIVES_GLOBAL_INLINE boolean weed_palette_is_float(int pal)
Definition: colourspace.c:1475
lives_cc_params::in_sampling
int in_sampling
Definition: colourspace.h:120
weed_leaf_copy_or_delete
LIVES_GLOBAL_INLINE weed_error_t weed_leaf_copy_or_delete(weed_layer_t *dlayer, const char *key, weed_layer_t *slayer)
Definition: effects-weed.c:68
USE_THREADS
#define USE_THREADS
set to 0 to disable threading for pixbuf operations, 1 to enable. Other values are invalid.
Definition: colourspace.c:37
CEIL
#define CEIL(a, b)
Definition: main.h:283
yuv411_macropixel::u2
uint8_t u2
Definition: colourspace.h:94
lives_painter_create_from_surface
WIDGET_HELPER_GLOBAL_INLINE lives_painter_t * lives_painter_create_from_surface(lives_painter_surface_t *target)
Definition: widget-helper.c:309
weed_layer_get_flags
LIVES_GLOBAL_INLINE int weed_layer_get_flags(weed_layer_t *layer)
Definition: colourspace.c:9699
weed_layer_get_palette
LIVES_GLOBAL_INLINE int weed_layer_get_palette(weed_layer_t *layer)
Definition: colourspace.c:13977
avg_chroma_3_1
#define avg_chroma_3_1(x, y)
Definition: colourspace.c:1791
weed_yuv_clamping_get_name
const char * weed_yuv_clamping_get_name(int clamping)
Definition: weed-effects-utils.c:751
weed_layer_set_pixel_data_packed
LIVES_GLOBAL_INLINE weed_layer_t * weed_layer_set_pixel_data_packed(weed_layer_t *layer, void *pixel_data)
Definition: colourspace.c:9746
lives_mv
int lives_mv(const char *from, const char *to)
Definition: utils.c:4446
swab4
LIVES_GLOBAL_INLINE void swab4(const void *from, const void *to, size_t gran)
Definition: machinestate.c:2462
lives_painter_surface_flush
WIDGET_HELPER_GLOBAL_INLINE boolean lives_painter_surface_flush(lives_painter_surface_t *surf)
Definition: widget-helper.c:648
lives_clip_t::frame_index
frames_t * frame_index
index of frames for CLIP_TYPE_FILE >0 means corresponding frame within original clip -1 means corresp...
Definition: main.h:1004
ALIGN_MIN
#define ALIGN_MIN
rowstride alignment values
Definition: colourspace.h:31
create_empty_pixel_data
boolean create_empty_pixel_data(weed_layer_t *layer, boolean black_fill, boolean may_contig)
creates pixel data for layer
Definition: colourspace.c:9058
resize_all
int resize_all(int fileno, int width, int height, lives_img_type_t imgtype, boolean do_back, int *nbad, int *nmiss)
utility funcs for GUI
Definition: colourspace.c:13622
weed_paramtmpl_get_type
WEED_GLOBAL_INLINE int weed_paramtmpl_get_type(weed_plant_t *paramtmpl)
Definition: weed-effects-utils.c:312
weed_layer_get_pixel_data_packed
LIVES_GLOBAL_INLINE uint8_t * weed_layer_get_pixel_data_packed(weed_layer_t *layer)
Definition: colourspace.c:13915
weed_layer_set_size
LIVES_GLOBAL_INLINE weed_layer_t * weed_layer_set_size(weed_layer_t *layer, int width, int height)
Definition: colourspace.c:9731
_future_prefs::pb_quality
short pb_quality
Definition: preferences.h:831
LAB1
#define LAB1
Definition: colourspace.c:1023
lives_painter_image_surface_get_width
WIDGET_HELPER_GLOBAL_INLINE int lives_painter_image_surface_get_width(lives_painter_surface_t *surf)
Definition: widget-helper.c:747
WEED_PLANT_LAYER
#define WEED_PLANT_LAYER
Definition: colourspace.h:217
weed_palettes_rbswapped
LIVES_GLOBAL_INLINE boolean weed_palettes_rbswapped(int pal0, int pal1)
Definition: colourspace.c:1444
CLAMP0255
#define CLAMP0255(a)
Definition: colourspace.c:211
lives_cc_params::out_alpha
boolean out_alpha
Definition: colourspace.h:115
mainwindow::files
lives_clip_t * files[MAX_FILES+1]
+1 for the clipboard
Definition: mainwindow.h:729
fill_plane
LIVES_INLINE void fill_plane(uint8_t *ptr, int psize, int width, int height, int rowstride, unsigned char *bpix)
a "layer" is CHANNEL type plant which is not created from a plugin CHANNEL_TEMPLATE.
Definition: colourspace.c:9019
CANCEL_NONE
@ CANCEL_NONE
no cancel
Definition: main.h:701
ALIGN_CEIL
#define ALIGN_CEIL(a, b)
Definition: main.h:286
bgr2yuv
#define bgr2yuv(b0, g0, r0, y, u, v)
Definition: colourspace.c:1830
weed_palette_has_alpha
LIVES_GLOBAL_INLINE boolean weed_palette_has_alpha(int pal)
Definition: colourspace.c:1466
lives_cc_params::src
void * src
Definition: colourspace.h:103
weed_layer_get_yuv_sampling
LIVES_GLOBAL_INLINE int weed_layer_get_yuv_sampling(weed_layer_t *layer)
Definition: colourspace.c:13965
lives_cc_params::destp
void * destp[4]
Definition: colourspace.h:113
palette
_palette * palette
interface colour settings
Definition: main.c:101
KR_BT709
#define KR_BT709
Definition: colourspace.h:49
WEED_LEAF_LAYER_TYPE
#define WEED_LEAF_LAYER_TYPE
Definition: colourspace.h:219
lives_cc_params::orowstrides
int orowstrides[4]
Definition: colourspace.h:111
error
error("LSD_RANDFUNC(ptr, size) must be defined")
weed_palette_is_pixbuf_palette
#define weed_palette_is_pixbuf_palette(pal)
Definition: colourspace.h:296
weed_layer_set_audio_data
LIVES_GLOBAL_INLINE weed_layer_t * weed_layer_set_audio_data(weed_layer_t *layer, float **data, int arate, int naudchans, weed_size_t nsamps)
Definition: colourspace.c:9681
weed_layer_get_gamma
int weed_layer_get_gamma(weed_layer_t *layer)
Definition: colourspace.c:12002
weed_palette_get_plane_ratio_vertical
LIVES_GLOBAL_INLINE double weed_palette_get_plane_ratio_vertical(int pal, int plane)
Definition: colourspace.c:1488
lives_cc_params::xoffset
size_t xoffset
Definition: colourspace.h:109
weed_palette_is_planar
#define weed_palette_is_planar(pal)
Definition: weed-effects-utils.h:255
init_colour_engine
void init_colour_engine(void)
Definition: colourspace.c:1661
weed_palette_has_alpha_last
LIVES_GLOBAL_INLINE boolean weed_palette_has_alpha_last(int pal)
Definition: colourspace.c:1519
lives_strdup_printf
#define lives_strdup_printf(fmt,...)
Definition: support.c:27
lives_pixbuf_new
WIDGET_HELPER_GLOBAL_INLINE LiVESPixbuf * lives_pixbuf_new(boolean has_alpha, int width, int height)
Definition: widget-helper.c:3047
lives_painter_image_surface_get_stride
WIDGET_HELPER_GLOBAL_INLINE int lives_painter_image_surface_get_stride(lives_painter_surface_t *surf)
Definition: widget-helper.c:771
lives_cc_params::in_clamping
boolean in_clamping
Definition: colourspace.h:116
lives_calloc
#define lives_calloc
Definition: machinestate.h:67
SCALE_FACTOR
#define SCALE_FACTOR
Definition: colourspace.h:40
K2
#define K2
Definition: colourspace.c:1037
_get_alpha
LIVES_LOCAL_INLINE int _get_alpha(int pal)
Definition: colourspace.c:1496
WEED_GAMMA_VARIANT
#define WEED_GAMMA_VARIANT
Definition: colourspace.h:255
convert_layer_palette
boolean convert_layer_palette(weed_layer_t *layer, int outpl, int op_clamping)
Definition: colourspace.c:11945
consider_swapping
boolean consider_swapping(int *inpal, int *outpal)
look for shortcuts in palette conversions instead of converting e.g RGB -> BGRA, we may be able to pr...
Definition: colourspace.c:13427
hsv2rgb
void hsv2rgb(double h, double s, double v, uint8_t *r, uint8_t *g, uint8_t *b)
Definition: colourspace.c:1113
WEED_LEAF_PROGSCAN
#define WEED_LEAF_PROGSCAN
Definition: colourspace.h:26
weed_layer_t
weed_plant_t weed_layer_t
Definition: colourspace.h:71
lives_pixbuf_get_pixels_readonly
WIDGET_HELPER_GLOBAL_INLINE const unsigned char * lives_pixbuf_get_pixels_readonly(const LiVESPixbuf *pixbuf)
Definition: widget-helper.c:3151
lives_clip_t::hsize
int hsize
frame width (horizontal) in pixels (NOT macropixels !)
Definition: main.h:896
lives_pixbuf_new_blank
LiVESPixbuf * lives_pixbuf_new_blank(int width, int height, int palette)
Definition: colourspace.c:11953
LIVES_THRDATTR_NONE
#define LIVES_THRDATTR_NONE
Definition: machinestate.h:437
weed_layer_get_yuv_clamping
LIVES_GLOBAL_INLINE int weed_layer_get_yuv_clamping(weed_layer_t *layer)
Definition: colourspace.c:13959
LAB0
#define LAB0
Definition: colourspace.c:1022
weed_layer_unref
int weed_layer_unref(weed_layer_t *layer)
Definition: colourspace.c:13888
PB_QUALITY_MED
#define PB_QUALITY_MED
default
Definition: preferences.h:33
KB_BT709
#define KB_BT709
Definition: colourspace.h:50
lives_memmove
#define lives_memmove
Definition: machinestate.h:64
lives_pixbuf_new_from_data
WIDGET_HELPER_GLOBAL_INLINE LiVESPixbuf * lives_pixbuf_new_from_data(const unsigned char *buf, boolean has_alpha, int width, int height, int rowstride, LiVESPixbufDestroyNotify lives_free_buffer_fn, livespointer destroy_fn_data)
Definition: widget-helper.c:3065
weed_layer_copy
weed_layer_t * weed_layer_copy(weed_layer_t *dlayer, weed_layer_t *slayer)
copy source layer slayer to dest layer dlayer
Definition: colourspace.c:13739
layer_to_lives_painter
lives_painter_t * layer_to_lives_painter(weed_layer_t *layer)
convert a weed layer to lives_painter (a.k.a cairo)
Definition: colourspace.c:13473
lives_memcpy
#define lives_memcpy
Definition: machinestate.h:55
DEF_FRAME_HSIZE_UNSCALED
#define DEF_FRAME_HSIZE_UNSCALED
Definition: mainwindow.h:139
future_prefs
_future_prefs * future_prefs
Definition: preferences.h:848
lives_cc_params::hsize
size_t hsize
Definition: colourspace.h:105
RAT_MIN
#define RAT_MIN
weed_layer_set_rowstride
LIVES_GLOBAL_INLINE weed_layer_t * weed_layer_set_rowstride(weed_layer_t *layer, int rowstride)
Definition: colourspace.c:9770
weed_layer_get_pixel_data
LIVES_GLOBAL_INLINE void ** weed_layer_get_pixel_data(weed_layer_t *layer, int *nplanes)
Definition: colourspace.c:13908
myround
#define myround(n)
Definition: main.h:300
weed_layer_set_yuv_sampling
LIVES_GLOBAL_INLINE weed_layer_t * weed_layer_set_yuv_sampling(weed_layer_t *layer, int sampling)
Definition: colourspace.c:9798
weed_palette_has_alpha_first
LIVES_GLOBAL_INLINE boolean weed_palette_has_alpha_first(int pal)
Definition: colourspace.c:1515
get_luma8
double get_luma8(uint8_t r, uint8_t g, uint8_t b)
Definition: colourspace.c:549
create_blank_layer
weed_layer_t * create_blank_layer(weed_layer_t *layer, const char *image_ext, int width, int height, int target_palette)
fills layer with default values.
Definition: colourspace.c:9611
weed_layer_get_yuv_subspace
LIVES_GLOBAL_INLINE int weed_layer_get_yuv_subspace(weed_layer_t *layer)
Definition: colourspace.c:13971
ALIGN_SIZE
#define ALIGN_SIZE
Definition: colourspace.c:9035
lives_painter_image_surface_get_data
WIDGET_HELPER_GLOBAL_INLINE uint8_t * lives_painter_image_surface_get_data(lives_painter_surface_t *surf)
Definition: widget-helper.c:735
K1
#define K1
Definition: colourspace.c:1036
YUV_CLAMP_MINI
#define YUV_CLAMP_MINI
Definition: colourspace.h:56
LIVES_INTENTION_PLAY
@ LIVES_INTENTION_PLAY
Definition: plugins.h:45
main.h
make_image_file_name
char * make_image_file_name(lives_clip_t *clip, frames_t frame, const char *img_ext)
lives_image_type can be a string, lives_img_type_t is an enumeration
Definition: utils.c:3053
WEED_LAYER_TYPE_AUDIO
#define WEED_LAYER_TYPE_AUDIO
Definition: colourspace.h:222
lives_layer_get_clip
LIVES_GLOBAL_INLINE int lives_layer_get_clip(weed_layer_t *layer)
Definition: colourspace.c:9705
rgb2hsv
void rgb2hsv(uint8_t r, uint8_t g, uint8_t b, double *h, double *s, double *v)
Definition: colourspace.c:1090
spc_rnd
#define spc_rnd(val)
Definition: colourspace.c:541
weed_palette_is_sane
boolean weed_palette_is_sane(int pal)
Definition: colourspace.c:1523
lives_layer_new_for_frame
LIVES_GLOBAL_INLINE weed_layer_t * lives_layer_new_for_frame(int clip, frames_t frame)
Definition: colourspace.c:9833
UV_CLAMP_MAX
#define UV_CLAMP_MAX
Definition: colourspace.h:61
lives_painter_image_surface_get_format
WIDGET_HELPER_GLOBAL_INLINE lives_painter_format_t lives_painter_image_surface_get_format(lives_painter_surface_t *surf)
Definition: widget-helper.c:783
weed_layer_set_gamma
LIVES_GLOBAL_INLINE weed_layer_t * weed_layer_set_gamma(weed_layer_t *layer, int gamma_type)
Definition: colourspace.c:9784
mainwindow::effort
int effort
Definition: mainwindow.h:1773
sig
#define sig(a)
Definition: main.h:268
WEED_LEAF_CLIP
#define WEED_LEAF_CLIP
Definition: colourspace.h:18
mainw
mainwindow * mainw
Definition: main.c:103
MAX_THREADS
#define MAX_THREADS
Definition: colourspace.h:69
get_image_ext_for_type
const char * get_image_ext_for_type(lives_img_type_t imgtype)
Definition: utils.c:3025
LAB3
#define LAB3
Definition: colourspace.c:1025
rgb2xyz
void rgb2xyz(uint8_t r, uint8_t g, uint8_t b, double *x, double *y, double *z)
Definition: colourspace.c:1013
weed_layer_set_palette_yuv
LIVES_GLOBAL_INLINE weed_layer_t * weed_layer_set_palette_yuv(weed_layer_t *layer, int palette, int clamping, int sampling, int subspace)
Definition: colourspace.c:9812
RAT_TIO
#define RAT_TIO
WEED_IS_LAYER
#define WEED_IS_LAYER(plant)
Definition: colourspace.h:224
RNDFAC
#define RNDFAC
Definition: colourspace.c:1038
weed_layer_get_audio_rate
LIVES_GLOBAL_INLINE int weed_layer_get_audio_rate(weed_layer_t *layer)
Definition: colourspace.c:13992
yuv2bgr_with_gamma
#define yuv2bgr_with_gamma(y, u, v, b, g, r, lut)
Definition: colourspace.c:2058
convert_layer_palette_full
boolean convert_layer_palette_full(weed_layer_t *layer, int outpl, int oclamping, int osampling, int osubspace, int tgamma)
convert the palette of a layer
Definition: colourspace.c:10160
frames_t
int frames_t
Definition: main.h:99
lives_layer_get_frame
LIVES_GLOBAL_INLINE frames_t lives_layer_get_frame(weed_layer_t *layer)
Definition: colourspace.c:9711
resize_layer
boolean resize_layer(weed_layer_t *layer, int width, int height, LiVESInterpType interp, int opal_hint, int oclamp_hint)
resize a layer
Definition: colourspace.c:12537
LIVES_INTENTION_TRANSCODE
@ LIVES_INTENTION_TRANSCODE
Definition: plugins.h:47
ALIGN_DEF
#define ALIGN_DEF
Definition: colourspace.h:32
weed_layer_create_full
weed_layer_t * weed_layer_create_full(int width, int height, int *rowstrides, int palette, int YUV_clamping, int YUV_sampling, int YUV_subspace, int gamma_type)
Definition: colourspace.c:13722
lives_painter_to_layer
boolean lives_painter_to_layer(lives_painter_t *cr, weed_layer_t *layer)
convert a lives_painter_t (a.k.a) cairo_t to a weed layer
Definition: colourspace.c:13549
PB_QUALITY_LOW
#define PB_QUALITY_LOW
Definition: preferences.h:32
alpha_unpremult
void alpha_unpremult(weed_layer_t *layer, boolean un)
(un)premultply alpha using a lookup table
Definition: colourspace.c:9923
weed_layer_get_audio_data
LIVES_GLOBAL_INLINE float ** weed_layer_get_audio_data(weed_layer_t *layer, int *naudchans)
Definition: colourspace.c:13921
weed_layer_free
LIVES_GLOBAL_INLINE weed_layer_t * weed_layer_free(weed_layer_t *layer)
frees pixel_data for a layer, then the layer itself
Definition: colourspace.c:13883
WEED_LEAF_HOST_REFS
#define WEED_LEAF_HOST_REFS
Definition: effects-weed.h:72
weed_layer_get_width_pixels
LIVES_GLOBAL_INLINE int weed_layer_get_width_pixels(weed_layer_t *layer)
Definition: colourspace.c:13947
gamma_const_t::offs
float offs
Definition: colourspace.h:76
_prefs::pb_quality
short pb_quality
Definition: preferences.h:31
weed_palette_get_plane_ratio_horizontal
LIVES_GLOBAL_INLINE double weed_palette_get_plane_ratio_horizontal(int pal, int plane)
Definition: colourspace.c:1480
lives_clip_t::vsize
int vsize
frame height (vertical) in pixels
Definition: main.h:897
WEED_LEAF_HOST_SURFACE_SRC
#define WEED_LEAF_HOST_SURFACE_SRC
Definition: colourspace.h:22
WEED_LEAF_HOST_PIXEL_DATA_CONTIGUOUS
#define WEED_LEAF_HOST_PIXEL_DATA_CONTIGUOUS
Definition: colourspace.h:20
compact_rowstrides
boolean compact_rowstrides(weed_layer_t *layer)
Definition: colourspace.c:12422
init_conversions
LIVES_GLOBAL_INLINE void init_conversions(int intent)
Definition: colourspace.c:1804
lives_pixbuf_get_height
WIDGET_HELPER_GLOBAL_INLINE int lives_pixbuf_get_height(const LiVESPixbuf *pixbuf)
Definition: widget-helper.c:3118
weed_layer_ref
LIVES_GLOBAL_INLINE int weed_layer_ref(weed_layer_t *layer)
Definition: colourspace.c:13899
lives_clip_t
corresponds to one clip in the GUI
Definition: main.h:877
yuv411_macropixel::y2
uint8_t y2
Definition: colourspace.h:98
lives_calloc_safety
LIVES_GLOBAL_INLINE void * lives_calloc_safety(size_t nmemb, size_t xsize)
Definition: machinestate.c:603
WEED_GAMMA_MONITOR
#define WEED_GAMMA_MONITOR
Definition: colourspace.h:253
weed_layer_set_rowstrides
LIVES_GLOBAL_INLINE weed_layer_t * weed_layer_set_rowstrides(weed_layer_t *layer, int *rowstrides, int nplanes)
Definition: colourspace.c:9763
lives_clip_t::gamma_type
int gamma_type
Definition: main.h:903
lives_painter_destroy
WIDGET_HELPER_GLOBAL_INLINE boolean lives_painter_destroy(lives_painter_t *cr)
Definition: widget-helper.c:412
effects-weed.h
weed_layer_set_flags
LIVES_GLOBAL_INLINE weed_layer_t * weed_layer_set_flags(weed_layer_t *layer, int flags)
Definition: colourspace.c:9692
uyvy_macropixel::y0
uint8_t y0
Definition: colourspace.h:81
weed_layer_get_rowstride
LIVES_GLOBAL_INLINE int weed_layer_get_rowstride(weed_layer_t *layer)
for packed palettes
Definition: colourspace.c:13935
avg_chroma_1_3f
#define avg_chroma_1_3f(x, y)
Definition: colourspace.c:1818
RAT_START
#define RAT_START
avg_chroma_3_1f
#define avg_chroma_3_1f(x, y)
Definition: colourspace.c:1817
LIVES_INTENTION_RENDER
@ LIVES_INTENTION_RENDER
Definition: plugins.h:48
gamma_convert_layer
LIVES_GLOBAL_INLINE boolean gamma_convert_layer(int gamma_type, weed_layer_t *layer)
Definition: colourspace.c:12195
get_pixbuf_rowstride_value
#define get_pixbuf_rowstride_value(rowstride)
Definition: colourspace.c:194
lives_cc_params::psize
size_t psize
Definition: colourspace.h:108
weed_palette_get_name
const char * weed_palette_get_name(int pal)
Definition: weed-effects-utils.c:703
lives_widget_object_unref
WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_object_unref(livespointer object)
decrease refcount by one: if refcount==0, object is destroyed
Definition: widget-helper.c:815
layer_to_pixbuf
LiVESPixbuf * layer_to_pixbuf(weed_layer_t *layer, boolean realpalette, boolean fordisplay)
Definition: colourspace.c:12210
cdist94
double cdist94(uint8_t r0, uint8_t g0, uint8_t b0, uint8_t r1, uint8_t g1, uint8_t b1)
Definition: colourspace.c:1075
WEED_LAYER_ALPHA_PREMULT
#define WEED_LAYER_ALPHA_PREMULT
Definition: colourspace.h:256
lives_cc_params::in_alpha
boolean in_alpha
Definition: colourspace.h:114
_prefs::alpha_post
boolean alpha_post
set to TRUE to force use of post alpha internally
Definition: preferences.h:358
yuyv_macropixel::u0
uint8_t u0
Definition: colourspace.h:88
lives_pixbuf_get_rowstride
WIDGET_HELPER_GLOBAL_INLINE int lives_pixbuf_get_rowstride(const LiVESPixbuf *pixbuf)
Definition: widget-helper.c:3096
lives_thread_t
LiVESList lives_thread_t
Definition: machinestate.h:434
pixbuf_to_layer
boolean pixbuf_to_layer(weed_layer_t *layer, LiVESPixbuf *pixbuf)
turn a (Gdk)Pixbuf into a Weed layer
Definition: colourspace.c:13347
CLAMP0255f
#define CLAMP0255f(a)
Definition: colourspace.c:212
FALSE
#define FALSE
Definition: videoplugin.h:60
gamma_convert_sub_layer
boolean gamma_convert_sub_layer(int gamma_type, double fileg, weed_layer_t *layer, int x, int y, int width, int height, boolean may_thread)
alter the transfer function of a Weed layer, from current value to gamma_type
Definition: colourspace.c:12124
yuyv_macropixel::y1
uint8_t y1
Definition: colourspace.h:89
WEED_LEAF_HOST_PIXBUF_SRC
#define WEED_LEAF_HOST_PIXBUF_SRC
Definition: colourspace.h:21
weed_palette_get_pixels_per_macropixel
LIVES_GLOBAL_INLINE int weed_palette_get_pixels_per_macropixel(int pal)
Definition: colourspace.c:1403
xyz2lab
void xyz2lab(double x, double y, double z, double *l, double *a, double *b)
Definition: colourspace.c:1028
yuyv_macropixel::v0
uint8_t v0
Definition: colourspace.h:90
lives_pixbuf_cheat
LIVES_INLINE LiVESPixbuf * lives_pixbuf_cheat(boolean has_alpha, int width, int height, uint8_t *buf)
Definition: colourspace.c:11990
weed_layer_set_yuv_clamping
LIVES_GLOBAL_INLINE weed_layer_t * weed_layer_set_yuv_clamping(weed_layer_t *layer, int clamping)
Definition: colourspace.c:9791
capability::byte_order
int byte_order
Definition: main.h:577
weed_palette_get_bits_per_macropixel
LIVES_GLOBAL_INLINE int weed_palette_get_bits_per_macropixel(int pal)
Definition: colourspace.c:1411
weed_layer_is_audio
LIVES_GLOBAL_INLINE int weed_layer_is_audio(weed_layer_t *layer)
Definition: colourspace.c:9675
gamma_conv_params
void gamma_conv_params(int gamma_type, weed_layer_t *inst, boolean is_in)
Definition: colourspace.c:12019
lives_rm
int lives_rm(const char *file)
Definition: utils.c:4395
LIVES_INLINE
#define LIVES_INLINE
Definition: main.h:238
WEED_PLANT_IS_CHANNEL
#define WEED_PLANT_IS_CHANNEL(plant)
Definition: weed-effects-utils.h:41
lives_pixbuf_get_n_channels
WIDGET_HELPER_GLOBAL_INLINE int lives_pixbuf_get_n_channels(const LiVESPixbuf *pixbuf)
Definition: widget-helper.c:3129
get_luma16
double get_luma16(uint16_t r, uint16_t g, uint16_t b)
Definition: colourspace.c:557
YUV_CLAMP_MIN
#define YUV_CLAMP_MIN
Definition: colourspace.h:55
weed_layer_create_from_file_progressive
boolean weed_layer_create_from_file_progressive(weed_layer_t *layer, const char *fname, int width, int height, int tpalette, const char *img_ext)
Definition: main.c:6989
lives_pixbuf_save
boolean lives_pixbuf_save(LiVESPixbuf *pixbuf, char *fname, lives_img_type_t imgtype, int quality, int width, int height, LiVESError **gerrorptr)
Save a pixbuf to a file using the specified imgtype and the specified quality/compression value.
Definition: main.c:9304
rgb2yuv_with_gamma
LIVES_INLINE void rgb2yuv_with_gamma(uint8_t r0, uint8_t g0, uint8_t b0, uint8_t *y, uint8_t *u, uint8_t *v, uint8_t *lut)
Definition: colourspace.c:1833
weed_layer_get_audio_length
LIVES_GLOBAL_INLINE int weed_layer_get_audio_length(weed_layer_t *layer)
Definition: colourspace.c:14004
lives_pixbuf_get_has_alpha
WIDGET_HELPER_GLOBAL_INLINE boolean lives_pixbuf_get_has_alpha(const LiVESPixbuf *pixbuf)
Definition: widget-helper.c:3162
lives_cc_params
Definition: colourspace.h:102
yuv411_macropixel
Definition: colourspace.h:93