Coverage Report

Created: 2026-10-15 06:27

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