LiVES 3.2.0
colourspace.c
Go to the documentation of this file.
1// colourspace.c
2// LiVES
3// (c) G. Finch 2004 - 2020 <salsaman+lives@gmail.com>
4// Released under the GPL 3 or later
5// see file ../COPYING for licensing details
6
7// code for palette conversions
8
9/*
10 This program is free software; you can redistribute it and/or
11 modify it under the terms of the GNU General Public License
12 as published by the Free Software Foundation; either version 2
13 of the License, or (at your option) any later version.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23*/
24
25// *
26// TODO -
27// - resizing of single plane (including bicubic) (maybe just triplicate the values and pretend it's RGB)
28// - external plugins for palette conversion, resizing
29// - RGB(A) float, YUV10, etc.
30
31#include <math.h>
32
33#include "main.h"
34
35boolean weed_palette_is_sane(int pal);
36
37#define USE_THREADS 1
38
39#ifdef USE_SWSCALE
40
41#ifdef FF_API_PIX_FMT
42typedef enum PixelFormat swpixfmt;
43#else
44typedef enum AVPixelFormat swpixfmt;
45#endif
46
47#if USE_THREADS
48#include <pthread.h>
49typedef 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
67static volatile int nb = 0;
68static volatile int swctx_count = 0;
69static swsctx_block bloxx[MAX_SWS_BLOCKS];
70static struct SwsContext *swscalep[MAX_SWS_CTX];
71static pthread_mutex_t ctxcnt_mutex = PTHREAD_MUTEX_INITIALIZER;
72
73static 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
176LIVES_LOCAL_INLINE void sws_freeblock(swsctx_block * block) {
177 block->in_use = FALSE;
178}
179
180#else
181static struct SwsContext *swscale = NULL;
182#endif
183
184#endif // USE_SWSCALE
185
186#include "cvirtual.h"
187#include "effects-weed.h"
188
189static 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
207static 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
218static int *Y_R;
219static int *Y_G;
220static int *Y_B;
221static int *Cb_R;
222static int *Cb_G;
223static int *Cb_B;
224static int *Cr_R;
225static int *Cr_G;
226static int *Cr_B;
227
228// clamped Y'CbCr
229static int Y_Rc[256];
230static int Y_Gc[256];
231static int Y_Bc[256];
232static int Cb_Rc[256];
233static int Cb_Gc[256];
234static int Cb_Bc[256];
235static int Cr_Rc[256];
236static int Cr_Gc[256];
237static int Cr_Bc[256];
238
239// unclamped Y'CbCr
240static int Y_Ru[256];
241static int Y_Gu[256];
242static int Y_Bu[256];
243static int Cb_Ru[256];
244static int Cb_Gu[256];
245static int Cb_Bu[256];
246static int Cr_Ru[256];
247static int Cr_Gu[256];
248static int Cr_Bu[256];
249
250// clamped BT.709
251static int HY_Rc[256];
252static int HY_Gc[256];
253static int HY_Bc[256];
254static int HCb_Rc[256];
255static int HCb_Gc[256];
256static int HCb_Bc[256];
257static int HCr_Rc[256];
258static int HCr_Gc[256];
259static int HCr_Bc[256];
260
261// unclamped BT.709
262static int HY_Ru[256];
263static int HY_Gu[256];
264static int HY_Bu[256];
265static int HCb_Ru[256];
266static int HCb_Gu[256];
267static int HCb_Bu[256];
268static int HCr_Ru[256];
269static int HCr_Gu[256];
270static int HCr_Bu[256];
271
272static boolean conv_RY_inited = FALSE;
273
274// generic
275static int *RGB_Y;
276static int *R_Cr;
277static int *G_Cb;
278static int *G_Cr;
279static int *B_Cb;
280
281// clamped Y'CbCr
282static int RGB_Yc[256];
283static int R_Crc[256];
284static int G_Cbc[256];
285static int G_Crc[256];
286static int B_Cbc[256];
287
288// unclamped Y'CbCr
289static int RGB_Yu[256];
290static int R_Cru[256];
291static int G_Cru[256];
292static int G_Cbu[256];
293static int B_Cbu[256];
294
295// clamped BT.709
296static int HRGB_Yc[256];
297static int HR_Crc[256];
298static int HG_Crc[256];
299static int HG_Cbc[256];
300static int HB_Cbc[256];
301
302// unclamped BT.709
303static int HRGB_Yu[256];
304static int HR_Cru[256];
305static int HG_Cru[256];
306static int HG_Cbu[256];
307static int HB_Cbu[256];
308
309static boolean conv_YR_inited = FALSE;
310
311static short min_Y, max_Y, min_UV, max_UV;
312
313// averaging
314static uint8_t *cavg;
315static uint8_t cavgc[256][256];
316static uint8_t cavgu[256][256];
317static uint8_t cavgrgb[256][256];
318static boolean avg_inited = FALSE;
319
320// pre-post multiply alpha
321static int unal[256][256];
322static int al[256][256];
323static int unalcy[256][256];
324static int alcy[256][256];
325static int unalcuv[256][256];
326static int alcuv[256][256];
327
328// clamping and subspace converters
329
330// generic
331static uint8_t *Y_to_Y;
332static uint8_t *U_to_U;
333static uint8_t *V_to_V;
334
335// same subspace, clamped to unclamped
336static uint8_t Yclamped_to_Yunclamped[256];
337static uint8_t UVclamped_to_UVunclamped[256];
338
339// same subspace, unclamped to clamped
340static uint8_t Yunclamped_to_Yclamped[256];
341static uint8_t UVunclamped_to_UVclamped[256];
342
343static boolean conv_YY_inited = FALSE;
344
345
346// gamma correction
347
349// x <= b ? x * c : (a + 1) * powf(x, 1 / G) - a
350
352// inv: x < d ? x / c : powf((x + a) / (a + 1), G)
353
355
356// for sRGB:
357// a = 0.055, b = 0.0031308, c = 12.92, d = 0.04045, G = 2.4
358
361
362static gamma_const_t gamma_tx[3];
363
364static uint8_t *gamma_s2l = NULL;
365static uint8_t *gamma_l2s = NULL;
366static uint8_t *gamma_b2l = NULL;
367static uint8_t *gamma_l2b = NULL;
368static uint8_t *gamma_s2b = NULL;
369static uint8_t *gamma_b2s = NULL;
370
371static 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
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;
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) {
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) {
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
497static 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
503static 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
544LIVES_GLOBAL_INLINE int32_t round_special(int32_t val) {
545 return spc_rnd(val);
546}
547
548
549double get_luma8(uint8_t r, uint8_t g, uint8_t b) {
551 short a = _spc_rnd(Y_Ru[r] + Y_Gu[g] + Y_Bu[b], PB_QUALITY_HIGH);
552 if (a > 255) a = 255;
553 return a < 0 ? 0. : (double)a / 255.;
554}
555
556
557double get_luma16(uint16_t r, uint16_t g, uint16_t b) {
559 return get_luma8(r >> 8, g >> 8, b >> 8);
560}
561
562
563static 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
672static void init_YUV_to_RGB_tables(void) {
673 register int i;
674
675 // These values are for what I call YUV_SUBSPACE_YCBCR
676
677 /* clip Y values under 16 */
678 for (i = 0; i <= YUV_CLAMP_MINI; i++) RGB_Yc[i] = 0;
679
680 for (; i < Y_CLAMP_MAXI; i++) {
681 RGB_Yc[i] = myround(((double)i - YUV_CLAMP_MIN) / (Y_CLAMP_MAX - YUV_CLAMP_MIN) * 255. * SCALE_FACTOR);
682 }
683 /* clip Y values above 235 */
684 for (; i < 256; i++) RGB_Yc[i] = 255 * SCALE_FACTOR;
685
686 /* clip Cb/Cr values below 16 */
687 for (i = 0; i <= YUV_CLAMP_MINI; i++) R_Crc[i] = G_Crc[i] = G_Cbc[i] = B_Cbc[i] = 0;
688
689 for (; i < UV_CLAMP_MAXI; i++) {
690 R_Crc[i] = myround(2. * (1. - KR_YCBCR) * ((((double)i - YUV_CLAMP_MIN) /
691 (UV_CLAMP_MAX - YUV_CLAMP_MIN) * 255.) - UV_BIAS) * SCALE_FACTOR); // 2*(1-Kr)
692
693 G_Cbc[i] = myround(-.5 / (1. + KB_YCBCR + KR_YCBCR) * ((((double)i - YUV_CLAMP_MIN) /
695
696 G_Crc[i] = myround(-.5 / (1. - KR_YCBCR) * ((((double)i - YUV_CLAMP_MIN) /
698
699 B_Cbc[i] = myround(2. * (1. - KB_YCBCR) * ((((double)i - YUV_CLAMP_MIN) /
700 (UV_CLAMP_MAX - YUV_CLAMP_MIN) * 255.) - UV_BIAS) * SCALE_FACTOR); // 2*(1-Kb)
701 }
702 /* clip Cb/Cr values above 240 */
703 for (; i < 256; i++) {
704 R_Crc[i] = myround(2. * (1. - KR_YCBCR) * (((UV_CLAMP_MAX - YUV_CLAMP_MIN) /
705 (UV_CLAMP_MAX - YUV_CLAMP_MIN) * 255.) - UV_BIAS) * SCALE_FACTOR); // 2*(1-Kr)
706 G_Crc[i] = myround(-.5 / (1. - KR_YCBCR) * (((UV_CLAMP_MAX - YUV_CLAMP_MIN) /
708 G_Cbc[i] = myround(-.5 / (1. + KB_YCBCR + KR_YCBCR) * (((UV_CLAMP_MAX - YUV_CLAMP_MIN) /
710 B_Cbc[i] = myround(2. * (1. - KB_YCBCR) * (((UV_CLAMP_MAX - YUV_CLAMP_MIN) /
711 (UV_CLAMP_MAX - YUV_CLAMP_MIN) * 255.) - UV_BIAS) * SCALE_FACTOR); // 2*(1-Kb)
712 }
713
714 // unclamped Y'CbCr
715 for (i = 0; i <= 255; i++) {
716 RGB_Yu[i] = i * SCALE_FACTOR;
717 }
718
719 for (i = 0; i <= 255; i++) {
720 R_Cru[i] = myround(2. * (1. - KR_YCBCR) * ((double)i - UV_BIAS) * SCALE_FACTOR); // 2*(1-Kr)
721 G_Cru[i] = myround(-.5 / (1. - KR_YCBCR) * ((double)i - UV_BIAS) * SCALE_FACTOR);
722 G_Cbu[i] = myround(-.5 / (1. + KB_YCBCR + KR_YCBCR) * ((double)i - UV_BIAS) * SCALE_FACTOR);
723 B_Cbu[i] = myround(2. * (1. - KB_YCBCR) * ((double)i - UV_BIAS) * SCALE_FACTOR); // 2*(1-Kb)
724 }
725
726 // These values are for what I call YUV_SUBSPACE_BT709
727
728 /* clip Y values under 16 */
729 for (i = 0; i <= YUV_CLAMP_MINI; i++) HRGB_Yc[i] = 0;
730
731 for (; i < Y_CLAMP_MAXI; i++) {
732 HRGB_Yc[i] = myround(((double)i - YUV_CLAMP_MIN) / (Y_CLAMP_MAX - YUV_CLAMP_MIN) * 255. * SCALE_FACTOR);
733 }
734
735 /* clip Y values above 235 */
736 for (; i < 256; i++) HRGB_Yc[i] = 255 * SCALE_FACTOR;
737
738 /* clip Cb/Cr values below 16 */
739 for (i = 0; i <= YUV_CLAMP_MINI; i++) HR_Crc[i] = HG_Crc[i] = HG_Cbc[i] = HB_Cbc[i] = 0;
740
741 for (; i < UV_CLAMP_MAXI; i++) {
742 HR_Crc[i] = myround(2. * (1. - KR_BT709) * ((((double)i - YUV_CLAMP_MIN) /
743 (UV_CLAMP_MAX - YUV_CLAMP_MIN) * 255.) - UV_BIAS) * SCALE_FACTOR); // 2*(1-Kr)
744 HG_Crc[i] = myround(-.5 / (1. - KR_BT709) * ((((double)i - YUV_CLAMP_MIN) /
746 HG_Cbc[i] = myround(-.5 / (1. + KB_BT709 + KB_BT709) * ((((double)i - YUV_CLAMP_MIN) /
748 HB_Cbc[i] = myround(2. * (1. - KB_BT709) * ((((double)i - YUV_CLAMP_MIN) /
749 (UV_CLAMP_MAX - YUV_CLAMP_MIN) * 255.) - UV_BIAS) * SCALE_FACTOR); // 2*(1-Kb)
750 }
751 /* clip Cb/Cr values above 240 */
752 for (; i < 256; i++) {
753 HR_Crc[i] = myround(2. * (1. - KR_BT709) * (255. - UV_BIAS) * SCALE_FACTOR); // 2*(1-Kr)
754 HG_Crc[i] = myround(-.5 / (1. - KR_BT709) * (255. - UV_BIAS) * SCALE_FACTOR);
755 HG_Cbc[i] = myround(-.5 / (1. + KB_BT709 + KB_BT709) * (255. - UV_BIAS) * SCALE_FACTOR);
756 HB_Cbc[i] = myround(2. * (1. - KB_BT709) * (255. - UV_BIAS) * SCALE_FACTOR); // 2*(1-Kb)
757 }
758
759 // unclamped Y'CbCr
760 for (i = 0; i <= 255; i++) HRGB_Yu[i] = i * SCALE_FACTOR;
761
762 for (i = 0; i <= 255; i++) {
763 HR_Cru[i] = myround(2. * (1. - KR_BT709) * ((double)i - UV_BIAS) * SCALE_FACTOR); // 2*(1-Kr)
764 HG_Cru[i] = myround(-.5 / (1. - KR_BT709) * ((double)i - UV_BIAS) * SCALE_FACTOR);
765 HG_Cbu[i] = myround(-.5 / (1. + KB_BT709 + KB_BT709) * ((double)i - UV_BIAS) * SCALE_FACTOR);
766 HB_Cbu[i] = myround(2. * (1. - KB_BT709) * ((double)i - UV_BIAS) * SCALE_FACTOR); // 2*(1-Kb)
767 }
768 conv_YR_inited = TRUE;
769}
770
771
772static 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
805static 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
829static 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
847static 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
953static 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
1013void 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.
1026LIVES_LOCAL_INLINE double lab_conv(double a) {return a > LAB0 ? pow(a, LAB1) : a * LAB2 + LAB3;}
1027
1028void 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
1039static 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
1054static 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
1075double 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
1090void 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
1113void 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
1142boolean pick_nice_colour(uint8_t r0, uint8_t g0, uint8_t b0, uint8_t *r1, uint8_t *g1, uint8_t *b1,
1143 double max, double lmin, double lmax) {
1144 // given 2 colours a and b, calculate the cie94 distance (d) between them, then find a third colour
1145 // first calc the avg, calc d(a, b) with threshold > 1.
1146 // pick a random colour, the dist from avg must be approx. d(a, b) * max
1147 // da / db must be > ,9 and db / da also
1148 // finally luma should be between lmin and lmax
1149 // restrictions are gradually loosened
1150
1151#define DIST_THRESH 10.
1152#define RAT_START .9
1153#define RAT_TIO .9999999
1154#define RAT_MIN .2
1155
1156 volatile double gmm = 1. + lmax * 2., gmn = 1. + lmin;
1157 volatile uint8_t xr, xb, xg, ar, ag, ab;
1158 volatile uint8_t rmin = MIN(r0, *r1) / 1.5, gmin = MIN(g0, *g1) / gmm, bmin = MIN(b0, *b1) / 1.5;
1159 volatile uint8_t rmax = MAX(r0, *r1), gmax = MAX(g0, *g1), bmax = MAX(b0, *b1);
1160 volatile double da, db, z, rat = RAT_START, d = cdist94(r0, g0, b0, *r1, *g1, *b1);
1161 if (d < DIST_THRESH) d = DIST_THRESH;
1162 max *= d;
1163
1164 ar = (volatile double)(r0 + *r1) / 2.;
1165 ag = (volatile double)(g0 + *g1) / 2.;
1166 ab = (volatile double)(b0 + *b1) / 2.;
1167
1168 rmax = (rmax < 128 ? rmax << 1 : 255) - rmin;
1169 gmax = (gmax < 255 / gmn ? gmax *gmn : 255) - gmin;
1170 bmax = (bmax < 128 ? bmax << 1 : 255) - bmin;
1171
1172 while ((z = rat * RAT_TIO) > RAT_MIN) {
1173 rat = z;
1175 xr = fastrand_int(bmax) + bmin;
1176 xg = fastrand_int(gmax) + gmin;
1177 xb = fastrand_int(bmax) + bmin;
1178
1179 da = cdist94(ar, ag, ab, xr, xg, xb);
1180 if (max * rat > da) continue;
1181 da = cdist94(r0, g0, b0, xr, xg, xb);
1182 db = cdist94(*r1, *g1, *b1, xr, xg, xb);
1183 if (da * rat * lmax > db || db * rat > da * lmax) continue;
1184 else {
1185 double l = get_luma8(xr, xg, xb);
1186 if (l < lmin || l > lmax) continue;
1187 *r1 = xr; *g1 = xg; *b1 = xb;
1188 return TRUE;
1189 }
1190 }
1191 return FALSE;
1192}
1193
1194
1196// pixel conversions
1197#ifdef WEED_ADVANCED_PALETTES
1198
1199static weed_macropixel_t advp[256];
1200
1202 lives_memset(advp, 0, 256 * sizeof(weed_macropixel_t));
1203
1204 advp[0] = (weed_macropixel_t) {
1205 WEED_PALETTE_RGB24,
1206 {WEED_VCHAN_red, WEED_VCHAN_green, WEED_VCHAN_blue}
1207 };
1208
1209 advp[1] = (weed_macropixel_t) {
1210 WEED_PALETTE_BGR24,
1211 {WEED_VCHAN_blue, WEED_VCHAN_green, WEED_VCHAN_red}
1212 };
1213
1214 advp[2] = (weed_macropixel_t) {
1215 WEED_PALETTE_RGBA32,
1216 {WEED_VCHAN_red, WEED_VCHAN_green, WEED_VCHAN_blue, WEED_VCHAN_alpha}
1217 };
1218
1219 advp[3] = (weed_macropixel_t) {
1220 WEED_PALETTE_BGRA32,
1221 {WEED_VCHAN_blue, WEED_VCHAN_green, WEED_VCHAN_red, WEED_VCHAN_alpha}
1222 };
1223
1224 advp[4] = (weed_macropixel_t) {
1225 WEED_PALETTE_ARGB32,
1226 {WEED_VCHAN_alpha, WEED_VCHAN_red, WEED_VCHAN_green, WEED_VCHAN_blue}
1227 };
1228
1229 advp[5] = (weed_macropixel_t) {
1230 WEED_PALETTE_RGBFLOAT,
1231 {WEED_VCHAN_red, WEED_VCHAN_green, WEED_VCHAN_blue},
1232 WEED_VCHAN_DESC_FP, {0}, {0}, 1, {32, 32, 32}
1233 };
1234
1235 advp[6] = (weed_macropixel_t) {
1236 WEED_PALETTE_RGBAFLOAT,
1237 {WEED_VCHAN_red, WEED_VCHAN_green, WEED_VCHAN_blue, WEED_VCHAN_alpha},
1238 WEED_VCHAN_DESC_FP, {0}, {0}, 1, {32, 32, 32, 32}
1239 };
1240
1242 advp[7] = (weed_macropixel_t) {
1243 WEED_PALETTE_YUV420P,
1244 {WEED_VCHAN_Y, WEED_VCHAN_U, WEED_VCHAN_V},
1245 WEED_VCHAN_DESC_PLANAR, {1, 2, 2}, {1, 2, 2}
1246 };
1247
1248 advp[8] = (weed_macropixel_t) {
1249 WEED_PALETTE_YVU420P,
1250 {WEED_VCHAN_Y, WEED_VCHAN_V, WEED_VCHAN_U},
1251 WEED_VCHAN_DESC_PLANAR, {1, 2, 2}, {1, 2, 2}
1252 };
1253
1254 advp[9] = (weed_macropixel_t) {
1255 WEED_PALETTE_YUV422P,
1256 {WEED_VCHAN_Y, WEED_VCHAN_U, WEED_VCHAN_V},
1257 WEED_VCHAN_DESC_PLANAR, {1, 2, 2}, {1, 1, 1}
1258 };
1259
1260 advp[10] = (weed_macropixel_t) {
1261 WEED_PALETTE_YUV444P,
1262 {WEED_VCHAN_Y, WEED_VCHAN_U, WEED_VCHAN_V}, WEED_VCHAN_DESC_PLANAR
1263 };
1264
1265 advp[11] = (weed_macropixel_t) {
1266 WEED_PALETTE_YUVA4444P,
1267 {WEED_VCHAN_Y, WEED_VCHAN_U, WEED_VCHAN_V, WEED_VCHAN_alpha},
1268 WEED_VCHAN_DESC_PLANAR
1269 };
1270
1272 advp[12] = (weed_macropixel_t) {
1273 WEED_PALETTE_UYVY,
1274 {WEED_VCHAN_U, WEED_VCHAN_Y, WEED_VCHAN_V, WEED_VCHAN_Y},
1275 0, {0}, {0}, 2
1276 };
1277
1278 advp[13] = (weed_macropixel_t) {
1279 WEED_PALETTE_YUYV,
1280 {WEED_VCHAN_Y, WEED_VCHAN_U, WEED_VCHAN_Y, WEED_VCHAN_V},
1281 0, {0}, {0}, 2
1282 };
1283
1284 advp[14] = (weed_macropixel_t) {WEED_PALETTE_YUV888, {WEED_VCHAN_Y, WEED_VCHAN_U, WEED_VCHAN_V}};
1285
1286 advp[15] = (weed_macropixel_t) {
1287 WEED_PALETTE_YUVA8888,
1288 {WEED_VCHAN_Y, WEED_VCHAN_U, WEED_VCHAN_V, WEED_VCHAN_alpha}
1289 };
1290
1291 advp[16] = (weed_macropixel_t) {
1292 WEED_PALETTE_YUV411, {
1293 WEED_VCHAN_U, WEED_VCHAN_Y, WEED_VCHAN_Y,
1294 WEED_VCHAN_V, WEED_VCHAN_Y, WEED_VCHAN_Y
1295 },
1296 0, {0}, {0}, 4
1297 };
1298
1300 advp[17] = (weed_macropixel_t) {WEED_PALETTE_A8, {WEED_VCHAN_alpha}};
1301
1302 advp[18] = (weed_macropixel_t) {WEED_PALETTE_A1, {WEED_VCHAN_alpha}, 0, {0}, {0}, 1, {1}};
1303
1304 advp[19] = (weed_macropixel_t) {
1305 WEED_PALETTE_AFLOAT, {WEED_VCHAN_alpha},
1306 WEED_VCHAN_DESC_FP, {0}, {0}, 1, {32}
1307 };
1308
1309 advp[20] = (weed_macropixel_t) {WEED_PALETTE_END};
1310
1311 // custom palettes (designed for future use or for testing)
1312 advp[21] = (weed_macropixel_t) {
1313 LIVES_PALETTE_ABGR32,
1314 {WEED_VCHAN_alpha, WEED_VCHAN_blue, WEED_VCHAN_green, WEED_VCHAN_red}
1315 };
1316
1317 advp[22] = (weed_macropixel_t) {
1318 LIVES_PALETTE_YVU422P,
1319 {WEED_VCHAN_Y, WEED_VCHAN_V, WEED_VCHAN_U},
1320 WEED_VCHAN_DESC_PLANAR, {1, 2, 2}, {1, 1, 1}
1321 };
1322
1323 advp[23] = (weed_macropixel_t) {
1324 LIVES_PALETTE_YUVA420P,
1325 {WEED_VCHAN_Y, WEED_VCHAN_U, WEED_VCHAN_V, WEED_VCHAN_alpha},
1326 WEED_VCHAN_DESC_PLANAR, {1, 2, 2, 1}, {1, 2, 2, 1}
1327 };
1328
1329 advp[24] = (weed_macropixel_t) {
1330 LIVES_PALETTE_AYUV8888,
1331 {WEED_VCHAN_alpha, WEED_VCHAN_Y, WEED_VCHAN_U, WEED_VCHAN_V}
1332 };
1333
1334 advp[25] = (weed_macropixel_t) {
1335 LIVES_PALETTE_YUVFLOAT,
1336 {WEED_VCHAN_Y, WEED_VCHAN_U, WEED_VCHAN_V},
1337 WEED_VCHAN_DESC_FP, {0}, {0}, 1, {32, 32, 32}
1338 };
1339
1340 advp[26] = (weed_macropixel_t) {
1341 LIVES_PALETTE_YUVAFLOAT,
1342 {WEED_VCHAN_Y, WEED_VCHAN_U, WEED_VCHAN_V, WEED_VCHAN_alpha},
1343 WEED_VCHAN_DESC_FP, {0}, {0}, 1, {32, 32, 32, 32}
1344 };
1345
1346 advp[27] = (weed_macropixel_t) {
1347 LIVES_PALETTE_RGB48,
1348 {WEED_VCHAN_red, WEED_VCHAN_green, WEED_VCHAN_blue},
1349 0, {0}, {0}, 1, {16, 16, 16}
1350 };
1351
1352 advp[28] = (weed_macropixel_t) {
1353 LIVES_PALETTE_RGBA64, {
1354 WEED_VCHAN_red, WEED_VCHAN_green,
1355 WEED_VCHAN_blue, WEED_VCHAN_alpha
1356 },
1357 0, {0}, {0}, 1, {16, 16, 16, 16}
1358 };
1359
1360 advp[29] = (weed_macropixel_t) {
1361 LIVES_PALETTE_YUV121010,
1362 {WEED_VCHAN_Y, WEED_VCHAN_U, WEED_VCHAN_V},
1363 0, {0}, {0}, 1, {12, 10, 10}
1364 };
1365}
1366
1367
1368LIVES_GLOBAL_INLINE const weed_macropixel_t *get_advanced_palette(int weed_palette) {
1369 for (register int i = 0; advp[i].ext_ref != WEED_PALETTE_END; i++)
1370 if (advp[i].ext_ref == weed_palette) return &advp[i];
1371 return NULL;
1372}
1373
1375 return (get_advanced_palette(pal) != NULL);
1376}
1377
1378LIVES_GLOBAL_INLINE int get_simple_palette(weed_macropixel_t *mpx) {
1379 if (mpx) return mpx->ext_ref;
1380 return WEED_PALETTE_NONE;
1381}
1382
1383LIVES_LOCAL_INLINE boolean is_rgbchan(uint16_t ctype) {
1384 return (ctype == WEED_VCHAN_red || ctype == WEED_VCHAN_green || ctype == WEED_VCHAN_blue);
1385}
1386
1387LIVES_LOCAL_INLINE boolean is_yuvchan(uint16_t ctype) {
1388 return (ctype == WEED_VCHAN_Y || ctype == WEED_VCHAN_U || ctype == WEED_VCHAN_V);
1389}
1390
1393 const weed_macropixel_t *mpx = get_advanced_palette(pal);
1394 if (!mpx) return 0;
1395 else {
1396 size_t psize = 0;
1397 for (register int i = 0; i < MAXPPLANES && mpx->chantype[i]; i++)
1398 psize += mpx->bitsize[i] == 0 ? 1 : mpx->bitsize[i] / 8;
1399 return psize;
1400 }
1401}
1402
1404 int npix = 0;
1405 const weed_macropixel_t *mpx = get_advanced_palette(pal);
1406 if (!mpx) return 0;
1407 npix = mpx->npixels;
1408 return !npix ? 1 : npix;
1409}
1410
1413 if (ppm) return pixel_size(pal) * 8;
1414 return 0;
1415}
1416
1418 const weed_macropixel_t *mpx = get_advanced_palette(pal);
1419 register int i = 0;
1420 if (mpx) {
1421 if (!(mpx->flags & WEED_VCHAN_DESC_PLANAR)) return 1;
1422 for (i = 0; i < MAXPPLANES && mpx->chantype[i]; i++);
1423 }
1424 return i;
1425}
1426
1428 const weed_macropixel_t *mpx = get_advanced_palette(pal);
1429 if (mpx && mpx->chantype[0] == WEED_VCHAN_alpha && !mpx->chantype[1]) return TRUE;
1430 return FALSE;
1431}
1432
1434 const weed_macropixel_t *mpx = get_advanced_palette(pal);
1435 if (mpx) {
1436 for (register int i = 0; i < MAXPPLANES && mpx->chantype[i]; i++) {
1437 if (mpx->chantype[i] == WEED_VCHAN_red) return TRUE;
1438 if (mpx->chantype[i] == WEED_VCHAN_blue) return FALSE;
1439 }
1440 }
1441 return FALSE;
1442}
1443
1445 return weed_palette_red_first(pal0) != weed_palette_red_first(pal1);
1446}
1447
1449 const weed_macropixel_t *mpx = get_advanced_palette(pal);
1450 if (mpx) {
1451 for (register int i = 0; i < MAXPPLANES && mpx->chantype[i]; i++)
1452 if (is_rgbchan(mpx->chantype[i])) return TRUE;
1453 }
1454 return FALSE;
1455}
1456
1458 const weed_macropixel_t *mpx = get_advanced_palette(pal);
1459 if (mpx) {
1460 for (register int i = 0; i < MAXPPLANES && mpx->chantype[i]; i++)
1461 if (is_yuvchan(mpx->chantype[i])) return TRUE;
1462 }
1463 return FALSE;
1464}
1465
1467 const weed_macropixel_t *mpx = get_advanced_palette(pal);
1468 if (mpx) {
1469 for (register int i = 0; i < MAXPPLANES && mpx->chantype[i]; i++)
1470 if (mpx->chantype[i] == WEED_VCHAN_alpha) return TRUE;
1471 }
1472 return FALSE;
1473}
1474
1476 const weed_macropixel_t *mpx = get_advanced_palette(pal);
1477 return (mpx && (mpx->flags & WEED_VCHAN_DESC_FP));
1478}
1479
1481 uint8_t subsam = 0;
1482 const weed_macropixel_t *mpx = get_advanced_palette(pal);
1483 if (mpx) subsam = mpx->hsub[plane];
1484 if (subsam) return 1. / (double)(subsam);
1485 return 1.;
1486}
1487
1489 uint8_t subsam = 0;
1490 const weed_macropixel_t *mpx = get_advanced_palette(pal);
1491 if (mpx) subsam = mpx->vsub[plane];
1492 if (subsam) return 1. / (double)(subsam);
1493 return 1.;
1494}
1495
1497 const weed_macropixel_t *mpx = get_advanced_palette(pal);
1498 if (mpx) {
1499 for (register int i = 0; i < MAXPPLANES && mpx->chantype[i]; i++)
1500 if (mpx->chantype[i] == WEED_VCHAN_alpha) return i;
1501 }
1502 return -1;
1503}
1504
1506 if (weed_palette_is_planar(pal)) return _get_alpha(pal);
1507 return -1;
1508}
1509
1511 if (!weed_palette_is_planar(pal)) return _get_alpha(pal);
1512 return -1;
1513}
1514
1516 return _get_alpha(pal) == 0;
1517}
1518
1520 return _get_alpha(pal) == 3;
1521}
1522
1524 // first cpt must be alpha, red, blue, y, u, or v
1525 //
1526 // if first was alpha, 2nd must be NULL, red, blue or y, u, v
1527 // if first was red or blue, 2nd must be green
1528 // if first was y, 2nd must be y, u or v
1529 //
1530 // if second was green, 3rd must be blue or red, but != 1st
1531 // if second was y, u, or v, third must be y, u or v
1532 // if second was red or blue, 3rd must be green
1533 //
1534 // if third was red or blue, fourth may be alpha or NULL
1535 // if third was green, fourth must be red or blue but != 2nd
1536 // if third was y, u, or v, fourth may be y, u, v or alpha
1537 //
1538 // if fourth was red, blue or alpha, fifth must be NULL
1539 // if fourth was y, u, or v, fifth must be y, u, v or alpha
1540 //
1541 // if fifth was alpha, sixth must be NULL
1542 // if fifth was y, u, or v, sixth must be y, u, v or alpha
1543 //
1544 // etc. for 7 and 8
1545
1546 // there must be some symmetry between u and v, e.g. yyuyyv is allowed but not yyuyv or yuy
1547 // 0, 1, or 2 y before / after a u or v, y numbers must match and u / v numbers too
1548
1549 // future directions: allow single plane / cpt r, g, b or y
1550 boolean red = FALSE, blue = FALSE, alpha = FALSE;
1551 int nseqy = 0, nseqyu = 0, nseqyv = 0, nu = 0, nv = 0;
1552 const weed_macropixel_t *mpx = get_advanced_palette(pal);
1553 if (!mpx) return FALSE;
1554 for (register int i = 0; i < MAXPPLANES && mpx->chantype[i]; i++) {
1555 uint16_t ctype = mpx->chantype[i];
1556 if (i > 3 && alpha) return FALSE;
1557 switch (ctype) {
1558 case WEED_VCHAN_Y:
1559 if (red || blue) return FALSE;
1560 if (++nseqy > 2) return FALSE;
1561 break;
1562 case WEED_VCHAN_U:
1563 if (red || blue) return FALSE;
1564 if (nseqyv && nseqy && nseqy != nseqyv) return FALSE;
1565 nu++;
1566 nseqyu = nseqy;
1567 nseqy = nseqyv = 0;
1568 break;
1569 case WEED_VCHAN_V:
1570 if (red || blue) return FALSE;
1571 if (nseqyu && nseqy && nseqy != nseqyu) return FALSE;
1572 nv++;
1573 nseqyv = nseqy;
1574 nseqy = nseqyu = 0;
1575 break;
1576 default:
1577 switch (i) {
1578 case 0:
1579 switch (ctype) {
1580 case WEED_VCHAN_alpha: alpha = TRUE; break;
1581 case WEED_VCHAN_red: red = TRUE; break;
1582 case WEED_VCHAN_blue: blue = TRUE; break;
1583 default: return FALSE;
1584 }
1585 break;
1586 case 1:
1587 if (nu || nv || nseqy) return FALSE;
1588 switch (ctype) {
1589 case WEED_VCHAN_alpha: return FALSE;
1590 case WEED_VCHAN_green:
1591 if (!red && !blue) return FALSE;
1592 break;
1593 case WEED_VCHAN_red:
1594 if (!alpha) return FALSE;
1595 red = TRUE;
1596 break;
1597 case WEED_VCHAN_blue:
1598 if (!alpha) return FALSE;
1599 blue = TRUE;
1600 break;
1601 default: return FALSE;
1602 }
1603 break;
1604 case 2:
1605 if (nu || nv || nseqy) return FALSE;
1606 switch (ctype) {
1607 case WEED_VCHAN_alpha: return FALSE;
1608 case WEED_VCHAN_green:
1609 if (!red && !blue) return FALSE;
1610 break;
1611 case WEED_VCHAN_red:
1612 if (!blue) return FALSE;
1613 red = TRUE;
1614 break;
1615 case WEED_VCHAN_blue:
1616 if (!red) return FALSE;
1617 blue = TRUE;
1618 break;
1619 default: return FALSE;
1620 }
1621 break;
1622 case 3:
1623 switch (ctype) {
1624 case WEED_VCHAN_alpha:
1625 if (alpha) return FALSE;
1626 alpha = TRUE;
1627 break;
1628 case WEED_VCHAN_red:
1629 if (!blue) return FALSE;
1630 red = TRUE;
1631 break;
1632 case WEED_VCHAN_blue:
1633 if (!red) return FALSE;
1634 blue = TRUE;
1635 break;
1636 default: return FALSE;
1637 }
1638 break;
1639 default:
1640 if (ctype != WEED_VCHAN_alpha) return FALSE;
1641 alpha = TRUE;
1642 break;
1643 }
1644 break;
1645 }
1646 }
1647 if (red != blue || nv != nu || (nseqy != nseqyu && nseqy != nseqyv)) return FALSE;
1648 return TRUE;
1649}
1650#endif
1651
1652
1653static 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
1658static void rgb2yuv(uint8_t r0, uint8_t g0, uint8_t b0, uint8_t *y, uint8_t *u, uint8_t *v) GNU_HOT;
1659static void yuv2rgb(uint8_t y, uint8_t u, uint8_t v, uint8_t *r, uint8_t *g, uint8_t *b) GNU_HOT;
1660
1662 init_RGB_to_YUV_tables();
1663 init_YUV_to_RGB_tables();
1664 init_YUV_to_YUV_tables();
1665 init_average();
1666 init_unal();
1667 init_gamma_tx();
1669#ifdef WEED_ADVANCED_PALETTES
1671#endif
1672 //#define TEST_CONV
1673#ifdef TEST_CONV
1674 if (1) {
1675 int cr, cg, cb;
1676 uint8_t r = 100, g, b, y, u, v, xr, xg, xb;;
1677 set_conversion_arrays(WEED_YUV_CLAMPING_UNCLAMPED, WEED_YUV_SUBSPACE_YCBCR);
1678 //prefs->pb_quality = PB_QUALITY_MED;
1679 for (cr = 100; cr < 256; cr++) {
1680 g = 0;
1681 for (cg = 0; cg < 256; cg++) {
1682 b = 0;
1683 for (cb = 0; cb < 256; cb++) {
1684 g_print("in: %d %d %d\n", r, g, b);
1685 rgb2yuv(r, g, b, &y, &u, &v);
1686 yuv2rgb(y, u, v, &xr, &xg, &xb);
1687 g_print("out: %d %d %d %d %d %d\n", y, u, v, xr, xg, xb);
1688 b++;
1689 }
1690 g++;
1691 }
1692 r++;
1693 }
1694 }
1695#endif
1696}
1697
1698// internal thread fns
1699static void *convert_rgb_to_uyvy_frame_thread(void *cc_params);
1700static void *convert_bgr_to_uyvy_frame_thread(void *cc_params);
1701static void *convert_rgb_to_yuyv_frame_thread(void *cc_params);
1702static void *convert_bgr_to_yuyv_frame_thread(void *cc_params);
1703static void *convert_argb_to_uyvy_frame_thread(void *cc_params);
1704static void *convert_argb_to_yuyv_frame_thread(void *cc_params);
1705
1706static void *convert_rgb_to_yuv_frame_thread(void *cc_params);
1707static void *convert_bgr_to_yuv_frame_thread(void *cc_params);
1708static void *convert_argb_to_yuv_frame_thread(void *cc_params);
1709static void *convert_rgb_to_yuvp_frame_thread(void *cc_params);
1710static void *convert_bgr_to_yuvp_frame_thread(void *cc_params);
1711static void *convert_argb_to_yuvp_frame_thread(void *cc_params);
1712
1713static void *convert_uyvy_to_rgb_frame_thread(void *cc_params);
1714static void *convert_uyvy_to_bgr_frame_thread(void *cc_params);
1715static void *convert_uyvy_to_argb_frame_thread(void *cc_params);
1716static void *convert_yuyv_to_rgb_frame_thread(void *cc_params);
1717static void *convert_yuyv_to_bgr_frame_thread(void *cc_params);
1718static void *convert_yuyv_to_argb_frame_thread(void *cc_params);
1719
1720static void *convert_yuv_planar_to_rgb_frame_thread(void *cc_params);
1721static void *convert_yuv_planar_to_bgr_frame_thread(void *cc_params);
1722static void *convert_yuv_planar_to_argb_frame_thread(void *cc_params);
1723
1724static void *convert_yuv420p_to_rgb_frame_thread(void *cc_params);
1725static void *convert_yuv420p_to_bgr_frame_thread(void *cc_params);
1726static void *convert_yuv420p_to_argb_frame_thread(void *cc_params);
1727
1728static void *convert_yuv888_to_rgb_frame_thread(void *cc_params);
1729static void *convert_yuv888_to_bgr_frame_thread(void *cc_params);
1730static void *convert_yuv888_to_argb_frame_thread(void *cc_params);
1731static void *convert_yuva8888_to_rgba_frame_thread(void *cc_params);
1732static void *convert_yuva8888_to_bgra_frame_thread(void *cc_params);
1733static void *convert_yuva8888_to_argb_frame_thread(void *cc_params);
1734
1735static void *convert_swap3_frame_thread(void *cc_params);
1736static void *convert_swap4_frame_thread(void *cc_params);
1737static void *convert_swap3addpost_frame_thread(void *cc_params);
1738static void *convert_swap3addpre_frame_thread(void *cc_params);
1739static void *convert_swap3delpost_frame_thread(void *cc_params);
1740static void *convert_swap3delpre_frame_thread(void *cc_params);
1741static void *convert_addpre_frame_thread(void *cc_params);
1742static void *convert_addpost_frame_thread(void *cc_params);
1743static void *convert_delpre_frame_thread(void *cc_params);
1744static void *convert_delpost_frame_thread(void *cc_params);
1745static void *convert_swap3postalpha_frame_thread(void *cc_params);
1746#ifdef WEED_ADVANCED_PALETTES
1747static void *convert_swap3prealpha_frame_thread(void *cc_params);
1748#endif
1749static void *convert_swapprepost_frame_thread(void *cc_params);
1750
1751static void *convert_swab_frame_thread(void *cc_params);
1752
1753#if 0
1754static 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
1756static void rgb2uyvy(uint8_t r0, uint8_t g0, uint8_t b0, uint8_t r1, uint8_t g1, uint8_t b1,
1758static 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;
1760static void rgb16_2uyvy(uint16_t r0, uint16_t g0, uint16_t b0, uint16_t r1, uint16_t g1, uint16_t b1,
1762#if 0
1763static 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
1767static void rgb2yuyv(uint8_t r0, uint8_t g0, uint8_t b0, uint8_t r1, uint8_t g1, uint8_t b1,
1769#if 0
1770static 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
1773static 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
1776static 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;
1777static 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;
1779static 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;
1781static void yuv888_2_rgb(uint8_t *yuv, uint8_t *rgb, boolean add_alpha) GNU_FLATTEN GNU_HOT;
1782static void yuva8888_2_rgba(uint8_t *yuva, uint8_t *rgba, boolean del_alpha) GNU_FLATTEN GNU_HOT;
1783static void yuv888_2_bgr(uint8_t *yuv, uint8_t *bgr, boolean add_alpha) GNU_FLATTEN GNU_HOT;
1784static void yuva8888_2_bgra(uint8_t *yuva, uint8_t *bgra, boolean del_alpha) GNU_FLATTEN GNU_HOT;
1785static void yuv888_2_argb(uint8_t *yuv, uint8_t *argb) GNU_FLATTEN GNU_HOT;
1786static void yuva8888_2_argb(uint8_t *yuva, uint8_t *argb) GNU_FLATTEN GNU_HOT;
1787static void uyvy_2_yuv422(uyvy_macropixel *uyvy, uint8_t *y0, uint8_t *u0, uint8_t *v0, uint8_t *y1) GNU_HOT;
1788static 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
1794static 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
1800static uint8_t avg_chromaf_fast(uint8_t x, uint8_t y) {
1801 return avg_chroma(x, y);
1802}
1803
1805 avg_chromaf = avg_chromaf_fast;
1806 if (intent == LIVES_INTENTION_RENDER || intent == LIVES_INTENTION_TRANSCODE) {
1807 //avg_chromaf = avg_chromaf_high;
1810 // this ensures we render at the highest settings
1812 } else {
1814 }
1815}
1816
1817#define avg_chroma_3_1f(x, y) ((uint8_t)(avg_chromaf(x, avg_chromaf(x, y))))
1818#define avg_chroma_1_3f(x, y) ((uint8_t)(avg_chromaf(avg_chromaf(x, y), y)))
1819
1820LIVES_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
1833LIVES_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
1846LIVES_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
1861LIVES_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
1877LIVES_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
1893LIVES_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
1910LIVES_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
1966LIVES_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
2022LIVES_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
2044LIVES_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
2052LIVES_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
2060LIVES_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
2068LIVES_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
2075LIVES_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
2081LIVES_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
2087LIVES_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
2093LIVES_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
2099LIVES_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
2105LIVES_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
2111LIVES_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
2119LIVES_INLINE void yuyv_2_yuv422(yuyv_macropixel *yuyv, uint8_t *y0, uint8_t *u0, uint8_t *v0, uint8_t *y1) {
2120 *y0 = yuyv->y0;
2121 *u0 = yuyv->u0;
2122 *y1 = yuyv->y1;
2123 *v0 = yuyv->v0;
2124}
2125
2127//utilities
2128
2129
2131#ifdef LIVES_PAINTER_IS_CAIRO
2132 if (pal == WEED_PALETTE_A8 || pal == WEED_PALETTE_A1) return TRUE;
2133 if (capable->byte_order == LIVES_BIG_ENDIAN) {
2134 if (pal == WEED_PALETTE_ARGB32) return TRUE;
2135 } else {
2136 if (pal == WEED_PALETTE_BGRA32) return TRUE;
2137 }
2138#endif
2139 return FALSE;
2140}
2141
2142
2143boolean weed_palette_is_lower_quality(int p1, int p2) {
2144 // return TRUE if p1 is lower quality than p2
2145 // we don't yet handle float palettes, or RGB or alpha properly
2146
2147 // currently only works well for YUV palettes
2148
2149 if ((weed_palette_is_alpha(p1) && !weed_palette_is_alpha(p2)) ||
2150 (weed_palette_is_alpha(p2) && !weed_palette_is_alpha(p1))) return TRUE; // invalid conversion
2151
2152 if (weed_palette_is_rgb(p1) && weed_palette_is_rgb(p2)) return FALSE;
2153
2154 switch (p2) {
2155 case WEED_PALETTE_YUVA8888:
2156 if (p1 != WEED_PALETTE_YUVA8888 && p1 != WEED_PALETTE_YUVA4444P) return TRUE;
2157 break;
2158 case WEED_PALETTE_YUVA4444P:
2159 if (p1 != WEED_PALETTE_YUVA8888 && p1 != WEED_PALETTE_YUVA4444P) return TRUE;
2160 break;
2161 case WEED_PALETTE_YUV888:
2162 if (p1 != WEED_PALETTE_YUVA8888 && p1 != WEED_PALETTE_YUVA4444P && p1 != WEED_PALETTE_YUV444P
2163 && p1 != WEED_PALETTE_YUVA4444P)
2164 return TRUE;
2165 break;
2166 case WEED_PALETTE_YUV444P:
2167 if (p1 != WEED_PALETTE_YUVA8888 && p1 != WEED_PALETTE_YUVA4444P && p1 != WEED_PALETTE_YUV444P
2168 && p1 != WEED_PALETTE_YUVA4444P)
2169 return TRUE;
2170 break;
2171
2172 case WEED_PALETTE_YUV422P:
2173 case WEED_PALETTE_UYVY8888:
2174 case WEED_PALETTE_YUYV8888:
2175 if (p1 != WEED_PALETTE_YUVA8888 && p1 != WEED_PALETTE_YUVA4444P && p1 != WEED_PALETTE_YUV444P &&
2176 p1 != WEED_PALETTE_YUVA4444P && p1 != WEED_PALETTE_YUV422P && p1 != WEED_PALETTE_UYVY8888
2177 && p1 != WEED_PALETTE_YUYV8888)
2178 return TRUE;
2179 break;
2180
2181 case WEED_PALETTE_YUV420P:
2182 case WEED_PALETTE_YVU420P:
2183 if (p1 == WEED_PALETTE_YUV411) return TRUE;
2184 break;
2185 case WEED_PALETTE_A8:
2186 if (p1 == WEED_PALETTE_A1) return TRUE;
2187 }
2188 return FALSE; // TODO
2189}
2190
2192
2194 int width = lives_pixbuf_get_width(pixbuf);
2195 int height = lives_pixbuf_get_height(pixbuf);
2196 int rstride = lives_pixbuf_get_rowstride(pixbuf);
2197 boolean has_alpha = lives_pixbuf_get_has_alpha(pixbuf);
2198 const uint8_t *pdata = lives_pixbuf_get_pixels_readonly(pixbuf);
2199 uint8_t a, b, c;
2200 int offs = 0;
2201 int psize = has_alpha ? 4 : 3;
2202 register int i, j;
2203
2204 width *= psize;
2205
2206 for (j = 0; j < height; j++) {
2207 for (i = offs; i < width; i += psize) {
2223 a = pdata[i];
2224 b = pdata[i + 1];
2225 c = pdata[i + 2];
2226
2227 if (((a & 0x1F) ^ a) & ((c & 0x1F) ^ c) & (((b & 0x1F) ^ b) | ((((b << 1) & 0x1F) ^ (b << 1))
2228 & ((((b & 0x0F) << 2) & 0x1F) ^ ((b & 0x0F) << 2))))) return FALSE;
2229 }
2230 pdata += rstride;
2231 }
2232 return TRUE;
2233}
2234
2235
2236void pixel_data_planar_from_membuf(void **pixel_data, void *data, size_t size, int palette, boolean contig) {
2237 // convert contiguous memory block planes to planar data
2238 // size is the byte size of the Y plane (width*height in pixels)
2239
2240 switch (palette) {
2241 case WEED_PALETTE_YUV444P:
2242 if (contig) lives_memcpy(pixel_data[0], data, size * 3);
2243 else {
2244 lives_memcpy(pixel_data[0], data, size);
2245 lives_memcpy(pixel_data[1], (uint8_t *)data + size, size);
2246 lives_memcpy(pixel_data[2], (uint8_t *)data + size * 2, size);
2247 }
2248 break;
2249 case WEED_PALETTE_YUVA4444P:
2250 if (contig) lives_memcpy(pixel_data[0], data, size * 4);
2251 else {
2252 lives_memcpy(pixel_data[0], data, size);
2253 lives_memcpy(pixel_data[1], (uint8_t *)data + size, size);
2254 lives_memcpy(pixel_data[2], (uint8_t *)data + size * 2, size);
2255 lives_memcpy(pixel_data[3], (uint8_t *)data + size * 2, size);
2256 }
2257 break;
2258 case WEED_PALETTE_YUV422P:
2259 if (contig) lives_memcpy(pixel_data[0], data, size * 2);
2260 else {
2261 lives_memcpy(pixel_data[0], data, size);
2262 lives_memcpy(pixel_data[1], (uint8_t *)data + size, size / 2);
2263 lives_memcpy(pixel_data[2], (uint8_t *)data + size * 3 / 2, size / 2);
2264 }
2265 break;
2266 case WEED_PALETTE_YUV420P:
2267 case WEED_PALETTE_YVU420P:
2268 if (contig) lives_memcpy(pixel_data[0], data, size * 3 / 2);
2269 else {
2270 lives_memcpy(pixel_data[0], data, size);
2271 lives_memcpy(pixel_data[1], (uint8_t *)data + size, size / 4);
2272 lives_memcpy(pixel_data[2], (uint8_t *)data + size * 5 / 4, size / 4);
2273 }
2274 break;
2275 }
2276}
2277
2278
2280// frame conversions
2281
2282static 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) {
2294 uint8_t *end = src + vsize * irowstride;
2295 int nthreads = 1;
2296 int dheight, xdheight;
2298
2299 xdheight = CEIL((double)vsize / (double)prefs->nfx_threads, 4);
2300 for (i = prefs->nfx_threads - 1; i >= 0; i--) {
2301 dheight = xdheight;
2302
2303 if ((src + dheight * i * irowstride) < end) {
2304 ccparams[i].src = src + dheight * i * irowstride;
2305 ccparams[i].hsize = hsize;
2306 ccparams[i].dest = dest + dheight * i * orowstride;
2307
2308 if (dheight * (i + 1) > (vsize - 4)) {
2309 dheight = vsize - (dheight * i);
2310 }
2311
2312 ccparams[i].vsize = dheight;
2313
2314 ccparams[i].irowstrides[0] = irowstride;
2315 ccparams[i].orowstrides[0] = orowstride;
2316 ccparams[i].out_alpha = add_alpha;
2317 ccparams[i].in_clamping = clamping;
2318 ccparams[i].in_subspace = subspace;
2319 ccparams[i].thread_id = i;
2320
2321 if (i == 0) convert_yuv888_to_rgb_frame_thread(&ccparams[i]);
2322 else {
2323 lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_yuv888_to_rgb_frame_thread, &ccparams[i]);
2324 nthreads++;
2325 }
2326 }
2327 }
2328
2329 for (i = 1; i < nthreads; i++) {
2330 lives_thread_join(threads[i], NULL);
2331 }
2332 lives_free(ccparams);
2333 return;
2334 }
2335 }
2336
2337 if (add_alpha) offs = 4;
2338 orowstride -= offs * hsize;
2339 irowstride -= hsize * 3;
2340
2341 for (y = 0; y < vsize; y++) {
2342 for (x = 0; x < hsize; x++) {
2343 yuv888_2_rgb(src, dest, add_alpha);
2344 src += 3;
2345 dest += offs;
2346 }
2347 dest += orowstride;
2348 src += irowstride;
2349 }
2350}
2351
2352
2353static 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
2362static 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) {
2375 uint8_t *end = src + vsize * irowstride;
2376 int nthreads = 1;
2377 int dheight, xdheight;
2379
2380 xdheight = CEIL((double)vsize / (double)prefs->nfx_threads, 4);
2381 for (i = prefs->nfx_threads - 1; i >= 0; i--) {
2382 dheight = xdheight;
2383
2384 if ((src + dheight * i * irowstride) < end) {
2385 ccparams[i].src = src + dheight * i * irowstride;
2386 ccparams[i].hsize = hsize;
2387 ccparams[i].dest = dest + dheight * i * orowstride;
2388
2389 if (dheight * (i + 1) > (vsize - 4)) {
2390 dheight = vsize - (dheight * i);
2391 }
2392
2393 ccparams[i].vsize = dheight;
2394
2395 ccparams[i].irowstrides[0] = irowstride;
2396 ccparams[i].orowstrides[0] = orowstride;
2397 ccparams[i].out_alpha = !del_alpha;
2398 ccparams[i].in_clamping = clamping;
2399 ccparams[i].in_subspace = subspace;
2400 ccparams[i].thread_id = i;
2401
2402 if (i == 0) convert_yuva8888_to_rgba_frame_thread(&ccparams[i]);
2403 else {
2404 lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_yuva8888_to_rgba_frame_thread, &ccparams[i]);
2405 nthreads++;
2406 }
2407 }
2408 }
2409
2410 for (i = 1; i < nthreads; i++) {
2411 lives_thread_join(threads[i], NULL);
2412 }
2413 lives_free(ccparams);
2414 return;
2415 }
2416
2417 if (del_alpha) offs = 3;
2418 orowstride -= offs * hsize;
2419 irowstride -= hsize * 4;
2420
2421 for (y = 0; y < vsize; y++) {
2422 for (x = 0; x < hsize; x++) {
2423 yuva8888_2_rgba(src, dest, del_alpha);
2424 src += 4;
2425 dest += offs;
2426 }
2427 dest += orowstride;
2428 src += irowstride;
2429 }
2430}
2431
2432
2433static 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
2442static 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) {
2453 uint8_t *end = src + vsize * irowstride;
2454 int nthreads = 1;
2455 int dheight, xdheight;
2457
2458 xdheight = CEIL((double)vsize / (double)prefs->nfx_threads, 4);
2459 for (i = prefs->nfx_threads - 1; i >= 0; i--) {
2460 dheight = xdheight;
2461
2462 if ((src + dheight * i * irowstride) < end) {
2463 ccparams[i].src = src + dheight * i * irowstride;
2464 ccparams[i].hsize = hsize;
2465 ccparams[i].dest = dest + dheight * i * orowstride;
2466
2467 if (dheight * (i + 1) > (vsize - 4)) {
2468 dheight = vsize - (dheight * i);
2469 }
2470
2471 ccparams[i].vsize = dheight;
2472
2473 ccparams[i].irowstrides[0] = irowstride;
2474 ccparams[i].orowstrides[0] = orowstride;
2475 ccparams[i].out_alpha = add_alpha;
2476 ccparams[i].in_clamping = clamping;
2477 ccparams[i].in_subspace = subspace;
2478 ccparams[i].thread_id = i;
2479
2480 if (i == 0) convert_yuv888_to_bgr_frame_thread(&ccparams[i]);
2481 else {
2482 lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_yuv888_to_bgr_frame_thread, &ccparams[i]);
2483 nthreads++;
2484 }
2485 }
2486 }
2487
2488 for (i = 1; i < nthreads; i++) {
2489 lives_thread_join(threads[i], NULL);
2490 }
2491 lives_free(ccparams);
2492 return;
2493 }
2494
2495 if (add_alpha) offs = 4;
2496 orowstride -= offs * hsize;
2497 irowstride -= hsize * 3;
2498
2499 for (y = 0; y < vsize; y++) {
2500 for (x = 0; x < hsize; x++) {
2501 yuv888_2_bgr(src, dest, add_alpha);
2502 src += 3;
2503 dest += offs;
2504 }
2505 dest += orowstride;
2506 src += irowstride;
2507 }
2508}
2509
2510
2511static 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
2520static 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) {
2532 uint8_t *end = src + vsize * irowstride;
2533 int nthreads = 1;
2534 int dheight, xdheight;
2536
2537 xdheight = CEIL((double)vsize / (double)prefs->nfx_threads, 4);
2538 for (i = prefs->nfx_threads - 1; i >= 0; i--) {
2539 dheight = xdheight;
2540
2541 if ((src + dheight * i * irowstride) < end) {
2542 ccparams[i].src = src + dheight * i * irowstride;
2543 ccparams[i].hsize = hsize;
2544 ccparams[i].dest = dest + dheight * i * orowstride;
2545
2546 if (dheight * (i + 1) > (vsize - 4)) {
2547 dheight = vsize - (dheight * i);
2548 }
2549
2550 ccparams[i].vsize = dheight;
2551
2552 ccparams[i].irowstrides[0] = irowstride;
2553 ccparams[i].orowstrides[0] = orowstride;
2554 ccparams[i].out_alpha = !del_alpha;
2555 ccparams[i].in_clamping = clamping;
2556 ccparams[i].in_subspace = subspace;
2557 ccparams[i].thread_id = i;
2558
2559 if (i == 0) convert_yuva8888_to_bgra_frame_thread(&ccparams[i]);
2560 else {
2561 lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_yuva8888_to_bgra_frame_thread, &ccparams[i]);
2562 nthreads++;
2563 }
2564 }
2565 }
2566
2567 for (i = 1; i < nthreads; i++) {
2568 lives_thread_join(threads[i], NULL);
2569 }
2570 lives_free(ccparams);
2571 return;
2572 }
2573
2574 if (del_alpha) offs = 3;
2575 orowstride -= offs * hsize;
2576 irowstride -= 4 * hsize;
2577
2578 for (y = 0; y < vsize; y++) {
2579 for (x = 0; x < hsize; x++) {
2580 yuva8888_2_bgra(src, dest, del_alpha);
2581 src += 4;
2582 dest += offs;
2583 }
2584 dest += orowstride;
2585 src += irowstride;
2586 }
2587}
2588
2589
2590static 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
2599static 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) {
2610 uint8_t *end = src + vsize * irowstride;
2611 int nthreads = 1;
2612 int dheight, xdheight;
2614
2615 xdheight = CEIL((double)vsize / (double)prefs->nfx_threads, 4);
2616 for (i = prefs->nfx_threads - 1; i >= 0; i--) {
2617 dheight = xdheight;
2618
2619 if ((src + dheight * i * irowstride) < end) {
2620 ccparams[i].src = src + dheight * i * irowstride;
2621 ccparams[i].hsize = hsize;
2622 ccparams[i].dest = dest + dheight * i * orowstride;
2623
2624 if (dheight * (i + 1) > (vsize - 4)) {
2625 dheight = vsize - (dheight * i);
2626 }
2627
2628 ccparams[i].vsize = dheight;
2629
2630 ccparams[i].irowstrides[0] = irowstride;
2631 ccparams[i].orowstrides[0] = orowstride;
2632 ccparams[i].in_clamping = clamping;
2633 ccparams[i].in_subspace = subspace;
2634 ccparams[i].thread_id = i;
2635
2636 if (i == 0) convert_yuv888_to_argb_frame_thread(&ccparams[i]);
2637 else {
2638 lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_yuv888_to_argb_frame_thread, &ccparams[i]);
2639 nthreads++;
2640 }
2641 }
2642 }
2643
2644 for (i = 1; i < nthreads; i++) {
2645 lives_thread_join(threads[i], NULL);
2646 }
2647 lives_free(ccparams);
2648 return;
2649 }
2650
2651 orowstride -= offs * hsize;
2652 irowstride -= hsize * 3;
2653
2654 for (y = 0; y < vsize; y++) {
2655 for (x = 0; x < hsize; x++) {
2656 yuv888_2_argb(src, dest);
2657 src += 3;
2658 dest += 4;
2659 }
2660 dest += orowstride;
2661 src += irowstride;
2662 }
2663}
2664
2665
2666static 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
2675static 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) {
2687 uint8_t *end = src + vsize * irowstride;
2688 int nthreads = 1;
2689 int dheight, xdheight;
2691
2692 xdheight = CEIL((double)vsize / (double)prefs->nfx_threads, 4);
2693 for (i = prefs->nfx_threads - 1; i >= 0; i--) {
2694 dheight = xdheight;
2695
2696 if ((src + dheight * i * irowstride) < end) {
2697 ccparams[i].src = src + dheight * i * irowstride;
2698 ccparams[i].hsize = hsize;
2699 ccparams[i].dest = dest + dheight * i * orowstride;
2700
2701 if (dheight * (i + 1) > (vsize - 4)) {
2702 dheight = vsize - (dheight * i);
2703 }
2704
2705 ccparams[i].vsize = dheight;
2706
2707 ccparams[i].irowstrides[0] = irowstride;
2708 ccparams[i].orowstrides[0] = orowstride;
2709 ccparams[i].in_clamping = clamping;
2710 ccparams[i].in_subspace = subspace;
2711 ccparams[i].thread_id = i;
2712
2713 if (i == 0) convert_yuva8888_to_argb_frame_thread(&ccparams[i]);
2714 else {
2715 lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_yuva8888_to_rgba_frame_thread, &ccparams[i]);
2716 nthreads++;
2717 }
2718 }
2719 }
2720
2721 for (i = 1; i < nthreads; i++) {
2722 lives_thread_join(threads[i], NULL);
2723 }
2724 lives_free(ccparams);
2725 return;
2726 }
2727
2728 orowstride -= offs * hsize;
2729 irowstride -= hsize * 4;
2730
2731 for (y = 0; y < vsize; y++) {
2732 for (x = 0; x < hsize; x++) {
2733 yuva8888_2_argb(src, dest);
2734 src += 4;
2735 dest += 4;
2736 }
2737 dest += orowstride;
2738 src += irowstride;
2739 }
2740}
2741
2742
2743static 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
2752static void convert_yuv420p_to_rgb_frame(uint8_t **src, int width, int height, boolean is_bottom, int *istrides, int orowstride,
2753 uint8_t *dest, boolean add_alpha, boolean is_422, int sampling, int clamping, int subspace,
2754 int gamma, int tgamma, uint8_t *gamma_lut, int thread_id) {
2755 int i, j;
2756 uint8_t *s_y = src[0], *s_u = src[1], *s_v = src[2];
2757 int opsize = 3;
2758 int irow = istrides[0] - width;
2759 boolean even = TRUE;
2760 size_t uv_offs = 0;
2761 uint8_t y, u, v, next_u, next_v, last_u, last_v;
2762
2763 if (thread_id == -1) {
2764 if (LIVES_UNLIKELY(!conv_YR_inited)) init_YUV_to_RGB_tables();
2765
2767 set_conversion_arrays(clamping, subspace);
2768
2769 if (tgamma) gamma_lut = create_gamma_lut(1.0, gamma, tgamma);
2770 if (prefs->nfx_threads > 1) {
2772 uint8_t *end = src[0] + height * istrides[0];
2773 int nthreads = 1;
2774 int dheight, xdheight;
2776
2777 xdheight = CEIL((double)height / (double)prefs->nfx_threads, 4);
2778 for (i = prefs->nfx_threads - 1; i >= 0; i--) {
2779 dheight = xdheight;
2780
2781 if ((src[0] + dheight * i * istrides[0]) < end) {
2782 ccparams[i].srcp[0] = src[0] + dheight * i * istrides[0];
2783 ccparams[i].srcp[1] = src[1] + dheight / 2 * i * istrides[1];
2784 ccparams[i].srcp[2] = src[2] + dheight / 2 * i * istrides[2];
2785 ccparams[i].hsize = width;
2786 ccparams[i].dest = dest + dheight * i * orowstride;
2787
2788 if (dheight * (i + 1) > (height - 4)) {
2789 dheight = height - (dheight * i);
2790 }
2791
2792 ccparams[i].vsize = dheight;
2793 if (i == prefs->nfx_threads - 1) {
2794 ccparams[i].is_bottom = TRUE;
2795 }
2796 ccparams[i].irowstrides[0] = istrides[0];
2797 ccparams[i].irowstrides[1] = istrides[1];
2798 ccparams[i].irowstrides[2] = istrides[2];
2799 ccparams[i].orowstrides[0] = orowstride;
2800 ccparams[i].out_alpha = add_alpha;
2801 ccparams[i].in_sampling = sampling;
2802 ccparams[i].in_clamping = clamping;
2803 ccparams[i].in_subspace = subspace;
2804 ccparams[i].is_422 = is_422;
2805 ccparams[i].lut = gamma_lut;
2806 ccparams[i].thread_id = i;
2807
2808 if (i == 0) convert_yuv420p_to_rgb_frame_thread(&ccparams[i]);
2809 else {
2810 lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_yuv420p_to_rgb_frame_thread, &ccparams[i]);
2811 nthreads++;
2812 }
2813 }
2814 }
2815
2816 for (i = 1; i < nthreads; i++) {
2817 lives_thread_join(threads[i], NULL);
2818 }
2819 lives_free(ccparams);
2820 if (gamma_lut) lives_gamma_lut_free(gamma_lut);
2821 return;
2822 }
2823 }
2824
2825 if (add_alpha) opsize = 4;
2826 width *= opsize;
2827
2828 for (i = 0; i < height; i++) {
2829 if (!is_422) {
2830 if (!(i & 1)) even = TRUE;
2831 else even = FALSE;
2832 }
2833
2834 uv_offs = 0;
2835
2836 for (j = 0; j < width; j += opsize) {
2837 // process two pixels at a time, and we average the first colour pixel with the last from the previous 2
2838 // we know we can do this because Y must be even width
2839 y = *(s_y++);
2841 if (j > 0) {
2843 u = avg_chroma_3_1(next_u, last_u);
2844 v = avg_chroma_3_1(next_v, last_v);
2845 last_u = next_u;
2846 last_v = next_v;
2847 } else {
2848 if (even) {
2849 last_u = next_u = u = s_u[uv_offs];
2850 last_v = next_v = v = s_v[uv_offs];
2851 } else {
2852 if (is_bottom && i == height - 1) {
2853 next_u = u = s_u[uv_offs];
2854 next_v = v = s_v[uv_offs];
2855 } else {
2856 next_u = u = avg_chromaf(s_u[uv_offs], s_u[uv_offs + istrides[1]]);
2857 next_v = v = avg_chromaf(s_v[uv_offs], s_v[uv_offs + istrides[2]]);
2858 }
2859 }
2860 }
2861 if (gamma_lut)
2862 yuv2rgb_with_gamma(y, u, v, &dest[j], &dest[j + 1], &dest[j + 2], gamma_lut);
2863 else
2864 yuv2rgb(y, u, v, &dest[j], &dest[j + 1], &dest[j + 2]);
2865 if (add_alpha) dest[j + 3] = 255;
2866
2867 // second RGB pixel
2868 j += opsize;
2869 y = *(s_y++);
2870
2871 last_u = next_u;
2872 last_v = next_v;
2873
2874 if (j < width - 1) {
2875 if (even) {
2877 next_u = s_u[uv_offs];
2878 next_v = s_v[uv_offs];
2879 } else {
2880 if (is_bottom && i == height - 1) {
2881 next_u = u = s_u[uv_offs];
2882 next_v = v = s_v[uv_offs];
2883 } else {
2884 //g_print("vals %ld and %d %d %d\n", uv_offs, istrides[2], i, j);
2885 next_u = u = avg_chromaf(s_u[uv_offs], s_u[uv_offs + istrides[1]]);
2886 next_v = v = avg_chromaf(s_v[uv_offs], s_v[uv_offs + istrides[2]]);
2887 }
2888 }
2890 u = avg_chroma_3_1(next_u, last_u);
2891 v = avg_chroma_3_1(next_v, last_v);
2892 } else {
2893 u = last_u;
2894 v = last_v;
2895 }
2896 if (gamma_lut)
2897 yuv2rgb_with_gamma(y, u, v, &dest[j], &dest[j + 1], &dest[j + 2], gamma_lut);
2898 else
2899 yuv2rgb(y, u, v, &dest[j], &dest[j + 1], &dest[j + 2]);
2900 if (add_alpha) dest[j + 3] = 255;
2901 uv_offs++;
2902 }
2903 s_y += irow;
2904 dest += orowstride;
2905 if (is_422 || !even) {
2906 s_u += istrides[1];
2907 s_v += istrides[2];
2908 }
2909 }
2910}
2911
2912static 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
2924static void convert_yuv420p_to_bgr_frame(uint8_t **src, int width, int height, boolean is_bottom, int *istrides, int orowstride,
2925 uint8_t *dest, boolean add_alpha, boolean is_422, int sampling, int clamping, int subspace,
2926 int gamma, int tgamma, uint8_t *gamma_lut, int thread_id) {
2927 int i, j;
2928 uint8_t *s_y = src[0], *s_u = src[1], *s_v = src[2];
2929 int opsize = 3;
2930 int irow = istrides[0] - width;
2931 boolean even = TRUE;
2932 uint8_t y, u, v, next_u, next_v, last_u, last_v;
2933 size_t uv_offs = 0;
2934
2935 if (thread_id == -1) {
2936 if (LIVES_UNLIKELY(!conv_YR_inited)) init_YUV_to_RGB_tables();
2937
2939 set_conversion_arrays(clamping, subspace);
2940
2941 if (tgamma) gamma_lut = create_gamma_lut(1.0, gamma, tgamma);
2942 if (prefs->nfx_threads > 1) {
2944 uint8_t *end = src[0] + height * istrides[0];
2945 int nthreads = 1;
2946 int dheight, xdheight;
2948
2949 xdheight = CEIL((double)height / (double)prefs->nfx_threads, 4);
2950 for (i = prefs->nfx_threads - 1; i >= 0; i--) {
2951 dheight = xdheight;
2952
2953 if ((src[0] + dheight * i * istrides[0]) < end) {
2954 ccparams[i].srcp[0] = src[0] + dheight * i * istrides[0];
2955 ccparams[i].srcp[1] = src[1] + dheight / 2 * i * istrides[1];
2956 ccparams[i].srcp[2] = src[2] + dheight / 2 * i * istrides[2];
2957 ccparams[i].hsize = width;
2958 ccparams[i].dest = dest + dheight * i * orowstride;
2959
2960 if (dheight * (i + 1) > (height - 4)) {
2961 dheight = height - (dheight * i);
2962 }
2963
2964 ccparams[i].vsize = dheight;
2965 if (i == prefs->nfx_threads - 1) ccparams->is_bottom = TRUE;
2966
2967 ccparams[i].irowstrides[0] = istrides[0];
2968 ccparams[i].irowstrides[1] = istrides[1];
2969 ccparams[i].irowstrides[2] = istrides[2];
2970 ccparams[i].orowstrides[0] = orowstride;
2971 ccparams[i].out_alpha = add_alpha;
2972 ccparams[i].in_sampling = sampling;
2973 ccparams[i].in_clamping = clamping;
2974 ccparams[i].in_subspace = subspace;
2975 ccparams[i].is_422 = is_422;
2976 ccparams[i].lut = gamma_lut;
2977 ccparams[i].thread_id = i;
2978
2979 if (i == 0) convert_yuv420p_to_bgr_frame_thread(&ccparams[i]);
2980 else {
2981 lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_yuv420p_to_bgr_frame_thread, &ccparams[i]);
2982 nthreads++;
2983 }
2984 }
2985 }
2986
2987 for (i = 1; i < nthreads; i++) {
2988 lives_thread_join(threads[i], NULL);
2989 }
2990 lives_free(ccparams);
2991 if (gamma_lut) lives_gamma_lut_free(gamma_lut);
2992 return;
2993 }
2994 }
2995
2996 if (add_alpha) opsize = 4;
2997 width *= opsize;
2998
2999 for (i = 0; i < height; i++) {
3000 if (!is_422) {
3001 if (!(i & 1)) even = TRUE;
3002 else even = FALSE;
3003 }
3004
3005 uv_offs = 0;
3006
3007 for (j = 0; j < width; j += opsize) {
3008 // process two pixels at a time, and we average the first colour pixel with the last from the previous 2
3009 // we know we can do this because Y must be even width
3010 y = *(s_y++);
3012 if (j > 0) {
3014 u = avg_chroma_3_1(next_u, last_u);
3015 v = avg_chroma_3_1(next_v, last_v);
3016 last_u = next_u;
3017 last_v = next_v;
3018 } else {
3019 if (even) {
3020 next_u = u = s_u[uv_offs];
3021 next_v = v = s_v[uv_offs];
3022 } else {
3023 if (i == height - 1 && is_bottom) {
3024 next_u = u = s_u[uv_offs];
3025 next_v = v = s_v[uv_offs];
3026 } else {
3027 next_u = u = avg_chromaf(s_u[uv_offs], s_u[uv_offs + istrides[1]]);
3028 next_v = v = avg_chromaf(s_v[uv_offs], s_v[uv_offs + istrides[2]]);
3029 }
3030 }
3031 }
3032 if (gamma_lut)
3033 yuv2bgr_with_gamma(y, u, v, &dest[j], &dest[j + 1], &dest[j + 2], gamma_lut);
3034 else
3035 yuv2bgr(y, u, v, &dest[j], &dest[j + 1], &dest[j + 2]);
3036 if (add_alpha) dest[j + 3] = 255;
3037
3038 // second RGB pixel
3039 j += opsize;
3040 y = *(s_y++);
3041 last_u = next_u;
3042 last_v = next_v;
3043
3044 if (j < width - 1) {
3045 if (even) {
3047 next_u = s_u[uv_offs];
3048 next_v = s_v[uv_offs];
3049 } else {
3050 if (i == height - 1 && is_bottom) {
3051 next_u = u = s_u[uv_offs];
3052 next_v = v = s_v[uv_offs];
3053 } else {
3054 next_u = u = avg_chromaf(s_u[uv_offs], s_u[uv_offs + istrides[1]]);
3055 next_v = v = avg_chromaf(s_v[uv_offs], s_v[uv_offs + istrides[2]]);
3056 }
3057 }
3059 u = avg_chroma_3_1(next_u, last_u);
3060 v = avg_chroma_3_1(next_v, last_v);
3061 } else {
3062 u = last_u;
3063 v = last_v;
3064 }
3065 if (gamma_lut)
3066 yuv2bgr_with_gamma(y, u, v, &dest[j], &dest[j + 1], &dest[j + 2], gamma_lut);
3067 else
3068 yuv2bgr(y, u, v, &dest[j], &dest[j + 1], &dest[j + 2]);
3069 if (add_alpha) dest[j + 3] = 255;
3070 uv_offs++;
3071 }
3072 s_y += irow;
3073 dest += orowstride;
3074 if (is_422 || !even) {
3075 s_u += istrides[1];
3076 s_v += istrides[2];
3077 }
3078 }
3079}
3080
3081static 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
3093static void convert_yuv420p_to_argb_frame(uint8_t **src, int width, int height, boolean is_bottom, int *istrides,
3094 int orowstride,
3095 uint8_t *dest, boolean is_422, int sampling, int clamping, int subspace,
3096 int gamma, int tgamma, uint8_t *gamma_lut, int thread_id) {
3097 int i, j;
3098 uint8_t *s_y = src[0], *s_u = src[1], *s_v = src[2];
3099 int opsize = 4;
3100 int irow = istrides[0] - width;
3101 boolean even = TRUE;
3102 uint8_t y, u, v, next_u = 0, next_v = 0, last_u = 0, last_v = 0;
3103 size_t uv_offs = 0;
3104
3105 if (thread_id == -1) {
3106 if (LIVES_UNLIKELY(!conv_YR_inited)) init_YUV_to_RGB_tables();
3107
3109 set_conversion_arrays(clamping, subspace);
3110
3111 if (tgamma) gamma_lut = create_gamma_lut(1.0, gamma, tgamma);
3112 if (prefs->nfx_threads > 1) {
3114 uint8_t *end = src[0] + height * istrides[0];
3115 int nthreads = 1;
3116 int dheight, xdheight;
3118
3119 xdheight = CEIL((double)height / (double)prefs->nfx_threads, 4);
3120 for (i = prefs->nfx_threads - 1; i >= 0; i--) {
3121 dheight = xdheight;
3122
3123 if ((src[0] + dheight * i * istrides[0]) < end) {
3124 ccparams[i].srcp[0] = src[0] + dheight * i * istrides[0];
3125 ccparams[i].srcp[1] = src[1] + dheight / 2 * i * istrides[1];
3126 ccparams[i].srcp[2] = src[2] + dheight / 2 * i * istrides[2];
3127 ccparams[i].hsize = width;
3128 ccparams[i].dest = dest + dheight * i * orowstride;
3129
3130 if (dheight * (i + 1) > (height - 4)) {
3131 dheight = height - (dheight * i);
3132 }
3133
3134 ccparams[i].vsize = dheight;
3135 if (i == prefs->nfx_threads - 1) ccparams->is_bottom = TRUE;
3136
3137 ccparams[i].irowstrides[0] = istrides[0];
3138 ccparams[i].irowstrides[1] = istrides[1];
3139 ccparams[i].irowstrides[2] = istrides[2];
3140 ccparams[i].orowstrides[0] = orowstride;
3141 ccparams[i].in_sampling = sampling;
3142 ccparams[i].in_clamping = clamping;
3143 ccparams[i].in_subspace = subspace;
3144 ccparams[i].is_422 = is_422;
3145 ccparams[i].lut = gamma_lut;
3146 ccparams[i].thread_id = i;
3147
3148 if (i == 0) convert_yuv420p_to_argb_frame_thread(&ccparams[i]);
3149 else {
3150 lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_yuv420p_to_argb_frame_thread, &ccparams[i]);
3151 nthreads++;
3152 }
3153 }
3154 }
3155
3156 for (i = 1; i < nthreads; i++) {
3157 lives_thread_join(threads[i], NULL);
3158 }
3159 lives_free(ccparams);
3160 if (gamma_lut) lives_gamma_lut_free(gamma_lut);
3161 return;
3162 }
3163 }
3164
3165 width *= opsize;
3166
3167 for (i = 0; i < height; i++) {
3168 if (!is_422) {
3169 if (!(i & 1)) even = TRUE;
3170 else even = FALSE;
3171 }
3172
3173 uv_offs = 0;
3174
3175 for (j = 0; j < width; j += opsize) {
3176 // process two pixels at a time, and we average the first colour pixel with the last from the previous 2
3177 // we know we can do this because Y must be even width
3178 dest[j] = 255;
3179 y = *(s_y++);
3181 if (j > 0) {
3183 u = avg_chroma_3_1(next_u, last_u);
3184 v = avg_chroma_3_1(next_v, last_v);
3185 last_u = next_u;
3186 last_v = next_v;
3187 } else {
3188 if (even) {
3189 next_u = u = s_u[uv_offs];
3190 next_v = v = s_v[uv_offs];
3191 } else {
3192 if (i == height - 1 && is_bottom) {
3193 next_u = u = s_u[uv_offs];
3194 next_v = v = s_v[uv_offs];
3195 } else {
3196 next_u = u = avg_chromaf(s_u[uv_offs], s_u[uv_offs + istrides[1]]);
3197 next_v = v = avg_chromaf(s_v[uv_offs], s_v[uv_offs + istrides[2]]);
3198 }
3199 }
3200 }
3201 if (gamma_lut)
3202 yuv2rgb_with_gamma(y, u, v, &dest[j + 1], &dest[j + 2], &dest[j + 3], gamma_lut);
3203 else
3204 yuv2rgb(y, u, v, &dest[j + 1], &dest[j + 2], &dest[j + 3]);
3205
3206 // second RGB pixel
3207 j += opsize;
3208 y = *(s_y++);
3209 last_u = next_u;
3210 last_v = next_v;
3211 dest[j] = 255;
3212
3213 if (j < width - 1) {
3214 if (even) {
3216 next_u = s_u[uv_offs];
3217 next_v = s_v[uv_offs];
3218 } else {
3219 if (i == height - 1 && is_bottom) {
3220 next_u = u = s_u[uv_offs];
3221 next_v = v = s_v[uv_offs];
3222 } else {
3223 next_u = u = avg_chromaf(s_u[uv_offs], s_u[uv_offs + istrides[1]]);
3224 next_v = v = avg_chromaf(s_v[uv_offs], s_v[uv_offs + istrides[2]]);
3225 }
3226 }
3228 u = avg_chroma_3_1(next_u, last_u);
3229 v = avg_chroma_3_1(next_v, last_v);
3230 } else {
3231 u = last_u;
3232 v = last_v;
3233 }
3234 if (gamma_lut)
3235 yuv2rgb_with_gamma(y, u, v, &dest[j + 1], &dest[j + 2], &dest[j + 3], gamma_lut);
3236 else
3237 yuv2rgb(y, u, v, &dest[j + 1], &dest[j + 2], &dest[j + 3]);
3238 uv_offs++;
3239 }
3240 s_y += irow;
3241 dest += orowstride;
3242 if (is_422 || !even) {
3243 s_u += istrides[1];
3244 s_v += istrides[2];
3245 }
3246 }
3247}
3248
3249static 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
3261static 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) {
3280 int nthreads = 1;
3281 int dheight, xdheight;
3283
3284 xdheight = CEIL((double)vsize / (double)prefs->nfx_threads, 4);
3285 for (i = prefs->nfx_threads - 1; i >= 0; i--) {
3286 dheight = xdheight;
3287
3288 if ((rgbdata + dheight * i * rowstride) < end) {
3289 ccparams[i].src = rgbdata + dheight * i * rowstride;
3290 ccparams[i].hsize = hsize;
3291 ccparams[i].dest = u + dheight * i * orowstride / 4;
3292
3293 if (dheight * (i + 1) > (vsize - 4)) {
3294 dheight = vsize - (dheight * i);
3295 }
3296
3297 ccparams[i].vsize = dheight;
3298
3299 ccparams[i].irowstrides[0] = rowstride;
3300 ccparams[i].orowstrides[0] = orowstride;
3301 ccparams[i].in_alpha = has_alpha;
3302 ccparams[i].out_clamping = clamping;
3303 ccparams[i].lut = gamma_lut;
3304 ccparams[i].thread_id = i;
3305
3306 if (i == 0) convert_rgb_to_uyvy_frame_thread(&ccparams[i]);
3307 else {
3308 lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_rgb_to_uyvy_frame_thread, &ccparams[i]);
3309 nthreads++;
3310 }
3311 }
3312 }
3313
3314 for (i = 1; i < nthreads; i++) {
3315 lives_thread_join(threads[i], NULL);
3316 }
3317 lives_free(ccparams);
3318 if (gamma_lut) lives_gamma_lut_free(gamma_lut);
3319 return;
3320 }
3321
3322 if (has_alpha) {
3323 z++;
3324 y++;
3325 x++;
3326 ipsize = 4;
3327 }
3328
3329 ipsize2 = ipsize * 2;
3330 hs3 = hsize * ipsize;
3331 orowstride = orowstride / 2 - hsize;
3332 for (int k = 0; k < vsize; k++) {
3333 for (i = 0; i < hs3; i += ipsize2) {
3334 // convert 6 RGBRGB bytes to 4 UYVY bytes
3335 if (gamma_lut)
3336 rgb2uyvy_with_gamma(rgbdata[i], rgbdata[i + 1], rgbdata[i + 2], rgbdata[i + x], rgbdata[i + y],
3337 rgbdata[i + z], u++, gamma_lut);
3338 else
3339 rgb2uyvy(rgbdata[i], rgbdata[i + 1], rgbdata[i + 2], rgbdata[i + x], rgbdata[i + y], rgbdata[i + z], u++);
3340 }
3341 rgbdata += rowstride;
3342 u += orowstride;
3343 }
3344}
3345
3346
3347static 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
3357static 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) {
3373 int nthreads = 1;
3374 int dheight, xdheight;
3376
3377 xdheight = CEIL((double)vsize / (double)prefs->nfx_threads, 4);
3378 for (i = prefs->nfx_threads - 1; i >= 0; i--) {
3379 dheight = xdheight;
3380
3381 if ((rgbdata + dheight * i * rowstride) < end) {
3382 ccparams[i].src = rgbdata + dheight * i * rowstride;
3383 ccparams[i].hsize = hsize;
3384 ccparams[i].dest = u + dheight * i * orowstride / 4;
3385
3386 if (dheight * (i + 1) > (vsize - 4)) {
3387 dheight = vsize - (dheight * i);
3388 }
3389
3390 ccparams[i].vsize = dheight;
3391
3392 ccparams[i].irowstrides[0] = rowstride;
3393 ccparams[i].orowstrides[0] = orowstride;
3394 ccparams[i].in_alpha = has_alpha;
3395 ccparams[i].out_clamping = clamping;
3396 ccparams[i].lut = gamma_lut;
3397 ccparams[i].thread_id = i;
3398
3399 if (i == 0) convert_rgb_to_yuyv_frame_thread(&ccparams[i]);
3400 else {
3401 lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_rgb_to_yuyv_frame_thread, &ccparams[i]);
3402 nthreads++;
3403 }
3404 }
3405 }
3406
3407 for (i = 1; i < nthreads; i++) {
3408 lives_thread_join(threads[i], NULL);
3409 }
3410 lives_free(ccparams);
3411 if (gamma_lut) lives_gamma_lut_free(gamma_lut);
3412 return;
3413 }
3414
3415 if (has_alpha) {
3416 z++;
3417 y++;
3418 x++;
3419 ipsize = 4;
3420 }
3421
3422 ipsize2 = ipsize * 2;
3423 hs3 = hsize * ipsize;
3424 orowstride = orowstride / 2 - hsize;
3425
3426 for (; rgbdata < end; rgbdata += rowstride) {
3427 for (i = 0; i < hs3; i += ipsize2) {
3428 // convert 6 RGBRGB bytes to 4 YUYV bytes
3429 if (gamma_lut)
3430 rgb2yuyv_with_gamma(rgbdata[i], rgbdata[i + 1], rgbdata[i + 2], rgbdata[i + x], rgbdata[i + y],
3431 rgbdata[i + z], u++, gamma_lut);
3432 else
3433 rgb2yuyv(rgbdata[i], rgbdata[i + 1], rgbdata[i + 2], rgbdata[i + x], rgbdata[i + y], rgbdata[i + z], u++);
3434 }
3435 u += orowstride;
3436 }
3437}
3438
3439
3440static 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
3449static 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) {
3465 int nthreads = 1;
3466 int dheight, xdheight;
3468
3469 xdheight = CEIL((double)vsize / (double)prefs->nfx_threads, 4);
3470 for (i = prefs->nfx_threads - 1; i >= 0; i--) {
3471 dheight = xdheight;
3472
3473 if ((rgbdata + dheight * i * rowstride) < end) {
3474 ccparams[i].src = rgbdata + dheight * i * rowstride;
3475 ccparams[i].hsize = hsize;
3476 ccparams[i].dest = u + dheight * i * orowstride / 4;
3477
3478 if (dheight * (i + 1) > (vsize - 4)) {
3479 dheight = vsize - (dheight * i);
3480 }
3481
3482 ccparams[i].vsize = dheight;
3483
3484 ccparams[i].irowstrides[0] = rowstride;
3485 ccparams[i].orowstrides[0] = orowstride;
3486 ccparams[i].in_alpha = has_alpha;
3487 ccparams[i].out_clamping = clamping;
3488 ccparams[i].lut = gamma_lut;
3489 ccparams[i].thread_id = i;
3490
3491 if (i == 0) convert_bgr_to_uyvy_frame_thread(&ccparams[i]);
3492 else {
3493 lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_bgr_to_uyvy_frame_thread, &ccparams[i]);
3494 nthreads++;
3495 }
3496 }
3497 }
3498
3499 for (i = 1; i < nthreads; i++) {
3500 lives_thread_join(threads[i], NULL);
3501 }
3502 lives_free(ccparams);
3503 if (gamma_lut) lives_gamma_lut_free(gamma_lut);
3504 return;
3505 }
3506
3507 if (has_alpha) {
3508 z++;
3509 y++;
3510 x++;
3511 ipsize = 4;
3512 }
3513
3514 ipsize2 = ipsize * 2;
3515 hs3 = hsize * ipsize;
3516 orowstride = orowstride / 2 - hsize;
3517
3518 for (; rgbdata < end; rgbdata += rowstride) {
3519 for (i = 0; i < hs3; i += ipsize2) {
3520 //convert 6 RGBRGB bytes to 4 UYVY bytes
3521 if (gamma_lut)
3522 rgb2uyvy_with_gamma(rgbdata[i + 2], rgbdata[i + 1], rgbdata[i], rgbdata[i + z], rgbdata[i + y],
3523 rgbdata[i + x], u++, gamma_lut);
3524 else
3525 rgb2uyvy(rgbdata[i + 2], rgbdata[i + 1], rgbdata[i], rgbdata[i + z], rgbdata[i + y], rgbdata[i + x], u++);
3526 }
3527 u += orowstride;
3528 }
3529}
3530
3531
3532static 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
3541static 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) {
3559 int nthreads = 1;
3560 int dheight, xdheight;
3562
3563 xdheight = CEIL((double)vsize / (double)prefs->nfx_threads, 4);
3564 for (i = prefs->nfx_threads - 1; i >= 0; i--) {
3565 dheight = xdheight;
3566
3567 if ((rgbdata + dheight * i * rowstride) < end) {
3568 ccparams[i].src = rgbdata + dheight * i * rowstride;
3569 ccparams[i].hsize = hsize;
3570 ccparams[i].dest = u + dheight * i * orowstride / 4;
3571
3572 if (dheight * (i + 1) > (vsize - 4)) {
3573 dheight = vsize - (dheight * i);
3574 }
3575
3576 ccparams[i].vsize = dheight;
3577
3578 ccparams[i].irowstrides[0] = rowstride;
3579 ccparams[i].orowstrides[0] = orowstride;
3580 ccparams[i].in_alpha = has_alpha;
3581 ccparams[i].out_clamping = clamping;
3582 ccparams[i].lut = gamma_lut;
3583 ccparams[i].thread_id = i;
3584
3585 if (i == 0) convert_bgr_to_yuyv_frame_thread(&ccparams[i]);
3586 else {
3587 lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_bgr_to_yuyv_frame_thread, &ccparams[i]);
3588 nthreads++;
3589 }
3590 }
3591 }
3592
3593 for (i = 1; i < nthreads; i++) {
3594 lives_thread_join(threads[i], NULL);
3595 }
3596 lives_free(ccparams);
3597 if (gamma_lut) lives_gamma_lut_free(gamma_lut);
3598 return;
3599 }
3600
3601 if (has_alpha) {
3602 z++;
3603 y++;
3604 x++;
3605 ipsize = 4;
3606 }
3607
3608 ipsize2 = ipsize * 2;
3609 hs3 = hsize * ipsize;
3610 orowstride = orowstride / 2 - hsize;
3611
3612 for (; rgbdata < end; rgbdata += rowstride) {
3613 for (i = 0; i < hs3; i += ipsize2) {
3614 // convert 6 RGBRGB bytes to 4 UYVY bytes
3615 if (gamma_lut)
3616 rgb2yuyv_with_gamma(rgbdata[i + 2], rgbdata[i + 1], rgbdata[i], rgbdata[i + z], rgbdata[i + y],
3617 rgbdata[i + x], u++, gamma_lut);
3618 else
3619 rgb2yuyv(rgbdata[i + 2], rgbdata[i + 1], rgbdata[i], rgbdata[i + z], rgbdata[i + y], rgbdata[i + x], u++);
3620 }
3621 u += orowstride;
3622 }
3623}
3624
3625
3626static 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
3635static 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) {
3651 int nthreads = 1;
3652 int dheight, xdheight;
3654
3655 xdheight = CEIL((double)vsize / (double)prefs->nfx_threads, 4);
3656 for (i = prefs->nfx_threads - 1; i >= 0; i--) {
3657 dheight = xdheight;
3658
3659 if ((rgbdata + dheight * i * rowstride) < end) {
3660 ccparams[i].src = rgbdata + dheight * i * rowstride;
3661 ccparams[i].hsize = hsize;
3662 ccparams[i].dest = u + dheight * i * orowstride / 4;
3663
3664 if (dheight * (i + 1) > (vsize - 4)) {
3665 dheight = vsize - (dheight * i);
3666 }
3667
3668 ccparams[i].vsize = dheight;
3669
3670 ccparams[i].irowstrides[0] = rowstride;
3671 ccparams[i].orowstrides[0] = orowstride;
3672 ccparams[i].out_clamping = clamping;
3673 ccparams[i].lut = gamma_lut;
3674 ccparams[i].thread_id = i;
3675
3676 if (i == 0) convert_argb_to_uyvy_frame_thread(&ccparams[i]);
3677 else {
3678 lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_argb_to_uyvy_frame_thread, &ccparams[i]);
3679 nthreads++;
3680 }
3681 }
3682 }
3683
3684 for (i = 1; i < nthreads; i++) {
3685 lives_thread_join(threads[i], NULL);
3686 }
3687 lives_free(ccparams);
3688 if (gamma_lut) lives_gamma_lut_free(gamma_lut);
3689 return;
3690 }
3691
3692 ipsize2 = ipsize * 2;
3693 hs3 = hsize * ipsize;
3694 orowstride = orowstride / 2 - hsize;
3695
3696 for (; rgbdata < end; rgbdata += rowstride) {
3697 for (i = 0; i < hs3; i += ipsize2) {
3698 // convert 6 RGBRGB bytes to 4 UYVY bytes
3699 if (gamma_lut)
3700 rgb2uyvy_with_gamma(rgbdata[i + 1], rgbdata[i + 2], rgbdata[i + 3], rgbdata[i + 5], rgbdata[i + 6],
3701 rgbdata[i + 7], u++, gamma_lut);
3702 else
3703 rgb2uyvy(rgbdata[i + 1], rgbdata[i + 2], rgbdata[i + 3], rgbdata[i + 5], rgbdata[i + 6], rgbdata[i + 7], u++);
3704 }
3705 u += orowstride;
3706 }
3707}
3708
3709
3710static 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
3719static 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) {
3735 int nthreads = 1;
3736 int dheight, xdheight;
3738
3739 xdheight = CEIL((double)vsize / (double)prefs->nfx_threads, 4);
3740 for (i = prefs->nfx_threads - 1; i >= 0; i--) {
3741 dheight = xdheight;
3742
3743 if ((rgbdata + dheight * i * rowstride) < end) {
3744 ccparams[i].src = rgbdata + dheight * i * rowstride;
3745 ccparams[i].hsize = hsize;
3746 ccparams[i].dest = u + dheight * i * orowstride / 4;
3747
3748 if (dheight * (i + 1) > (vsize - 4)) {
3749 dheight = vsize - (dheight * i);
3750 }
3751
3752 ccparams[i].vsize = dheight;
3753
3754 ccparams[i].irowstrides[0] = rowstride;
3755 ccparams[i].orowstrides[0] = orowstride;
3756 ccparams[i].out_clamping = clamping;
3757 ccparams[i].lut = gamma_lut;
3758 ccparams[i].thread_id = i;
3759
3760 if (i == 0) convert_argb_to_yuyv_frame_thread(&ccparams[i]);
3761 else {
3762 lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_argb_to_yuyv_frame_thread, &ccparams[i]);
3763 nthreads++;
3764 }
3765 }
3766 }
3767
3768 for (i = 1; i < nthreads; i++) {
3769 lives_thread_join(threads[i], NULL);
3770 }
3771 lives_free(ccparams);
3772 if (gamma_lut) lives_gamma_lut_free(gamma_lut);
3773 return;
3774 }
3775
3776 ipsize2 = ipsize * 2;
3777 hs3 = hsize * ipsize;
3778 orowstride = orowstride / 2 - hsize;
3779 for (; rgbdata < end; rgbdata += rowstride) {
3780 for (i = 0; i < hs3; i += ipsize2) {
3781 // convert 6 RGBRGB bytes to 4 UYVY bytes
3782 if (gamma_lut)
3783 rgb2yuyv_with_gamma(rgbdata[i + 1], rgbdata[i + 2], rgbdata[i + 3], rgbdata[i + 5], rgbdata[i + 6],
3784 rgbdata[i + 7], u++, gamma_lut);
3785 else
3786 rgb2yuyv(rgbdata[i + 1], rgbdata[i + 2], rgbdata[i + 3], rgbdata[i + 5], rgbdata[i + 6], rgbdata[i + 7], u++);
3787 }
3788 u += orowstride;
3789 }
3790}
3791
3792
3793static 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
3802static 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) {
3816 int nthreads = 1;
3817 int dheight, xdheight;
3819
3820 xdheight = CEIL((double)vsize / (double)prefs->nfx_threads, 4);
3821 for (i = prefs->nfx_threads - 1; i >= 0; i--) {
3822 dheight = xdheight;
3823
3824 if ((rgbdata + dheight * i * rowstride) < end) {
3825 ccparams[i].src = rgbdata + dheight * i * rowstride;
3826 ccparams[i].hsize = hsize;
3827 ccparams[i].dest = u + dheight * i * orow;
3828
3829 if (dheight * (i + 1) > (vsize - 4)) {
3830 dheight = vsize - (dheight * i);
3831 }
3832
3833 ccparams[i].vsize = dheight;
3834
3835 ccparams[i].irowstrides[0] = rowstride;
3836 ccparams[i].orowstrides[0] = orow;
3837 ccparams[i].in_alpha = in_has_alpha;
3838 ccparams[i].out_alpha = out_has_alpha;
3839 ccparams[i].out_clamping = clamping;
3840 ccparams[i].thread_id = i;
3841
3842 if (i == 0) convert_rgb_to_yuv_frame_thread(&ccparams[i]);
3843 else {
3844 lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_rgb_to_yuv_frame_thread, &ccparams[i]);
3845 nthreads++;
3846 }
3847 }
3848 }
3849
3850 for (i = 1; i < nthreads; i++) {
3851 lives_thread_join(threads[i], NULL);
3852 }
3853 lives_free(ccparams);
3854 return;
3855 }
3856
3857 if (in_has_alpha) ipsize = 4;
3858 if (out_has_alpha) opsize = 4;
3859
3860 hsize = (hsize >> 1) << 1;
3861 iwidth = hsize * ipsize;
3862 orow -= hsize * opsize;
3863
3864 for (; rgbdata < end; rgbdata += rowstride) {
3865 for (i = 0; i < iwidth; i += ipsize) {
3866 if (in_has_alpha) in_alpha = rgbdata[i + 3];
3867 if (out_has_alpha) u[3] = in_alpha;
3868 rgb2yuv(rgbdata[i], rgbdata[i + 1], rgbdata[i + 2], &(u[0]), &(u[1]), &(u[2]));
3869 u += opsize;
3870 }
3871 u += orow;
3872 }
3873}
3874
3875
3876static 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
3886static 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) {
3907 int nthreads = 1;
3908 int dheight, xdheight;
3910
3911 xdheight = CEIL((double)vsize / (double)prefs->nfx_threads, 4);
3912 for (i = prefs->nfx_threads - 1; i >= 0; i--) {
3913 dheight = xdheight;
3914
3915 if ((rgbdata + dheight * i * rowstride) < end) {
3916 ccparams[i].src = rgbdata + dheight * i * rowstride;
3917 ccparams[i].hsize = hsize;
3918
3919 ccparams[i].destp[0] = y + dheight * i * orow;
3920 ccparams[i].destp[1] = u + dheight * i * orow;
3921 ccparams[i].destp[2] = v + dheight * i * orow;
3922 if (out_has_alpha) ccparams[i].destp[3] = a + dheight * i * orow;
3923
3924 if (dheight * (i + 1) > (vsize - 4)) {
3925 dheight = vsize - (dheight * i);
3926 }
3927
3928 ccparams[i].vsize = dheight;
3929
3930 ccparams[i].irowstrides[0] = rowstride;
3931 ccparams[i].orowstrides[0] = orow;
3932 ccparams[i].in_alpha = in_has_alpha;
3933 ccparams[i].out_alpha = out_has_alpha;
3934 ccparams[i].out_clamping = clamping;
3935 ccparams[i].thread_id = i;
3936
3937 if (i == 0) convert_rgb_to_yuvp_frame_thread(&ccparams[i]);
3938 else {
3939 lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_rgb_to_yuvp_frame_thread, &ccparams[i]);
3940 nthreads++;
3941 }
3942 }
3943 }
3944
3945 for (i = 1; i < nthreads; i++) {
3946 lives_thread_join(threads[i], NULL);
3947 }
3948 lives_free(ccparams);
3949 return;
3950 }
3951
3952 if (in_has_alpha) ipsize = 4;
3953
3954 hsize = (hsize >> 1) << 1;
3955 iwidth = hsize * ipsize;
3956 orow -= hsize;
3957
3958 for (; rgbdata < end; rgbdata += rowstride) {
3959 for (i = 0; i < iwidth; i += ipsize) {
3960 if (in_has_alpha) in_alpha = rgbdata[i + 3];
3961 if (out_has_alpha) *(a++) = in_alpha;
3962 rgb2yuv(rgbdata[i], rgbdata[i + 1], rgbdata[i + 2], y, u, v);
3963 y++;
3964 u++;
3965 v++;
3966 }
3967 y += orow;
3968 u += orow;
3969 v += orow;
3970 if (out_has_alpha) a += orow;
3971 }
3972}
3973
3974
3975static 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
3985static 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) {
3999 int nthreads = 1;
4000 int dheight, xdheight;
4002
4003 xdheight = CEIL((double)vsize / (double)prefs->nfx_threads, 4);
4004 for (i = prefs->nfx_threads - 1; i >= 0; i--) {
4005 dheight = xdheight;
4006
4007 if ((rgbdata + dheight * i * rowstride) < end) {
4008 ccparams[i].src = rgbdata + dheight * i * rowstride;
4009 ccparams[i].hsize = hsize;
4010 ccparams[i].dest = u + dheight * i * orow;
4011
4012 if (dheight * (i + 1) > (vsize - 4)) {
4013 dheight = vsize - (dheight * i);
4014 }
4015
4016 ccparams[i].vsize = dheight;
4017
4018 ccparams[i].irowstrides[0] = rowstride;
4019 ccparams[i].in_alpha = in_has_alpha;
4020 ccparams[i].out_alpha = out_has_alpha;
4021 ccparams[i].out_clamping = clamping;
4022 ccparams[i].thread_id = i;
4023
4024 if (i == 0) convert_bgr_to_yuv_frame_thread(&ccparams[i]);
4025 else {
4026 lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_bgr_to_yuv_frame_thread, &ccparams[i]);
4027 nthreads++;
4028 }
4029 }
4030 }
4031
4032 for (i = 1; i < nthreads; i++) {
4033 lives_thread_join(threads[i], NULL);
4034 }
4035 lives_free(ccparams);
4036 return;
4037 }
4038
4039 if (in_has_alpha) ipsize = 4;
4040 if (out_has_alpha) opsize = 4;
4041
4042 hsize = (hsize >> 1) << 1;
4043 iwidth = hsize * ipsize;
4044 orow -= hsize * opsize;
4045
4046 for (; rgbdata < end; rgbdata += rowstride) {
4047 for (i = 0; i < iwidth; i += ipsize) {
4048 bgr2yuv(rgbdata[i], rgbdata[i + 1], rgbdata[i + 2], &(u[0]), &(u[1]), &(u[2]));
4049 if (in_has_alpha) in_alpha = rgbdata[i + 3];
4050 if (out_has_alpha) u[3] = in_alpha;
4051 u += opsize;
4052 }
4053 u += orow;
4054 }
4055}
4056
4057
4058static 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
4067static 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) {
4090 int nthreads = 1;
4091 int dheight, xdheight;
4093
4094 xdheight = CEIL((double)vsize / (double)prefs->nfx_threads, 4);
4095 for (i = prefs->nfx_threads - 1; i >= 0; i--) {
4096 dheight = xdheight;
4097
4098 if ((rgbdata + dheight * i * rowstride) < end) {
4099 ccparams[i].src = rgbdata + dheight * i * rowstride;
4100 ccparams[i].hsize = hsize;
4101
4102 ccparams[i].destp[0] = y + dheight * i * orow;
4103 ccparams[i].destp[1] = u + dheight * i * orow;
4104 ccparams[i].destp[2] = v + dheight * i * orow;
4105 if (out_has_alpha) ccparams[i].destp[3] = a + dheight * i * orow;
4106
4107 if (dheight * (i + 1) > (vsize - 4)) {
4108 dheight = vsize - (dheight * i);
4109 }
4110
4111 ccparams[i].vsize = dheight;
4112
4113 ccparams[i].irowstrides[0] = rowstride;
4114 ccparams[i].orowstrides[0] = orow;
4115 ccparams[i].in_alpha = in_has_alpha;
4116 ccparams[i].out_alpha = out_has_alpha;
4117 ccparams[i].out_clamping = clamping;
4118 ccparams[i].thread_id = i;
4119
4120 if (i == 0) convert_bgr_to_yuvp_frame_thread(&ccparams[i]);
4121 else {
4122 lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_bgr_to_yuvp_frame_thread, &ccparams[i]);
4123 nthreads++;
4124 }
4125 }
4126 }
4127
4128 for (i = 1; i < nthreads; i++) {
4129 lives_thread_join(threads[i], NULL);
4130 }
4131 lives_free(ccparams);
4132 return;
4133 }
4134
4135 if (in_has_alpha) ipsize = 4;
4136
4137 hsize = (hsize >> 1) << 1;
4138 iwidth = hsize * ipsize;
4139 orow -= hsize;
4140
4141 for (; rgbdata < end; rgbdata += rowstride) {
4142 for (i = 0; i < iwidth; i += ipsize) {
4143 bgr2yuv(rgbdata[i], rgbdata[i + 1], rgbdata[i + 2], &(y[0]), &(u[0]), &(v[0]));
4144 if (in_has_alpha) in_alpha = rgbdata[i + 3];
4145 if (out_has_alpha) *(a++) = in_alpha;
4146 y++;
4147 u++;
4148 v++;
4149 }
4150 y += orow;
4151 u += orow;
4152 v += orow;
4153 if (out_has_alpha) a += orow;
4154 }
4155}
4156
4157
4158static 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
4168static 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) {
4181 int nthreads = 1;
4182 int dheight, xdheight;
4184
4185 xdheight = CEIL((double)vsize / (double)prefs->nfx_threads, 4);
4186 for (i = prefs->nfx_threads - 1; i >= 0; i--) {
4187 dheight = xdheight;
4188
4189 if ((rgbdata + dheight * i * rowstride) < end) {
4190 ccparams[i].src = rgbdata + dheight * i * rowstride;
4191 ccparams[i].hsize = hsize;
4192
4193 ccparams[i].dest = u + dheight * i * orow;
4194
4195 if (dheight * (i + 1) > (vsize - 4)) {
4196 dheight = vsize - (dheight * i);
4197 }
4198
4199 ccparams[i].vsize = dheight;
4200
4201 ccparams[i].irowstrides[0] = rowstride;
4202 ccparams[i].orowstrides[0] = orow;
4203 ccparams[i].out_alpha = out_has_alpha;
4204 ccparams[i].out_clamping = clamping;
4205 ccparams[i].thread_id = i;
4206
4207 if (i == 0) convert_rgb_to_yuv_frame_thread(&ccparams[i]);
4208 else {
4209 lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_argb_to_yuv_frame_thread, &ccparams[i]);
4210 nthreads++;
4211 }
4212 }
4213 }
4214
4215 for (i = 1; i < nthreads; i++) {
4216 lives_thread_join(threads[i], NULL);
4217 }
4218 lives_free(ccparams);
4219 return;
4220 }
4221
4222 if (out_has_alpha) opsize = 4;
4223
4224 hsize = (hsize >> 1) << 1;
4225 iwidth = hsize * ipsize;
4226 orow -= hsize * opsize;
4227
4228 for (; rgbdata < end; rgbdata += rowstride) {
4229 for (i = 0; i < iwidth; i += ipsize) {
4230 if (out_has_alpha) u[3] = rgbdata[i];
4231 rgb2yuv(rgbdata[i + 1], rgbdata[i + 2], rgbdata[i + 3], &(u[0]), &(u[1]), &(u[2]));
4232 u += opsize;
4233 }
4234 u += orow;
4235 }
4236}
4237
4238
4239static 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
4248static 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) {
4268 int nthreads = 1;
4269 int dheight, xdheight;
4271
4272 xdheight = CEIL((double)vsize / (double)prefs->nfx_threads, 4);
4273 for (i = prefs->nfx_threads - 1; i >= 0; i--) {
4274 dheight = xdheight;
4275
4276 if ((rgbdata + dheight * i * rowstride) < end) {
4277 ccparams[i].src = rgbdata + dheight * i * rowstride;
4278 ccparams[i].hsize = hsize;
4279
4280 ccparams[i].destp[0] = y + dheight * i * orow;
4281 ccparams[i].destp[1] = u + dheight * i * orow;
4282 ccparams[i].destp[2] = v + dheight * i * orow;
4283 if (out_has_alpha) ccparams[i].destp[3] = a + dheight * i * orow;
4284
4285 if (dheight * (i + 1) > (vsize - 4)) {
4286 dheight = vsize - (dheight * i);
4287 }
4288
4289 ccparams[i].vsize = dheight;
4290
4291 ccparams[i].irowstrides[0] = rowstride;
4292 ccparams[i].orowstrides[0] = orow;
4293 ccparams[i].out_alpha = out_has_alpha;
4294 ccparams[i].out_clamping = clamping;
4295 ccparams[i].thread_id = i;
4296
4297 if (i == 0) convert_argb_to_yuvp_frame_thread(&ccparams[i]);
4298 else {
4299 lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_argb_to_yuvp_frame_thread, &ccparams[i]);
4300 nthreads++;
4301 }
4302 }
4303 }
4304
4305 for (i = 1; i < nthreads; i++) {
4306 lives_thread_join(threads[i], NULL);
4307 }
4308 lives_free(ccparams);
4309 return;
4310 }
4311
4312 hsize = (hsize >> 1) << 1;
4313 iwidth = hsize * ipsize;
4314 orow -= hsize;
4315
4316 for (; rgbdata < end; rgbdata += rowstride) {
4317 for (i = 0; i < iwidth; i += ipsize) {
4318 if (out_has_alpha) *(a++) = rgbdata[i];
4319 rgb2yuv(rgbdata[i + 1], rgbdata[i + 2], rgbdata[i + 3], y, u, v);
4320 y++;
4321 u++;
4322 v++;
4323 }
4324 y += orow;
4325 u += orow;
4326 v += orow;
4327 if (out_has_alpha) a += orow;
4328 }
4329}
4330
4331
4332static 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
4342static 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;
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
4415static 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;
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
4477static 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;
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
4534static 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
4561static 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
4589static 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
4632static 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
4675static 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
4706static 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) {
4718 int nthreads = 1;
4719 int dheight, xdheight;
4721
4722 xdheight = CEIL((double)height / (double)prefs->nfx_threads, 4);
4723 for (i = prefs->nfx_threads - 1; i >= 0; i--) {
4724 dheight = xdheight;
4725
4726 if ((dheight * i) < height) {
4727 ccparams[i].src = src + dheight * i * irow / 4;
4728 ccparams[i].hsize = width;
4729 ccparams[i].dest = dest + dheight * i * orowstride;
4730
4731 if (dheight * (i + 1) > (height - 4)) {
4732 dheight = height - (dheight * i);
4733 }
4734
4735 ccparams[i].vsize = dheight;
4736
4737 ccparams[i].irowstrides[0] = irow;
4738 ccparams[i].orowstrides[0] = orowstride;
4739 ccparams[i].out_alpha = add_alpha;
4740 ccparams[i].in_clamping = clamping;
4741 ccparams[i].in_subspace = subspace;
4742 ccparams[i].thread_id = i;
4743
4744 if (i == 0) convert_uyvy_to_rgb_frame_thread(&ccparams[i]);
4745 else {
4746 lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_uyvy_to_rgb_frame_thread, &ccparams[i]);
4747 nthreads++;
4748 }
4749 }
4750 }
4751
4752 for (i = 1; i < nthreads; i++) {
4753 lives_thread_join(threads[i], NULL);
4754 }
4755 lives_free(ccparams);
4756 return;
4757 }
4758
4759 if (add_alpha) {
4760 psize = 8;
4761 a = 4;
4762 b = 5;
4763 c = 6;
4764 }
4765
4766 orowstride -= width * psize;
4767 irow = irow / 4 - width;
4768 for (i = 0; i < height; i++) {
4769 for (j = 0; j < width; j++) {
4770 uyvy2rgb(src, &dest[0], &dest[1], &dest[2], &dest[a], &dest[b], &dest[c]);
4771 if (add_alpha) dest[3] = dest[7] = 255;
4772 dest += psize;
4773 src++;
4774 }
4775 src += irow;
4776 dest += orowstride;
4777 }
4778}
4779
4780
4781static 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
4791static 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) {
4804 int nthreads = 1;
4805 int dheight, xdheight;
4807
4808 xdheight = CEIL((double)height / (double)prefs->nfx_threads, 4);
4809 for (i = prefs->nfx_threads - 1; i >= 0; i--) {
4810 dheight = xdheight;
4811
4812 if ((dheight * i) < height) {
4813 ccparams[i].src = src + dheight * i * irow / 4;
4814 ccparams[i].hsize = width;
4815 ccparams[i].dest = dest + dheight * i * orowstride;
4816
4817 if (dheight * (i + 1) > (height - 4)) {
4818 dheight = height - (dheight * i);
4819 }
4820
4821 ccparams[i].vsize = dheight;
4822
4823 ccparams[i].irowstrides[0] = irow;
4824 ccparams[i].orowstrides[0] = orowstride;
4825 ccparams[i].out_alpha = add_alpha;
4826 ccparams[i].in_clamping = clamping;
4827 ccparams[i].thread_id = i;
4828
4829 if (i == 0) convert_uyvy_to_bgr_frame_thread(&ccparams[i]);
4830 else {
4831 lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_uyvy_to_bgr_frame_thread, &ccparams[i]);
4832 nthreads++;
4833 }
4834 }
4835 }
4836
4837 for (i = 1; i < nthreads; i++) {
4838 lives_thread_join(threads[i], NULL);
4839 }
4840 lives_free(ccparams);
4841 return;
4842 }
4843
4844 if (add_alpha) {
4845 psize = 8;
4846 a = 4;
4847 b = 5;
4848 c = 6;
4849 }
4850
4851 orowstride -= width * psize;
4852 irow = irow / 4 - width;
4853 for (i = 0; i < height; i++) {
4854 for (j = 0; j < width; j++) {
4855 uyvy2rgb(src, &dest[2], &dest[1], &dest[0], &dest[c], &dest[b], &dest[a]);
4856 if (add_alpha) dest[3] = dest[7] = 255;
4857 dest += psize;
4858 src++;
4859 }
4860 src += irow;
4861 dest += orowstride;
4862 }
4863}
4864
4865
4866static 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
4875static 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) {
4886 int nthreads = 1;
4887 int dheight, xdheight;
4889
4890 xdheight = CEIL((double)height / (double)prefs->nfx_threads, 4);
4891 for (i = prefs->nfx_threads - 1; i >= 0; i--) {
4892 dheight = xdheight;
4893
4894 if ((dheight * i) < height) {
4895 ccparams[i].src = src + dheight * i * irow / 4;
4896 ccparams[i].hsize = width;
4897 ccparams[i].dest = dest + dheight * i * orowstride;
4898
4899 if (dheight * (i + 1) > (height - 4)) {
4900 dheight = height - (dheight * i);
4901 }
4902
4903 ccparams[i].vsize = dheight;
4904
4905 ccparams[i].irowstrides[0] = irow;
4906 ccparams[i].orowstrides[0] = orowstride;
4907 ccparams[i].in_clamping = clamping;
4908 ccparams[i].thread_id = i;
4909
4910 if (i == 0) convert_uyvy_to_argb_frame_thread(&ccparams[i]);
4911 else {
4912 lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_uyvy_to_argb_frame_thread, &ccparams[i]);
4913 nthreads++;
4914 }
4915 }
4916 }
4917
4918 for (i = 1; i < nthreads; i++) {
4919 lives_thread_join(threads[i], NULL);
4920 }
4921 lives_free(ccparams);
4922 return;
4923 }
4924
4925 orowstride -= width * psize;
4926 irow = irow / 4 - width;
4927 for (i = 0; i < height; i++) {
4928 for (j = 0; j < width; j++) {
4929 uyvy2rgb(src, &dest[1], &dest[2], &dest[3], &dest[5], &dest[6], &dest[7]);
4930 dest[0] = dest[4] = 255;
4931 dest += psize;
4932 src++;
4933 }
4934 src += irow;
4935 dest += orowstride;
4936 }
4937}
4938
4939
4940static 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
4949static 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) {
4961 int nthreads = 1;
4962 int dheight, xdheight;
4964
4965 xdheight = CEIL((double)height / (double)prefs->nfx_threads, 4);
4966 for (i = prefs->nfx_threads - 1; i >= 0; i--) {
4967 dheight = xdheight;
4968
4969 if ((dheight * i) < height) {
4970 ccparams[i].src = src + dheight * i * irow / 4;
4971 ccparams[i].hsize = width;
4972 ccparams[i].dest = dest + dheight * i * orowstride;
4973
4974 if (dheight * (i + 1) > (height - 4)) {
4975 dheight = height - (dheight * i);
4976 }
4977
4978 ccparams[i].vsize = dheight;
4979 ccparams[i].irowstrides[0] = irow;
4980 ccparams[i].orowstrides[0] = orowstride;
4981 ccparams[i].out_alpha = add_alpha;
4982 ccparams[i].in_clamping = clamping;
4983 ccparams[i].thread_id = i;
4984
4985 if (i == 0) convert_yuyv_to_rgb_frame_thread(&ccparams[i]);
4986 else {
4987 lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_yuyv_to_rgb_frame_thread, &ccparams[i]);
4988 nthreads++;
4989 }
4990 }
4991 }
4992
4993 for (i = 1; i < nthreads; i++) {
4994 lives_thread_join(threads[i], NULL);
4995 }
4996 lives_free(ccparams);
4997 return;
4998 }
4999
5000 if (add_alpha) {
5001 psize = 8;
5002 a = 4;
5003 b = 5;
5004 c = 6;
5005 }
5006
5007 orowstride -= width * psize;
5008 irow = irow / 4 - width;
5009 for (i = 0; i < height; i++) {
5010 for (j = 0; j < width; j++) {
5011 yuyv2rgb(src, &dest[0], &dest[1], &dest[2], &dest[a], &dest[b], &dest[c]);
5012 if (add_alpha) dest[3] = dest[7] = 255;
5013 dest += psize;
5014 src++;
5015 }
5016 src += irow;
5017 dest += orowstride;
5018 }
5019}
5020
5021
5022static 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
5031static 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) {
5043 int nthreads = 1;
5044 int dheight, xdheight;
5046
5047 xdheight = CEIL((double)height / (double)prefs->nfx_threads, 4);
5048 for (i = prefs->nfx_threads - 1; i >= 0; i--) {
5049 dheight = xdheight;
5050
5051 if ((dheight * i) < height) {
5052 ccparams[i].src = src + dheight * i * irow / 4;
5053 ccparams[i].hsize = width;
5054 ccparams[i].dest = dest + dheight * i * orowstride;
5055
5056 if (dheight * (i + 1) > (height - 4)) {
5057 dheight = height - (dheight * i);
5058 }
5059
5060 ccparams[i].vsize = dheight;
5061
5062 ccparams[i].irowstrides[0] = irow;
5063 ccparams[i].orowstrides[0] = orowstride;
5064 ccparams[i].out_alpha = add_alpha;
5065 ccparams[i].in_clamping = clamping;
5066 ccparams[i].thread_id = i;
5067
5068 if (i == 0) convert_yuyv_to_bgr_frame_thread(&ccparams[i]);
5069 else {
5070 lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_yuyv_to_bgr_frame_thread, &ccparams[i]);
5071 nthreads++;
5072 }
5073 }
5074 }
5075
5076 for (i = 1; i < nthreads; i++) {
5077 lives_thread_join(threads[i], NULL);
5078 }
5079 lives_free(ccparams);
5080 return;
5081 }
5082
5083 if (add_alpha) {
5084 psize = 8;
5085 a = 4;
5086 b = 5;
5087 c = 6;
5088 }
5089
5090 orowstride -= width * psize;
5091 irow = irow / 4 - width;
5092 for (i = 0; i < height; i++) {
5093 for (j = 0; j < width; j++) {
5094 yuyv2rgb(src, &dest[2], &dest[1], &dest[0], &dest[c], &dest[b], &dest[a]);
5095 if (add_alpha) dest[3] = dest[7] = 255;
5096 dest += psize;
5097 src++;
5098 }
5099 src += irow;
5100 dest += orowstride;
5101 }
5102}
5103
5104
5105static 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
5114static 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) {
5125 int nthreads = 1;
5126 int dheight, xdheight;
5128
5129 xdheight = CEIL((double)height / (double)prefs->nfx_threads, 4);
5130 for (i = prefs->nfx_threads - 1; i >= 0; i--) {
5131 dheight = xdheight;
5132
5133 if ((dheight * i) < height) {
5134 ccparams[i].src = src + dheight * i * irow / 4;
5135 ccparams[i].hsize = width;
5136 ccparams[i].dest = dest + dheight * i * orowstride;
5137
5138 if (dheight * (i + 1) > (height - 4)) {
5139 dheight = height - (dheight * i);
5140 }
5141
5142 ccparams[i].vsize = dheight;
5143
5144 ccparams[i].irowstrides[0] = irow;
5145 ccparams[i].orowstrides[0] = orowstride;
5146 ccparams[i].in_clamping = clamping;
5147 ccparams[i].thread_id = i;
5148
5149 if (i == 0) convert_yuyv_to_argb_frame_thread(&ccparams[i]);
5150 else {
5151 lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_yuyv_to_argb_frame_thread, &ccparams[i]);
5152 nthreads++;
5153 }
5154 }
5155 }
5156
5157 for (i = 1; i < nthreads; i++) {
5158 lives_thread_join(threads[i], NULL);
5159 }
5160 lives_free(ccparams);
5161 return;
5162 }
5163
5164 orowstride -= width * psize;
5165 irow = irow / 4 - width;
5166 for (i = 0; i < height; i++) {
5167 for (j = 0; j < width; j++) {
5168 yuyv2rgb(src, &dest[1], &dest[2], &dest[3], &dest[5], &dest[6], &dest[7]);
5169 dest[0] = dest[4] = 255;
5170 dest += psize;
5171 src++;
5172 }
5173 src += irow;
5174 dest += orowstride;
5175 }
5176}
5177
5178
5179static 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
5188static 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
5236static 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
5283static 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) {
5303 int nthreads = 1;
5304 int dheight, xdheight;
5306
5307 xdheight = CEIL((double)height / (double)prefs->nfx_threads, 4);
5308 for (i = prefs->nfx_threads - 1; i >= 0; i--) {
5309 dheight = xdheight;
5310
5311 if ((y + dheight * i * irowstride) < end) {
5312 ccparams[i].hsize = width;
5313
5314 ccparams[i].srcp[0] = y + dheight * i * irowstride;
5315 ccparams[i].srcp[1] = u + dheight * i * irowstride;
5316 ccparams[i].srcp[2] = v + dheight * i * irowstride;
5317 if (in_alpha) ccparams[i].srcp[3] = a + dheight * i * irowstride;
5318
5319 ccparams[i].dest = dest + dheight * i * orowstride;
5320
5321 if (dheight * (i + 1) > (height - 4)) {
5322 dheight = height - (dheight * i);
5323 }
5324
5325 ccparams[i].vsize = dheight;
5326
5327 ccparams[i].irowstrides[0] = irowstride;
5328 ccparams[i].orowstrides[0] = orowstride;
5329 ccparams[i].in_alpha = in_alpha;
5330 ccparams[i].out_alpha = out_alpha;
5331 ccparams[i].out_clamping = clamping;
5332 ccparams[i].thread_id = i;
5333
5334 if (i == 0) convert_yuv_planar_to_rgb_frame_thread(&ccparams[i]);
5335 else {
5336 lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_yuv_planar_to_rgb_frame_thread, &ccparams[i]);
5337 nthreads++;
5338 }
5339 }
5340 }
5341
5342 for (i = 1; i < nthreads; i++) {
5343 lives_thread_join(threads[i], NULL);
5344 }
5345 lives_free(ccparams);
5346 return;
5347 }
5348
5349 if (out_alpha) opstep = 4;
5350
5351 orowstride -= width * opstep;
5352 irowstride -= width;
5353
5354 for (i = 0; i < height; i++) {
5355 for (j = 0; j < width; j++) {
5356 yuv2rgb(*(y++), *(u++), *(v++), &dest[0], &dest[1], &dest[2]);
5357 if (out_alpha) {
5358 if (in_alpha) {
5359 dest[3] = *(a++);
5360 } else dest[3] = 255;
5361 }
5362 dest += opstep;
5363 }
5364 dest += orowstride;
5365 y += irowstride;
5366 u += irowstride;
5367 v += irowstride;
5368 if (a) a += irowstride;
5369 }
5370}
5371
5372
5373static 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
5383static 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) {
5403 int nthreads = 1;
5404 int dheight, xdheight;
5406
5407 xdheight = CEIL((double)height / (double)prefs->nfx_threads, 4);
5408
5409 for (i = prefs->nfx_threads - 1; i >= 0; i--) {
5410 dheight = xdheight;
5411
5412 if ((y + dheight * i * irowstride) < end) {
5413 ccparams[i].hsize = width;
5414
5415 ccparams[i].srcp[0] = y + dheight * i * irowstride;
5416 ccparams[i].srcp[1] = u + dheight * i * irowstride;
5417 ccparams[i].srcp[2] = v + dheight * i * irowstride;
5418 if (in_alpha) ccparams[i].srcp[3] = a + dheight * i * irowstride;
5419
5420 ccparams[i].dest = dest + dheight * i * orowstride;
5421
5422 if (dheight * (i + 1) > (height - 4)) {
5423 dheight = height - (dheight * i);
5424 }
5425
5426 ccparams[i].vsize = dheight;
5427
5428 ccparams[i].irowstrides[0] = irowstride;
5429 ccparams[i].orowstrides[0] = orowstride;
5430 ccparams[i].in_alpha = in_alpha;
5431 ccparams[i].out_alpha = out_alpha;
5432 ccparams[i].out_clamping = clamping;
5433 ccparams[i].thread_id = i;
5434
5435 if (i == 0) convert_yuv_planar_to_bgr_frame_thread(&ccparams[i]);
5436 else {
5437 lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_yuv_planar_to_bgr_frame_thread, &ccparams[i]);
5438 nthreads++;
5439 }
5440 }
5441 }
5442
5443 for (i = 1; i < nthreads; i++) {
5444 lives_thread_join(threads[i], NULL);
5445 }
5446 lives_free(ccparams);
5447 return;
5448 }
5449
5450 orowstride -= width * opstep;
5451 irowstride -= width;
5452
5453 for (i = 0; i < height; i++) {
5454 for (j = 0; j < width; j++) {
5455 yuv2bgr(*(y++), *(u++), *(v++), &dest[0], &dest[1], &dest[2]);
5456 if (out_alpha) {
5457 if (in_alpha) {
5458 dest[3] = *(a++);
5459 } else dest[3] = 255;
5460 }
5461 dest += opstep;
5462 }
5463 dest += orowstride;
5464 y += irowstride;
5465 u += irowstride;
5466 v += irowstride;
5467 if (a) a += irowstride;
5468 }
5469}
5470
5471
5472static 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
5482static 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) {
5501 int nthreads = 1;
5502 int dheight, xdheight;
5504
5505 xdheight = CEIL((double)height / (double)prefs->nfx_threads, 4);
5506 for (i = prefs->nfx_threads - 1; i >= 0; i--) {
5507 dheight = xdheight;
5508
5509 if ((y + dheight * i * irowstride) < end) {
5510 ccparams[i].hsize = width;
5511
5512 ccparams[i].srcp[0] = y + dheight * i * irowstride;
5513 ccparams[i].srcp[1] = u + dheight * i * irowstride;
5514 ccparams[i].srcp[2] = v + dheight * i * irowstride;
5515 if (in_alpha) ccparams[i].srcp[3] = a + dheight * i * irowstride;
5516
5517 ccparams[i].dest = dest + dheight * i * orowstride;
5518
5519 if (dheight * (i + 1) > (height - 4)) {
5520 dheight = height - (dheight * i);
5521 }
5522
5523 ccparams[i].vsize = dheight;
5524
5525 ccparams[i].irowstrides[0] = irowstride;
5526 ccparams[i].orowstrides[0] = orowstride;
5527 ccparams[i].in_alpha = in_alpha;
5528 ccparams[i].out_clamping = clamping;
5529 ccparams[i].thread_id = i;
5530
5531 if (i == 0) convert_yuv_planar_to_argb_frame_thread(&ccparams[i]);
5532 else {
5533 lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_yuv_planar_to_argb_frame_thread, &ccparams[i]);
5534 nthreads++;
5535 }
5536 }
5537 }
5538
5539 for (i = 1; i < nthreads; i++) {
5540 lives_thread_join(threads[i], NULL);
5541 }
5542 lives_free(ccparams);
5543 return;
5544 }
5545
5546 orowstride -= width * opstep;
5547 orowstride -= width;
5548
5549 for (i = 0; i < height; i++) {
5550 for (j = 0; j < width; j++) {
5551 yuv2rgb(*(y++), *(u++), *(v++), &dest[1], &dest[2], &dest[3]);
5552 if (in_alpha) {
5553 dest[0] = *(a++);
5554 } else dest[0] = 255;
5555 dest += opstep;
5556 }
5557 dest += orowstride;
5558 y += irowstride;
5559 u += irowstride;
5560 v += irowstride;
5561 if (a) a += irowstride;
5562 }
5563}
5564
5565
5566static 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
5575static 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
5622static 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
5666static 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
5716static 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
5755static 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
5761static 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
5825static 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
5870static 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
5892static 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
5914static 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
5935static 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
5956static 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
5998static 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
6040static 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
6070static 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
6102static 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
6162static 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
6180static 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
6198static 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
6253static 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
6297static 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
6341static 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
6374static 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
6482static 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
6591static 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
6691static 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
6808static 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
6911static 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
6981static 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
7051static 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
7107static 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
7216static 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
7266static void convert_splitplanes_frame(uint8_t *src, int width, int height, int irowstride, int *orowstrides,
7267 uint8_t **dest, boolean src_alpha, boolean dest_alpha) {
7268 // TODO - orowstrides
7269 // convert 888(8) packed to 444(4)P planar
7270 size_t size = width * height;
7271 int ipsize = 3;
7272
7273 uint8_t *y = dest[0];
7274 uint8_t *u = dest[1];
7275 uint8_t *v = dest[2];
7276 uint8_t *a = dest_alpha ? dest[3] : NULL;
7277
7278 uint8_t *end;
7279
7280 register int i, j;
7281
7282 if (src_alpha) ipsize = 4;
7283
7284 if (irowstride == ipsize * width && irowstride == orowstrides[0] && irowstride == orowstrides[1]
7285 && irowstride == orowstrides[2] && (!dest_alpha || irowstride == orowstrides[3])) {
7286 for (end = src + size * ipsize; src < end;) {
7287 *(y++) = *(src++);
7288 *(u++) = *(src++);
7289 *(v++) = *(src++);
7290 if (dest_alpha) {
7291 if (src_alpha) *(a++) = *(src++);
7292 else *(a++) = 255;
7293 }
7294 }
7295 } else {
7296 orowstrides[0] -= width;
7297 orowstrides[1] -= width;
7298 orowstrides[2] -= width;
7299 width *= ipsize;
7300 irowstride -= width;
7301 if (dest_alpha) orowstrides[3] -= width;
7302 for (i = 0; i < height; i++) {
7303 for (j = 0; j < width; j += ipsize) {
7304 *(y++) = *(src++);
7305 *(u++) = *(src++);
7306 *(v++) = *(src++);
7307 if (dest_alpha) {
7308 if (src_alpha) *(a++) = *(src++);
7309 else *(a++) = 255;
7310 }
7311 }
7312 y += orowstrides[0];
7313 u += orowstrides[1];
7314 v += orowstrides[2];
7315 if (dest_alpha) {
7316 a += orowstrides[3];
7317 }
7318 src += irowstride;
7319 }
7320 }
7321}
7322
7323
7325// RGB palette conversions
7326
7327static 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) {
7335 int nthreads = 1;
7336 int dheight, xdheight;
7338
7339 xdheight = CEIL((double)height / (double)prefs->nfx_threads, 4);
7340 for (i = prefs->nfx_threads - 1; i >= 0; i--) {
7341 dheight = xdheight;
7342
7343 if ((src + dheight * i * irowstride) < end) {
7344 ccparams[i].src = src + dheight * i * irowstride;
7345 ccparams[i].hsize = width;
7346 ccparams[i].dest = dest + dheight * i * orowstride;
7347
7348 if (dheight * (i + 1) > (height - 4)) {
7349 dheight = height - (dheight * i);
7350 }
7351
7352 ccparams[i].vsize = dheight;
7353
7354 ccparams[i].irowstrides[0] = irowstride;
7355 ccparams[i].orowstrides[0] = orowstride;
7356 ccparams[i].lut = gamma_lut;
7357 ccparams[i].thread_id = i;
7358
7359 if (i == 0) convert_swap3_frame_thread(&ccparams[i]);
7360 else {
7361 lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_swap3_frame_thread, &ccparams[i]);
7362 nthreads++;
7363 }
7364 }
7365 }
7366
7367 for (i = 1; i < nthreads; i++) {
7368 lives_thread_join(threads[i], NULL);
7369 }
7370 lives_free(ccparams);
7371 if (gamma_lut) lives_gamma_lut_free(gamma_lut);
7372 return;
7373 }
7374
7375 if (src == dest) {
7376 uint8_t tmp;
7377 int width3 = width * 3;
7378 orowstride -= width3;
7379 for (; src < end; src += irowstride) {
7380 for (i = 0; i < width3; i += 3) {
7381 tmp = src[i];
7382 if (!gamma_lut) {
7383 dest[0] = src[i + 2]; // red
7384 dest[2] = tmp; // blue
7385 } else {
7386 dest[0] = gamma_lut[src[i + 2]]; // red
7387 dest[1] = gamma_lut[src[i + 1]]; // red
7388 dest[2] = gamma_lut[tmp]; // blue
7389 }
7390 dest += 3;
7391 }
7392 dest += orowstride;
7393 }
7394 return;
7395 }
7396
7397 if ((irowstride == width * 3) && (orowstride == irowstride)) {
7398 // quick version
7399#ifdef ENABLE_OIL
7400 if (!gamma_lut) {
7401 oil_rgb2bgr(dest, src, width * height);
7402 return;
7403 }
7404#endif
7405 for (; src < end; src += 3) {
7406 if (!gamma_lut) {
7407 *(dest++) = src[2]; // red
7408 *(dest++) = src[1]; // green
7409 *(dest++) = src[0]; // blue
7410 } else {
7411 *(dest++) = gamma_lut[src[2]]; // red
7412 *(dest++) = gamma_lut[src[1]]; // green
7413 *(dest++) = gamma_lut[src[0]]; // blue
7414 }
7415 }
7416 } else {
7417 int width3 = width * 3;
7418 orowstride -= width3;
7419 for (; src < end; src += irowstride) {
7420 for (i = 0; i < width3; i += 3) {
7421 if (!gamma_lut) {
7422 *(dest++) = src[i + 2]; // red
7423 *(dest++) = src[i + 1]; // green
7424 *(dest++) = src[i]; // blue
7425 } else {
7426 *(dest++) = gamma_lut[src[2]]; // red
7427 *(dest++) = gamma_lut[src[1]]; // green
7428 *(dest++) = gamma_lut[src[0]]; // blue
7429 }
7430 }
7431 dest += orowstride;
7432 }
7433 }
7434}
7435
7436
7437static 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
7445static 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) {
7453 int nthreads = 1;
7454 int dheight, xdheight;
7456
7457 xdheight = CEIL((double)height / (double)prefs->nfx_threads, 4);
7458 for (i = prefs->nfx_threads - 1; i >= 0; i--) {
7459 dheight = xdheight;
7460
7461 if ((src + dheight * i * irowstride) < end) {
7462 ccparams[i].src = src + dheight * i * irowstride;
7463 ccparams[i].hsize = width;
7464 ccparams[i].dest = dest + dheight * i * orowstride;
7465
7466 if ((height - dheight * i) < dheight) dheight = height - (dheight * i);
7467
7468 ccparams[i].vsize = dheight;
7469
7470 ccparams[i].irowstrides[0] = irowstride;
7471 ccparams[i].orowstrides[0] = orowstride;
7472 ccparams[i].thread_id = i;
7473
7474 if (i == 0) convert_swap4_frame_thread(&ccparams[i]);
7475 else {
7476 lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_swap4_frame_thread, &ccparams[i]);
7477 nthreads++;
7478 }
7479 }
7480 }
7481
7482 for (i = 1; i < nthreads; i++) {
7483 lives_thread_join(threads[i], NULL);
7484 }
7485 lives_free(ccparams);
7486 return;
7487 }
7488
7489 if (src == dest) {
7490 uint8_t tmp[4];
7491 int width4 = width * 4;
7492 orowstride -= width4;
7493 for (; src < end; src += irowstride) {
7494 for (i = 0; i < width4; i += 4) {
7495 tmp[0] = src[i + 3]; // alpha
7496 tmp[1] = src[i + 2]; // red
7497 tmp[2] = src[i + 1]; // green
7498 tmp[3] = src[i]; // blue
7499 lives_memcpy(dest, tmp, 4);
7500 dest += 4;
7501 }
7502 dest += orowstride;
7503 }
7504 return;
7505 }
7506
7507 if ((irowstride == width * 4) && (orowstride == irowstride)) {
7508 // quick version
7509 for (; src < end; src += 4) {
7510 *(dest++) = src[3]; // alpha
7511 *(dest++) = src[2]; // red
7512 *(dest++) = src[1]; // green
7513 *(dest++) = src[0]; // blue
7514 }
7515 } else {
7516 int width4 = width * 4;
7517 orowstride -= width4;
7518 for (; src < end; src += irowstride) {
7519 for (i = 0; i < width4; i += 4) {
7520 *(dest++) = src[i + 3]; // alpha
7521 *(dest++) = src[i + 2]; // red
7522 *(dest++) = src[i + 1]; // green
7523 *(dest++) = src[i]; // blue
7524 }
7525 dest += orowstride;
7526 }
7527 }
7528}
7529
7530
7531static 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
7539static 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) {
7547 int nthreads = 1;
7548 int dheight, xdheight;
7550
7551 xdheight = CEIL((double)height / (double)prefs->nfx_threads, 4);
7552 for (i = prefs->nfx_threads - 1; i >= 0; i--) {
7553 dheight = xdheight;
7554
7555 if ((src + dheight * i * irowstride) < end) {
7556 ccparams[i].src = src + dheight * i * irowstride;
7557 ccparams[i].hsize = width;
7558 ccparams[i].dest = dest + dheight * i * orowstride;
7559
7560 if (dheight * (i + 1) > (height - 4)) {
7561 dheight = height - (dheight * i);
7562 }
7563
7564 ccparams[i].vsize = dheight;
7565
7566 ccparams[i].irowstrides[0] = irowstride;
7567 ccparams[i].orowstrides[0] = orowstride;
7568 ccparams[i].thread_id = i;
7569
7570 if (i == 0) convert_swap3addpost_frame_thread(&ccparams[i]);
7571 else {
7572 lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_swap3addpost_frame_thread, &ccparams[i]);
7573 nthreads++;
7574 }
7575 }
7576 }
7577
7578 for (i = 1; i < nthreads; i++) {
7579 lives_thread_join(threads[i], NULL);
7580 }
7581 lives_free(ccparams);
7582 return;
7583 }
7584
7585 if ((irowstride == width * 3) && (orowstride == width * 4)) {
7586 // quick version
7587 for (; src < end; src += 3) {
7588 *(dest++) = src[2]; // red
7589 *(dest++) = src[1]; // green
7590 *(dest++) = src[0]; // blue
7591 *(dest++) = 255; // alpha
7592 }
7593 } else {
7594 int width3 = width * 3;
7595 orowstride -= width * 4;
7596 for (; src < end; src += irowstride) {
7597 for (i = 0; i < width3; i += 3) {
7598 *(dest++) = src[i + 2]; // red
7599 *(dest++) = src[i + 1]; // green
7600 *(dest++) = src[i]; // blue
7601 *(dest++) = 255; // alpha
7602 }
7603 dest += orowstride;
7604 }
7605 }
7606}
7607
7608
7609static 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
7617static 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) {
7625 int nthreads = 1;
7626 int dheight, xdheight;
7628
7629 xdheight = CEIL((double)height / (double)prefs->nfx_threads, 4);
7630 for (i = prefs->nfx_threads - 1; i >= 0; i--) {
7631 dheight = xdheight;
7632
7633 if ((src + dheight * i * irowstride) < end) {
7634 ccparams[i].src = src + dheight * i * irowstride;
7635 ccparams[i].hsize = width;
7636 ccparams[i].dest = dest + dheight * i * orowstride;
7637
7638 if (dheight * (i + 1) > (height - 4)) {
7639 dheight = height - (dheight * i);
7640 }
7641
7642 ccparams[i].vsize = dheight;
7643
7644 ccparams[i].irowstrides[0] = irowstride;
7645 ccparams[i].orowstrides[0] = orowstride;
7646 ccparams[i].thread_id = i;
7647
7648 if (i == 0) convert_swap3addpre_frame_thread(&ccparams[i]);
7649 else {
7650 lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_swap3addpre_frame_thread, &ccparams[i]);
7651 nthreads++;
7652 }
7653 }
7654 }
7655
7656 for (i = 1; i < nthreads; i++) {
7657 lives_thread_join(threads[i], NULL);
7658 }
7659 lives_free(ccparams);
7660 return;
7661 }
7662 if ((irowstride == width * 3) && (orowstride == width * 4)) {
7663 // quick version
7664 for (; src < end; src += 3) {
7665 *(dest++) = 255; // alpha
7666 *(dest++) = src[2]; // red
7667 *(dest++) = src[1]; // green
7668 *(dest++) = src[0]; // blue
7669 }
7670 } else {
7671 int width3 = width * 3;
7672 orowstride -= width * 4;
7673 for (; src < end; src += irowstride) {
7674 for (i = 0; i < width3; i += 3) {
7675 *(dest++) = 255; // alpha
7676 *(dest++) = src[i + 2]; // red
7677 *(dest++) = src[i + 1]; // green
7678 *(dest++) = src[i]; // blue
7679 }
7680 dest += orowstride;
7681 }
7682 }
7683}
7684
7685
7686static 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
7694static 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) {
7702 int nthreads = 1;
7703 int dheight, xdheight;
7705
7706 xdheight = CEIL((double)height / (double)prefs->nfx_threads, 4);
7707 for (i = prefs->nfx_threads - 1; i >= 0; i--) {
7708 dheight = xdheight;
7709
7710 if ((src + dheight * i * rowstride) < end) {
7711 ccparams[i].src = src + dheight * i * rowstride;
7712 ccparams[i].hsize = width;
7713
7714 if (dheight * (i + 1) > (height - 4)) {
7715 dheight = height - (dheight * i);
7716 }
7717
7718 ccparams[i].vsize = dheight;
7719
7720 ccparams[i].irowstrides[0] = rowstride;
7721 ccparams[i].thread_id = i;
7722
7723 if (i == 0) convert_swap3postalpha_frame_thread(&ccparams[i]);
7724 else {
7725 lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_swap3postalpha_frame_thread, &ccparams[i]);
7726 nthreads++;
7727 }
7728 }
7729 }
7730
7731 for (i = 1; i < nthreads; i++) {
7732 lives_thread_join(threads[i], NULL);
7733 }
7734 lives_free(ccparams);
7735 return;
7736 }
7737
7738 rowstride -= width << 2;
7739 for (; src < end; src += rowstride) {
7740 for (i = 0; i < width; i++) {
7741 tmp = src[0];
7742 src[0] = src[2];
7743 src[2] = tmp;
7744 src += 4;
7745 }
7746 }
7747}
7748
7749
7750static 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
7758static 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) {
7766 int nthreads = 1;
7767 int dheight, xdheight;
7769
7770 xdheight = CEIL((double)height / (double)prefs->nfx_threads, 4);
7771 for (i = prefs->nfx_threads - 1; i >= 0; i--) {
7772 dheight = xdheight;
7773
7774 if ((src + dheight * i * rowstride) < end) {
7775 ccparams[i].src = src + dheight * i * rowstride;
7776 ccparams[i].hsize = width;
7777
7778 if (dheight * (i + 1) > (height - 4)) {
7779 dheight = height - (dheight * i);
7780 }
7781
7782 ccparams[i].vsize = dheight;
7783
7784 ccparams[i].irowstrides[0] = rowstride;
7785 ccparams[i].thread_id = i;
7786
7787 if (i == 0) convert_swap3prealpha_frame_thread(&ccparams[i]);
7788 else {
7789 lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_swap3prealpha_frame_thread, &ccparams[i]);
7790 nthreads++;
7791 }
7792 }
7793 }
7794
7795 for (i = 1; i < nthreads; i++) {
7796 lives_thread_join(threads[i], NULL);
7797 }
7798 lives_free(ccparams);
7799 return;
7800 }
7801
7802 rowstride -= width << 2;
7803
7804 for (; src < end; src += rowstride) {
7805 for (i = 0; i < width; i++) {
7806 tmp = src[1];
7807 src[1] = src[3];
7808 src[3] = tmp;
7809 src += 4;
7810 }
7811 }
7812}
7813
7814
7815static 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
7823static 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) {
7831 int nthreads = 1;
7832 int dheight, xdheight;
7834
7835 xdheight = CEIL((double)height / (double)prefs->nfx_threads, 4);
7836 for (i = prefs->nfx_threads - 1; i >= 0; i--) {
7837 dheight = xdheight;
7838
7839 if ((src + dheight * i * irowstride) < end) {
7840 ccparams[i].src = src + dheight * i * irowstride;
7841 ccparams[i].hsize = width;
7842 ccparams[i].dest = dest + dheight * i * orowstride;
7843
7844 if (dheight * (i + 1) > (height - 4)) {
7845 dheight = height - (dheight * i);
7846 }
7847
7848 ccparams[i].vsize = dheight;
7849
7850 ccparams[i].irowstrides[0] = irowstride;
7851 ccparams[i].orowstrides[0] = orowstride;
7852 ccparams[i].lut = gamma_lut;
7853 ccparams[i].thread_id = i;
7854
7855 if (i == 0) convert_addpost_frame_thread(&ccparams[i]);
7856 else {
7857 lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_addpost_frame_thread, &ccparams[i]);
7858 nthreads++;
7859 }
7860 }
7861 }
7862
7863 for (i = 1; i < nthreads; i++) {
7864 lives_thread_join(threads[i], NULL);
7865 }
7866 lives_free(ccparams);
7867 if (gamma_lut) lives_gamma_lut_free(gamma_lut);
7868 return;
7869 }
7870
7871 if ((irowstride == width * 3) && (orowstride == width * 4)) {
7872 // quick version
7873#ifdef ENABLE_OIL
7874 if (!gamma_lut) {
7875 oil_rgb2rgba(dest, src, width * height);
7876 return;
7877 }
7878#endif
7879 for (; src < end; src += 3) {
7880 if (!gamma_lut) {
7881 lives_memcpy(dest, src, 3);
7882 dest += 3;
7883 } else {
7884 *(dest++) = gamma_lut[src[0]];
7885 *(dest++) = gamma_lut[src[1]];
7886 *(dest++) = gamma_lut[src[2]];
7887 }
7888 *(dest++) = 255; // alpha
7889 }
7890 } else {
7891 int width3 = width * 3;
7892 orowstride -= width * 4;
7893 for (; src < end; src += irowstride) {
7894 for (i = 0; i < width3; i += 3) {
7895 if (!gamma_lut) {
7896 lives_memcpy(dest, src + i, 3);
7897 dest += 3;
7898 } else {
7899 *(dest++) = gamma_lut[src[i]];
7900 *(dest++) = gamma_lut[src[i + 1]];
7901 *(dest++) = gamma_lut[src[i + 2]];
7902 }
7903 *(dest++) = 255; // alpha
7904 }
7905 dest += orowstride;
7906 }
7907 }
7908}
7909
7910
7911static 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
7919static 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) {
7927 int nthreads = 1;
7928 int dheight, xdheight;
7930
7931 xdheight = CEIL((double)height / (double)prefs->nfx_threads, 4);
7932 for (i = prefs->nfx_threads - 1; i >= 0; i--) {
7933 dheight = xdheight;
7934
7935 if ((src + dheight * i * irowstride) < end) {
7936 ccparams[i].src = src + dheight * i * irowstride;
7937 ccparams[i].hsize = width;
7938 ccparams[i].dest = dest + dheight * i * orowstride;
7939
7940 if (dheight * (i + 1) > (height - 4)) {
7941 dheight = height - (dheight * i);
7942 }
7943
7944 ccparams[i].vsize = dheight;
7945
7946 ccparams[i].irowstrides[0] = irowstride;
7947 ccparams[i].orowstrides[0] = orowstride;
7948 ccparams[i].thread_id = i;
7949
7950 if (i == 0) convert_addpre_frame_thread(&ccparams[i]);
7951 else {
7952 lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_addpre_frame_thread, &ccparams[i]);
7953 nthreads++;
7954 }
7955 }
7956 }
7957
7958 for (i = 1; i < nthreads; i++) {
7959 lives_thread_join(threads[i], NULL);
7960 }
7961 lives_free(ccparams);
7962 return;
7963 }
7964
7965 if ((irowstride == width * 3) && (orowstride == width * 4)) {
7966 // quick version
7967 for (; src < end; src += 3) {
7968 *(dest++) = 255; // alpha
7969 lives_memcpy(dest, src, 3);
7970 dest += 3;
7971 }
7972 } else {
7973 int width3 = width * 3;
7974 orowstride -= width * 4;
7975 for (; src < end; src += irowstride) {
7976 for (i = 0; i < width3; i += 3) {
7977 *(dest++) = 255; // alpha
7978 lives_memcpy(dest, src + i, 3);
7979 dest += 3;
7980 }
7981 dest += orowstride;
7982 }
7983 }
7984}
7985
7986
7987static 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
7995static 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) {
8003 int nthreads = 1;
8004 int dheight, xdheight;
8006
8007 xdheight = CEIL((double)height / (double)prefs->nfx_threads, 4);
8008 for (i = prefs->nfx_threads - 1; i >= 0; i--) {
8009 dheight = xdheight;
8010
8011 if ((src + dheight * i * irowstride) < end) {
8012 ccparams[i].src = src + dheight * i * irowstride;
8013 ccparams[i].hsize = width;
8014 ccparams[i].dest = dest + dheight * i * orowstride;
8015
8016 if (dheight * (i + 1) > (height - 4)) {
8017 dheight = height - (dheight * i);
8018 }
8019
8020 ccparams[i].vsize = dheight;
8021
8022 ccparams[i].irowstrides[0] = irowstride;
8023 ccparams[i].orowstrides[0] = orowstride;
8024 ccparams[i].thread_id = i;
8025
8026 if (i == 0) convert_swap3delpost_frame_thread(&ccparams[i]);
8027 else {
8028 lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_swap3delpost_frame_thread, &ccparams[i]);
8029 nthreads++;
8030 }
8031 }
8032 }
8033
8034 for (i = 1; i < nthreads; i++) {
8035 lives_thread_join(threads[i], NULL);
8036 }
8037 lives_free(ccparams);
8038 return;
8039 }
8040
8041 if ((irowstride == width * 4) && (orowstride == width * 3)) {
8042 // quick version
8043 for (; src < end; src += 4) {
8044 *(dest++) = src[2]; // red
8045 *(dest++) = src[1]; // green
8046 *(dest++) = src[0]; // blue
8047 }
8048 } else {
8049 int width4 = width * 4;
8050 orowstride -= width * 3;
8051 for (; src < end; src += irowstride) {
8052 for (i = 0; i < width4; i += 4) {
8053 *(dest++) = src[i + 2]; // red
8054 *(dest++) = src[i + 1]; // green
8055 *(dest++) = src[i]; // blue
8056 }
8057 dest += orowstride;
8058 }
8059 }
8060}
8061
8062
8063static 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
8071static 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) {
8079 int nthreads = 1;
8080 int dheight, xdheight;
8082
8083 xdheight = CEIL((double)height / (double)prefs->nfx_threads, 4);
8084 for (i = prefs->nfx_threads - 1; i >= 0; i--) {
8085 dheight = xdheight;
8086
8087 if ((src + dheight * i * irowstride) < end) {
8088 ccparams[i].src = src + dheight * i * irowstride;
8089 ccparams[i].hsize = width;
8090 ccparams[i].dest = dest + dheight * i * orowstride;
8091
8092 if (dheight * (i + 1) > (height - 4)) {
8093 dheight = height - (dheight * i);
8094 }
8095
8096 ccparams[i].vsize = dheight;
8097
8098 ccparams[i].irowstrides[0] = irowstride;
8099 ccparams[i].orowstrides[0] = orowstride;
8100 ccparams[i].lut = gamma_lut;
8101 ccparams[i].thread_id = i;
8102
8103 if (i == 0) convert_delpost_frame_thread(&ccparams[i]);
8104 else {
8105 lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_delpost_frame_thread, &ccparams[i]);
8106 nthreads++;
8107 }
8108 }
8109 }
8110
8111 for (i = 1; i < nthreads; i++) {
8112 lives_thread_join(threads[i], NULL);
8113 }
8114 lives_free(ccparams);
8115 if (gamma_lut) lives_gamma_lut_free(gamma_lut);
8116 return;
8117 }
8118
8119 if ((irowstride == width * 4) && (orowstride == width * 3)) {
8120 // quick version
8121 for (; src < end; src += 4) {
8122 if (!gamma_lut) {
8123 lives_memcpy(dest, src, 3);
8124 dest += 3;
8125 } else {
8126 *(dest++) = gamma_lut[src[0]];
8127 *(dest++) = gamma_lut[src[1]];
8128 *(dest++) = gamma_lut[src[2]];
8129 }
8130 }
8131 } else {
8132 int width4 = width * 4;
8133 orowstride -= width * 3;
8134 for (; src < end; src += irowstride) {
8135 for (i = 0; i < width4; i += 4) {
8136 if (!gamma_lut) {
8137 lives_memcpy(dest, src + i, 3);
8138 dest += 3;
8139 } else {
8140 *(dest++) = gamma_lut[src[i]];
8141 *(dest++) = gamma_lut[src[i + 1]];
8142 *(dest++) = gamma_lut[src[i + 2]];
8143 }
8144 }
8145 dest += orowstride;
8146 }
8147 }
8148}
8149
8150
8151static 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
8159static 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) {
8167 int nthreads = 1;
8168 int dheight, xdheight;
8170
8171 xdheight = CEIL((double)height / (double)prefs->nfx_threads, 4);
8172 for (i = prefs->nfx_threads - 1; i >= 0; i--) {
8173 dheight = xdheight;
8174
8175 if ((src + dheight * i * irowstride) < end) {
8176 ccparams[i].src = src + dheight * i * irowstride;
8177 ccparams[i].hsize = width;
8178 ccparams[i].dest = dest + dheight * i * orowstride;
8179
8180 if (dheight * (i + 1) > (height - 4)) {
8181 dheight = height - (dheight * i);
8182 }
8183
8184 ccparams[i].vsize = dheight;
8185
8186 ccparams[i].irowstrides[0] = irowstride;
8187 ccparams[i].orowstrides[0] = orowstride;
8188 ccparams[i].thread_id = i;
8189
8190 if (i == 0) convert_delpre_frame_thread(&ccparams[i]);
8191 else {
8192 lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_delpre_frame_thread, &ccparams[i]);
8193 nthreads++;
8194 }
8195 }
8196 }
8197
8198 for (i = 1; i < nthreads; i++) {
8199 lives_thread_join(threads[i], NULL);
8200 }
8201 lives_free(ccparams);
8202 return;
8203 }
8204
8205 src++;
8206
8207 if ((irowstride == width * 4) && (orowstride == width * 3)) {
8208 // quick version
8209 for (; src < end; src += 4) {
8210 lives_memcpy(dest, src, 3);
8211 dest += 3;
8212 }
8213 } else {
8214 int width4 = width * 4;
8215 orowstride -= width * 3;
8216 for (; src < end; src += irowstride) {
8217 for (i = 0; i < width4; i += 4) {
8218 lives_memcpy(dest, src + i, 3);
8219 dest += 3;
8220 }
8221 dest += orowstride;
8222 }
8223 }
8224}
8225
8226
8227static 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
8235static 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) {
8243 int nthreads = 1;
8244 int dheight, xdheight;
8246
8247 xdheight = CEIL((double)height / (double)prefs->nfx_threads, 4);
8248 for (i = prefs->nfx_threads - 1; i >= 0; i--) {
8249 dheight = xdheight;
8250
8251 if ((src + dheight * i * irowstride) < end) {
8252 ccparams[i].src = src + dheight * i * irowstride;
8253 ccparams[i].hsize = width;
8254 ccparams[i].dest = dest + dheight * i * orowstride;
8255
8256 if (dheight * (i + 1) > (height - 4)) {
8257 dheight = height - (dheight * i);
8258 }
8259
8260 ccparams[i].vsize = dheight;
8261
8262 ccparams[i].irowstrides[0] = irowstride;
8263 ccparams[i].orowstrides[0] = orowstride;
8264 ccparams[i].thread_id = i;
8265
8266 if (i == 0) convert_swap3delpre_frame_thread(&ccparams[i]);
8267 else {
8268 lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_swap3delpre_frame_thread, &ccparams[i]);
8269 nthreads++;
8270 }
8271 }
8272 }
8273
8274 for (i = 1; i < nthreads; i++) {
8275 lives_thread_join(threads[i], NULL);
8276 }
8277 lives_free(ccparams);
8278 return;
8279 }
8280
8281 if ((irowstride == width * 4) && (orowstride == width * 3)) {
8282 // quick version
8283 for (; src < end; src += 4) {
8284 *(dest++) = src[3]; // red
8285 *(dest++) = src[2]; // green
8286 *(dest++) = src[1]; // blue
8287 }
8288 } else {
8289 int width4 = width * 4;
8290 orowstride -= width * 3;
8291 for (; src < end; src += irowstride) {
8292 for (i = 0; i < width4; i += 4) {
8293 *(dest++) = src[i + 3]; // red
8294 *(dest++) = src[i + 2]; // green
8295 *(dest++) = src[i + 1]; // blue
8296 }
8297 dest += orowstride;
8298 }
8299 }
8300}
8301
8302
8303static 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
8311static 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) {
8320 int nthreads = 1;
8321 int dheight, xdheight;
8323
8324 xdheight = CEIL((double)height / (double)prefs->nfx_threads, 4);
8325 for (i = prefs->nfx_threads - 1; i >= 0; i--) {
8326 dheight = xdheight;
8327
8328 if ((src + dheight * i * irowstride) < end) {
8329 ccparams[i].src = src + dheight * i * irowstride;
8330 ccparams[i].hsize = width;
8331 ccparams[i].dest = dest + dheight * i * orowstride;
8332
8333 if (dheight * (i + 1) > (height - 4)) {
8334 dheight = height - (dheight * i);
8335 }
8336
8337 ccparams[i].vsize = dheight;
8338
8339 ccparams[i].irowstrides[0] = irowstride;
8340 ccparams[i].orowstrides[0] = orowstride;
8341 ccparams[i].thread_id = i;
8342
8343 if (i == 0) convert_swapprepost_frame_thread(&ccparams[i]);
8344 else {
8345 lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_swapprepost_frame_thread, &ccparams[i]);
8346 nthreads++;
8347 }
8348 }
8349 }
8350
8351 for (i = 1; i < nthreads; i++) {
8352 lives_thread_join(threads[i], NULL);
8353 }
8354 lives_free(ccparams);
8355 return;
8356 }
8357
8358 uup = (uint64_t *)src;
8359 if ((void *)uup == (void *)src) {
8360 uint64_t uu;
8361 int width8 = width >> 3;
8362 orowstride -= width * 4;
8363 for (; src < end; src += irowstride) {
8364 for (i = 0; i < width8; i++) {
8365 uu = ((*uup & 0xFF000000FF000000) >> 24);
8366 uu |= ((*uup & 0x00FFFFFF00FFFFFF) << 8);
8367 lives_memcpy(dest, &uu, 8);
8368 dest += 8;
8369 uup++;
8370 }
8371 dest += orowstride;
8372 }
8373 return;
8374 }
8375
8376 if (src == dest) {
8377 uint8_t tmp;
8378 int width4 = width << 2;
8379 orowstride -= width4;
8380 for (; src < end; src += irowstride) {
8381 for (i = 0; i < width4; i += 4) {
8382 tmp = dest[i];
8383 lives_memmove(&dest[i], &dest[i + 1], 3);
8384 dest[i + 3] = tmp;
8385 }
8386 dest += orowstride;
8387 }
8388 return;
8389 } else {
8390 uint8_t tmp;
8391 int width4 = width << 2;
8392 orowstride -= width4;
8393 for (; src < end; src += irowstride) {
8394 for (i = 0; i < width4; i += 4) {
8395 tmp = src[i];
8396 lives_memcpy(&dest[i], &src[i + 1], 3);
8397 dest[i + 3] = tmp;
8398 }
8399 dest += orowstride;
8400 }
8401 }
8402}
8403
8404
8405static void *convert_swapprepost_frame_thread(void *data) {
8406 lives_cc_params *ccparams = (lives_cc_params *)data;
8407 convert_swapprepost_frame((uint8_t *)ccparams->src, ccparams->hsize, ccparams->vsize, ccparams->irowstrides[0],
8408 ccparams->orowstrides[0], (uint8_t *)ccparams->dest, ccparams->thread_id);
8409 return NULL;
8410}
8411
8412
8414// genric YUV
8415
8416static 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) {
8423 int nthreads = 1;
8424 int dheight, xdheight;
8426
8427 xdheight = CEIL((double)height / (double)prefs->nfx_threads, 4);
8428 for (i = prefs->nfx_threads - 1; i >= 0; i--) {
8429 dheight = xdheight;
8430
8431 if ((src + dheight * i * width4) < end) {
8432 ccparams[i].src = src + dheight * i * irow;
8433 ccparams[i].hsize = width;
8434 ccparams[i].dest = dest + dheight * i * orow;
8435
8436 if (dheight * (i + 1) > (height - 4)) {
8437 dheight = height - (dheight * i);
8438 }
8439
8440 ccparams[i].vsize = dheight;
8441 ccparams[i].irowstrides[0] = irow;
8442 ccparams[i].orowstrides[0] = orow;
8443
8444 ccparams[i].thread_id = i;
8445
8446 if (i == 0) convert_swab_frame_thread(&ccparams[i]);
8447 else {
8448 lives_thread_create(&threads[i], LIVES_THRDATTR_NONE, convert_swab_frame_thread, &ccparams[i]);
8449 nthreads++;
8450 }
8451 }
8452 }
8453
8454 for (i = 1; i < nthreads; i++) {
8455 lives_thread_join(threads[i], NULL);
8456 }
8457 lives_free(ccparams);
8458 return;
8459 }
8460
8461 for (; src < end; src += irow) {
8462 for (i = 0; i < width4; i += 4) {
8463 swab4(&src[i], &dest[i], 1);
8464 }
8465 dest += orow;
8466 }
8467}
8468
8469
8470static 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
8479static 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
8517static 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
8552static 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
8624static 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
8720static 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
8784static 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
8837static void switch_yuv_clamping_and_subspace(weed_layer_t *layer, int oclamping, int osubspace) {
8838 // currently subspace conversions are not performed - TODO
8839 // we assume subspace Y'CbCr
8840 int iclamping = weed_get_int_value(layer, WEED_LEAF_YUV_CLAMPING, NULL);
8841 int isubspace = weed_get_int_value(layer, WEED_LEAF_YUV_SUBSPACE, NULL);
8842
8843 int palette = weed_get_int_value(layer, WEED_LEAF_CURRENT_PALETTE, NULL);
8844 int height = weed_get_int_value(layer, WEED_LEAF_HEIGHT, NULL);
8845 int rowstride = weed_layer_get_rowstride(layer);
8846 void **pixel_data = weed_get_voidptr_array(layer, WEED_LEAF_PIXEL_DATA, NULL);
8847
8848 uint8_t *src, *src1, *src2, *end;
8849
8850 get_YUV_to_YUV_conversion_arrays(iclamping, isubspace, oclamping, osubspace);
8851
8852 switch (palette) {
8853 case WEED_PALETTE_YUVA8888:
8854 src = (uint8_t *)pixel_data[0];
8855 end = src + height * rowstride;
8856 while (src < end) {
8857 *src = Y_to_Y[*src];
8858 src++;
8859 *src = U_to_U[*src];
8860 src++;
8861 *src = V_to_V[*src];
8862 src += 2;
8863 }
8864 break;
8865 case WEED_PALETTE_YUV888:
8866 src = (uint8_t *)pixel_data[0];
8867 end = src + height * rowstride;
8868 while (src < end) {
8869 *src = Y_to_Y[*src];
8870 src++;
8871 *src = U_to_U[*src];
8872 src++;
8873 *src = V_to_V[*src];
8874 src++;
8875 }
8876 break;
8877 case WEED_PALETTE_YUVA4444P:
8878 case WEED_PALETTE_YUV444P:
8879 src = (uint8_t *)pixel_data[0];
8880 src1 = (uint8_t *)pixel_data[1];
8881 src2 = (uint8_t *)pixel_data[2];
8882 end = src + height * rowstride;
8883 while (src < end) {
8884 *src = Y_to_Y[*src];
8885 src++;
8886 *src1 = U_to_U[*src1];
8887 src1++;
8888 *src2 = V_to_V[*src2];
8889 src2++;
8890 }
8891 break;
8892 case WEED_PALETTE_UYVY:
8893 src = (uint8_t *)pixel_data[0];
8894 end = src + height * rowstride;
8895 while (src < end) {
8896 *src = U_to_U[*src];
8897 src++;
8898 *src = Y_to_Y[*src];
8899 src++;
8900 *src = V_to_V[*src];
8901 src++;
8902 *src = Y_to_Y[*src];
8903 src++;
8904 }
8905 break;
8906 case WEED_PALETTE_YUYV:
8907 src = (uint8_t *)pixel_data[0];
8908 end = src + height * rowstride;
8909 while (src < end) {
8910 *src = Y_to_Y[*src];
8911 src++;
8912 *src = U_to_U[*src];
8913 src++;
8914 *src = Y_to_Y[*src];
8915 src++;
8916 *src = V_to_V[*src];
8917 src++;
8918 }
8919 break;
8920 case WEED_PALETTE_YUV422P:
8921 src = (uint8_t *)pixel_data[0];
8922 src1 = (uint8_t *)pixel_data[1];
8923 src2 = (uint8_t *)pixel_data[2];
8924 end = src + height * rowstride;
8925 // TODO: u, v rowstrides
8926 while (src < end) {
8927 *src = Y_to_Y[*src];
8928 src++;
8929 *src = Y_to_Y[*src];
8930 src++;
8931 *src1 = U_to_U[*src1];
8932 src1++;
8933 *src2 = V_to_V[*src2];
8934 src2++;
8935 }
8936 break;
8937 case WEED_PALETTE_YVU420P:
8938 src = (uint8_t *)pixel_data[0];
8939 src1 = (uint8_t *)pixel_data[2];
8940 src2 = (uint8_t *)pixel_data[1];
8941 end = src + height * rowstride;
8942 // TODO: u, v rowstrides
8943 while (src < end) {
8944 *src = Y_to_Y[*src];
8945 src++;
8946 *src = Y_to_Y[*src];
8947 src++;
8948 *src = Y_to_Y[*src];
8949 src++;
8950 *src = Y_to_Y[*src];
8951 src++;
8952 *src1 = U_to_U[*src1];
8953 src1++;
8954 *src2 = V_to_V[*src2];
8955 src2++;
8956 }
8957 break;
8958 case WEED_PALETTE_YUV420P:
8959 src = (uint8_t *)pixel_data[0];
8960 src1 = (uint8_t *)pixel_data[1];
8961 src2 = (uint8_t *)pixel_data[2];
8962 end = src + height * rowstride;
8963 // TODO: u, v rowstrides
8964 while (src < end) {
8965 *src = Y_to_Y[*src];
8966 src++;
8967 *src = Y_to_Y[*src];
8968 src++;
8969 *src = Y_to_Y[*src];
8970 src++;
8971 *src = Y_to_Y[*src];
8972 src++;
8973 *src1 = U_to_U[*src1];
8974 src1++;
8975 *src2 = V_to_V[*src2];
8976 src2++;
8977 }
8978 break;
8979 case WEED_PALETTE_YUV411:
8980 src = (uint8_t *)pixel_data[0];
8981 end = src + height * rowstride;
8982 while (src < end) {
8983 *src = U_to_U[*src];
8984 src++;
8985 *src = Y_to_Y[*src];
8986 src++;
8987 *src = Y_to_Y[*src];
8988 src++;
8989 *src = V_to_V[*src];
8990 src++;
8991 *src = Y_to_Y[*src];
8992 src++;
8993 *src = Y_to_Y[*src];
8994 src++;
8995 }
8996 break;
8997 }
8998 weed_set_int_value(layer, WEED_LEAF_YUV_CLAMPING, oclamping);
8999 lives_free(pixel_data);
9000}
9001
9002
9004// TODO - move into layers.c
9005
9019LIVES_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
9058boolean create_empty_pixel_data(weed_layer_t *layer, boolean black_fill, boolean may_contig) {
9059 int palette = weed_layer_get_palette(layer);
9060 int width = weed_layer_get_width(layer);
9061 int height = weed_layer_get_height(layer);
9062 int rowstride, *rowstrides;
9063 int *fixed_rs = NULL;
9064
9065 uint32_t pflags;
9066 int clamping = WEED_YUV_CLAMPING_CLAMPED;
9067 boolean compact = FALSE;
9068
9069 uint8_t *pixel_data = NULL;
9070 uint8_t *memblock;
9071 uint8_t **pd_array;
9072
9073 unsigned char black[6] = {0, 0, 0, 255, 255, 255};
9074 unsigned char yuv_black[6] = {16, 128, 128, 255, 255, 255};
9075 float blackf[4] = {0., 0., 0., 1.};
9076
9077 size_t framesize, framesize2;
9078
9079 // max is 128 min is 32, and it must be a power of 2 (i.e 32, 64, 128)
9080 int sbits = 7, al, r;
9081 int rowstride_alignment = 16;
9082
9083 if (width <= 0 || height <= 0) return FALSE;
9084
9085 if (!weed_plant_has_leaf(layer, WEED_LEAF_NATURAL_SIZE)) {
9086 int nsize[2];
9087 // set "natural_size" in case a filter needs it
9088 nsize[0] = width;
9089 nsize[1] = height;
9090 weed_set_int_array(layer, WEED_LEAF_NATURAL_SIZE, 2, nsize);
9091 }
9092
9093 if (weed_leaf_get_flags(layer, WEED_LEAF_ROWSTRIDES) & LIVES_FLAG_MAINTAIN_VALUE) {
9095 fixed_rs = weed_layer_get_rowstrides(layer, NULL);
9096 } else {
9097 if (THREADVAR(rowstride_alignment) < ALIGN_DEF) THREADVAR(rowstride_alignment) = ALIGN_DEF;
9098 rowstride_alignment = THREADVAR(rowstride_alignment);
9099
9100 if (THREADVAR(rowstride_alignment_hint) > 0) {
9101 r = rowstride_alignment = THREADVAR(rowstride_alignment_hint);
9102 for (al = 1 << sbits; (al > ALIGN_MIN && !(al & r)); al >>= 1) sbits--;
9103 rowstride_alignment = al;
9104 }
9105 if (THREADVAR(rowstride_alignment_hint) < 0 || (weed_palette_is_alpha(palette) && THREADVAR(rowstride_alignment_hint) == 0)) {
9106 compact = TRUE;
9107 rowstride_alignment = 1;
9108 }
9109 THREADVAR(rowstride_alignment_hint) = 0;
9110
9111 for (sbits = 7; (1 << sbits) > rowstride_alignment; sbits--);
9112 }
9113
9114 if (weed_plant_has_leaf(layer, WEED_LEAF_HOST_PIXBUF_SRC)) {
9115 weed_leaf_delete(layer, WEED_LEAF_HOST_PIXBUF_SRC);
9116 }
9117 if (weed_plant_has_leaf(layer, WEED_LEAF_HOST_SURFACE_SRC)) {
9118 weed_leaf_delete(layer, WEED_LEAF_HOST_SURFACE_SRC);
9119 }
9120 if (weed_plant_has_leaf(layer, WEED_LEAF_HOST_SURFACE_SRC)) {
9121 weed_leaf_delete(layer, WEED_LEAF_HOST_SURFACE_SRC);
9122 }
9123 pflags = weed_leaf_get_flags(layer, WEED_LEAF_PIXEL_DATA);
9124 weed_leaf_set_flags(layer, WEED_LEAF_PIXEL_DATA, pflags & ~LIVES_FLAG_MAINTAIN_VALUE);
9125
9126 if (black_fill) {
9127 if (weed_plant_has_leaf(layer, WEED_LEAF_YUV_CLAMPING))
9128 clamping = weed_get_int_value(layer, WEED_LEAF_YUV_CLAMPING, NULL);
9129 if (clamping != WEED_YUV_CLAMPING_CLAMPED) yuv_black[0] = 0;
9130 }
9131
9132 switch (palette) {
9133 case WEED_PALETTE_RGBA32:
9134 case WEED_PALETTE_BGRA32:
9135 case WEED_PALETTE_ARGB32:
9136 if (fixed_rs) rowstride = fixed_rs[0];
9137 else {
9138 rowstride = width * 4;
9139 if (!compact) rowstride = ALIGN_CEIL(rowstride, rowstride_alignment);
9140 }
9141 framesize = ALIGN_CEIL(rowstride * height, ALIGN_SIZE) + EXTRA_BYTES;
9142 pixel_data = (uint8_t *)lives_calloc(framesize >> SHIFTVAL, ALIGN_SIZE);
9143 if (!pixel_data) return FALSE;
9144 weed_set_int_value(layer, WEED_LEAF_ROWSTRIDES, rowstride);
9145 weed_set_voidptr_value(layer, WEED_LEAF_PIXEL_DATA, pixel_data);
9146 if (black_fill) {
9147 if (palette == WEED_PALETTE_ARGB32) {
9148 black[3] = black[0];
9149 black[0] = 255;
9150 }
9151 fill_plane(pixel_data, 4, width, height, rowstride, black);
9152 }
9153 weed_set_int_value(layer, WEED_LEAF_ROWSTRIDES, rowstride);
9154 weed_set_voidptr_value(layer, WEED_LEAF_PIXEL_DATA, pixel_data);
9155 break;
9156
9157 case WEED_PALETTE_RGB24:
9158 case WEED_PALETTE_BGR24:
9159 if (fixed_rs) rowstride = fixed_rs[0];
9160 else {
9161 rowstride = width * 3;
9162 if (!compact) rowstride = ALIGN_CEIL(rowstride, rowstride_alignment);
9163 }
9164 framesize = ALIGN_CEIL(rowstride * height, ALIGN_SIZE) + EXTRA_BYTES;
9165 pixel_data = (uint8_t *)lives_calloc(framesize >> SHIFTVAL, ALIGN_SIZE);
9166 if (!pixel_data) return FALSE;
9167 weed_set_voidptr_value(layer, WEED_LEAF_PIXEL_DATA, pixel_data);
9168 weed_set_int_value(layer, WEED_LEAF_ROWSTRIDES, rowstride);
9169 break;
9170
9171 case WEED_PALETTE_YUV888:
9172 if (fixed_rs) rowstride = fixed_rs[0];
9173 else {
9174 rowstride = width * 3;
9175 if (!compact) rowstride = ALIGN_CEIL(rowstride, rowstride_alignment);
9176 }
9177 framesize = ALIGN_CEIL(rowstride * height, ALIGN_SIZE) + EXTRA_BYTES;
9178 pixel_data = (uint8_t *)lives_calloc(framesize >> SHIFTVAL, ALIGN_SIZE);
9179 if (!pixel_data) return FALSE;
9180 if (black_fill) fill_plane(pixel_data, 3, width, height, rowstride, yuv_black);
9181 weed_set_int_value(layer, WEED_LEAF_ROWSTRIDES, rowstride);
9182 weed_set_voidptr_value(layer, WEED_LEAF_PIXEL_DATA, pixel_data);
9183 break;
9184
9185 case WEED_PALETTE_YUVA8888:
9186 if (fixed_rs) rowstride = fixed_rs[0];
9187 else {
9188 rowstride = width * 4;
9189 if (!compact) rowstride = ALIGN_CEIL(rowstride, rowstride_alignment);
9190 }
9191 framesize = ALIGN_CEIL(rowstride * height, ALIGN_SIZE) + EXTRA_BYTES;
9192 pixel_data = (uint8_t *)lives_calloc(framesize >> SHIFTVAL, ALIGN_SIZE);
9193 if (!pixel_data) return FALSE;
9194 if (black_fill) fill_plane(pixel_data, 4, width, height, rowstride, yuv_black);
9195 weed_set_int_value(layer, WEED_LEAF_ROWSTRIDES, rowstride);
9196 weed_set_voidptr_value(layer, WEED_LEAF_PIXEL_DATA, pixel_data);
9197 break;
9198
9199 case WEED_PALETTE_UYVY:
9200 if (fixed_rs) rowstride = fixed_rs[0];
9201 else {
9202 rowstride = width * 4;
9203 if (!compact) rowstride = ALIGN_CEIL(rowstride, rowstride_alignment);
9204 }
9205 framesize = ALIGN_CEIL(rowstride * height, ALIGN_SIZE) + EXTRA_BYTES;
9206 pixel_data = (uint8_t *)lives_calloc(framesize >> SHIFTVAL, ALIGN_SIZE);
9207 if (!pixel_data) return FALSE;
9208 if (black_fill) {
9209 yuv_black[1] = yuv_black[3] = yuv_black[0];
9210 yuv_black[0] = yuv_black[2];
9211 fill_plane(pixel_data, 4, width, height, rowstride, yuv_black);
9212 }
9213 weed_set_int_value(layer, WEED_LEAF_ROWSTRIDES, rowstride);
9214 weed_set_voidptr_value(layer, WEED_LEAF_PIXEL_DATA, pixel_data);
9215 break;
9216
9217 case WEED_PALETTE_YUYV:
9218 if (fixed_rs) rowstride = fixed_rs[0];
9219 else {
9220 rowstride = width * 4;
9221 if (!compact) rowstride = ALIGN_CEIL(rowstride, rowstride_alignment);
9222 }
9223 framesize = ALIGN_CEIL(rowstride * height, ALIGN_SIZE) + EXTRA_BYTES;
9224 pixel_data = (uint8_t *)lives_calloc(framesize >> SHIFTVAL, ALIGN_SIZE);
9225 if (!pixel_data) return FALSE;
9226 if (black_fill) {
9227 yuv_black[2] = yuv_black[0];
9228 black[3] = yuv_black[1];
9229 fill_plane(pixel_data, 4, width, height, rowstride, yuv_black);
9230 }
9231 weed_set_int_value(layer, WEED_LEAF_ROWSTRIDES, rowstride);
9232 weed_set_voidptr_value(layer, WEED_LEAF_PIXEL_DATA, pixel_data);
9233 break;
9234
9235 case WEED_PALETTE_YUV420P:
9236 case WEED_PALETTE_YVU420P:
9237 width = (width >> 1) << 1;
9238 height = (height >> 1) << 1;
9239 weed_layer_set_size(layer, width, height);
9240 if (fixed_rs) rowstride = fixed_rs[0];
9241 else {
9242 rowstride = width;
9243 if (!compact) rowstride = ALIGN_CEIL(rowstride, rowstride_alignment);
9244 }
9245 framesize = ALIGN_CEIL(rowstride * height, ALIGN_SIZE);
9246 rowstrides = (int *)lives_malloc(sizint * 3);
9247 if (fixed_rs) {
9248 rowstrides[0] = fixed_rs[0];
9249 rowstride = rowstrides[1] = fixed_rs[1];
9250 rowstrides[2] = fixed_rs[2];
9251 } else {
9252 rowstrides[0] = rowstride;
9253 rowstride >>= 1;
9254 rowstrides[1] = rowstrides[2] = rowstride;
9255 }
9256 //if (!compact) rowstride = ALIGN_CEIL(rowstride, rowstride_alignment);
9257 framesize2 = ALIGN_CEIL(rowstride * (height >> 1), ALIGN_SIZE);
9258 weed_set_int_array(layer, WEED_LEAF_ROWSTRIDES, 3, rowstrides);
9259 lives_free(rowstrides);
9260
9261 pd_array = (uint8_t **)lives_malloc(3 * sizeof(uint8_t *));
9262
9263 if (!may_contig) {
9264 weed_leaf_delete(layer, WEED_LEAF_HOST_PIXEL_DATA_CONTIGUOUS);
9265 pd_array[0] = (uint8_t *)lives_calloc((framesize + EXTRA_BYTES) >> SHIFTVAL, ALIGN_SIZE);
9266 if (!pd_array[0]) {
9267 lives_free(pd_array);
9268 return FALSE;
9269 }
9270 pd_array[1] = (uint8_t *)lives_calloc((framesize2 + EXTRA_BYTES) >> SHIFTVAL, ALIGN_SIZE);
9271 if (!pd_array[1]) {
9272 lives_free(pd_array[0]);
9273 lives_free(pd_array);
9274 return FALSE;
9275 }
9276 pd_array[2] = (uint8_t *)lives_calloc((framesize2 + EXTRA_BYTES) >> SHIFTVAL, ALIGN_SIZE);
9277 if (!pd_array[2]) {
9278 lives_free(pd_array[1]);
9279 lives_free(pd_array[0]);
9280 lives_free(pd_array);
9281 return FALSE;
9282 }
9283 } else {
9284 weed_set_boolean_value(layer, WEED_LEAF_HOST_PIXEL_DATA_CONTIGUOUS, WEED_TRUE);
9285 memblock = (uint8_t *)lives_calloc((framesize + framesize2 * 2 + EXTRA_BYTES) >> SHIFTVAL, ALIGN_SIZE);
9286 if (!memblock) return FALSE;
9287 pd_array[0] = (uint8_t *)memblock;
9288 pd_array[1] = (uint8_t *)(memblock + framesize);
9289 pd_array[2] = (uint8_t *)(memblock + framesize + framesize2);
9290 }
9291 if (black_fill) {
9292 if (yuv_black[0] != 0) lives_memset(pd_array[0], yuv_black[0], framesize);
9293 if (may_contig) {
9294 lives_memset(pd_array[1], yuv_black[1], framesize2 * 2); // fill both planes
9295 } else {
9296 lives_memset(pd_array[1], yuv_black[1], framesize2);
9297 lives_memset(pd_array[2], yuv_black[2], framesize2);
9298 }
9299 }
9300
9301 weed_set_voidptr_array(layer, WEED_LEAF_PIXEL_DATA, 3, (void **)pd_array);
9302 lives_free(pd_array);
9303 break;
9304
9305 case WEED_PALETTE_YUV422P:
9306 width = (width >> 1) << 1;
9307 weed_layer_set_width(layer, width);
9308 if (fixed_rs) rowstride = fixed_rs[0];
9309 else {
9310 rowstride = width;
9311 if (!compact) rowstride = ALIGN_CEIL(rowstride, rowstride_alignment);
9312 }
9313 framesize = ALIGN_CEIL(rowstride * height, ALIGN_SIZE);
9314 rowstrides = (int *)lives_malloc(sizint * 3);
9315 if (fixed_rs) rowstride = fixed_rs[1];
9316 else {
9317 rowstrides[0] = rowstride;
9318 rowstride = width >> 1;
9319 if (!compact) rowstride = ALIGN_CEIL(rowstride, rowstride_alignment);
9320 }
9321 framesize2 = ALIGN_CEIL(rowstride * height, ALIGN_SIZE);
9322 if (fixed_rs) {
9323 rowstrides[0] = fixed_rs[0];
9324 rowstrides[1] = fixed_rs[1];
9325 rowstrides[2] = fixed_rs[2];
9326 } else rowstrides[1] = rowstrides[2] = rowstride;
9327 weed_set_int_array(layer, WEED_LEAF_ROWSTRIDES, 3, rowstrides);
9328 lives_free(rowstrides);
9329 pd_array = (uint8_t **)lives_malloc(3 * sizeof(uint8_t *));
9330
9331 if (!may_contig) {
9332 weed_leaf_delete(layer, WEED_LEAF_HOST_PIXEL_DATA_CONTIGUOUS);
9333 pd_array[0] = (uint8_t *)lives_calloc(framesize >> SHIFTVAL, ALIGN_SIZE);
9334 if (!pd_array[0]) {
9335 lives_free(pd_array);
9336 return FALSE;
9337 }
9338 pd_array[1] = (uint8_t *)lives_calloc(framesize2 >> SHIFTVAL, ALIGN_SIZE);
9339 if (!pd_array[1]) {
9340 lives_free(pd_array[0]);
9341 lives_free(pd_array);
9342 return FALSE;
9343 }
9344 pd_array[2] = (uint8_t *)lives_calloc((framesize2 + EXTRA_BYTES) >> SHIFTVAL, ALIGN_SIZE);
9345 if (!pd_array[2]) {
9346 lives_free(pd_array[1]);
9347 lives_free(pd_array[0]);
9348 lives_free(pd_array);
9349 return FALSE;
9350 }
9351 } else {
9352 weed_set_boolean_value(layer, WEED_LEAF_HOST_PIXEL_DATA_CONTIGUOUS, WEED_TRUE);
9353 memblock = (uint8_t *)lives_calloc((framesize + framesize2 * 2 + EXTRA_BYTES) >> SHIFTVAL, ALIGN_SIZE);
9354 if (!memblock) return FALSE;
9355 pd_array[0] = (uint8_t *)memblock;
9356 pd_array[1] = (uint8_t *)(memblock + framesize);
9357 pd_array[2] = (uint8_t *)(memblock + framesize + framesize2);
9358 }
9359 if (black_fill) {
9360 if (yuv_black[0] != 0) lives_memset(pd_array[0], yuv_black[0], framesize);
9361 if (may_contig) {
9362 lives_memset(pd_array[1], yuv_black[1], framesize2 * 2);
9363 } else {
9364 lives_memset(pd_array[1], yuv_black[1], framesize2);
9365 lives_memset(pd_array[2], yuv_black[2], framesize2);
9366 }
9367 }
9368 weed_set_voidptr_array(layer, WEED_LEAF_PIXEL_DATA, 3, (void **)pd_array);
9369 lives_free(pd_array);
9370 break;
9371
9372 case WEED_PALETTE_YUV444P:
9373 if (!fixed_rs) {
9374 rowstride = width;
9375 if (!compact) rowstride = ALIGN_CEIL(rowstride, rowstride_alignment);
9376 }
9377 rowstrides = (int *)lives_malloc(sizint * 3);
9378 if (fixed_rs) {
9379 rowstride = rowstrides[0] = fixed_rs[0];
9380 rowstrides[1] = fixed_rs[1];
9381 rowstrides[2] = fixed_rs[2];
9382 } else rowstrides[0] = rowstrides[1] = rowstrides[2] = rowstride;
9383 weed_set_int_array(layer, WEED_LEAF_ROWSTRIDES, 3, rowstrides);
9384 lives_free(rowstrides);
9385 pd_array = (uint8_t **)lives_malloc(3 * sizeof(uint8_t *));
9386 framesize = ALIGN_CEIL(rowstride * height, ALIGN_SIZE);
9387
9388 if (!may_contig) {
9389 weed_leaf_delete(layer, WEED_LEAF_HOST_PIXEL_DATA_CONTIGUOUS);
9390 pd_array[0] = (uint8_t *)lives_calloc(framesize >> SHIFTVAL, ALIGN_SIZE);
9391 if (!pd_array[0]) {
9392 lives_free(pd_array);
9393 return FALSE;
9394 }
9395 pd_array[1] = (uint8_t *)lives_calloc(framesize >> SHIFTVAL, ALIGN_SIZE);
9396 if (!pd_array[1]) {
9397 lives_free(pd_array[0]);
9398 lives_free(pd_array);
9399 return FALSE;
9400 }
9401 pd_array[2] = (uint8_t *)lives_calloc((framesize + EXTRA_BYTES) >> SHIFTVAL, ALIGN_SIZE);
9402 if (!pd_array[2]) {
9403 lives_free(pd_array[1]);
9404 lives_free(pd_array[0]);
9405 lives_free(pd_array);
9406 return FALSE;
9407 }
9408 } else {
9409 weed_set_boolean_value(layer, WEED_LEAF_HOST_PIXEL_DATA_CONTIGUOUS, WEED_TRUE);
9410 memblock = (uint8_t *)lives_calloc((framesize * 3 + EXTRA_BYTES) >> SHIFTVAL, ALIGN_SIZE);
9411 if (!memblock) return FALSE;
9412 pd_array[0] = memblock;
9413 pd_array[1] = memblock + framesize;
9414 pd_array[2] = memblock + framesize * 2;
9415 }
9416 if (black_fill) {
9417 if (yuv_black[0] != 0) lives_memset(pd_array[0], yuv_black[0], framesize);
9418 if (may_contig) {
9419 lives_memset(pd_array[1], yuv_black[1], framesize * 2);
9420 } else {
9421 lives_memset(pd_array[1], yuv_black[1], framesize);
9422 lives_memset(pd_array[2], yuv_black[2], framesize);
9423 }
9424 }
9425 weed_set_voidptr_array(layer, WEED_LEAF_PIXEL_DATA, 3, (void **)pd_array);
9426 lives_free(pd_array);
9427 break;
9428
9429 case WEED_PALETTE_YUVA4444P:
9430 if (!fixed_rs) {
9431 rowstride = width;
9432 if (!compact) rowstride = ALIGN_CEIL(rowstride, rowstride_alignment);
9433 }
9434 rowstrides = (int *)lives_malloc(sizint * 4);
9435 if (fixed_rs) {
9436 rowstride = rowstrides[0] = fixed_rs[0];
9437 rowstrides[1] = fixed_rs[1];
9438 rowstrides[2] = fixed_rs[2];
9439 rowstrides[3] = fixed_rs[3];
9440 } else rowstrides[0] = rowstrides[1] = rowstrides[2] = rowstrides[3] = rowstride;
9441 weed_set_int_array(layer, WEED_LEAF_ROWSTRIDES, 4, rowstrides);
9442 lives_free(rowstrides);
9443 pd_array = (uint8_t **)lives_malloc(4 * sizeof(uint8_t *));
9444 framesize = ALIGN_CEIL(rowstride * height, ALIGN_SIZE);
9445
9446 if (!may_contig) {
9447 weed_leaf_delete(layer, WEED_LEAF_HOST_PIXEL_DATA_CONTIGUOUS);
9448 pd_array[0] = (uint8_t *)lives_calloc((framesize + EXTRA_BYTES) >> SHIFTVAL, ALIGN_SIZE);
9449 if (!pd_array[0]) {
9450 lives_free(pd_array);
9451 return FALSE;
9452 }
9453 pd_array[1] = (uint8_t *)lives_calloc((framesize + EXTRA_BYTES) >> SHIFTVAL, ALIGN_SIZE);
9454 if (!pd_array[1]) {
9455 lives_free(pd_array[0]);
9456 lives_free(pd_array);
9457 return FALSE;
9458 }
9459 pd_array[2] = (uint8_t *)lives_calloc((framesize + EXTRA_BYTES) >> SHIFTVAL, ALIGN_SIZE);
9460 if (!pd_array[2]) {
9461 lives_free(pd_array[1]);
9462 lives_free(pd_array[0]);
9463 lives_free(pd_array);
9464 return FALSE;
9465 }
9466 pd_array[3] = (uint8_t *)lives_calloc((framesize + EXTRA_BYTES) >> SHIFTVAL, ALIGN_SIZE);
9467 if (!pd_array[3]) {
9468 lives_free(pd_array[2]);
9469 lives_free(pd_array[1]);
9470 lives_free(pd_array[0]);
9471 lives_free(pd_array);
9472 return FALSE;
9473 }
9474 } else {
9475 weed_set_boolean_value(layer, WEED_LEAF_HOST_PIXEL_DATA_CONTIGUOUS, WEED_TRUE);
9476 memblock = (uint8_t *)lives_calloc((framesize * 4 + EXTRA_BYTES) >> SHIFTVAL, ALIGN_SIZE);
9477 if (!memblock) return FALSE;
9478 pd_array[0] = memblock;
9479 pd_array[1] = memblock + framesize;
9480 pd_array[2] = memblock + framesize * 2;
9481 pd_array[3] = memblock + framesize * 3;
9482 }
9483 if (black_fill) {
9484 if (yuv_black[0] != 0) {
9485 lives_memset(pd_array[0], yuv_black[0], framesize * 2);
9486 }
9487 if (may_contig) {
9488 lives_memset(pd_array[1], yuv_black[1], framesize * 2);
9489 } else {
9490 lives_memset(pd_array[1], yuv_black[1], framesize);
9491 lives_memset(pd_array[2], yuv_black[2], framesize);
9492 }
9493 lives_memset(pd_array[3], 255, framesize);
9494 }
9495 weed_set_voidptr_array(layer, WEED_LEAF_PIXEL_DATA, 4, (void **)pd_array);
9496 lives_free(pd_array);
9497 break;
9498
9499 case WEED_PALETTE_YUV411:
9500 if (fixed_rs) rowstride = fixed_rs[0];
9501 else {
9502 rowstride = width * 6; // a macro-pixel is 6 bytes, and contains 4 real pixels
9503 if (!compact) rowstride = ALIGN_CEIL(rowstride, rowstride_alignment);
9504 }
9505 weed_layer_set_width(layer, width);
9506 framesize = ALIGN_CEIL(rowstride * height, ALIGN_SIZE);
9507 pixel_data = (uint8_t *)lives_calloc((framesize + EXTRA_BYTES) >> SHIFTVAL, ALIGN_SIZE);
9508 if (!pixel_data) return FALSE;
9509 if (black_fill) {
9510 yuv_black[3] = yuv_black[1];
9511 yuv_black[1] = yuv_black[2] = yuv_black[4] = yuv_black[5] = yuv_black[0];
9512 yuv_black[0] = yuv_black[3];
9513 pixel_data = (uint8_t *)lives_calloc((framesize + EXTRA_BYTES) >> SHIFTVAL, ALIGN_SIZE);
9514 if (black_fill) {
9515 fill_plane(pixel_data, 6, width, height, rowstride, black);
9516 }
9517 }
9518 if (!pixel_data) return FALSE;
9519 weed_set_voidptr_value(layer, WEED_LEAF_PIXEL_DATA, pixel_data);
9520 weed_set_int_value(layer, WEED_LEAF_ROWSTRIDES, rowstride);
9521 break;
9522
9523 case WEED_PALETTE_RGBFLOAT:
9524 if (fixed_rs) rowstride = fixed_rs[0];
9525 else {
9526 rowstride = width * 3 * sizeof(float);
9527 if (!compact) rowstride = ALIGN_CEIL(rowstride, rowstride_alignment);
9528 }
9529 pixel_data = (uint8_t *)lives_calloc((rowstride * height + EXTRA_BYTES) >> SHIFTVAL, ALIGN_SIZE);
9530 if (!pixel_data) return FALSE;
9531 weed_set_voidptr_value(layer, WEED_LEAF_PIXEL_DATA, pixel_data);
9532 weed_set_int_value(layer, WEED_LEAF_ROWSTRIDES, rowstride);
9533 break;
9534
9535 case WEED_PALETTE_RGBAFLOAT:
9536 if (fixed_rs) rowstride = fixed_rs[0];
9537 else {
9538 rowstride = width * 4 * sizeof(float);
9539 if (!compact) rowstride = ALIGN_CEIL(rowstride, rowstride_alignment);
9540 }
9541 pixel_data = (uint8_t *)lives_calloc((rowstride * height + EXTRA_BYTES), ALIGN_SIZE);
9542 if (black_fill) {
9543 fill_plane(pixel_data, 4 * sizeof(float), width, height, rowstride, (uint8_t *)blackf);
9544 }
9545 if (!pixel_data) return FALSE;
9546 weed_set_voidptr_value(layer, WEED_LEAF_PIXEL_DATA, pixel_data);
9547 weed_set_int_value(layer, WEED_LEAF_ROWSTRIDES, rowstride);
9548 break;
9549
9550 case WEED_PALETTE_AFLOAT:
9551 if (fixed_rs) rowstride = fixed_rs[0];
9552 else {
9553 rowstride = width * sizeof(float);
9554 if (!compact) rowstride = ALIGN_CEIL(rowstride, rowstride_alignment);
9555 }
9556 pixel_data = (uint8_t *)lives_calloc((width * height + EXTRA_BYTES) >> SHIFTVAL, ALIGN_SIZE);
9557 if (!pixel_data) return FALSE;
9558 if (black_fill) {
9559 blackf[0] = 1.;
9560 fill_plane(pixel_data, sizeof(float), width, height, rowstride, (uint8_t *)blackf);
9561 }
9562 weed_set_voidptr_value(layer, WEED_LEAF_PIXEL_DATA, pixel_data);
9563 weed_set_int_value(layer, WEED_LEAF_ROWSTRIDES, rowstride);
9564 break;
9565
9566 case WEED_PALETTE_A8:
9567 if (fixed_rs) rowstride = fixed_rs[0];
9568 else {
9569 rowstride = width;
9570 if (!compact) rowstride = ALIGN_CEIL(rowstride, rowstride_alignment);
9571 }
9572 framesize = ALIGN_CEIL((rowstride * height + EXTRA_BYTES), ALIGN_SIZE);
9573 pixel_data = (uint8_t *)lives_calloc(framesize >> SHIFTVAL, ALIGN_SIZE);
9574 if (!pixel_data) return FALSE;
9575 if (black_fill) {
9576 lives_memset(pixel_data, 255, rowstride * height);
9577 }
9578 if (!pixel_data) return FALSE;
9579 weed_set_voidptr_value(layer, WEED_LEAF_PIXEL_DATA, pixel_data);
9580 weed_set_int_value(layer, WEED_LEAF_ROWSTRIDES, rowstride);
9581 break;
9582
9583 case WEED_PALETTE_A1:
9584 if (fixed_rs) rowstride = fixed_rs[0];
9585 else rowstride = (width + 7) >> 3;
9586 framesize = ALIGN_CEIL(rowstride * height, ALIGN_SIZE);
9587 pixel_data = (uint8_t *)lives_calloc((framesize + EXTRA_BYTES) >> SHIFTVAL, ALIGN_SIZE);
9588 if (!pixel_data) return FALSE;
9589 lives_memset(pixel_data, 255, rowstride * height);
9590 weed_set_voidptr_value(layer, WEED_LEAF_PIXEL_DATA, pixel_data);
9591 weed_set_int_value(layer, WEED_LEAF_ROWSTRIDES, rowstride);
9592 break;
9593
9594 default:
9595 lives_printerr("Warning: asked to create empty pixel_data for palette %d !\n", palette);
9596 break_me("create_empty_pixel_data w. unknown pal");
9597 }
9598 return TRUE;
9599}
9600
9601
9611weed_layer_t *create_blank_layer(weed_layer_t *layer, const char *image_ext, int width, int height, int target_palette) {
9612 if (!layer) layer = weed_layer_new(WEED_LAYER_TYPE_VIDEO);
9613 else {
9614 if (!width) width = weed_layer_get_width(layer);
9615 if (!height) height = weed_layer_get_height(layer);
9616 if (!width || !height) {
9617 int clip = lives_layer_get_clip(layer);
9618 if (clip && IS_VALID_CLIP(clip)) {
9619 width = mainw->files[clip]->hsize;
9620 height = mainw->files[clip]->vsize;
9621 }
9622 }
9623 }
9624 if (width == 0) width = DEF_FRAME_HSIZE_UNSCALED;
9625 if (height == 0) height = DEF_FRAME_VSIZE_UNSCALED;
9626 weed_layer_set_size(layer, width, height);
9627 if (!weed_plant_has_leaf(layer, WEED_LEAF_CURRENT_PALETTE)) {
9628 if (target_palette != WEED_PALETTE_END) weed_layer_set_palette(layer, target_palette);
9629 else {
9630 if (!image_ext || !strcmp(image_ext, LIVES_FILE_EXT_JPG))
9631 weed_layer_set_palette(layer, WEED_PALETTE_RGB24);
9632 else weed_layer_set_palette(layer, WEED_PALETTE_RGBA32);
9633 }
9634 }
9636 if (!weed_plant_has_leaf(layer, WEED_LEAF_GAMMA_TYPE)) {
9637 int clip = lives_layer_get_clip(layer);
9638 if (clip && IS_VALID_CLIP(clip))
9640 else
9641 weed_layer_set_gamma(layer, WEED_GAMMA_SRGB);
9642 }
9643 return layer;
9644}
9645
9646
9647LIVES_GLOBAL_INLINE boolean rowstrides_differ(int n1, int *n1_array, int n2, int *n2_array) {
9648 // returns TRUE if the rowstrides differ
9649 if (!n1_array || !n2_array || n1 != n2) return TRUE;
9650 for (int i = 0; i < n1; i++) if (n1_array[i] != n2_array[i]) return TRUE;
9651 return FALSE;
9652}
9653
9654
9656 weed_layer_t *layer = weed_plant_new(WEED_PLANT_LAYER);
9657 weed_set_int_value(layer, WEED_LEAF_LAYER_TYPE, layer_type);
9658 weed_set_int_value(layer, WEED_LEAF_HOST_REFS, 1);
9659 return layer;
9660}
9661
9662
9664 if (!layer || !WEED_IS_LAYER(layer)) return WEED_LAYER_TYPE_NONE;
9665 return weed_get_int_value(layer, WEED_LEAF_LAYER_TYPE, NULL);
9666}
9667
9668
9670 if (layer && WEED_IS_LAYER(layer) && weed_layer_get_type(layer) == WEED_LAYER_TYPE_VIDEO) return WEED_TRUE;
9671 return WEED_FALSE;
9672}
9673
9674
9676 if (layer && WEED_IS_LAYER(layer) && weed_layer_get_type(layer) == WEED_LAYER_TYPE_AUDIO) return WEED_TRUE;
9677 return WEED_FALSE;
9678}
9679
9680
9682 int arate, int naudchans, weed_size_t nsamps) {
9683 if (!layer || !WEED_IS_LAYER(layer)) return NULL;
9684 weed_set_voidptr_array(layer, WEED_LEAF_AUDIO_DATA, naudchans, (void **)data);
9685 weed_set_int_value(layer, WEED_LEAF_AUDIO_RATE, arate);
9686 weed_set_int_value(layer, WEED_LEAF_AUDIO_DATA_LENGTH, nsamps);
9687 weed_set_int_value(layer, WEED_LEAF_AUDIO_CHANNELS, naudchans);
9688 return layer;
9689}
9690
9691
9693 if (!layer || !WEED_IS_LAYER(layer)) return NULL;
9694 weed_set_int_value(layer, WEED_LEAF_FLAGS, flags);
9695 return layer;
9696}
9697
9698
9700 if (!layer || !WEED_IS_LAYER(layer)) return 0;
9701 return weed_get_int_value(layer, WEED_LEAF_FLAGS, NULL);
9702}
9703
9704
9706 if (!layer || !WEED_IS_LAYER(layer)) return 0;
9707 return weed_get_int_value(layer, WEED_LEAF_CLIP, NULL);
9708}
9709
9710
9712 if (!layer || !WEED_IS_LAYER(layer)) return 0;
9713 return weed_get_int_value(layer, WEED_LEAF_FRAME, NULL);
9714}
9715
9716
9718 if (!layer || !WEED_IS_LAYER(layer)) return NULL;
9719 weed_set_int_value(layer, WEED_LEAF_WIDTH, width);
9720 return layer;
9721}
9722
9723
9725 if (!layer || !WEED_IS_LAYER(layer)) return NULL;
9726 weed_set_int_value(layer, WEED_LEAF_HEIGHT, height);
9727 return layer;
9728}
9729
9730
9732 if (!layer || !WEED_IS_LAYER(layer)) return NULL;
9733 weed_layer_set_width(layer, width);
9734 weed_layer_set_height(layer, height);
9735 return layer;
9736}
9737
9738
9740 if (!layer || !WEED_IS_LAYER(layer)) return NULL;
9741 weed_set_voidptr_array(layer, WEED_LEAF_PIXEL_DATA, nplanes, pixel_data);
9742 return layer;
9743}
9744
9745
9747 if (!layer || !WEED_IS_LAYER(layer)) return NULL;
9748 weed_set_voidptr_value(layer, WEED_LEAF_PIXEL_DATA, pixel_data);
9749 return layer;
9750}
9751
9752
9754 if (!layer || !WEED_IS_LAYER(layer)) return NULL;
9755 weed_set_voidptr_array(layer, WEED_LEAF_PIXEL_DATA, 0, NULL);
9756 weed_leaf_delete(layer, WEED_LEAF_HOST_PIXEL_DATA_CONTIGUOUS);
9757 weed_leaf_delete(layer, WEED_LEAF_HOST_PIXBUF_SRC);
9758 weed_leaf_delete(layer, WEED_LEAF_HOST_SURFACE_SRC);
9759 return layer;
9760}
9761
9762
9764 if (!layer || !WEED_IS_LAYER(layer)) return NULL;
9765 weed_set_int_array(layer, WEED_LEAF_ROWSTRIDES, nplanes, rowstrides);
9766 return layer;
9767}
9768
9769
9771 if (!layer || !WEED_IS_LAYER(layer)) return NULL;
9772 weed_set_int_value(layer, WEED_LEAF_ROWSTRIDES, rowstride);
9773 return layer;
9774}
9775
9776
9778 if (!layer || !WEED_IS_LAYER(layer)) return NULL;
9779 weed_set_int_value(layer, WEED_LEAF_CURRENT_PALETTE, palette);
9780 return layer;
9781}
9782
9783
9785 if (!layer || !WEED_IS_LAYER(layer)) return NULL;
9786 weed_set_int_value(layer, WEED_LEAF_GAMMA_TYPE, gamma_type);
9787 return layer;
9788}
9789
9790
9792 if (!layer || !WEED_IS_LAYER(layer)) return NULL;
9793 weed_set_int_value(layer, WEED_LEAF_YUV_CLAMPING, clamping);
9794 return layer;
9795}
9796
9797
9799 if (!layer || !WEED_IS_LAYER(layer)) return NULL;
9800 weed_set_int_value(layer, WEED_LEAF_YUV_SAMPLING, sampling);
9801 return layer;
9802}
9803
9804
9806 if (!layer || !WEED_IS_LAYER(layer)) return NULL;
9807 weed_set_int_value(layer, WEED_LEAF_YUV_SUBSPACE, subspace);
9808 return layer;
9809}
9810
9811
9813 int clamping, int sampling, int subspace) {
9814 if (!weed_layer_set_palette(layer, palette)) return NULL;
9815 weed_layer_set_yuv_clamping(layer, clamping);
9816 weed_layer_set_yuv_sampling(layer, sampling);
9817 weed_layer_set_yuv_subspace(layer, subspace);
9818 return layer;
9819}
9820
9821
9823 // TODO -> int64
9824 weed_set_int_value(layer, WEED_LEAF_FRAME, frame);
9825}
9826
9827
9829 weed_set_int_value(layer, WEED_LEAF_CLIP, clip);
9830}
9831
9832
9834 // create a layer ready to receive a frame from a clip
9836 lives_layer_set_clip(layer, clip);
9837 lives_layer_set_frame(layer, frame);
9838 return layer;
9839}
9840
9841
9842// returns TRUE on success
9843boolean copy_pixel_data(weed_layer_t *layer, weed_layer_t *old_layer, size_t alignment) {
9844 // copy (deep) old_layer -> layer
9845
9846 int numplanes, xheight, xwidth;
9847 int *orowstrides = weed_layer_get_rowstrides(old_layer, &numplanes), *rowstrides;
9848 void **pixel_data, **npixel_data;
9849 int pal = weed_layer_get_palette(layer);
9850 int width = weed_layer_get_width(layer);
9851 int height = weed_layer_get_height(layer);
9852 int psize = pixel_size(pal);
9853 int i = numplanes, j;
9854 boolean newdata = FALSE;
9855
9856 if (alignment != 0 && !old_layer) {
9857 while (i > 0) if (orowstrides[--i] % alignment != 0) i = -1;
9858 if (i == 0) return TRUE;
9859 }
9860
9861 if (!old_layer) {
9862 newdata = TRUE;
9864 weed_layer_copy(old_layer, layer);
9865 }
9866 pixel_data = weed_layer_get_pixel_data(old_layer, &numplanes);
9867 if (!pixel_data || !pixel_data[0]) {
9868 if (newdata) {
9870 weed_layer_free(old_layer);
9871 }
9872 return FALSE;
9873 }
9874
9876
9877 if (alignment != 0) THREADVAR(rowstride_alignment_hint) = alignment;
9878
9879 if (!create_empty_pixel_data(layer, FALSE, TRUE)) {
9880 if (newdata) {
9881 weed_layer_copy(layer, old_layer);
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
9923void alpha_unpremult(weed_layer_t *layer, boolean un) {
9925 int error;
9926 int aoffs, coffs, psize, psizel, widthx;
9927 int alpha;
9928 int flags = 0;
9929 int width = weed_get_int_value(layer, WEED_LEAF_WIDTH, NULL);
9930 int height = weed_get_int_value(layer, WEED_LEAF_HEIGHT, NULL);
9931 int rowstride = weed_get_int_value(layer, WEED_LEAF_ROWSTRIDES, NULL);
9932 int pal = weed_get_int_value(layer, WEED_LEAF_CURRENT_PALETTE, NULL);
9933
9934 int *rows;
9935
9936 unsigned char *ptr;
9937 unsigned char **ptrp;
9938
9939 boolean clamped;
9940
9941 int i, j, p;
9942
9943 if (!unal_inited) init_unal();
9944
9945 if (weed_plant_has_leaf(layer, WEED_LEAF_YUV_CLAMPING))
9946 clamped = (weed_get_int_value(layer, WEED_LEAF_YUV_CLAMPING, &error) == WEED_YUV_CLAMPING_CLAMPED);
9947 else clamped = TRUE;
9948
9949 switch (pal) {
9950 case WEED_PALETTE_RGBA32:
9951 case WEED_PALETTE_BGRA32:
9952 clamped = FALSE;
9953 case WEED_PALETTE_YUVA8888:
9954 widthx = width * 4;
9955 psize = 4;
9956 psizel = 3;
9957 coffs = 0;
9958 aoffs = 3;
9959 break;
9960 case WEED_PALETTE_ARGB32:
9961 widthx = width * 4;
9962 psize = 4;
9963 psizel = 4;
9964 coffs = 1;
9965 aoffs = 0;
9966 clamped = FALSE;
9967 break;
9968 case WEED_PALETTE_YUVA4444P:
9970 ptrp = (unsigned char **)weed_get_voidptr_array(layer, WEED_LEAF_PIXEL_DATA, &error);
9971 rows = weed_get_int_array(layer, WEED_LEAF_ROWSTRIDES, &error);
9972
9973 if (!clamped) {
9974 if (un) {
9975 for (i = 0; i < height; i++) {
9976 for (j = 0; j < width; j++) {
9977 alpha = ptrp[3][j];
9978 for (p = 0; p < 3; p++) {
9979 ptrp[p][j] = unal[alpha][ptrp[p][j]];
9980 }
9981 }
9982 for (p = 0; p < 4; p++) {
9983 ptrp[p] += rows[p];
9984 }
9985 }
9986 } else {
9987 for (i = 0; i < height; i++) {
9988 for (j = 0; j < width; j++) {
9989 alpha = ptrp[3][j];
9990 for (p = 0; p < 3; p++) {
9991 ptrp[p][j] = al[alpha][ptrp[p][j]];
9992 }
9993 }
9994 for (p = 0; p < 4; p++) {
9995 ptrp[p] += rows[p];
9996 }
9997 }
9998 }
9999 } else {
10000 if (un) {
10001 for (i = 0; i < height; i++) {
10002 for (j = 0; j < width; j++) {
10003 alpha = ptrp[3][j];
10004 ptrp[0][j] = unalcy[alpha][ptrp[0][j]];
10005 ptrp[1][j] = unalcuv[alpha][ptrp[0][j]];
10006 ptrp[2][j] = unalcuv[alpha][ptrp[0][j]];
10007 }
10008 for (p = 0; p < 4; p++) {
10009 ptrp[p] += rows[p];
10010 }
10011 }
10012 } else {
10013 for (i = 0; i < height; i++) {
10014 for (j = 0; j < width; j++) {
10015 alpha = ptrp[3][j];
10016 ptrp[0][j] = alcy[alpha][ptrp[0][j]];
10017 ptrp[1][j] = alcuv[alpha][ptrp[0][j]];
10018 ptrp[2][j] = alcuv[alpha][ptrp[0][j]];
10019 }
10020 for (p = 0; p < 4; p++) {
10021 ptrp[p] += rows[p];
10022 // *INDENT-OFF*
10023 }}}}
10024 // *INDENT-ON*
10025
10026 return;
10027 default:
10028 return;
10029 }
10030
10031 ptr = (unsigned char *)weed_get_voidptr_value(layer, WEED_LEAF_PIXEL_DATA, &error);
10032
10033 if (!clamped) {
10034 if (un) {
10035 for (i = 0; i < height; i++) {
10036 for (j = 0; j < widthx; j += psize) {
10037 alpha = ptr[j + aoffs];
10038 for (p = coffs; p < psizel; p++) {
10039 ptr[j + p] = unal[alpha][ptr[j + p]];
10040 }
10041 }
10042 ptr += rowstride;
10043 }
10044 } else {
10045 for (i = 0; i < height; i++) {
10046 for (j = 0; j < widthx; j += psize) {
10047 alpha = ptr[j + aoffs];
10048 for (p = coffs; p < psizel; p++) {
10049 ptr[j + p] = al[alpha][ptr[j + p]];
10050 }
10051 }
10052 ptr += rowstride;
10053 }
10054 }
10055 } else {
10057 if (un) {
10058 for (i = 0; i < height; i++) {
10059 for (j = 0; j < widthx; j += psize) {
10060 alpha = ptr[j + 3];
10061 ptr[j] = unalcy[alpha][ptr[j]];
10062 ptr[j + 1] = unalcuv[alpha][ptr[j]];
10063 ptr[j + 2] = unalcuv[alpha][ptr[j]];
10064 }
10065 ptr += rowstride;
10066 }
10067 } else {
10068 for (i = 0; i < height; i++) {
10069 for (j = 0; j < widthx; j += psize) {
10070 alpha = ptr[j + 3];
10071 ptr[j] = alcy[alpha][ptr[j]];
10072 ptr[j + 1] = alcuv[alpha][ptr[j]];
10073 ptr[j + 2] = alcuv[alpha][ptr[j]];
10074 }
10075 ptr += rowstride;
10076 }
10077 }
10078 }
10079
10080 flags = weed_layer_get_flags(layer);
10081
10082 if (!un) flags |= WEED_LAYER_ALPHA_PREMULT;
10083 else if (flags & WEED_LAYER_ALPHA_PREMULT) flags ^= WEED_LAYER_ALPHA_PREMULT;
10084
10085 if (flags == 0) weed_leaf_delete(layer, WEED_LEAF_FLAGS);
10086 else weed_set_int_value(layer, WEED_LEAF_FLAGS, flags);
10087}
10088
10089
10090static 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
10108LIVES_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
10160boolean 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);
10302 // TODO: rowstrides for uyvy, yuyv, 422P, 411
10303
10305#ifdef WEED_ADVANCED_PALETTES
10306 if (!weed_palette_is_sane(inpl) || !weed_palette_is_sane(outpl)) {
10307 if (!weed_palette_is_sane(outpl)) g_print("BAD pal %d\n", outpl);
10308 if (!weed_palette_is_sane(inpl)) g_print("BAD pal %d\n", inpl);
10309 return FALSE;
10310 }
10311 if (get_advanced_palette(inpl)->chantype[1] == WEED_VCHAN_V) swap_chroma_planes(layer);
10312#else
10313 if (inpl == WEED_PALETTE_YVU420P) swap_chroma_planes(layer);
10314#endif
10315
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);
10330 } else {
10331 // add post
10332 if (weed_palettes_rbswapped(inpl, outpl)) {
10333 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10334 orowstride = weed_layer_get_rowstride(layer);
10335 gudest = weed_layer_get_pixel_data_packed(layer);
10336 convert_swap3addpost_frame(gusrc, width, height, irowstride, orowstride, gudest,
10337 -USE_THREADS);
10338 } else {
10339 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10340 orowstride = weed_layer_get_rowstride(layer);
10341 gudest = weed_layer_get_pixel_data_packed(layer);
10342 convert_addpost_frame(gusrc, width, height, irowstride, orowstride, gudest,
10343 create_gamma_lut(1.0, weed_layer_get_gamma(layer), new_gamma_type),
10344 -USE_THREADS);
10345 }
10346 }
10347 } else {
10349 if (weed_palettes_rbswapped(inpl, outpl)) {
10350 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10351 orowstride = weed_layer_get_rowstride(layer);
10352 gudest = weed_layer_get_pixel_data_packed(layer);
10353 convert_swap3addpre_frame(gusrc, width, height, irowstride, orowstride, gudest,
10354 -USE_THREADS);
10355 } else {
10356 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10357 orowstride = weed_layer_get_rowstride(layer);
10358 gudest = weed_layer_get_pixel_data_packed(layer);
10359 convert_addpre_frame(gusrc, width, height, irowstride, orowstride, gudest, -USE_THREADS);
10360 }
10361 }
10362 } else {
10364 if (!weed_palette_has_alpha_first(outpl)) {
10365 if (!weed_palette_has_alpha_last(outpl)) {
10366 if (weed_palettes_rbswapped(inpl, outpl)) {
10367 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10368 orowstride = weed_layer_get_rowstride(layer);
10369 gudest = weed_layer_get_pixel_data_packed(layer);
10370 convert_swap3delpost_frame(gusrc, width, height, irowstride, orowstride, gudest,
10371 -USE_THREADS);
10372 } else {
10373 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10374 orowstride = weed_layer_get_rowstride(layer);
10375 gudest = weed_layer_get_pixel_data_packed(layer);
10376 convert_delpost_frame(gusrc, width, height, irowstride, orowstride, gudest,
10377 create_gamma_lut(1.0, weed_layer_get_gamma(layer), new_gamma_type),
10378 -USE_THREADS);
10379 }
10380 } else {
10382 convert_swap3postalpha_frame(gusrc, width, height, irowstride, -USE_THREADS);
10384 }
10385 } else {
10387 if (weed_palettes_rbswapped(inpl, outpl)) {
10388 convert_swap4_frame(gusrc, width, height, irowstride, irowstride, gusrc, -USE_THREADS);
10390 } else {
10391 convert_swapprepost_frame(gusrc, width, height, irowstride, irowstride, gusrc,
10392 -USE_THREADS);
10394 }
10395 }
10396 }
10397 } else {
10398 // inpl has pre
10399 if (!weed_palette_has_alpha_first(outpl)) {
10400 if (!weed_palette_has_alpha_last(outpl)) {
10401 if (weed_palettes_rbswapped(inpl, outpl)) {
10402 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10403 orowstride = weed_layer_get_rowstride(layer);
10404 gudest = weed_layer_get_pixel_data_packed(layer);
10405 convert_swap3delpre_frame(gusrc, width, height, irowstride, orowstride, gudest,
10406 -USE_THREADS);
10407 } else {
10408 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10409 orowstride = weed_layer_get_rowstride(layer);
10410 gudest = weed_layer_get_pixel_data_packed(layer);
10411 convert_delpre_frame(gusrc, width, height, irowstride, orowstride, gudest, -USE_THREADS);
10412 }
10413 } else {
10415 if (weed_palettes_rbswapped(inpl, outpl)) {
10416 convert_swap4_frame(gusrc, width, height, irowstride, irowstride, gusrc, -USE_THREADS);
10418 } else {
10419 convert_swapprepost_frame(gusrc, width, height, irowstride, irowstride, gusrc,
10420 -USE_THREADS);
10422 }
10423 }
10424 } else {
10426 convert_swap3prealpha_frame(gusrc, width, height, irowstride, -USE_THREADS);
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);
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",
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);
10563 break;
10564 case WEED_PALETTE_ARGB32:
10565 convert_swapprepost_frame(gusrc, width, height, irowstride, irowstride, gusrc, -USE_THREADS);
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);
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);
10757 break;
10758 case WEED_PALETTE_ARGB32:
10759 convert_swap4_frame(gusrc, width, height, irowstride, irowstride, gusrc, -USE_THREADS);
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);
10852 break;
10853 case WEED_PALETTE_BGRA32:
10854 convert_swap4_frame(gusrc, width, height, irowstride, irowstride, gusrc, -USE_THREADS);
10856 break;
10857 case WEED_PALETTE_UYVY8888:
10858 weed_set_int_value(layer, WEED_LEAF_WIDTH, width >> 1);
10859 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10860 orowstride = weed_layer_get_rowstride(layer);
10861 gudest = weed_layer_get_pixel_data_packed(layer);
10862 convert_argb_to_uyvy_frame(gusrc, width, height, irowstride, orowstride, (uyvy_macropixel *)gudest, oclamping,
10863 create_gamma_lut(1.0, weed_layer_get_gamma(layer), new_gamma_type),
10864 -USE_THREADS);
10865 break;
10866 case WEED_PALETTE_YUYV8888:
10867 weed_set_int_value(layer, WEED_LEAF_WIDTH, width >> 1);
10868 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10869 orowstride = weed_layer_get_rowstride(layer);
10870 gudest = weed_layer_get_pixel_data_packed(layer);
10871 convert_argb_to_yuyv_frame(gusrc, width, height, irowstride, orowstride, (yuyv_macropixel *)gudest, oclamping,
10872 create_gamma_lut(1.0, weed_layer_get_gamma(layer), new_gamma_type),
10873 -USE_THREADS);
10874 break;
10875 case WEED_PALETTE_YUV888:
10876 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10877 gudest = weed_layer_get_pixel_data_packed(layer);
10878 orowstride = weed_layer_get_rowstride(layer);
10879 convert_argb_to_yuv_frame(gusrc, width, height, irowstride, orowstride, gudest, FALSE, oclamping, -USE_THREADS);
10880 break;
10881 case WEED_PALETTE_YUVA8888:
10882 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10883 gudest = weed_layer_get_pixel_data_packed(layer);
10884 orowstride = weed_layer_get_rowstride(layer);
10885 convert_argb_to_yuv_frame(gusrc, width, height, irowstride, orowstride, gudest, TRUE, oclamping, -USE_THREADS);
10886 break;
10887 case WEED_PALETTE_YUV444P:
10888 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10889 gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
10890 orowstride = weed_layer_get_rowstride(layer);
10891 convert_argb_to_yuvp_frame(gusrc, width, height, irowstride, orowstride, gudest_array, FALSE, oclamping, -USE_THREADS);
10892 break;
10893 case WEED_PALETTE_YUVA4444P:
10894 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10895 gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
10896 orowstride = weed_layer_get_rowstride(layer);
10897 convert_argb_to_yuvp_frame(gusrc, width, height, irowstride, orowstride, gudest_array, TRUE, oclamping, -USE_THREADS);
10898 break;
10899 case WEED_PALETTE_YUV422P:
10900 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10901 gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
10902 ostrides = weed_layer_get_rowstrides(layer, NULL);
10903 convert_argb_to_yuv420_frame(gusrc, width, height, irowstride, ostrides, gudest_array, TRUE,
10904 WEED_YUV_SAMPLING_DEFAULT, oclamping);
10905 weed_set_int_value(layer, WEED_LEAF_YUV_SAMPLING, WEED_YUV_SAMPLING_DEFAULT);
10906 break;
10907 case WEED_PALETTE_YUV420P:
10908 case WEED_PALETTE_YVU420P:
10909 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10910 gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
10911 ostrides = weed_layer_get_rowstrides(layer, NULL);
10912 convert_argb_to_yuv420_frame(gusrc, width, height, irowstride, ostrides, gudest_array, FALSE, osubspace, oclamping);
10913 weed_set_int_value(layer, WEED_LEAF_YUV_SAMPLING, WEED_YUV_SAMPLING_DEFAULT);
10914 break;
10915 case WEED_PALETTE_YUV411:
10916 weed_set_int_value(layer, WEED_LEAF_WIDTH, width >> 2);
10917 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10918 gudest = weed_layer_get_pixel_data_packed(layer);
10919 convert_argb_to_yuv411_frame(gusrc, width, height, irowstride, (yuv411_macropixel *)gudest, oclamping);
10920 break;
10921 default:
10922 lives_printerr("Invalid palette conversion: %s to %s not written yet !!\n", weed_palette_get_name(inpl),
10923 weed_palette_get_name(outpl));
10924 goto memfail;
10925 }
10926 break;
10927 case WEED_PALETTE_YUV444P:
10928 gusrc_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
10929 switch (outpl) {
10930 case WEED_PALETTE_YUV422P:
10931 if (!create_empty_pixel_data(layer, FALSE, FALSE)) goto memfail;
10932 gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
10933 lives_free(gudest_array[0]);
10934 gudest_array[0] = gusrc_array[0];
10935 weed_set_voidptr_array(layer, WEED_LEAF_PIXEL_DATA, 3, (void **)gudest_array);
10936 ostrides = weed_layer_get_rowstrides(layer, NULL);
10937 convert_halve_chroma(gusrc_array, width, height, istrides, ostrides, gudest_array, iclamping);
10938 gusrc_array[0] = NULL;
10939 weed_layer_set_pixel_data(orig_layer, (void **)gusrc_array, 3);
10940 break;
10941 case WEED_PALETTE_RGB24:
10942 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10943 orowstride = weed_layer_get_rowstride(layer);
10944 gudest = weed_layer_get_pixel_data_packed(layer);
10945 convert_yuv_planar_to_rgb_frame(gusrc_array, width, height, irowstride, orowstride, gudest, FALSE, FALSE, iclamping,
10946 -USE_THREADS);
10947 break;
10948 case WEED_PALETTE_RGBA32:
10949 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10950 orowstride = weed_layer_get_rowstride(layer);
10951 gudest = weed_layer_get_pixel_data_packed(layer);
10952 convert_yuv_planar_to_rgb_frame(gusrc_array, width, height, irowstride, orowstride, gudest, FALSE, TRUE, iclamping,
10953 -USE_THREADS);
10954 break;
10955 case WEED_PALETTE_BGR24:
10956 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10957 orowstride = weed_layer_get_rowstride(layer);
10958 gudest = weed_layer_get_pixel_data_packed(layer);
10959 convert_yuv_planar_to_bgr_frame(gusrc_array, width, height, irowstride, orowstride, gudest, FALSE, FALSE, iclamping,
10960 -USE_THREADS);
10961 break;
10962 case WEED_PALETTE_BGRA32:
10963 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10964 orowstride = weed_layer_get_rowstride(layer);
10965 gudest = weed_layer_get_pixel_data_packed(layer);
10966 convert_yuv_planar_to_bgr_frame(gusrc_array, width, height, irowstride, orowstride, gudest, FALSE, TRUE, iclamping,
10967 -USE_THREADS);
10968 break;
10969 case WEED_PALETTE_ARGB32:
10970 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10971 orowstride = weed_layer_get_rowstride(layer);
10972 gudest = weed_layer_get_pixel_data_packed(layer);
10973 convert_yuv_planar_to_argb_frame(gusrc_array, width, height, irowstride, orowstride, gudest, FALSE, iclamping, -USE_THREADS);
10974 break;
10975 case WEED_PALETTE_UYVY8888:
10976 weed_set_int_value(layer, WEED_LEAF_WIDTH, width >> 1);
10977 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10978 orowstride = weed_layer_get_rowstride(layer);
10979 gudest = weed_layer_get_pixel_data_packed(layer);
10980 convert_yuv_planar_to_uyvy_frame(gusrc_array, width, height, irowstride, orowstride, (uyvy_macropixel *)gudest, iclamping);
10981 break;
10982 case WEED_PALETTE_YUYV8888:
10983 weed_set_int_value(layer, WEED_LEAF_WIDTH, width >> 1);
10984 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10985 orowstride = weed_layer_get_rowstride(layer);
10986 gudest = weed_layer_get_pixel_data_packed(layer);
10987 convert_yuv_planar_to_yuyv_frame(gusrc_array, width, height, irowstride, orowstride, (yuyv_macropixel *)gudest, iclamping);
10988 break;
10989 case WEED_PALETTE_YUV888:
10990 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10991 gudest = weed_layer_get_pixel_data_packed(layer);
10992 orowstride = weed_layer_get_rowstride(layer);
10993 convert_combineplanes_frame(gusrc_array, width, height, irowstride, orowstride, gudest, FALSE, FALSE);
10994 break;
10995 case WEED_PALETTE_YUVA8888:
10996 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
10997 gudest = weed_layer_get_pixel_data_packed(layer);
10998 orowstride = weed_layer_get_rowstride(layer);
10999 convert_combineplanes_frame(gusrc_array, width, height, irowstride, orowstride, gudest, FALSE, TRUE);
11000 break;
11001 case WEED_PALETTE_YUVA4444P:
11002 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11003 gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
11004 orowstride = weed_layer_get_rowstride(layer);
11005 convert_yuvp_to_yuvap_frame(gusrc_array, width, height, irowstride, orowstride, gudest_array);
11006 break;
11007 case WEED_PALETTE_YUV420P:
11008 case WEED_PALETTE_YVU420P:
11009 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11010 gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
11011 ostrides = weed_layer_get_rowstrides(layer, NULL);
11012 convert_yuvp_to_yuv420_frame(gusrc_array, width, height, istrides, ostrides, gudest_array, iclamping);
11013 weed_set_int_value(layer, WEED_LEAF_YUV_SAMPLING, WEED_YUV_SAMPLING_DEFAULT);
11014 break;
11015 case WEED_PALETTE_YUV411:
11016 weed_set_int_value(layer, WEED_LEAF_WIDTH, width >> 2);
11017 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11018 gudest = weed_layer_get_pixel_data_packed(layer);
11019 convert_yuvp_to_yuv411_frame(gusrc_array, width, height, irowstride, (yuv411_macropixel *)gudest, iclamping);
11020 break;
11021 default:
11022 lives_printerr("Invalid palette conversion: %s to %s not written yet !!\n", weed_palette_get_name(inpl),
11023 weed_palette_get_name(outpl));
11024 goto memfail;
11025 }
11026 break;
11027 case WEED_PALETTE_YUVA4444P:
11028 gusrc_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
11029 switch (outpl) {
11030 case WEED_PALETTE_YUV422P:
11031 if (!create_empty_pixel_data(layer, FALSE, FALSE)) goto memfail;
11032 gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
11033 lives_free(gudest_array[0]);
11034 gudest_array[0] = gusrc_array[0];
11035 weed_set_voidptr_array(layer, WEED_LEAF_PIXEL_DATA, 3, (void **)gudest_array);
11036 ostrides = weed_layer_get_rowstrides(layer, NULL);
11037 convert_halve_chroma(gusrc_array, width, height, istrides, ostrides, gudest_array, iclamping);
11038 gusrc_array[0] = NULL;
11039 weed_layer_set_pixel_data(orig_layer, (void **)gusrc_array, 4);
11040 break;
11041 case WEED_PALETTE_RGB24:
11042 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11043 orowstride = weed_layer_get_rowstride(layer);
11044 gudest = weed_layer_get_pixel_data_packed(layer);
11045 convert_yuv_planar_to_rgb_frame(gusrc_array, width, height, irowstride, orowstride, gudest, TRUE, FALSE, iclamping,
11046 -USE_THREADS);
11047 break;
11048 case WEED_PALETTE_RGBA32:
11049 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11050 orowstride = weed_layer_get_rowstride(layer);
11051 gudest = weed_layer_get_pixel_data_packed(layer);
11052 convert_yuv_planar_to_rgb_frame(gusrc_array, width, height, irowstride, orowstride, gudest, TRUE, TRUE, iclamping,
11053 -USE_THREADS);
11054 break;
11055 case WEED_PALETTE_BGR24:
11056 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11057 orowstride = weed_layer_get_rowstride(layer);
11058 gudest = weed_layer_get_pixel_data_packed(layer);
11059 convert_yuv_planar_to_bgr_frame(gusrc_array, width, height, irowstride, orowstride, gudest, TRUE, FALSE, iclamping,
11060 -USE_THREADS);
11061 break;
11062 case WEED_PALETTE_BGRA32:
11063 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11064 orowstride = weed_layer_get_rowstride(layer);
11065 gudest = weed_layer_get_pixel_data_packed(layer);
11066 convert_yuv_planar_to_bgr_frame(gusrc_array, width, height, irowstride, orowstride, gudest, TRUE, TRUE, iclamping,
11067 -USE_THREADS);
11068 break;
11069 case WEED_PALETTE_ARGB32:
11070 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11071 orowstride = weed_layer_get_rowstride(layer);
11072 gudest = weed_layer_get_pixel_data_packed(layer);
11073 convert_yuv_planar_to_argb_frame(gusrc_array, width, height, irowstride, orowstride, gudest, TRUE, iclamping, -USE_THREADS);
11074 break;
11075 case WEED_PALETTE_UYVY8888:
11076 weed_set_int_value(layer, WEED_LEAF_WIDTH, width >> 1);
11077 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11078 orowstride = weed_layer_get_rowstride(layer);
11079 gudest = weed_layer_get_pixel_data_packed(layer);
11080 convert_yuv_planar_to_uyvy_frame(gusrc_array, width, height, irowstride, orowstride, (uyvy_macropixel *)gudest, iclamping);
11081 break;
11082 case WEED_PALETTE_YUYV8888:
11083 weed_set_int_value(layer, WEED_LEAF_WIDTH, width >> 1);
11084 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11085 orowstride = weed_layer_get_rowstride(layer);
11086 gudest = weed_layer_get_pixel_data_packed(layer);
11087 convert_yuv_planar_to_yuyv_frame(gusrc_array, width, height, irowstride, orowstride, (yuyv_macropixel *)gudest, iclamping);
11088 break;
11089 case WEED_PALETTE_YUV888:
11090 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11091 gudest = weed_layer_get_pixel_data_packed(layer);
11092 orowstride = weed_layer_get_rowstride(layer);
11093 convert_combineplanes_frame(gusrc_array, width, height, irowstride, orowstride, gudest, TRUE, FALSE);
11094 break;
11095 case WEED_PALETTE_YUVA8888:
11096 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11097 gudest = weed_layer_get_pixel_data_packed(layer);
11098 orowstride = weed_layer_get_rowstride(layer);
11099 convert_combineplanes_frame(gusrc_array, width, height, irowstride, orowstride, gudest, TRUE, TRUE);
11100 break;
11101 case WEED_PALETTE_YUV444P:
11102 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11103 gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
11104 orowstride = weed_layer_get_rowstride(layer);
11105 convert_yuvap_to_yuvp_frame(gusrc_array, width, height, irowstride, orowstride, gudest_array);
11106 break;
11107 case WEED_PALETTE_YUV420P:
11108 case WEED_PALETTE_YVU420P:
11109 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11110 gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
11111 ostrides = weed_layer_get_rowstrides(layer, NULL);
11112 convert_yuvp_to_yuv420_frame(gusrc_array, width, height, istrides, ostrides, gudest_array, iclamping);
11113 weed_set_int_value(layer, WEED_LEAF_YUV_SAMPLING, WEED_YUV_SAMPLING_DEFAULT);
11114 break;
11115 case WEED_PALETTE_YUV411:
11116 weed_set_int_value(layer, WEED_LEAF_WIDTH, width >> 2);
11117 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11118 gudest = weed_layer_get_pixel_data_packed(layer);
11119 convert_yuvp_to_yuv411_frame(gusrc_array, width, height, irowstride, (yuv411_macropixel *)gudest, iclamping);
11120 break;
11121 default:
11122 lives_printerr("Invalid palette conversion: %s to %s not written yet !!\n", weed_palette_get_name(inpl),
11123 weed_palette_get_name(outpl));
11124 goto memfail;
11125 }
11126 break;
11127 case WEED_PALETTE_UYVY8888:
11128 gusrc = weed_layer_get_pixel_data_packed(layer);
11129 switch (outpl) {
11130 case WEED_PALETTE_YUYV8888:
11131 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11132 orowstride = weed_layer_get_rowstride(layer);
11133 gudest = weed_layer_get_pixel_data_packed(layer);
11134 convert_swab_frame(gusrc, width, height, irowstride, orowstride, gudest, -USE_THREADS);
11135 break;
11136 case WEED_PALETTE_YUV422P:
11137 weed_set_int_value(layer, WEED_LEAF_WIDTH, width << 1);
11138 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11139 gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
11140 convert_uyvy_to_yuv422_frame((uyvy_macropixel *)gusrc, width, height, gudest_array);
11141 break;
11142 case WEED_PALETTE_RGB24:
11143 //weed_set_int_value(layer, WEED_LEAF_WIDTH, width << 1);
11144 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11145 gudest = weed_layer_get_pixel_data_packed(layer);
11146 orowstride = weed_layer_get_rowstride(layer);
11147 convert_uyvy_to_rgb_frame((uyvy_macropixel *)gusrc, width, height, irowstride, orowstride, gudest,
11148 FALSE, iclamping, isubspace, -USE_THREADS);
11149 break;
11150 case WEED_PALETTE_RGBA32:
11151 weed_set_int_value(layer, WEED_LEAF_WIDTH, width << 1);
11152 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11153 gudest = weed_layer_get_pixel_data_packed(layer);
11154 orowstride = weed_layer_get_rowstride(layer);
11155 convert_uyvy_to_rgb_frame((uyvy_macropixel *)gusrc, width, height, irowstride, orowstride, gudest,
11156 TRUE, iclamping, isampling, -USE_THREADS);
11157 break;
11158 case WEED_PALETTE_BGR24:
11159 weed_set_int_value(layer, WEED_LEAF_WIDTH, width << 1);
11160 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11161 gudest = weed_layer_get_pixel_data_packed(layer);
11162 orowstride = weed_layer_get_rowstride(layer);
11163 convert_uyvy_to_bgr_frame((uyvy_macropixel *)gusrc, width, height, irowstride, orowstride, gudest,
11164 FALSE, iclamping, -USE_THREADS);
11165 break;
11166 case WEED_PALETTE_BGRA32:
11167 weed_set_int_value(layer, WEED_LEAF_WIDTH, width << 1);
11168 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11169 gudest = weed_layer_get_pixel_data_packed(layer);
11170 orowstride = weed_layer_get_rowstride(layer);
11171 convert_uyvy_to_bgr_frame((uyvy_macropixel *)gusrc, width, height, irowstride, orowstride, gudest,
11172 TRUE, iclamping, -USE_THREADS);
11173 break;
11174 case WEED_PALETTE_ARGB32:
11175 weed_set_int_value(layer, WEED_LEAF_WIDTH, width << 1);
11176 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11177 gudest = weed_layer_get_pixel_data_packed(layer);
11178 orowstride = weed_layer_get_rowstride(layer);
11179 convert_uyvy_to_argb_frame((uyvy_macropixel *)gusrc, width, height, irowstride, orowstride,
11180 gudest, iclamping, -USE_THREADS);
11181 break;
11182 case WEED_PALETTE_YUV444P:
11183 weed_set_int_value(layer, WEED_LEAF_WIDTH, width << 1);
11184 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11185 gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
11186 ostrides = weed_layer_get_rowstrides(layer, NULL);
11187 convert_uyvy_to_yuvp_frame((uyvy_macropixel *)gusrc, width, height, irowstride, ostrides, gudest_array, FALSE);
11188 break;
11189 case WEED_PALETTE_YUVA4444P:
11190 weed_set_int_value(layer, WEED_LEAF_WIDTH, width << 1);
11191 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11192 gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
11193 ostrides = weed_layer_get_rowstrides(layer, NULL);
11194 convert_uyvy_to_yuvp_frame((uyvy_macropixel *)gusrc, width, height, irowstride, ostrides, gudest_array, TRUE);
11195 break;
11196 case WEED_PALETTE_YUV888:
11197 weed_set_int_value(layer, WEED_LEAF_WIDTH, width << 1);
11198 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11199 gudest = weed_layer_get_pixel_data_packed(layer);
11200 orowstride = weed_layer_get_rowstride(layer);
11201 convert_uyvy_to_yuv888_frame((uyvy_macropixel *)gusrc, width, height, irowstride, orowstride, gudest, FALSE);
11202 break;
11203 case WEED_PALETTE_YUVA8888:
11204 weed_set_int_value(layer, WEED_LEAF_WIDTH, width << 1);
11205 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11206 gudest = weed_layer_get_pixel_data_packed(layer);
11207 orowstride = weed_layer_get_rowstride(layer);
11208 convert_uyvy_to_yuv888_frame((uyvy_macropixel *)gusrc, width, height, irowstride, orowstride, gudest, TRUE);
11209 break;
11210 case WEED_PALETTE_YUV420P:
11211 case WEED_PALETTE_YVU420P:
11212 weed_set_int_value(layer, WEED_LEAF_WIDTH, width << 1);
11213 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11214 gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
11215 convert_uyvy_to_yuv420_frame((uyvy_macropixel *)gusrc, width, height, gudest_array, iclamping);
11216 weed_set_int_value(layer, WEED_LEAF_YUV_SAMPLING, WEED_YUV_SAMPLING_DEFAULT);
11217 break;
11218 case WEED_PALETTE_YUV411:
11219 weed_set_int_value(layer, WEED_LEAF_WIDTH, width >> 1);
11220 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11221 gudest = weed_layer_get_pixel_data_packed(layer);
11222 convert_uyvy_to_yuv411_frame((uyvy_macropixel *)gusrc, width, height, (yuv411_macropixel *)gudest, iclamping);
11223 break;
11224 default:
11225 lives_printerr("Invalid palette conversion: %s to %s not written yet !!\n", weed_palette_get_name(inpl),
11226 weed_palette_get_name(outpl));
11227 goto memfail;
11228 }
11229 break;
11230 case WEED_PALETTE_YUYV8888:
11231 gusrc = weed_layer_get_pixel_data_packed(layer);
11232 switch (outpl) {
11233 case WEED_PALETTE_UYVY8888:
11234 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11235 orowstride = weed_layer_get_rowstride(layer);
11236 gudest = weed_layer_get_pixel_data_packed(layer);
11237 convert_swab_frame(gusrc, width, height, irowstride, orowstride, gudest, -USE_THREADS);
11238 break;
11239 case WEED_PALETTE_YUV422P:
11240 weed_set_int_value(layer, WEED_LEAF_WIDTH, width << 1);
11241 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11242 gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
11243 convert_yuyv_to_yuv422_frame((yuyv_macropixel *)gusrc, width, height, gudest_array);
11244 break;
11245 case WEED_PALETTE_RGB24:
11246 weed_set_int_value(layer, WEED_LEAF_WIDTH, width << 1);
11247 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11248 gudest = weed_layer_get_pixel_data_packed(layer);
11249 orowstride = weed_layer_get_rowstride(layer);
11250 convert_yuyv_to_rgb_frame((yuyv_macropixel *)gusrc, width, height, irowstride, orowstride, gudest,
11251 FALSE, iclamping, -USE_THREADS);
11252 break;
11253 case WEED_PALETTE_RGBA32:
11254 weed_set_int_value(layer, WEED_LEAF_WIDTH, width << 1);
11255 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11256 gudest = weed_layer_get_pixel_data_packed(layer);
11257 orowstride = weed_layer_get_rowstride(layer);
11258 convert_yuyv_to_rgb_frame((yuyv_macropixel *)gusrc, width, height, irowstride, orowstride, gudest,
11259 TRUE, iclamping, -USE_THREADS);
11260 break;
11261 case WEED_PALETTE_BGR24:
11262 weed_set_int_value(layer, WEED_LEAF_WIDTH, width << 1);
11263 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11264 gudest = weed_layer_get_pixel_data_packed(layer);
11265 orowstride = weed_layer_get_rowstride(layer);
11266 convert_yuyv_to_bgr_frame((yuyv_macropixel *)gusrc, width, height, irowstride, orowstride, gudest,
11267 FALSE, iclamping, -USE_THREADS);
11268 break;
11269 case WEED_PALETTE_BGRA32:
11270 weed_set_int_value(layer, WEED_LEAF_WIDTH, width << 1);
11271 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11272 gudest = weed_layer_get_pixel_data_packed(layer);
11273 orowstride = weed_layer_get_rowstride(layer);
11274 convert_yuyv_to_bgr_frame((yuyv_macropixel *)gusrc, width, height, irowstride, orowstride, gudest,
11275 TRUE, iclamping, -USE_THREADS);
11276 break;
11277 case WEED_PALETTE_ARGB32:
11278 weed_set_int_value(layer, WEED_LEAF_WIDTH, width << 1);
11279 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11280 gudest = weed_layer_get_pixel_data_packed(layer);
11281 orowstride = weed_layer_get_rowstride(layer);
11282 convert_yuyv_to_argb_frame((yuyv_macropixel *)gusrc, width, height, irowstride, orowstride,
11283 gudest, iclamping, -USE_THREADS);
11284 break;
11285 case WEED_PALETTE_YUV444P:
11286 weed_set_int_value(layer, WEED_LEAF_WIDTH, width << 1);
11287 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11288 gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
11289 ostrides = weed_layer_get_rowstrides(layer, NULL);
11290 convert_yuyv_to_yuvp_frame((yuyv_macropixel *)gusrc, width, height, irowstride, ostrides, gudest_array, FALSE);
11291 break;
11292 case WEED_PALETTE_YUVA4444P:
11293 weed_set_int_value(layer, WEED_LEAF_WIDTH, width << 1);
11294 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11295 gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
11296 ostrides = weed_layer_get_rowstrides(layer, NULL);
11297 convert_yuyv_to_yuvp_frame((yuyv_macropixel *)gusrc, width, height, irowstride, ostrides, gudest_array, TRUE);
11298 break;
11299 case WEED_PALETTE_YUV888:
11300 weed_set_int_value(layer, WEED_LEAF_WIDTH, width << 1);
11301 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11302 gudest = weed_layer_get_pixel_data_packed(layer);
11303 orowstride = weed_layer_get_rowstride(layer);
11304 convert_yuyv_to_yuv888_frame((yuyv_macropixel *)gusrc, width, height, irowstride, orowstride, gudest, FALSE);
11305 break;
11306 case WEED_PALETTE_YUVA8888:
11307 weed_set_int_value(layer, WEED_LEAF_WIDTH, width << 1);
11308 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11309 gudest = weed_layer_get_pixel_data_packed(layer);
11310 orowstride = weed_layer_get_rowstride(layer);
11311 convert_yuyv_to_yuv888_frame((yuyv_macropixel *)gusrc, width, height, irowstride, orowstride, gudest, TRUE);
11312 break;
11313 case WEED_PALETTE_YUV420P:
11314 case WEED_PALETTE_YVU420P:
11315 weed_set_int_value(layer, WEED_LEAF_WIDTH, width << 1);
11316 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11317 gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
11318 convert_yuyv_to_yuv420_frame((yuyv_macropixel *)gusrc, width, height, gudest_array, iclamping);
11319 weed_set_int_value(layer, WEED_LEAF_YUV_SAMPLING, WEED_YUV_SAMPLING_DEFAULT);
11320 break;
11321 case WEED_PALETTE_YUV411:
11322 weed_set_int_value(layer, WEED_LEAF_WIDTH, width >> 1);
11323 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11324 gudest = weed_layer_get_pixel_data_packed(layer);
11325 convert_yuyv_to_yuv411_frame((yuyv_macropixel *)gusrc, width, height, (yuv411_macropixel *)gudest, iclamping);
11326 break;
11327 default:
11328 lives_printerr("Invalid palette conversion: %s to %s not written yet !!\n", weed_palette_get_name(inpl),
11329 weed_palette_get_name(outpl));
11330 goto memfail;
11331 }
11332 break;
11333 case WEED_PALETTE_YUV888:
11334 // need to check rowstrides (may have been resized)
11335 gusrc = weed_layer_get_pixel_data_packed(layer);
11336 switch (outpl) {
11337 case WEED_PALETTE_YUVA8888:
11338 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11339 gudest = weed_layer_get_pixel_data_packed(layer);
11340 orowstride = weed_layer_get_rowstride(layer);
11341 convert_addpost_frame(gusrc, width, height, irowstride, orowstride, gudest, NULL, -USE_THREADS);
11342 break;
11343 case WEED_PALETTE_YUV444P:
11344 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11345 gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
11346 ostrides = weed_layer_get_rowstrides(layer, NULL);
11347 convert_splitplanes_frame(gusrc, width, height, irowstride, ostrides, gudest_array, FALSE, FALSE);
11348 break;
11349 case WEED_PALETTE_YUVA4444P:
11350 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11351 gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
11352 ostrides = weed_layer_get_rowstrides(layer, NULL);
11353 convert_splitplanes_frame(gusrc, width, height, irowstride, ostrides, gudest_array, FALSE, TRUE);
11354 break;
11355 case WEED_PALETTE_RGB24:
11356 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11357 orowstride = weed_layer_get_rowstride(layer);
11358 gudest = weed_layer_get_pixel_data_packed(layer);
11359 convert_yuv888_to_rgb_frame(gusrc, width, height, irowstride, orowstride, gudest, FALSE, iclamping, isampling, -USE_THREADS);
11360 break;
11361 case WEED_PALETTE_RGBA32:
11362 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11363 orowstride = weed_layer_get_rowstride(layer);
11364 gudest = weed_layer_get_pixel_data_packed(layer);
11365 convert_yuv888_to_rgb_frame(gusrc, width, height, irowstride, orowstride, gudest, TRUE, iclamping, isampling, -USE_THREADS);
11366 break;
11367 case WEED_PALETTE_BGR24:
11368 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11369 orowstride = weed_layer_get_rowstride(layer);
11370 gudest = weed_layer_get_pixel_data_packed(layer);
11371 convert_yuv888_to_bgr_frame(gusrc, width, height, irowstride, orowstride, gudest, FALSE, iclamping, isampling, -USE_THREADS);
11372 break;
11373 case WEED_PALETTE_BGRA32:
11374 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11375 orowstride = weed_layer_get_rowstride(layer);
11376 gudest = weed_layer_get_pixel_data_packed(layer);
11377 convert_yuv888_to_bgr_frame(gusrc, width, height, irowstride, orowstride, gudest, TRUE, iclamping, isampling, -USE_THREADS);
11378 break;
11379 case WEED_PALETTE_ARGB32:
11380 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11381 orowstride = weed_layer_get_rowstride(layer);
11382 gudest = weed_layer_get_pixel_data_packed(layer);
11383 convert_yuv888_to_argb_frame(gusrc, width, height, irowstride, orowstride, gudest, iclamping, isampling, -USE_THREADS);
11384 break;
11385 case WEED_PALETTE_YVU420P:
11386 case WEED_PALETTE_YUV420P:
11387 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11388 gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
11389 ostrides = weed_get_int_array(layer, WEED_LEAF_ROWSTRIDES, &error);
11390 convert_yuv888_to_yuv420_frame(gusrc, width, height, irowstride, ostrides, gudest_array, FALSE, iclamping);
11391 weed_set_int_value(layer, WEED_LEAF_YUV_SAMPLING, WEED_YUV_SAMPLING_DEFAULT);
11392 //weed_set_int_value(layer,WEED_LEAF_YUV_SAMPLING,osampling);
11393 break;
11394 case WEED_PALETTE_YUV422P:
11395 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11396 gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
11397 ostrides = weed_get_int_array(layer, WEED_LEAF_ROWSTRIDES, &error);
11398 convert_yuv888_to_yuv422_frame(gusrc, width, height, irowstride, ostrides, gudest_array, FALSE, iclamping);
11399 break;
11400 case WEED_PALETTE_UYVY8888:
11401 weed_set_int_value(layer, WEED_LEAF_WIDTH, width >> 1);
11402 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11403 orowstride = weed_layer_get_rowstride(layer);
11404 gudest = weed_layer_get_pixel_data_packed(layer);
11405 convert_yuv888_to_uyvy_frame(gusrc, width, height, irowstride, orowstride, (uyvy_macropixel *)gudest, FALSE, iclamping);
11406 break;
11407 case WEED_PALETTE_YUYV8888:
11408 weed_set_int_value(layer, WEED_LEAF_WIDTH, width >> 1);
11409 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11410 orowstride = weed_layer_get_rowstride(layer);
11411 gudest = weed_layer_get_pixel_data_packed(layer);
11412 convert_yuv888_to_yuyv_frame(gusrc, width, height, irowstride, orowstride, (yuyv_macropixel *)gudest, FALSE, iclamping);
11413 break;
11414 case WEED_PALETTE_YUV411:
11415 weed_set_int_value(layer, WEED_LEAF_WIDTH, width >> 2);
11416 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11417 gudest = weed_layer_get_pixel_data_packed(layer);
11418 convert_yuv888_to_yuv411_frame(gusrc, width, height, irowstride, (yuv411_macropixel *)gudest, FALSE);
11419 break;
11420 default:
11421 lives_printerr("Invalid palette conversion: %s to %s not written yet !!\n", weed_palette_get_name(inpl),
11422 weed_palette_get_name(outpl));
11423 goto memfail;
11424 }
11425 break;
11426 case WEED_PALETTE_YUVA8888:
11427 gusrc = weed_layer_get_pixel_data_packed(layer);
11428 switch (outpl) {
11429 case WEED_PALETTE_YUV888:
11430 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11431 gudest = weed_layer_get_pixel_data_packed(layer);
11432 orowstride = weed_layer_get_rowstride(layer);
11433 convert_delpost_frame(gusrc, width, height, irowstride, orowstride, gudest, NULL, -USE_THREADS);
11434 break;
11435 case WEED_PALETTE_YUVA4444P:
11436 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11437 gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
11438 ostrides = weed_layer_get_rowstrides(layer, NULL);
11439 convert_splitplanes_frame(gusrc, width, height, irowstride, ostrides, gudest_array, TRUE, TRUE);
11440 break;
11441 case WEED_PALETTE_YUV444P:
11442 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11443 gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
11444 ostrides = weed_layer_get_rowstrides(layer, NULL);
11445 convert_splitplanes_frame(gusrc, width, height, irowstride, ostrides, gudest_array, TRUE, FALSE);
11446 break;
11447 case WEED_PALETTE_RGB24:
11448 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11449 orowstride = weed_layer_get_rowstride(layer);
11450 gudest = weed_layer_get_pixel_data_packed(layer);
11451 convert_yuva8888_to_rgba_frame(gusrc, width, height, irowstride, orowstride, gudest, TRUE, iclamping, isampling, -USE_THREADS);
11452 break;
11453 case WEED_PALETTE_RGBA32:
11454 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11455 orowstride = weed_layer_get_rowstride(layer);
11456 gudest = weed_layer_get_pixel_data_packed(layer);
11457 convert_yuva8888_to_rgba_frame(gusrc, width, height, irowstride, orowstride, gudest, FALSE, iclamping, isampling, -USE_THREADS);
11458 break;
11459 case WEED_PALETTE_BGR24:
11460 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11461 orowstride = weed_layer_get_rowstride(layer);
11462 gudest = weed_layer_get_pixel_data_packed(layer);
11463 convert_yuva8888_to_bgra_frame(gusrc, width, height, irowstride, orowstride, gudest, TRUE, iclamping, isampling, -USE_THREADS);
11464 break;
11465 case WEED_PALETTE_BGRA32:
11466 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11467 orowstride = weed_layer_get_rowstride(layer);
11468 gudest = weed_layer_get_pixel_data_packed(layer);
11469 convert_yuva8888_to_bgra_frame(gusrc, width, height, irowstride, orowstride, gudest, FALSE, iclamping, isampling, -USE_THREADS);
11470 break;
11471 case WEED_PALETTE_ARGB32:
11472 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11473 orowstride = weed_layer_get_rowstride(layer);
11474 gudest = weed_layer_get_pixel_data_packed(layer);
11475 convert_yuva8888_to_argb_frame(gusrc, width, height, irowstride, orowstride, gudest, iclamping, isampling, -USE_THREADS);
11476 break;
11477 case WEED_PALETTE_YUV420P:
11478 case WEED_PALETTE_YVU420P:
11479 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11480 gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
11481 ostrides = weed_layer_get_rowstrides(layer, NULL);
11482 convert_yuv888_to_yuv420_frame(gusrc, width, height, irowstride, ostrides, gudest_array, TRUE, iclamping);
11483 weed_set_int_value(layer, WEED_LEAF_YUV_SAMPLING, WEED_YUV_SAMPLING_DEFAULT);
11484 //weed_set_int_value(layer,WEED_LEAF_YUV_SAMPLING,osampling);
11485 break;
11486 case WEED_PALETTE_YUV422P:
11487 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11488 gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
11489 ostrides = weed_layer_get_rowstrides(layer, NULL);
11490 convert_yuv888_to_yuv422_frame(gusrc, width, height, irowstride, ostrides, gudest_array, TRUE, iclamping);
11491 break;
11492 case WEED_PALETTE_UYVY8888:
11493 weed_set_int_value(layer, WEED_LEAF_WIDTH, width >> 1);
11494 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11495 orowstride = weed_layer_get_rowstride(layer);
11496 gudest = weed_layer_get_pixel_data_packed(layer);
11497 convert_yuv888_to_uyvy_frame(gusrc, width, height, irowstride, orowstride, (uyvy_macropixel *)gudest, TRUE, iclamping);
11498 break;
11499 case WEED_PALETTE_YUYV8888:
11500 weed_set_int_value(layer, WEED_LEAF_WIDTH, width >> 1);
11501 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11502 orowstride = weed_layer_get_rowstride(layer);
11503 gudest = weed_layer_get_pixel_data_packed(layer);
11504 convert_yuv888_to_yuyv_frame(gusrc, width, height, irowstride, orowstride, (yuyv_macropixel *)gudest, TRUE, iclamping);
11505 break;
11506 case WEED_PALETTE_YUV411:
11507 weed_set_int_value(layer, WEED_LEAF_WIDTH, width >> 2);
11508 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11509 gudest = weed_layer_get_pixel_data_packed(layer);
11510 convert_yuv888_to_yuv411_frame(gusrc, width, height, irowstride, (yuv411_macropixel *)gudest, TRUE);
11511 break;
11512 default:
11513 lives_printerr("Invalid palette conversion: %s to %s not written yet !!\n", weed_palette_get_name(inpl),
11514 weed_palette_get_name(outpl));
11515 goto memfail;
11516 }
11517 break;
11518 case WEED_PALETTE_YVU420P:
11519 case WEED_PALETTE_YUV420P:
11520 gusrc_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
11521 switch (outpl) {
11522 case WEED_PALETTE_RGB24:
11523 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11524 orowstride = weed_layer_get_rowstride(layer);
11525 gudest = weed_layer_get_pixel_data_packed(layer);
11526 convert_yuv420p_to_rgb_frame(gusrc_array, width, height, TRUE, istrides, orowstride, gudest, FALSE, FALSE,
11527 isampling, iclamping, isubspace, weed_layer_get_gamma(layer), new_gamma_type, NULL, -USE_THREADS);
11528 break;
11529 case WEED_PALETTE_RGBA32:
11530 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11531 orowstride = weed_layer_get_rowstride(layer);
11532 gudest = weed_layer_get_pixel_data_packed(layer);
11533 convert_yuv420p_to_rgb_frame(gusrc_array, width, height, TRUE, istrides, orowstride, gudest, TRUE, FALSE,
11534 isampling, iclamping, isubspace, weed_layer_get_gamma(layer), new_gamma_type, NULL, -USE_THREADS);
11535 break;
11536 case WEED_PALETTE_BGR24:
11537 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11538 orowstride = weed_layer_get_rowstride(layer);
11539 gudest = weed_layer_get_pixel_data_packed(layer);
11540 convert_yuv420p_to_bgr_frame(gusrc_array, width, height, TRUE, istrides, orowstride, gudest, FALSE, FALSE,
11541 isampling, iclamping, isubspace, weed_layer_get_gamma(layer), new_gamma_type, NULL, -USE_THREADS);
11542 break;
11543 case WEED_PALETTE_BGRA32:
11544 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11545 orowstride = weed_layer_get_rowstride(layer);
11546 gudest = weed_layer_get_pixel_data_packed(layer);
11547 convert_yuv420p_to_bgr_frame(gusrc_array, width, height, TRUE, istrides, orowstride, gudest, TRUE, FALSE,
11548 isampling, iclamping, isubspace, weed_layer_get_gamma(layer), new_gamma_type, NULL, -USE_THREADS);
11549 break;
11550 case WEED_PALETTE_ARGB32:
11551 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11552 orowstride = weed_layer_get_rowstride(layer);
11553 gudest = weed_layer_get_pixel_data_packed(layer);
11554 convert_yuv420p_to_argb_frame(gusrc_array, width, height, TRUE, istrides, orowstride, gudest, FALSE,
11555 isampling, iclamping, isubspace, weed_layer_get_gamma(layer), new_gamma_type, NULL, -USE_THREADS);
11556 break;
11557 case WEED_PALETTE_UYVY8888:
11558 weed_set_int_value(layer, WEED_LEAF_WIDTH, width >> 1);
11559 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11560 orowstride = weed_layer_get_rowstride(layer);
11561 gudest = weed_layer_get_pixel_data_packed(layer);
11562 convert_yuv420_to_uyvy_frame(gusrc_array, width, height, istrides, orowstride, (uyvy_macropixel *)gudest, iclamping);
11563 break;
11564 case WEED_PALETTE_YUYV8888:
11565 weed_set_int_value(layer, WEED_LEAF_WIDTH, width >> 1);
11566 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11567 orowstride = weed_layer_get_rowstride(layer);
11568 gudest = weed_layer_get_pixel_data_packed(layer);
11569 convert_yuv420_to_yuyv_frame(gusrc_array, width, height, istrides, orowstride, (yuyv_macropixel *)gudest, iclamping);
11570 break;
11571 case WEED_PALETTE_YUV422P:
11573 gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
11574 lives_free(gudest_array[0]);
11575 gudest_array[0] = gusrc_array[0];
11576 weed_set_voidptr_array(layer, WEED_LEAF_PIXEL_DATA, 3, (void **)gudest_array);
11577 ostrides = weed_layer_get_rowstrides(layer, NULL);
11578 convert_double_chroma(gusrc_array, width >> 1, height >> 1, istrides, ostrides, gudest_array, iclamping);
11579 gusrc_array[0] = NULL;
11580 weed_layer_set_pixel_data(orig_layer, (void **)gusrc_array, 3);
11581 break;
11582 case WEED_PALETTE_YUV444P:
11584 gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
11585 lives_free(gudest_array[0]);
11586 gudest_array[0] = gusrc_array[0];
11587 weed_set_voidptr_array(layer, WEED_LEAF_PIXEL_DATA, 3, (void **)gudest_array);
11588 orowstride = weed_layer_get_rowstride(layer);
11589 convert_quad_chroma(gusrc_array, width, height, istrides, orowstride, gudest_array, FALSE, isampling, iclamping);
11590 gusrc_array[0] = NULL;
11591 weed_layer_set_pixel_data(orig_layer, (void **)gusrc_array, 3);
11592 break;
11593 case WEED_PALETTE_YUVA4444P:
11595 gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
11596 lives_free(gudest_array[0]);
11597 gudest_array[0] = gusrc_array[0];
11598 weed_set_voidptr_array(layer, WEED_LEAF_PIXEL_DATA, 4, (void **)gudest_array);
11599 orowstride = weed_layer_get_rowstride(layer);
11600 convert_quad_chroma(gusrc_array, width, height, istrides, orowstride, gudest_array, TRUE, isampling, iclamping);
11601 gusrc_array[0] = NULL;
11602 weed_layer_set_pixel_data(orig_layer, (void **)gusrc_array, 3);
11603 break;
11604 case WEED_PALETTE_YVU420P:
11605 case WEED_PALETTE_YUV420P:
11606 if (contig && istrides[1] != istrides[2]) {
11607 uint8_t *gd0, *gd1, *gd2, *gs0 = gusrc_array[0], *gs1 = gusrc_array[1], *gs2 = gusrc_array[2];
11608 size_t hwidth = width >> 1;
11609 size_t ir0 = istrides[0] - width, ir1 = istrides[1] - hwidth, ir2 = istrides[2] - hwidth, or0, or1, or2;
11610 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11611 ostrides = weed_layer_get_rowstrides(layer, NULL);
11612 or0 = ostrides[0] - width;
11613 or1 = ostrides[1] - hwidth;
11614 or2 = ostrides[2] - hwidth;
11615 gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
11616 gd0 = gudest_array[0];
11617 gd1 = gudest_array[1];
11618 gd2 = gudest_array[2];
11619 for (int i = 0; i < height; i++) {
11620 lives_memcpy(gd0, gs0, width);
11621 gd0 += or0;
11622 gs0 += ir0;
11623 lives_memcpy(gd1, gs1, hwidth);
11624 gd1 += or1;
11625 gs1 += ir1;
11626 lives_memcpy(gd2, gs2, hwidth);
11627 gd2 += or2;
11628 gs2 += ir2;
11629 i++;
11630 lives_memcpy(gd0, gs0, width);
11631 gd0 += or0;
11632 gs0 += ir0;
11633 }
11634 break;
11635 } else {
11637 size_t frmsz = istrides[1] * (height >> 1);
11639 swap_chroma_planes(layer);
11640 if (!(tmp = lives_calloc_safety(frmsz, 1))) goto memfail;
11642 lives_memcpy(tmp, (void **)gusrc_array[1], frmsz); // v plane
11643 lives_memcpy(gusrc_array[1], (void **)gusrc_array[2], frmsz); //u -> v
11644 lives_memcpy(gusrc_array[2], tmp, frmsz); // v -> u
11645 lives_free(tmp);
11646 }
11647 break;
11648 case WEED_PALETTE_YUV888:
11649 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11650 gudest = weed_layer_get_pixel_data_packed(layer);
11651 orowstride = weed_layer_get_rowstride(layer);
11652 convert_quad_chroma_packed(gusrc_array, width, height, istrides, orowstride, gudest, FALSE, isampling, iclamping);
11653 break;
11654 case WEED_PALETTE_YUVA8888:
11655 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11656 gudest = weed_layer_get_pixel_data_packed(layer);
11657 orowstride = weed_layer_get_rowstride(layer);
11658 convert_quad_chroma_packed(gusrc_array, width, height, istrides, orowstride, gudest, TRUE, isampling, iclamping);
11659 break;
11660 case WEED_PALETTE_YUV411:
11661 weed_set_int_value(layer, WEED_LEAF_WIDTH, width >> 2);
11662 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11663 gudest = weed_layer_get_pixel_data_packed(layer);
11664 convert_yuv420_to_yuv411_frame(gusrc_array, width, height, (yuv411_macropixel *)gudest, FALSE, iclamping);
11665 break;
11666 default:
11667 lives_printerr("Invalid palette conversion: %s to %s not written yet !!\n", weed_palette_get_name(inpl),
11668 weed_palette_get_name(outpl));
11669 goto memfail;
11670 }
11671 break;
11672 case WEED_PALETTE_YUV422P:
11673 gusrc_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
11674 switch (outpl) {
11675 case WEED_PALETTE_RGB24:
11676 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11677 orowstride = weed_layer_get_rowstride(layer);
11678 gudest = weed_layer_get_pixel_data_packed(layer);
11679 convert_yuv420p_to_rgb_frame(gusrc_array, width, height, TRUE, istrides, orowstride, gudest, FALSE, TRUE,
11680 isampling, iclamping, isubspace, weed_layer_get_gamma(layer), new_gamma_type, NULL, -USE_THREADS);
11681 break;
11682 case WEED_PALETTE_RGBA32:
11683 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11684 orowstride = weed_layer_get_rowstride(layer);
11685 gudest = weed_layer_get_pixel_data_packed(layer);
11686 convert_yuv420p_to_rgb_frame(gusrc_array, width, height, TRUE, istrides, orowstride, gudest, TRUE, TRUE,
11687 isampling, iclamping, isubspace, weed_layer_get_gamma(layer), new_gamma_type, NULL, -USE_THREADS);
11688 break;
11689 case WEED_PALETTE_BGR24:
11690 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11691 orowstride = weed_layer_get_rowstride(layer);
11692 gudest = weed_layer_get_pixel_data_packed(layer);
11693 convert_yuv420p_to_bgr_frame(gusrc_array, width, height, TRUE, istrides, orowstride, gudest, FALSE, TRUE,
11694 isampling, iclamping, isubspace, weed_layer_get_gamma(layer), new_gamma_type, NULL, -USE_THREADS);
11695 break;
11696 case WEED_PALETTE_BGRA32:
11697 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11698 orowstride = weed_layer_get_rowstride(layer);
11699 gudest = weed_layer_get_pixel_data_packed(layer);
11700 convert_yuv420p_to_bgr_frame(gusrc_array, width, height, TRUE, istrides, orowstride, gudest, TRUE, TRUE,
11701 isampling, iclamping, isubspace, weed_layer_get_gamma(layer), new_gamma_type, NULL, -USE_THREADS);
11702 break;
11703 case WEED_PALETTE_ARGB32:
11704 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11705 orowstride = weed_layer_get_rowstride(layer);
11706 gudest = weed_layer_get_pixel_data_packed(layer);
11707 convert_yuv420p_to_argb_frame(gusrc_array, width, height, TRUE, istrides, orowstride, gudest, TRUE,
11708 isampling, iclamping, isubspace, weed_layer_get_gamma(layer), new_gamma_type, NULL, -USE_THREADS);
11709 break;
11710 case WEED_PALETTE_UYVY8888:
11711 weed_set_int_value(layer, WEED_LEAF_WIDTH, width >> 1);
11712 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11713 orowstride = weed_layer_get_rowstride(layer);
11714 gudest = weed_layer_get_pixel_data_packed(layer);
11715 convert_yuv422p_to_uyvy_frame(gusrc_array, width, height, istrides, orowstride, gudest);
11716 break;
11717 case WEED_PALETTE_YUYV8888:
11718 weed_set_int_value(layer, WEED_LEAF_WIDTH, width >> 1);
11719 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11720 orowstride = weed_layer_get_rowstride(layer);
11721 gudest = weed_layer_get_pixel_data_packed(layer);
11722 convert_yuv422p_to_yuyv_frame(gusrc_array, width, height, istrides, orowstride, gudest);
11723 break;
11724 case WEED_PALETTE_YUV420P:
11725 case WEED_PALETTE_YVU420P:
11727 gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
11728 lives_free(gudest_array[0]);
11729 gudest_array[0] = gusrc_array[0];
11730 weed_set_voidptr_array(layer, WEED_LEAF_PIXEL_DATA, 3, (void **)gudest_array);
11731 ostrides = weed_layer_get_rowstrides(layer, NULL);
11732 convert_halve_chroma(gusrc_array, width >> 1, height >> 1, istrides, ostrides, gudest_array, iclamping);
11733 gusrc_array[0] = NULL;
11734 weed_layer_set_pixel_data(orig_layer, (void **)gusrc_array, 3);
11735 weed_set_int_value(layer, WEED_LEAF_YUV_SAMPLING, isampling);
11736 break;
11737 case WEED_PALETTE_YUV444P:
11739 gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
11740 lives_free(gudest_array[0]);
11741 gudest_array[0] = gusrc_array[0];
11742 weed_set_voidptr_array(layer, WEED_LEAF_PIXEL_DATA, 3, (void **)gudest_array);
11743 ostrides = weed_layer_get_rowstrides(layer, NULL);
11744 convert_double_chroma(gusrc_array, width >> 1, height >> 1, istrides, ostrides, gudest_array, iclamping);
11745 gusrc_array[0] = NULL;
11746 weed_layer_set_pixel_data(orig_layer, (void **)gusrc_array, 3);
11747 break;
11748 case WEED_PALETTE_YUVA4444P:
11750 gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
11751 lives_free(gudest_array[0]);
11752 gudest_array[0] = gusrc_array[0];
11753 weed_set_voidptr_array(layer, WEED_LEAF_PIXEL_DATA, 4, (void **)gudest_array);
11754 ostrides = weed_layer_get_rowstrides(layer, NULL);
11755 convert_double_chroma(gusrc_array, width >> 1, height >> 1, istrides, ostrides, gudest_array, iclamping);
11756 lives_memset(gudest_array[3], 255, width * height);
11757 gusrc_array[0] = NULL;
11758 weed_layer_set_pixel_data(orig_layer, (void **)gusrc_array, 3);
11759 break;
11760 case WEED_PALETTE_YUV888:
11761 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11762 gudest = weed_layer_get_pixel_data_packed(layer);
11763 orowstride = weed_layer_get_rowstride(layer);
11764 convert_double_chroma_packed(gusrc_array, width, height, istrides, orowstride, gudest, FALSE, isampling, iclamping);
11765 break;
11766 case WEED_PALETTE_YUVA8888:
11767 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11768 gudest = weed_layer_get_pixel_data_packed(layer);
11769 orowstride = weed_layer_get_rowstride(layer);
11770 convert_double_chroma_packed(gusrc_array, width, height, istrides, orowstride, gudest, TRUE, isampling, iclamping);
11771 break;
11772 case WEED_PALETTE_YUV411:
11773 weed_set_int_value(layer, WEED_LEAF_WIDTH, width >> 2);
11774 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11775 gudest = weed_layer_get_pixel_data_packed(layer);
11776 convert_yuv420_to_yuv411_frame(gusrc_array, width, height, (yuv411_macropixel *)gudest, TRUE, iclamping);
11777 break;
11778 default:
11779 lives_printerr("Invalid palette conversion: %s to %s not written yet !!\n", weed_palette_get_name(inpl),
11780 weed_palette_get_name(outpl));
11781 goto memfail;
11782 }
11783 break;
11784 case WEED_PALETTE_YUV411:
11785 gusrc = weed_layer_get_pixel_data_packed(layer);
11786 switch (outpl) {
11787 case WEED_PALETTE_RGB24:
11788 weed_set_int_value(layer, WEED_LEAF_WIDTH, width << 2);
11789 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11790 orowstride = weed_layer_get_rowstride(layer);
11791 gudest = weed_layer_get_pixel_data_packed(layer);
11792 convert_yuv411_to_rgb_frame((yuv411_macropixel *)gusrc, width, height, orowstride, gudest, FALSE, iclamping);
11793 break;
11794 case WEED_PALETTE_RGBA32:
11795 weed_set_int_value(layer, WEED_LEAF_WIDTH, width << 2);
11796 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11797 orowstride = weed_layer_get_rowstride(layer);
11798 gudest = weed_layer_get_pixel_data_packed(layer);
11799 convert_yuv411_to_rgb_frame((yuv411_macropixel *)gusrc, width, height, orowstride, gudest, TRUE, iclamping);
11800 break;
11801 case WEED_PALETTE_BGR24:
11802 weed_set_int_value(layer, WEED_LEAF_WIDTH, width << 2);
11803 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11804 orowstride = weed_layer_get_rowstride(layer);
11805 gudest = weed_layer_get_pixel_data_packed(layer);
11806 convert_yuv411_to_bgr_frame((yuv411_macropixel *)gusrc, width, height, orowstride, gudest, FALSE, iclamping);
11807 break;
11808 case WEED_PALETTE_BGRA32:
11809 weed_set_int_value(layer, WEED_LEAF_WIDTH, width << 2);
11810 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11811 orowstride = weed_layer_get_rowstride(layer);
11812 gudest = weed_layer_get_pixel_data_packed(layer);
11813 convert_yuv411_to_bgr_frame((yuv411_macropixel *)gusrc, width, height, orowstride, gudest, TRUE, iclamping);
11814 break;
11815 case WEED_PALETTE_ARGB32:
11816 weed_set_int_value(layer, WEED_LEAF_WIDTH, width << 2);
11817 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11818 orowstride = weed_layer_get_rowstride(layer);
11819 gudest = weed_layer_get_pixel_data_packed(layer);
11820 convert_yuv411_to_argb_frame((yuv411_macropixel *)gusrc, width, height, orowstride, gudest, iclamping);
11821 break;
11822 case WEED_PALETTE_YUV888:
11823 weed_set_int_value(layer, WEED_LEAF_WIDTH, width << 2);
11824 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11825 gudest = weed_layer_get_pixel_data_packed(layer);
11826 convert_yuv411_to_yuv888_frame((yuv411_macropixel *)gusrc, width, height, gudest, FALSE, iclamping);
11827 break;
11828 case WEED_PALETTE_YUVA8888:
11829 weed_set_int_value(layer, WEED_LEAF_WIDTH, width << 2);
11830 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11831 gudest = weed_layer_get_pixel_data_packed(layer);
11832 convert_yuv411_to_yuv888_frame((yuv411_macropixel *)gusrc, width, height, gudest, TRUE, iclamping);
11833 break;
11834 case WEED_PALETTE_YUV444P:
11835 weed_set_int_value(layer, WEED_LEAF_WIDTH, width << 2);
11836 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11837 gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
11838 convert_yuv411_to_yuvp_frame((yuv411_macropixel *)gusrc, width, height, gudest_array, FALSE, iclamping);
11839 break;
11840 case WEED_PALETTE_YUVA4444P:
11841 weed_set_int_value(layer, WEED_LEAF_WIDTH, width << 2);
11842 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11843 gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
11844 convert_yuv411_to_yuvp_frame((yuv411_macropixel *)gusrc, width, height, gudest_array, TRUE, iclamping);
11845 break;
11846 case WEED_PALETTE_UYVY8888:
11847 weed_set_int_value(layer, WEED_LEAF_WIDTH, width << 1);
11848 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11849 gudest = weed_layer_get_pixel_data_packed(layer);
11850 convert_yuv411_to_uyvy_frame((yuv411_macropixel *)gusrc, width, height, (uyvy_macropixel *)gudest, iclamping);
11851 break;
11852 case WEED_PALETTE_YUYV8888:
11853 weed_set_int_value(layer, WEED_LEAF_WIDTH, width << 1);
11854 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11855 gudest = weed_layer_get_pixel_data_packed(layer);
11856 convert_yuv411_to_yuyv_frame((yuv411_macropixel *)gusrc, width, height, (yuyv_macropixel *)gudest, iclamping);
11857 break;
11858 case WEED_PALETTE_YUV422P:
11859 weed_set_int_value(layer, WEED_LEAF_WIDTH, width << 2);
11860 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11861 gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
11862 convert_yuv411_to_yuv422_frame((yuv411_macropixel *)gusrc, width, height, gudest_array, iclamping);
11863 break;
11864 case WEED_PALETTE_YUV420P:
11865 weed_set_int_value(layer, WEED_LEAF_WIDTH, width << 2);
11866 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11867 gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
11868 convert_yuv411_to_yuv420_frame((yuv411_macropixel *)gusrc, width, height, gudest_array, FALSE, iclamping);
11869 break;
11870 case WEED_PALETTE_YVU420P:
11871 weed_set_int_value(layer, WEED_LEAF_WIDTH, width << 2);
11872 if (!create_empty_pixel_data(layer, FALSE, TRUE)) goto memfail;
11873 gudest_array = (uint8_t **)weed_layer_get_pixel_data(layer, NULL);
11874 convert_yuv411_to_yuv420_frame((yuv411_macropixel *)gusrc, width, height, gudest_array, TRUE, iclamping);
11875 break;
11876 default:
11877 lives_printerr("Invalid palette conversion: %s to %s not written yet !!\n", weed_palette_get_name(inpl),
11878 weed_palette_get_name(outpl));
11879 goto memfail;
11880 }
11881 break;
11882 default:
11883 lives_printerr("Invalid palette conversion: %s to %s not written yet !!\n", weed_palette_get_name(inpl),
11884 weed_palette_get_name(outpl));
11885 goto memfail;
11886 }
11887
11888#ifdef WEED_ADVANCED_PALETTES
11889conv_done:
11890#endif
11891
11892 lives_freep((void **)&ostrides);
11893 lives_freep((void **)&gusrc_array);
11894
11895 //lives_freep((void **)&gudest_array);
11896
11897 if (orig_layer) weed_layer_free(orig_layer);
11898
11899 if (new_gamma_type != WEED_GAMMA_UNKNOWN && can_inline_gamma(inpl, outpl)) {
11900 weed_layer_set_gamma(layer, new_gamma_type);
11901 }
11902
11903 if (weed_palette_is_rgb(outpl)) {
11904 weed_leaf_delete(layer, WEED_LEAF_YUV_CLAMPING);
11905 weed_leaf_delete(layer, WEED_LEAF_YUV_SUBSPACE);
11906 weed_leaf_delete(layer, WEED_LEAF_YUV_SAMPLING);
11907 } else {
11908 weed_set_int_value(layer, WEED_LEAF_YUV_CLAMPING, oclamping);
11909 if (weed_palette_is_rgb(inpl)) {
11910 if (weed_layer_get_gamma(layer) == WEED_GAMMA_BT709)
11911 weed_set_int_value(layer, WEED_LEAF_YUV_SUBSPACE, WEED_YUV_SUBSPACE_BT709);
11912 else
11913 weed_set_int_value(layer, WEED_LEAF_YUV_SUBSPACE, WEED_YUV_SUBSPACE_YCBCR);
11914 }
11915 if (!weed_plant_has_leaf(layer, WEED_LEAF_YUV_SAMPLING)) weed_set_int_value(layer,
11916 WEED_LEAF_YUV_SAMPLING, WEED_YUV_SAMPLING_DEFAULT);
11917 }
11918
11920#ifdef WEED_ADVANCED_PALETTES
11921 if (get_advanced_palette(outpl)->chantype[1] == WEED_VCHAN_V) swap_chroma_planes(layer);
11922#else
11923 if (outpl == WEED_PALETTE_YVU420P) swap_chroma_planes(layer);
11924#endif
11925
11926 lives_free(istrides);
11927 return TRUE;
11928
11929memfail:
11930 lives_freep((void **)&gudest_array);
11931 weed_layer_set_palette(layer, inpl);
11932 weed_layer_set_size(layer, width, height);
11933 if (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
11945boolean convert_layer_palette(weed_layer_t *layer, int outpl, int op_clamping) {
11946 return convert_layer_palette_full(layer, outpl, op_clamping, WEED_YUV_SAMPLING_DEFAULT, WEED_YUV_SUBSPACE_YUV,
11947 WEED_GAMMA_UNKNOWN);
11948}
11949
11951
11952
11953LiVESPixbuf *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
11990LIVES_INLINE LiVESPixbuf *lives_pixbuf_cheat(boolean has_alpha, int width, int height, uint8_t *buf) {
11991 // we can cheat if our buffer is correctly sized
11992 LiVESPixbuf *pixbuf;
11993 int channels = has_alpha ? 4 : 3;
11994 int rowstride = get_pixbuf_rowstride_value(width * channels);
11995
11996 pixbuf = lives_pixbuf_new_from_data(buf, has_alpha, width, height, rowstride,
11997 (LiVESPixbufDestroyNotify)lives_free_buffer, NULL);
11998 return pixbuf;
11999}
12000
12001
12003 int gamma_type = WEED_GAMMA_UNKNOWN;
12004 int error;
12005 if (prefs->apply_gamma) {
12006 if (weed_plant_has_leaf(layer, WEED_LEAF_GAMMA_TYPE)) {
12007 gamma_type = weed_get_int_value(layer, WEED_LEAF_GAMMA_TYPE, &error);
12008 }
12009 if (gamma_type == WEED_GAMMA_UNKNOWN) {
12010 break_me("weed_layer_get_gamma with unk. gamma");
12011 LIVES_WARN("Layer with unknown gamma !!");
12012 gamma_type = WEED_GAMMA_SRGB;
12013 }
12014 }
12015 return gamma_type;
12016}
12017
12018
12019void 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
12092static 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
12124boolean 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 {
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
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
12202LIVES_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
12210LiVESPixbuf *layer_to_pixbuf(weed_layer_t *layer, boolean realpalette, boolean fordisplay) {
12211 // create a gdkpixbuf from a weed layer
12212 // layer "pixel_data" is then either copied to the pixbuf pixels, or the contents shared with the pixbuf and array value set to NULL
12213 // layer may safely be passed to weed_layer_free() since if the pixel data is shared then it will be set to NULL in the layer.
12214 // pixbuf should be unreffed after use as per normal
12215
12216 LiVESPixbuf *pixbuf;
12217
12218 uint8_t *pixel_data, *pixels, *end;
12219
12220 boolean cheat = FALSE, done;
12221
12222 int palette, xpalette;
12223 int width;
12224 int height;
12225 int irowstride;
12226 int rowstride, orowstride;
12227 int n_channels;
12228
12229 if (!layer) return NULL;
12230
12232
12233 if (weed_plant_has_leaf(layer, WEED_LEAF_HOST_PIXBUF_SRC) && (!realpalette || weed_palette_is_pixbuf_palette(palette))) {
12234 // our layer pixel_data originally came from a pixbuf, so just free the layer and return the pixbuf
12235 pixbuf = (LiVESPixbuf *)weed_get_voidptr_value(layer, WEED_LEAF_HOST_PIXBUF_SRC, NULL);
12237 weed_leaf_delete(layer, WEED_LEAF_HOST_PIXBUF_SRC);
12238 return pixbuf;
12239 }
12240
12241 // otherwise we need to steal or copy the pixel_data
12242
12244 layer = create_blank_layer(layer, NULL, 0, 0, WEED_PALETTE_END);
12245 }
12246
12247 do {
12249 height = weed_layer_get_height(layer);
12250 irowstride = weed_layer_get_rowstride(layer);
12251 pixel_data = (uint8_t *)weed_get_voidptr_value(layer, WEED_LEAF_PIXEL_DATA, NULL);
12252 done = TRUE;
12253 xpalette = palette;
12254 if (realpalette) {
12256 // force conversion to RGB24 or RGBA32
12257 xpalette = WEED_PALETTE_END;
12258 } else {
12259 if (prefs->apply_gamma) {
12260 gamma_convert_layer(WEED_GAMMA_SRGB, layer);
12261 if (fordisplay && prefs->use_screen_gamma)
12263 }
12264 }
12265 }
12266 switch (xpalette) {
12267 case WEED_PALETTE_RGB24:
12268 case WEED_PALETTE_BGR24:
12269 case WEED_PALETTE_YUV888:
12270#ifndef GUI_QT
12271 if (irowstride == get_pixbuf_rowstride_value(width * 3)) {
12272 // rowstrides are OK, we can just steal the pixel_data
12273 pixbuf = lives_pixbuf_cheat(FALSE, width, height, pixel_data);
12275 cheat = TRUE;
12276 } else {
12277#endif
12278 // otherwise we need to copy the data
12279 pixbuf = lives_pixbuf_new(FALSE, width, height);
12280 }
12281 n_channels = 3;
12282 break;
12283 case WEED_PALETTE_RGBA32:
12284 case WEED_PALETTE_BGRA32:
12285#ifdef USE_SWSCALE
12286 case WEED_PALETTE_ARGB32:
12287#else
12288#ifdef GUI_QT
12289 case WEED_PALETTE_ARGB32:
12290#endif
12291#endif
12292 case WEED_PALETTE_YUVA8888:
12293#ifndef GUI_QT
12294 if (irowstride == get_pixbuf_rowstride_value(width * 4)) {
12295 // rowstrides are OK, we can just steal the pixel_data
12296 pixbuf = lives_pixbuf_cheat(TRUE, width, height, pixel_data);
12298 cheat = TRUE;
12299 } else
12300#endif
12301 // otherwise we need to copy the data
12302 pixbuf = lives_pixbuf_new(TRUE, width, height);
12303 n_channels = 4;
12304 break;
12305 default:
12307 if (!convert_layer_palette(layer, WEED_PALETTE_RGBA32, 0)) return NULL;
12308 palette = WEED_PALETTE_RGBA32;
12309 } else {
12310 if (!convert_layer_palette(layer, WEED_PALETTE_RGB24, 0)) return NULL;
12311 palette = WEED_PALETTE_RGB24;
12312 }
12313 done = FALSE;
12314 }
12315 } while (!done);
12316
12317 if (!cheat && LIVES_IS_PIXBUF(pixbuf)) {
12318 // copy the pixel data
12319 boolean done = FALSE;
12320 pixels = lives_pixbuf_get_pixels(pixbuf);
12321 orowstride = lives_pixbuf_get_rowstride(pixbuf);
12322
12323 if (irowstride > orowstride) rowstride = orowstride;
12324 else rowstride = irowstride;
12325 end = pixels + orowstride * height;
12326
12327 for (; pixels < end && !done; pixels += orowstride) {
12328 if (pixels + orowstride >= end) {
12329 orowstride = rowstride = get_last_pixbuf_rowstride_value(width, n_channels);
12330 done = TRUE;
12331 }
12332 lives_memcpy(pixels, pixel_data, rowstride);
12333 if (rowstride < orowstride) lives_memset(pixels + rowstride, 255, orowstride - rowstride);
12334 pixel_data += irowstride;
12335 }
12337 }
12338
12339 return pixbuf;
12340}
12341
12342
12343LIVES_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
12362void lives_pixbuf_set_opaque(LiVESPixbuf * pixbuf) {
12363 unsigned char *pdata = lives_pixbuf_get_pixels(pixbuf);
12364 int row = lives_pixbuf_get_rowstride(pixbuf);
12365 int height = lives_pixbuf_get_height(pixbuf);
12366 int offs;
12367#ifdef GUI_GTK
12368 offs = 3;
12369#endif
12370
12371#ifdef GUI_QT
12372 offs = 0;
12373#endif
12374
12375 register int i, j;
12376 for (i = 0; i < height; i++) {
12377 for (j = offs; j < row; j += 4) {
12378 pdata[j] = 255;
12379 }
12380 pdata += row;
12381 }
12382}
12383
12384
12386 int offs;
12387 boolean planar = FALSE;
12388 int pal = weed_layer_get_palette(layer);
12389 if (weed_palette_is_planar(pal)) {
12390 offs = weed_palette_get_alpha_plane(pal);
12391 planar = TRUE;
12392 } else offs = weed_palette_get_alpha_offset(pal);
12393
12394 if (offs >= 0) {
12395 int width = weed_layer_get_width(layer);
12396 int height = weed_layer_get_height(layer);
12397 int rowstride;
12398
12399 if (planar) {
12400 int *rowstrides = weed_layer_get_rowstrides(layer, NULL);
12401 void **pixel_data = weed_layer_get_pixel_data(layer, NULL);
12402 rowstride = rowstrides[offs];
12403 height *= weed_palette_get_plane_ratio_vertical(pal, offs);
12404 lives_memset(pixel_data, 255, rowstride * height);
12405 lives_free(rowstrides);
12406 lives_free(pixel_data);
12407 } else {
12408 ssize_t frsize, psize = pixel_size(pal);
12409 uint8_t *pixel_data = weed_layer_get_pixel_data_packed(layer);
12410 rowstride = weed_layer_get_rowstride(layer);
12411 frsize = height * rowstride;
12412 width *= psize;
12413 for (register int i = 0; i < frsize; i += rowstride) {
12414 for (register int j = offs; j < width; j += psize) {
12415 pixel_data[i + j] = 255;
12416 // *INDENT-OFF*
12417 }}}}
12418 // *INDENT-ON*
12419}
12420
12421
12423 // remove any extra padding after the image data
12424 weed_layer_t *old_layer;
12425 void **pixel_data, **new_pixel_data;
12426 int *rowstrides = weed_layer_get_rowstrides(layer, NULL), *orows;
12427 int pal = weed_layer_get_palette(layer);
12428 int width = weed_layer_get_width(layer);
12429 int height = weed_layer_get_height(layer);
12430 int xheight;
12431 int crow = width * weed_palette_get_bits_per_macropixel(pal) / 8;
12432 int cxrow;
12433 int nplanes;
12434 boolean needs_change = FALSE;
12435 register int i, j;
12436
12437 pixel_data = weed_layer_get_pixel_data(layer, &nplanes);
12438
12439 for (i = 0; i < nplanes; i++) {
12440 cxrow = crow * weed_palette_get_plane_ratio_horizontal(pal, i);
12441 if (cxrow != rowstrides[i]) {
12442 // nth plane has extra padding
12443 needs_change = TRUE;
12444 }
12445 }
12446
12447 if (!needs_change) {
12448 lives_free(pixel_data);
12449 lives_free(rowstrides);
12450 return TRUE;
12451 }
12452
12454 if (!old_layer) return FALSE;
12455 if (!weed_layer_copy(old_layer, layer)) return FALSE;
12456
12457 THREADVAR(rowstride_alignment_hint) = -1;
12459
12460 if (!create_empty_pixel_data(layer, FALSE, TRUE)) {
12461 weed_layer_copy(layer, old_layer);
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
12499static 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
12537boolean resize_layer(weed_layer_t *layer, int width, int height, LiVESInterpType interp, int opal_hint, int oclamp_hint) {
12538 // TODO ** - see if there is a resize plugin candidate/delegate which supports this palette :
12539 // this allows e.g libabl or a hardware rescaler
12540 LiVESPixbuf *pixbuf = NULL;
12541 LiVESPixbuf *new_pixbuf = NULL;
12542
12543 boolean retval = TRUE;
12544
12545 int palette = weed_layer_get_palette(layer);
12546
12547 // original width and height (in pixels)
12548 int iwidth = weed_layer_get_width_pixels(layer);
12549 int iheight = weed_layer_get_height(layer);
12550 int iclamping = weed_layer_get_yuv_clamping(layer);
12551 int new_gamma_type = weed_layer_get_gamma(layer);
12552
12553#ifdef USE_SWSCALE
12554 boolean resolved = FALSE;
12555 int xpalette, xopal_hint;
12556#endif
12557#ifdef USE_RESTHREAD
12558 boolean progscan = FALSE;
12559 if (weed_get_int_value(layer, WEED_LEAF_PROGSCAN, NULL) > 0) progscan = TRUE;
12560#endif
12561 if (!weed_plant_has_leaf(layer, WEED_LEAF_PIXEL_DATA)) {
12562 weed_layer_set_size(layer, width / weed_palette_get_pixels_per_macropixel(opal_hint), height);
12563 weed_layer_set_palette(layer, opal_hint);
12564 weed_layer_set_yuv_clamping(layer, oclamp_hint);
12565 return FALSE;
12566 }
12567
12568 if (width <= 0 || height <= 0) {
12569 char *msg = lives_strdup_printf("unable to scale layer to %d x %d for palette %d\n", width, height, palette);
12570 LIVES_DEBUG(msg);
12571 lives_free(msg);
12572 return FALSE;
12573 }
12574 // #define DEBUG_RESIZE
12575#ifdef DEBUG_RESIZE
12576 g_print("resizing layer size %d X %d with palette %s to %d X %d, hinted %s\n", iwidth, iheight,
12578 iclamping, 0), width, height, weed_palette_get_name_full(opal_hint, oclamp_hint, 0));
12579#endif
12580
12581 iwidth = (iwidth >> 1) << 1;
12582 iheight = (iheight >> 1) << 1;
12583
12584 if (width < 4) width = 4;
12585 if (height < 4) height = 4;
12586
12587 if (iwidth != width || iheight != height) {
12588 // prevent a crash in swscale
12589 width = (width >> 1) << 1;
12590 height = (height >> 1) << 1;
12591 }
12592 if (iwidth == width && iheight == height) return TRUE; // no resize needed
12593
12594 // if in palette is a YUV palette which we cannot scale, convert to YUV888 (unclamped) or YUVA8888 (unclamped)
12595 // we can always scale these by pretending they are RGB24 and RGBA32 respectively
12597 if (!weed_palette_is_resizable(palette, iclamping, TRUE)) {
12598 if (opal_hint == WEED_PALETTE_END || weed_palette_is_yuv(opal_hint)) {
12600 convert_layer_palette(layer, WEED_PALETTE_YUVA8888, WEED_YUV_CLAMPING_UNCLAMPED);
12601 } else {
12602 convert_layer_palette(layer, WEED_PALETTE_YUV888, WEED_YUV_CLAMPING_UNCLAMPED);
12603 }
12604 oclamp_hint = iclamping = (weed_get_int_value(layer, WEED_LEAF_YUV_CLAMPING, NULL));
12605 } else {
12607 convert_layer_palette(layer, WEED_PALETTE_RGBA32, 0);
12608 } else {
12609 convert_layer_palette(layer, WEED_PALETTE_RGB24, 0);
12610 }
12611 }
12613 iwidth = weed_layer_get_width_pixels(layer);
12614 iheight = weed_layer_get_height(layer);
12615 if (iwidth == width && iheight == height) return TRUE; // no resize needed
12616#ifdef DEBUG_RESIZE
12617 g_print("intermediate conversion 1 to %s\n", weed_palette_get_name_full(palette, iclamping, 0));
12618#endif
12619 }
12620 }
12621
12622 // check if we can also convert to the output palette
12623#ifdef USE_SWSCALE
12624 // only swscale can convert and resize together
12625 if (opal_hint == WEED_PALETTE_END || !weed_palette_is_resizable(opal_hint, oclamp_hint, FALSE)) {
12626#endif
12627 opal_hint = palette;
12628 oclamp_hint = iclamping;
12629#ifdef USE_SWSCALE
12630 }
12631#endif
12632
12633 // check if we can convert to the target palette/clamping
12634 if (!weed_palette_is_resizable(opal_hint, oclamp_hint, FALSE)) {
12635 opal_hint = palette;
12636 oclamp_hint = iclamping;
12637 }
12638
12639#ifdef USE_SWSCALE
12640 // sws doesn't understand YUV888 or YUVA888, but if the output palette is also YUV888 or YUVA8888
12641 // then we can use unclamped values and pretend they are RGB24 and RGBA32.
12642 // Otherwise we need to convert to YUV444P and YUVA4444P.
12643
12644 // lookup values for av_pix_fmt
12645 xpalette = palette;
12646 xopal_hint = opal_hint;
12647
12648 if (palette == WEED_PALETTE_YUV888) {
12649 if (opal_hint == WEED_PALETTE_YUV888 || opal_hint == WEED_PALETTE_YUVA8888) {
12650 if (iclamping == WEED_YUV_CLAMPING_CLAMPED) {
12651 convert_layer_palette(layer, WEED_PALETTE_YUV888, WEED_YUV_CLAMPING_UNCLAMPED);
12652 palette = weed_layer_get_palette_yuv(layer, &iclamping, NULL, NULL);
12653#ifdef DEBUG_RESIZE
12654 g_print("intermediate conversion 2 to %s\n", weed_palette_get_name_full(palette, iclamping, 0));
12655#endif
12656 }
12657 if (iclamping == WEED_YUV_CLAMPING_UNCLAMPED) {
12658 xpalette = WEED_PALETTE_RGB24;
12659 oclamp_hint = WEED_YUV_CLAMPING_UNCLAMPED;
12660 resolved = TRUE;
12661 if (opal_hint == WEED_PALETTE_YUV888) {
12662 xopal_hint = WEED_PALETTE_RGB24;
12663 } else {
12664 xopal_hint = WEED_PALETTE_RGBA32;
12665 }
12666#ifdef DEBUG_RESIZE
12667 g_print("masquerading as %s\n", weed_palette_get_name_full(xpalette, oclamp_hint, 0));
12668#endif
12669 }
12670 }
12671 if (!resolved) {
12672 convert_layer_palette(layer, WEED_PALETTE_YUV444P, iclamping);
12673 xpalette = palette = weed_layer_get_palette_yuv(layer, &iclamping, NULL, NULL);
12674#ifdef DEBUG_RESIZE
12675 g_print("intermediate conversion 3 to %s\n", weed_palette_get_name_full(xpalette, iclamping, 0));
12676#endif
12677 }
12678 } else if (palette == WEED_PALETTE_YUVA8888) {
12679 if (opal_hint == WEED_PALETTE_YUV888 || opal_hint == WEED_PALETTE_YUVA8888) {
12680 if (iclamping == WEED_YUV_CLAMPING_CLAMPED) {
12681 convert_layer_palette(layer, WEED_PALETTE_YUVA8888, WEED_YUV_CLAMPING_UNCLAMPED);
12682 xpalette = palette = weed_layer_get_palette_yuv(layer, &iclamping, NULL, NULL);
12683 }
12684 if (iclamping == WEED_YUV_CLAMPING_UNCLAMPED) {
12685 xpalette = WEED_PALETTE_RGBA32;
12686 oclamp_hint = WEED_YUV_CLAMPING_UNCLAMPED;
12687 resolved = TRUE;
12688 if (opal_hint == WEED_PALETTE_YUVA8888) {
12689 xopal_hint = WEED_PALETTE_RGBA32;
12690 } else {
12691 xopal_hint = WEED_PALETTE_RGB24;
12692 }
12693#ifdef DEBUG_RESIZE
12694 g_print("masquerading as %s\n", weed_palette_get_name_full(xpalette, oclamp_hint, 0));
12695#endif
12696 }
12697 }
12698 if (!resolved) {
12699 convert_layer_palette(layer, WEED_PALETTE_YUVA4444P, iclamping);
12700 xpalette = palette = weed_layer_get_palette_yuv(layer, &iclamping, NULL, NULL);
12701#ifdef DEBUG_RESIZE
12702 g_print("intermediate conversion 4 to %s\n", weed_palette_get_name_full(xpalette, iclamping, 0));
12703#endif
12704 }
12705 }
12706
12707 // reget these after conversion, convert width from macropixels to pixels
12709 iheight = weed_layer_get_height(layer);
12710 if (iwidth == width && iheight == height) return TRUE; // no resize needed
12711
12712 if (opal_hint == WEED_PALETTE_YUV888) opal_hint = xopal_hint = WEED_PALETTE_YUV444P;
12713 else if (opal_hint == WEED_PALETTE_YUVA8888) opal_hint = xopal_hint = WEED_PALETTE_YUVA4444P;
12714
12715 if (iwidth > 1 && iheight > 1 && weed_palette_is_resizable(palette, iclamping, TRUE) &&
12716 weed_palette_is_resizable(xopal_hint, oclamp_hint, FALSE)) {
12717 weed_layer_t *old_layer;
12718
12719 void **in_pixel_data, **out_pixel_data;
12720
12721 int *irowstrides, *orowstrides;
12722
12723 //boolean store_ctx = FALSE;
12724
12725 swpixfmt ipixfmt, opixfmt;
12726
12727 int flags;
12728
12729 const uint8_t *ipd[4], *opd[4];
12730 int irw[4], orw[4];
12731
12732 int i;
12733#if USE_THREADS
12734 lives_sw_params *swparams;
12736 swsctx_block *ctxblock;
12737 int offset;
12738 int nthrds = 1;
12739#else
12740 int scan;
12741#endif
12742 int subspace = WEED_YUV_SUBSPACE_YUV;
12743 int inplanes, oplanes;
12744
12747
12748 // get current values
12749 in_pixel_data = weed_layer_get_pixel_data(layer, &inplanes);
12750 irowstrides = weed_layer_get_rowstrides(layer, NULL);
12751
12753 weed_layer_copy(old_layer, layer);
12754
12755 av_log_set_level(AV_LOG_FATAL);
12756
12757 THREADVAR(rowstride_alignment_hint) = 16;
12758
12759 if (interp == LIVES_INTERP_BEST) {
12760 if (width > iwidth || height > iheight)
12761 flags = SWS_LANCZOS; // other opts SINC, LANCZOS, SPLINE; ACCURATE_RND, BITEXACT. ERROR_DIFFUSION
12762 else
12763 flags = SWS_BICUBIC;
12764 } else if (interp == LIVES_INTERP_FAST) flags = SWS_FAST_BILINEAR;
12765 else flags = SWS_BILINEAR;
12766
12767 ipixfmt = weed_palette_to_avi_pix_fmt(xpalette, &iclamping);
12768 opixfmt = weed_palette_to_avi_pix_fmt(xopal_hint, &oclamp_hint);
12769
12770 for (i = 0; i < 4; i++) {
12771 // swscale always likes 4 elements, even if fewer planes are used
12772 if (i < inplanes) {
12773 ipd[i] = in_pixel_data[i];
12774 irw[i] = irowstrides[i];
12775 } else {
12776 ipd[i] = NULL;
12777 irw[i] = 0;
12778 }
12779 }
12780
12781 if (weed_palette_is_rgb(palette) && !weed_palette_is_rgb(opal_hint) &&
12782 weed_layer_get_gamma(layer) == WEED_GAMMA_LINEAR) {
12783 // gamma correction
12784 if (prefs->apply_gamma) {
12785 gamma_convert_layer(WEED_GAMMA_SRGB, layer);
12786 }
12787 }
12788 new_gamma_type = weed_layer_get_gamma(layer);
12789
12790 // set new values
12791
12792 if (palette != opal_hint) {
12793 weed_layer_set_palette(layer, opal_hint);
12794 }
12795
12796 if (weed_palette_is_yuv(opal_hint)) weed_layer_set_yuv_clamping(layer, oclamp_hint);
12797 //weed_layer_set_size(layer, width, height);
12798 weed_layer_set_size(layer, width / weed_palette_get_pixels_per_macropixel(opal_hint), height);
12800
12801 if (!create_empty_pixel_data(layer, FALSE, TRUE)) {
12802 weed_layer_copy(layer, old_layer);
12804 weed_layer_free(old_layer);
12805 return FALSE;
12806 }
12807
12808 weed_layer_set_gamma(layer, new_gamma_type);
12809 out_pixel_data = weed_layer_get_pixel_data(layer, &oplanes);
12810 orowstrides = weed_layer_get_rowstrides(layer, NULL);
12811
12813 if (new_gamma_type == WEED_GAMMA_BT709) subspace = WEED_YUV_SUBSPACE_BT709;
12814 } else if (weed_palette_is_yuv(palette)) {
12815 if (new_gamma_type == WEED_GAMMA_BT709 || weed_layer_get_yuv_subspace(old_layer) == WEED_YUV_SUBSPACE_BT709)
12816 subspace = WEED_YUV_SUBSPACE_BT709;
12817 }
12818
12819 for (i = 0; i < 4; i++) {
12820 // swscale always likes 4 elements, even if fewer planes are used
12821 if (i < oplanes) {
12822 opd[i] = out_pixel_data[i];
12823 orw[i] = orowstrides[i];
12824 } else {
12825 opd[i] = NULL;
12826 orw[i] = 0;
12827 }
12828 }
12829
12830 //width /= weed_palette_get_pixels_per_macropixel(palette);
12831
12832#if USE_THREADS
12833 while ((nthrds << 1) <= prefs->nfx_threads) {
12834 if ((height | iheight) & 3) break;
12835 nthrds <<= 1;
12836 iheight >>= 1;
12837 height >>= 1;
12838 }
12839 swparams = (lives_sw_params *)lives_calloc(nthrds, sizeof(lives_sw_params));
12840#else
12841 // TODO - can we set the gamma ?
12842 //g_print("iht is %d, height = %d\n", iheight, height);
12843 swscale = sws_getCachedContext(swscale, iwidth, iheight, ipixfmt, width, height, opixfmt, flags, NULL, NULL, NULL);
12844 sws_setColorspaceDetails(swscale, sws_getCoefficients((subspace == WEED_YUV_SUBSPACE_BT709)
12845 ? SWS_CS_ITU709 : SWS_CS_ITU601), iclamping,
12846 sws_getCoefficients((subspace == WEED_YUV_SUBSPACE_BT709)
12847 ? SWS_CS_ITU709 : SWS_CS_ITU601), oclamp_hint, 0, 1 << 16, 1 << 16);
12848
12849 if (!swscale) {
12850 LIVES_DEBUG("swscale is NULL !!");
12851 } else {
12852#endif
12853
12854#ifdef DEBUG_RESIZE
12855 g_print("before resize with swscale: layer size %d X %d with palette %s to %d X %d, hinted %s,\n"
12856 "masquerading as %s (avpixfmt %d to avpixfmt %d)\n",
12857 iwidth, iheight, weed_palette_get_name_full(palette, iclamping, 0), width, height,
12859 oclamp_hint, 0),
12860 weed_palette_get_name_full(xopal_hint, oclamp_hint, 0), ipixfmt, opixfmt);
12861#endif
12862#if USE_THREADS
12863 ctxblock = sws_getblock(nthrds, iwidth, iheight, irw, ipixfmt, width, height, orw, opixfmt, flags,
12864 subspace, iclamping, oclamp_hint);
12865 offset = ctxblock->offset;
12866 for (int sl = 0; sl < nthrds; sl++) {
12867 swparams[sl].thread_id = sl;
12868 swparams[sl].iheight = iheight;
12869 swparams[sl].width = width;
12870 swparams[sl].file_gamma = 1.;
12871 swparams[sl].swscale = swscalep[sl + offset] =
12872 sws_getCachedContext(swscalep[sl + offset], iwidth, iheight, ipixfmt, width,
12873 height, opixfmt, flags, NULL, NULL, NULL);
12874
12875 if (!swparams[sl].swscale) {
12876 LIVES_DEBUG("swscale is NULL !!");
12877 } else {
12878 //if (progscan) {
12879 swparams[sl].layer = layer;
12880 swparams[sl].file_gamma = weed_get_double_value(layer, "file_gamma", NULL);
12881 if (swparams[sl].file_gamma == 0.) swparams[sl].file_gamma = 1.;
12882 //} else swparams[sl].layer = NULL;
12883 sws_setColorspaceDetails(swparams[sl].swscale,
12884 sws_getCoefficients((subspace == WEED_YUV_SUBSPACE_BT709)
12885 ? SWS_CS_ITU709 : SWS_CS_ITU601), iclamping,
12886 sws_getCoefficients((subspace == WEED_YUV_SUBSPACE_BT709)
12887 ? SWS_CS_ITU709 : SWS_CS_ITU601), oclamp_hint, 0, 65536, 65536);
12888 for (i = 0; i < 4; i++) {
12889 if (i < inplanes)
12890 swparams[sl].ipd[i] =
12891 ipd[i] + (size_t)(sl * irw[i] * iheight
12893 else
12894 swparams[sl].ipd[i] = NULL;
12895
12896 if (i < oplanes)
12897 swparams[sl].opd[i] =
12898 opd[i] + (size_t)(sl * orw[i] * height
12900 else
12901 swparams[sl].opd[i] = NULL;
12902 }
12903 swparams[sl].irw = irw;
12904 swparams[sl].orw = orw;
12905 if (sl < nthrds - 1) lives_thread_create(&threads[sl], LIVES_THRDATTR_NONE, swscale_threadfunc, &swparams[sl]);
12906 else swscale_threadfunc(&swparams[sl]);
12907 }
12908 }
12909 iheight = height;
12910 // height = 0;
12911 for (int sl = 0; sl < nthrds - 1; sl++) {
12912 if (swparams[sl].swscale) {
12913 lives_thread_join(threads[sl], NULL);
12914 height += swparams[sl].ret;
12915 } else height += iheight;
12916 }
12917
12918 sws_freeblock(ctxblock);
12919 lives_free(swparams);
12920
12921#else
12922#ifdef USE_RESTHREAD
12923 if (progscan)
12924 while ((scan = weed_get_int_value(layer, WEED_LEAF_PROGSCAN, NULL)) > 0 && scan < iheight)
12925 lives_nanosleep(100);
12926#endif
12927 height = sws_scale(swscale, (const uint8_t *const *)ipd, irw, 0, iheight,
12928 (uint8_t *const *)opd, orw);
12929 }
12930#endif
12931
12932#ifdef DEBUG_RESIZE
12933 g_print("after resize with swscale: layer size %d X %d, palette %s (assumed succesful)\n",
12934 width, height, weed_palette_get_name_full(opal_hint, oclamp_hint, 0));
12935#endif
12936 //if (store_ctx) swscale_add_context(iwidth, iheight, width, height, ipixfmt, opixfmt, flags, swscale);
12937 //weed_layer_set_width(layer, width);
12938 weed_layer_set_height(layer, height);
12939
12940 /* for (int gg = 0; gg < height; gg++) { */
12941 /* memset(&((uint8_t *)out_pixel_data[0])[gg * orowstrides[0]], 255, width * 3 / 2); */
12942 /* } */
12943
12944 // this will properly free() in_pixel_data
12945 weed_layer_free(old_layer);
12946 lives_free(out_pixel_data);
12947 lives_free(orowstrides);
12948 lives_free(irowstrides);
12949 lives_free(in_pixel_data);
12950 return TRUE;
12951 }
12952#endif
12953
12954 // reget these after conversion, convert width from macropixels to pixels
12956 iheight = weed_layer_get_height(layer);
12957 if (iwidth == width && iheight == height) return TRUE; // no resize needed
12958
12959 switch (palette) {
12960 // anything with 3 or 4 channels (alpha must be last)
12961
12962 case WEED_PALETTE_YUV888:
12963 case WEED_PALETTE_YUVA8888:
12964 if (iclamping == WEED_YUV_CLAMPING_CLAMPED) {
12966 convert_layer_palette(layer, WEED_PALETTE_YUVA8888, WEED_YUV_CLAMPING_UNCLAMPED);
12967 } else {
12968 convert_layer_palette(layer, WEED_PALETTE_YUV888, WEED_YUV_CLAMPING_UNCLAMPED);
12969 }
12970 }
12971
12972 case WEED_PALETTE_RGB24:
12973 case WEED_PALETTE_BGR24:
12974 case WEED_PALETTE_RGBA32:
12975 case WEED_PALETTE_BGRA32:
12976
12977 // create a new pixbuf
12978 //gamma_convert_layer(cfile->gamma_type, layer);
12979 pixbuf = layer_to_pixbuf(layer, FALSE, FALSE);
12980
12982 new_pixbuf = lives_pixbuf_scale_simple(pixbuf, width, height, interp);
12984 if (new_pixbuf) {
12987 }
12988
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
13015boolean letterbox_layer(weed_layer_t *layer, int nwidth, int nheight, int width, int height,
13016 LiVESInterpType interp, int tpal, int tclamp) {
13017 // stretch or shrink layer to width/height, then overlay it in a black rectangle size nwidth/nheight
13018 // width, nwidth should be in pixels
13019 weed_layer_t *old_layer;
13020 int *rowstrides, *irowstrides;
13021 void **pixel_data;
13022 void **new_pixel_data;
13023 uint8_t *dst, *src;
13024 int lwidth, lheight;
13025 int offs_x = 0, offs_y = 0;
13026 int pal;
13027
13028 int i;
13029
13030 if (!width || !height || !nwidth || !nheight) return TRUE;
13031 if (nwidth < width) nwidth = width;
13032 if (nheight < height) nheight = height;
13033
13035 if (nheight == height && nwidth == width) {
13036 resize_layer(layer, width, height, interp, tpal, tclamp);
13037 return TRUE;
13038 }
13039
13040 pal = weed_layer_get_palette(layer);
13041 lwidth = weed_layer_get_width_pixels(layer);
13042 lheight = weed_layer_get_height(layer);
13043
13044 if (lwidth != width || lheight != height) {
13046 if (!resize_layer(layer, width, height, interp, tpal, tclamp)) return FALSE;
13047 pal = weed_layer_get_palette(layer);
13048 lwidth = weed_layer_get_width_pixels(layer);
13049 lheight = weed_layer_get_height(layer);
13050 }
13051
13052 // old layer will hold pointers to the original pixel data for layer
13054
13055 if (!old_layer) return FALSE;
13056 if (!weed_layer_copy(old_layer, layer)) return FALSE;
13057
13058 pixel_data = weed_layer_get_pixel_data(old_layer, NULL);
13059
13060 if (!pixel_data) {
13061 weed_layer_free(old_layer);
13062 return FALSE;
13063 }
13064
13065 width = lwidth;
13066 height = lheight;
13067 irowstrides = weed_layer_get_rowstrides(layer, NULL);
13068
13070 weed_layer_set_size(layer, nwidth / weed_palette_get_pixels_per_macropixel(pal), nheight);
13072 if (!create_empty_pixel_data(layer, TRUE, TRUE)) goto memfail2;
13073
13074 new_pixel_data = weed_layer_get_pixel_data(layer, NULL);
13075
13078 nheight = weed_layer_get_height(layer);
13079
13080 if (nwidth < width || nheight < height || !new_pixel_data) {
13082 goto memfail2;
13083 }
13084
13085 offs_x = (nwidth - width + 1) >> 1;
13086 offs_y = (nheight - height + 1) >> 1;
13087
13088 rowstrides = weed_layer_get_rowstrides(layer, NULL);
13089
13090 switch (pal) {
13091 // 3 byte pixels, packed
13092 case WEED_PALETTE_RGB24:
13093 case WEED_PALETTE_BGR24:
13094 case WEED_PALETTE_YUV888:
13095 width *= 3;
13096 dst = (uint8_t *)new_pixel_data[0] + offs_y * rowstrides[0] + offs_x * 3;
13097 src = (uint8_t *)pixel_data[0];
13098 for (i = 0; i < height; i++) {
13099 lives_memcpy(dst, src, width);
13100 dst += rowstrides[0];
13101 src += irowstrides[0];
13102 }
13103 break;
13104
13105 // 4 byte pixels, packed
13106 case WEED_PALETTE_UYVY:
13107 case WEED_PALETTE_YUYV:
13108 offs_x >>= 1;
13109 width >>= 1;
13110
13111 case WEED_PALETTE_RGBA32:
13112 case WEED_PALETTE_BGRA32:
13113 case WEED_PALETTE_ARGB32:
13114 case WEED_PALETTE_YUVA8888:
13115
13116 width *= 4;
13117 dst = (uint8_t *)new_pixel_data[0] + offs_y * rowstrides[0] + offs_x * 4;
13118 src = (uint8_t *)pixel_data[0];
13119 for (i = 0; i < height; i++) {
13120 lives_memcpy(dst, src, width);
13121 dst += rowstrides[0];
13122 src += irowstrides[0];
13123 }
13124 break;
13125
13126 case WEED_PALETTE_YUV411:
13127 width *= 6;
13128 dst = (uint8_t *)new_pixel_data[0] + offs_y * rowstrides[0] + offs_x * 6;
13129 src = (uint8_t *)pixel_data[0];
13130 for (i = 0; i < height; i++) {
13131 lives_memcpy(dst, src, width);
13132 dst += rowstrides[0];
13133 src += irowstrides[0];
13134 }
13135 break;
13136
13137 case WEED_PALETTE_YUV444P:
13138 dst = (uint8_t *)new_pixel_data[0] + offs_y * rowstrides[0] + offs_x;
13139 src = (uint8_t *)pixel_data[0];
13140 for (i = 0; i < height; i++) {
13141 lives_memcpy(dst, src, width);
13142 dst += rowstrides[0];
13143 src += irowstrides[0];
13144 }
13145 dst = (uint8_t *)new_pixel_data[1] + offs_y * rowstrides[1] + offs_x;
13146 src = (uint8_t *)pixel_data[1];
13147 for (i = 0; i < height; i++) {
13148 lives_memcpy(dst, src, width);
13149 dst += rowstrides[1];
13150 src += irowstrides[1];
13151 }
13152 dst = (uint8_t *)new_pixel_data[2] + offs_y * rowstrides[2] + offs_x;
13153 src = (uint8_t *)pixel_data[2];
13154 for (i = 0; i < height; i++) {
13155 lives_memcpy(dst, src, width);
13156 dst += rowstrides[2];
13157 src += irowstrides[2];
13158 }
13159 break;
13160
13161 case WEED_PALETTE_YUVA4444P:
13162 dst = (uint8_t *)new_pixel_data[0] + offs_y * rowstrides[0] + offs_x;
13163 src = (uint8_t *)pixel_data[0];
13164 for (i = 0; i < height; i++) {
13165 lives_memcpy(dst, src, width);
13166 dst += rowstrides[0];
13167 src += irowstrides[0];
13168 }
13169 dst = (uint8_t *)new_pixel_data[1] + offs_y * rowstrides[1] + offs_x;
13170 src = (uint8_t *)pixel_data[1];
13171 for (i = 0; i < height; i++) {
13172 lives_memcpy(dst, src, width);
13173 dst += rowstrides[1];
13174 src += irowstrides[1];
13175 }
13176 dst = (uint8_t *)new_pixel_data[2] + offs_y * rowstrides[2] + offs_x;
13177 src = (uint8_t *)pixel_data[2];
13178 for (i = 0; i < height; i++) {
13179 lives_memcpy(dst, src, width);
13180 dst += rowstrides[2];
13181 src += irowstrides[2];
13182 }
13183 dst = (uint8_t *)new_pixel_data[3] + offs_y * rowstrides[3] + offs_x;
13184 src = (uint8_t *)pixel_data[3];
13185 for (i = 0; i < height; i++) {
13186 lives_memcpy(dst, src, width);
13187 dst += rowstrides[3];
13188 src += irowstrides[3];
13189 }
13190 break;
13191
13192 case WEED_PALETTE_YUV422P:
13193 dst = (uint8_t *)new_pixel_data[0] + offs_y * rowstrides[0] + offs_x;
13194 src = (uint8_t *)pixel_data[0];
13195 for (i = 0; i < height; i++) {
13196 lives_memcpy(dst, src, width);
13197 dst += rowstrides[0];
13198 src += irowstrides[0];
13199 }
13200 height >>= 1;
13201 offs_x >>= 1;
13202 dst = (uint8_t *)new_pixel_data[1] + offs_y * rowstrides[1] + offs_x;
13203 src = (uint8_t *)pixel_data[1];
13204 for (i = 0; i < height; i++) {
13205 lives_memcpy(dst, src, width);
13206 dst += rowstrides[1];
13207 src += irowstrides[1];
13208 }
13209 dst = (uint8_t *)new_pixel_data[2] + offs_y * rowstrides[2] + offs_x;
13210 src = (uint8_t *)pixel_data[2];
13211 for (i = 0; i < height; i++) {
13212 lives_memcpy(dst, src, width);
13213 dst += rowstrides[2];
13214 src += irowstrides[2];
13215 }
13216 break;
13217
13218 case WEED_PALETTE_YUV420P:
13219 case WEED_PALETTE_YVU420P:
13220 dst = (uint8_t *)new_pixel_data[0] + offs_y * rowstrides[0] + offs_x;
13221 src = (uint8_t *)pixel_data[0];
13222 for (i = 0; i < height; i++) {
13223 lives_memcpy(dst, src, width);
13224 dst += rowstrides[0];
13225 src += irowstrides[0];
13226 }
13227 height >>= 1;
13228 offs_x >>= 1;
13229 width >>= 1;
13230 offs_y >>= 1;
13231 dst = (uint8_t *)new_pixel_data[1] + offs_y * rowstrides[1] + offs_x;
13232 src = (uint8_t *)pixel_data[1];
13233 for (i = 0; i < height; i++) {
13234 lives_memcpy(dst, src, width);
13235 dst += rowstrides[1];
13236 src += irowstrides[1];
13237 }
13238 dst = (uint8_t *)new_pixel_data[2] + offs_y * rowstrides[2] + offs_x;
13239 src = (uint8_t *)pixel_data[2];
13240 for (i = 0; i < height; i++) {
13241 lives_memcpy(dst, src, width);
13242 dst += rowstrides[2];
13243 src += irowstrides[2];
13244 }
13245 break;
13246
13247 case WEED_PALETTE_RGBFLOAT:
13248 width *= 3 * sizeof(float);
13249 dst = (uint8_t *)new_pixel_data[0] + offs_y * rowstrides[0] + offs_x * 3 * sizeof(float);
13250 src = (uint8_t *)pixel_data[0];
13251 for (i = 0; i < height; i++) {
13252 lives_memcpy(dst, src, width);
13253 dst += rowstrides[0];
13254 src += irowstrides[0];
13255 }
13256 break;
13257
13258 case WEED_PALETTE_RGBAFLOAT:
13259 width *= 4 * sizeof(float);
13260 dst = (uint8_t *)new_pixel_data[0] + offs_y * rowstrides[0] + offs_x * 4 * sizeof(float);
13261 src = (uint8_t *)pixel_data[0];
13262 for (i = 0; i < height; i++) {
13263 lives_memcpy(dst, src, width);
13264 dst += rowstrides[0];
13265 src += irowstrides[0];
13266 }
13267 break;
13268
13269 case WEED_PALETTE_AFLOAT:
13270 width *= sizeof(float);
13271 dst = (uint8_t *)new_pixel_data[0] + offs_y * rowstrides[0] + offs_x * sizeof(float);
13272 src = (uint8_t *)pixel_data[0];
13273 for (i = 0; i < height; i++) {
13274 lives_memcpy(dst, src, width);
13275 dst += rowstrides[0];
13276 src += irowstrides[0];
13277 }
13278 break;
13279
13280 case WEED_PALETTE_A8:
13281 dst = (uint8_t *)new_pixel_data[0] + offs_y * rowstrides[0] + offs_x;
13282 src = (uint8_t *)pixel_data[0];
13283 for (i = 0; i < height; i++) {
13284 lives_memcpy(dst, src, width);
13285 dst += rowstrides[0];
13286 src += irowstrides[0];
13287 }
13288 break;
13289
13290 // assume offs_x and width is a multiple of 8
13291 case WEED_PALETTE_A1:
13292 width >>= 3;
13293 dst = (uint8_t *)new_pixel_data[0] + offs_y * rowstrides[0] + (offs_x >> 3);
13294 src = (uint8_t *)pixel_data[0];
13295 for (i = 0; i < height; i++) {
13296 lives_memcpy(dst, src, width);
13297 dst += rowstrides[0];
13298 src += irowstrides[0];
13299 }
13300 break;
13301 }
13302
13306 }
13308 weed_layer_free(old_layer);
13309 lives_free(pixel_data);
13310 lives_free(new_pixel_data);
13311 lives_free(irowstrides);
13312 lives_free(rowstrides);
13313 return TRUE;
13314
13315memfail2:
13317 weed_layer_copy(layer, old_layer);
13319 weed_layer_free(old_layer);
13320 lives_free(pixel_data);
13321 lives_free(irowstrides);
13322 return FALSE;
13323}
13324
13325
13347boolean pixbuf_to_layer(weed_layer_t *layer, LiVESPixbuf * pixbuf) {
13348 size_t framesize;
13349 void *pixel_data;
13350 void *in_pixel_data;
13351 int rowstride;
13352 int width;
13353 int height;
13354 int nchannels, palette;
13355
13356 if (!LIVES_IS_PIXBUF(pixbuf)) {
13357 weed_layer_set_size(layer, 0, 0);
13358 weed_set_int_value(layer, WEED_LEAF_ROWSTRIDES, 0);
13360 return FALSE;
13361 }
13362
13363 rowstride = lives_pixbuf_get_rowstride(pixbuf);
13364 width = lives_pixbuf_get_width(pixbuf);
13365 height = lives_pixbuf_get_height(pixbuf);
13366 nchannels = lives_pixbuf_get_n_channels(pixbuf);
13367
13368 weed_layer_set_width(layer, width);
13369 weed_layer_set_height(layer, height);
13370 weed_set_int_value(layer, WEED_LEAF_ROWSTRIDES, rowstride);
13371
13372 if (!weed_plant_has_leaf(layer, WEED_LEAF_CURRENT_PALETTE)) {
13373#ifdef GUI_GTK
13374 if (nchannels == 4) weed_set_int_value(layer, WEED_LEAF_CURRENT_PALETTE, WEED_PALETTE_RGBA32);
13375 else weed_set_int_value(layer, WEED_LEAF_CURRENT_PALETTE, WEED_PALETTE_RGB24);
13376#endif
13377 }
13378
13379 if (rowstride == get_last_pixbuf_rowstride_value(width, nchannels)) {
13380 in_pixel_data = (void *)lives_pixbuf_get_pixels(pixbuf);
13382 weed_set_voidptr_value(layer, WEED_LEAF_PIXEL_DATA, in_pixel_data);
13383 weed_set_voidptr_value(layer, WEED_LEAF_HOST_PIXBUF_SRC, pixbuf);
13384 palette = weed_get_int_value(layer, WEED_LEAF_CURRENT_PALETTE, NULL);
13385 if (weed_palette_is_rgb(palette)) weed_set_int_value(layer, WEED_LEAF_GAMMA_TYPE, WEED_GAMMA_SRGB);
13386 return TRUE;
13387 }
13388
13389 framesize = ALIGN_CEIL(rowstride * height, 32);
13390 pixel_data = lives_calloc(framesize >> 5, 32);
13391
13392 if (pixel_data) {
13393 in_pixel_data = (void *)lives_pixbuf_get_pixels_readonly(pixbuf);
13394 lives_memcpy(pixel_data, in_pixel_data, rowstride * (height - 1));
13395 // this part is needed because layers always have a memory size height*rowstride, whereas gdkpixbuf can have
13396 // a shorter last row
13397 lives_memcpy((uint8_t *)pixel_data + rowstride * (height - 1), (uint8_t *)in_pixel_data + rowstride * (height - 1),
13398 get_last_pixbuf_rowstride_value(width, nchannels));
13399 }
13400
13402 weed_set_voidptr_value(layer, WEED_LEAF_PIXEL_DATA, pixel_data);
13403
13404 palette = weed_get_int_value(layer, WEED_LEAF_CURRENT_PALETTE, NULL);
13405 if (weed_palette_is_rgb(palette)) weed_set_int_value(layer, WEED_LEAF_GAMMA_TYPE, WEED_GAMMA_SRGB);
13406
13407 return FALSE;
13408}
13409
13410
13412 if (pal == WEED_PALETTE_RGB24) return WEED_PALETTE_BGR24;
13413 if (pal == WEED_PALETTE_RGBA32) return WEED_PALETTE_BGRA32;
13414 if (pal == WEED_PALETTE_BGR24) return WEED_PALETTE_RGB24;
13415 if (pal == WEED_PALETTE_BGRA32) return WEED_PALETTE_RGBA32;
13416 return WEED_PALETTE_END;
13417}
13418
13427boolean consider_swapping(int *inpal, int *outpal) {
13428 if (*inpal == *outpal) return FALSE;
13429 if (!weed_palette_is_rgb(*inpal) || !weed_palette_is_rgb(*outpal)) return FALSE;
13430 switch (*inpal) {
13431 case WEED_PALETTE_RGB24:
13432 case WEED_PALETTE_RGBA32:
13433 switch (*outpal) {
13434 case WEED_PALETTE_BGR24:
13435 case WEED_PALETTE_BGRA32:
13436 *inpal = swap_red_blue(*inpal);
13437 return TRUE;
13438 default: return FALSE;
13439 }
13440 case WEED_PALETTE_BGR24:
13441 case WEED_PALETTE_BGRA32:
13442 switch (*outpal) {
13443 case WEED_PALETTE_RGB24:
13444 case WEED_PALETTE_RGBA32:
13445 case WEED_PALETTE_ARGB32:
13446 *inpal = swap_red_blue(*inpal);
13447 return TRUE;
13448 default: return FALSE;
13449 }
13450 case WEED_PALETTE_ARGB32:
13452 switch (*outpal) {
13453 case WEED_PALETTE_BGR24:
13454 case WEED_PALETTE_BGRA32:
13455 *outpal = swap_red_blue(*outpal);
13456 return TRUE;
13457 default: return FALSE;
13458 }
13459 default:
13460 break;
13461 }
13462 return FALSE;
13463}
13464
13465
13466
13467#ifdef GUI_GTK
13468
13473lives_painter_t *layer_to_lives_painter(weed_layer_t *layer) {
13474 lives_painter_surface_t *surf;
13475 lives_painter_t *cairo;
13476 lives_painter_format_t cform;
13477 uint8_t *src, *dst, *pixel_data;
13478
13479 int irowstride, orowstride;
13480 int width, widthx;
13481 int height, pal;
13482
13483 register int i;
13484
13485 if (weed_plant_has_leaf(layer, WEED_LEAF_HOST_SURFACE_SRC)) {
13486 surf = (lives_painter_surface_t *)weed_get_voidptr_value(layer, WEED_LEAF_HOST_SURFACE_SRC, NULL);
13487 } else {
13488 width = weed_layer_get_width(layer);
13489 pal = weed_layer_get_palette(layer);
13490 if (pal == WEED_PALETTE_A8) {
13491 cform = LIVES_PAINTER_FORMAT_A8;
13492 widthx = width;
13493 } else if (pal == WEED_PALETTE_A1) {
13494 cform = LIVES_PAINTER_FORMAT_A1;
13495 widthx = width >> 3;
13496 } else {
13497 cform = LIVES_PAINTER_COLOR_PALETTE(capable->byte_order);
13498 convert_layer_palette(layer, cform, 0);
13499 cform = LIVES_PAINTER_FORMAT_ARGB32;
13500 widthx = width << 2;
13501 }
13502
13503 height = weed_layer_get_height(layer);
13504 irowstride = weed_layer_get_rowstride(layer);
13505 orowstride = lives_painter_format_stride_for_width(cform, width);
13506 src = (uint8_t *)weed_layer_get_pixel_data_packed(layer);
13507
13508 if (irowstride == orowstride && !weed_plant_has_leaf(layer, WEED_LEAF_HOST_PIXBUF_SRC) &&
13509 !weed_plant_has_leaf(layer, WEED_LEAF_HOST_ORIG_PDATA)) {
13510 pixel_data = src;
13511 } else {
13512 dst = pixel_data = (uint8_t *)lives_calloc(1, height * orowstride);
13513 if (!pixel_data) return NULL;
13514 for (i = 0; i < height; i++) {
13515 lives_memcpy(dst, src, widthx);
13516 dst += orowstride;
13517 src += irowstride;
13518 }
13520 weed_layer_set_pixel_data_packed(layer, pixel_data);
13521 weed_layer_set_rowstride(layer, orowstride);
13522 }
13523
13524 if (weed_palette_has_alpha(pal)) {
13525 int flags = weed_get_int_value(layer, WEED_LEAF_FLAGS, NULL);
13526 if (!(flags & WEED_LAYER_ALPHA_PREMULT)) {
13527 // if we have post-multiplied alpha, pre multiply
13528 alpha_unpremult(layer, FALSE);
13529 flags |= WEED_LAYER_ALPHA_PREMULT;
13530 weed_set_int_value(layer, WEED_LEAF_FLAGS, flags);
13531 }
13532 }
13533 surf = lives_painter_image_surface_create_for_data(pixel_data, cform, width, height, orowstride);
13534 }
13535 if (!surf) return NULL;
13536
13537 cairo = lives_painter_create_from_surface(surf); // surf is refcounted
13538#ifdef DEBUG_CAIRO_SURFACE
13539 g_print("VALaa1 = %d %p\n", cairo_surface_get_reference_count(surf), surf);
13540#endif
13541 weed_set_voidptr_value(layer, WEED_LEAF_PIXEL_DATA, lives_painter_image_surface_get_data(surf));
13542 weed_set_voidptr_value(layer, WEED_LEAF_HOST_SURFACE_SRC, surf);
13543 return cairo;
13544}
13545
13546
13549boolean 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
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
13566
13568 weed_set_voidptr_value(layer, WEED_LEAF_HOST_SURFACE_SRC, surface);
13569
13570#ifdef DEBUG_CAIRO_SURFACE
13571 g_print("VALaa2 = %d %p\n", cairo_surface_get_reference_count(surface), surface);
13572#endif
13575
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
13584
13585 switch (cform) {
13586 case LIVES_PAINTER_FORMAT_ARGB32:
13587 if (capable->byte_order == LIVES_BIG_ENDIAN) {
13588 weed_layer_set_palette(layer, WEED_PALETTE_ARGB32);
13589 } else {
13590 weed_layer_set_palette(layer, WEED_PALETTE_BGRA32);
13591 }
13592 weed_layer_set_gamma(layer, WEED_GAMMA_SRGB);
13593
13594 if (prefs->alpha_post) {
13596 alpha_unpremult(layer, TRUE);
13597 } else {
13598 int flags = weed_layer_get_flags(layer);
13599 flags |= WEED_LAYER_ALPHA_PREMULT;
13600 weed_layer_set_flags(layer, flags);
13601 }
13602 break;
13603
13604 case LIVES_PAINTER_FORMAT_A8:
13605 weed_layer_set_palette(layer, WEED_PALETTE_A8);
13606 break;
13607
13608 case LIVES_PAINTER_FORMAT_A1:
13609 weed_layer_set_palette(layer, WEED_PALETTE_A1);
13610 break;
13611
13612 default:
13613 break;
13614 }
13615
13616 return TRUE;
13617}
13618
13619#endif
13620
13621
13622int resize_all(int fileno, int width, int height, lives_img_type_t imgtype, boolean do_back, int *nbad, int *nmiss) {
13623 LiVESPixbuf *pixbuf;
13624 LiVESError *error = NULL;
13625 lives_clip_t *sfile;
13626 lives_img_type_t ximgtype;
13627 weed_layer_t *layer;
13628 char *fname;
13629 int miss = 0, bad = 0;
13630 int nimty = (int)N_IMG_TYPES;
13631 int j, nres = 0;
13632
13634 if (!IS_VALID_CLIP(fileno)) return 0;
13635 sfile = mainw->files[fileno];
13636 for (int i = 0; i < sfile->frames; i++) {
13637 threaded_dialog_spin((double)i / (double)sfile->frames);
13638 if (mainw->cancelled) return nres;
13639 if (sfile->frame_index && sfile->frame_index[i] != -1) continue;
13640 ximgtype = imgtype;
13641 fname = make_image_file_name(sfile, i + 1, get_image_ext_for_type(ximgtype));
13642 if (!lives_file_test(fname, LIVES_FILE_TEST_EXISTS)) {
13643 // check all img_types
13644 for (j = 1; j < nimty; j++) {
13645 ximgtype = (lives_img_type_t)j;
13646 if (ximgtype == imgtype) continue;
13647 lives_free(fname);
13648 fname = make_image_file_name(sfile, i + 1, get_image_ext_for_type(ximgtype));
13649 if (lives_file_test(fname, LIVES_FILE_TEST_EXISTS)) break;
13650 }
13651 if (j == nimty) {
13652 miss++;
13653 lives_free(fname);
13654 continue;
13655 } else bad++;
13656 }
13658 weed_set_int_value(layer, WEED_LEAF_HOST_FLAGS, LIVES_LAYER_LOAD_IF_NEEDS_RESIZE);
13659 if (!weed_layer_create_from_file_progressive(layer, fname, width, height, WEED_PALETTE_END,
13660 get_image_ext_for_type(ximgtype))) {
13661 lives_free(fname);
13662 miss++;
13663 continue;
13664 }
13665
13666 if (weed_layer_get_width(layer) == width
13667 && weed_layer_get_height(layer) == height) {
13668 weed_layer_free(layer);
13669 lives_free(fname);
13670 continue;
13671 }
13672
13673 if (!resize_layer(layer, width, height, LIVES_INTERP_BEST, WEED_PALETTE_END,
13674 WEED_YUV_CLAMPING_UNCLAMPED)) {
13675 weed_layer_free(layer);
13676 lives_free(fname);
13677 continue;
13678 }
13679 pixbuf = layer_to_pixbuf(layer, TRUE, FALSE);
13680 weed_layer_free(layer);
13681 if (pixbuf) {
13682 if (do_back) {
13683 char *fname_bak = make_image_file_name(sfile, i + 1, LIVES_FILE_EXT_BAK);
13684 if (lives_file_test(fname_bak, LIVES_FILE_TEST_EXISTS)) lives_rm(fname_bak);
13685 lives_mv(fname, fname_bak);
13686 }
13687 lives_pixbuf_save(pixbuf, fname, ximgtype, 100 - prefs->ocp, width, height, &error);
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
13708weed_layer_t *weed_layer_create(int width, int height, int *rowstrides, int palette) {
13710
13711 weed_layer_set_width(layer, width);
13712 weed_layer_set_height(layer, height);
13713
13714 if (palette != WEED_PALETTE_END) {
13716 if (rowstrides) weed_layer_set_rowstrides(layer, rowstrides, weed_palette_get_nplanes(palette));
13717 }
13718 return layer;
13719}
13720
13721
13722weed_layer_t *weed_layer_create_full(int width, int height, int *rowstrides, int palette,
13723 int YUV_clamping, int YUV_sampling, int YUV_subspace, int gamma_type) {
13724 weed_layer_t *layer = weed_layer_create(width, height, rowstrides, palette);
13725 weed_layer_set_palette_yuv(layer, palette, YUV_clamping, YUV_sampling, YUV_subspace);
13726 weed_layer_set_gamma(layer, gamma_type);
13727 return layer;
13728}
13729
13730
13740 weed_layer_t *layer;
13741 void **pd_array = NULL;
13742
13743 if (!slayer || (!WEED_IS_LAYER(slayer) && !WEED_PLANT_IS_CHANNEL(slayer))) return NULL;
13744
13745 if (dlayer) {
13746 if (!WEED_IS_LAYER(dlayer) && !WEED_PLANT_IS_CHANNEL(dlayer)) return NULL;
13747 layer = dlayer;
13748 }
13749
13750 pd_array = weed_layer_get_pixel_data(slayer, NULL);
13751
13752 if (!dlayer) {
13754 int height = weed_layer_get_height(slayer);
13755 int width = weed_layer_get_width(slayer);
13756 int palette = weed_layer_get_palette(slayer);
13757 int *rowstrides = weed_layer_get_rowstrides(slayer, NULL);
13758 if (height <= 0 || width < 0 || !rowstrides || !weed_palette_is_valid(palette)) {
13759 if (pd_array) lives_free(pd_array);
13760 return NULL;
13761 } else {
13762 layer = weed_layer_create(width, height, rowstrides, palette);
13763 if (!pd_array) weed_layer_nullify_pixel_data(layer);
13764 else copy_pixel_data(layer, slayer, 0);
13765 lives_free(rowstrides);
13766 }
13767 } else {
13769 weed_leaf_dup(layer, slayer, WEED_LEAF_ROWSTRIDES);
13770 weed_leaf_dup(layer, slayer, WEED_LEAF_PIXEL_DATA);
13771 weed_leaf_dup(layer, slayer, WEED_LEAF_NATURAL_SIZE);
13772 weed_leaf_copy_or_delete(layer, WEED_LEAF_HEIGHT, slayer);
13773 weed_leaf_copy_or_delete(layer, WEED_LEAF_WIDTH, slayer);
13774 weed_leaf_copy_or_delete(layer, WEED_LEAF_CURRENT_PALETTE, slayer);
13775 if (pd_array) {
13780 }
13781 if (pd_array) {
13782 if (weed_leaf_set_flags(layer, WEED_LEAF_PIXEL_DATA,
13783 weed_leaf_get_flags(slayer, WEED_LEAF_PIXEL_DATA)));
13784 }
13785 }
13786
13787 weed_leaf_copy_or_delete(layer, WEED_LEAF_GAMMA_TYPE, slayer);
13788 weed_leaf_copy_or_delete(layer, WEED_LEAF_FLAGS, slayer);
13789 weed_leaf_copy_or_delete(layer, WEED_LEAF_YUV_CLAMPING, slayer);
13790 weed_leaf_copy_or_delete(layer, WEED_LEAF_YUV_SUBSPACE, slayer);
13791 weed_leaf_copy_or_delete(layer, WEED_LEAF_YUV_SAMPLING, slayer);
13792 weed_leaf_copy_or_delete(layer, WEED_LEAF_PIXEL_ASPECT_RATIO, slayer);
13793
13794 if (pd_array) lives_free(pd_array);
13795 return layer;
13796}
13797
13798
13800 int refs;
13801 if (!layer) return 0;
13802 refs = weed_get_int_value(layer, WEED_LEAF_HOST_REFS, NULL);
13803 return refs;
13804}
13805
13806
13820 void **pixel_data;
13821 int pd_elements;
13822
13823 if (!layer) return;
13824
13825 if (weed_leaf_get_flags(layer, WEED_LEAF_PIXEL_DATA) & LIVES_FLAG_MAINTAIN_VALUE)
13826 return;
13827
13828 if (weed_get_boolean_value(layer, WEED_LEAF_HOST_ORIG_PDATA, NULL) == WEED_TRUE)
13829 return;
13830
13831 if (weed_layer_count_refs(layer) > 1) {
13833 return;
13834 }
13835
13836 if ((pixel_data = weed_layer_get_pixel_data(layer, &pd_elements)) != NULL) {
13837 if (pd_elements > 0) {
13838 if (weed_plant_has_leaf(layer, WEED_LEAF_HOST_PIXBUF_SRC)) {
13839 LiVESPixbuf *pixbuf = (LiVESPixbuf *)weed_get_voidptr_value(layer, WEED_LEAF_HOST_PIXBUF_SRC, NULL);
13840 if (pixbuf) lives_widget_object_unref(pixbuf);
13841 } else {
13842 if (weed_plant_has_leaf(layer, WEED_LEAF_HOST_SURFACE_SRC)) {
13843 lives_painter_surface_t *surface = (lives_painter_surface_t *)weed_get_voidptr_value(layer,
13845 if (surface) {
13846 // this is where most surfaces die, as we convert from BGRA -> RGB
13847 uint8_t *pdata = lives_painter_image_surface_get_data(surface);
13848#ifdef DEBUG_CAIRO_SURFACE
13849 g_print("VALaa23rrr = %d %p\n", cairo_surface_get_reference_count(surface), surface);
13850#endif
13851 // call twice to remove our extra ref.
13854 lives_free(pdata);
13855 }
13856 } else {
13857 if (weed_get_boolean_value(layer, WEED_LEAF_HOST_PIXEL_DATA_CONTIGUOUS, NULL) == WEED_TRUE) {
13858 pd_elements = 1;
13859 }
13860 for (int i = 0; i < pd_elements; i++) {
13861 if (pixel_data[i]) lives_free(pixel_data[i]);
13862 }
13863 }
13864 }
13865 lives_free(pixel_data);
13867 }
13868 }
13869
13870 weed_leaf_delete(layer, WEED_LEAF_HOST_PIXEL_DATA_CONTIGUOUS);
13871 weed_leaf_delete(layer, WEED_LEAF_HOST_PIXBUF_SRC);
13872 weed_leaf_delete(layer, WEED_LEAF_HOST_SURFACE_SRC);
13873}
13874
13875
13884 if (weed_layer_unref(layer)) return layer;
13885 return NULL;
13886}
13887
13889 int refs;
13890 if (!layer) return 0;
13891 refs = weed_get_int_value(layer, WEED_LEAF_HOST_REFS, NULL) - 1;
13892 weed_set_int_value(layer, WEED_LEAF_HOST_REFS, refs);
13893 if (refs > 0) return refs;
13895 weed_plant_free(layer);
13896 return 0;
13897}
13898
13900 int refs;
13901 if (!layer) return 0;
13902 refs = weed_get_int_value(layer, WEED_LEAF_HOST_REFS, NULL);
13903 weed_set_int_value(layer, WEED_LEAF_HOST_REFS, ++refs);
13904 return refs;
13905}
13906
13907
13909 if (nplanes) *nplanes = 0;
13910 if (!layer) return NULL;
13911 return weed_get_voidptr_array_counted(layer, WEED_LEAF_PIXEL_DATA, nplanes);
13912}
13913
13914
13916 if (!layer) return NULL;
13917 return (uint8_t *)weed_get_voidptr_value(layer, WEED_LEAF_PIXEL_DATA, NULL);
13918}
13919
13920
13922 if (naudchans) *naudchans = 0;
13923 if (!layer) return NULL;
13924 return (float **)weed_get_voidptr_array_counted(layer, WEED_LEAF_AUDIO_DATA, naudchans);
13925}
13926
13927
13929 if (nplanes) *nplanes = 0;
13930 if (!layer) return NULL;
13931 return weed_get_int_array_counted(layer, WEED_LEAF_ROWSTRIDES, nplanes);
13932}
13933
13934
13936 if (!layer) return 0;
13937 return weed_get_int_value(layer, WEED_LEAF_ROWSTRIDES, NULL);
13938}
13939
13940
13942 if (!layer) return -1;
13943 return weed_get_int_value(layer, WEED_LEAF_WIDTH, NULL);
13944}
13945
13946
13948 if (!layer) return -1;
13950}
13951
13952
13954 if (!layer) return -1;
13955 return weed_get_int_value(layer, WEED_LEAF_HEIGHT, NULL);
13956}
13957
13958
13960 if (!layer) return 0;
13961 return weed_get_int_value(layer, WEED_LEAF_YUV_CLAMPING, NULL);
13962}
13963
13964
13966 if (!layer) return 0;
13967 return weed_get_int_value(layer, WEED_LEAF_YUV_SAMPLING, NULL);
13968}
13969
13970
13972 if (!layer) return 0;
13973 return weed_get_int_value(layer, WEED_LEAF_YUV_SUBSPACE, NULL);
13974}
13975
13976
13978 if (!layer) return WEED_PALETTE_END;
13979 return weed_get_int_value(layer, WEED_LEAF_CURRENT_PALETTE, NULL);
13980}
13981
13982
13983LIVES_GLOBAL_INLINE int weed_layer_get_palette_yuv(weed_layer_t *layer, int *clamping, int *sampling, int *subspace) {
13984 if (!layer) return WEED_PALETTE_END;
13985 if (clamping) *clamping = weed_layer_get_yuv_clamping(layer);
13986 if (sampling) *sampling = weed_layer_get_yuv_sampling(layer);
13987 if (subspace) *subspace = weed_layer_get_yuv_subspace(layer);
13988 return weed_get_int_value(layer, WEED_LEAF_CURRENT_PALETTE, NULL);
13989}
13990
13991
13993 if (!WEED_IS_LAYER(layer)) return 0;
13994 return weed_get_int_value(layer, WEED_LEAF_AUDIO_RATE, NULL);
13995}
13996
13997
13999 if (!WEED_IS_LAYER(layer)) return 0;
14000 return weed_get_int_value(layer, WEED_LEAF_AUDIO_CHANNELS, NULL);
14001}
14002
14003
14005 if (!WEED_IS_LAYER(layer)) return 0;
14006 return weed_get_int_value(layer, WEED_LEAF_AUDIO_DATA_LENGTH, NULL);
14007}
14008
LIVES_LOCAL_INLINE int _get_alpha(int pal)
Definition: colourspace.c:1496
LIVES_LOCAL_INLINE boolean can_inline_gamma(int inpl, int opal)
LIVES_GLOBAL_INLINE int weed_palette_get_alpha_offset(int pal)
Definition: colourspace.c:1510
int resize_all(int fileno, int width, int height, lives_img_type_t imgtype, boolean do_back, int *nbad, int *nmiss)
utility funcs for GUI
boolean weed_palette_is_sane(int pal)
Definition: colourspace.c:1523
LIVES_GLOBAL_INLINE void init_conversions(int intent)
Definition: colourspace.c:1804
LIVES_GLOBAL_INLINE weed_layer_t * lives_layer_new_for_frame(int clip, frames_t frame)
Definition: colourspace.c:9833
LIVES_GLOBAL_INLINE weed_layer_t * weed_layer_set_height(weed_layer_t *layer, int height)
Definition: colourspace.c:9724
LIVES_INLINE boolean weed_palette_is_resizable(int pal, int clamped, boolean in_out)
LIVES_GLOBAL_INLINE int weed_layer_count_refs(weed_layer_t *layer)
LiVESPixbuf * layer_to_pixbuf(weed_layer_t *layer, boolean realpalette, boolean fordisplay)
LIVES_INLINE void rgb2yuv_with_gamma(uint8_t r0, uint8_t g0, uint8_t b0, uint8_t *y, uint8_t *u, uint8_t *v, uint8_t *lut)
Definition: colourspace.c:1833
LIVES_GLOBAL_INLINE void lives_layer_set_frame(weed_layer_t *layer, frames_t frame)
Definition: colourspace.c:9822
boolean letterbox_layer(weed_layer_t *layer, int nwidth, int nheight, int width, int height, LiVESInterpType interp, int tpal, int tclamp)
LIVES_GLOBAL_INLINE int * weed_layer_get_rowstrides(weed_layer_t *layer, int *nplanes)
boolean copy_pixel_data(weed_layer_t *layer, weed_layer_t *old_layer, size_t alignment)
Definition: colourspace.c:9843
LIVES_GLOBAL_INLINE int lives_layer_get_clip(weed_layer_t *layer)
Definition: colourspace.c:9705
LIVES_GLOBAL_INLINE weed_layer_t * weed_layer_free(weed_layer_t *layer)
frees pixel_data for a layer, then the layer itself
void lives_pixbuf_set_opaque(LiVESPixbuf *pixbuf)
LIVES_GLOBAL_INLINE weed_layer_t * weed_layer_set_palette_yuv(weed_layer_t *layer, int palette, int clamping, int sampling, int subspace)
Definition: colourspace.c:9812
#define avg_chroma_3_1f(x, y)
Definition: colourspace.c:1817
LIVES_GLOBAL_INLINE int weed_layer_get_yuv_sampling(weed_layer_t *layer)
#define LAB0
Definition: colourspace.c:1022
void gamma_conv_params(int gamma_type, weed_layer_t *inst, boolean is_in)
LIVES_GLOBAL_INLINE int weed_layer_get_audio_rate(weed_layer_t *layer)
LIVES_GLOBAL_INLINE boolean weed_palette_is_alpha(int pal)
Definition: colourspace.c:1427
LIVES_GLOBAL_INLINE int weed_layer_get_yuv_subspace(weed_layer_t *layer)
LIVES_GLOBAL_INLINE int weed_layer_is_audio(weed_layer_t *layer)
Definition: colourspace.c:9675
LIVES_GLOBAL_INLINE boolean gamma_convert_layer_variant(double file_gamma, int tgamma, weed_layer_t *layer)
LIVES_GLOBAL_INLINE int weed_palette_get_bits_per_macropixel(int pal)
Definition: colourspace.c:1411
boolean pixbuf_to_layer(weed_layer_t *layer, LiVESPixbuf *pixbuf)
turn a (Gdk)Pixbuf into a Weed layer
boolean pick_nice_colour(uint8_t r0, uint8_t g0, uint8_t b0, uint8_t *r1, uint8_t *g1, uint8_t *b1, double max, double lmin, double lmax)
Definition: colourspace.c:1142
LIVES_GLOBAL_INLINE int weed_layer_get_height(weed_layer_t *layer)
LIVES_GLOBAL_INLINE int weed_palette_get_nplanes(int pal)
Definition: colourspace.c:1417
#define RNDFAC
Definition: colourspace.c:1038
LIVES_GLOBAL_INLINE boolean weed_palette_has_alpha_first(int pal)
Definition: colourspace.c:1515
int weed_layer_unref(weed_layer_t *layer)
weed_layer_t * weed_layer_create_full(int width, int height, int *rowstrides, int palette, int YUV_clamping, int YUV_sampling, int YUV_subspace, int gamma_type)
LIVES_GLOBAL_INLINE int weed_layer_get_naudchans(weed_layer_t *layer)
LIVES_GLOBAL_INLINE int32_t round_special(int32_t val)
Definition: colourspace.c:544
LIVES_GLOBAL_INLINE weed_layer_t * weed_layer_new(int layer_type)
Definition: colourspace.c:9655
LIVES_LOCAL_INLINE boolean is_yuvchan(uint16_t ctype)
Definition: colourspace.c:1387
LIVES_GLOBAL_INLINE boolean weed_palette_is_valid(int pal)
Definition: colourspace.c:1374
LIVES_GLOBAL_INLINE boolean gamma_convert_layer(int gamma_type, weed_layer_t *layer)
LIVES_GLOBAL_INLINE uint8_t * weed_layer_get_pixel_data_packed(weed_layer_t *layer)
LIVES_INLINE void rgb2yuyv_with_gamma(uint8_t r0, uint8_t g0, uint8_t b0, uint8_t r1, uint8_t g1, uint8_t b1, yuyv_macropixel *yuyv, uint8_t *lut)
Definition: colourspace.c:1893
LIVES_GLOBAL_INLINE boolean weed_palette_is_painter_palette(int pal)
Definition: colourspace.c:2130
void xyz2lab(double x, double y, double z, double *l, double *a, double *b)
Definition: colourspace.c:1028
#define RAT_MIN
LIVES_GLOBAL_INLINE boolean weed_palette_red_first(int pal)
Definition: colourspace.c:1433
LIVES_GLOBAL_INLINE int get_simple_palette(weed_macropixel_t *mpx)
Definition: colourspace.c:1378
boolean convert_layer_palette(weed_layer_t *layer, int outpl, int op_clamping)
void alpha_unpremult(weed_layer_t *layer, boolean un)
(un)premultply alpha using a lookup table
Definition: colourspace.c:9923
LIVES_GLOBAL_INLINE boolean weed_palette_is_yuv(int pal)
Definition: colourspace.c:1457
boolean create_empty_pixel_data(weed_layer_t *layer, boolean black_fill, boolean may_contig)
creates pixel data for layer
Definition: colourspace.c:9058
LIVES_GLOBAL_INLINE boolean weed_palette_has_alpha_last(int pal)
Definition: colourspace.c:1519
boolean weed_palette_is_lower_quality(int p1, int p2)
Definition: colourspace.c:2143
#define RAT_START
#define get_last_pixbuf_rowstride_value(width, nchans)
Definition: colourspace.c:201
#define ALIGN_SIZE
Definition: colourspace.c:9035
boolean consider_swapping(int *inpal, int *outpal)
look for shortcuts in palette conversions instead of converting e.g RGB -> BGRA, we may be able to pr...
lives_painter_t * layer_to_lives_painter(weed_layer_t *layer)
convert a weed layer to lives_painter (a.k.a cairo)
LIVES_GLOBAL_INLINE boolean lives_pixbuf_is_all_black(LiVESPixbuf *pixbuf)
Definition: colourspace.c:2193
LIVES_GLOBAL_INLINE int weed_layer_get_flags(weed_layer_t *layer)
Definition: colourspace.c:9699
LIVES_GLOBAL_INLINE int weed_layer_is_video(weed_layer_t *layer)
Definition: colourspace.c:9669
LIVES_GLOBAL_INLINE weed_layer_t * weed_layer_set_pixel_data_packed(weed_layer_t *layer, void *pixel_data)
Definition: colourspace.c:9746
LIVES_GLOBAL_INLINE boolean weed_palette_has_alpha(int pal)
Definition: colourspace.c:1466
#define CLAMP0255(a)
Definition: colourspace.c:211
LIVES_GLOBAL_INLINE weed_layer_t * weed_layer_set_yuv_sampling(weed_layer_t *layer, int sampling)
Definition: colourspace.c:9798
LIVES_GLOBAL_INLINE weed_layer_t * weed_layer_set_size(weed_layer_t *layer, int width, int height)
Definition: colourspace.c:9731
#define spc_rnd(val)
Definition: colourspace.c:541
LIVES_GLOBAL_INLINE boolean weed_palette_is_float(int pal)
Definition: colourspace.c:1475
boolean resize_layer(weed_layer_t *layer, int width, int height, LiVESInterpType interp, int opal_hint, int oclamp_hint)
resize a layer
LIVES_LOCAL_INLINE boolean is_rgbchan(uint16_t ctype)
Definition: colourspace.c:1383
LIVES_GLOBAL_INLINE float ** weed_layer_get_audio_data(weed_layer_t *layer, int *naudchans)
LIVES_GLOBAL_INLINE double weed_palette_get_plane_ratio_vertical(int pal, int plane)
Definition: colourspace.c:1488
LIVES_GLOBAL_INLINE int weed_layer_get_palette_yuv(weed_layer_t *layer, int *clamping, int *sampling, int *subspace)
LIVES_LOCAL_INLINE double lab_conv(double a)
Definition: colourspace.c:1026
LIVES_GLOBAL_INLINE int weed_palette_get_pixels_per_macropixel(int pal)
Definition: colourspace.c:1403
#define LAB1
Definition: colourspace.c:1023
#define avg_chroma_3_1(x, y)
Definition: colourspace.c:1791
LiVESPixbuf * lives_pixbuf_new_blank(int width, int height, int palette)
LIVES_GLOBAL_INLINE weed_layer_t * weed_layer_set_width(weed_layer_t *layer, int width)
width in macropixels of the layer palette
Definition: colourspace.c:9717
LIVES_GLOBAL_INLINE int weed_layer_get_rowstride(weed_layer_t *layer)
for packed palettes
LIVES_GLOBAL_INLINE boolean rowstrides_differ(int n1, int *n1_array, int n2, int *n2_array)
Definition: colourspace.c:9647
#define SHIFTVAL
Definition: colourspace.c:9034
#define RAT_TIO
LIVES_GLOBAL_INLINE void lives_layer_set_clip(weed_layer_t *layer, int clip)
Definition: colourspace.c:9828
LIVES_GLOBAL_INLINE void ** weed_layer_get_pixel_data(weed_layer_t *layer, int *nplanes)
LIVES_GLOBAL_INLINE int weed_layer_ref(weed_layer_t *layer)
LIVES_GLOBAL_INLINE boolean weed_palette_is_rgb(int pal)
Definition: colourspace.c:1448
LIVES_GLOBAL_INLINE boolean weed_palettes_rbswapped(int pal0, int pal1)
Definition: colourspace.c:1444
LIVES_LOCAL_INLINE int swap_red_blue(int pal)
void init_advanced_palettes(void)
Definition: colourspace.c:1201
double get_luma16(uint16_t r, uint16_t g, uint16_t b)
Definition: colourspace.c:557
double get_luma8(uint8_t r, uint8_t g, uint8_t b)
Definition: colourspace.c:549
weed_layer_t * weed_layer_create(int width, int height, int *rowstrides, int palette)
create a layer, setting the most important properties
LIVES_INLINE LiVESPixbuf * lives_pixbuf_cheat(boolean has_alpha, int width, int height, uint8_t *buf)
LIVES_GLOBAL_INLINE weed_layer_t * weed_layer_set_gamma(weed_layer_t *layer, int gamma_type)
Definition: colourspace.c:9784
#define LAB3
Definition: colourspace.c:1025
LIVES_GLOBAL_INLINE int weed_layer_get_audio_length(weed_layer_t *layer)
LIVES_GLOBAL_INLINE weed_layer_t * weed_layer_set_rowstrides(weed_layer_t *layer, int *rowstrides, int nplanes)
Definition: colourspace.c:9763
#define K1
Definition: colourspace.c:1036
LIVES_GLOBAL_INLINE weed_layer_t * weed_layer_set_rowstride(weed_layer_t *layer, int rowstride)
Definition: colourspace.c:9770
LIVES_GLOBAL_INLINE weed_layer_t * weed_layer_set_flags(weed_layer_t *layer, int flags)
Definition: colourspace.c:9692
LIVES_GLOBAL_INLINE weed_layer_t * weed_layer_set_audio_data(weed_layer_t *layer, float **data, int arate, int naudchans, weed_size_t nsamps)
Definition: colourspace.c:9681
LIVES_GLOBAL_INLINE weed_layer_t * weed_layer_set_yuv_clamping(weed_layer_t *layer, int clamping)
Definition: colourspace.c:9791
#define K2
Definition: colourspace.c:1037
#define yuv2bgr_with_gamma(y, u, v, b, g, r, lut)
Definition: colourspace.c:2058
#define yuv2bgr(y, u, v, b, g, r)
Definition: colourspace.c:2050
LIVES_GLOBAL_INLINE weed_layer_t * weed_layer_set_pixel_data(weed_layer_t *layer, void **pixel_data, int nplanes)
Definition: colourspace.c:9739
#define USE_THREADS
set to 0 to disable threading for pixbuf operations, 1 to enable. Other values are invalid.
Definition: colourspace.c:37
LIVES_GLOBAL_INLINE int weed_palette_get_alpha_plane(int pal)
Definition: colourspace.c:1505
double cdist94(uint8_t r0, uint8_t g0, uint8_t b0, uint8_t r1, uint8_t g1, uint8_t b1)
Definition: colourspace.c:1075
LIVES_GLOBAL_INLINE frames_t lives_layer_get_frame(weed_layer_t *layer)
Definition: colourspace.c:9711
LIVES_INLINE void fill_plane(uint8_t *ptr, int psize, int width, int height, int rowstride, unsigned char *bpix)
a "layer" is CHANNEL type plant which is not created from a plugin CHANNEL_TEMPLATE.
Definition: colourspace.c:9019
boolean gamma_convert_sub_layer(int gamma_type, double fileg, weed_layer_t *layer, int x, int y, int width, int height, boolean may_thread)
alter the transfer function of a Weed layer, from current value to gamma_type
LIVES_GLOBAL_INLINE weed_layer_t * weed_layer_set_palette(weed_layer_t *layer, int palette)
functions all return the input layer for convenience; no checking for valid values is done if layer i...
Definition: colourspace.c:9777
LIVES_GLOBAL_INLINE int weed_layer_get_width(weed_layer_t *layer)
LIVES_GLOBAL_INLINE weed_layer_t * weed_layer_set_yuv_subspace(weed_layer_t *layer, int subspace)
Definition: colourspace.c:9805
void lives_layer_set_opaque(weed_layer_t *layer)
#define get_pixbuf_rowstride_value(rowstride)
Definition: colourspace.c:194
int weed_layer_get_gamma(weed_layer_t *layer)
LIVES_GLOBAL_INLINE const weed_macropixel_t * get_advanced_palette(int weed_palette)
Definition: colourspace.c:1368
LIVES_GLOBAL_INLINE int weed_layer_get_width_pixels(weed_layer_t *layer)
#define avg_chroma_1_3f(x, y)
Definition: colourspace.c:1818
weed_layer_t * create_blank_layer(weed_layer_t *layer, const char *image_ext, int width, int height, int target_palette)
fills layer with default values.
Definition: colourspace.c:9611
LIVES_GLOBAL_INLINE weed_layer_t * weed_layer_nullify_pixel_data(weed_layer_t *layer)
Definition: colourspace.c:9753
void rgb2hsv(uint8_t r, uint8_t g, uint8_t b, double *h, double *s, double *v)
Definition: colourspace.c:1090
boolean compact_rowstrides(weed_layer_t *layer)
void hsv2rgb(double h, double s, double v, uint8_t *r, uint8_t *g, uint8_t *b)
Definition: colourspace.c:1113
#define bgr2yuv(b0, g0, r0, y, u, v)
Definition: colourspace.c:1830
LIVES_GLOBAL_INLINE double weed_palette_get_plane_ratio_horizontal(int pal, int plane)
Definition: colourspace.c:1480
void pixel_data_planar_from_membuf(void **pixel_data, void *data, size_t size, int palette, boolean contig)
Definition: colourspace.c:2236
void weed_layer_pixel_data_free(weed_layer_t *layer)
free pixel_data from layer
LIVES_GLOBAL_INLINE int weed_layer_get_palette(weed_layer_t *layer)
void init_colour_engine(void)
Definition: colourspace.c:1661
#define avg_chroma(x, y)
Definition: colourspace.c:1790
#define CLAMP0255f(a)
Definition: colourspace.c:212
void rgb2xyz(uint8_t r, uint8_t g, uint8_t b, double *x, double *y, double *z)
Definition: colourspace.c:1013
LIVES_GLOBAL_INLINE int weed_layer_get_type(weed_layer_t *layer)
Definition: colourspace.c:9663
#define DIST_THRESH
boolean lives_painter_to_layer(lives_painter_t *cr, weed_layer_t *layer)
convert a lives_painter_t (a.k.a) cairo_t to a weed layer
#define LAB2
Definition: colourspace.c:1024
weed_layer_t * weed_layer_copy(weed_layer_t *dlayer, weed_layer_t *slayer)
copy source layer slayer to dest layer dlayer
LIVES_GLOBAL_INLINE int weed_layer_get_yuv_clamping(weed_layer_t *layer)
boolean convert_layer_palette_full(weed_layer_t *layer, int outpl, int oclamping, int osampling, int osubspace, int tgamma)
convert the palette of a layer
LIVES_GLOBAL_INLINE size_t pixel_size(int pal)
Definition: colourspace.c:1391
#define CLAMP_FACTOR_UV
Definition: colourspace.h:65
#define WEED_LAYER_TYPE_VIDEO
Definition: colourspace.h:221
#define WEED_LEAF_CLIP
Definition: colourspace.h:18
#define LIVES_LAYER_LOAD_IF_NEEDS_RESIZE
private flags
Definition: colourspace.h:259
#define WEED_GAMMA_VARIANT
Definition: colourspace.h:255
#define WEED_LAYER_TYPE_AUDIO
Definition: colourspace.h:222
#define KB_BT709
Definition: colourspace.h:50
#define CLAMP_FACTOR_Y
Definition: colourspace.h:64
#define YUV_CLAMP_MIN
Definition: colourspace.h:55
#define WEED_LEAF_PIXEL_BITS
Definition: colourspace.h:23
#define WEED_LEAF_HOST_FLAGS
Definition: colourspace.h:24
#define WEED_LEAF_HOST_PIXBUF_SRC
Definition: colourspace.h:21
#define KR_YCBCR
Definition: colourspace.h:43
#define WEED_GAMMA_MONITOR
Definition: colourspace.h:253
#define Y_CLAMP_MAX
Definition: colourspace.h:58
#define KR_BT709
Definition: colourspace.h:49
#define KB_YCBCR
Definition: colourspace.h:44
#define ALIGN_MIN
rowstride alignment values
Definition: colourspace.h:31
#define WEED_LEAF_HOST_SURFACE_SRC
Definition: colourspace.h:22
#define UV_CLAMP_MAXI
Definition: colourspace.h:62
#define MAX_THREADS
Definition: colourspace.h:69
#define WEED_LEAF_LAYER_TYPE
Definition: colourspace.h:219
#define WEED_IS_LAYER(plant)
Definition: colourspace.h:224
#define weed_palette_is_pixbuf_palette(pal)
Definition: colourspace.h:296
#define FP_BITS
Definition: colourspace.h:35
#define WEED_LEAF_FRAME
Definition: colourspace.h:19
#define WEED_PLANT_LAYER
Definition: colourspace.h:217
#define WEED_LEAF_HOST_PIXEL_DATA_CONTIGUOUS
Definition: colourspace.h:20
#define UV_CLAMP_MAX
Definition: colourspace.h:61
#define WEED_LAYER_TYPE_NONE
Definition: colourspace.h:220
#define SCALE_FACTOR
Definition: colourspace.h:40
#define WEED_LAYER_ALPHA_PREMULT
Definition: colourspace.h:256
#define ALIGN_DEF
Definition: colourspace.h:32
weed_plant_t weed_layer_t
Definition: colourspace.h:71
#define YUV_CLAMP_MINI
Definition: colourspace.h:56
#define WEED_LEAF_PROGSCAN
Definition: colourspace.h:26
#define UV_BIAS
Definition: colourspace.h:67
#define Y_CLAMP_MAXI
Definition: colourspace.h:59
void threaded_dialog_spin(double fraction)
Definition: dialogs.c:3823
LIVES_GLOBAL_INLINE weed_error_t weed_leaf_copy_or_delete(weed_layer_t *dlayer, const char *key, weed_layer_t *slayer)
Definition: effects-weed.c:68
#define WEED_LEAF_HOST_ORIG_PDATA
Definition: effects-weed.h:60
#define LIVES_FLAG_MAINTAIN_VALUE
soft flag, like immutable / deletable for host
Definition: effects-weed.h:109
#define WEED_LEAF_HOST_REFS
Definition: effects-weed.h:72
error("LSD_RANDFUNC(ptr, size) must be defined")
LIVES_GLOBAL_INLINE void * lives_calloc_safety(size_t nmemb, size_t xsize)
Definition: machinestate.c:603
LIVES_GLOBAL_INLINE uint32_t fastrand_int(uint32_t range)
pick a pseudo random uint between 0 and range (inclusive)
Definition: machinestate.c:54
LIVES_GLOBAL_INLINE void swab4(const void *from, const void *to, size_t gran)
uint64_t lives_thread_join(lives_thread_t work, void **retval)
int lives_thread_create(lives_thread_t *thread, lives_thread_attr_t attr, lives_funcptr_t func, void *arg)
LiVESList lives_thread_t
Definition: machinestate.h:434
#define EXTRA_BYTES
TODO - split into: memory, files, sysops, threads.
Definition: machinestate.h:16
#define lives_nanosleep(nanosec)
Definition: machinestate.h:307
#define lives_calloc
Definition: machinestate.h:67
#define THREADVAR(var)
Definition: machinestate.h:531
#define lives_free
Definition: machinestate.h:52
#define lives_memset
Definition: machinestate.h:61
#define lives_malloc
Definition: machinestate.h:46
#define lives_memcpy
Definition: machinestate.h:55
#define lives_memmove
Definition: machinestate.h:64
#define LIVES_THRDATTR_NONE
Definition: machinestate.h:437
_palette * palette
interface colour settings
Definition: main.c:101
ssize_t sizint
type sizes
Definition: main.c:102
void break_me(const char *brkstr)
Definition: main.c:159
mainwindow * mainw
Definition: main.c:103
boolean lives_pixbuf_save(LiVESPixbuf *pixbuf, char *fname, lives_img_type_t imgtype, int quality, int width, int height, LiVESError **gerrorptr)
Save a pixbuf to a file using the specified imgtype and the specified quality/compression value.
Definition: main.c:9304
boolean weed_layer_create_from_file_progressive(weed_layer_t *layer, const char *fname, int width, int height, int tpalette, const char *img_ext)
Definition: main.c:6989
#define LIVES_WARN(x)
Definition: main.h:1862
int frames_t
Definition: main.h:99
#define GNU_HOT
Definition: main.h:88
#define LIVES_DEBUG(x)
Definition: main.h:1848
#define LIVES_GLOBAL_INLINE
Definition: main.h:239
#define LIVES_INLINE
Definition: main.h:238
#define LIVES_LOCAL_INLINE
Definition: main.h:246
#define sig(a)
Definition: main.h:268
#define ALIGN_CEIL(a, b)
Definition: main.h:286
const char * get_image_ext_for_type(lives_img_type_t imgtype)
Definition: utils.c:3025
int lives_mv(const char *from, const char *to)
Definition: utils.c:4446
#define IS_VALID_CLIP(clip)
Definition: main.h:808
int lives_rm(const char *file)
Definition: utils.c:4395
capability * capable
Definition: main.h:627
#define LIVES_ERROR(x)
Definition: main.h:1870
lives_img_type_t
Definition: main.h:774
@ N_IMG_TYPES
Definition: main.h:778
#define GNU_FLATTEN
Definition: main.h:87
boolean lives_freep(void **ptr)
Definition: utils.c:1411
#define myround(n)
Definition: main.h:300
char * make_image_file_name(lives_clip_t *clip, frames_t frame, const char *img_ext)
lives_image_type can be a string, lives_img_type_t is an enumeration
Definition: utils.c:3053
@ CANCEL_NONE
no cancel
Definition: main.h:701
#define CEIL(a, b)
Definition: main.h:283
#define DEF_FRAME_VSIZE_UNSCALED
Definition: mainwindow.h:144
#define DEF_FRAME_HSIZE_UNSCALED
Definition: mainwindow.h:139
#define LIVES_FILE_EXT_BAK
Definition: mainwindow.h:495
#define EFFORT_RANGE_MAX
if set to TRUE during playback then a new frame (or possibly the current one) will be displayed ASAP
Definition: mainwindow.h:1770
#define LIVES_FILE_EXT_JPG
Definition: mainwindow.h:488
@ LIVES_INTENTION_RENDER
Definition: plugins.h:48
@ LIVES_INTENTION_PLAY
Definition: plugins.h:45
@ LIVES_INTENTION_TRANSCODE
Definition: plugins.h:47
_prefs * prefs
Definition: preferences.h:847
#define PB_QUALITY_HIGH
Definition: preferences.h:34
#define PB_QUALITY_MED
default
Definition: preferences.h:33
#define PB_QUALITY_LOW
Definition: preferences.h:32
_future_prefs * future_prefs
Definition: preferences.h:848
short pb_quality
Definition: preferences.h:831
int nfx_threads
Definition: preferences.h:356
int ocp
open_compression_percent : get/set in prefs
Definition: preferences.h:217
double screen_gamma
Definition: preferences.h:442
boolean alpha_post
set to TRUE to force use of post alpha internally
Definition: preferences.h:358
boolean apply_gamma
Definition: preferences.h:451
boolean use_screen_gamma
Definition: preferences.h:452
short pb_quality
Definition: preferences.h:31
int byte_order
Definition: main.h:577
int orowstrides[4]
Definition: colourspace.h:111
boolean in_alpha
Definition: colourspace.h:114
boolean in_clamping
Definition: colourspace.h:116
boolean is_bottom
Definition: colourspace.h:107
int irowstrides[4]
Definition: colourspace.h:110
void * destp[4]
Definition: colourspace.h:113
boolean out_clamping
Definition: colourspace.h:117
void * srcp[4]
Definition: colourspace.h:104
boolean out_alpha
Definition: colourspace.h:115
boolean alpha_first
Definition: colourspace.h:122
corresponds to one clip in the GUI
Definition: main.h:877
frames_t frames
number of video frames
Definition: main.h:890
frames_t * frame_index
index of frames for CLIP_TYPE_FILE >0 means corresponding frame within original clip -1 means corresp...
Definition: main.h:1004
int vsize
frame height (vertical) in pixels
Definition: main.h:897
int gamma_type
Definition: main.h:903
int hsize
frame width (horizontal) in pixels (NOT macropixels !)
Definition: main.h:896
weed_plant_t * frame_layer
Definition: mainwindow.h:948
lives_clip_t * files[MAX_FILES+1]
+1 for the clipboard
Definition: mainwindow.h:729
volatile lives_cancel_t cancelled
Definition: mainwindow.h:798
#define lives_strdup_printf(fmt,...)
Definition: support.c:27
#define TRUE
Definition: videoplugin.h:59
#define FALSE
Definition: videoplugin.h:60
char * weed_palette_get_name_full(int pal, int clamping, int subspace)
WEED_GLOBAL_INLINE int weed_paramtmpl_get_type(weed_plant_t *paramtmpl)
const char * weed_palette_get_name(int pal)
const char * weed_yuv_clamping_get_name(int clamping)
#define weed_palette_is_planar(pal)
#define WEED_PLANT_IS_CHANNEL(plant)
WIDGET_HELPER_GLOBAL_INLINE lives_painter_format_t lives_painter_image_surface_get_format(lives_painter_surface_t *surf)
WIDGET_HELPER_GLOBAL_INLINE lives_painter_surface_t * lives_painter_get_target(lives_painter_t *cr)
WIDGET_HELPER_GLOBAL_INLINE int lives_painter_image_surface_get_stride(lives_painter_surface_t *surf)
WIDGET_HELPER_GLOBAL_INLINE LiVESPixbuf * lives_pixbuf_scale_simple(const LiVESPixbuf *src, int dest_width, int dest_height, LiVESInterpType interp_type)
WIDGET_HELPER_GLOBAL_INLINE LiVESPixbuf * lives_pixbuf_new(boolean has_alpha, int width, int height)
WIDGET_HELPER_GLOBAL_INLINE int lives_painter_image_surface_get_height(lives_painter_surface_t *surf)
WIDGET_HELPER_GLOBAL_INLINE int lives_painter_format_stride_for_width(lives_painter_format_t form, int width)
WIDGET_HELPER_GLOBAL_INLINE boolean lives_painter_surface_destroy(lives_painter_surface_t *surf)
WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_object_unref(livespointer object)
decrease refcount by one: if refcount==0, object is destroyed
WIDGET_HELPER_GLOBAL_INLINE const unsigned char * lives_pixbuf_get_pixels_readonly(const LiVESPixbuf *pixbuf)
WIDGET_HELPER_GLOBAL_INLINE int lives_painter_image_surface_get_width(lives_painter_surface_t *surf)
WIDGET_HELPER_GLOBAL_INLINE int lives_pixbuf_get_rowstride(const LiVESPixbuf *pixbuf)
WIDGET_HELPER_GLOBAL_INLINE boolean lives_painter_surface_flush(lives_painter_surface_t *surf)
WIDGET_HELPER_GLOBAL_INLINE lives_painter_surface_t * lives_painter_surface_reference(lives_painter_surface_t *surf)
WIDGET_HELPER_GLOBAL_INLINE lives_painter_surface_t * lives_painter_image_surface_create_for_data(uint8_t *data, lives_painter_format_t format, int width, int height, int stride)
WIDGET_HELPER_GLOBAL_INLINE lives_painter_t * lives_painter_create_from_surface(lives_painter_surface_t *target)
WIDGET_HELPER_GLOBAL_INLINE boolean lives_painter_destroy(lives_painter_t *cr)
WIDGET_HELPER_GLOBAL_INLINE uint8_t * lives_painter_image_surface_get_data(lives_painter_surface_t *surf)
WIDGET_HELPER_GLOBAL_INLINE unsigned char * lives_pixbuf_get_pixels(const LiVESPixbuf *pixbuf)
WIDGET_HELPER_GLOBAL_INLINE LiVESPixbuf * lives_pixbuf_new_from_data(const unsigned char *buf, boolean has_alpha, int width, int height, int rowstride, LiVESPixbufDestroyNotify lives_free_buffer_fn, livespointer destroy_fn_data)
WIDGET_HELPER_GLOBAL_INLINE int lives_pixbuf_get_height(const LiVESPixbuf *pixbuf)
WIDGET_HELPER_GLOBAL_INLINE int lives_pixbuf_get_width(const LiVESPixbuf *pixbuf)
WIDGET_HELPER_GLOBAL_INLINE boolean lives_pixbuf_get_has_alpha(const LiVESPixbuf *pixbuf)
WIDGET_HELPER_GLOBAL_INLINE int lives_pixbuf_get_n_channels(const LiVESPixbuf *pixbuf)