Coverage Report

Created: 2026-08-31 06:26

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