Coverage Report

Created: 2024-05-20 06:11

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