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 ///< set to 0 to disable threading for pixbuf operations, 1 to enable. Other values are invalid.
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
sws_getblock(int nreq,int iwidth,int iheight,int * irow,swpixfmt ipixfmt,int width,int height,int * orow,swpixfmt opixfmt,int flags,int subspace,int iclamping,int oclamp_hint)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
sws_freeblock(swsctx_block * block)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
lives_free_buffer(uint8_t * pixels,livespointer data)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
348 /// linear -> gamma:
349 // x <= b ? x * c : (a + 1) * powf(x, 1 / G) - a
350
351 /// gamma to linear:
352 // inv: x < d ? x / c : powf((x + a) / (a + 1), G)
353
354 /// b = d / c
355
356 // for sRGB:
357 // a = 0.055, b = 0.0031308, c = 12.92, d = 0.04045, G = 2.4
358
359 /// for bt709:
360 /// a = 0.099, b = 0.018, c = 4.5, d = 0.081, G = 2.22222222
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
create_gamma_lut(double fileg,int gamma_from,int gamma_to)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
lives_gamma_lut_free(uint8_t * lut)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
_spc_rnd(int32_t val,short quality)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
round_special(int32_t val)544 LIVES_GLOBAL_INLINE int32_t round_special(int32_t val) {
545 return spc_rnd(val);
546 }
547
548
get_luma8(uint8_t r,uint8_t g,uint8_t b)549 double get_luma8(uint8_t r, uint8_t g, uint8_t b) {
550 /// return luma value between 0. (black) and 1. (white)
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
get_luma16(uint16_t r,uint16_t g,uint16_t b)557 double get_luma16(uint16_t r, uint16_t g, uint16_t b) {
558 /// return luma value between 0. (black) and 1. (white)
559 return get_luma8(r >> 8, g >> 8, b >> 8);
560 }
561
562
init_RGB_to_YUV_tables(void)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
init_YUV_to_RGB_tables(void)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) /
694 (UV_CLAMP_MAX - YUV_CLAMP_MIN) * 255.) - UV_BIAS) * SCALE_FACTOR);
695
696 G_Crc[i] = myround(-.5 / (1. - KR_YCBCR) * ((((double)i - YUV_CLAMP_MIN) /
697 (UV_CLAMP_MAX - YUV_CLAMP_MIN) * 255.) - UV_BIAS) * SCALE_FACTOR);
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) /
707 (UV_CLAMP_MAX - YUV_CLAMP_MIN) * 255.) - UV_BIAS) * SCALE_FACTOR);
708 G_Cbc[i] = myround(-.5 / (1. + KB_YCBCR + KR_YCBCR) * (((UV_CLAMP_MAX - YUV_CLAMP_MIN) /
709 (UV_CLAMP_MAX - YUV_CLAMP_MIN) * 255.) - UV_BIAS) * SCALE_FACTOR);
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) /
745 (UV_CLAMP_MAX - YUV_CLAMP_MIN) * 255.) - UV_BIAS) * SCALE_FACTOR);
746 HG_Cbc[i] = myround(-.5 / (1. + KB_BT709 + KB_BT709) * ((((double)i - YUV_CLAMP_MIN) /
747 (UV_CLAMP_MAX - YUV_CLAMP_MIN) * 255.) - UV_BIAS) * SCALE_FACTOR);
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
init_YUV_to_YUV_tables(void)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
init_average(void)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
init_unal(void)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
set_conversion_arrays(int clamping,int subspace)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
get_YUV_to_YUV_conversion_arrays(int iclamping,int isubspace,int oclamping,int osubspace)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
rgb2xyz(uint8_t r,uint8_t g,uint8_t b,double * x,double * y,double * z)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.
lab_conv(double a)1026 LIVES_LOCAL_INLINE double lab_conv(double a) {return a > LAB0 ? pow(a, LAB1) : a * LAB2 + LAB3;}
1027
xyz2lab(double x,double y,double z,double * l,double * a,double * b)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
cdist94lab(double l0,double a0,double b0,double l1,double a1,double b1)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
get_maxmin_diff(uint8_t a,uint8_t b,uint8_t c,uint8_t * max,uint8_t * min)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
cdist94(uint8_t r0,uint8_t g0,uint8_t b0,uint8_t r1,uint8_t g1,uint8_t b1)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
rgb2hsv(uint8_t r,uint8_t g,uint8_t b,double * h,double * s,double * v)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
hsv2rgb(double h,double s,double v,uint8_t * r,uint8_t * g,uint8_t * b)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
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)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;
1174 /// pick a random col
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
1195 //////////////////////////
1196 // pixel conversions
1197 #ifdef WEED_ADVANCED_PALETTES
1198
1199 static weed_macropixel_t advp[256];
1200
init_advanced_palettes(void)1201 void init_advanced_palettes(void) {
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
1241 /// yuv planar
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
1271 /// yuv packed
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
1299 /// alpha
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
get_advanced_palette(int weed_palette)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
weed_palette_is_valid(int pal)1374 LIVES_GLOBAL_INLINE boolean weed_palette_is_valid(int pal) {
1375 return (get_advanced_palette(pal) != NULL);
1376 }
1377
get_simple_palette(weed_macropixel_t * mpx)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
is_rgbchan(uint16_t ctype)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
is_yuvchan(uint16_t ctype)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
pixel_size(int pal)1391 LIVES_GLOBAL_INLINE size_t pixel_size(int pal) {
1392 /// This is actually the MACRO pixel size om bytes, to get the real pixel size, divide by weed_palette_pixels_per_macropixel()
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
weed_palette_get_pixels_per_macropixel(int pal)1403 LIVES_GLOBAL_INLINE int weed_palette_get_pixels_per_macropixel(int pal) {
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
weed_palette_get_bits_per_macropixel(int pal)1411 LIVES_GLOBAL_INLINE int weed_palette_get_bits_per_macropixel(int pal) {
1412 int ppm = weed_palette_get_pixels_per_macropixel(pal);
1413 if (ppm) return pixel_size(pal) * 8;
1414 return 0;
1415 }
1416
weed_palette_get_nplanes(int pal)1417 LIVES_GLOBAL_INLINE int weed_palette_get_nplanes(int pal) {
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
weed_palette_is_alpha(int pal)1427 LIVES_GLOBAL_INLINE boolean weed_palette_is_alpha(int pal) {
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
weed_palette_red_first(int pal)1433 LIVES_GLOBAL_INLINE boolean weed_palette_red_first(int pal) {
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
weed_palettes_rbswapped(int pal0,int pal1)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
weed_palette_is_rgb(int pal)1448 LIVES_GLOBAL_INLINE boolean weed_palette_is_rgb(int pal) {
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
weed_palette_is_yuv(int pal)1457 LIVES_GLOBAL_INLINE boolean weed_palette_is_yuv(int pal) {
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
weed_palette_has_alpha(int pal)1466 LIVES_GLOBAL_INLINE boolean weed_palette_has_alpha(int pal) {
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
weed_palette_is_float(int pal)1475 LIVES_GLOBAL_INLINE boolean weed_palette_is_float(int pal) {
1476 const weed_macropixel_t *mpx = get_advanced_palette(pal);
1477 return (mpx && (mpx->flags & WEED_VCHAN_DESC_FP));
1478 }
1479
weed_palette_get_plane_ratio_horizontal(int pal,int plane)1480 LIVES_GLOBAL_INLINE double weed_palette_get_plane_ratio_horizontal(int pal, int plane) {
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
weed_palette_get_plane_ratio_vertical(int pal,int plane)1488 LIVES_GLOBAL_INLINE double weed_palette_get_plane_ratio_vertical(int pal, int plane) {
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
_get_alpha(int pal)1496 LIVES_LOCAL_INLINE int _get_alpha(int pal) {
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
weed_palette_get_alpha_plane(int pal)1505 LIVES_GLOBAL_INLINE int weed_palette_get_alpha_plane(int pal) {
1506 if (weed_palette_is_planar(pal)) return _get_alpha(pal);
1507 return -1;
1508 }
1509
weed_palette_get_alpha_offset(int pal)1510 LIVES_GLOBAL_INLINE int weed_palette_get_alpha_offset(int pal) {
1511 if (!weed_palette_is_planar(pal)) return _get_alpha(pal);
1512 return -1;
1513 }
1514
weed_palette_has_alpha_first(int pal)1515 LIVES_GLOBAL_INLINE boolean weed_palette_has_alpha_first(int pal) {
1516 return _get_alpha(pal) == 0;
1517 }
1518
weed_palette_has_alpha_last(int pal)1519 LIVES_GLOBAL_INLINE boolean weed_palette_has_alpha_last(int pal) {
1520 return _get_alpha(pal) == 3;
1521 }
1522
weed_palette_is_sane(int pal)1523 LIVES_GLOBAL_INLINE boolean weed_palette_is_sane(int pal) {
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
init_gamma_tx(void)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
init_colour_engine(void)1661 void init_colour_engine(void) {
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();
1668 init_conversions(LIVES_INTENTION_PLAY);
1669 #ifdef WEED_ADVANCED_PALETTES
1670 init_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,
1757 uyvy_macropixel *uyvy) GNU_FLATTEN GNU_HOT;
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,
1761 uyvy_macropixel *uyvy) GNU_FLATTEN GNU_HOT;
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,
1768 yuyv_macropixel *yuyv) GNU_FLATTEN GNU_HOT;
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
avg_chromaf_fast(uint8_t x,uint8_t y)1800 static uint8_t avg_chromaf_fast(uint8_t x, uint8_t y) {
1801 return avg_chroma(x, y);
1802 }
1803
init_conversions(int intent)1804 LIVES_GLOBAL_INLINE void init_conversions(int intent) {
1805 avg_chromaf = avg_chromaf_fast;
1806 if (intent == LIVES_INTENTION_RENDER || intent == LIVES_INTENTION_TRANSCODE) {
1807 //avg_chromaf = avg_chromaf_high;
1808 if (prefs) prefs->pb_quality = PB_QUALITY_HIGH;
1809 /// set the 'effort' to as low as possible; if using adaptive quality
1810 // this ensures we render at the highest settings
1811 mainw->effort = -EFFORT_RANGE_MAX;
1812 } else {
1813 if (prefs) prefs->pb_quality = future_prefs->pb_quality;
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
rgb2yuv(uint8_t r0,uint8_t g0,uint8_t b0,uint8_t * y,uint8_t * u,uint8_t * v)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
rgb2yuv_with_gamma(uint8_t r0,uint8_t g0,uint8_t b0,uint8_t * y,uint8_t * u,uint8_t * v,uint8_t * lut)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
rgb2uyvy(uint8_t r0,uint8_t g0,uint8_t b0,uint8_t r1,uint8_t g1,uint8_t b1,uyvy_macropixel * uyvy)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
rgb2uyvy_with_gamma(uint8_t r0,uint8_t g0,uint8_t b0,uint8_t r1,uint8_t g1,uint8_t b1,uyvy_macropixel * uyvy,uint8_t * lut)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
rgb2yuyv(uint8_t r0,uint8_t g0,uint8_t b0,uint8_t r1,uint8_t g1,uint8_t b1,yuyv_macropixel * yuyv)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
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)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
rgb16_2uyvy(uint16_t r0,uint16_t g0,uint16_t b0,uint16_t r1,uint16_t g1,uint16_t b1,uyvy_macropixel * uyvy)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
rgb2_411(uint8_t r0,uint8_t g0,uint8_t b0,uint8_t r1,uint8_t g1,uint8_t b1,uint8_t r2,uint8_t g2,uint8_t b2,uint8_t r3,uint8_t g3,uint8_t b3,yuv411_macropixel * yuv)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
yuv2rgb(uint8_t y,uint8_t u,uint8_t v,uint8_t * r,uint8_t * g,uint8_t * b)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
yuv2rgb_with_gamma(uint8_t y,uint8_t u,uint8_t v,uint8_t * r,uint8_t * g,uint8_t * b,uint8_t * lut)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
uyvy2rgb(uyvy_macropixel * uyvy,uint8_t * r0,uint8_t * g0,uint8_t * b0,uint8_t * r1,uint8_t * g1,uint8_t * b1)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
yuyv2rgb(yuyv_macropixel * yuyv,uint8_t * r0,uint8_t * g0,uint8_t * b0,uint8_t * r1,uint8_t * g1,uint8_t * b1)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
yuv888_2_rgb(uint8_t * yuv,uint8_t * rgb,boolean add_alpha)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
yuva8888_2_rgba(uint8_t * yuva,uint8_t * rgba,boolean del_alpha)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
yuv888_2_bgr(uint8_t * yuv,uint8_t * bgr,boolean add_alpha)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
yuva8888_2_bgra(uint8_t * yuva,uint8_t * bgra,boolean del_alpha)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
yuv888_2_argb(uint8_t * yuv,uint8_t * argb)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
yuva8888_2_argb(uint8_t * yuva,uint8_t * argb)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
uyvy_2_yuv422(uyvy_macropixel * uyvy,uint8_t * y0,uint8_t * u0,uint8_t * v0,uint8_t * y1)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
yuyv_2_yuv422(yuyv_macropixel * yuyv,uint8_t * y0,uint8_t * u0,uint8_t * v0,uint8_t * y1)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
2126 /////////////////////////////////////////////////
2127 //utilities
2128
2129
weed_palette_is_painter_palette(int pal)2130 LIVES_GLOBAL_INLINE boolean weed_palette_is_painter_palette(int pal) {
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
weed_palette_is_lower_quality(int p1,int p2)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
2191 /////////////////////////////////////////////////////////
2192
lives_pixbuf_is_all_black(LiVESPixbuf * pixbuf)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) {
2208 /** return FALSE if r >= 32, b >= 32 and g >= 24
2209 here we use a, b, and c for the first 3 bytes of the pixel. Since a and c are symmetric and we ignore byte 4,
2210 this will work for RGB, BGR, RGBA and BGRA (we could also check ARGB by setting offs to 1).
2211
2212 Algorithm:
2213 (a & 0x1F) ^ a - nonzero iff a >= 32
2214 (c & 0x1F) ^ c - nonzero iff c >= 32
2215
2216 ((a & c) & 0x1F) ^ (a & c) - nonzero only if both are true
2217
2218 (b & 0x1F) ^ b - nonzero iff b >= 32
2219 ((b << 1) & 0x1F) ^ (b << 1) - nonzero iff b >= 16
2220 ((b << 2) & 0x1F) ^ (b << 2) - nonzero iff b >= 8
2221 b & 0x0F - masks any values >= 32
2222 */
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
pixel_data_planar_from_membuf(void ** pixel_data,void * data,size_t size,int palette,boolean contig)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
2279 ///////////////////////////////////////////////////////////
2280 // frame conversions
2281
convert_yuv888_to_rgb_frame(uint8_t * src,int hsize,int vsize,int irowstride,int orowstride,uint8_t * dest,boolean add_alpha,int clamping,int subspace,int thread_id)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;
2297 lives_cc_params *ccparams = (lives_cc_params *)lives_calloc(prefs->nfx_threads, sizeof(lives_cc_params));
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
convert_yuv888_to_rgb_frame_thread(void * data)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
convert_yuva8888_to_rgba_frame(uint8_t * src,int hsize,int vsize,int irowstride,int orowstride,uint8_t * dest,boolean del_alpha,int clamping,int subspace,int thread_id)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;
2378 lives_cc_params *ccparams = (lives_cc_params *)lives_calloc(prefs->nfx_threads, sizeof(lives_cc_params));
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
convert_yuva8888_to_rgba_frame_thread(void * data)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
convert_yuv888_to_bgr_frame(uint8_t * src,int hsize,int vsize,int irowstride,int orowstride,uint8_t * dest,boolean add_alpha,int clamping,int subspace,int thread_id)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;
2456 lives_cc_params *ccparams = (lives_cc_params *)lives_calloc(prefs->nfx_threads, sizeof(lives_cc_params));
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
convert_yuv888_to_bgr_frame_thread(void * data)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
convert_yuva8888_to_bgra_frame(uint8_t * src,int hsize,int vsize,int irowstride,int orowstride,uint8_t * dest,boolean del_alpha,int clamping,int subspace,int thread_id)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;
2535 lives_cc_params *ccparams = (lives_cc_params *)lives_calloc(prefs->nfx_threads, sizeof(lives_cc_params));
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
convert_yuva8888_to_bgra_frame_thread(void * data)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
convert_yuv888_to_argb_frame(uint8_t * src,int hsize,int vsize,int irowstride,int orowstride,uint8_t * dest,int clamping,int subspace,int thread_id)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;
2613 lives_cc_params *ccparams = (lives_cc_params *)lives_calloc(prefs->nfx_threads, sizeof(lives_cc_params));
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
convert_yuv888_to_argb_frame_thread(void * data)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
convert_yuva8888_to_argb_frame(uint8_t * src,int hsize,int vsize,int irowstride,int orowstride,uint8_t * dest,int clamping,int subspace,int thread_id)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;
2690 lives_cc_params *ccparams = (lives_cc_params *)lives_calloc(prefs->nfx_threads, sizeof(lives_cc_params));
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
convert_yuva8888_to_argb_frame_thread(void * data)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
convert_yuv420p_to_rgb_frame(uint8_t ** src,int width,int height,boolean is_bottom,int * istrides,int orowstride,uint8_t * dest,boolean add_alpha,boolean is_422,int sampling,int clamping,int subspace,int gamma,int tgamma,uint8_t * gamma_lut,int thread_id)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
2766 /// TODO: this is NOT threadsafe !!!!
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;
2775 lives_cc_params *ccparams = (lives_cc_params *)lives_calloc(prefs->nfx_threads, sizeof(lives_cc_params));
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++);
2840 /// even row, normal
2841 if (j > 0) {
2842 /// center = 3 : 1, left = only next, right = avg(last, next)
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) {
2876 /// even row, normal
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 }
2889 /// center = 3 : 1, left = avg(last, next), right = only next
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
convert_yuv420p_to_rgb_frame_thread(void * data)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
convert_yuv420p_to_bgr_frame(uint8_t ** src,int width,int height,boolean is_bottom,int * istrides,int orowstride,uint8_t * dest,boolean add_alpha,boolean is_422,int sampling,int clamping,int subspace,int gamma,int tgamma,uint8_t * gamma_lut,int thread_id)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
2938 /// TODO: this is NOT threadsafe !!!!
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;
2947 lives_cc_params *ccparams = (lives_cc_params *)lives_calloc(prefs->nfx_threads, sizeof(lives_cc_params));
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++);
3011 /// even row, normal
3012 if (j > 0) {
3013 /// center = 3 : 1, left = only next, right = avg(last, next)
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) {
3046 /// even row, normal
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 }
3058 /// center = 3 : 1, left = avg(last, next), right = only next
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
convert_yuv420p_to_bgr_frame_thread(void * data)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
convert_yuv420p_to_argb_frame(uint8_t ** src,int width,int height,boolean is_bottom,int * istrides,int orowstride,uint8_t * dest,boolean is_422,int sampling,int clamping,int subspace,int gamma,int tgamma,uint8_t * gamma_lut,int thread_id)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
3108 /// TODO: this is NOT threadsafe !!!!
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;
3117 lives_cc_params *ccparams = (lives_cc_params *)lives_calloc(prefs->nfx_threads, sizeof(lives_cc_params));
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++);
3180 /// even row, normal
3181 if (j > 0) {
3182 /// center = 3 : 1, left = only next, right = avg(last, next)
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) {
3215 /// even row, normal
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 }
3227 /// center = 3 : 1, left = avg(last, next), right = only next
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
convert_yuv420p_to_argb_frame_thread(void * data)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
convert_rgb_to_uyvy_frame(uint8_t * rgbdata,int hsize,int vsize,int rowstride,int orowstride,uyvy_macropixel * u,boolean has_alpha,int clamping,uint8_t * gamma_lut,int thread_id)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;
3282 lives_cc_params *ccparams = (lives_cc_params *)lives_calloc(prefs->nfx_threads, sizeof(lives_cc_params));
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
convert_rgb_to_uyvy_frame_thread(void * data)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
convert_rgb_to_yuyv_frame(uint8_t * rgbdata,int hsize,int vsize,int rowstride,int orowstride,yuyv_macropixel * u,boolean has_alpha,int clamping,uint8_t * gamma_lut,int thread_id)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;
3375 lives_cc_params *ccparams = (lives_cc_params *)lives_calloc(prefs->nfx_threads, sizeof(lives_cc_params));
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
convert_rgb_to_yuyv_frame_thread(void * data)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
convert_bgr_to_uyvy_frame(uint8_t * rgbdata,int hsize,int vsize,int rowstride,int orowstride,uyvy_macropixel * u,boolean has_alpha,int clamping,uint8_t * gamma_lut,int thread_id)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;
3467 lives_cc_params *ccparams = (lives_cc_params *)lives_calloc(prefs->nfx_threads, sizeof(lives_cc_params));
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
convert_bgr_to_uyvy_frame_thread(void * data)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
convert_bgr_to_yuyv_frame(uint8_t * rgbdata,int hsize,int vsize,int rowstride,int orowstride,yuyv_macropixel * u,boolean has_alpha,int clamping,uint8_t * gamma_lut,int thread_id)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;
3561 lives_cc_params *ccparams = (lives_cc_params *)lives_calloc(prefs->nfx_threads, sizeof(lives_cc_params));
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
convert_bgr_to_yuyv_frame_thread(void * data)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
convert_argb_to_uyvy_frame(uint8_t * rgbdata,int hsize,int vsize,int rowstride,int orowstride,uyvy_macropixel * u,int clamping,uint8_t * gamma_lut,int thread_id)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;
3653 lives_cc_params *ccparams = (lives_cc_params *)lives_calloc(prefs->nfx_threads, sizeof(lives_cc_params));
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
convert_argb_to_uyvy_frame_thread(void * data)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
convert_argb_to_yuyv_frame(uint8_t * rgbdata,int hsize,int vsize,int rowstride,int orowstride,yuyv_macropixel * u,int clamping,uint8_t * gamma_lut,int thread_id)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;
3737 lives_cc_params *ccparams = (lives_cc_params *)lives_calloc(prefs->nfx_threads, sizeof(lives_cc_params));
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
convert_argb_to_yuyv_frame_thread(void * data)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
convert_rgb_to_yuv_frame(uint8_t * rgbdata,int hsize,int vsize,int rowstride,int orow,uint8_t * u,boolean in_has_alpha,boolean out_has_alpha,int clamping,int thread_id)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;
3818 lives_cc_params *ccparams = (lives_cc_params *)lives_calloc(prefs->nfx_threads, sizeof(lives_cc_params));
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
convert_rgb_to_yuv_frame_thread(void * data)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
convert_rgb_to_yuvp_frame(uint8_t * rgbdata,int hsize,int vsize,int rowstride,int orow,uint8_t ** yuvp,boolean in_has_alpha,boolean out_has_alpha,int clamping,int thread_id)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;
3909 lives_cc_params *ccparams = (lives_cc_params *)lives_calloc(prefs->nfx_threads, sizeof(lives_cc_params));
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
convert_rgb_to_yuvp_frame_thread(void * data)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
convert_bgr_to_yuv_frame(uint8_t * rgbdata,int hsize,int vsize,int rowstride,int orow,uint8_t * u,boolean in_has_alpha,boolean out_has_alpha,int clamping,int thread_id)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;
4001 lives_cc_params *ccparams = (lives_cc_params *)lives_calloc(prefs->nfx_threads, sizeof(lives_cc_params));
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
convert_bgr_to_yuv_frame_thread(void * data)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
convert_bgr_to_yuvp_frame(uint8_t * rgbdata,int hsize,int vsize,int rowstride,int orow,uint8_t ** yuvp,boolean in_has_alpha,boolean out_has_alpha,int clamping,int thread_id)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;
4092 lives_cc_params *ccparams = (lives_cc_params *)lives_calloc(prefs->nfx_threads, sizeof(lives_cc_params));
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
convert_bgr_to_yuvp_frame_thread(void * data)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
convert_argb_to_yuv_frame(uint8_t * rgbdata,int hsize,int vsize,int rowstride,int orow,uint8_t * u,boolean out_has_alpha,int clamping,int thread_id)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;
4183 lives_cc_params *ccparams = (lives_cc_params *)lives_calloc(prefs->nfx_threads, sizeof(lives_cc_params));
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
convert_argb_to_yuv_frame_thread(void * data)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
convert_argb_to_yuvp_frame(uint8_t * rgbdata,int hsize,int vsize,int rowstride,int orow,uint8_t ** yuvp,boolean out_has_alpha,int clamping,int thread_id)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;
4270 lives_cc_params *ccparams = (lives_cc_params *)lives_calloc(prefs->nfx_threads, sizeof(lives_cc_params));
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
convert_argb_to_yuvp_frame_thread(void * data)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
convert_rgb_to_yuv420_frame(uint8_t * rgbdata,int hsize,int vsize,int rowstride,int * ostrides,uint8_t ** dest,boolean is_422,boolean has_alpha,int subspace,int clamping)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
convert_argb_to_yuv420_frame(uint8_t * rgbdata,int hsize,int vsize,int rowstride,int * ostrides,uint8_t ** dest,boolean is_422,int subspace,int clamping)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
convert_bgr_to_yuv420_frame(uint8_t * rgbdata,int hsize,int vsize,int rowstride,int * ostrides,uint8_t ** dest,boolean is_422,boolean has_alpha,int subspace,int clamping)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
convert_yuv422p_to_uyvy_frame(uint8_t ** src,int width,int height,int * irows,int orow,uint8_t * dest)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
convert_yuv422p_to_yuyv_frame(uint8_t ** src,int width,int height,int * irows,int orow,uint8_t * dest)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
convert_rgb_to_yuv411_frame(uint8_t * rgbdata,int hsize,int vsize,int rowstride,yuv411_macropixel * u,boolean has_alpha,int clamping)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
convert_bgr_to_yuv411_frame(uint8_t * rgbdata,int hsize,int vsize,int rowstride,yuv411_macropixel * u,boolean has_alpha,int clamping)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
convert_argb_to_yuv411_frame(uint8_t * rgbdata,int hsize,int vsize,int rowstride,yuv411_macropixel * u,int clamping)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
convert_uyvy_to_rgb_frame(uyvy_macropixel * src,int width,int height,int irow,int orowstride,uint8_t * dest,boolean add_alpha,int clamping,int subspace,int thread_id)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;
4720 lives_cc_params *ccparams = (lives_cc_params *)lives_calloc(prefs->nfx_threads, sizeof(lives_cc_params));
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
convert_uyvy_to_rgb_frame_thread(void * data)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
convert_uyvy_to_bgr_frame(uyvy_macropixel * src,int width,int height,int irow,int orowstride,uint8_t * dest,boolean add_alpha,int clamping,int thread_id)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;
4806 lives_cc_params *ccparams = (lives_cc_params *)lives_calloc(prefs->nfx_threads, sizeof(lives_cc_params));
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
convert_uyvy_to_bgr_frame_thread(void * data)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
convert_uyvy_to_argb_frame(uyvy_macropixel * src,int width,int height,int irow,int orowstride,uint8_t * dest,int clamping,int thread_id)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;
4888 lives_cc_params *ccparams = (lives_cc_params *)lives_calloc(prefs->nfx_threads, sizeof(lives_cc_params));
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
convert_uyvy_to_argb_frame_thread(void * data)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
convert_yuyv_to_rgb_frame(yuyv_macropixel * src,int width,int height,int irow,int orowstride,uint8_t * dest,boolean add_alpha,int clamping,int thread_id)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;
4963 lives_cc_params *ccparams = (lives_cc_params *)lives_calloc(prefs->nfx_threads, sizeof(lives_cc_params));
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
convert_yuyv_to_rgb_frame_thread(void * data)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
convert_yuyv_to_bgr_frame(yuyv_macropixel * src,int width,int height,int irow,int orowstride,uint8_t * dest,boolean add_alpha,int clamping,int thread_id)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;
5045 lives_cc_params *ccparams = (lives_cc_params *)lives_calloc(prefs->nfx_threads, sizeof(lives_cc_params));
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
convert_yuyv_to_bgr_frame_thread(void * data)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
convert_yuyv_to_argb_frame(yuyv_macropixel * src,int width,int height,int irow,int orowstride,uint8_t * dest,int clamping,int thread_id)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;
5127 lives_cc_params *ccparams = (lives_cc_params *)lives_calloc(prefs->nfx_threads, sizeof(lives_cc_params));
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
convert_yuyv_to_argb_frame_thread(void * data)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
convert_yuv420_to_uyvy_frame(uint8_t ** src,int width,int height,int * irows,int orow,uyvy_macropixel * dest,int clamping)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
convert_yuv420_to_yuyv_frame(uint8_t ** src,int width,int height,int * irows,int orow,yuyv_macropixel * dest,int clamping)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
convert_yuv_planar_to_rgb_frame(uint8_t ** src,int width,int height,int irowstride,int orowstride,uint8_t * dest,boolean in_alpha,boolean out_alpha,int clamping,int thread_id)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;
5305 lives_cc_params *ccparams = (lives_cc_params *)lives_calloc(prefs->nfx_threads, sizeof(lives_cc_params));
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
convert_yuv_planar_to_rgb_frame_thread(void * data)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
convert_yuv_planar_to_bgr_frame(uint8_t ** src,int width,int height,int irowstride,int orowstride,uint8_t * dest,boolean in_alpha,boolean out_alpha,int clamping,int thread_id)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;
5405 lives_cc_params *ccparams = (lives_cc_params *)lives_calloc(prefs->nfx_threads, sizeof(lives_cc_params));
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
convert_yuv_planar_to_bgr_frame_thread(void * data)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
convert_yuv_planar_to_argb_frame(uint8_t ** src,int width,int height,int irowstride,int orowstride,uint8_t * dest,boolean in_alpha,int clamping,int thread_id)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;
5503 lives_cc_params *ccparams = (lives_cc_params *)lives_calloc(prefs->nfx_threads, sizeof(lives_cc_params));
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
convert_yuv_planar_to_argb_frame_thread(void * data)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
convert_yuv_planar_to_uyvy_frame(uint8_t ** src,int width,int height,int irowstride,int orowstride,uyvy_macropixel * uyvy,int clamping)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
convert_yuv_planar_to_yuyv_frame(uint8_t ** src,int width,int height,int irowstride,int orowstride,yuyv_macropixel * yuyv,int clamping)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
convert_combineplanes_frame(uint8_t ** src,int width,int height,int irowstride,int orowstride,uint8_t * dest,boolean in_alpha,boolean out_alpha)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
convert_yuvap_to_yuvp_frame(uint8_t ** src,int width,int height,int irowstride,int orowstride,uint8_t ** dest)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
convert_yuvp_to_yuvap_frame(uint8_t ** src,int width,int height,int irowstride,int orowstride,uint8_t ** dest)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
convert_yuvp_to_yuv420_frame(uint8_t ** src,int width,int height,int * irows,int * orows,uint8_t ** dest,int clamping)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
convert_yuvp_to_yuv411_frame(uint8_t ** src,int width,int height,int irowstride,yuv411_macropixel * yuv,int clamping)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
convert_uyvy_to_yuvp_frame(uyvy_macropixel * uyvy,int width,int height,int irow,int * orow,uint8_t ** dest,boolean add_alpha)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
convert_yuyv_to_yuvp_frame(yuyv_macropixel * yuyv,int width,int height,int irow,int * orow,uint8_t ** dest,boolean add_alpha)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
convert_uyvy_to_yuv888_frame(uyvy_macropixel * uyvy,int width,int height,int irow,int orow,uint8_t * yuv,boolean add_alpha)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
convert_yuyv_to_yuv888_frame(yuyv_macropixel * yuyv,int width,int height,int irow,int orow,uint8_t * yuv,boolean add_alpha)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
convert_uyvy_to_yuv420_frame(uyvy_macropixel * uyvy,int width,int height,uint8_t ** yuv,int clamping)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
convert_yuyv_to_yuv420_frame(yuyv_macropixel * yuyv,int width,int height,uint8_t ** yuv,int clamping)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
convert_uyvy_to_yuv411_frame(uyvy_macropixel * uyvy,int width,int height,yuv411_macropixel * yuv,int clamping)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
convert_yuyv_to_yuv411_frame(yuyv_macropixel * yuyv,int width,int height,yuv411_macropixel * yuv,int clamping)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
convert_yuv888_to_yuv420_frame(uint8_t * yuv8,int width,int height,int irowstride,int * orows,uint8_t ** yuv4,boolean src_alpha,int clamping)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
convert_uyvy_to_yuv422_frame(uyvy_macropixel * uyvy,int width,int height,uint8_t ** yuv)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
convert_yuyv_to_yuv422_frame(yuyv_macropixel * yuyv,int width,int height,uint8_t ** yuv)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
convert_yuv888_to_yuv422_frame(uint8_t * yuv8,int width,int height,int irowstride,int * ostrides,uint8_t ** yuv4,boolean has_alpha,int clamping)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
convert_yuv888_to_uyvy_frame(uint8_t * yuv,int width,int height,int irowstride,int orow,uyvy_macropixel * uyvy,boolean has_alpha,int clamping)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
convert_yuv888_to_yuyv_frame(uint8_t * yuv,int width,int height,int irowstride,int orow,yuyv_macropixel * yuyv,boolean has_alpha,int clamping)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
convert_yuv888_to_yuv411_frame(uint8_t * yuv8,int width,int height,int irowstride,yuv411_macropixel * yuv411,boolean has_alpha)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
convert_yuv411_to_rgb_frame(yuv411_macropixel * yuv411,int width,int height,int orowstride,uint8_t * dest,boolean add_alpha,int clamping)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
convert_yuv411_to_bgr_frame(yuv411_macropixel * yuv411,int width,int height,int orowstride,uint8_t * dest,boolean add_alpha,int clamping)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
convert_yuv411_to_argb_frame(yuv411_macropixel * yuv411,int width,int height,int orowstride,uint8_t * dest,int clamping)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
convert_yuv411_to_yuv888_frame(yuv411_macropixel * yuv411,int width,int height,uint8_t * dest,boolean add_alpha,int clamping)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
convert_yuv411_to_yuvp_frame(yuv411_macropixel * yuv411,int width,int height,uint8_t ** dest,boolean add_alpha,int clamping)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
convert_yuv411_to_uyvy_frame(yuv411_macropixel * yuv411,int width,int height,uyvy_macropixel * uyvy,int clamping)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
convert_yuv411_to_yuyv_frame(yuv411_macropixel * yuv411,int width,int height,yuyv_macropixel * yuyv,int clamping)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
convert_yuv411_to_yuv422_frame(yuv411_macropixel * yuv411,int width,int height,uint8_t ** dest,int clamping)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
convert_yuv411_to_yuv420_frame(yuv411_macropixel * yuv411,int width,int height,uint8_t ** dest,boolean is_yvu,int clamping)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
convert_yuv420_to_yuv411_frame(uint8_t ** src,int hsize,int vsize,yuv411_macropixel * dest,boolean is_422,int clamping)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
convert_splitplanes_frame(uint8_t * src,int width,int height,int irowstride,int * orowstrides,uint8_t ** dest,boolean src_alpha,boolean dest_alpha)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
7324 /////////////////////////////////////////////////////////////////
7325 // RGB palette conversions
7326
convert_swap3_frame(uint8_t * src,int width,int height,int irowstride,int orowstride,uint8_t * dest,uint8_t * gamma_lut,int thread_id)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;
7337 lives_cc_params *ccparams = (lives_cc_params *)lives_calloc(prefs->nfx_threads, sizeof(lives_cc_params));
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
convert_swap3_frame_thread(void * data)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
convert_swap4_frame(uint8_t * src,int width,int height,int irowstride,int orowstride,uint8_t * dest,int thread_id)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;
7455 lives_cc_params *ccparams = (lives_cc_params *)lives_calloc(prefs->nfx_threads, sizeof(lives_cc_params));
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
convert_swap4_frame_thread(void * data)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
convert_swap3addpost_frame(uint8_t * src,int width,int height,int irowstride,int orowstride,uint8_t * dest,int thread_id)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;
7549 lives_cc_params *ccparams = (lives_cc_params *)lives_calloc(prefs->nfx_threads, sizeof(lives_cc_params));
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
convert_swap3addpost_frame_thread(void * data)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
convert_swap3addpre_frame(uint8_t * src,int width,int height,int irowstride,int orowstride,uint8_t * dest,int thread_id)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;
7627 lives_cc_params *ccparams = (lives_cc_params *)lives_calloc(prefs->nfx_threads, sizeof(lives_cc_params));
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
convert_swap3addpre_frame_thread(void * data)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
convert_swap3postalpha_frame(uint8_t * src,int width,int height,int rowstride,int thread_id)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;
7704 lives_cc_params *ccparams = (lives_cc_params *)lives_calloc(prefs->nfx_threads, sizeof(lives_cc_params));
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
convert_swap3postalpha_frame_thread(void * data)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
convert_swap3prealpha_frame(uint8_t * src,int width,int height,int rowstride,int thread_id)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;
7768 lives_cc_params *ccparams = (lives_cc_params *)lives_calloc(prefs->nfx_threads, sizeof(lives_cc_params));
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
convert_swap3prealpha_frame_thread(void * data)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
convert_addpost_frame(uint8_t * src,int width,int height,int irowstride,int orowstride,uint8_t * dest,uint8_t * gamma_lut,int thread_id)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;
7833 lives_cc_params *ccparams = (lives_cc_params *)lives_calloc(prefs->nfx_threads, sizeof(lives_cc_params));
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
convert_addpost_frame_thread(void * data)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
convert_addpre_frame(uint8_t * src,int width,int height,int irowstride,int orowstride,uint8_t * dest,int thread_id)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;
7929 lives_cc_params *ccparams = (lives_cc_params *)lives_calloc(prefs->nfx_threads, sizeof(lives_cc_params));
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
convert_addpre_frame_thread(void * data)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
convert_swap3delpost_frame(uint8_t * src,int width,int height,int irowstride,int orowstride,uint8_t * dest,int thread_id)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;
8005 lives_cc_params *ccparams = (lives_cc_params *)lives_calloc(prefs->nfx_threads, sizeof(lives_cc_params));
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
convert_swap3delpost_frame_thread(void * data)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
convert_delpost_frame(uint8_t * src,int width,int height,int irowstride,int orowstride,uint8_t * dest,uint8_t * gamma_lut,int thread_id)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;
8081 lives_cc_params *ccparams = (lives_cc_params *)lives_calloc(prefs->nfx_threads, sizeof(lives_cc_params));
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
convert_delpost_frame_thread(void * data)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
convert_delpre_frame(uint8_t * src,int width,int height,int irowstride,int orowstride,uint8_t * dest,int thread_id)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;
8169 lives_cc_params *ccparams = (lives_cc_params *)lives_calloc(prefs->nfx_threads, sizeof(lives_cc_params));
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
convert_delpre_frame_thread(void * data)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
convert_swap3delpre_frame(uint8_t * src,int width,int height,int irowstride,int orowstride,uint8_t * dest,int thread_id)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;
8245 lives_cc_params *ccparams = (lives_cc_params *)lives_calloc(prefs->nfx_threads, sizeof(lives_cc_params));
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
convert_swap3delpre_frame_thread(void * data)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
convert_swapprepost_frame(uint8_t * src,int width,int height,int irowstride,int orowstride,uint8_t * dest,int thread_id)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;
8322 lives_cc_params *ccparams = (lives_cc_params *)lives_calloc(prefs->nfx_threads, sizeof(lives_cc_params));
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
convert_swapprepost_frame_thread(void * data)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
8413 //////////////////////////
8414 // genric YUV
8415
convert_swab_frame(uint8_t * src,int width,int height,int irow,int orow,uint8_t * dest,int thread_id)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;
8425 lives_cc_params *ccparams = (lives_cc_params *)lives_calloc(prefs->nfx_threads, sizeof(lives_cc_params));
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
convert_swab_frame_thread(void * data)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
convert_halve_chroma(uint8_t ** src,int width,int height,int * istrides,int * ostrides,uint8_t ** dest,int clamping)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
convert_double_chroma(uint8_t ** src,int width,int height,int * istrides,int * ostrides,uint8_t ** dest,int clamping)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
convert_quad_chroma(uint8_t ** src,int width,int height,int * istrides,int ostride,uint8_t ** dest,boolean add_alpha,int sampling,int clamping)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
convert_quad_chroma_packed(uint8_t ** src,int width,int height,int * istrides,int ostride,uint8_t * dest,boolean add_alpha,int sampling,int clamping)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
convert_double_chroma_packed(uint8_t ** src,int width,int height,int * istrides,int ostride,uint8_t * dest,boolean add_alpha,int sampling,int clamping)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
switch_yuv_sampling(weed_layer_t * layer)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
switch_yuv_clamping_and_subspace(weed_layer_t * layer,int oclamping,int osubspace)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
9003 ////////////////////////////////////////////////////////////////////////////////////////
9004 // TODO - move into layers.c
9005
9006 /**
9007 a "layer" is CHANNEL type plant which is not created from a plugin CHANNEL_TEMPLATE.
9008 When we pass this to a plugin, we need to adjust it depending
9009 on the plugin's CHANNEL_TEMPLATE to which we will assign it.
9010
9011 e.g.: memory may need aligning afterwards for particular plugins which set channel template flags:
9012 layer palette may need changing, layer may need resizing */
9013
9014 /**
9015 @brief fills the plane pointed to by ptr with bpix
9016
9017 psize is sizeof(bpix), width, height and rowstride are the dimensions of the target plane
9018 */
fill_plane(uint8_t * ptr,int psize,int width,int height,int rowstride,unsigned char * bpix)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
9037 /**
9038 @brief creates pixel data for layer
9039
9040 @returns FALSE on memory error
9041
9042 width, height, and current_palette must be pre-set in layer; width is in (macro) pixels of the palette
9043 width and height may be adjusted (rounded) in the function
9044 rowstrides will be set, and each plane will be aligned depending on THREADVAR(rowstride_alignment)
9045 if THREADVAR(rowstride_alignment_hint) is non 0 it will set THREADVAR(rowstride_alignment), which must be a power of 2
9046 the special value -1 for the hint will create compact frames (rowstride = width * pixel_size)
9047
9048 if black_fill is set, fill with opaque black in the specified palette: for yuv palettes, YUV_clamping may be pre-set
9049 otherwise it will be set to WEED_YUV_CLAMPING_CLAMPED.
9050
9051 may_contig should normally be set to TRUE, except for special uses during palette conversion
9052 if set, then for planar palettes, only plane 0 will be allocated, so only this value should be freed
9053 in this case, the leaf WEED_LEAF_HOST_PIXEL_DATA_CONTIGUOUS will be set to WEED_TRUE
9054
9055 the allocated frames will be aligned to the pixel size for whatever palette and may be padded with extra bytes
9056 to guard against accidental overwrites
9057 */
create_empty_pixel_data(weed_layer_t * layer,boolean black_fill,boolean may_contig)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) {
9094 /// force use of fixed rowstrides, eg. decoder plugin
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
9602 /**
9603 @brief fills layer with default values.
9604
9605 If either width or height are zero, then dimensions will be taken from the layer or
9606 defaults used
9607 if layer has a palette set, that will be maintained, else it will be set to target_palette
9608 if targette palette is WEED_PALETTE_END then default will be set depending on image_ext
9609 if this is "jpg" then it will be RGB24, otherwise RGBA32
9610 finally we create the pixel data for layer */
create_blank_layer(weed_layer_t * layer,const char * image_ext,int width,int height,int target_palette)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 }
9635 if (!create_empty_pixel_data(layer, TRUE, TRUE)) weed_layer_nullify_pixel_data(layer);
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
rowstrides_differ(int n1,int * n1_array,int n2,int * n2_array)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
weed_layer_new(int layer_type)9655 LIVES_GLOBAL_INLINE weed_layer_t *weed_layer_new(int layer_type) {
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
weed_layer_get_type(weed_layer_t * layer)9663 LIVES_GLOBAL_INLINE int weed_layer_get_type(weed_layer_t *layer) {
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
weed_layer_is_video(weed_layer_t * layer)9669 LIVES_GLOBAL_INLINE int weed_layer_is_video(weed_layer_t *layer) {
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
weed_layer_is_audio(weed_layer_t * layer)9675 LIVES_GLOBAL_INLINE int weed_layer_is_audio(weed_layer_t *layer) {
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
weed_layer_set_audio_data(weed_layer_t * layer,float ** data,int arate,int naudchans,weed_size_t nsamps)9681 LIVES_GLOBAL_INLINE weed_layer_t *weed_layer_set_audio_data(weed_layer_t *layer, float **data,
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
weed_layer_set_flags(weed_layer_t * layer,int flags)9692 LIVES_GLOBAL_INLINE weed_layer_t *weed_layer_set_flags(weed_layer_t *layer, int flags) {
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
weed_layer_get_flags(weed_layer_t * layer)9699 LIVES_GLOBAL_INLINE int weed_layer_get_flags(weed_layer_t *layer) {
9700 if (!layer || !WEED_IS_LAYER(layer)) return 0;
9701 return weed_get_int_value(layer, WEED_LEAF_FLAGS, NULL);
9702 }
9703
9704
lives_layer_get_clip(weed_layer_t * layer)9705 LIVES_GLOBAL_INLINE int lives_layer_get_clip(weed_layer_t *layer) {
9706 if (!layer || !WEED_IS_LAYER(layer)) return 0;
9707 return weed_get_int_value(layer, WEED_LEAF_CLIP, NULL);
9708 }
9709
9710
lives_layer_get_frame(weed_layer_t * layer)9711 LIVES_GLOBAL_INLINE frames_t lives_layer_get_frame(weed_layer_t *layer) {
9712 if (!layer || !WEED_IS_LAYER(layer)) return 0;
9713 return weed_get_int_value(layer, WEED_LEAF_FRAME, NULL);
9714 }
9715
9716
weed_layer_set_width(weed_layer_t * layer,int width)9717 LIVES_GLOBAL_INLINE weed_layer_t *weed_layer_set_width(weed_layer_t *layer, int width) {
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
weed_layer_set_height(weed_layer_t * layer,int height)9724 LIVES_GLOBAL_INLINE weed_layer_t *weed_layer_set_height(weed_layer_t *layer, int height) {
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
weed_layer_set_size(weed_layer_t * layer,int width,int height)9731 LIVES_GLOBAL_INLINE weed_layer_t *weed_layer_set_size(weed_layer_t *layer, int width, int height) {
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
weed_layer_set_pixel_data(weed_layer_t * layer,void ** pixel_data,int nplanes)9739 LIVES_GLOBAL_INLINE weed_layer_t *weed_layer_set_pixel_data(weed_layer_t *layer, void **pixel_data, int nplanes) {
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
weed_layer_set_pixel_data_packed(weed_layer_t * layer,void * pixel_data)9746 LIVES_GLOBAL_INLINE weed_layer_t *weed_layer_set_pixel_data_packed(weed_layer_t *layer, void *pixel_data) {
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
weed_layer_nullify_pixel_data(weed_layer_t * layer)9753 LIVES_GLOBAL_INLINE weed_layer_t *weed_layer_nullify_pixel_data(weed_layer_t *layer) {
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
weed_layer_set_rowstrides(weed_layer_t * layer,int * rowstrides,int nplanes)9763 LIVES_GLOBAL_INLINE weed_layer_t *weed_layer_set_rowstrides(weed_layer_t *layer, int *rowstrides, int nplanes) {
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
weed_layer_set_rowstride(weed_layer_t * layer,int rowstride)9770 LIVES_GLOBAL_INLINE weed_layer_t *weed_layer_set_rowstride(weed_layer_t *layer, int rowstride) {
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
weed_layer_set_palette(weed_layer_t * layer,int palette)9777 LIVES_GLOBAL_INLINE weed_layer_t *weed_layer_set_palette(weed_layer_t *layer, int palette) {
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
weed_layer_set_gamma(weed_layer_t * layer,int gamma_type)9784 LIVES_GLOBAL_INLINE weed_layer_t *weed_layer_set_gamma(weed_layer_t *layer, int gamma_type) {
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
weed_layer_set_yuv_clamping(weed_layer_t * layer,int clamping)9791 LIVES_GLOBAL_INLINE weed_layer_t *weed_layer_set_yuv_clamping(weed_layer_t *layer, int clamping) {
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
weed_layer_set_yuv_sampling(weed_layer_t * layer,int sampling)9798 LIVES_GLOBAL_INLINE weed_layer_t *weed_layer_set_yuv_sampling(weed_layer_t *layer, int sampling) {
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
weed_layer_set_yuv_subspace(weed_layer_t * layer,int subspace)9805 LIVES_GLOBAL_INLINE weed_layer_t *weed_layer_set_yuv_subspace(weed_layer_t *layer, int subspace) {
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
weed_layer_set_palette_yuv(weed_layer_t * layer,int palette,int clamping,int sampling,int subspace)9812 LIVES_GLOBAL_INLINE weed_layer_t *weed_layer_set_palette_yuv(weed_layer_t *layer, int palette,
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
lives_layer_set_frame(weed_layer_t * layer,frames_t frame)9822 LIVES_GLOBAL_INLINE void lives_layer_set_frame(weed_layer_t *layer, frames_t frame) {
9823 // TODO -> int64
9824 weed_set_int_value(layer, WEED_LEAF_FRAME, frame);
9825 }
9826
9827
lives_layer_set_clip(weed_layer_t * layer,int clip)9828 LIVES_GLOBAL_INLINE void lives_layer_set_clip(weed_layer_t *layer, int clip) {
9829 weed_set_int_value(layer, WEED_LEAF_CLIP, clip);
9830 }
9831
9832
lives_layer_new_for_frame(int clip,frames_t frame)9833 LIVES_GLOBAL_INLINE weed_layer_t *lives_layer_new_for_frame(int clip, frames_t frame) {
9834 // create a layer ready to receive a frame from a clip
9835 weed_layer_t *layer = weed_layer_new(WEED_LAYER_TYPE_VIDEO);
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
copy_pixel_data(weed_layer_t * layer,weed_layer_t * old_layer,size_t alignment)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;
9863 old_layer = weed_layer_new(WEED_LAYER_TYPE_VIDEO);
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
9875 weed_layer_nullify_pixel_data(layer);
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
9920 /** (un)premultply alpha using a lookup table
9921
9922 if un is FALSE we go the other way, and do a pre-multiplication */
alpha_unpremult(weed_layer_t * layer,boolean un)9923 void alpha_unpremult(weed_layer_t *layer, boolean un) {
9924 /// this is only used when going from palette with alpha to one without
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:
9969 /// special case - planar with alpha
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 {
10056 /// unclamped YUVA8888 (packed)
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
swap_chroma_planes(weed_layer_t * layer)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
can_inline_gamma(int inpl,int opal)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
10132 /**
10133 @brief convert the palette of a layer
10134
10135 convert to/from the 5 non-float RGB palettes and 10 YUV palettes
10136 giving a total of 15*14=210 conversions
10137
10138 in addition YUV can be converted from clamped to unclamped and vice-versa
10139
10140 chroma sub and supersampling is implemented, and threading is used wherever possible
10141
10142 all conversions are performed via lookup tables
10143
10144 NOTE - if converting to YUV411, we cut pixels so (RGB) width is divisible by 4
10145 if converting to YUV420 or YVU420, we cut pixels so (RGB) width is divisible by 2
10146 if converting to YUV420 or YVU420, we cut pixels so height is divisible by 2
10147
10148 returns FALSE if the palette conversion fails or if layer is NULL
10149
10150 - original palette pixel_data is free()d (unless converting between YUV420 and YVU420, there the u and v pointers are
10151 simply swapped).
10152
10153 current limitations:
10154 - chroma is assumed centred between luma for input and output
10155 - bt709 yuv is only implemented for conversions to / from rgb palettes and yuv420 / yvu420
10156 - rowstride values may be ignored for UYVY, YUYV and YUV411 planar palettes.
10157 - RGB float palettes not yet implemented
10158
10159 */
convert_layer_palette_full(weed_layer_t * layer,int outpl,int oclamping,int osampling,int osubspace,int tgamma)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);
10300 weed_layer_set_size(layer, width * weed_palette_get_pixels_per_macropixel(inpl)
10301 / weed_palette_get_pixels_per_macropixel(outpl), height);
10302 // TODO: rowstrides for uyvy, yuyv, 422P, 411
10303
10304 /// if V plane is before U, swap the pointers
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 {
10348 /// add pre
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 {
10363 /// inpl has post
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 {
10381 /// outpl has post
10382 convert_swap3postalpha_frame(gusrc, width, height, irowstride, -USE_THREADS);
10383 weed_layer_nullify_pixel_data(orig_layer);
10384 }
10385 } else {
10386 /// outpl has pre
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 {
10414 /// outpl has post
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 {
10425 /// outpl has pre
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:
11572 create_empty_pixel_data(layer, FALSE, FALSE);
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:
11583 create_empty_pixel_data(layer, FALSE, FALSE);
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:
11594 create_empty_pixel_data(layer, FALSE, FALSE);
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 {
11636 /// if we came in as YVU, we got swapped to YUV
11637 size_t frmsz = istrides[1] * (height >> 1);
11638 /// swap (again) and both become YVU
11639 swap_chroma_planes(layer);
11640 if (!(tmp = lives_calloc_safety(frmsz, 1))) goto memfail;
11641 /// swap again and both become YUV (YVU out will get swapped on more time)
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:
11726 create_empty_pixel_data(layer, FALSE, FALSE);
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:
11738 create_empty_pixel_data(layer, FALSE, FALSE);
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:
11749 create_empty_pixel_data(layer, FALSE, FALSE);
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
11919 /// if V plane is before U, swap the pointers
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
convert_layer_palette(weed_layer_t * layer,int outpl,int op_clamping)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
11950 /////////////////////////////////////////////////////////////////////////////////////
11951
11952
lives_pixbuf_new_blank(int width,int height,int palette)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
lives_pixbuf_cheat(boolean has_alpha,int width,int height,uint8_t * buf)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
weed_layer_get_gamma(weed_layer_t * layer)12002 int weed_layer_get_gamma(weed_layer_t *layer) {
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
gamma_conv_params(int gamma_type,weed_layer_t * inst,boolean is_in)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
gamma_convert_layer_thread(void * data)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
12120 /**
12121 @brief alter the transfer function of a Weed layer, from current value to gamma_type
12122
12123 */
gamma_convert_sub_layer(int gamma_type,double fileg,weed_layer_t * layer,int x,int y,int width,int height,boolean may_thread)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
gamma_convert_layer(int gamma_type,weed_layer_t * layer)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
gamma_convert_layer_variant(double file_gamma,int tgamma,weed_layer_t * layer)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
layer_to_pixbuf(weed_layer_t * layer,boolean realpalette,boolean fordisplay)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
12231 palette = weed_layer_get_palette(layer);
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);
12236 weed_layer_nullify_pixel_data(layer);
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 {
12248 width = weed_layer_get_width(layer) * weed_palette_get_pixels_per_macropixel(palette);
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) {
12255 if (!weed_palette_is_pixbuf_palette(palette)) {
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)
12262 gamma_convert_layer(WEED_GAMMA_MONITOR, layer);
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);
12274 weed_layer_nullify_pixel_data(layer);
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);
12297 weed_layer_nullify_pixel_data(layer);
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:
12306 if (weed_palette_has_alpha(palette)) {
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 }
12336 weed_layer_pixel_data_free(layer);
12337 }
12338
12339 return pixbuf;
12340 }
12341
12342
weed_palette_is_resizable(int pal,int clamped,boolean in_out)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
lives_pixbuf_set_opaque(LiVESPixbuf * pixbuf)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
lives_layer_set_opaque(weed_layer_t * layer)12385 void lives_layer_set_opaque(weed_layer_t *layer) {
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
compact_rowstrides(weed_layer_t * layer)12422 boolean compact_rowstrides(weed_layer_t *layer) {
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
12453 old_layer = weed_layer_new(WEED_LAYER_TYPE_VIDEO);
12454 if (!old_layer) return FALSE;
12455 if (!weed_layer_copy(old_layer, layer)) return FALSE;
12456
12457 THREADVAR(rowstride_alignment_hint) = -1;
12458 weed_layer_nullify_pixel_data(layer);
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
swscale_threadfunc(void * arg)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
12524 /**
12525 @brief resize a layer
12526
12527 width is in PIXELS (not macropixels)
12528
12529 opal_hint and oclamp_hint may be set to hint the desired output palette and YUV clamping
12530 this is simply to ensure more efficient resizing, and may be ignored
12531
12532 - setting opal_hint to WEED_PALETTE_END will attempt to minimise palette changes
12533
12534 "current_palette" should be checked on return as it may change
12535
12536 @return FALSE if we were unable to resize */
resize_layer(weed_layer_t * layer,int width,int height,LiVESInterpType interp,int opal_hint,int oclamp_hint)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,
12577 weed_palette_get_name_full(palette,
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
12596 if (weed_palette_is_yuv(palette)) {
12597 if (!weed_palette_is_resizable(palette, iclamping, TRUE)) {
12598 if (opal_hint == WEED_PALETTE_END || weed_palette_is_yuv(opal_hint)) {
12599 if (weed_palette_has_alpha(palette)) {
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 {
12606 if (weed_palette_has_alpha(palette)) {
12607 convert_layer_palette(layer, WEED_PALETTE_RGBA32, 0);
12608 } else {
12609 convert_layer_palette(layer, WEED_PALETTE_RGB24, 0);
12610 }
12611 }
12612 palette = weed_layer_get_palette(layer);
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
12708 iwidth = weed_layer_get_width(layer) * weed_palette_get_pixels_per_macropixel(palette);
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
12745 /// old layer will hold a ref to the original pixel_data. We will free it at the end since the pixel_data
12746 /// of layer will be recreated when we calll create_empty_pixel_data()
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
12752 old_layer = weed_layer_new(WEED_LAYER_TYPE_VIDEO);
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);
12799 weed_layer_nullify_pixel_data(layer);
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
12812 if (weed_palette_is_rgb(palette)) {
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
12892 * weed_palette_get_plane_ratio_vertical(palette, i));
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
12955 iwidth = weed_layer_get_width(layer) * weed_palette_get_pixels_per_macropixel(palette);
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) {
12965 if (weed_palette_has_alpha(palette)) {
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
12981 threaded_dialog_spin(0.);
12982 new_pixbuf = lives_pixbuf_scale_simple(pixbuf, width, height, interp);
12983 threaded_dialog_spin(0.);
12984 if (new_pixbuf) {
12985 weed_layer_set_size(layer, lives_pixbuf_get_width(new_pixbuf), lives_pixbuf_get_height(new_pixbuf));
12986 weed_layer_set_rowstride(layer, lives_pixbuf_get_rowstride(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
letterbox_layer(weed_layer_t * layer,int nwidth,int nheight,int width,int height,LiVESInterpType interp,int tpal,int tclamp)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
13034 /// no letterboxing needed - resize and return
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) {
13045 /// resize the inner rectangle
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
13053 old_layer = weed_layer_new(WEED_LAYER_TYPE_VIDEO);
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
13069 /// create the outer rectangle in layer
13070 weed_layer_set_size(layer, nwidth / weed_palette_get_pixels_per_macropixel(pal), nheight);
13071 weed_layer_nullify_pixel_data(layer);
13072 if (!create_empty_pixel_data(layer, TRUE, TRUE)) goto memfail2;
13073
13074 new_pixel_data = weed_layer_get_pixel_data(layer, NULL);
13075
13076 /// get the actual size after any adjustments
13077 nwidth = weed_layer_get_width(layer) * weed_palette_get_pixels_per_macropixel(pal);
13078 nheight = weed_layer_get_height(layer);
13079
13080 if (nwidth < width || nheight < height || !new_pixel_data) {
13081 /// this shouldnt happen, but if the outer rectangle is smaller than the inner we have to abort
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
13303 if (mainw->frame_layer && weed_layer_get_pixel_data_packed(mainw->frame_layer) == pixel_data[0]) {
13304 /// retain pixel_data if it belongs to mainw->frame_layer
13305 weed_layer_nullify_pixel_data(old_layer);
13306 }
13307 /// otherwise do not nullify, as we want to free old pixel_data
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:
13316 weed_layer_pixel_data_free(layer);
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
13326 /**
13327 @brief turn a (Gdk)Pixbuf into a Weed layer
13328
13329 return TRUE if we can use the original pixbuf pixels; in this case the pixbuf pixels should only be freed via
13330 lives_layer_pixel_data_free() or lives_layer_free()
13331 see code example.
13332
13333 code example:
13334
13335 if (pixbuf) {
13336 if (!pixbuf_to_layer(layer, pixbuf)) lives_widget_object_unref(pixbuf);
13337 else do NOT unref the pixbuf !!!!
13338 }
13339
13340 do something with layer...
13341
13342 weed_layer_pixel_data_free(layer); unrefs the pixbuf
13343 or
13344 weed_layer_free(layer); also unrefs the pixbuf
13345
13346 */
pixbuf_to_layer(weed_layer_t * layer,LiVESPixbuf * pixbuf)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);
13359 weed_layer_pixel_data_free(layer);
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);
13381 weed_layer_pixel_data_free(layer);
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
13401 weed_layer_pixel_data_free(layer);
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
swap_red_blue(int pal)13411 LIVES_LOCAL_INLINE int swap_red_blue(int pal) {
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
13419 /**
13420 @brief look for shortcuts in palette conversions
13421 instead of converting e.g RGB -> BGRA, we may be able to pretend that the
13422 input palette is BGR and thus the conversion to BGRA is slightly cheaper
13423 we can do this provided the caller can take into account that the red / blue
13424 components are now swapped.
13425 If this is possible, then either inpal or outpal mau ne altered, and TRUE is returned
13426 */
consider_swapping(int * inpal,int * outpal)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:
13451 /// since we dont have ABGR, we can switch the out palette instead
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
13469 /**
13470 @brief convert a weed layer to lives_painter (a.k.a cairo)
13471
13472 width, height and rowstrides of source layer may all change */
layer_to_lives_painter(weed_layer_t * layer)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 }
13519 weed_layer_pixel_data_free(layer);
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
13547 /**
13548 @brief convert a lives_painter_t (a.k.a) cairo_t to a weed layer */
lives_painter_to_layer(lives_painter_t * cr,weed_layer_t * layer)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
13557 /// flush to ensure all writing to the image surface was done
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
13567 weed_layer_set_pixel_data_packed(layer, src);
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
13573 lives_painter_surface_reference(surface);
13574 lives_painter_destroy(cr);
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) {
13595 /// un-premultiply the alpha
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
resize_all(int fileno,int width,int height,lives_img_type_t imgtype,boolean do_back,int * nbad,int * nmiss)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
13633 mainw->cancelled = CANCEL_NONE;
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 }
13657 layer = weed_layer_new(WEED_LAYER_TYPE_VIDEO);
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
13706 /**
13707 @brief create a layer, setting the most important properties */
weed_layer_create(int width,int height,int * rowstrides,int palette)13708 weed_layer_t *weed_layer_create(int width, int height, int *rowstrides, int palette) {
13709 weed_layer_t *layer = weed_layer_new(WEED_LAYER_TYPE_VIDEO);
13710
13711 weed_layer_set_width(layer, width);
13712 weed_layer_set_height(layer, height);
13713
13714 if (palette != WEED_PALETTE_END) {
13715 weed_layer_set_palette(layer, palette);
13716 if (rowstrides) weed_layer_set_rowstrides(layer, rowstrides, weed_palette_get_nplanes(palette));
13717 }
13718 return layer;
13719 }
13720
13721
weed_layer_create_full(int width,int height,int * rowstrides,int palette,int YUV_clamping,int YUV_sampling,int YUV_subspace,int gamma_type)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
13731 /**
13732 @brief copy source layer slayer to dest layer dlayer
13733
13734 if dlayer is NULL, we return a new layer, otherwise we return dlayer
13735 for a newly created layer, this is a deep copy, since the pixel_data array is also copied
13736 for an existing dlayer, we copy pixel_data by reference.
13737 all the other relevant attributes are also copied
13738 */
weed_layer_copy(weed_layer_t * dlayer,weed_layer_t * slayer)13739 weed_layer_t *weed_layer_copy(weed_layer_t *dlayer, weed_layer_t *slayer) {
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) {
13753 /// deep copy
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 {
13768 /// shallow copy
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) {
13776 weed_leaf_copy_or_delete(layer, WEED_LEAF_HOST_PIXBUF_SRC, slayer);
13777 weed_leaf_copy_or_delete(layer, WEED_LEAF_HOST_ORIG_PDATA, slayer);
13778 weed_leaf_copy_or_delete(layer, WEED_LEAF_HOST_SURFACE_SRC, slayer);
13779 weed_leaf_copy_or_delete(layer, WEED_LEAF_HOST_PIXEL_DATA_CONTIGUOUS, slayer);
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
weed_layer_count_refs(weed_layer_t * layer)13799 LIVES_GLOBAL_INLINE int weed_layer_count_refs(weed_layer_t *layer) {
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
13807 /**
13808 @brief free pixel_data from layer
13809
13810 we do not free if WEED_LEAF_HOST_ORIG_PDATA is set (data is an alpha in which "belongs" to another out param)
13811
13812 take care of WEED_LEAF_HOST_PIXEL_DATA_CONTIGUOUS
13813 take care of WEED_LEAF_HOST_PIXBUF_SRC
13814 take care of WEED_LEAF_HOST_SURFACE_SRC
13815
13816 sets WEED_LEAF_PIXEL_DATA to NULL for the layer
13817
13818 this function should always be used to free WEED_LEAF_PIXEL_DATA */
weed_layer_pixel_data_free(weed_layer_t * layer)13819 void weed_layer_pixel_data_free(weed_layer_t *layer) {
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) {
13832 weed_layer_nullify_pixel_data(layer);
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,
13844 WEED_LEAF_HOST_SURFACE_SRC, NULL);
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.
13852 lives_painter_surface_destroy(surface);
13853 lives_painter_surface_destroy(surface);
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);
13866 weed_layer_nullify_pixel_data(layer);
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
13876 /**
13877 @brief frees pixel_data for a layer, then the layer itself
13878
13879 if plant is freed
13880 returns (void *)NULL for convenience
13881 */
13882
weed_layer_free(weed_layer_t * layer)13883 LIVES_GLOBAL_INLINE weed_layer_t *weed_layer_free(weed_layer_t *layer) {
13884 if (weed_layer_unref(layer)) return layer;
13885 return NULL;
13886 }
13887
weed_layer_unref(weed_layer_t * layer)13888 int weed_layer_unref(weed_layer_t *layer) {
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;
13894 weed_layer_pixel_data_free(layer);
13895 weed_plant_free(layer);
13896 return 0;
13897 }
13898
weed_layer_ref(weed_layer_t * layer)13899 LIVES_GLOBAL_INLINE int weed_layer_ref(weed_layer_t *layer) {
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
weed_layer_get_pixel_data(weed_layer_t * layer,int * nplanes)13908 LIVES_GLOBAL_INLINE void **weed_layer_get_pixel_data(weed_layer_t *layer, int *nplanes) {
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
weed_layer_get_pixel_data_packed(weed_layer_t * layer)13915 LIVES_GLOBAL_INLINE uint8_t *weed_layer_get_pixel_data_packed(weed_layer_t *layer) {
13916 if (!layer) return NULL;
13917 return (uint8_t *)weed_get_voidptr_value(layer, WEED_LEAF_PIXEL_DATA, NULL);
13918 }
13919
13920
weed_layer_get_audio_data(weed_layer_t * layer,int * naudchans)13921 LIVES_GLOBAL_INLINE float **weed_layer_get_audio_data(weed_layer_t *layer, int *naudchans) {
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
weed_layer_get_rowstrides(weed_layer_t * layer,int * nplanes)13928 LIVES_GLOBAL_INLINE int *weed_layer_get_rowstrides(weed_layer_t *layer, int *nplanes) {
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
weed_layer_get_rowstride(weed_layer_t * layer)13935 LIVES_GLOBAL_INLINE int weed_layer_get_rowstride(weed_layer_t *layer) {
13936 if (!layer) return 0;
13937 return weed_get_int_value(layer, WEED_LEAF_ROWSTRIDES, NULL);
13938 }
13939
13940
weed_layer_get_width(weed_layer_t * layer)13941 LIVES_GLOBAL_INLINE int weed_layer_get_width(weed_layer_t *layer) {
13942 if (!layer) return -1;
13943 return weed_get_int_value(layer, WEED_LEAF_WIDTH, NULL);
13944 }
13945
13946
weed_layer_get_width_pixels(weed_layer_t * layer)13947 LIVES_GLOBAL_INLINE int weed_layer_get_width_pixels(weed_layer_t *layer) {
13948 if (!layer) return -1;
13949 return weed_layer_get_width(layer) * weed_palette_get_pixels_per_macropixel(weed_layer_get_palette(layer));
13950 }
13951
13952
weed_layer_get_height(weed_layer_t * layer)13953 LIVES_GLOBAL_INLINE int weed_layer_get_height(weed_layer_t *layer) {
13954 if (!layer) return -1;
13955 return weed_get_int_value(layer, WEED_LEAF_HEIGHT, NULL);
13956 }
13957
13958
weed_layer_get_yuv_clamping(weed_layer_t * layer)13959 LIVES_GLOBAL_INLINE int weed_layer_get_yuv_clamping(weed_layer_t *layer) {
13960 if (!layer) return 0;
13961 return weed_get_int_value(layer, WEED_LEAF_YUV_CLAMPING, NULL);
13962 }
13963
13964
weed_layer_get_yuv_sampling(weed_layer_t * layer)13965 LIVES_GLOBAL_INLINE int weed_layer_get_yuv_sampling(weed_layer_t *layer) {
13966 if (!layer) return 0;
13967 return weed_get_int_value(layer, WEED_LEAF_YUV_SAMPLING, NULL);
13968 }
13969
13970
weed_layer_get_yuv_subspace(weed_layer_t * layer)13971 LIVES_GLOBAL_INLINE int weed_layer_get_yuv_subspace(weed_layer_t *layer) {
13972 if (!layer) return 0;
13973 return weed_get_int_value(layer, WEED_LEAF_YUV_SUBSPACE, NULL);
13974 }
13975
13976
weed_layer_get_palette(weed_layer_t * layer)13977 LIVES_GLOBAL_INLINE int weed_layer_get_palette(weed_layer_t *layer) {
13978 if (!layer) return WEED_PALETTE_END;
13979 return weed_get_int_value(layer, WEED_LEAF_CURRENT_PALETTE, NULL);
13980 }
13981
13982
weed_layer_get_palette_yuv(weed_layer_t * layer,int * clamping,int * sampling,int * subspace)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
weed_layer_get_audio_rate(weed_layer_t * layer)13992 LIVES_GLOBAL_INLINE int weed_layer_get_audio_rate(weed_layer_t *layer) {
13993 if (!WEED_IS_LAYER(layer)) return 0;
13994 return weed_get_int_value(layer, WEED_LEAF_AUDIO_RATE, NULL);
13995 }
13996
13997
weed_layer_get_naudchans(weed_layer_t * layer)13998 LIVES_GLOBAL_INLINE int weed_layer_get_naudchans(weed_layer_t *layer) {
13999 if (!WEED_IS_LAYER(layer)) return 0;
14000 return weed_get_int_value(layer, WEED_LEAF_AUDIO_CHANNELS, NULL);
14001 }
14002
14003
weed_layer_get_audio_length(weed_layer_t * layer)14004 LIVES_GLOBAL_INLINE int weed_layer_get_audio_length(weed_layer_t *layer) {
14005 if (!WEED_IS_LAYER(layer)) return 0;
14006 return weed_get_int_value(layer, WEED_LEAF_AUDIO_DATA_LENGTH, NULL);
14007 }
14008
14009