Coverage Report

Created: 2026-04-12 06:58

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/FreeRDP/libfreerdp/primitives/prim_YUV.c
Line
Count
Source
1
/**
2
 * FreeRDP: A Remote Desktop Protocol Implementation
3
 * Generic YUV/RGB conversion operations
4
 *
5
 * Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6
 * Copyright 2015-2017 Armin Novak <armin.novak@thincast.com>
7
 * Copyright 2015-2017 Norbert Federa <norbert.federa@thincast.com>
8
 * Copyright 2015-2017 Vic Lee
9
 * Copyright 2015-2017 Thincast Technologies GmbH
10
 *
11
 * Licensed under the Apache License, Version 2.0 (the "License");
12
 * you may not use this file except in compliance with the License.
13
 * You may obtain a copy of the License at
14
 *
15
 *     http://www.apache.org/licenses/LICENSE-2.0
16
 *
17
 * Unless required by applicable law or agreed to in writing, software
18
 * distributed under the License is distributed on an "AS IS" BASIS,
19
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20
 * See the License for the specific language governing permissions and
21
 * limitations under the License.
22
 */
23
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 inline pstatus_t general_LumaToYUV444(const BYTE* WINPR_RESTRICT pSrcRaw[3],
37
                                             const UINT32 srcStep[3],
38
                                             BYTE* WINPR_RESTRICT pDstRaw[3],
39
                                             const UINT32 dstStep[3],
40
                                             const RECTANGLE_16* WINPR_RESTRICT roi)
41
0
{
42
0
  const UINT32 nWidth = roi->right - roi->left;
43
0
  const UINT32 nHeight = roi->bottom - roi->top;
44
0
  const UINT32 halfWidth = (nWidth + 1) / 2;
45
0
  const UINT32 halfHeight = (nHeight + 1) / 2;
46
0
  const UINT32 oddY = 1;
47
0
  const UINT32 evenY = 0;
48
0
  const UINT32 oddX = 1;
49
0
  const UINT32 evenX = 0;
50
0
  const BYTE* pSrc[3] = { pSrcRaw[0] + 1ULL * roi->top * srcStep[0] + roi->left,
51
0
                        pSrcRaw[1] + 1ULL * roi->top / 2 * srcStep[1] + roi->left / 2,
52
0
                        pSrcRaw[2] + 1ULL * roi->top / 2 * srcStep[2] + roi->left / 2 };
53
0
  BYTE* pDst[3] = { pDstRaw[0] + 1ULL * roi->top * dstStep[0] + roi->left,
54
0
                  pDstRaw[1] + 1ULL * roi->top * dstStep[1] + roi->left,
55
0
                  pDstRaw[2] + 1ULL * roi->top * dstStep[2] + roi->left };
56
57
  /* Y data is already here... */
58
  /* B1 */
59
0
  for (size_t y = 0; y < nHeight; y++)
60
0
  {
61
0
    const BYTE* Ym = pSrc[0] + y * srcStep[0];
62
0
    BYTE* pY = pDst[0] + dstStep[0] * y;
63
0
    memcpy(pY, Ym, nWidth);
64
0
  }
65
66
  /* The first half of U, V are already here part of this frame. */
67
  /* B2 and B3 */
68
0
  for (UINT32 y = 0; y < halfHeight; y++)
69
0
  {
70
0
    const UINT32 val2y = (2UL * y + evenY);
71
0
    const UINT32 val2y1 = val2y + oddY;
72
0
    const BYTE* Um = pSrc[1] + 1ULL * y * srcStep[1];
73
0
    const BYTE* Vm = pSrc[2] + 1ULL * y * srcStep[2];
74
0
    BYTE* pU = pDst[1] + 1ULL * dstStep[1] * val2y;
75
0
    BYTE* pV = pDst[2] + 1ULL * dstStep[2] * val2y;
76
0
    BYTE* pU1 = pDst[1] + 1ULL * dstStep[1] * val2y1;
77
0
    BYTE* pV1 = pDst[2] + 1ULL * dstStep[2] * val2y1;
78
79
0
    for (UINT32 x = 0; x < halfWidth; x++)
80
0
    {
81
0
      const UINT32 val2x = 2UL * x + evenX;
82
0
      const UINT32 val2x1 = val2x + oddX;
83
0
      pU[val2x] = Um[x];
84
0
      pV[val2x] = Vm[x];
85
0
      pU[val2x1] = Um[x];
86
0
      pV[val2x1] = Vm[x];
87
0
      pU1[val2x] = Um[x];
88
0
      pV1[val2x] = Vm[x];
89
0
      pU1[val2x1] = Um[x];
90
0
      pV1[val2x1] = Vm[x];
91
0
    }
92
0
  }
93
94
0
  return PRIMITIVES_SUCCESS;
95
0
}
96
97
static inline pstatus_t general_ChromaV1ToYUV444(const BYTE* WINPR_RESTRICT pSrcRaw[3],
98
                                                 const UINT32 srcStep[3],
99
                                                 BYTE* WINPR_RESTRICT pDstRaw[3],
100
                                                 const UINT32 dstStep[3],
101
                                                 const RECTANGLE_16* WINPR_RESTRICT roi)
102
0
{
103
0
  const UINT32 mod = 16;
104
0
  UINT32 uY = 0;
105
0
  UINT32 vY = 0;
106
0
  const UINT32 nWidth = roi->right - roi->left;
107
0
  const UINT32 nHeight = roi->bottom - roi->top;
108
0
  const UINT32 halfWidth = (nWidth) / 2;
109
0
  const UINT32 halfHeight = (nHeight) / 2;
110
0
  const UINT32 oddY = 1;
111
0
  const UINT32 evenY = 0;
112
0
  const UINT32 oddX = 1;
113
  /* The auxiliary frame is aligned to multiples of 16x16.
114
   * We need the padded height for B4 and B5 conversion. */
115
0
  const UINT32 padHeigth = nHeight + 16 - nHeight % 16;
116
0
  const BYTE* pSrc[3] = { pSrcRaw[0] + 1ULL * roi->top * srcStep[0] + roi->left,
117
0
                        pSrcRaw[1] + 1ULL * roi->top / 2 * srcStep[1] + roi->left / 2,
118
0
                        pSrcRaw[2] + 1ULL * roi->top / 2 * srcStep[2] + roi->left / 2 };
119
0
  BYTE* pDst[3] = { pDstRaw[0] + 1ULL * roi->top * dstStep[0] + roi->left,
120
0
                  pDstRaw[1] + 1ULL * roi->top * dstStep[1] + roi->left,
121
0
                  pDstRaw[2] + 1ULL * roi->top * dstStep[2] + roi->left };
122
123
  /* The second half of U and V is a bit more tricky... */
124
  /* B4 and B5 */
125
0
  for (size_t y = 0; y < padHeigth; y++)
126
0
  {
127
0
    const BYTE* Ya = pSrc[0] + y * srcStep[0];
128
0
    BYTE* pX = nullptr;
129
130
0
    if ((y) % mod < (mod + 1) / 2)
131
0
    {
132
0
      const size_t pos = (2 * uY++ + oddY);
133
134
0
      if (pos >= nHeight)
135
0
        continue;
136
137
0
      pX = pDst[1] + dstStep[1] * pos;
138
0
    }
139
0
    else
140
0
    {
141
0
      const size_t pos = (2 * vY++ + oddY);
142
143
0
      if (pos >= nHeight)
144
0
        continue;
145
146
0
      pX = pDst[2] + dstStep[2] * pos;
147
0
    }
148
149
0
    memcpy(pX, Ya, nWidth);
150
0
  }
151
152
  /* B6 and B7 */
153
0
  for (UINT32 y = 0; y < halfHeight; y++)
154
0
  {
155
0
    const UINT32 val2y = (y * 2UL + evenY);
156
0
    const BYTE* Ua = pSrc[1] + 1ULL * y * srcStep[1];
157
0
    const BYTE* Va = pSrc[2] + 1ULL * y * srcStep[2];
158
0
    BYTE* pU = pDst[1] + 1ULL * dstStep[1] * val2y;
159
0
    BYTE* pV = pDst[2] + 1ULL * dstStep[2] * val2y;
160
161
0
    for (UINT32 x = 0; x < halfWidth; x++)
162
0
    {
163
0
      const UINT32 val2x1 = (x * 2 + oddX);
164
0
      pU[val2x1] = Ua[x];
165
0
      pV[val2x1] = Va[x];
166
0
    }
167
0
  }
168
169
0
  return PRIMITIVES_SUCCESS;
170
0
}
171
172
static inline pstatus_t general_ChromaV2ToYUV444(const BYTE* WINPR_RESTRICT pSrc[3],
173
                                                 const UINT32 srcStep[3], UINT32 nTotalWidth,
174
                                                 WINPR_ATTR_UNUSED UINT32 nTotalHeight,
175
                                                 BYTE* WINPR_RESTRICT pDst[3],
176
                                                 const UINT32 dstStep[3],
177
                                                 const RECTANGLE_16* WINPR_RESTRICT roi)
178
0
{
179
0
  const UINT32 nWidth = roi->right - roi->left;
180
0
  const UINT32 nHeight = roi->bottom - roi->top;
181
0
  const UINT32 halfWidth = (nWidth + 1) / 2;
182
0
  const UINT32 halfHeight = (nHeight + 1) / 2;
183
0
  const UINT32 quaterWidth = (nWidth + 3) / 4;
184
185
  /* B4 and B5: odd UV values for width/2, height */
186
0
  for (UINT32 y = 0; y < nHeight; y++)
187
0
  {
188
0
    const UINT32 yTop = y + roi->top;
189
0
    const BYTE* pYaU = pSrc[0] + 1ULL * srcStep[0] * yTop + roi->left / 2;
190
0
    const BYTE* pYaV = pYaU + nTotalWidth / 2;
191
0
    BYTE* pU = pDst[1] + 1ULL * dstStep[1] * yTop + roi->left;
192
0
    BYTE* pV = pDst[2] + 1ULL * dstStep[2] * yTop + roi->left;
193
194
0
    for (UINT32 x = 0; x < halfWidth; x++)
195
0
    {
196
0
      const UINT32 odd = 2UL * x + 1UL;
197
0
      pU[odd] = *pYaU++;
198
0
      pV[odd] = *pYaV++;
199
0
    }
200
0
  }
201
202
  /* B6 - B9 */
203
0
  for (size_t y = 0; y < halfHeight; y++)
204
0
  {
205
0
    const BYTE* pUaU = pSrc[1] + srcStep[1] * (y + roi->top / 2) + roi->left / 4;
206
0
    const BYTE* pUaV = pUaU + nTotalWidth / 4;
207
0
    const BYTE* pVaU = pSrc[2] + srcStep[2] * (y + roi->top / 2) + roi->left / 4;
208
0
    const BYTE* pVaV = pVaU + nTotalWidth / 4;
209
0
    BYTE* pU = pDst[1] + 1ULL * dstStep[1] * (2ULL * y + 1 + roi->top) + roi->left;
210
0
    BYTE* pV = pDst[2] + 1ULL * dstStep[2] * (2ULL * y + 1 + roi->top) + roi->left;
211
212
0
    for (size_t x = 0; x < quaterWidth; x++)
213
0
    {
214
0
      pU[4 * x + 0] = *pUaU++;
215
0
      pV[4 * x + 0] = *pUaV++;
216
0
      pU[4 * x + 2] = *pVaU++;
217
0
      pV[4 * x + 2] = *pVaV++;
218
0
    }
219
0
  }
220
221
0
  return PRIMITIVES_SUCCESS;
222
0
}
223
224
static pstatus_t general_YUV420CombineToYUV444(avc444_frame_type type,
225
                                               const BYTE* WINPR_RESTRICT pSrc[3],
226
                                               const UINT32 srcStep[3], UINT32 nWidth,
227
                                               UINT32 nHeight, BYTE* WINPR_RESTRICT pDst[3],
228
                                               const UINT32 dstStep[3],
229
                                               const RECTANGLE_16* WINPR_RESTRICT roi)
230
0
{
231
0
  if (!pSrc || !pSrc[0] || !pSrc[1] || !pSrc[2])
232
0
    return -1;
233
234
0
  if (!pDst || !pDst[0] || !pDst[1] || !pDst[2])
235
0
    return -1;
236
237
0
  if (!roi)
238
0
    return -1;
239
240
0
  switch (type)
241
0
  {
242
0
    case AVC444_LUMA:
243
0
      return general_LumaToYUV444(pSrc, srcStep, pDst, dstStep, roi);
244
245
0
    case AVC444_CHROMAv1:
246
0
      return general_ChromaV1ToYUV444(pSrc, srcStep, pDst, dstStep, roi);
247
248
0
    case AVC444_CHROMAv2:
249
0
      return general_ChromaV2ToYUV444(pSrc, srcStep, nWidth, nHeight, pDst, dstStep, roi);
250
251
0
    default:
252
0
      return -1;
253
0
  }
254
0
}
255
256
static pstatus_t
257
general_YUV444SplitToYUV420(const BYTE* WINPR_RESTRICT pSrc[3], const UINT32 srcStep[3],
258
                            BYTE* WINPR_RESTRICT pMainDst[3], const UINT32 dstMainStep[3],
259
                            BYTE* WINPR_RESTRICT pAuxDst[3], const UINT32 dstAuxStep[3],
260
                            const prim_size_t* WINPR_RESTRICT roi)
261
0
{
262
0
  UINT32 uY = 0;
263
0
  UINT32 vY = 0;
264
265
  /* The auxiliary frame is aligned to multiples of 16x16.
266
   * We need the padded height for B4 and B5 conversion. */
267
0
  const UINT32 padHeigth = roi->height + 16 - roi->height % 16;
268
0
  const UINT32 halfWidth = (roi->width + 1) / 2;
269
0
  const UINT32 halfHeight = (roi->height + 1) / 2;
270
271
  /* B1 */
272
0
  for (size_t y = 0; y < roi->height; y++)
273
0
  {
274
0
    const BYTE* pSrcY = pSrc[0] + y * srcStep[0];
275
0
    BYTE* pY = pMainDst[0] + y * dstMainStep[0];
276
0
    memcpy(pY, pSrcY, roi->width);
277
0
  }
278
279
  /* B2 and B3 */
280
0
  for (size_t y = 0; y < halfHeight; y++)
281
0
  {
282
0
    const BYTE* pSrcU = pSrc[1] + 2ULL * y * srcStep[1];
283
0
    const BYTE* pSrcV = pSrc[2] + 2ULL * y * srcStep[2];
284
0
    BYTE* pU = pMainDst[1] + y * dstMainStep[1];
285
0
    BYTE* pV = pMainDst[2] + y * dstMainStep[2];
286
287
0
    for (size_t x = 0; x < halfWidth; x++)
288
0
    {
289
0
      pU[x] = pSrcV[2 * x];
290
0
      pV[x] = pSrcU[2 * x];
291
0
    }
292
0
  }
293
294
  /* B4 and B5 */
295
0
  for (size_t y = 0; y < padHeigth; y++)
296
0
  {
297
0
    BYTE* pY = pAuxDst[0] + y * dstAuxStep[0];
298
299
0
    if (y % 16 < 8)
300
0
    {
301
0
      const size_t pos = (2 * uY++ + 1);
302
0
      const BYTE* pSrcU = pSrc[1] + pos * srcStep[1];
303
304
0
      if (pos >= roi->height)
305
0
        continue;
306
307
0
      memcpy(pY, pSrcU, roi->width);
308
0
    }
309
0
    else
310
0
    {
311
0
      const size_t pos = (2 * vY++ + 1);
312
0
      const BYTE* pSrcV = pSrc[2] + pos * srcStep[2];
313
314
0
      if (pos >= roi->height)
315
0
        continue;
316
317
0
      memcpy(pY, pSrcV, roi->width);
318
0
    }
319
0
  }
320
321
  /* B6 and B7 */
322
0
  for (size_t y = 0; y < halfHeight; y++)
323
0
  {
324
0
    const BYTE* pSrcU = pSrc[1] + 2 * y * srcStep[1];
325
0
    const BYTE* pSrcV = pSrc[2] + 2 * y * srcStep[2];
326
0
    BYTE* pU = pAuxDst[1] + y * dstAuxStep[1];
327
0
    BYTE* pV = pAuxDst[2] + y * dstAuxStep[2];
328
329
0
    for (size_t x = 0; x < halfWidth; x++)
330
0
    {
331
0
      pU[x] = pSrcU[2 * x + 1];
332
0
      pV[x] = pSrcV[2 * x + 1];
333
0
    }
334
0
  }
335
336
0
  return PRIMITIVES_SUCCESS;
337
0
}
338
339
static inline void general_YUV444ToRGB_DOUBLE_ROW(BYTE* WINPR_RESTRICT pRGB[2], UINT32 DstFormat,
340
                                                  const BYTE* WINPR_RESTRICT pY[2],
341
                                                  const BYTE* WINPR_RESTRICT pU[2],
342
                                                  const BYTE* WINPR_RESTRICT pV[2], size_t nWidth)
343
0
{
344
0
  fkt_writePixel writePixel = getPixelWriteFunction(DstFormat, FALSE);
345
346
0
  WINPR_ASSERT(nWidth % 2 == 0);
347
0
  for (size_t x = 0; x < nWidth; x += 2)
348
0
  {
349
0
    for (size_t i = 0; i < 2; i++)
350
0
    {
351
0
      for (size_t j = 0; j < 2; j++)
352
0
      {
353
0
        const BYTE y = pY[i][x + j];
354
0
        INT32 u = pU[i][x + j];
355
0
        INT32 v = pV[i][x + j];
356
0
        if ((i == 0) && (j == 0))
357
0
        {
358
0
          const INT32 subU = (INT32)pU[0][x + 1] + pU[1][x] + pU[1][x + 1];
359
0
          const INT32 avgU = ((4 * u) - subU);
360
0
          u = CONDITIONAL_CLIP(avgU, WINPR_ASSERTING_INT_CAST(BYTE, u));
361
362
0
          const INT32 subV = (INT32)pV[0][x + 1] + pV[1][x] + pV[1][x + 1];
363
0
          const INT32 avgV = ((4 * v) - subV);
364
0
          v = CONDITIONAL_CLIP(avgV, WINPR_ASSERTING_INT_CAST(BYTE, v));
365
0
        }
366
0
        pRGB[i] = writeYUVPixel(pRGB[i], DstFormat, y, u, v, writePixel);
367
0
      }
368
0
    }
369
0
  }
370
0
}
371
372
static inline void general_YUV444ToRGB_SINGLE_ROW(BYTE* WINPR_RESTRICT pRGB, UINT32 DstFormat,
373
                                                  const BYTE* WINPR_RESTRICT pY,
374
                                                  const BYTE* WINPR_RESTRICT pU,
375
                                                  const BYTE* WINPR_RESTRICT pV, size_t nWidth)
376
0
{
377
0
  fkt_writePixel writePixel = getPixelWriteFunction(DstFormat, FALSE);
378
379
0
  WINPR_ASSERT(nWidth % 2 == 0);
380
0
  for (size_t x = 0; x < nWidth; x += 2)
381
0
  {
382
0
    for (size_t j = 0; j < 2; j++)
383
0
    {
384
0
      const BYTE y = pY[x + j];
385
0
      const BYTE u = pU[x + j];
386
0
      const BYTE v = pV[x + j];
387
0
      pRGB = writeYUVPixel(pRGB, DstFormat, y, u, v, writePixel);
388
0
    }
389
0
  }
390
0
}
391
392
static inline pstatus_t general_YUV444ToRGB_8u_P3AC4R_general(const BYTE* WINPR_RESTRICT pSrc[3],
393
                                                              const UINT32 srcStep[3],
394
                                                              BYTE* WINPR_RESTRICT pDst,
395
                                                              UINT32 dstStep, UINT32 DstFormat,
396
                                                              const prim_size_t* WINPR_RESTRICT roi)
397
0
{
398
0
  WINPR_ASSERT(pSrc);
399
0
  WINPR_ASSERT(pDst);
400
0
  WINPR_ASSERT(roi);
401
402
0
  const UINT32 nWidth = roi->width;
403
0
  const UINT32 nHeight = roi->height;
404
405
0
  size_t y = 0;
406
0
  for (; y < nHeight - nHeight % 2; y += 2)
407
0
  {
408
0
    const BYTE* WINPR_RESTRICT pY[2] = { pSrc[0] + y * srcStep[0],
409
0
                                       pSrc[0] + (y + 1) * srcStep[0] };
410
0
    const BYTE* WINPR_RESTRICT pU[2] = { pSrc[1] + y * srcStep[1],
411
0
                                       pSrc[1] + (y + 1) * srcStep[1] };
412
0
    const BYTE* WINPR_RESTRICT pV[2] = { pSrc[2] + y * srcStep[2],
413
0
                                       pSrc[2] + (y + 1) * srcStep[2] };
414
0
    BYTE* WINPR_RESTRICT pRGB[] = { pDst + y * dstStep, pDst + (y + 1) * dstStep };
415
416
0
    general_YUV444ToRGB_DOUBLE_ROW(pRGB, DstFormat, pY, pU, pV, nWidth);
417
0
  }
418
0
  for (; y < nHeight; y++)
419
0
  {
420
0
    const BYTE* WINPR_RESTRICT pY = pSrc[0] + y * srcStep[0];
421
0
    const BYTE* WINPR_RESTRICT pU = pSrc[1] + y * srcStep[1];
422
0
    const BYTE* WINPR_RESTRICT pV = pSrc[2] + y * srcStep[2];
423
0
    BYTE* WINPR_RESTRICT pRGB = pDst + y * dstStep;
424
425
0
    general_YUV444ToRGB_SINGLE_ROW(pRGB, DstFormat, pY, pU, pV, nWidth);
426
0
  }
427
428
0
  return PRIMITIVES_SUCCESS;
429
0
}
430
431
static inline void general_YUV444ToBGRX_DOUBLE_ROW(BYTE* WINPR_RESTRICT pRGB[2], UINT32 DstFormat,
432
                                                   const BYTE* WINPR_RESTRICT pY[2],
433
                                                   const BYTE* WINPR_RESTRICT pU[2],
434
                                                   const BYTE* WINPR_RESTRICT pV[2], size_t nWidth)
435
0
{
436
0
  WINPR_ASSERT(nWidth % 2 == 0);
437
0
  for (size_t x = 0; x < nWidth; x += 2)
438
0
  {
439
0
    const INT32 subU = pU[0][x + 1] + pU[1][x] + pU[1][x + 1];
440
0
    const INT32 avgU = ((4 * pU[0][x]) - subU);
441
0
    const BYTE useU = CONDITIONAL_CLIP(avgU, pU[0][x]);
442
0
    const INT32 subV = pV[0][x + 1] + pV[1][x] + pV[1][x + 1];
443
0
    const INT32 avgV = ((4 * pV[0][x]) - subV);
444
0
    const BYTE useV = CONDITIONAL_CLIP(avgV, pV[0][x]);
445
446
0
    const BYTE U[2][2] = { { useU, pU[0][x + 1] }, { pU[1][x], pU[1][x + 1] } };
447
0
    const BYTE V[2][2] = { { useV, pV[0][x + 1] }, { pV[1][x], pV[1][x + 1] } };
448
449
0
    for (size_t i = 0; i < 2; i++)
450
0
    {
451
0
      for (size_t j = 0; j < 2; j++)
452
0
      {
453
0
        const BYTE y = pY[i][x + j];
454
0
        const BYTE u = U[i][j];
455
0
        const BYTE v = V[i][j];
456
0
        pRGB[i] = writeYUVPixel(pRGB[i], DstFormat, y, u, v, writePixelBGRX);
457
0
      }
458
0
    }
459
0
  }
460
0
}
461
462
static inline void general_YUV444ToBGRX_SINGLE_ROW(BYTE* WINPR_RESTRICT pRGB, UINT32 DstFormat,
463
                                                   const BYTE* WINPR_RESTRICT pY,
464
                                                   const BYTE* WINPR_RESTRICT pU,
465
                                                   const BYTE* WINPR_RESTRICT pV, size_t nWidth)
466
0
{
467
0
  WINPR_ASSERT(nWidth % 2 == 0);
468
0
  for (size_t x = 0; x < nWidth; x += 2)
469
0
  {
470
0
    for (size_t j = 0; j < 2; j++)
471
0
    {
472
0
      const BYTE Y = pY[x + j];
473
0
      const BYTE U = pU[x + j];
474
0
      const BYTE V = pV[x + j];
475
0
      pRGB = writeYUVPixel(pRGB, DstFormat, Y, U, V, writePixelBGRX);
476
0
    }
477
0
  }
478
0
}
479
480
static inline pstatus_t general_YUV444ToRGB_8u_P3AC4R_BGRX(const BYTE* WINPR_RESTRICT pSrc[3],
481
                                                           const UINT32 srcStep[3],
482
                                                           BYTE* WINPR_RESTRICT pDst,
483
                                                           UINT32 dstStep, UINT32 DstFormat,
484
                                                           const prim_size_t* WINPR_RESTRICT roi)
485
0
{
486
0
  WINPR_ASSERT(pSrc);
487
0
  WINPR_ASSERT(pDst);
488
0
  WINPR_ASSERT(roi);
489
490
0
  const UINT32 nWidth = roi->width;
491
0
  const UINT32 nHeight = roi->height;
492
493
0
  size_t y = 0;
494
0
  for (; y < nHeight - nHeight % 2; y += 2)
495
0
  {
496
0
    const BYTE* pY[2] = { pSrc[0] + y * srcStep[0], pSrc[0] + (y + 1) * srcStep[0] };
497
0
    const BYTE* pU[2] = { pSrc[1] + y * srcStep[1], pSrc[1] + (y + 1) * srcStep[1] };
498
0
    const BYTE* pV[2] = { pSrc[2] + y * srcStep[2], pSrc[2] + (y + 1) * srcStep[2] };
499
0
    BYTE* pRGB[] = { pDst + y * dstStep, pDst + (y + 1) * dstStep };
500
501
0
    general_YUV444ToBGRX_DOUBLE_ROW(pRGB, DstFormat, pY, pU, pV, nWidth);
502
0
  }
503
504
0
  for (; y < nHeight; y++)
505
0
  {
506
0
    const BYTE* WINPR_RESTRICT pY = pSrc[0] + y * srcStep[0];
507
0
    const BYTE* WINPR_RESTRICT pU = pSrc[1] + y * srcStep[1];
508
0
    const BYTE* WINPR_RESTRICT pV = pSrc[2] + y * srcStep[2];
509
0
    BYTE* WINPR_RESTRICT pRGB = pDst + y * dstStep;
510
511
0
    general_YUV444ToBGRX_SINGLE_ROW(pRGB, DstFormat, pY, pU, pV, nWidth);
512
0
  }
513
0
  return PRIMITIVES_SUCCESS;
514
0
}
515
516
static pstatus_t general_YUV444ToRGB_8u_P3AC4R(const BYTE* WINPR_RESTRICT pSrc[3],
517
                                               const UINT32 srcStep[3], BYTE* WINPR_RESTRICT pDst,
518
                                               UINT32 dstStep, UINT32 DstFormat,
519
                                               const prim_size_t* WINPR_RESTRICT roi)
520
0
{
521
0
  switch (DstFormat)
522
0
  {
523
0
    case PIXEL_FORMAT_BGRA32:
524
0
    case PIXEL_FORMAT_BGRX32:
525
0
      return general_YUV444ToRGB_8u_P3AC4R_BGRX(pSrc, srcStep, pDst, dstStep, DstFormat, roi);
526
527
0
    default:
528
0
      return general_YUV444ToRGB_8u_P3AC4R_general(pSrc, srcStep, pDst, dstStep, DstFormat,
529
0
                                                   roi);
530
0
  }
531
0
}
532
/**
533
 * | R |   ( | 256     0    403 | |    Y    | )
534
 * | G | = ( | 256   -48   -120 | | U - 128 | ) >> 8
535
 * | B |   ( | 256   475      0 | | V - 128 | )
536
 */
537
static void general_YUV420ToRGB_8u_P3AC4R_double_line(BYTE* WINPR_RESTRICT pEven,
538
                                                      BYTE* WINPR_RESTRICT pOdd, UINT32 DstFormat,
539
                                                      const BYTE* WINPR_RESTRICT pYeven,
540
                                                      const BYTE* WINPR_RESTRICT pYodd,
541
                                                      const BYTE* WINPR_RESTRICT pU,
542
                                                      const BYTE* WINPR_RESTRICT pV, UINT32 width,
543
                                                      fkt_writePixel writePixel, UINT32 formatSize)
544
0
{
545
546
0
  UINT32 x = 0;
547
0
  for (; x < width / 2; x++)
548
0
  {
549
0
    const BYTE U = pU[x];
550
0
    const BYTE V = pV[x];
551
0
    const BYTE eY0 = pYeven[2ULL * x + 0];
552
0
    const BYTE eY1 = pYeven[2ULL * x + 1];
553
0
    writeYUVPixel(&pEven[2ULL * x * formatSize], DstFormat, eY0, U, V, writePixel);
554
0
    writeYUVPixel(&pEven[(2ULL * x + 1) * formatSize], DstFormat, eY1, U, V, writePixel);
555
556
0
    const BYTE oY0 = pYodd[2ULL * x + 0];
557
0
    const BYTE oY1 = pYodd[2ULL * x + 1];
558
0
    writeYUVPixel(&pOdd[2ULL * x * formatSize], DstFormat, oY0, U, V, writePixel);
559
0
    writeYUVPixel(&pOdd[(2ULL * x + 1) * formatSize], DstFormat, oY1, U, V, writePixel);
560
0
  }
561
562
0
  for (; x < (width + 1) / 2; x++)
563
0
  {
564
0
    const BYTE U = pU[x];
565
0
    const BYTE V = pV[x];
566
0
    const BYTE eY0 = pYeven[2ULL * x + 0];
567
0
    writeYUVPixel(&pEven[2ULL * x * formatSize], DstFormat, eY0, U, V, writePixel);
568
569
0
    const BYTE oY0 = pYodd[2ULL * x + 0];
570
0
    writeYUVPixel(&pOdd[2ULL * x * formatSize], DstFormat, oY0, U, V, writePixel);
571
0
  }
572
0
}
573
574
static void general_YUV420ToRGB_8u_P3AC4R_single_line(BYTE* WINPR_RESTRICT pEven, UINT32 DstFormat,
575
                                                      const BYTE* WINPR_RESTRICT pYeven,
576
                                                      const BYTE* WINPR_RESTRICT pU,
577
                                                      const BYTE* WINPR_RESTRICT pV, UINT32 width,
578
                                                      fkt_writePixel writePixel, UINT32 formatSize)
579
0
{
580
581
0
  UINT32 x = 0;
582
0
  for (; x < width / 2; x++)
583
0
  {
584
0
    const BYTE U = pU[x];
585
0
    const BYTE V = pV[x];
586
0
    const BYTE eY0 = pYeven[2ULL * x + 0];
587
0
    const BYTE eY1 = pYeven[2ULL * x + 1];
588
0
    writeYUVPixel(&pEven[2ULL * x * formatSize], DstFormat, eY0, U, V, writePixel);
589
0
    writeYUVPixel(&pEven[(2ULL * x + 1) * formatSize], DstFormat, eY1, U, V, writePixel);
590
0
  }
591
592
0
  for (; x < (width + 1) / 2; x++)
593
0
  {
594
0
    const BYTE U = pU[x];
595
0
    const BYTE V = pV[x];
596
0
    const BYTE eY0 = pYeven[2ULL * x + 0];
597
0
    writeYUVPixel(&pEven[2ULL * x * formatSize], DstFormat, eY0, U, V, writePixel);
598
0
  }
599
0
}
600
601
static pstatus_t general_YUV420ToRGB_8u_P3AC4R(const BYTE* WINPR_RESTRICT pSrc[3],
602
                                               const UINT32 srcStep[3], BYTE* WINPR_RESTRICT pDst,
603
                                               UINT32 dstStep, UINT32 DstFormat,
604
                                               const prim_size_t* WINPR_RESTRICT roi)
605
0
{
606
0
  WINPR_ASSERT(roi);
607
0
  const DWORD formatSize = FreeRDPGetBytesPerPixel(DstFormat);
608
0
  fkt_writePixel writePixel = getPixelWriteFunction(DstFormat, FALSE);
609
0
  const UINT32 nWidth = roi->width;
610
0
  const UINT32 nHeight = roi->height;
611
612
0
  UINT32 y = 0;
613
0
  for (; y < nHeight / 2; y++)
614
0
  {
615
0
    const BYTE* pYe = &pSrc[0][(2ULL * y + 0) * srcStep[0]];
616
0
    const BYTE* pYo = &pSrc[0][(2ULL * y + 1) * srcStep[0]];
617
0
    const BYTE* pU = &pSrc[1][1ULL * srcStep[1] * y];
618
0
    const BYTE* pV = &pSrc[2][1ULL * srcStep[2] * y];
619
0
    BYTE* pRGBeven = &pDst[2ULL * y * dstStep];
620
0
    BYTE* pRGBodd = &pDst[(2ULL * y + 1) * dstStep];
621
0
    general_YUV420ToRGB_8u_P3AC4R_double_line(pRGBeven, pRGBodd, DstFormat, pYe, pYo, pU, pV,
622
0
                                              nWidth, writePixel, formatSize);
623
0
  }
624
625
  // Last row (if odd)
626
0
  for (; y < (nHeight + 1) / 2; y++)
627
0
  {
628
0
    const BYTE* pY = &pSrc[0][2ULL * srcStep[0] * y];
629
0
    const BYTE* pU = &pSrc[1][1ULL * srcStep[1] * y];
630
0
    const BYTE* pV = &pSrc[2][1ULL * srcStep[2] * y];
631
0
    BYTE* pEven = &pDst[2ULL * y * dstStep];
632
633
0
    general_YUV420ToRGB_8u_P3AC4R_single_line(pEven, DstFormat, pY, pU, pV, nWidth, writePixel,
634
0
                                              formatSize);
635
0
  }
636
637
0
  return PRIMITIVES_SUCCESS;
638
0
}
639
640
static inline void BGRX_fillYUV(size_t offset, const BYTE* WINPR_RESTRICT pRGB[2],
641
                                BYTE* WINPR_RESTRICT pY[2], BYTE* WINPR_RESTRICT pU[2],
642
                                BYTE* WINPR_RESTRICT pV[2])
643
0
{
644
0
  WINPR_ASSERT(pRGB);
645
0
  WINPR_ASSERT(pY);
646
0
  WINPR_ASSERT(pU);
647
0
  WINPR_ASSERT(pV);
648
649
0
  const UINT32 SrcFormat = PIXEL_FORMAT_BGRX32;
650
0
  const UINT32 bpp = 4;
651
652
0
  for (size_t i = 0; i < 2; i++)
653
0
  {
654
0
    for (size_t j = 0; j < 2; j++)
655
0
    {
656
0
      BYTE B = 0;
657
0
      BYTE G = 0;
658
0
      BYTE R = 0;
659
0
      const UINT32 color = FreeRDPReadColor(&pRGB[i][(offset + j) * bpp], SrcFormat);
660
0
      FreeRDPSplitColor(color, SrcFormat, &R, &G, &B, nullptr, nullptr);
661
0
      pY[i][offset + j] = RGB2Y(R, G, B);
662
0
      pU[i][offset + j] = RGB2U(R, G, B);
663
0
      pV[i][offset + j] = RGB2V(R, G, B);
664
0
    }
665
0
  }
666
667
  /* Apply chroma filter */
668
0
  const INT32 avgU = (pU[0][offset] + pU[0][offset + 1] + pU[1][offset] + pU[1][offset + 1]) / 4;
669
0
  pU[0][offset] = CONDITIONAL_CLIP(avgU, pU[0][offset]);
670
0
  const INT32 avgV = (pV[0][offset] + pV[0][offset + 1] + pV[1][offset] + pV[1][offset + 1]) / 4;
671
0
  pV[0][offset] = CONDITIONAL_CLIP(avgV, pV[0][offset]);
672
0
}
673
674
static inline void BGRX_fillYUV_single(size_t offset, const BYTE* WINPR_RESTRICT pRGB,
675
                                       BYTE* WINPR_RESTRICT pY, BYTE* WINPR_RESTRICT pU,
676
                                       BYTE* WINPR_RESTRICT pV)
677
0
{
678
0
  WINPR_ASSERT(pRGB);
679
0
  WINPR_ASSERT(pY);
680
0
  WINPR_ASSERT(pU);
681
0
  WINPR_ASSERT(pV);
682
683
0
  const UINT32 SrcFormat = PIXEL_FORMAT_BGRX32;
684
0
  const UINT32 bpp = 4;
685
686
0
  for (size_t j = 0; j < 2; j++)
687
0
  {
688
0
    BYTE B = 0;
689
0
    BYTE G = 0;
690
0
    BYTE R = 0;
691
0
    const UINT32 color = FreeRDPReadColor(&pRGB[(offset + j) * bpp], SrcFormat);
692
0
    FreeRDPSplitColor(color, SrcFormat, &R, &G, &B, nullptr, nullptr);
693
0
    pY[offset + j] = RGB2Y(R, G, B);
694
0
    pU[offset + j] = RGB2U(R, G, B);
695
0
    pV[offset + j] = RGB2V(R, G, B);
696
0
  }
697
0
}
698
699
static inline void general_BGRXToYUV444_DOUBLE_ROW(const BYTE* WINPR_RESTRICT pRGB[2],
700
                                                   BYTE* WINPR_RESTRICT pY[2],
701
                                                   BYTE* WINPR_RESTRICT pU[2],
702
                                                   BYTE* WINPR_RESTRICT pV[2], UINT32 nWidth)
703
0
{
704
705
0
  WINPR_ASSERT((nWidth % 2) == 0);
706
0
  for (size_t x = 0; x < nWidth; x += 2)
707
0
  {
708
0
    BGRX_fillYUV(x, pRGB, pY, pU, pV);
709
0
  }
710
0
}
711
712
static inline void general_BGRXToYUV444_SINGLE_ROW(const BYTE* WINPR_RESTRICT pRGB,
713
                                                   BYTE* WINPR_RESTRICT pY, BYTE* WINPR_RESTRICT pU,
714
                                                   BYTE* WINPR_RESTRICT pV, UINT32 nWidth)
715
0
{
716
717
0
  WINPR_ASSERT((nWidth % 2) == 0);
718
0
  for (size_t x = 0; x < nWidth; x += 2)
719
0
  {
720
0
    BGRX_fillYUV_single(x, pRGB, pY, pU, pV);
721
0
  }
722
0
}
723
724
static inline pstatus_t general_RGBToYUV444_8u_P3AC4R_BGRX(const BYTE* WINPR_RESTRICT pSrc,
725
                                                           const UINT32 srcStep,
726
                                                           BYTE* WINPR_RESTRICT pDst[3],
727
                                                           const UINT32 dstStep[3],
728
                                                           const prim_size_t* WINPR_RESTRICT roi)
729
0
{
730
0
  const UINT32 nWidth = roi->width;
731
0
  const UINT32 nHeight = roi->height;
732
733
0
  size_t y = 0;
734
0
  for (; y < nHeight - nHeight % 2; y += 2)
735
0
  {
736
0
    const BYTE* pRGB[] = { pSrc + y * srcStep, pSrc + (y + 1) * srcStep };
737
0
    BYTE* pY[] = { pDst[0] + y * dstStep[0], pDst[0] + (y + 1) * dstStep[0] };
738
0
    BYTE* pU[] = { pDst[1] + y * dstStep[1], pDst[1] + (y + 1) * dstStep[1] };
739
0
    BYTE* pV[] = { pDst[2] + y * dstStep[2], pDst[2] + (y + 1) * dstStep[2] };
740
741
0
    general_BGRXToYUV444_DOUBLE_ROW(pRGB, pY, pU, pV, nWidth);
742
0
  }
743
744
0
  for (; y < nHeight; y++)
745
0
  {
746
0
    const BYTE* pRGB = pSrc + y * srcStep;
747
0
    BYTE* pY = pDst[0] + y * dstStep[0];
748
0
    BYTE* pU = pDst[1] + y * dstStep[1];
749
0
    BYTE* pV = pDst[2] + y * dstStep[2];
750
751
0
    general_BGRXToYUV444_SINGLE_ROW(pRGB, pY, pU, pV, nWidth);
752
0
  }
753
754
0
  return PRIMITIVES_SUCCESS;
755
0
}
756
757
static inline void fillYUV(size_t offset, const BYTE* WINPR_RESTRICT pRGB[2], UINT32 SrcFormat,
758
                           BYTE* WINPR_RESTRICT pY[2], BYTE* WINPR_RESTRICT pU[2],
759
                           BYTE* WINPR_RESTRICT pV[2])
760
0
{
761
0
  WINPR_ASSERT(pRGB);
762
0
  WINPR_ASSERT(pY);
763
0
  WINPR_ASSERT(pU);
764
0
  WINPR_ASSERT(pV);
765
0
  const UINT32 bpp = FreeRDPGetBytesPerPixel(SrcFormat);
766
767
0
  INT32 avgU = 0;
768
0
  INT32 avgV = 0;
769
0
  for (size_t i = 0; i < 2; i++)
770
0
  {
771
0
    for (size_t j = 0; j < 2; j++)
772
0
    {
773
0
      BYTE B = 0;
774
0
      BYTE G = 0;
775
0
      BYTE R = 0;
776
0
      const UINT32 color = FreeRDPReadColor(&pRGB[i][(offset + j) * bpp], SrcFormat);
777
0
      FreeRDPSplitColor(color, SrcFormat, &R, &G, &B, nullptr, nullptr);
778
0
      const BYTE y = RGB2Y(R, G, B);
779
0
      const BYTE u = RGB2U(R, G, B);
780
0
      const BYTE v = RGB2V(R, G, B);
781
0
      avgU += u;
782
0
      avgV += v;
783
0
      pY[i][offset + j] = y;
784
0
      pU[i][offset + j] = u;
785
0
      pV[i][offset + j] = v;
786
0
    }
787
0
  }
788
789
  /* Apply chroma filter */
790
0
  avgU /= 4;
791
0
  pU[0][offset] = CLIP(avgU);
792
793
0
  avgV /= 4;
794
0
  pV[0][offset] = CLIP(avgV);
795
0
}
796
797
static inline void fillYUV_single(size_t offset, const BYTE* WINPR_RESTRICT pRGB, UINT32 SrcFormat,
798
                                  BYTE* WINPR_RESTRICT pY, BYTE* WINPR_RESTRICT pU,
799
                                  BYTE* WINPR_RESTRICT pV)
800
0
{
801
0
  WINPR_ASSERT(pRGB);
802
0
  WINPR_ASSERT(pY);
803
0
  WINPR_ASSERT(pU);
804
0
  WINPR_ASSERT(pV);
805
0
  const UINT32 bpp = FreeRDPGetBytesPerPixel(SrcFormat);
806
807
0
  for (size_t j = 0; j < 2; j++)
808
0
  {
809
0
    BYTE B = 0;
810
0
    BYTE G = 0;
811
0
    BYTE R = 0;
812
0
    const UINT32 color = FreeRDPReadColor(&pRGB[(offset + j) * bpp], SrcFormat);
813
0
    FreeRDPSplitColor(color, SrcFormat, &R, &G, &B, nullptr, nullptr);
814
0
    const BYTE y = RGB2Y(R, G, B);
815
0
    const BYTE u = RGB2U(R, G, B);
816
0
    const BYTE v = RGB2V(R, G, B);
817
0
    pY[offset + j] = y;
818
0
    pU[offset + j] = u;
819
0
    pV[offset + j] = v;
820
0
  }
821
0
}
822
823
static inline void general_RGBToYUV444_DOUBLE_ROW(const BYTE* WINPR_RESTRICT pRGB[2],
824
                                                  UINT32 SrcFormat, BYTE* WINPR_RESTRICT pY[2],
825
                                                  BYTE* WINPR_RESTRICT pU[2],
826
                                                  BYTE* WINPR_RESTRICT pV[2], UINT32 nWidth)
827
0
{
828
829
0
  WINPR_ASSERT((nWidth % 2) == 0);
830
0
  for (size_t x = 0; x < nWidth; x += 2)
831
0
  {
832
0
    fillYUV(x, pRGB, SrcFormat, pY, pU, pV);
833
0
  }
834
0
}
835
836
static inline void general_RGBToYUV444_SINGLE_ROW(const BYTE* WINPR_RESTRICT pRGB, UINT32 SrcFormat,
837
                                                  BYTE* WINPR_RESTRICT pY, BYTE* WINPR_RESTRICT pU,
838
                                                  BYTE* WINPR_RESTRICT pV, UINT32 nWidth)
839
0
{
840
841
0
  WINPR_ASSERT((nWidth % 2) == 0);
842
0
  for (size_t x = 0; x < nWidth; x += 2)
843
0
  {
844
0
    fillYUV_single(x, pRGB, SrcFormat, pY, pU, pV);
845
0
  }
846
0
}
847
848
static inline pstatus_t general_RGBToYUV444_8u_P3AC4R_RGB(const BYTE* WINPR_RESTRICT pSrc,
849
                                                          UINT32 SrcFormat, const UINT32 srcStep,
850
                                                          BYTE* WINPR_RESTRICT pDst[3],
851
                                                          const UINT32 dstStep[3],
852
                                                          const prim_size_t* WINPR_RESTRICT roi)
853
0
{
854
0
  const UINT32 nWidth = roi->width;
855
0
  const UINT32 nHeight = roi->height;
856
857
0
  size_t y = 0;
858
0
  for (; y < nHeight - nHeight % 2; y += 2)
859
0
  {
860
0
    const BYTE* pRGB[] = { pSrc + y * srcStep, pSrc + (y + 1) * srcStep };
861
0
    BYTE* pY[] = { &pDst[0][y * dstStep[0]], &pDst[0][(y + 1) * dstStep[0]] };
862
0
    BYTE* pU[] = { &pDst[1][y * dstStep[1]], &pDst[1][(y + 1) * dstStep[1]] };
863
0
    BYTE* pV[] = { &pDst[2][y * dstStep[2]], &pDst[2][(y + 1) * dstStep[2]] };
864
865
0
    general_RGBToYUV444_DOUBLE_ROW(pRGB, SrcFormat, pY, pU, pV, nWidth);
866
0
  }
867
0
  for (; y < nHeight; y++)
868
0
  {
869
0
    const BYTE* pRGB = pSrc + y * srcStep;
870
0
    BYTE* pY = &pDst[0][y * dstStep[0]];
871
0
    BYTE* pU = &pDst[1][y * dstStep[1]];
872
0
    BYTE* pV = &pDst[2][y * dstStep[2]];
873
874
0
    general_RGBToYUV444_SINGLE_ROW(pRGB, SrcFormat, pY, pU, pV, nWidth);
875
0
  }
876
877
0
  return PRIMITIVES_SUCCESS;
878
0
}
879
880
static pstatus_t general_RGBToYUV444_8u_P3AC4R(const BYTE* WINPR_RESTRICT pSrc, UINT32 SrcFormat,
881
                                               const UINT32 srcStep, BYTE* WINPR_RESTRICT pDst[3],
882
                                               const UINT32 dstStep[3],
883
                                               const prim_size_t* WINPR_RESTRICT roi)
884
0
{
885
0
  switch (SrcFormat)
886
0
  {
887
0
    case PIXEL_FORMAT_BGRA32:
888
0
    case PIXEL_FORMAT_BGRX32:
889
0
      return general_RGBToYUV444_8u_P3AC4R_BGRX(pSrc, srcStep, pDst, dstStep, roi);
890
0
    default:
891
0
      return general_RGBToYUV444_8u_P3AC4R_RGB(pSrc, SrcFormat, srcStep, pDst, dstStep, roi);
892
0
  }
893
0
}
894
895
static inline void fillI444_single(size_t offset, const BYTE* WINPR_RESTRICT pRGB, UINT32 SrcFormat,
896
                                   BYTE* WINPR_RESTRICT pY, BYTE* WINPR_RESTRICT pU,
897
                                   BYTE* WINPR_RESTRICT pV)
898
0
{
899
0
  WINPR_ASSERT(pRGB);
900
0
  WINPR_ASSERT(pY);
901
0
  WINPR_ASSERT(pU);
902
0
  WINPR_ASSERT(pV);
903
904
0
  const UINT32 bpp = FreeRDPGetBytesPerPixel(SrcFormat);
905
906
0
  BYTE B = 0;
907
0
  BYTE G = 0;
908
0
  BYTE R = 0;
909
0
  const UINT32 color = FreeRDPReadColor(&pRGB[offset * bpp], SrcFormat);
910
0
  FreeRDPSplitColor(color, SrcFormat, &R, &G, &B, nullptr, nullptr);
911
0
  const BYTE y = RGB2Y(R, G, B);
912
0
  const BYTE u = RGB2U(R, G, B);
913
0
  const BYTE v = RGB2V(R, G, B);
914
0
  pY[offset] = y;
915
0
  pU[offset] = u;
916
0
  pV[offset] = v;
917
0
}
918
919
static inline void general_RGBToI444_SINGLE_ROW(const BYTE* WINPR_RESTRICT pRGB, UINT32 SrcFormat,
920
                                                BYTE* WINPR_RESTRICT pY, BYTE* WINPR_RESTRICT pU,
921
                                                BYTE* WINPR_RESTRICT pV, UINT32 nWidth)
922
0
{
923
0
  for (size_t x = 0; x < nWidth; x++)
924
0
  {
925
0
    fillI444_single(x, pRGB, SrcFormat, pY, pU, pV);
926
0
  }
927
0
}
928
929
static inline pstatus_t general_RGBToI444_8u_RGB(const BYTE* WINPR_RESTRICT pSrc, UINT32 SrcFormat,
930
                                                 const UINT32 srcStep, BYTE* WINPR_RESTRICT pDst[3],
931
                                                 const UINT32 dstStep[3],
932
                                                 const prim_size_t* WINPR_RESTRICT roi)
933
0
{
934
0
  const UINT32 nWidth = roi->width;
935
0
  const UINT32 nHeight = roi->height;
936
937
0
  for (size_t y = 0; y < nHeight; y++)
938
0
  {
939
0
    const BYTE* pRGB = pSrc + y * srcStep;
940
0
    BYTE* pY = &pDst[0][y * dstStep[0]];
941
0
    BYTE* pU = &pDst[1][y * dstStep[1]];
942
0
    BYTE* pV = &pDst[2][y * dstStep[2]];
943
944
0
    general_RGBToI444_SINGLE_ROW(pRGB, SrcFormat, pY, pU, pV, nWidth);
945
0
  }
946
947
0
  return PRIMITIVES_SUCCESS;
948
0
}
949
950
static pstatus_t general_RGBToI444_8u(const BYTE* WINPR_RESTRICT pSrc, UINT32 SrcFormat,
951
                                      const UINT32 srcStep, BYTE* WINPR_RESTRICT pDst[3],
952
                                      const UINT32 dstStep[3],
953
                                      const prim_size_t* WINPR_RESTRICT roi)
954
0
{
955
0
  switch (SrcFormat)
956
0
  {
957
0
    default:
958
0
      return general_RGBToI444_8u_RGB(pSrc, SrcFormat, srcStep, pDst, dstStep, roi);
959
0
  }
960
0
}
961
962
static inline pstatus_t general_RGBToYUV420_BGRX(const BYTE* WINPR_RESTRICT pSrc, UINT32 srcStep,
963
                                                 BYTE* WINPR_RESTRICT pDst[3],
964
                                                 const UINT32 dstStep[3],
965
                                                 const prim_size_t* WINPR_RESTRICT roi)
966
0
{
967
0
  size_t x1 = 0;
968
0
  size_t x2 = 4;
969
0
  size_t x3 = srcStep;
970
0
  size_t x4 = srcStep + 4;
971
0
  size_t y1 = 0;
972
0
  size_t y2 = 1;
973
0
  size_t y3 = dstStep[0];
974
0
  size_t y4 = dstStep[0] + 1;
975
0
  UINT32 max_x = roi->width - 1;
976
977
0
  size_t y = 0;
978
0
  for (size_t i = 0; y < roi->height - roi->height % 2; y += 2, i++)
979
0
  {
980
0
    const BYTE* src = pSrc + y * srcStep;
981
0
    BYTE* ydst = pDst[0] + y * dstStep[0];
982
0
    BYTE* udst = pDst[1] + i * dstStep[1];
983
0
    BYTE* vdst = pDst[2] + i * dstStep[2];
984
985
0
    for (size_t x = 0; x < roi->width; x += 2)
986
0
    {
987
0
      BYTE R = 0;
988
0
      BYTE G = 0;
989
0
      BYTE B = 0;
990
0
      INT32 Ra = 0;
991
0
      INT32 Ga = 0;
992
0
      INT32 Ba = 0;
993
      /* row 1, pixel 1 */
994
0
      Ba = B = *(src + x1 + 0);
995
0
      Ga = G = *(src + x1 + 1);
996
0
      Ra = R = *(src + x1 + 2);
997
0
      ydst[y1] = RGB2Y(R, G, B);
998
999
0
      if (x < max_x)
1000
0
      {
1001
        /* row 1, pixel 2 */
1002
0
        Ba += B = *(src + x2 + 0);
1003
0
        Ga += G = *(src + x2 + 1);
1004
0
        Ra += R = *(src + x2 + 2);
1005
0
        ydst[y2] = RGB2Y(R, G, B);
1006
0
      }
1007
1008
      /* row 2, pixel 1 */
1009
0
      Ba += B = *(src + x3 + 0);
1010
0
      Ga += G = *(src + x3 + 1);
1011
0
      Ra += R = *(src + x3 + 2);
1012
0
      ydst[y3] = RGB2Y(R, G, B);
1013
1014
0
      if (x < max_x)
1015
0
      {
1016
        /* row 2, pixel 2 */
1017
0
        Ba += B = *(src + x4 + 0);
1018
0
        Ga += G = *(src + x4 + 1);
1019
0
        Ra += R = *(src + x4 + 2);
1020
0
        ydst[y4] = RGB2Y(R, G, B);
1021
0
      }
1022
1023
0
      Ba >>= 2;
1024
0
      Ga >>= 2;
1025
0
      Ra >>= 2;
1026
0
      *udst++ = RGB2U(Ra, Ga, Ba);
1027
0
      *vdst++ = RGB2V(Ra, Ga, Ba);
1028
0
      ydst += 2;
1029
0
      src += 8;
1030
0
    }
1031
0
  }
1032
1033
0
  for (; y < roi->height; y++)
1034
0
  {
1035
0
    const BYTE* src = pSrc + y * srcStep;
1036
0
    BYTE* ydst = pDst[0] + y * dstStep[0];
1037
0
    BYTE* udst = pDst[1] + (y / 2) * dstStep[1];
1038
0
    BYTE* vdst = pDst[2] + (y / 2) * dstStep[2];
1039
1040
0
    for (size_t x = 0; x < roi->width; x += 2)
1041
0
    {
1042
0
      BYTE R = 0;
1043
0
      BYTE G = 0;
1044
0
      BYTE B = 0;
1045
0
      INT32 Ra = 0;
1046
0
      INT32 Ga = 0;
1047
0
      INT32 Ba = 0;
1048
      /* row 1, pixel 1 */
1049
0
      Ba = B = *(src + x1 + 0);
1050
0
      Ga = G = *(src + x1 + 1);
1051
0
      Ra = R = *(src + x1 + 2);
1052
0
      ydst[y1] = RGB2Y(R, G, B);
1053
1054
0
      if (x < max_x)
1055
0
      {
1056
        /* row 1, pixel 2 */
1057
0
        Ba += B = *(src + x2 + 0);
1058
0
        Ga += G = *(src + x2 + 1);
1059
0
        Ra += R = *(src + x2 + 2);
1060
0
        ydst[y2] = RGB2Y(R, G, B);
1061
0
      }
1062
1063
0
      Ba >>= 2;
1064
0
      Ga >>= 2;
1065
0
      Ra >>= 2;
1066
0
      *udst++ = RGB2U(Ra, Ga, Ba);
1067
0
      *vdst++ = RGB2V(Ra, Ga, Ba);
1068
0
      ydst += 2;
1069
0
      src += 8;
1070
0
    }
1071
0
  }
1072
1073
0
  return PRIMITIVES_SUCCESS;
1074
0
}
1075
1076
static inline pstatus_t general_RGBToYUV420_RGBX(const BYTE* WINPR_RESTRICT pSrc, UINT32 srcStep,
1077
                                                 BYTE* WINPR_RESTRICT pDst[3],
1078
                                                 const UINT32 dstStep[3],
1079
                                                 const prim_size_t* WINPR_RESTRICT roi)
1080
0
{
1081
0
  size_t x1 = 0;
1082
0
  size_t x2 = 4;
1083
0
  size_t x3 = srcStep;
1084
0
  size_t x4 = srcStep + 4;
1085
0
  size_t y1 = 0;
1086
0
  size_t y2 = 1;
1087
0
  size_t y3 = dstStep[0];
1088
0
  size_t y4 = dstStep[0] + 1;
1089
0
  UINT32 max_x = roi->width - 1;
1090
1091
0
  size_t y = 0;
1092
0
  for (size_t i = 0; y < roi->height - roi->height % 2; y += 2, i++)
1093
0
  {
1094
0
    const BYTE* src = pSrc + y * srcStep;
1095
0
    BYTE* ydst = pDst[0] + y * dstStep[0];
1096
0
    BYTE* udst = pDst[1] + i * dstStep[1];
1097
0
    BYTE* vdst = pDst[2] + i * dstStep[2];
1098
1099
0
    for (UINT32 x = 0; x < roi->width; x += 2)
1100
0
    {
1101
0
      BYTE R = *(src + x1 + 0);
1102
0
      BYTE G = *(src + x1 + 1);
1103
0
      BYTE B = *(src + x1 + 2);
1104
      /* row 1, pixel 1 */
1105
0
      INT32 Ra = R;
1106
0
      INT32 Ga = G;
1107
0
      INT32 Ba = B;
1108
0
      ydst[y1] = RGB2Y(R, G, B);
1109
1110
0
      if (x < max_x)
1111
0
      {
1112
        /* row 1, pixel 2 */
1113
0
        R = *(src + x2 + 0);
1114
0
        G = *(src + x2 + 1);
1115
0
        B = *(src + x2 + 2);
1116
0
        Ra += R;
1117
0
        Ga += G;
1118
0
        Ba += B;
1119
0
        ydst[y2] = RGB2Y(R, G, B);
1120
0
      }
1121
1122
      /* row 2, pixel 1 */
1123
0
      R = *(src + x3 + 0);
1124
0
      G = *(src + x3 + 1);
1125
0
      B = *(src + x3 + 2);
1126
1127
0
      Ra += R;
1128
0
      Ga += G;
1129
0
      Ba += B;
1130
0
      ydst[y3] = RGB2Y(R, G, B);
1131
1132
0
      if (x < max_x)
1133
0
      {
1134
        /* row 2, pixel 2 */
1135
0
        R = *(src + x4 + 0);
1136
0
        G = *(src + x4 + 1);
1137
0
        B = *(src + x4 + 2);
1138
1139
0
        Ra += R;
1140
0
        Ga += G;
1141
0
        Ba += B;
1142
0
        ydst[y4] = RGB2Y(R, G, B);
1143
0
      }
1144
1145
0
      Ba >>= 2;
1146
0
      Ga >>= 2;
1147
0
      Ra >>= 2;
1148
0
      *udst++ = RGB2U(Ra, Ga, Ba);
1149
0
      *vdst++ = RGB2V(Ra, Ga, Ba);
1150
0
      ydst += 2;
1151
0
      src += 8;
1152
0
    }
1153
0
  }
1154
1155
0
  for (; y < roi->height; y++)
1156
0
  {
1157
0
    const BYTE* src = pSrc + y * srcStep;
1158
0
    BYTE* ydst = pDst[0] + y * dstStep[0];
1159
0
    BYTE* udst = pDst[1] + (y / 2) * dstStep[1];
1160
0
    BYTE* vdst = pDst[2] + (y / 2) * dstStep[2];
1161
1162
0
    for (UINT32 x = 0; x < roi->width; x += 2)
1163
0
    {
1164
0
      BYTE R = *(src + x1 + 0);
1165
0
      BYTE G = *(src + x1 + 1);
1166
0
      BYTE B = *(src + x1 + 2);
1167
      /* row 1, pixel 1 */
1168
0
      INT32 Ra = R;
1169
0
      INT32 Ga = G;
1170
0
      INT32 Ba = B;
1171
0
      ydst[y1] = RGB2Y(R, G, B);
1172
1173
0
      if (x < max_x)
1174
0
      {
1175
        /* row 1, pixel 2 */
1176
0
        R = *(src + x2 + 0);
1177
0
        G = *(src + x2 + 1);
1178
0
        B = *(src + x2 + 2);
1179
0
        Ra += R;
1180
0
        Ga += G;
1181
0
        Ba += B;
1182
0
        ydst[y2] = RGB2Y(R, G, B);
1183
0
      }
1184
1185
0
      Ba >>= 2;
1186
0
      Ga >>= 2;
1187
0
      Ra >>= 2;
1188
0
      *udst++ = RGB2U(Ra, Ga, Ba);
1189
0
      *vdst++ = RGB2V(Ra, Ga, Ba);
1190
0
      ydst += 2;
1191
0
      src += 8;
1192
0
    }
1193
0
  }
1194
1195
0
  return PRIMITIVES_SUCCESS;
1196
0
}
1197
1198
static inline pstatus_t general_RGBToYUV420_ANY(const BYTE* WINPR_RESTRICT pSrc, UINT32 srcFormat,
1199
                                                UINT32 srcStep, BYTE* WINPR_RESTRICT pDst[3],
1200
                                                const UINT32 dstStep[3],
1201
                                                const prim_size_t* WINPR_RESTRICT roi)
1202
0
{
1203
0
  const UINT32 bpp = FreeRDPGetBytesPerPixel(srcFormat);
1204
0
  size_t x1 = 0;
1205
0
  size_t x2 = bpp;
1206
0
  size_t x3 = srcStep;
1207
0
  size_t x4 = srcStep + bpp;
1208
0
  size_t y1 = 0;
1209
0
  size_t y2 = 1;
1210
0
  size_t y3 = dstStep[0];
1211
0
  size_t y4 = dstStep[0] + 1;
1212
0
  UINT32 max_x = roi->width - 1;
1213
1214
0
  size_t y = 0;
1215
0
  for (size_t i = 0; y < roi->height - roi->height % 2; y += 2, i++)
1216
0
  {
1217
0
    const BYTE* src = pSrc + y * srcStep;
1218
0
    BYTE* ydst = pDst[0] + y * dstStep[0];
1219
0
    BYTE* udst = pDst[1] + i * dstStep[1];
1220
0
    BYTE* vdst = pDst[2] + i * dstStep[2];
1221
1222
0
    for (size_t x = 0; x < roi->width; x += 2)
1223
0
    {
1224
0
      BYTE R = 0;
1225
0
      BYTE G = 0;
1226
0
      BYTE B = 0;
1227
0
      INT32 Ra = 0;
1228
0
      INT32 Ga = 0;
1229
0
      INT32 Ba = 0;
1230
0
      UINT32 color = 0;
1231
      /* row 1, pixel 1 */
1232
0
      color = FreeRDPReadColor(src + x1, srcFormat);
1233
0
      FreeRDPSplitColor(color, srcFormat, &R, &G, &B, nullptr, nullptr);
1234
0
      Ra = R;
1235
0
      Ga = G;
1236
0
      Ba = B;
1237
0
      ydst[y1] = RGB2Y(R, G, B);
1238
1239
0
      if (x < max_x)
1240
0
      {
1241
        /* row 1, pixel 2 */
1242
0
        color = FreeRDPReadColor(src + x2, srcFormat);
1243
0
        FreeRDPSplitColor(color, srcFormat, &R, &G, &B, nullptr, nullptr);
1244
0
        Ra += R;
1245
0
        Ga += G;
1246
0
        Ba += B;
1247
0
        ydst[y2] = RGB2Y(R, G, B);
1248
0
      }
1249
1250
      /* row 2, pixel 1 */
1251
0
      color = FreeRDPReadColor(src + x3, srcFormat);
1252
0
      FreeRDPSplitColor(color, srcFormat, &R, &G, &B, nullptr, nullptr);
1253
0
      Ra += R;
1254
0
      Ga += G;
1255
0
      Ba += B;
1256
0
      ydst[y3] = RGB2Y(R, G, B);
1257
1258
0
      if (x < max_x)
1259
0
      {
1260
        /* row 2, pixel 2 */
1261
0
        color = FreeRDPReadColor(src + x4, srcFormat);
1262
0
        FreeRDPSplitColor(color, srcFormat, &R, &G, &B, nullptr, nullptr);
1263
0
        Ra += R;
1264
0
        Ga += G;
1265
0
        Ba += B;
1266
0
        ydst[y4] = RGB2Y(R, G, B);
1267
0
      }
1268
1269
0
      Ra >>= 2;
1270
0
      Ga >>= 2;
1271
0
      Ba >>= 2;
1272
0
      *udst++ = RGB2U(Ra, Ga, Ba);
1273
0
      *vdst++ = RGB2V(Ra, Ga, Ba);
1274
0
      ydst += 2;
1275
0
      src += 2ULL * bpp;
1276
0
    }
1277
0
  }
1278
1279
0
  for (; y < roi->height; y++)
1280
0
  {
1281
0
    const BYTE* src = pSrc + y * srcStep;
1282
0
    BYTE* ydst = pDst[0] + y * dstStep[0];
1283
0
    BYTE* udst = pDst[1] + (y / 2) * dstStep[1];
1284
0
    BYTE* vdst = pDst[2] + (y / 2) * dstStep[2];
1285
1286
0
    for (size_t x = 0; x < roi->width; x += 2)
1287
0
    {
1288
0
      BYTE R = 0;
1289
0
      BYTE G = 0;
1290
0
      BYTE B = 0;
1291
      /* row 1, pixel 1 */
1292
0
      UINT32 color = FreeRDPReadColor(src + x1, srcFormat);
1293
0
      FreeRDPSplitColor(color, srcFormat, &R, &G, &B, nullptr, nullptr);
1294
0
      INT32 Ra = R;
1295
0
      INT32 Ga = G;
1296
0
      INT32 Ba = B;
1297
0
      ydst[y1] = RGB2Y(R, G, B);
1298
1299
0
      if (x < max_x)
1300
0
      {
1301
        /* row 1, pixel 2 */
1302
0
        color = FreeRDPReadColor(src + x2, srcFormat);
1303
0
        FreeRDPSplitColor(color, srcFormat, &R, &G, &B, nullptr, nullptr);
1304
0
        Ra += R;
1305
0
        Ga += G;
1306
0
        Ba += B;
1307
0
        ydst[y2] = RGB2Y(R, G, B);
1308
0
      }
1309
1310
0
      Ra >>= 2;
1311
0
      Ga >>= 2;
1312
0
      Ba >>= 2;
1313
0
      *udst++ = RGB2U(Ra, Ga, Ba);
1314
0
      *vdst++ = RGB2V(Ra, Ga, Ba);
1315
0
      ydst += 2;
1316
0
      src += 2ULL * bpp;
1317
0
    }
1318
0
  }
1319
1320
0
  return PRIMITIVES_SUCCESS;
1321
0
}
1322
1323
static pstatus_t general_RGBToYUV420_8u_P3AC4R(const BYTE* WINPR_RESTRICT pSrc, UINT32 srcFormat,
1324
                                               UINT32 srcStep, BYTE* WINPR_RESTRICT pDst[3],
1325
                                               const UINT32 dstStep[3],
1326
                                               const prim_size_t* WINPR_RESTRICT roi)
1327
0
{
1328
0
  switch (srcFormat)
1329
0
  {
1330
0
    case PIXEL_FORMAT_BGRA32:
1331
0
    case PIXEL_FORMAT_BGRX32:
1332
0
      return general_RGBToYUV420_BGRX(pSrc, srcStep, pDst, dstStep, roi);
1333
1334
0
    case PIXEL_FORMAT_RGBA32:
1335
0
    case PIXEL_FORMAT_RGBX32:
1336
0
      return general_RGBToYUV420_RGBX(pSrc, srcStep, pDst, dstStep, roi);
1337
1338
0
    default:
1339
0
      return general_RGBToYUV420_ANY(pSrc, srcFormat, srcStep, pDst, dstStep, roi);
1340
0
  }
1341
0
}
1342
1343
static inline void int_general_RGBToAVC444YUV_BGRX_DOUBLE_ROW(
1344
    size_t offset, const BYTE* WINPR_RESTRICT pSrcEven, const BYTE* WINPR_RESTRICT pSrcOdd,
1345
    BYTE* WINPR_RESTRICT b1Even, BYTE* WINPR_RESTRICT b1Odd, BYTE* WINPR_RESTRICT b2,
1346
    BYTE* WINPR_RESTRICT b3, BYTE* WINPR_RESTRICT b4, BYTE* WINPR_RESTRICT b5,
1347
    BYTE* WINPR_RESTRICT b6, BYTE* WINPR_RESTRICT b7, UINT32 width)
1348
0
{
1349
0
  WINPR_ASSERT((width % 2) == 0);
1350
0
  for (size_t x = offset; x < width; x += 2)
1351
0
  {
1352
0
    const BYTE* srcEven = &pSrcEven[4ULL * x];
1353
0
    const BYTE* srcOdd = &pSrcOdd[4ULL * x];
1354
0
    const BOOL lastX = (x + 1) >= width;
1355
0
    BYTE Y1e = 0;
1356
0
    BYTE Y2e = 0;
1357
0
    BYTE U1e = 0;
1358
0
    BYTE V1e = 0;
1359
0
    BYTE U2e = 0;
1360
0
    BYTE V2e = 0;
1361
0
    BYTE Y1o = 0;
1362
0
    BYTE Y2o = 0;
1363
0
    BYTE U1o = 0;
1364
0
    BYTE V1o = 0;
1365
0
    BYTE U2o = 0;
1366
0
    BYTE V2o = 0;
1367
    /* Read 4 pixels, 2 from even, 2 from odd lines */
1368
0
    {
1369
0
      const BYTE b = *srcEven++;
1370
0
      const BYTE g = *srcEven++;
1371
0
      const BYTE r = *srcEven++;
1372
0
      srcEven++;
1373
0
      Y1e = Y2e = Y1o = Y2o = RGB2Y(r, g, b);
1374
0
      U1e = U2e = U1o = U2o = RGB2U(r, g, b);
1375
0
      V1e = V2e = V1o = V2o = RGB2V(r, g, b);
1376
0
    }
1377
1378
0
    if (!lastX)
1379
0
    {
1380
0
      const BYTE b = *srcEven++;
1381
0
      const BYTE g = *srcEven++;
1382
0
      const BYTE r = *srcEven++;
1383
0
      srcEven++;
1384
0
      Y2e = RGB2Y(r, g, b);
1385
0
      U2e = RGB2U(r, g, b);
1386
0
      V2e = RGB2V(r, g, b);
1387
0
    }
1388
1389
0
    if (b1Odd)
1390
0
    {
1391
0
      const BYTE b = *srcOdd++;
1392
0
      const BYTE g = *srcOdd++;
1393
0
      const BYTE r = *srcOdd++;
1394
0
      srcOdd++;
1395
0
      Y1o = Y2o = RGB2Y(r, g, b);
1396
0
      U1o = U2o = RGB2U(r, g, b);
1397
0
      V1o = V2o = RGB2V(r, g, b);
1398
0
    }
1399
1400
0
    if (b1Odd && !lastX)
1401
0
    {
1402
0
      const BYTE b = *srcOdd++;
1403
0
      const BYTE g = *srcOdd++;
1404
0
      const BYTE r = *srcOdd++;
1405
0
      srcOdd++;
1406
0
      Y2o = RGB2Y(r, g, b);
1407
0
      U2o = RGB2U(r, g, b);
1408
0
      V2o = RGB2V(r, g, b);
1409
0
    }
1410
1411
    /* We have 4 Y pixels, so store them. */
1412
0
    *b1Even++ = Y1e;
1413
0
    *b1Even++ = Y2e;
1414
1415
0
    if (b1Odd)
1416
0
    {
1417
0
      *b1Odd++ = Y1o;
1418
0
      *b1Odd++ = Y2o;
1419
0
    }
1420
1421
    /* 2x 2y pixel in luma UV plane use averaging
1422
     */
1423
0
    {
1424
0
      const BYTE Uavg = WINPR_ASSERTING_INT_CAST(BYTE, ((UINT16)U1e + U2e + U1o + U2o) / 4);
1425
0
      const BYTE Vavg = WINPR_ASSERTING_INT_CAST(BYTE, ((UINT16)V1e + V2e + V1o + V2o) / 4);
1426
0
      *b2++ = Uavg;
1427
0
      *b3++ = Vavg;
1428
0
    }
1429
1430
    /* UV from 2x, 2y+1 */
1431
0
    if (b1Odd)
1432
0
    {
1433
0
      *b4++ = U1o;
1434
0
      *b5++ = V1o;
1435
1436
0
      if (!lastX)
1437
0
      {
1438
0
        *b4++ = U2o;
1439
0
        *b5++ = V2o;
1440
0
      }
1441
0
    }
1442
1443
    /* UV from 2x+1, 2y */
1444
0
    if (!lastX)
1445
0
    {
1446
0
      *b6++ = U2e;
1447
0
      *b7++ = V2e;
1448
0
    }
1449
0
  }
1450
0
}
1451
1452
void general_RGBToAVC444YUV_BGRX_DOUBLE_ROW(size_t offset, const BYTE* WINPR_RESTRICT pSrcEven,
1453
                                            const BYTE* WINPR_RESTRICT pSrcOdd,
1454
                                            BYTE* WINPR_RESTRICT b1Even, BYTE* WINPR_RESTRICT b1Odd,
1455
                                            BYTE* WINPR_RESTRICT b2, BYTE* WINPR_RESTRICT b3,
1456
                                            BYTE* WINPR_RESTRICT b4, BYTE* WINPR_RESTRICT b5,
1457
                                            BYTE* WINPR_RESTRICT b6, BYTE* WINPR_RESTRICT b7,
1458
                                            UINT32 width)
1459
0
{
1460
0
  int_general_RGBToAVC444YUV_BGRX_DOUBLE_ROW(offset, pSrcEven, pSrcOdd, b1Even, b1Odd, b2, b3, b4,
1461
0
                                             b5, b6, b7, width);
1462
0
}
1463
1464
static inline pstatus_t general_RGBToAVC444YUV_BGRX(const BYTE* WINPR_RESTRICT pSrc, UINT32 srcStep,
1465
                                                    BYTE* WINPR_RESTRICT pDst1[3],
1466
                                                    const UINT32 dst1Step[3],
1467
                                                    BYTE* WINPR_RESTRICT pDst2[3],
1468
                                                    const UINT32 dst2Step[3],
1469
                                                    const prim_size_t* WINPR_RESTRICT roi)
1470
0
{
1471
  /**
1472
   * Note:
1473
   * Read information in function general_RGBToAVC444YUV_ANY below !
1474
   */
1475
0
  size_t y = 0;
1476
0
  for (; y < roi->height - roi->height % 2; y += 2)
1477
0
  {
1478
0
    const BYTE* srcEven = pSrc + 1ULL * y * srcStep;
1479
0
    const BYTE* srcOdd = pSrc + 1ULL * (y + 1) * srcStep;
1480
0
    const size_t i = y >> 1;
1481
0
    const size_t n = (i & (uint32_t)~7) + i;
1482
0
    BYTE* b1Even = pDst1[0] + 1ULL * y * dst1Step[0];
1483
0
    BYTE* b1Odd = (b1Even + dst1Step[0]);
1484
0
    BYTE* b2 = pDst1[1] + 1ULL * (y / 2) * dst1Step[1];
1485
0
    BYTE* b3 = pDst1[2] + 1ULL * (y / 2) * dst1Step[2];
1486
0
    BYTE* b4 = pDst2[0] + 1ULL * dst2Step[0] * n;
1487
0
    BYTE* b5 = b4 + 8ULL * dst2Step[0];
1488
0
    BYTE* b6 = pDst2[1] + 1ULL * (y / 2) * dst2Step[1];
1489
0
    BYTE* b7 = pDst2[2] + 1ULL * (y / 2) * dst2Step[2];
1490
0
    int_general_RGBToAVC444YUV_BGRX_DOUBLE_ROW(0, srcEven, srcOdd, b1Even, b1Odd, b2, b3, b4,
1491
0
                                               b5, b6, b7, roi->width);
1492
0
  }
1493
0
  for (; y < roi->height; y++)
1494
0
  {
1495
0
    const BYTE* srcEven = pSrc + 1ULL * y * srcStep;
1496
0
    BYTE* b1Even = pDst1[0] + 1ULL * y * dst1Step[0];
1497
0
    BYTE* b2 = pDst1[1] + 1ULL * (y / 2) * dst1Step[1];
1498
0
    BYTE* b3 = pDst1[2] + 1ULL * (y / 2) * dst1Step[2];
1499
0
    BYTE* b6 = pDst2[1] + 1ULL * (y / 2) * dst2Step[1];
1500
0
    BYTE* b7 = pDst2[2] + 1ULL * (y / 2) * dst2Step[2];
1501
0
    int_general_RGBToAVC444YUV_BGRX_DOUBLE_ROW(0, srcEven, nullptr, b1Even, nullptr, b2, b3,
1502
0
                                               nullptr, nullptr, b6, b7, roi->width);
1503
0
  }
1504
1505
0
  return PRIMITIVES_SUCCESS;
1506
0
}
1507
1508
static inline void general_RGBToAVC444YUV_RGBX_DOUBLE_ROW(
1509
    const BYTE* WINPR_RESTRICT srcEven, const BYTE* WINPR_RESTRICT srcOdd,
1510
    BYTE* WINPR_RESTRICT b1Even, BYTE* WINPR_RESTRICT b1Odd, BYTE* WINPR_RESTRICT b2,
1511
    BYTE* WINPR_RESTRICT b3, BYTE* WINPR_RESTRICT b4, BYTE* WINPR_RESTRICT b5,
1512
    BYTE* WINPR_RESTRICT b6, BYTE* WINPR_RESTRICT b7, UINT32 width)
1513
0
{
1514
0
  WINPR_ASSERT((width % 2) == 0);
1515
0
  for (UINT32 x = 0; x < width; x += 2)
1516
0
  {
1517
0
    const BOOL lastX = (x + 1) >= width;
1518
0
    BYTE Y1e = 0;
1519
0
    BYTE Y2e = 0;
1520
0
    BYTE U1e = 0;
1521
0
    BYTE V1e = 0;
1522
0
    BYTE U2e = 0;
1523
0
    BYTE V2e = 0;
1524
0
    BYTE Y1o = 0;
1525
0
    BYTE Y2o = 0;
1526
0
    BYTE U1o = 0;
1527
0
    BYTE V1o = 0;
1528
0
    BYTE U2o = 0;
1529
0
    BYTE V2o = 0;
1530
    /* Read 4 pixels, 2 from even, 2 from odd lines */
1531
0
    {
1532
0
      const BYTE r = *srcEven++;
1533
0
      const BYTE g = *srcEven++;
1534
0
      const BYTE b = *srcEven++;
1535
0
      srcEven++;
1536
0
      Y1e = Y2e = Y1o = Y2o = RGB2Y(r, g, b);
1537
0
      U1e = U2e = U1o = U2o = RGB2U(r, g, b);
1538
0
      V1e = V2e = V1o = V2o = RGB2V(r, g, b);
1539
0
    }
1540
1541
0
    if (!lastX)
1542
0
    {
1543
0
      const BYTE r = *srcEven++;
1544
0
      const BYTE g = *srcEven++;
1545
0
      const BYTE b = *srcEven++;
1546
0
      srcEven++;
1547
0
      Y2e = RGB2Y(r, g, b);
1548
0
      U2e = RGB2U(r, g, b);
1549
0
      V2e = RGB2V(r, g, b);
1550
0
    }
1551
1552
0
    if (b1Odd)
1553
0
    {
1554
0
      const BYTE r = *srcOdd++;
1555
0
      const BYTE g = *srcOdd++;
1556
0
      const BYTE b = *srcOdd++;
1557
0
      srcOdd++;
1558
0
      Y1o = Y2o = RGB2Y(r, g, b);
1559
0
      U1o = U2o = RGB2U(r, g, b);
1560
0
      V1o = V2o = RGB2V(r, g, b);
1561
0
    }
1562
1563
0
    if (b1Odd && !lastX)
1564
0
    {
1565
0
      const BYTE r = *srcOdd++;
1566
0
      const BYTE g = *srcOdd++;
1567
0
      const BYTE b = *srcOdd++;
1568
0
      srcOdd++;
1569
0
      Y2o = RGB2Y(r, g, b);
1570
0
      U2o = RGB2U(r, g, b);
1571
0
      V2o = RGB2V(r, g, b);
1572
0
    }
1573
1574
    /* We have 4 Y pixels, so store them. */
1575
0
    *b1Even++ = Y1e;
1576
0
    *b1Even++ = Y2e;
1577
1578
0
    if (b1Odd)
1579
0
    {
1580
0
      *b1Odd++ = Y1o;
1581
0
      *b1Odd++ = Y2o;
1582
0
    }
1583
1584
    /* 2x 2y pixel in luma UV plane use averaging
1585
     */
1586
0
    {
1587
0
      const BYTE Uavg = WINPR_ASSERTING_INT_CAST(BYTE, ((UINT16)U1e + U2e + U1o + U2o) / 4);
1588
0
      const BYTE Vavg = WINPR_ASSERTING_INT_CAST(BYTE, ((UINT16)V1e + V2e + V1o + V2o) / 4);
1589
0
      *b2++ = Uavg;
1590
0
      *b3++ = Vavg;
1591
0
    }
1592
1593
    /* UV from 2x, 2y+1 */
1594
0
    if (b1Odd)
1595
0
    {
1596
0
      *b4++ = U1o;
1597
0
      *b5++ = V1o;
1598
1599
0
      if (!lastX)
1600
0
      {
1601
0
        *b4++ = U2o;
1602
0
        *b5++ = V2o;
1603
0
      }
1604
0
    }
1605
1606
    /* UV from 2x+1, 2y */
1607
0
    if (!lastX)
1608
0
    {
1609
0
      *b6++ = U2e;
1610
0
      *b7++ = V2e;
1611
0
    }
1612
0
  }
1613
0
}
1614
1615
static inline pstatus_t general_RGBToAVC444YUV_RGBX(const BYTE* WINPR_RESTRICT pSrc, UINT32 srcStep,
1616
                                                    BYTE* WINPR_RESTRICT pDst1[3],
1617
                                                    const UINT32 dst1Step[3],
1618
                                                    BYTE* WINPR_RESTRICT pDst2[3],
1619
                                                    const UINT32 dst2Step[3],
1620
                                                    const prim_size_t* WINPR_RESTRICT roi)
1621
0
{
1622
  /**
1623
   * Note:
1624
   * Read information in function general_RGBToAVC444YUV_ANY below !
1625
   */
1626
1627
0
  size_t y = 0;
1628
0
  for (; y < roi->height - roi->height % 2; y += 2)
1629
0
  {
1630
0
    const BOOL last = (y >= (roi->height - 1));
1631
0
    const BYTE* srcEven = pSrc + 1ULL * y * srcStep;
1632
0
    const BYTE* srcOdd = pSrc + 1ULL * (y + 1) * srcStep;
1633
0
    const size_t i = y >> 1;
1634
0
    const size_t n = (i & (size_t)~7) + i;
1635
0
    BYTE* b1Even = pDst1[0] + 1ULL * y * dst1Step[0];
1636
0
    BYTE* b1Odd = !last ? (b1Even + dst1Step[0]) : nullptr;
1637
0
    BYTE* b2 = pDst1[1] + 1ULL * (y / 2) * dst1Step[1];
1638
0
    BYTE* b3 = pDst1[2] + 1ULL * (y / 2) * dst1Step[2];
1639
0
    BYTE* b4 = pDst2[0] + 1ULL * dst2Step[0] * n;
1640
0
    BYTE* b5 = b4 + 8ULL * dst2Step[0];
1641
0
    BYTE* b6 = pDst2[1] + 1ULL * (y / 2) * dst2Step[1];
1642
0
    BYTE* b7 = pDst2[2] + 1ULL * (y / 2) * dst2Step[2];
1643
0
    general_RGBToAVC444YUV_RGBX_DOUBLE_ROW(srcEven, srcOdd, b1Even, b1Odd, b2, b3, b4, b5, b6,
1644
0
                                           b7, roi->width);
1645
0
  }
1646
0
  for (; y < roi->height; y++)
1647
0
  {
1648
0
    const BYTE* srcEven = pSrc + 1ULL * y * srcStep;
1649
0
    BYTE* b1Even = pDst1[0] + 1ULL * y * dst1Step[0];
1650
0
    BYTE* b2 = pDst1[1] + 1ULL * (y / 2) * dst1Step[1];
1651
0
    BYTE* b3 = pDst1[2] + 1ULL * (y / 2) * dst1Step[2];
1652
0
    BYTE* b6 = pDst2[1] + 1ULL * (y / 2) * dst2Step[1];
1653
0
    BYTE* b7 = pDst2[2] + 1ULL * (y / 2) * dst2Step[2];
1654
0
    general_RGBToAVC444YUV_RGBX_DOUBLE_ROW(srcEven, nullptr, b1Even, nullptr, b2, b3, nullptr,
1655
0
                                           nullptr, b6, b7, roi->width);
1656
0
  }
1657
0
  return PRIMITIVES_SUCCESS;
1658
0
}
1659
1660
static inline void general_RGBToAVC444YUV_ANY_DOUBLE_ROW(
1661
    const BYTE* WINPR_RESTRICT srcEven, const BYTE* WINPR_RESTRICT srcOdd, UINT32 srcFormat,
1662
    BYTE* WINPR_RESTRICT b1Even, BYTE* WINPR_RESTRICT b1Odd, BYTE* WINPR_RESTRICT b2,
1663
    BYTE* WINPR_RESTRICT b3, BYTE* WINPR_RESTRICT b4, BYTE* WINPR_RESTRICT b5,
1664
    BYTE* WINPR_RESTRICT b6, BYTE* WINPR_RESTRICT b7, UINT32 width)
1665
0
{
1666
0
  const UINT32 bpp = FreeRDPGetBytesPerPixel(srcFormat);
1667
0
  for (UINT32 x = 0; x < width; x += 2)
1668
0
  {
1669
0
    const BOOL lastX = (x + 1) >= width;
1670
0
    BYTE Y1e = 0;
1671
0
    BYTE Y2e = 0;
1672
0
    BYTE U1e = 0;
1673
0
    BYTE V1e = 0;
1674
0
    BYTE U2e = 0;
1675
0
    BYTE V2e = 0;
1676
0
    BYTE Y1o = 0;
1677
0
    BYTE Y2o = 0;
1678
0
    BYTE U1o = 0;
1679
0
    BYTE V1o = 0;
1680
0
    BYTE U2o = 0;
1681
0
    BYTE V2o = 0;
1682
    /* Read 4 pixels, 2 from even, 2 from odd lines */
1683
0
    {
1684
0
      BYTE r = 0;
1685
0
      BYTE g = 0;
1686
0
      BYTE b = 0;
1687
0
      const UINT32 color = FreeRDPReadColor(srcEven, srcFormat);
1688
0
      srcEven += bpp;
1689
0
      FreeRDPSplitColor(color, srcFormat, &r, &g, &b, nullptr, nullptr);
1690
0
      Y1e = Y2e = Y1o = Y2o = RGB2Y(r, g, b);
1691
0
      U1e = U2e = U1o = U2o = RGB2U(r, g, b);
1692
0
      V1e = V2e = V1o = V2o = RGB2V(r, g, b);
1693
0
    }
1694
1695
0
    if (!lastX)
1696
0
    {
1697
0
      BYTE r = 0;
1698
0
      BYTE g = 0;
1699
0
      BYTE b = 0;
1700
0
      const UINT32 color = FreeRDPReadColor(srcEven, srcFormat);
1701
0
      srcEven += bpp;
1702
0
      FreeRDPSplitColor(color, srcFormat, &r, &g, &b, nullptr, nullptr);
1703
0
      Y2e = RGB2Y(r, g, b);
1704
0
      U2e = RGB2U(r, g, b);
1705
0
      V2e = RGB2V(r, g, b);
1706
0
    }
1707
1708
0
    if (b1Odd)
1709
0
    {
1710
0
      BYTE r = 0;
1711
0
      BYTE g = 0;
1712
0
      BYTE b = 0;
1713
0
      const UINT32 color = FreeRDPReadColor(srcOdd, srcFormat);
1714
0
      srcOdd += bpp;
1715
0
      FreeRDPSplitColor(color, srcFormat, &r, &g, &b, nullptr, nullptr);
1716
0
      Y1o = Y2o = RGB2Y(r, g, b);
1717
0
      U1o = U2o = RGB2U(r, g, b);
1718
0
      V1o = V2o = RGB2V(r, g, b);
1719
0
    }
1720
1721
0
    if (b1Odd && !lastX)
1722
0
    {
1723
0
      BYTE r = 0;
1724
0
      BYTE g = 0;
1725
0
      BYTE b = 0;
1726
0
      const UINT32 color = FreeRDPReadColor(srcOdd, srcFormat);
1727
0
      srcOdd += bpp;
1728
0
      FreeRDPSplitColor(color, srcFormat, &r, &g, &b, nullptr, nullptr);
1729
0
      Y2o = RGB2Y(r, g, b);
1730
0
      U2o = RGB2U(r, g, b);
1731
0
      V2o = RGB2V(r, g, b);
1732
0
    }
1733
1734
    /* We have 4 Y pixels, so store them. */
1735
0
    *b1Even++ = Y1e;
1736
0
    *b1Even++ = Y2e;
1737
1738
0
    if (b1Odd)
1739
0
    {
1740
0
      *b1Odd++ = Y1o;
1741
0
      *b1Odd++ = Y2o;
1742
0
    }
1743
1744
    /* 2x 2y pixel in luma UV plane use averaging
1745
     */
1746
0
    {
1747
0
      const BYTE Uavg = WINPR_ASSERTING_INT_CAST(
1748
0
          BYTE, ((UINT16)U1e + (UINT16)U2e + (UINT16)U1o + (UINT16)U2o) / 4);
1749
0
      const BYTE Vavg = WINPR_ASSERTING_INT_CAST(
1750
0
          BYTE, ((UINT16)V1e + (UINT16)V2e + (UINT16)V1o + (UINT16)V2o) / 4);
1751
0
      *b2++ = Uavg;
1752
0
      *b3++ = Vavg;
1753
0
    }
1754
1755
    /* UV from 2x, 2y+1 */
1756
0
    if (b1Odd)
1757
0
    {
1758
0
      *b4++ = U1o;
1759
0
      *b5++ = V1o;
1760
1761
0
      if (!lastX)
1762
0
      {
1763
0
        *b4++ = U2o;
1764
0
        *b5++ = V2o;
1765
0
      }
1766
0
    }
1767
1768
    /* UV from 2x+1, 2y */
1769
0
    if (!lastX)
1770
0
    {
1771
0
      *b6++ = U2e;
1772
0
      *b7++ = V2e;
1773
0
    }
1774
0
  }
1775
0
}
1776
1777
static inline pstatus_t
1778
general_RGBToAVC444YUV_ANY(const BYTE* WINPR_RESTRICT pSrc, UINT32 srcFormat, UINT32 srcStep,
1779
                           BYTE* WINPR_RESTRICT pDst1[3], const UINT32 dst1Step[3],
1780
                           BYTE* WINPR_RESTRICT pDst2[3], const UINT32 dst2Step[3],
1781
                           const prim_size_t* WINPR_RESTRICT roi)
1782
0
{
1783
  /**
1784
   * Note: According to [MS-RDPEGFX 2.2.4.4 RFX_AVC420_BITMAP_STREAM] the
1785
   * width and height of the MPEG-4 AVC/H.264 codec bitstream MUST be aligned
1786
   * to a multiple of 16.
1787
   * Hence the passed destination YUV420/CHROMA420 buffers must have been
1788
   * allocated accordingly !!
1789
   */
1790
  /**
1791
   * [MS-RDPEGFX 3.3.8.3.2 YUV420p Stream Combination] defines the following "Bx areas":
1792
   *
1793
   * YUV420 frame (main view):
1794
   * B1:  From Y444 all pixels
1795
   * B2:  From U444 all pixels in even rows with even columns
1796
   * B3:  From V444 all pixels in even rows with even columns
1797
   *
1798
   * Chroma420 frame (auxiliary view):
1799
   * B45: From U444 and V444 all pixels from all odd rows
1800
   *      (The odd U444 and V444 rows must be interleaved in 8-line blocks in B45 !!!)
1801
   * B6:  From U444 all pixels in even rows with odd columns
1802
   * B7:  From V444 all pixels in even rows with odd columns
1803
   *
1804
   * Microsoft's horrible unclear description in MS-RDPEGFX translated to pseudo code looks like
1805
   * this:
1806
   *
1807
   * for (y = 0; y < fullHeight; y++)
1808
   * {
1809
   *     for (x = 0; x < fullWidth; x++)
1810
   *     {
1811
   *         B1[x,y] = Y444[x,y];
1812
   *     }
1813
   *  }
1814
   *
1815
   * for (y = 0; y < halfHeight; y++)
1816
   * {
1817
   *     for (x = 0; x < halfWidth; x++)
1818
   *     {
1819
   *         B2[x,y] = U444[2 * x,     2 * y];
1820
   *         B3[x,y] = V444[2 * x,     2 * y];
1821
   *         B6[x,y] = U444[2 * x + 1, 2 * y];
1822
   *         B7[x,y] = V444[2 * x + 1, 2 * y];
1823
   *     }
1824
   *  }
1825
   *
1826
   * for (y = 0; y < halfHeight; y++)
1827
   * {
1828
   *     yU  = (y / 8) * 16;   // identify first row of correct 8-line U block in B45
1829
   *     yU += (y % 8);        // add offset rows in destination block
1830
   *     yV  = yU + 8;         // the corresponding v line is always 8 rows ahead
1831
   *
1832
   *     for (x = 0; x < fullWidth; x++)
1833
   *     {
1834
   *         B45[x,yU] = U444[x, 2 * y + 1];
1835
   *         B45[x,yV] = V444[x, 2 * y + 1];
1836
   *     }
1837
   *  }
1838
   *
1839
   */
1840
0
  const BYTE* pMaxSrc = pSrc + 1ULL * (roi->height - 1) * srcStep;
1841
1842
0
  for (size_t y = 0; y < roi->height; y += 2)
1843
0
  {
1844
0
    WINPR_ASSERT(y < UINT32_MAX);
1845
1846
0
    const BOOL last = (y >= (roi->height - 1));
1847
0
    const BYTE* srcEven = y < roi->height ? pSrc + y * srcStep : pMaxSrc;
1848
0
    const BYTE* srcOdd = !last ? pSrc + (y + 1) * srcStep : pMaxSrc;
1849
0
    const UINT32 i = (UINT32)y >> 1;
1850
0
    const UINT32 n = (i & (uint32_t)~7) + i;
1851
0
    BYTE* b1Even = pDst1[0] + y * dst1Step[0];
1852
0
    BYTE* b1Odd = !last ? (b1Even + dst1Step[0]) : nullptr;
1853
0
    BYTE* b2 = pDst1[1] + (y / 2) * dst1Step[1];
1854
0
    BYTE* b3 = pDst1[2] + (y / 2) * dst1Step[2];
1855
0
    BYTE* b4 = pDst2[0] + 1ULL * dst2Step[0] * n;
1856
0
    BYTE* b5 = b4 + 8ULL * dst2Step[0];
1857
0
    BYTE* b6 = pDst2[1] + (y / 2) * dst2Step[1];
1858
0
    BYTE* b7 = pDst2[2] + (y / 2) * dst2Step[2];
1859
0
    general_RGBToAVC444YUV_ANY_DOUBLE_ROW(srcEven, srcOdd, srcFormat, b1Even, b1Odd, b2, b3, b4,
1860
0
                                          b5, b6, b7, roi->width);
1861
0
  }
1862
1863
0
  return PRIMITIVES_SUCCESS;
1864
0
}
1865
1866
static inline pstatus_t general_RGBToAVC444YUV(const BYTE* WINPR_RESTRICT pSrc, UINT32 srcFormat,
1867
                                               UINT32 srcStep, BYTE* WINPR_RESTRICT pDst1[3],
1868
                                               const UINT32 dst1Step[3],
1869
                                               BYTE* WINPR_RESTRICT pDst2[3],
1870
                                               const UINT32 dst2Step[3],
1871
                                               const prim_size_t* WINPR_RESTRICT roi)
1872
0
{
1873
0
  if (!pSrc || !pDst1 || !dst1Step || !pDst2 || !dst2Step)
1874
0
    return -1;
1875
1876
0
  if (!pDst1[0] || !pDst1[1] || !pDst1[2])
1877
0
    return -1;
1878
1879
0
  if (!dst1Step[0] || !dst1Step[1] || !dst1Step[2])
1880
0
    return -1;
1881
1882
0
  if (!pDst2[0] || !pDst2[1] || !pDst2[2])
1883
0
    return -1;
1884
1885
0
  if (!dst2Step[0] || !dst2Step[1] || !dst2Step[2])
1886
0
    return -1;
1887
1888
0
  switch (srcFormat)
1889
0
  {
1890
1891
0
    case PIXEL_FORMAT_BGRA32:
1892
0
    case PIXEL_FORMAT_BGRX32:
1893
0
      return general_RGBToAVC444YUV_BGRX(pSrc, srcStep, pDst1, dst1Step, pDst2, dst2Step,
1894
0
                                         roi);
1895
1896
0
    case PIXEL_FORMAT_RGBA32:
1897
0
    case PIXEL_FORMAT_RGBX32:
1898
0
      return general_RGBToAVC444YUV_RGBX(pSrc, srcStep, pDst1, dst1Step, pDst2, dst2Step,
1899
0
                                         roi);
1900
1901
0
    default:
1902
0
      return general_RGBToAVC444YUV_ANY(pSrc, srcFormat, srcStep, pDst1, dst1Step, pDst2,
1903
0
                                        dst2Step, roi);
1904
0
  }
1905
1906
0
  return !PRIMITIVES_SUCCESS;
1907
0
}
1908
1909
static inline void general_RGBToAVC444YUVv2_ANY_DOUBLE_ROW(
1910
    const BYTE* WINPR_RESTRICT srcEven, const BYTE* WINPR_RESTRICT srcOdd, UINT32 srcFormat,
1911
    BYTE* WINPR_RESTRICT yLumaDstEven, BYTE* WINPR_RESTRICT yLumaDstOdd,
1912
    BYTE* WINPR_RESTRICT uLumaDst, BYTE* WINPR_RESTRICT vLumaDst,
1913
    BYTE* WINPR_RESTRICT yEvenChromaDst1, BYTE* WINPR_RESTRICT yEvenChromaDst2,
1914
    BYTE* WINPR_RESTRICT yOddChromaDst1, BYTE* WINPR_RESTRICT yOddChromaDst2,
1915
    BYTE* WINPR_RESTRICT uChromaDst1, BYTE* WINPR_RESTRICT uChromaDst2,
1916
    BYTE* WINPR_RESTRICT vChromaDst1, BYTE* WINPR_RESTRICT vChromaDst2, UINT32 width)
1917
0
{
1918
0
  const UINT32 bpp = FreeRDPGetBytesPerPixel(srcFormat);
1919
1920
0
  WINPR_ASSERT((width % 2) == 0);
1921
0
  for (UINT32 x = 0; x < width; x += 2)
1922
0
  {
1923
0
    BYTE Ya = 0;
1924
0
    BYTE Ua = 0;
1925
0
    BYTE Va = 0;
1926
0
    BYTE Yb = 0;
1927
0
    BYTE Ub = 0;
1928
0
    BYTE Vb = 0;
1929
0
    BYTE Yc = 0;
1930
0
    BYTE Uc = 0;
1931
0
    BYTE Vc = 0;
1932
0
    BYTE Yd = 0;
1933
0
    BYTE Ud = 0;
1934
0
    BYTE Vd = 0;
1935
0
    {
1936
0
      BYTE b = 0;
1937
0
      BYTE g = 0;
1938
0
      BYTE r = 0;
1939
0
      const UINT32 color = FreeRDPReadColor(srcEven, srcFormat);
1940
0
      srcEven += bpp;
1941
0
      FreeRDPSplitColor(color, srcFormat, &r, &g, &b, nullptr, nullptr);
1942
0
      Ya = RGB2Y(r, g, b);
1943
0
      Ua = RGB2U(r, g, b);
1944
0
      Va = RGB2V(r, g, b);
1945
0
    }
1946
1947
0
    if (x < width - 1)
1948
0
    {
1949
0
      BYTE b = 0;
1950
0
      BYTE g = 0;
1951
0
      BYTE r = 0;
1952
0
      const UINT32 color = FreeRDPReadColor(srcEven, srcFormat);
1953
0
      srcEven += bpp;
1954
0
      FreeRDPSplitColor(color, srcFormat, &r, &g, &b, nullptr, nullptr);
1955
0
      Yb = RGB2Y(r, g, b);
1956
0
      Ub = RGB2U(r, g, b);
1957
0
      Vb = RGB2V(r, g, b);
1958
0
    }
1959
0
    else
1960
0
    {
1961
0
      Yb = Ya;
1962
0
      Ub = Ua;
1963
0
      Vb = Va;
1964
0
    }
1965
1966
0
    if (srcOdd)
1967
0
    {
1968
0
      BYTE b = 0;
1969
0
      BYTE g = 0;
1970
0
      BYTE r = 0;
1971
0
      const UINT32 color = FreeRDPReadColor(srcOdd, srcFormat);
1972
0
      srcOdd += bpp;
1973
0
      FreeRDPSplitColor(color, srcFormat, &r, &g, &b, nullptr, nullptr);
1974
0
      Yc = RGB2Y(r, g, b);
1975
0
      Uc = RGB2U(r, g, b);
1976
0
      Vc = RGB2V(r, g, b);
1977
0
    }
1978
0
    else
1979
0
    {
1980
0
      Yc = Ya;
1981
0
      Uc = Ua;
1982
0
      Vc = Va;
1983
0
    }
1984
1985
0
    if (srcOdd && (x < width - 1))
1986
0
    {
1987
0
      BYTE b = 0;
1988
0
      BYTE g = 0;
1989
0
      BYTE r = 0;
1990
0
      const UINT32 color = FreeRDPReadColor(srcOdd, srcFormat);
1991
0
      srcOdd += bpp;
1992
0
      FreeRDPSplitColor(color, srcFormat, &r, &g, &b, nullptr, nullptr);
1993
0
      Yd = RGB2Y(r, g, b);
1994
0
      Ud = RGB2U(r, g, b);
1995
0
      Vd = RGB2V(r, g, b);
1996
0
    }
1997
0
    else
1998
0
    {
1999
0
      Yd = Ya;
2000
0
      Ud = Ua;
2001
0
      Vd = Va;
2002
0
    }
2003
2004
    /* Y [b1] */
2005
0
    *yLumaDstEven++ = Ya;
2006
2007
0
    if (x < width - 1)
2008
0
      *yLumaDstEven++ = Yb;
2009
2010
0
    if (srcOdd)
2011
0
      *yLumaDstOdd++ = Yc;
2012
2013
0
    if (srcOdd && (x < width - 1))
2014
0
      *yLumaDstOdd++ = Yd;
2015
2016
    /* 2x 2y [b2,b3] */
2017
0
    *uLumaDst++ = (Ua + Ub + Uc + Ud) / 4;
2018
0
    *vLumaDst++ = (Va + Vb + Vc + Vd) / 4;
2019
2020
    /* 2x+1, y [b4,b5] even */
2021
0
    if (x < width - 1)
2022
0
    {
2023
0
      *yEvenChromaDst1++ = Ub;
2024
0
      *yEvenChromaDst2++ = Vb;
2025
0
    }
2026
2027
0
    if (srcOdd)
2028
0
    {
2029
      /* 2x+1, y [b4,b5] odd */
2030
0
      if (x < width - 1)
2031
0
      {
2032
0
        *yOddChromaDst1++ = Ud;
2033
0
        *yOddChromaDst2++ = Vd;
2034
0
      }
2035
2036
      /* 4x 2y+1 [b6, b7] */
2037
0
      if (x % 4 == 0)
2038
0
      {
2039
0
        *uChromaDst1++ = Uc;
2040
0
        *uChromaDst2++ = Vc;
2041
0
      }
2042
      /* 4x+2 2y+1 [b8, b9] */
2043
0
      else
2044
0
      {
2045
0
        *vChromaDst1++ = Uc;
2046
0
        *vChromaDst2++ = Vc;
2047
0
      }
2048
0
    }
2049
0
  }
2050
0
}
2051
2052
static inline pstatus_t
2053
general_RGBToAVC444YUVv2_ANY(const BYTE* WINPR_RESTRICT pSrc, UINT32 srcFormat, UINT32 srcStep,
2054
                             BYTE* WINPR_RESTRICT pDst1[3], const UINT32 dst1Step[3],
2055
                             BYTE* WINPR_RESTRICT pDst2[3], const UINT32 dst2Step[3],
2056
                             const prim_size_t* WINPR_RESTRICT roi)
2057
0
{
2058
  /**
2059
   * Note: According to [MS-RDPEGFX 2.2.4.4 RFX_AVC420_BITMAP_STREAM] the
2060
   * width and height of the MPEG-4 AVC/H.264 codec bitstream MUST be aligned
2061
   * to a multiple of 16.
2062
   * Hence the passed destination YUV420/CHROMA420 buffers must have been
2063
   * allocated accordingly !!
2064
   */
2065
  /**
2066
   * [MS-RDPEGFX 3.3.8.3.3 YUV420p Stream Combination for YUV444v2 mode] defines the following "Bx
2067
   * areas":
2068
   *
2069
   * YUV420 frame (main view):
2070
   * B1:  From Y444 all pixels
2071
   * B2:  From U444 all pixels in even rows with even rows and columns
2072
   * B3:  From V444 all pixels in even rows with even rows and columns
2073
   *
2074
   * Chroma420 frame (auxiliary view):
2075
   * B45: From U444 and V444 all pixels from all odd columns
2076
   * B67: From U444 and V444 every 4th pixel in odd rows
2077
   * B89:  From U444 and V444 every 4th pixel (initial offset of 2) in odd rows
2078
   *
2079
   * Chroma Bxy areas correspond to the left and right half of the YUV420 plane.
2080
   * for (y = 0; y < fullHeight; y++)
2081
   * {
2082
   *     for (x = 0; x < fullWidth; x++)
2083
   *     {
2084
   *         B1[x,y] = Y444[x,y];
2085
   *     }
2086
   *
2087
   *     for (x = 0; x < halfWidth; x++)
2088
   *     {
2089
   *         B4[x,y] = U444[2 * x, 2 * y];
2090
   *         B5[x,y] = V444[2 * x, 2 * y];
2091
   *     }
2092
   *  }
2093
   *
2094
   * for (y = 0; y < halfHeight; y++)
2095
   * {
2096
   *     for (x = 0; x < halfWidth; x++)
2097
   *     {
2098
   *         B2[x,y] = U444[2 * x,     2 * y];
2099
   *         B3[x,y] = V444[2 * x,     2 * y];
2100
   *         B6[x,y] = U444[4 * x,     2 * y + 1];
2101
   *         B7[x,y] = V444[4 * x,     2 * y + 1];
2102
   *         B8[x,y] = V444[4 * x + 2, 2 * y + 1];
2103
   *         B9[x,y] = V444[4 * x + 2, 2 * y] + 1;
2104
   *     }
2105
   *  }
2106
   *
2107
   */
2108
0
  if (roi->height < 1 || roi->width < 1)
2109
0
    return !PRIMITIVES_SUCCESS;
2110
2111
0
  size_t y = 0;
2112
0
  for (; y < roi->height - roi->height % 2; y += 2)
2113
0
  {
2114
0
    const BYTE* srcEven = (pSrc + y * srcStep);
2115
0
    const BYTE* srcOdd = (y < roi->height - 1) ? (srcEven + srcStep) : nullptr;
2116
0
    BYTE* dstLumaYEven = (pDst1[0] + y * dst1Step[0]);
2117
0
    BYTE* dstLumaYOdd = (dstLumaYEven + dst1Step[0]);
2118
0
    BYTE* dstLumaU = (pDst1[1] + (y / 2) * dst1Step[1]);
2119
0
    BYTE* dstLumaV = (pDst1[2] + (y / 2) * dst1Step[2]);
2120
0
    BYTE* dstEvenChromaY1 = (pDst2[0] + y * dst2Step[0]);
2121
0
    BYTE* dstEvenChromaY2 = dstEvenChromaY1 + roi->width / 2;
2122
0
    BYTE* dstOddChromaY1 = dstEvenChromaY1 + dst2Step[0];
2123
0
    BYTE* dstOddChromaY2 = dstEvenChromaY2 + dst2Step[0];
2124
0
    BYTE* dstChromaU1 = (pDst2[1] + (y / 2) * dst2Step[1]);
2125
0
    BYTE* dstChromaV1 = (pDst2[2] + (y / 2) * dst2Step[2]);
2126
0
    BYTE* dstChromaU2 = dstChromaU1 + roi->width / 4;
2127
0
    BYTE* dstChromaV2 = dstChromaV1 + roi->width / 4;
2128
0
    general_RGBToAVC444YUVv2_ANY_DOUBLE_ROW(
2129
0
        srcEven, srcOdd, srcFormat, dstLumaYEven, dstLumaYOdd, dstLumaU, dstLumaV,
2130
0
        dstEvenChromaY1, dstEvenChromaY2, dstOddChromaY1, dstOddChromaY2, dstChromaU1,
2131
0
        dstChromaU2, dstChromaV1, dstChromaV2, roi->width);
2132
0
  }
2133
0
  for (; y < roi->height; y++)
2134
0
  {
2135
0
    const BYTE* srcEven = (pSrc + y * srcStep);
2136
0
    BYTE* dstLumaYEven = (pDst1[0] + y * dst1Step[0]);
2137
0
    BYTE* dstLumaU = (pDst1[1] + (y / 2) * dst1Step[1]);
2138
0
    BYTE* dstLumaV = (pDst1[2] + (y / 2) * dst1Step[2]);
2139
0
    BYTE* dstEvenChromaY1 = (pDst2[0] + y * dst2Step[0]);
2140
0
    BYTE* dstEvenChromaY2 = dstEvenChromaY1 + roi->width / 2;
2141
0
    general_RGBToAVC444YUVv2_ANY_DOUBLE_ROW(
2142
0
        srcEven, nullptr, srcFormat, dstLumaYEven, nullptr, dstLumaU, dstLumaV, dstEvenChromaY1,
2143
0
        dstEvenChromaY2, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, roi->width);
2144
0
  }
2145
2146
0
  return PRIMITIVES_SUCCESS;
2147
0
}
2148
2149
static inline void int_general_RGBToAVC444YUVv2_BGRX_DOUBLE_ROW(
2150
    size_t offset, const BYTE* WINPR_RESTRICT pSrcEven, const BYTE* WINPR_RESTRICT pSrcOdd,
2151
    BYTE* WINPR_RESTRICT yLumaDstEven, BYTE* WINPR_RESTRICT yLumaDstOdd,
2152
    BYTE* WINPR_RESTRICT uLumaDst, BYTE* WINPR_RESTRICT vLumaDst,
2153
    BYTE* WINPR_RESTRICT yEvenChromaDst1, BYTE* WINPR_RESTRICT yEvenChromaDst2,
2154
    BYTE* WINPR_RESTRICT yOddChromaDst1, BYTE* WINPR_RESTRICT yOddChromaDst2,
2155
    BYTE* WINPR_RESTRICT uChromaDst1, BYTE* WINPR_RESTRICT uChromaDst2,
2156
    BYTE* WINPR_RESTRICT vChromaDst1, BYTE* WINPR_RESTRICT vChromaDst2, UINT32 width)
2157
0
{
2158
0
  WINPR_ASSERT((width % 2) == 0);
2159
0
  WINPR_ASSERT(pSrcEven);
2160
0
  WINPR_ASSERT(yLumaDstEven);
2161
0
  WINPR_ASSERT(uLumaDst);
2162
0
  WINPR_ASSERT(vLumaDst);
2163
2164
0
  for (size_t x = offset; x < width; x += 2)
2165
0
  {
2166
0
    const BYTE* srcEven = &pSrcEven[4ULL * x];
2167
0
    const BYTE* srcOdd = pSrcOdd ? &pSrcOdd[4ULL * x] : nullptr;
2168
0
    BYTE Ya = 0;
2169
0
    BYTE Ua = 0;
2170
0
    BYTE Va = 0;
2171
0
    BYTE Yb = 0;
2172
0
    BYTE Ub = 0;
2173
0
    BYTE Vb = 0;
2174
0
    BYTE Yc = 0;
2175
0
    BYTE Uc = 0;
2176
0
    BYTE Vc = 0;
2177
0
    BYTE Yd = 0;
2178
0
    BYTE Ud = 0;
2179
0
    BYTE Vd = 0;
2180
0
    {
2181
0
      const BYTE b = *srcEven++;
2182
0
      const BYTE g = *srcEven++;
2183
0
      const BYTE r = *srcEven++;
2184
0
      srcEven++;
2185
0
      Ya = RGB2Y(r, g, b);
2186
0
      Ua = RGB2U(r, g, b);
2187
0
      Va = RGB2V(r, g, b);
2188
0
    }
2189
2190
0
    if (x < width - 1)
2191
0
    {
2192
0
      const BYTE b = *srcEven++;
2193
0
      const BYTE g = *srcEven++;
2194
0
      const BYTE r = *srcEven++;
2195
0
      srcEven++;
2196
0
      Yb = RGB2Y(r, g, b);
2197
0
      Ub = RGB2U(r, g, b);
2198
0
      Vb = RGB2V(r, g, b);
2199
0
    }
2200
0
    else
2201
0
    {
2202
0
      Yb = Ya;
2203
0
      Ub = Ua;
2204
0
      Vb = Va;
2205
0
    }
2206
2207
0
    if (srcOdd)
2208
0
    {
2209
0
      const BYTE b = *srcOdd++;
2210
0
      const BYTE g = *srcOdd++;
2211
0
      const BYTE r = *srcOdd++;
2212
0
      srcOdd++;
2213
0
      Yc = RGB2Y(r, g, b);
2214
0
      Uc = RGB2U(r, g, b);
2215
0
      Vc = RGB2V(r, g, b);
2216
0
    }
2217
0
    else
2218
0
    {
2219
0
      Yc = Ya;
2220
0
      Uc = Ua;
2221
0
      Vc = Va;
2222
0
    }
2223
2224
0
    if (srcOdd && (x < width - 1))
2225
0
    {
2226
0
      const BYTE b = *srcOdd++;
2227
0
      const BYTE g = *srcOdd++;
2228
0
      const BYTE r = *srcOdd++;
2229
0
      srcOdd++;
2230
0
      Yd = RGB2Y(r, g, b);
2231
0
      Ud = RGB2U(r, g, b);
2232
0
      Vd = RGB2V(r, g, b);
2233
0
    }
2234
0
    else
2235
0
    {
2236
0
      Yd = Ya;
2237
0
      Ud = Ua;
2238
0
      Vd = Va;
2239
0
    }
2240
2241
    /* Y [b1] */
2242
0
    *yLumaDstEven++ = Ya;
2243
2244
0
    if (x < width - 1)
2245
0
      *yLumaDstEven++ = Yb;
2246
2247
0
    if (srcOdd && yLumaDstOdd)
2248
0
      *yLumaDstOdd++ = Yc;
2249
2250
0
    if (srcOdd && (x < width - 1) && yLumaDstOdd)
2251
0
      *yLumaDstOdd++ = Yd;
2252
2253
    /* 2x 2y [b2,b3] */
2254
0
    *uLumaDst++ = (Ua + Ub + Uc + Ud) / 4;
2255
0
    *vLumaDst++ = (Va + Vb + Vc + Vd) / 4;
2256
2257
    /* 2x+1, y [b4,b5] even */
2258
0
    if (x < width - 1)
2259
0
    {
2260
0
      *yEvenChromaDst1++ = Ub;
2261
0
      *yEvenChromaDst2++ = Vb;
2262
0
    }
2263
2264
0
    if (srcOdd)
2265
0
    {
2266
      /* 2x+1, y [b4,b5] odd */
2267
0
      if (x < width - 1)
2268
0
      {
2269
0
        *yOddChromaDst1++ = Ud;
2270
0
        *yOddChromaDst2++ = Vd;
2271
0
      }
2272
2273
      /* 4x 2y+1 [b6, b7] */
2274
0
      if (x % 4 == 0)
2275
0
      {
2276
0
        *uChromaDst1++ = Uc;
2277
0
        *uChromaDst2++ = Vc;
2278
0
      }
2279
      /* 4x+2 2y+1 [b8, b9] */
2280
0
      else
2281
0
      {
2282
0
        *vChromaDst1++ = Uc;
2283
0
        *vChromaDst2++ = Vc;
2284
0
      }
2285
0
    }
2286
0
  }
2287
0
}
2288
2289
void general_RGBToAVC444YUVv2_BGRX_DOUBLE_ROW(
2290
    size_t offset, const BYTE* WINPR_RESTRICT pSrcEven, const BYTE* WINPR_RESTRICT pSrcOdd,
2291
    BYTE* WINPR_RESTRICT yLumaDstEven, BYTE* WINPR_RESTRICT yLumaDstOdd,
2292
    BYTE* WINPR_RESTRICT uLumaDst, BYTE* WINPR_RESTRICT vLumaDst,
2293
    BYTE* WINPR_RESTRICT yEvenChromaDst1, BYTE* WINPR_RESTRICT yEvenChromaDst2,
2294
    BYTE* WINPR_RESTRICT yOddChromaDst1, BYTE* WINPR_RESTRICT yOddChromaDst2,
2295
    BYTE* WINPR_RESTRICT uChromaDst1, BYTE* WINPR_RESTRICT uChromaDst2,
2296
    BYTE* WINPR_RESTRICT vChromaDst1, BYTE* WINPR_RESTRICT vChromaDst2, UINT32 width)
2297
0
{
2298
0
  int_general_RGBToAVC444YUVv2_BGRX_DOUBLE_ROW(
2299
0
      offset, pSrcEven, pSrcOdd, yLumaDstEven, yLumaDstOdd, uLumaDst, vLumaDst, yEvenChromaDst1,
2300
0
      yEvenChromaDst2, yOddChromaDst1, yOddChromaDst2, uChromaDst1, uChromaDst2, vChromaDst1,
2301
0
      vChromaDst2, width);
2302
0
}
2303
2304
static inline pstatus_t general_RGBToAVC444YUVv2_BGRX(const BYTE* WINPR_RESTRICT pSrc,
2305
                                                      UINT32 srcStep, BYTE* WINPR_RESTRICT pDst1[3],
2306
                                                      const UINT32 dst1Step[3],
2307
                                                      BYTE* WINPR_RESTRICT pDst2[3],
2308
                                                      const UINT32 dst2Step[3],
2309
                                                      const prim_size_t* WINPR_RESTRICT roi)
2310
0
{
2311
0
  if (roi->height < 1 || roi->width < 1)
2312
0
    return !PRIMITIVES_SUCCESS;
2313
2314
0
  size_t y = 0;
2315
0
  for (; y < roi->height - roi->height % 2; y += 2)
2316
0
  {
2317
0
    const BYTE* srcEven = (pSrc + y * srcStep);
2318
0
    const BYTE* srcOdd = (srcEven + srcStep);
2319
0
    BYTE* dstLumaYEven = (pDst1[0] + y * dst1Step[0]);
2320
0
    BYTE* dstLumaYOdd = (dstLumaYEven + dst1Step[0]);
2321
0
    BYTE* dstLumaU = (pDst1[1] + (y / 2) * dst1Step[1]);
2322
0
    BYTE* dstLumaV = (pDst1[2] + (y / 2) * dst1Step[2]);
2323
0
    BYTE* dstEvenChromaY1 = (pDst2[0] + y * dst2Step[0]);
2324
0
    BYTE* dstEvenChromaY2 = dstEvenChromaY1 + roi->width / 2;
2325
0
    BYTE* dstOddChromaY1 = dstEvenChromaY1 + dst2Step[0];
2326
0
    BYTE* dstOddChromaY2 = dstEvenChromaY2 + dst2Step[0];
2327
0
    BYTE* dstChromaU1 = (pDst2[1] + (y / 2) * dst2Step[1]);
2328
0
    BYTE* dstChromaV1 = (pDst2[2] + (y / 2) * dst2Step[2]);
2329
0
    BYTE* dstChromaU2 = dstChromaU1 + roi->width / 4;
2330
0
    BYTE* dstChromaV2 = dstChromaV1 + roi->width / 4;
2331
0
    int_general_RGBToAVC444YUVv2_BGRX_DOUBLE_ROW(
2332
0
        0, srcEven, srcOdd, dstLumaYEven, dstLumaYOdd, dstLumaU, dstLumaV, dstEvenChromaY1,
2333
0
        dstEvenChromaY2, dstOddChromaY1, dstOddChromaY2, dstChromaU1, dstChromaU2, dstChromaV1,
2334
0
        dstChromaV2, roi->width);
2335
0
  }
2336
0
  for (; y < roi->height; y++)
2337
0
  {
2338
0
    const BYTE* srcEven = (pSrc + y * srcStep);
2339
0
    BYTE* dstLumaYEven = (pDst1[0] + y * dst1Step[0]);
2340
0
    BYTE* dstLumaU = (pDst1[1] + (y / 2) * dst1Step[1]);
2341
0
    BYTE* dstLumaV = (pDst1[2] + (y / 2) * dst1Step[2]);
2342
0
    BYTE* dstEvenChromaY1 = (pDst2[0] + y * dst2Step[0]);
2343
0
    BYTE* dstEvenChromaY2 = dstEvenChromaY1 + roi->width / 2;
2344
0
    int_general_RGBToAVC444YUVv2_BGRX_DOUBLE_ROW(
2345
0
        0, srcEven, nullptr, dstLumaYEven, nullptr, dstLumaU, dstLumaV, dstEvenChromaY1,
2346
0
        dstEvenChromaY2, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, roi->width);
2347
0
  }
2348
2349
0
  return PRIMITIVES_SUCCESS;
2350
0
}
2351
2352
static pstatus_t general_RGBToAVC444YUVv2(const BYTE* WINPR_RESTRICT pSrc, UINT32 srcFormat,
2353
                                          UINT32 srcStep, BYTE* WINPR_RESTRICT pDst1[3],
2354
                                          const UINT32 dst1Step[3], BYTE* WINPR_RESTRICT pDst2[3],
2355
                                          const UINT32 dst2Step[3],
2356
                                          const prim_size_t* WINPR_RESTRICT roi)
2357
0
{
2358
0
  switch (srcFormat)
2359
0
  {
2360
0
    case PIXEL_FORMAT_BGRA32:
2361
0
    case PIXEL_FORMAT_BGRX32:
2362
0
      return general_RGBToAVC444YUVv2_BGRX(pSrc, srcStep, pDst1, dst1Step, pDst2, dst2Step,
2363
0
                                           roi);
2364
2365
0
    default:
2366
0
      return general_RGBToAVC444YUVv2_ANY(pSrc, srcFormat, srcStep, pDst1, dst1Step, pDst2,
2367
0
                                          dst2Step, roi);
2368
0
  }
2369
2370
0
  return !PRIMITIVES_SUCCESS;
2371
0
}
2372
2373
void primitives_init_YUV(primitives_t* WINPR_RESTRICT prims)
2374
0
{
2375
0
  prims->YUV420ToRGB_8u_P3AC4R = general_YUV420ToRGB_8u_P3AC4R;
2376
0
  prims->YUV444ToRGB_8u_P3AC4R = general_YUV444ToRGB_8u_P3AC4R;
2377
0
  prims->RGBToYUV420_8u_P3AC4R = general_RGBToYUV420_8u_P3AC4R;
2378
0
  prims->RGBToYUV444_8u_P3AC4R = general_RGBToYUV444_8u_P3AC4R;
2379
0
  prims->RGBToI444_8u = general_RGBToI444_8u;
2380
0
  prims->YUV420CombineToYUV444 = general_YUV420CombineToYUV444;
2381
0
  prims->YUV444SplitToYUV420 = general_YUV444SplitToYUV420;
2382
0
  prims->RGBToAVC444YUV = general_RGBToAVC444YUV;
2383
0
  prims->RGBToAVC444YUVv2 = general_RGBToAVC444YUVv2;
2384
0
}
2385
2386
void primitives_init_YUV_opt(primitives_t* WINPR_RESTRICT prims)
2387
0
{
2388
0
  primitives_init_YUV(prims);
2389
0
  primitives_init_YUV_sse41(prims);
2390
0
  primitives_init_YUV_neon(prims);
2391
0
}