FreeRDP
prim_YUV.c
1 
24 #include <winpr/wtypes.h>
25 #include <winpr/assert.h>
26 #include <winpr/cast.h>
27 
28 #include <freerdp/config.h>
29 
30 #include <freerdp/types.h>
31 #include <freerdp/primitives.h>
32 #include <freerdp/codec/color.h>
33 #include "prim_internal.h"
34 #include "prim_YUV.h"
35 
36 static pstatus_t general_LumaToYUV444(const BYTE* WINPR_RESTRICT pSrcRaw[3],
37  const UINT32 srcStep[3], BYTE* WINPR_RESTRICT pDstRaw[3],
38  const UINT32 dstStep[3],
39  const RECTANGLE_16* WINPR_RESTRICT roi)
40 {
41  const UINT32 nWidth = roi->right - roi->left;
42  const UINT32 nHeight = roi->bottom - roi->top;
43  const UINT32 halfWidth = (nWidth + 1) / 2;
44  const UINT32 halfHeight = (nHeight + 1) / 2;
45  const UINT32 oddY = 1;
46  const UINT32 evenY = 0;
47  const UINT32 oddX = 1;
48  const UINT32 evenX = 0;
49  const BYTE* pSrc[3] = { pSrcRaw[0] + 1ULL * roi->top * srcStep[0] + roi->left,
50  pSrcRaw[1] + 1ULL * roi->top / 2 * srcStep[1] + roi->left / 2,
51  pSrcRaw[2] + 1ULL * roi->top / 2 * srcStep[2] + roi->left / 2 };
52  BYTE* pDst[3] = { pDstRaw[0] + 1ULL * roi->top * dstStep[0] + roi->left,
53  pDstRaw[1] + 1ULL * roi->top * dstStep[1] + roi->left,
54  pDstRaw[2] + 1ULL * roi->top * dstStep[2] + roi->left };
55 
56  /* Y data is already here... */
57  /* B1 */
58  for (size_t y = 0; y < nHeight; y++)
59  {
60  const BYTE* Ym = pSrc[0] + y * srcStep[0];
61  BYTE* pY = pDst[0] + dstStep[0] * y;
62  memcpy(pY, Ym, nWidth);
63  }
64 
65  /* The first half of U, V are already here part of this frame. */
66  /* B2 and B3 */
67  for (UINT32 y = 0; y < halfHeight; y++)
68  {
69  const UINT32 val2y = (2UL * y + evenY);
70  const UINT32 val2y1 = val2y + oddY;
71  const BYTE* Um = pSrc[1] + 1ULL * y * srcStep[1];
72  const BYTE* Vm = pSrc[2] + 1ULL * y * srcStep[2];
73  BYTE* pU = pDst[1] + 1ULL * dstStep[1] * val2y;
74  BYTE* pV = pDst[2] + 1ULL * dstStep[2] * val2y;
75  BYTE* pU1 = pDst[1] + 1ULL * dstStep[1] * val2y1;
76  BYTE* pV1 = pDst[2] + 1ULL * dstStep[2] * val2y1;
77 
78  for (UINT32 x = 0; x < halfWidth; x++)
79  {
80  const UINT32 val2x = 2UL * x + evenX;
81  const UINT32 val2x1 = val2x + oddX;
82  pU[val2x] = Um[x];
83  pV[val2x] = Vm[x];
84  pU[val2x1] = Um[x];
85  pV[val2x1] = Vm[x];
86  pU1[val2x] = Um[x];
87  pV1[val2x] = Vm[x];
88  pU1[val2x1] = Um[x];
89  pV1[val2x1] = Vm[x];
90  }
91  }
92 
93  return PRIMITIVES_SUCCESS;
94 }
95 
96 static pstatus_t general_ChromaFilter(BYTE* WINPR_RESTRICT pDst[3], const UINT32 dstStep[3],
97  const RECTANGLE_16* WINPR_RESTRICT roi)
98 {
99  const UINT32 oddY = 1;
100  const UINT32 evenY = 0;
101  const UINT32 nWidth = roi->right - roi->left;
102  const UINT32 nHeight = roi->bottom - roi->top;
103  const UINT32 halfHeight = (nHeight + 1) / 2;
104  const UINT32 halfWidth = (nWidth + 1) / 2;
105 
106  /* Filter */
107  for (UINT32 y = roi->top; y < halfHeight + roi->top; y++)
108  {
109  const UINT32 val2y = (y * 2 + evenY);
110  const UINT32 val2y1 = val2y + oddY;
111  BYTE* pU1 = pDst[1] + 1ULL * dstStep[1] * val2y1;
112  BYTE* pV1 = pDst[2] + 1ULL * dstStep[2] * val2y1;
113  BYTE* pU = pDst[1] + 1ULL * dstStep[1] * val2y;
114  BYTE* pV = pDst[2] + 1ULL * dstStep[2] * val2y;
115 
116  if (val2y1 > nHeight)
117  continue;
118 
119  for (UINT32 x = roi->left; x < halfWidth + roi->left; x++)
120  {
121  const UINT32 val2x = (x * 2);
122  const UINT32 val2x1 = val2x + 1;
123  const BYTE inU = pU[val2x];
124  const BYTE inV = pV[val2x];
125  const INT32 up = inU * 4;
126  const INT32 vp = inV * 4;
127  INT32 u2020 = 0;
128  INT32 v2020 = 0;
129 
130  if (val2x1 > nWidth)
131  continue;
132 
133  u2020 = up - pU[val2x1] - pU1[val2x] - pU1[val2x1];
134  v2020 = vp - pV[val2x1] - pV1[val2x] - pV1[val2x1];
135 
136  pU[val2x] = CONDITIONAL_CLIP(u2020, inU);
137  pV[val2x] = CONDITIONAL_CLIP(v2020, inV);
138  }
139  }
140 
141  return PRIMITIVES_SUCCESS;
142 }
143 
144 static pstatus_t general_ChromaV1ToYUV444(const BYTE* WINPR_RESTRICT pSrcRaw[3],
145  const UINT32 srcStep[3], BYTE* WINPR_RESTRICT pDstRaw[3],
146  const UINT32 dstStep[3],
147  const RECTANGLE_16* WINPR_RESTRICT roi)
148 {
149  const UINT32 mod = 16;
150  UINT32 uY = 0;
151  UINT32 vY = 0;
152  const UINT32 nWidth = roi->right - roi->left;
153  const UINT32 nHeight = roi->bottom - roi->top;
154  const UINT32 halfWidth = (nWidth) / 2;
155  const UINT32 halfHeight = (nHeight) / 2;
156  const UINT32 oddY = 1;
157  const UINT32 evenY = 0;
158  const UINT32 oddX = 1;
159  /* The auxiliary frame is aligned to multiples of 16x16.
160  * We need the padded height for B4 and B5 conversion. */
161  const UINT32 padHeigth = nHeight + 16 - nHeight % 16;
162  const BYTE* pSrc[3] = { pSrcRaw[0] + 1ULL * roi->top * srcStep[0] + roi->left,
163  pSrcRaw[1] + 1ULL * roi->top / 2 * srcStep[1] + roi->left / 2,
164  pSrcRaw[2] + 1ULL * roi->top / 2 * srcStep[2] + roi->left / 2 };
165  BYTE* pDst[3] = { pDstRaw[0] + 1ULL * roi->top * dstStep[0] + roi->left,
166  pDstRaw[1] + 1ULL * roi->top * dstStep[1] + roi->left,
167  pDstRaw[2] + 1ULL * roi->top * dstStep[2] + roi->left };
168 
169  /* The second half of U and V is a bit more tricky... */
170  /* B4 and B5 */
171  for (size_t y = 0; y < padHeigth; y++)
172  {
173  const BYTE* Ya = pSrc[0] + y * srcStep[0];
174  BYTE* pX = NULL;
175 
176  if ((y) % mod < (mod + 1) / 2)
177  {
178  const size_t pos = (2 * uY++ + oddY);
179 
180  if (pos >= nHeight)
181  continue;
182 
183  pX = pDst[1] + dstStep[1] * pos;
184  }
185  else
186  {
187  const size_t pos = (2 * vY++ + oddY);
188 
189  if (pos >= nHeight)
190  continue;
191 
192  pX = pDst[2] + dstStep[2] * pos;
193  }
194 
195  memcpy(pX, Ya, nWidth);
196  }
197 
198  /* B6 and B7 */
199  for (UINT32 y = 0; y < halfHeight; y++)
200  {
201  const UINT32 val2y = (y * 2UL + evenY);
202  const BYTE* Ua = pSrc[1] + 1ULL * y * srcStep[1];
203  const BYTE* Va = pSrc[2] + 1ULL * y * srcStep[2];
204  BYTE* pU = pDst[1] + 1ULL * dstStep[1] * val2y;
205  BYTE* pV = pDst[2] + 1ULL * dstStep[2] * val2y;
206 
207  for (UINT32 x = 0; x < halfWidth; x++)
208  {
209  const UINT32 val2x1 = (x * 2 + oddX);
210  pU[val2x1] = Ua[x];
211  pV[val2x1] = Va[x];
212  }
213  }
214 
215  /* Filter */
216  return general_ChromaFilter(pDst, dstStep, roi);
217 }
218 
219 static pstatus_t general_ChromaV2ToYUV444(const BYTE* WINPR_RESTRICT pSrc[3],
220  const UINT32 srcStep[3], UINT32 nTotalWidth,
221  UINT32 nTotalHeight, BYTE* WINPR_RESTRICT pDst[3],
222  const UINT32 dstStep[3],
223  const RECTANGLE_16* WINPR_RESTRICT roi)
224 {
225  const UINT32 nWidth = roi->right - roi->left;
226  const UINT32 nHeight = roi->bottom - roi->top;
227  const UINT32 halfWidth = (nWidth + 1) / 2;
228  const UINT32 halfHeight = (nHeight + 1) / 2;
229  const UINT32 quaterWidth = (nWidth + 3) / 4;
230 
231  /* B4 and B5: odd UV values for width/2, height */
232  for (UINT32 y = 0; y < nHeight; y++)
233  {
234  const UINT32 yTop = y + roi->top;
235  const BYTE* pYaU = pSrc[0] + 1ULL * srcStep[0] * yTop + roi->left / 2;
236  const BYTE* pYaV = pYaU + nTotalWidth / 2;
237  BYTE* pU = pDst[1] + 1ULL * dstStep[1] * yTop + roi->left;
238  BYTE* pV = pDst[2] + 1ULL * dstStep[2] * yTop + roi->left;
239 
240  for (UINT32 x = 0; x < halfWidth; x++)
241  {
242  const UINT32 odd = 2UL * x + 1UL;
243  pU[odd] = *pYaU++;
244  pV[odd] = *pYaV++;
245  }
246  }
247 
248  /* B6 - B9 */
249  for (size_t y = 0; y < halfHeight; y++)
250  {
251  const BYTE* pUaU = pSrc[1] + srcStep[1] * (y + roi->top / 2) + roi->left / 4;
252  const BYTE* pUaV = pUaU + nTotalWidth / 4;
253  const BYTE* pVaU = pSrc[2] + srcStep[2] * (y + roi->top / 2) + roi->left / 4;
254  const BYTE* pVaV = pVaU + nTotalWidth / 4;
255  BYTE* pU = pDst[1] + 1ULL * dstStep[1] * (2ULL * y + 1 + roi->top) + roi->left;
256  BYTE* pV = pDst[2] + 1ULL * dstStep[2] * (2ULL * y + 1 + roi->top) + roi->left;
257 
258  for (size_t x = 0; x < quaterWidth; x++)
259  {
260  pU[4 * x + 0] = *pUaU++;
261  pV[4 * x + 0] = *pUaV++;
262  pU[4 * x + 2] = *pVaU++;
263  pV[4 * x + 2] = *pVaV++;
264  }
265  }
266 
267  return general_ChromaFilter(pDst, dstStep, roi);
268 }
269 
270 static pstatus_t general_YUV420CombineToYUV444(avc444_frame_type type,
271  const BYTE* WINPR_RESTRICT pSrc[3],
272  const UINT32 srcStep[3], UINT32 nWidth,
273  UINT32 nHeight, BYTE* WINPR_RESTRICT pDst[3],
274  const UINT32 dstStep[3],
275  const RECTANGLE_16* WINPR_RESTRICT roi)
276 {
277  if (!pSrc || !pSrc[0] || !pSrc[1] || !pSrc[2])
278  return -1;
279 
280  if (!pDst || !pDst[0] || !pDst[1] || !pDst[2])
281  return -1;
282 
283  if (!roi)
284  return -1;
285 
286  switch (type)
287  {
288  case AVC444_LUMA:
289  return general_LumaToYUV444(pSrc, srcStep, pDst, dstStep, roi);
290 
291  case AVC444_CHROMAv1:
292  return general_ChromaV1ToYUV444(pSrc, srcStep, pDst, dstStep, roi);
293 
294  case AVC444_CHROMAv2:
295  return general_ChromaV2ToYUV444(pSrc, srcStep, nWidth, nHeight, pDst, dstStep, roi);
296 
297  default:
298  return -1;
299  }
300 }
301 
302 static pstatus_t
303 general_YUV444SplitToYUV420(const BYTE* WINPR_RESTRICT pSrc[3], const UINT32 srcStep[3],
304  BYTE* WINPR_RESTRICT pMainDst[3], const UINT32 dstMainStep[3],
305  BYTE* WINPR_RESTRICT pAuxDst[3], const UINT32 dstAuxStep[3],
306  const prim_size_t* WINPR_RESTRICT roi)
307 {
308  UINT32 uY = 0;
309  UINT32 vY = 0;
310  UINT32 halfWidth = 0;
311  UINT32 halfHeight = 0;
312  /* The auxiliary frame is aligned to multiples of 16x16.
313  * We need the padded height for B4 and B5 conversion. */
314  const UINT32 padHeigth = roi->height + 16 - roi->height % 16;
315  halfWidth = (roi->width + 1) / 2;
316  halfHeight = (roi->height + 1) / 2;
317 
318  /* B1 */
319  for (size_t y = 0; y < roi->height; y++)
320  {
321  const BYTE* pSrcY = pSrc[0] + y * srcStep[0];
322  BYTE* pY = pMainDst[0] + y * dstMainStep[0];
323  memcpy(pY, pSrcY, roi->width);
324  }
325 
326  /* B2 and B3 */
327  for (size_t y = 0; y < halfHeight; y++)
328  {
329  const BYTE* pSrcU = pSrc[1] + 2ULL * y * srcStep[1];
330  const BYTE* pSrcV = pSrc[2] + 2ULL * y * srcStep[2];
331  const BYTE* pSrcU1 = pSrc[1] + (2ULL * y + 1ULL) * srcStep[1];
332  const BYTE* pSrcV1 = pSrc[2] + (2ULL * y + 1ULL) * srcStep[2];
333  BYTE* pU = pMainDst[1] + y * dstMainStep[1];
334  BYTE* pV = pMainDst[2] + y * dstMainStep[2];
335 
336  for (size_t x = 0; x < halfWidth; x++)
337  {
338  /* Filter */
339  const INT32 u = pSrcU[2 * x] + pSrcU[2 * x + 1] + pSrcU1[2 * x] + pSrcU1[2 * x + 1];
340  const INT32 v = pSrcV[2 * x] + pSrcV[2 * x + 1] + pSrcV1[2 * x] + pSrcV1[2 * x + 1];
341  pU[x] = CLIP(u / 4L);
342  pV[x] = CLIP(v / 4L);
343  }
344  }
345 
346  /* B4 and B5 */
347  for (size_t y = 0; y < padHeigth; y++)
348  {
349  BYTE* pY = pAuxDst[0] + y * dstAuxStep[0];
350 
351  if (y % 16 < 8)
352  {
353  const size_t pos = (2 * uY++ + 1);
354  const BYTE* pSrcU = pSrc[1] + pos * srcStep[1];
355 
356  if (pos >= roi->height)
357  continue;
358 
359  memcpy(pY, pSrcU, roi->width);
360  }
361  else
362  {
363  const size_t pos = (2 * vY++ + 1);
364  const BYTE* pSrcV = pSrc[2] + pos * srcStep[2];
365 
366  if (pos >= roi->height)
367  continue;
368 
369  memcpy(pY, pSrcV, roi->width);
370  }
371  }
372 
373  /* B6 and B7 */
374  for (size_t y = 0; y < halfHeight; y++)
375  {
376  const BYTE* pSrcU = pSrc[1] + 2 * y * srcStep[1];
377  const BYTE* pSrcV = pSrc[2] + 2 * y * srcStep[2];
378  BYTE* pU = pAuxDst[1] + y * dstAuxStep[1];
379  BYTE* pV = pAuxDst[2] + y * dstAuxStep[2];
380 
381  for (size_t x = 0; x < halfWidth; x++)
382  {
383  pU[x] = pSrcU[2 * x + 1];
384  pV[x] = pSrcV[2 * x + 1];
385  }
386  }
387 
388  return PRIMITIVES_SUCCESS;
389 }
390 
391 static pstatus_t general_YUV444ToRGB_8u_P3AC4R_general(const BYTE* WINPR_RESTRICT pSrc[3],
392  const UINT32 srcStep[3],
393  BYTE* WINPR_RESTRICT pDst, UINT32 dstStep,
394  UINT32 DstFormat,
395  const prim_size_t* WINPR_RESTRICT roi)
396 {
397  const DWORD formatSize = FreeRDPGetBytesPerPixel(DstFormat);
398  fkt_writePixel writePixel = getPixelWriteFunction(DstFormat, FALSE);
399 
400  WINPR_ASSERT(pSrc);
401  WINPR_ASSERT(pDst);
402  WINPR_ASSERT(roi);
403 
404  const UINT32 nWidth = roi->width;
405  const UINT32 nHeight = roi->height;
406 
407  for (size_t y = 0; y < nHeight; y++)
408  {
409  const BYTE* pY = pSrc[0] + y * srcStep[0];
410  const BYTE* pU = pSrc[1] + y * srcStep[1];
411  const BYTE* pV = pSrc[2] + y * srcStep[2];
412  BYTE* pRGB = pDst + y * dstStep;
413 
414  for (size_t x = 0; x < nWidth; x++)
415  {
416  const BYTE Y = pY[x];
417  const BYTE U = pU[x];
418  const BYTE V = pV[x];
419  const BYTE r = YUV2R(Y, U, V);
420  const BYTE g = YUV2G(Y, U, V);
421  const BYTE b = YUV2B(Y, U, V);
422  pRGB = writePixel(pRGB, formatSize, DstFormat, r, g, b, 0);
423  }
424  }
425 
426  return PRIMITIVES_SUCCESS;
427 }
428 
429 static pstatus_t general_YUV444ToRGB_8u_P3AC4R_BGRX(const BYTE* WINPR_RESTRICT pSrc[3],
430  const UINT32 srcStep[3],
431  BYTE* WINPR_RESTRICT pDst, UINT32 dstStep,
432  UINT32 DstFormat,
433  const prim_size_t* WINPR_RESTRICT roi)
434 {
435  const DWORD formatSize = FreeRDPGetBytesPerPixel(DstFormat);
436 
437  WINPR_ASSERT(pSrc);
438  WINPR_ASSERT(pDst);
439  WINPR_ASSERT(roi);
440 
441  const UINT32 nWidth = roi->width;
442  const UINT32 nHeight = roi->height;
443 
444  for (size_t y = 0; y < nHeight; y++)
445  {
446  const BYTE* pY = pSrc[0] + y * srcStep[0];
447  const BYTE* pU = pSrc[1] + y * srcStep[1];
448  const BYTE* pV = pSrc[2] + y * srcStep[2];
449  BYTE* pRGB = pDst + y * dstStep;
450 
451  for (size_t x = 0; x < nWidth; x++)
452  {
453  const BYTE Y = pY[x];
454  const BYTE U = pU[x];
455  const BYTE V = pV[x];
456  const BYTE r = YUV2R(Y, U, V);
457  const BYTE g = YUV2G(Y, U, V);
458  const BYTE b = YUV2B(Y, U, V);
459  pRGB = writePixelBGRX(pRGB, formatSize, DstFormat, r, g, b, 0);
460  }
461  }
462 
463  return PRIMITIVES_SUCCESS;
464 }
465 
466 static pstatus_t general_YUV444ToRGB_8u_P3AC4R(const BYTE* WINPR_RESTRICT pSrc[3],
467  const UINT32 srcStep[3], BYTE* WINPR_RESTRICT pDst,
468  UINT32 dstStep, UINT32 DstFormat,
469  const prim_size_t* WINPR_RESTRICT roi)
470 {
471  switch (DstFormat)
472  {
473  case PIXEL_FORMAT_BGRA32:
474  case PIXEL_FORMAT_BGRX32:
475  return general_YUV444ToRGB_8u_P3AC4R_BGRX(pSrc, srcStep, pDst, dstStep, DstFormat, roi);
476 
477  default:
478  return general_YUV444ToRGB_8u_P3AC4R_general(pSrc, srcStep, pDst, dstStep, DstFormat,
479  roi);
480  }
481 }
487 static pstatus_t general_YUV420ToRGB_8u_P3AC4R(const BYTE* WINPR_RESTRICT pSrc[3],
488  const UINT32 srcStep[3], BYTE* WINPR_RESTRICT pDst,
489  UINT32 dstStep, UINT32 DstFormat,
490  const prim_size_t* WINPR_RESTRICT roi)
491 {
492  UINT32 dstPad = 0;
493  UINT32 srcPad[3];
494  BYTE Y = 0;
495  BYTE U = 0;
496  BYTE V = 0;
497  UINT32 halfWidth = 0;
498  UINT32 halfHeight = 0;
499  const BYTE* pY = NULL;
500  const BYTE* pU = NULL;
501  const BYTE* pV = NULL;
502  BYTE* pRGB = pDst;
503  UINT32 nWidth = 0;
504  UINT32 nHeight = 0;
505  UINT32 lastRow = 0;
506  UINT32 lastCol = 0;
507  const DWORD formatSize = FreeRDPGetBytesPerPixel(DstFormat);
508  fkt_writePixel writePixel = getPixelWriteFunction(DstFormat, FALSE);
509  pY = pSrc[0];
510  pU = pSrc[1];
511  pV = pSrc[2];
512  lastCol = roi->width & 0x01;
513  lastRow = roi->height & 0x01;
514  nWidth = (roi->width + 1) & (uint32_t)~0x0001;
515  nHeight = (roi->height + 1) & (uint32_t)~0x0001;
516  halfWidth = nWidth / 2;
517  halfHeight = nHeight / 2;
518  srcPad[0] = (srcStep[0] - nWidth);
519  srcPad[1] = (srcStep[1] - halfWidth);
520  srcPad[2] = (srcStep[2] - halfWidth);
521  dstPad = (dstStep - (nWidth * 4));
522 
523  for (UINT32 y = 0; y < halfHeight;)
524  {
525  if (++y == halfHeight)
526  lastRow <<= 1;
527 
528  for (UINT32 x = 0; x < halfWidth;)
529  {
530  BYTE r = 0;
531  BYTE g = 0;
532  BYTE b = 0;
533 
534  if (++x == halfWidth)
535  lastCol <<= 1;
536 
537  U = *pU++;
538  V = *pV++;
539  /* 1st pixel */
540  Y = *pY++;
541  r = YUV2R(Y, U, V);
542  g = YUV2G(Y, U, V);
543  b = YUV2B(Y, U, V);
544  pRGB = writePixel(pRGB, formatSize, DstFormat, r, g, b, 0);
545 
546  /* 2nd pixel */
547  if (!(lastCol & 0x02))
548  {
549  Y = *pY++;
550  r = YUV2R(Y, U, V);
551  g = YUV2G(Y, U, V);
552  b = YUV2B(Y, U, V);
553  pRGB = writePixel(pRGB, formatSize, DstFormat, r, g, b, 0);
554  }
555  else
556  {
557  pY++;
558  pRGB += formatSize;
559  lastCol >>= 1;
560  }
561  }
562 
563  pY += srcPad[0];
564  pU -= halfWidth;
565  pV -= halfWidth;
566  pRGB += dstPad;
567 
568  if (lastRow & 0x02)
569  break;
570 
571  for (UINT32 x = 0; x < halfWidth;)
572  {
573  BYTE r = 0;
574  BYTE g = 0;
575  BYTE b = 0;
576 
577  if (++x == halfWidth)
578  lastCol <<= 1;
579 
580  U = *pU++;
581  V = *pV++;
582  /* 3rd pixel */
583  Y = *pY++;
584  r = YUV2R(Y, U, V);
585  g = YUV2G(Y, U, V);
586  b = YUV2B(Y, U, V);
587  pRGB = writePixel(pRGB, formatSize, DstFormat, r, g, b, 0);
588 
589  /* 4th pixel */
590  if (!(lastCol & 0x02))
591  {
592  Y = *pY++;
593  r = YUV2R(Y, U, V);
594  g = YUV2G(Y, U, V);
595  b = YUV2B(Y, U, V);
596  pRGB = writePixel(pRGB, formatSize, DstFormat, r, g, b, 0);
597  }
598  else
599  {
600  pY++;
601  pRGB += formatSize;
602  lastCol >>= 1;
603  }
604  }
605 
606  pY += srcPad[0];
607  pU += srcPad[1];
608  pV += srcPad[2];
609  pRGB += dstPad;
610  }
611 
612  return PRIMITIVES_SUCCESS;
613 }
614 
620 static INLINE BYTE RGB2Y(INT32 R, INT32 G, INT32 B)
621 {
622  const INT32 val = ((54 * R + 183 * G + 18 * B) >> 8);
623  return WINPR_ASSERTING_INT_CAST(BYTE, val);
624 }
625 
626 static INLINE BYTE RGB2U(INT32 R, INT32 G, INT32 B)
627 {
628  const INT32 val = (((-29 * R - 99 * G + 128 * B) >> 8) + 128);
629  return WINPR_ASSERTING_INT_CAST(BYTE, val);
630 }
631 
632 static INLINE BYTE RGB2V(INT32 R, INT32 G, INT32 B)
633 {
634  const INT32 val = (((128 * R - 116 * G - 12 * B) >> 8) + 128);
635  return WINPR_ASSERTING_INT_CAST(BYTE, val);
636 }
637 
638 // NOLINTBEGIN(readability-non-const-parameter)
639 static pstatus_t general_RGBToYUV444_8u_P3AC4R(const BYTE* WINPR_RESTRICT pSrc, UINT32 SrcFormat,
640  const UINT32 srcStep, BYTE* WINPR_RESTRICT pDst[3],
641  UINT32 dstStep[3],
642  const prim_size_t* WINPR_RESTRICT roi)
643 // NOLINTEND(readability-non-const-parameter)
644 {
645  const UINT32 bpp = FreeRDPGetBytesPerPixel(SrcFormat);
646  UINT32 nWidth = 0;
647  UINT32 nHeight = 0;
648  nWidth = roi->width;
649  nHeight = roi->height;
650 
651  for (size_t y = 0; y < nHeight; y++)
652  {
653  const BYTE* pRGB = pSrc + y * srcStep;
654  BYTE* pY = pDst[0] + y * dstStep[0];
655  BYTE* pU = pDst[1] + y * dstStep[1];
656  BYTE* pV = pDst[2] + y * dstStep[2];
657 
658  for (size_t x = 0; x < nWidth; x++)
659  {
660  BYTE B = 0;
661  BYTE G = 0;
662  BYTE R = 0;
663  const UINT32 color = FreeRDPReadColor(&pRGB[x * bpp], SrcFormat);
664  FreeRDPSplitColor(color, SrcFormat, &R, &G, &B, NULL, NULL);
665  pY[x] = RGB2Y(R, G, B);
666  pU[x] = RGB2U(R, G, B);
667  pV[x] = RGB2V(R, G, B);
668  }
669  }
670 
671  return PRIMITIVES_SUCCESS;
672 }
673 
674 static INLINE pstatus_t general_RGBToYUV420_BGRX(const BYTE* WINPR_RESTRICT pSrc, UINT32 srcStep,
675  BYTE* WINPR_RESTRICT pDst[3],
676  const UINT32 dstStep[3],
677  const prim_size_t* WINPR_RESTRICT roi)
678 {
679  size_t i = 0;
680  size_t x1 = 0;
681  size_t x2 = 4;
682  size_t x3 = srcStep;
683  size_t x4 = srcStep + 4;
684  size_t y1 = 0;
685  size_t y2 = 1;
686  size_t y3 = dstStep[0];
687  size_t y4 = dstStep[0] + 1;
688  UINT32 max_x = roi->width - 1;
689  UINT32 max_y = roi->height - 1;
690 
691  for (size_t y = i = 0; y < roi->height; y += 2, i++)
692  {
693  const BYTE* src = pSrc + y * srcStep;
694  BYTE* ydst = pDst[0] + y * dstStep[0];
695  BYTE* udst = pDst[1] + i * dstStep[1];
696  BYTE* vdst = pDst[2] + i * dstStep[2];
697 
698  for (size_t x = 0; x < roi->width; x += 2)
699  {
700  BYTE R = 0;
701  BYTE G = 0;
702  BYTE B = 0;
703  INT32 Ra = 0;
704  INT32 Ga = 0;
705  INT32 Ba = 0;
706  /* row 1, pixel 1 */
707  Ba = B = *(src + x1 + 0);
708  Ga = G = *(src + x1 + 1);
709  Ra = R = *(src + x1 + 2);
710  ydst[y1] = RGB2Y(R, G, B);
711 
712  if (x < max_x)
713  {
714  /* row 1, pixel 2 */
715  Ba += B = *(src + x2 + 0);
716  Ga += G = *(src + x2 + 1);
717  Ra += R = *(src + x2 + 2);
718  ydst[y2] = RGB2Y(R, G, B);
719  }
720 
721  if (y < max_y)
722  {
723  /* row 2, pixel 1 */
724  Ba += B = *(src + x3 + 0);
725  Ga += G = *(src + x3 + 1);
726  Ra += R = *(src + x3 + 2);
727  ydst[y3] = RGB2Y(R, G, B);
728 
729  if (x < max_x)
730  {
731  /* row 2, pixel 2 */
732  Ba += B = *(src + x4 + 0);
733  Ga += G = *(src + x4 + 1);
734  Ra += R = *(src + x4 + 2);
735  ydst[y4] = RGB2Y(R, G, B);
736  }
737  }
738 
739  Ba >>= 2;
740  Ga >>= 2;
741  Ra >>= 2;
742  *udst++ = RGB2U(Ra, Ga, Ba);
743  *vdst++ = RGB2V(Ra, Ga, Ba);
744  ydst += 2;
745  src += 8;
746  }
747  }
748 
749  return PRIMITIVES_SUCCESS;
750 }
751 
752 static INLINE pstatus_t general_RGBToYUV420_RGBX(const BYTE* WINPR_RESTRICT pSrc, UINT32 srcStep,
753  BYTE* WINPR_RESTRICT pDst[3],
754  const UINT32 dstStep[3],
755  const prim_size_t* WINPR_RESTRICT roi)
756 {
757  size_t x1 = 0;
758  size_t x2 = 4;
759  size_t x3 = srcStep;
760  size_t x4 = srcStep + 4;
761  size_t y1 = 0;
762  size_t y2 = 1;
763  size_t y3 = dstStep[0];
764  size_t y4 = dstStep[0] + 1;
765  UINT32 max_x = roi->width - 1;
766  UINT32 max_y = roi->height - 1;
767 
768  for (size_t y = 0, i = 0; y < roi->height; y += 2, i++)
769  {
770  const BYTE* src = pSrc + y * srcStep;
771  BYTE* ydst = pDst[0] + y * dstStep[0];
772  BYTE* udst = pDst[1] + i * dstStep[1];
773  BYTE* vdst = pDst[2] + i * dstStep[2];
774 
775  for (UINT32 x = 0; x < roi->width; x += 2)
776  {
777  BYTE R = *(src + x1 + 0);
778  BYTE G = *(src + x1 + 1);
779  BYTE B = *(src + x1 + 2);
780  /* row 1, pixel 1 */
781  INT32 Ra = R;
782  INT32 Ga = G;
783  INT32 Ba = B;
784  ydst[y1] = RGB2Y(R, G, B);
785 
786  if (x < max_x)
787  {
788  /* row 1, pixel 2 */
789  R = *(src + x2 + 0);
790  G = *(src + x2 + 1);
791  B = *(src + x2 + 2);
792  Ra += R;
793  Ga += G;
794  Ba += B;
795  ydst[y2] = RGB2Y(R, G, B);
796  }
797 
798  if (y < max_y)
799  {
800  /* row 2, pixel 1 */
801  R = *(src + x3 + 0);
802  G = *(src + x3 + 1);
803  B = *(src + x3 + 2);
804 
805  Ra += R;
806  Ga += G;
807  Ba += B;
808  ydst[y3] = RGB2Y(R, G, B);
809 
810  if (x < max_x)
811  {
812  /* row 2, pixel 2 */
813  R = *(src + x4 + 0);
814  G = *(src + x4 + 1);
815  B = *(src + x4 + 2);
816 
817  Ra += R;
818  Ga += G;
819  Ba += B;
820  ydst[y4] = RGB2Y(R, G, B);
821  }
822  }
823 
824  Ba >>= 2;
825  Ga >>= 2;
826  Ra >>= 2;
827  *udst++ = RGB2U(Ra, Ga, Ba);
828  *vdst++ = RGB2V(Ra, Ga, Ba);
829  ydst += 2;
830  src += 8;
831  }
832  }
833 
834  return PRIMITIVES_SUCCESS;
835 }
836 
837 static INLINE pstatus_t general_RGBToYUV420_ANY(const BYTE* WINPR_RESTRICT pSrc, UINT32 srcFormat,
838  UINT32 srcStep, BYTE* WINPR_RESTRICT pDst[3],
839  const UINT32 dstStep[3],
840  const prim_size_t* WINPR_RESTRICT roi)
841 {
842  const UINT32 bpp = FreeRDPGetBytesPerPixel(srcFormat);
843  size_t x1 = 0;
844  size_t x2 = bpp;
845  size_t x3 = srcStep;
846  size_t x4 = srcStep + bpp;
847  size_t y1 = 0;
848  size_t y2 = 1;
849  size_t y3 = dstStep[0];
850  size_t y4 = dstStep[0] + 1;
851  UINT32 max_x = roi->width - 1;
852  UINT32 max_y = roi->height - 1;
853 
854  for (size_t y = 0, i = 0; y < roi->height; y += 2, i++)
855  {
856  const BYTE* src = pSrc + y * srcStep;
857  BYTE* ydst = pDst[0] + y * dstStep[0];
858  BYTE* udst = pDst[1] + i * dstStep[1];
859  BYTE* vdst = pDst[2] + i * dstStep[2];
860 
861  for (size_t x = 0; x < roi->width; x += 2)
862  {
863  BYTE R = 0;
864  BYTE G = 0;
865  BYTE B = 0;
866  INT32 Ra = 0;
867  INT32 Ga = 0;
868  INT32 Ba = 0;
869  UINT32 color = 0;
870  /* row 1, pixel 1 */
871  color = FreeRDPReadColor(src + x1, srcFormat);
872  FreeRDPSplitColor(color, srcFormat, &R, &G, &B, NULL, NULL);
873  Ra = R;
874  Ga = G;
875  Ba = B;
876  ydst[y1] = RGB2Y(R, G, B);
877 
878  if (x < max_x)
879  {
880  /* row 1, pixel 2 */
881  color = FreeRDPReadColor(src + x2, srcFormat);
882  FreeRDPSplitColor(color, srcFormat, &R, &G, &B, NULL, NULL);
883  Ra += R;
884  Ga += G;
885  Ba += B;
886  ydst[y2] = RGB2Y(R, G, B);
887  }
888 
889  if (y < max_y)
890  {
891  /* row 2, pixel 1 */
892  color = FreeRDPReadColor(src + x3, srcFormat);
893  FreeRDPSplitColor(color, srcFormat, &R, &G, &B, NULL, NULL);
894  Ra += R;
895  Ga += G;
896  Ba += B;
897  ydst[y3] = RGB2Y(R, G, B);
898 
899  if (x < max_x)
900  {
901  /* row 2, pixel 2 */
902  color = FreeRDPReadColor(src + x4, srcFormat);
903  FreeRDPSplitColor(color, srcFormat, &R, &G, &B, NULL, NULL);
904  Ra += R;
905  Ga += G;
906  Ba += B;
907  ydst[y4] = RGB2Y(R, G, B);
908  }
909  }
910 
911  Ra >>= 2;
912  Ga >>= 2;
913  Ba >>= 2;
914  *udst++ = RGB2U(Ra, Ga, Ba);
915  *vdst++ = RGB2V(Ra, Ga, Ba);
916  ydst += 2;
917  src += 2ULL * bpp;
918  }
919  }
920 
921  return PRIMITIVES_SUCCESS;
922 }
923 
924 static pstatus_t general_RGBToYUV420_8u_P3AC4R(const BYTE* WINPR_RESTRICT pSrc, UINT32 srcFormat,
925  UINT32 srcStep, BYTE* WINPR_RESTRICT pDst[3],
926  const UINT32 dstStep[3],
927  const prim_size_t* WINPR_RESTRICT roi)
928 {
929  switch (srcFormat)
930  {
931  case PIXEL_FORMAT_BGRA32:
932  case PIXEL_FORMAT_BGRX32:
933  return general_RGBToYUV420_BGRX(pSrc, srcStep, pDst, dstStep, roi);
934 
935  case PIXEL_FORMAT_RGBA32:
936  case PIXEL_FORMAT_RGBX32:
937  return general_RGBToYUV420_RGBX(pSrc, srcStep, pDst, dstStep, roi);
938 
939  default:
940  return general_RGBToYUV420_ANY(pSrc, srcFormat, srcStep, pDst, dstStep, roi);
941  }
942 }
943 
944 static INLINE void general_RGBToAVC444YUV_BGRX_DOUBLE_ROW(
945  const BYTE* WINPR_RESTRICT srcEven, const BYTE* WINPR_RESTRICT srcOdd,
946  BYTE* WINPR_RESTRICT b1Even, BYTE* WINPR_RESTRICT b1Odd, BYTE* WINPR_RESTRICT b2,
947  BYTE* WINPR_RESTRICT b3, BYTE* WINPR_RESTRICT b4, BYTE* WINPR_RESTRICT b5,
948  BYTE* WINPR_RESTRICT b6, BYTE* WINPR_RESTRICT b7, UINT32 width)
949 {
950  for (UINT32 x = 0; x < width; x += 2)
951  {
952  const BOOL lastX = (x + 1) >= width;
953  BYTE Y1e = 0;
954  BYTE Y2e = 0;
955  BYTE U1e = 0;
956  BYTE V1e = 0;
957  BYTE U2e = 0;
958  BYTE V2e = 0;
959  BYTE Y1o = 0;
960  BYTE Y2o = 0;
961  BYTE U1o = 0;
962  BYTE V1o = 0;
963  BYTE U2o = 0;
964  BYTE V2o = 0;
965  /* Read 4 pixels, 2 from even, 2 from odd lines */
966  {
967  const BYTE b = *srcEven++;
968  const BYTE g = *srcEven++;
969  const BYTE r = *srcEven++;
970  srcEven++;
971  Y1e = Y2e = Y1o = Y2o = RGB2Y(r, g, b);
972  U1e = U2e = U1o = U2o = RGB2U(r, g, b);
973  V1e = V2e = V1o = V2o = RGB2V(r, g, b);
974  }
975 
976  if (!lastX)
977  {
978  const BYTE b = *srcEven++;
979  const BYTE g = *srcEven++;
980  const BYTE r = *srcEven++;
981  srcEven++;
982  Y2e = RGB2Y(r, g, b);
983  U2e = RGB2U(r, g, b);
984  V2e = RGB2V(r, g, b);
985  }
986 
987  if (b1Odd)
988  {
989  const BYTE b = *srcOdd++;
990  const BYTE g = *srcOdd++;
991  const BYTE r = *srcOdd++;
992  srcOdd++;
993  Y1o = Y2o = RGB2Y(r, g, b);
994  U1o = U2o = RGB2U(r, g, b);
995  V1o = V2o = RGB2V(r, g, b);
996  }
997 
998  if (b1Odd && !lastX)
999  {
1000  const BYTE b = *srcOdd++;
1001  const BYTE g = *srcOdd++;
1002  const BYTE r = *srcOdd++;
1003  srcOdd++;
1004  Y2o = RGB2Y(r, g, b);
1005  U2o = RGB2U(r, g, b);
1006  V2o = RGB2V(r, g, b);
1007  }
1008 
1009  /* We have 4 Y pixels, so store them. */
1010  *b1Even++ = Y1e;
1011  *b1Even++ = Y2e;
1012 
1013  if (b1Odd)
1014  {
1015  *b1Odd++ = Y1o;
1016  *b1Odd++ = Y2o;
1017  }
1018 
1019  /* 2x 2y pixel in luma UV plane use averaging
1020  */
1021  {
1022  const BYTE Uavg = WINPR_ASSERTING_INT_CAST(BYTE, ((UINT16)U1e + U2e + U1o + U2o) / 4);
1023  const BYTE Vavg = WINPR_ASSERTING_INT_CAST(BYTE, ((UINT16)V1e + V2e + V1o + V2o) / 4);
1024  *b2++ = Uavg;
1025  *b3++ = Vavg;
1026  }
1027 
1028  /* UV from 2x, 2y+1 */
1029  if (b1Odd)
1030  {
1031  *b4++ = U1o;
1032  *b5++ = V1o;
1033 
1034  if (!lastX)
1035  {
1036  *b4++ = U2o;
1037  *b5++ = V2o;
1038  }
1039  }
1040 
1041  /* UV from 2x+1, 2y */
1042  if (!lastX)
1043  {
1044  *b6++ = U2e;
1045  *b7++ = V2e;
1046  }
1047  }
1048 }
1049 
1050 static INLINE pstatus_t general_RGBToAVC444YUV_BGRX(const BYTE* WINPR_RESTRICT pSrc, UINT32 srcStep,
1051  BYTE* WINPR_RESTRICT pDst1[3],
1052  const UINT32 dst1Step[3],
1053  BYTE* WINPR_RESTRICT pDst2[3],
1054  const UINT32 dst2Step[3],
1055  const prim_size_t* WINPR_RESTRICT roi)
1056 {
1061  const BYTE* pMaxSrc = pSrc + 1ULL * (roi->height - 1) * srcStep;
1062 
1063  for (UINT32 y = 0; y < roi->height; y += 2)
1064  {
1065  const BOOL last = (y >= (roi->height - 1));
1066  const BYTE* srcEven = y < roi->height ? pSrc + 1ULL * y * srcStep : pMaxSrc;
1067  const BYTE* srcOdd = !last ? pSrc + 1ULL * (y + 1) * srcStep : pMaxSrc;
1068  const UINT32 i = y >> 1;
1069  const UINT32 n = (i & (uint32_t)~7) + i;
1070  BYTE* b1Even = pDst1[0] + 1ULL * y * dst1Step[0];
1071  BYTE* b1Odd = !last ? (b1Even + dst1Step[0]) : NULL;
1072  BYTE* b2 = pDst1[1] + 1ULL * (y / 2) * dst1Step[1];
1073  BYTE* b3 = pDst1[2] + 1ULL * (y / 2) * dst1Step[2];
1074  BYTE* b4 = pDst2[0] + 1ULL * dst2Step[0] * n;
1075  BYTE* b5 = b4 + 8ULL * dst2Step[0];
1076  BYTE* b6 = pDst2[1] + 1ULL * (y / 2) * dst2Step[1];
1077  BYTE* b7 = pDst2[2] + 1ULL * (y / 2) * dst2Step[2];
1078  general_RGBToAVC444YUV_BGRX_DOUBLE_ROW(srcEven, srcOdd, b1Even, b1Odd, b2, b3, b4, b5, b6,
1079  b7, roi->width);
1080  }
1081 
1082  return PRIMITIVES_SUCCESS;
1083 }
1084 
1085 static INLINE void general_RGBToAVC444YUV_RGBX_DOUBLE_ROW(
1086  const BYTE* WINPR_RESTRICT srcEven, const BYTE* WINPR_RESTRICT srcOdd,
1087  BYTE* WINPR_RESTRICT b1Even, BYTE* WINPR_RESTRICT b1Odd, BYTE* WINPR_RESTRICT b2,
1088  BYTE* WINPR_RESTRICT b3, BYTE* WINPR_RESTRICT b4, BYTE* WINPR_RESTRICT b5,
1089  BYTE* WINPR_RESTRICT b6, BYTE* WINPR_RESTRICT b7, UINT32 width)
1090 {
1091  for (UINT32 x = 0; x < width; x += 2)
1092  {
1093  const BOOL lastX = (x + 1) >= width;
1094  BYTE Y1e = 0;
1095  BYTE Y2e = 0;
1096  BYTE U1e = 0;
1097  BYTE V1e = 0;
1098  BYTE U2e = 0;
1099  BYTE V2e = 0;
1100  BYTE Y1o = 0;
1101  BYTE Y2o = 0;
1102  BYTE U1o = 0;
1103  BYTE V1o = 0;
1104  BYTE U2o = 0;
1105  BYTE V2o = 0;
1106  /* Read 4 pixels, 2 from even, 2 from odd lines */
1107  {
1108  const BYTE r = *srcEven++;
1109  const BYTE g = *srcEven++;
1110  const BYTE b = *srcEven++;
1111  srcEven++;
1112  Y1e = Y2e = Y1o = Y2o = RGB2Y(r, g, b);
1113  U1e = U2e = U1o = U2o = RGB2U(r, g, b);
1114  V1e = V2e = V1o = V2o = RGB2V(r, g, b);
1115  }
1116 
1117  if (!lastX)
1118  {
1119  const BYTE r = *srcEven++;
1120  const BYTE g = *srcEven++;
1121  const BYTE b = *srcEven++;
1122  srcEven++;
1123  Y2e = RGB2Y(r, g, b);
1124  U2e = RGB2U(r, g, b);
1125  V2e = RGB2V(r, g, b);
1126  }
1127 
1128  if (b1Odd)
1129  {
1130  const BYTE r = *srcOdd++;
1131  const BYTE g = *srcOdd++;
1132  const BYTE b = *srcOdd++;
1133  srcOdd++;
1134  Y1o = Y2o = RGB2Y(r, g, b);
1135  U1o = U2o = RGB2U(r, g, b);
1136  V1o = V2o = RGB2V(r, g, b);
1137  }
1138 
1139  if (b1Odd && !lastX)
1140  {
1141  const BYTE r = *srcOdd++;
1142  const BYTE g = *srcOdd++;
1143  const BYTE b = *srcOdd++;
1144  srcOdd++;
1145  Y2o = RGB2Y(r, g, b);
1146  U2o = RGB2U(r, g, b);
1147  V2o = RGB2V(r, g, b);
1148  }
1149 
1150  /* We have 4 Y pixels, so store them. */
1151  *b1Even++ = Y1e;
1152  *b1Even++ = Y2e;
1153 
1154  if (b1Odd)
1155  {
1156  *b1Odd++ = Y1o;
1157  *b1Odd++ = Y2o;
1158  }
1159 
1160  /* 2x 2y pixel in luma UV plane use averaging
1161  */
1162  {
1163  const BYTE Uavg = WINPR_ASSERTING_INT_CAST(BYTE, ((UINT16)U1e + U2e + U1o + U2o) / 4);
1164  const BYTE Vavg = WINPR_ASSERTING_INT_CAST(BYTE, ((UINT16)V1e + V2e + V1o + V2o) / 4);
1165  *b2++ = Uavg;
1166  *b3++ = Vavg;
1167  }
1168 
1169  /* UV from 2x, 2y+1 */
1170  if (b1Odd)
1171  {
1172  *b4++ = U1o;
1173  *b5++ = V1o;
1174 
1175  if (!lastX)
1176  {
1177  *b4++ = U2o;
1178  *b5++ = V2o;
1179  }
1180  }
1181 
1182  /* UV from 2x+1, 2y */
1183  if (!lastX)
1184  {
1185  *b6++ = U2e;
1186  *b7++ = V2e;
1187  }
1188  }
1189 }
1190 
1191 static INLINE pstatus_t general_RGBToAVC444YUV_RGBX(const BYTE* WINPR_RESTRICT pSrc, UINT32 srcStep,
1192  BYTE* WINPR_RESTRICT pDst1[3],
1193  const UINT32 dst1Step[3],
1194  BYTE* WINPR_RESTRICT pDst2[3],
1195  const UINT32 dst2Step[3],
1196  const prim_size_t* WINPR_RESTRICT roi)
1197 {
1202  const BYTE* pMaxSrc = pSrc + 1ULL * (roi->height - 1) * srcStep;
1203 
1204  for (UINT32 y = 0; y < roi->height; y += 2)
1205  {
1206  const BOOL last = (y >= (roi->height - 1));
1207  const BYTE* srcEven = y < roi->height ? pSrc + 1ULL * y * srcStep : pMaxSrc;
1208  const BYTE* srcOdd = !last ? pSrc + 1ULL * (y + 1) * srcStep : pMaxSrc;
1209  const UINT32 i = y >> 1;
1210  const UINT32 n = (i & (uint32_t)~7) + i;
1211  BYTE* b1Even = pDst1[0] + 1ULL * y * dst1Step[0];
1212  BYTE* b1Odd = !last ? (b1Even + dst1Step[0]) : NULL;
1213  BYTE* b2 = pDst1[1] + 1ULL * (y / 2) * dst1Step[1];
1214  BYTE* b3 = pDst1[2] + 1ULL * (y / 2) * dst1Step[2];
1215  BYTE* b4 = pDst2[0] + 1ULL * dst2Step[0] * n;
1216  BYTE* b5 = b4 + 8ULL * dst2Step[0];
1217  BYTE* b6 = pDst2[1] + 1ULL * (y / 2) * dst2Step[1];
1218  BYTE* b7 = pDst2[2] + 1ULL * (y / 2) * dst2Step[2];
1219  general_RGBToAVC444YUV_RGBX_DOUBLE_ROW(srcEven, srcOdd, b1Even, b1Odd, b2, b3, b4, b5, b6,
1220  b7, roi->width);
1221  }
1222 
1223  return PRIMITIVES_SUCCESS;
1224 }
1225 
1226 static INLINE void general_RGBToAVC444YUV_ANY_DOUBLE_ROW(
1227  const BYTE* WINPR_RESTRICT srcEven, const BYTE* WINPR_RESTRICT srcOdd, UINT32 srcFormat,
1228  BYTE* WINPR_RESTRICT b1Even, BYTE* WINPR_RESTRICT b1Odd, BYTE* WINPR_RESTRICT b2,
1229  BYTE* WINPR_RESTRICT b3, BYTE* WINPR_RESTRICT b4, BYTE* WINPR_RESTRICT b5,
1230  BYTE* WINPR_RESTRICT b6, BYTE* WINPR_RESTRICT b7, UINT32 width)
1231 {
1232  const UINT32 bpp = FreeRDPGetBytesPerPixel(srcFormat);
1233  for (UINT32 x = 0; x < width; x += 2)
1234  {
1235  const BOOL lastX = (x + 1) >= width;
1236  BYTE Y1e = 0;
1237  BYTE Y2e = 0;
1238  BYTE U1e = 0;
1239  BYTE V1e = 0;
1240  BYTE U2e = 0;
1241  BYTE V2e = 0;
1242  BYTE Y1o = 0;
1243  BYTE Y2o = 0;
1244  BYTE U1o = 0;
1245  BYTE V1o = 0;
1246  BYTE U2o = 0;
1247  BYTE V2o = 0;
1248  /* Read 4 pixels, 2 from even, 2 from odd lines */
1249  {
1250  BYTE r = 0;
1251  BYTE g = 0;
1252  BYTE b = 0;
1253  const UINT32 color = FreeRDPReadColor(srcEven, srcFormat);
1254  srcEven += bpp;
1255  FreeRDPSplitColor(color, srcFormat, &r, &g, &b, NULL, NULL);
1256  Y1e = Y2e = Y1o = Y2o = RGB2Y(r, g, b);
1257  U1e = U2e = U1o = U2o = RGB2U(r, g, b);
1258  V1e = V2e = V1o = V2o = RGB2V(r, g, b);
1259  }
1260 
1261  if (!lastX)
1262  {
1263  BYTE r = 0;
1264  BYTE g = 0;
1265  BYTE b = 0;
1266  const UINT32 color = FreeRDPReadColor(srcEven, srcFormat);
1267  srcEven += bpp;
1268  FreeRDPSplitColor(color, srcFormat, &r, &g, &b, NULL, NULL);
1269  Y2e = RGB2Y(r, g, b);
1270  U2e = RGB2U(r, g, b);
1271  V2e = RGB2V(r, g, b);
1272  }
1273 
1274  if (b1Odd)
1275  {
1276  BYTE r = 0;
1277  BYTE g = 0;
1278  BYTE b = 0;
1279  const UINT32 color = FreeRDPReadColor(srcOdd, srcFormat);
1280  srcOdd += bpp;
1281  FreeRDPSplitColor(color, srcFormat, &r, &g, &b, NULL, NULL);
1282  Y1o = Y2o = RGB2Y(r, g, b);
1283  U1o = U2o = RGB2U(r, g, b);
1284  V1o = V2o = RGB2V(r, g, b);
1285  }
1286 
1287  if (b1Odd && !lastX)
1288  {
1289  BYTE r = 0;
1290  BYTE g = 0;
1291  BYTE b = 0;
1292  const UINT32 color = FreeRDPReadColor(srcOdd, srcFormat);
1293  srcOdd += bpp;
1294  FreeRDPSplitColor(color, srcFormat, &r, &g, &b, NULL, NULL);
1295  Y2o = RGB2Y(r, g, b);
1296  U2o = RGB2U(r, g, b);
1297  V2o = RGB2V(r, g, b);
1298  }
1299 
1300  /* We have 4 Y pixels, so store them. */
1301  *b1Even++ = Y1e;
1302  *b1Even++ = Y2e;
1303 
1304  if (b1Odd)
1305  {
1306  *b1Odd++ = Y1o;
1307  *b1Odd++ = Y2o;
1308  }
1309 
1310  /* 2x 2y pixel in luma UV plane use averaging
1311  */
1312  {
1313  const BYTE Uavg = WINPR_ASSERTING_INT_CAST(
1314  BYTE, ((UINT16)U1e + (UINT16)U2e + (UINT16)U1o + (UINT16)U2o) / 4);
1315  const BYTE Vavg = WINPR_ASSERTING_INT_CAST(
1316  BYTE, ((UINT16)V1e + (UINT16)V2e + (UINT16)V1o + (UINT16)V2o) / 4);
1317  *b2++ = Uavg;
1318  *b3++ = Vavg;
1319  }
1320 
1321  /* UV from 2x, 2y+1 */
1322  if (b1Odd)
1323  {
1324  *b4++ = U1o;
1325  *b5++ = V1o;
1326 
1327  if (!lastX)
1328  {
1329  *b4++ = U2o;
1330  *b5++ = V2o;
1331  }
1332  }
1333 
1334  /* UV from 2x+1, 2y */
1335  if (!lastX)
1336  {
1337  *b6++ = U2e;
1338  *b7++ = V2e;
1339  }
1340  }
1341 }
1342 
1343 static INLINE pstatus_t general_RGBToAVC444YUV_ANY(
1344  const BYTE* WINPR_RESTRICT pSrc, UINT32 srcFormat, UINT32 srcStep,
1345  BYTE* WINPR_RESTRICT pDst1[3], const UINT32 dst1Step[3], BYTE* WINPR_RESTRICT pDst2[3],
1346  const UINT32 dst2Step[3], const prim_size_t* WINPR_RESTRICT roi)
1347 {
1405  const BYTE* pMaxSrc = pSrc + 1ULL * (roi->height - 1) * srcStep;
1406 
1407  for (size_t y = 0; y < roi->height; y += 2)
1408  {
1409  WINPR_ASSERT(y < UINT32_MAX);
1410 
1411  const BOOL last = (y >= (roi->height - 1));
1412  const BYTE* srcEven = y < roi->height ? pSrc + y * srcStep : pMaxSrc;
1413  const BYTE* srcOdd = !last ? pSrc + (y + 1) * srcStep : pMaxSrc;
1414  const UINT32 i = (UINT32)y >> 1;
1415  const UINT32 n = (i & (uint32_t)~7) + i;
1416  BYTE* b1Even = pDst1[0] + y * dst1Step[0];
1417  BYTE* b1Odd = !last ? (b1Even + dst1Step[0]) : NULL;
1418  BYTE* b2 = pDst1[1] + (y / 2) * dst1Step[1];
1419  BYTE* b3 = pDst1[2] + (y / 2) * dst1Step[2];
1420  BYTE* b4 = pDst2[0] + 1ULL * dst2Step[0] * n;
1421  BYTE* b5 = b4 + 8ULL * dst2Step[0];
1422  BYTE* b6 = pDst2[1] + (y / 2) * dst2Step[1];
1423  BYTE* b7 = pDst2[2] + (y / 2) * dst2Step[2];
1424  general_RGBToAVC444YUV_ANY_DOUBLE_ROW(srcEven, srcOdd, srcFormat, b1Even, b1Odd, b2, b3, b4,
1425  b5, b6, b7, roi->width);
1426  }
1427 
1428  return PRIMITIVES_SUCCESS;
1429 }
1430 
1431 static INLINE pstatus_t general_RGBToAVC444YUV(const BYTE* WINPR_RESTRICT pSrc, UINT32 srcFormat,
1432  UINT32 srcStep, BYTE* WINPR_RESTRICT pDst1[3],
1433  const UINT32 dst1Step[3],
1434  BYTE* WINPR_RESTRICT pDst2[3],
1435  const UINT32 dst2Step[3],
1436  const prim_size_t* WINPR_RESTRICT roi)
1437 {
1438  if (!pSrc || !pDst1 || !dst1Step || !pDst2 || !dst2Step)
1439  return -1;
1440 
1441  if (!pDst1[0] || !pDst1[1] || !pDst1[2])
1442  return -1;
1443 
1444  if (!dst1Step[0] || !dst1Step[1] || !dst1Step[2])
1445  return -1;
1446 
1447  if (!pDst2[0] || !pDst2[1] || !pDst2[2])
1448  return -1;
1449 
1450  if (!dst2Step[0] || !dst2Step[1] || !dst2Step[2])
1451  return -1;
1452 
1453  switch (srcFormat)
1454  {
1455  case PIXEL_FORMAT_BGRA32:
1456  case PIXEL_FORMAT_BGRX32:
1457  return general_RGBToAVC444YUV_BGRX(pSrc, srcStep, pDst1, dst1Step, pDst2, dst2Step,
1458  roi);
1459 
1460  case PIXEL_FORMAT_RGBA32:
1461  case PIXEL_FORMAT_RGBX32:
1462  return general_RGBToAVC444YUV_RGBX(pSrc, srcStep, pDst1, dst1Step, pDst2, dst2Step,
1463  roi);
1464 
1465  default:
1466  return general_RGBToAVC444YUV_ANY(pSrc, srcFormat, srcStep, pDst1, dst1Step, pDst2,
1467  dst2Step, roi);
1468  }
1469 
1470  return !PRIMITIVES_SUCCESS;
1471 }
1472 
1473 static INLINE void general_RGBToAVC444YUVv2_ANY_DOUBLE_ROW(
1474  const BYTE* WINPR_RESTRICT srcEven, const BYTE* WINPR_RESTRICT srcOdd, UINT32 srcFormat,
1475  BYTE* WINPR_RESTRICT yLumaDstEven, BYTE* WINPR_RESTRICT yLumaDstOdd,
1476  BYTE* WINPR_RESTRICT uLumaDst, BYTE* WINPR_RESTRICT vLumaDst,
1477  BYTE* WINPR_RESTRICT yEvenChromaDst1, BYTE* WINPR_RESTRICT yEvenChromaDst2,
1478  BYTE* WINPR_RESTRICT yOddChromaDst1, BYTE* WINPR_RESTRICT yOddChromaDst2,
1479  BYTE* WINPR_RESTRICT uChromaDst1, BYTE* WINPR_RESTRICT uChromaDst2,
1480  BYTE* WINPR_RESTRICT vChromaDst1, BYTE* WINPR_RESTRICT vChromaDst2, UINT32 width)
1481 {
1482  const UINT32 bpp = FreeRDPGetBytesPerPixel(srcFormat);
1483 
1484  for (UINT32 x = 0; x < width; x += 2)
1485  {
1486  BYTE Ya = 0;
1487  BYTE Ua = 0;
1488  BYTE Va = 0;
1489  BYTE Yb = 0;
1490  BYTE Ub = 0;
1491  BYTE Vb = 0;
1492  BYTE Yc = 0;
1493  BYTE Uc = 0;
1494  BYTE Vc = 0;
1495  BYTE Yd = 0;
1496  BYTE Ud = 0;
1497  BYTE Vd = 0;
1498  {
1499  BYTE b = 0;
1500  BYTE g = 0;
1501  BYTE r = 0;
1502  const UINT32 color = FreeRDPReadColor(srcEven, srcFormat);
1503  srcEven += bpp;
1504  FreeRDPSplitColor(color, srcFormat, &r, &g, &b, NULL, NULL);
1505  Ya = RGB2Y(r, g, b);
1506  Ua = RGB2U(r, g, b);
1507  Va = RGB2V(r, g, b);
1508  }
1509 
1510  if (x < width - 1)
1511  {
1512  BYTE b = 0;
1513  BYTE g = 0;
1514  BYTE r = 0;
1515  const UINT32 color = FreeRDPReadColor(srcEven, srcFormat);
1516  srcEven += bpp;
1517  FreeRDPSplitColor(color, srcFormat, &r, &g, &b, NULL, NULL);
1518  Yb = RGB2Y(r, g, b);
1519  Ub = RGB2U(r, g, b);
1520  Vb = RGB2V(r, g, b);
1521  }
1522  else
1523  {
1524  Yb = Ya;
1525  Ub = Ua;
1526  Vb = Va;
1527  }
1528 
1529  if (srcOdd)
1530  {
1531  BYTE b = 0;
1532  BYTE g = 0;
1533  BYTE r = 0;
1534  const UINT32 color = FreeRDPReadColor(srcOdd, srcFormat);
1535  srcOdd += bpp;
1536  FreeRDPSplitColor(color, srcFormat, &r, &g, &b, NULL, NULL);
1537  Yc = RGB2Y(r, g, b);
1538  Uc = RGB2U(r, g, b);
1539  Vc = RGB2V(r, g, b);
1540  }
1541  else
1542  {
1543  Yc = Ya;
1544  Uc = Ua;
1545  Vc = Va;
1546  }
1547 
1548  if (srcOdd && (x < width - 1))
1549  {
1550  BYTE b = 0;
1551  BYTE g = 0;
1552  BYTE r = 0;
1553  const UINT32 color = FreeRDPReadColor(srcOdd, srcFormat);
1554  srcOdd += bpp;
1555  FreeRDPSplitColor(color, srcFormat, &r, &g, &b, NULL, NULL);
1556  Yd = RGB2Y(r, g, b);
1557  Ud = RGB2U(r, g, b);
1558  Vd = RGB2V(r, g, b);
1559  }
1560  else
1561  {
1562  Yd = Ya;
1563  Ud = Ua;
1564  Vd = Va;
1565  }
1566 
1567  /* Y [b1] */
1568  *yLumaDstEven++ = Ya;
1569 
1570  if (x < width - 1)
1571  *yLumaDstEven++ = Yb;
1572 
1573  if (srcOdd)
1574  *yLumaDstOdd++ = Yc;
1575 
1576  if (srcOdd && (x < width - 1))
1577  *yLumaDstOdd++ = Yd;
1578 
1579  /* 2x 2y [b2,b3] */
1580  *uLumaDst++ = (Ua + Ub + Uc + Ud) / 4;
1581  *vLumaDst++ = (Va + Vb + Vc + Vd) / 4;
1582 
1583  /* 2x+1, y [b4,b5] even */
1584  if (x < width - 1)
1585  {
1586  *yEvenChromaDst1++ = Ub;
1587  *yEvenChromaDst2++ = Vb;
1588  }
1589 
1590  if (srcOdd)
1591  {
1592  /* 2x+1, y [b4,b5] odd */
1593  if (x < width - 1)
1594  {
1595  *yOddChromaDst1++ = Ud;
1596  *yOddChromaDst2++ = Vd;
1597  }
1598 
1599  /* 4x 2y+1 [b6, b7] */
1600  if (x % 4 == 0)
1601  {
1602  *uChromaDst1++ = Uc;
1603  *uChromaDst2++ = Vc;
1604  }
1605  /* 4x+2 2y+1 [b8, b9] */
1606  else
1607  {
1608  *vChromaDst1++ = Uc;
1609  *vChromaDst2++ = Vc;
1610  }
1611  }
1612  }
1613 }
1614 
1615 static INLINE pstatus_t general_RGBToAVC444YUVv2_ANY(
1616  const BYTE* WINPR_RESTRICT pSrc, UINT32 srcFormat, UINT32 srcStep,
1617  BYTE* WINPR_RESTRICT pDst1[3], const UINT32 dst1Step[3], BYTE* WINPR_RESTRICT pDst2[3],
1618  const UINT32 dst2Step[3], const prim_size_t* WINPR_RESTRICT roi)
1619 {
1670  if (roi->height < 1 || roi->width < 1)
1671  return !PRIMITIVES_SUCCESS;
1672 
1673  for (size_t y = 0; y < roi->height; y += 2)
1674  {
1675  const BYTE* srcEven = (pSrc + y * srcStep);
1676  const BYTE* srcOdd = (y < roi->height - 1) ? (srcEven + srcStep) : NULL;
1677  BYTE* dstLumaYEven = (pDst1[0] + y * dst1Step[0]);
1678  BYTE* dstLumaYOdd = (dstLumaYEven + dst1Step[0]);
1679  BYTE* dstLumaU = (pDst1[1] + (y / 2) * dst1Step[1]);
1680  BYTE* dstLumaV = (pDst1[2] + (y / 2) * dst1Step[2]);
1681  BYTE* dstEvenChromaY1 = (pDst2[0] + y * dst2Step[0]);
1682  BYTE* dstEvenChromaY2 = dstEvenChromaY1 + roi->width / 2;
1683  BYTE* dstOddChromaY1 = dstEvenChromaY1 + dst2Step[0];
1684  BYTE* dstOddChromaY2 = dstEvenChromaY2 + dst2Step[0];
1685  BYTE* dstChromaU1 = (pDst2[1] + (y / 2) * dst2Step[1]);
1686  BYTE* dstChromaV1 = (pDst2[2] + (y / 2) * dst2Step[2]);
1687  BYTE* dstChromaU2 = dstChromaU1 + roi->width / 4;
1688  BYTE* dstChromaV2 = dstChromaV1 + roi->width / 4;
1689  general_RGBToAVC444YUVv2_ANY_DOUBLE_ROW(
1690  srcEven, srcOdd, srcFormat, dstLumaYEven, dstLumaYOdd, dstLumaU, dstLumaV,
1691  dstEvenChromaY1, dstEvenChromaY2, dstOddChromaY1, dstOddChromaY2, dstChromaU1,
1692  dstChromaU2, dstChromaV1, dstChromaV2, roi->width);
1693  }
1694 
1695  return PRIMITIVES_SUCCESS;
1696 }
1697 
1698 static INLINE void general_RGBToAVC444YUVv2_BGRX_DOUBLE_ROW(
1699  const BYTE* WINPR_RESTRICT srcEven, const BYTE* WINPR_RESTRICT srcOdd,
1700  BYTE* WINPR_RESTRICT yLumaDstEven, BYTE* WINPR_RESTRICT yLumaDstOdd,
1701  BYTE* WINPR_RESTRICT uLumaDst, BYTE* WINPR_RESTRICT vLumaDst,
1702  BYTE* WINPR_RESTRICT yEvenChromaDst1, BYTE* WINPR_RESTRICT yEvenChromaDst2,
1703  BYTE* WINPR_RESTRICT yOddChromaDst1, BYTE* WINPR_RESTRICT yOddChromaDst2,
1704  BYTE* WINPR_RESTRICT uChromaDst1, BYTE* WINPR_RESTRICT uChromaDst2,
1705  BYTE* WINPR_RESTRICT vChromaDst1, BYTE* WINPR_RESTRICT vChromaDst2, UINT32 width)
1706 {
1707  for (UINT32 x = 0; x < width; x += 2)
1708  {
1709  BYTE Ya = 0;
1710  BYTE Ua = 0;
1711  BYTE Va = 0;
1712  BYTE Yb = 0;
1713  BYTE Ub = 0;
1714  BYTE Vb = 0;
1715  BYTE Yc = 0;
1716  BYTE Uc = 0;
1717  BYTE Vc = 0;
1718  BYTE Yd = 0;
1719  BYTE Ud = 0;
1720  BYTE Vd = 0;
1721  {
1722  const BYTE b = *srcEven++;
1723  const BYTE g = *srcEven++;
1724  const BYTE r = *srcEven++;
1725  srcEven++;
1726  Ya = RGB2Y(r, g, b);
1727  Ua = RGB2U(r, g, b);
1728  Va = RGB2V(r, g, b);
1729  }
1730 
1731  if (x < width - 1)
1732  {
1733  const BYTE b = *srcEven++;
1734  const BYTE g = *srcEven++;
1735  const BYTE r = *srcEven++;
1736  srcEven++;
1737  Yb = RGB2Y(r, g, b);
1738  Ub = RGB2U(r, g, b);
1739  Vb = RGB2V(r, g, b);
1740  }
1741  else
1742  {
1743  Yb = Ya;
1744  Ub = Ua;
1745  Vb = Va;
1746  }
1747 
1748  if (srcOdd)
1749  {
1750  const BYTE b = *srcOdd++;
1751  const BYTE g = *srcOdd++;
1752  const BYTE r = *srcOdd++;
1753  srcOdd++;
1754  Yc = RGB2Y(r, g, b);
1755  Uc = RGB2U(r, g, b);
1756  Vc = RGB2V(r, g, b);
1757  }
1758  else
1759  {
1760  Yc = Ya;
1761  Uc = Ua;
1762  Vc = Va;
1763  }
1764 
1765  if (srcOdd && (x < width - 1))
1766  {
1767  const BYTE b = *srcOdd++;
1768  const BYTE g = *srcOdd++;
1769  const BYTE r = *srcOdd++;
1770  srcOdd++;
1771  Yd = RGB2Y(r, g, b);
1772  Ud = RGB2U(r, g, b);
1773  Vd = RGB2V(r, g, b);
1774  }
1775  else
1776  {
1777  Yd = Ya;
1778  Ud = Ua;
1779  Vd = Va;
1780  }
1781 
1782  /* Y [b1] */
1783  *yLumaDstEven++ = Ya;
1784 
1785  if (x < width - 1)
1786  *yLumaDstEven++ = Yb;
1787 
1788  if (srcOdd)
1789  *yLumaDstOdd++ = Yc;
1790 
1791  if (srcOdd && (x < width - 1))
1792  *yLumaDstOdd++ = Yd;
1793 
1794  /* 2x 2y [b2,b3] */
1795  *uLumaDst++ = (Ua + Ub + Uc + Ud) / 4;
1796  *vLumaDst++ = (Va + Vb + Vc + Vd) / 4;
1797 
1798  /* 2x+1, y [b4,b5] even */
1799  if (x < width - 1)
1800  {
1801  *yEvenChromaDst1++ = Ub;
1802  *yEvenChromaDst2++ = Vb;
1803  }
1804 
1805  if (srcOdd)
1806  {
1807  /* 2x+1, y [b4,b5] odd */
1808  if (x < width - 1)
1809  {
1810  *yOddChromaDst1++ = Ud;
1811  *yOddChromaDst2++ = Vd;
1812  }
1813 
1814  /* 4x 2y+1 [b6, b7] */
1815  if (x % 4 == 0)
1816  {
1817  *uChromaDst1++ = Uc;
1818  *uChromaDst2++ = Vc;
1819  }
1820  /* 4x+2 2y+1 [b8, b9] */
1821  else
1822  {
1823  *vChromaDst1++ = Uc;
1824  *vChromaDst2++ = Vc;
1825  }
1826  }
1827  }
1828 }
1829 
1830 static INLINE pstatus_t general_RGBToAVC444YUVv2_BGRX(const BYTE* WINPR_RESTRICT pSrc,
1831  UINT32 srcStep, BYTE* WINPR_RESTRICT pDst1[3],
1832  const UINT32 dst1Step[3],
1833  BYTE* WINPR_RESTRICT pDst2[3],
1834  const UINT32 dst2Step[3],
1835  const prim_size_t* WINPR_RESTRICT roi)
1836 {
1837  if (roi->height < 1 || roi->width < 1)
1838  return !PRIMITIVES_SUCCESS;
1839 
1840  for (size_t y = 0; y < roi->height; y += 2)
1841  {
1842  const BYTE* srcEven = (pSrc + y * srcStep);
1843  const BYTE* srcOdd = (y < roi->height - 1) ? (srcEven + srcStep) : NULL;
1844  BYTE* dstLumaYEven = (pDst1[0] + y * dst1Step[0]);
1845  BYTE* dstLumaYOdd = (dstLumaYEven + dst1Step[0]);
1846  BYTE* dstLumaU = (pDst1[1] + (y / 2) * dst1Step[1]);
1847  BYTE* dstLumaV = (pDst1[2] + (y / 2) * dst1Step[2]);
1848  BYTE* dstEvenChromaY1 = (pDst2[0] + y * dst2Step[0]);
1849  BYTE* dstEvenChromaY2 = dstEvenChromaY1 + roi->width / 2;
1850  BYTE* dstOddChromaY1 = dstEvenChromaY1 + dst2Step[0];
1851  BYTE* dstOddChromaY2 = dstEvenChromaY2 + dst2Step[0];
1852  BYTE* dstChromaU1 = (pDst2[1] + (y / 2) * dst2Step[1]);
1853  BYTE* dstChromaV1 = (pDst2[2] + (y / 2) * dst2Step[2]);
1854  BYTE* dstChromaU2 = dstChromaU1 + roi->width / 4;
1855  BYTE* dstChromaV2 = dstChromaV1 + roi->width / 4;
1856  general_RGBToAVC444YUVv2_BGRX_DOUBLE_ROW(
1857  srcEven, srcOdd, dstLumaYEven, dstLumaYOdd, dstLumaU, dstLumaV, dstEvenChromaY1,
1858  dstEvenChromaY2, dstOddChromaY1, dstOddChromaY2, dstChromaU1, dstChromaU2, dstChromaV1,
1859  dstChromaV2, roi->width);
1860  }
1861 
1862  return PRIMITIVES_SUCCESS;
1863 }
1864 
1865 static INLINE pstatus_t general_RGBToAVC444YUVv2(const BYTE* WINPR_RESTRICT pSrc, UINT32 srcFormat,
1866  UINT32 srcStep, BYTE* WINPR_RESTRICT pDst1[3],
1867  const UINT32 dst1Step[3],
1868  BYTE* WINPR_RESTRICT pDst2[3],
1869  const UINT32 dst2Step[3],
1870  const prim_size_t* WINPR_RESTRICT roi)
1871 {
1872  switch (srcFormat)
1873  {
1874  case PIXEL_FORMAT_BGRA32:
1875  case PIXEL_FORMAT_BGRX32:
1876  return general_RGBToAVC444YUVv2_BGRX(pSrc, srcStep, pDst1, dst1Step, pDst2, dst2Step,
1877  roi);
1878 
1879  default:
1880  return general_RGBToAVC444YUVv2_ANY(pSrc, srcFormat, srcStep, pDst1, dst1Step, pDst2,
1881  dst2Step, roi);
1882  }
1883 
1884  return !PRIMITIVES_SUCCESS;
1885 }
1886 
1887 void primitives_init_YUV(primitives_t* WINPR_RESTRICT prims)
1888 {
1889  prims->YUV420ToRGB_8u_P3AC4R = general_YUV420ToRGB_8u_P3AC4R;
1890  prims->YUV444ToRGB_8u_P3AC4R = general_YUV444ToRGB_8u_P3AC4R;
1891  prims->RGBToYUV420_8u_P3AC4R = general_RGBToYUV420_8u_P3AC4R;
1892  prims->RGBToYUV444_8u_P3AC4R = general_RGBToYUV444_8u_P3AC4R;
1893  prims->YUV420CombineToYUV444 = general_YUV420CombineToYUV444;
1894  prims->YUV444SplitToYUV420 = general_YUV444SplitToYUV420;
1895  prims->RGBToAVC444YUV = general_RGBToAVC444YUV;
1896  prims->RGBToAVC444YUVv2 = general_RGBToAVC444YUVv2;
1897 }
1898 
1899 void primitives_init_YUV_opt(primitives_t* WINPR_RESTRICT prims)
1900 {
1901  primitives_init_YUV_ssse3(prims);
1902  primitives_init_YUV_neon(prims);
1903 }