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