Coverage Report

Created: 2024-09-08 06:18

/src/FreeRDP/libfreerdp/codec/rfx_encode.c
Line
Count
Source (jump to first uncovered line)
1
/**
2
 * FreeRDP: A Remote Desktop Protocol Implementation
3
 * RemoteFX Codec Library - Encode
4
 *
5
 * Copyright 2011 Vic Lee
6
 * Copyright 2011 Norbert Federa <norbert.federa@thincast.com>
7
 *
8
 * Licensed under the Apache License, Version 2.0 (the "License");
9
 * you may not use this file except in compliance with the License.
10
 * You may obtain a copy of the License at
11
 *
12
 *     http://www.apache.org/licenses/LICENSE-2.0
13
 *
14
 * Unless required by applicable law or agreed to in writing, software
15
 * distributed under the License is distributed on an "AS IS" BASIS,
16
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
 * See the License for the specific language governing permissions and
18
 * limitations under the License.
19
 */
20
21
#include <freerdp/config.h>
22
23
#include <stdio.h>
24
#include <stdlib.h>
25
#include <string.h>
26
27
#include <winpr/crt.h>
28
#include <winpr/collections.h>
29
30
#include <freerdp/primitives.h>
31
32
#include "rfx_types.h"
33
#include "rfx_rlgr.h"
34
#include "rfx_differential.h"
35
#include "rfx_quantization.h"
36
#include "rfx_dwt.h"
37
38
#include "rfx_encode.h"
39
40
#define MINMAX(_v, _l, _h) ((_v) < (_l) ? (_l) : ((_v) > (_h) ? (_h) : (_v)))
41
42
static void rfx_encode_format_rgb(const BYTE* WINPR_RESTRICT rgb_data, int width, int height,
43
                                  int rowstride, UINT32 pixel_format,
44
                                  const BYTE* WINPR_RESTRICT palette, INT16* WINPR_RESTRICT r_buf,
45
                                  INT16* WINPR_RESTRICT g_buf, INT16* WINPR_RESTRICT b_buf)
46
0
{
47
0
  int x_exceed = 0;
48
0
  int y_exceed = 0;
49
0
  const BYTE* src = NULL;
50
0
  INT16 r = 0;
51
0
  INT16 g = 0;
52
0
  INT16 b = 0;
53
0
  INT16* r_last = NULL;
54
0
  INT16* g_last = NULL;
55
0
  INT16* b_last = NULL;
56
0
  x_exceed = 64 - width;
57
0
  y_exceed = 64 - height;
58
59
0
  for (int y = 0; y < height; y++)
60
0
  {
61
0
    src = rgb_data + 1ULL * y * rowstride;
62
63
0
    switch (pixel_format)
64
0
    {
65
0
      case PIXEL_FORMAT_BGRX32:
66
0
      case PIXEL_FORMAT_BGRA32:
67
0
        for (int x = 0; x < width; x++)
68
0
        {
69
0
          *b_buf++ = (INT16)(*src++);
70
0
          *g_buf++ = (INT16)(*src++);
71
0
          *r_buf++ = (INT16)(*src++);
72
0
          src++;
73
0
        }
74
75
0
        break;
76
77
0
      case PIXEL_FORMAT_XBGR32:
78
0
      case PIXEL_FORMAT_ABGR32:
79
0
        for (int x = 0; x < width; x++)
80
0
        {
81
0
          src++;
82
0
          *b_buf++ = (INT16)(*src++);
83
0
          *g_buf++ = (INT16)(*src++);
84
0
          *r_buf++ = (INT16)(*src++);
85
0
        }
86
87
0
        break;
88
89
0
      case PIXEL_FORMAT_RGBX32:
90
0
      case PIXEL_FORMAT_RGBA32:
91
0
        for (int x = 0; x < width; x++)
92
0
        {
93
0
          *r_buf++ = (INT16)(*src++);
94
0
          *g_buf++ = (INT16)(*src++);
95
0
          *b_buf++ = (INT16)(*src++);
96
0
          src++;
97
0
        }
98
99
0
        break;
100
101
0
      case PIXEL_FORMAT_XRGB32:
102
0
      case PIXEL_FORMAT_ARGB32:
103
0
        for (int x = 0; x < width; x++)
104
0
        {
105
0
          src++;
106
0
          *r_buf++ = (INT16)(*src++);
107
0
          *g_buf++ = (INT16)(*src++);
108
0
          *b_buf++ = (INT16)(*src++);
109
0
        }
110
111
0
        break;
112
113
0
      case PIXEL_FORMAT_BGR24:
114
0
        for (int x = 0; x < width; x++)
115
0
        {
116
0
          *b_buf++ = (INT16)(*src++);
117
0
          *g_buf++ = (INT16)(*src++);
118
0
          *r_buf++ = (INT16)(*src++);
119
0
        }
120
121
0
        break;
122
123
0
      case PIXEL_FORMAT_RGB24:
124
0
        for (int x = 0; x < width; x++)
125
0
        {
126
0
          *r_buf++ = (INT16)(*src++);
127
0
          *g_buf++ = (INT16)(*src++);
128
0
          *b_buf++ = (INT16)(*src++);
129
0
        }
130
131
0
        break;
132
133
0
      case PIXEL_FORMAT_BGR16:
134
0
        for (int x = 0; x < width; x++)
135
0
        {
136
0
          *b_buf++ = (INT16)(((*(src + 1)) & 0xF8) | ((*(src + 1)) >> 5));
137
0
          *g_buf++ = (INT16)((((*(src + 1)) & 0x07) << 5) | (((*src) & 0xE0) >> 3));
138
0
          *r_buf++ = (INT16)((((*src) & 0x1F) << 3) | (((*src) >> 2) & 0x07));
139
0
          src += 2;
140
0
        }
141
142
0
        break;
143
144
0
      case PIXEL_FORMAT_RGB16:
145
0
        for (int x = 0; x < width; x++)
146
0
        {
147
0
          *r_buf++ = (INT16)(((*(src + 1)) & 0xF8) | ((*(src + 1)) >> 5));
148
0
          *g_buf++ = (INT16)((((*(src + 1)) & 0x07) << 5) | (((*src) & 0xE0) >> 3));
149
0
          *b_buf++ = (INT16)((((*src) & 0x1F) << 3) | (((*src) >> 2) & 0x07));
150
0
          src += 2;
151
0
        }
152
153
0
        break;
154
155
0
      case PIXEL_FORMAT_RGB8:
156
0
        if (!palette)
157
0
          break;
158
159
0
        for (int x = 0; x < width; x++)
160
0
        {
161
0
          int shift = 0;
162
0
          BYTE idx = 0;
163
0
          shift = (7 - (x % 8));
164
0
          idx = ((*src) >> shift) & 1;
165
0
          idx |= (((*(src + 1)) >> shift) & 1) << 1;
166
0
          idx |= (((*(src + 2)) >> shift) & 1) << 2;
167
0
          idx |= (((*(src + 3)) >> shift) & 1) << 3;
168
0
          idx *= 3;
169
0
          *r_buf++ = (INT16)palette[idx];
170
0
          *g_buf++ = (INT16)palette[idx + 1];
171
0
          *b_buf++ = (INT16)palette[idx + 2];
172
173
0
          if (shift == 0)
174
0
            src += 4;
175
0
        }
176
177
0
        break;
178
179
0
      case PIXEL_FORMAT_A4:
180
0
        if (!palette)
181
0
          break;
182
183
0
        for (int x = 0; x < width; x++)
184
0
        {
185
0
          int idx = (*src) * 3;
186
0
          *r_buf++ = (INT16)palette[idx];
187
0
          *g_buf++ = (INT16)palette[idx + 1];
188
0
          *b_buf++ = (INT16)palette[idx + 2];
189
0
          src++;
190
0
        }
191
192
0
        break;
193
194
0
      default:
195
0
        break;
196
0
    }
197
198
    /* Fill the horizontal region outside of 64x64 tile size with the right-most pixel for best
199
     * quality */
200
0
    if (x_exceed > 0)
201
0
    {
202
0
      r = *(r_buf - 1);
203
0
      g = *(g_buf - 1);
204
0
      b = *(b_buf - 1);
205
206
0
      for (int x = 0; x < x_exceed; x++)
207
0
      {
208
0
        *r_buf++ = r;
209
0
        *g_buf++ = g;
210
0
        *b_buf++ = b;
211
0
      }
212
0
    }
213
0
  }
214
215
  /* Fill the vertical region outside of 64x64 tile size with the last line. */
216
0
  if (y_exceed > 0)
217
0
  {
218
0
    r_last = r_buf - 64;
219
0
    g_last = g_buf - 64;
220
0
    b_last = b_buf - 64;
221
222
0
    while (y_exceed > 0)
223
0
    {
224
0
      CopyMemory(r_buf, r_last, 64 * sizeof(INT16));
225
0
      CopyMemory(g_buf, g_last, 64 * sizeof(INT16));
226
0
      CopyMemory(b_buf, b_last, 64 * sizeof(INT16));
227
0
      r_buf += 64;
228
0
      g_buf += 64;
229
0
      b_buf += 64;
230
0
      y_exceed--;
231
0
    }
232
0
  }
233
0
}
234
235
/* rfx_encode_rgb_to_ycbcr code now resides in the primitives library. */
236
237
static void rfx_encode_component(RFX_CONTEXT* WINPR_RESTRICT context,
238
                                 const UINT32* WINPR_RESTRICT quantization_values,
239
                                 INT16* WINPR_RESTRICT data, BYTE* WINPR_RESTRICT buffer,
240
                                 int buffer_size, int* WINPR_RESTRICT size)
241
0
{
242
0
  INT16* dwt_buffer = NULL;
243
0
  dwt_buffer = BufferPool_Take(context->priv->BufferPool, -1); /* dwt_buffer */
244
0
  PROFILER_ENTER(context->priv->prof_rfx_encode_component)
245
0
  PROFILER_ENTER(context->priv->prof_rfx_dwt_2d_encode)
246
0
  context->dwt_2d_encode(data, dwt_buffer);
247
0
  PROFILER_EXIT(context->priv->prof_rfx_dwt_2d_encode)
248
0
  PROFILER_ENTER(context->priv->prof_rfx_quantization_encode)
249
0
  context->quantization_encode(data, quantization_values);
250
0
  PROFILER_EXIT(context->priv->prof_rfx_quantization_encode)
251
0
  PROFILER_ENTER(context->priv->prof_rfx_differential_encode)
252
0
  rfx_differential_encode(data + 4032, 64);
253
0
  PROFILER_EXIT(context->priv->prof_rfx_differential_encode)
254
0
  PROFILER_ENTER(context->priv->prof_rfx_rlgr_encode)
255
0
  *size = context->rlgr_encode(context->mode, data, 4096, buffer, buffer_size);
256
0
  PROFILER_EXIT(context->priv->prof_rfx_rlgr_encode)
257
0
  PROFILER_EXIT(context->priv->prof_rfx_encode_component)
258
0
  BufferPool_Return(context->priv->BufferPool, dwt_buffer);
259
0
}
260
261
void rfx_encode_rgb(RFX_CONTEXT* WINPR_RESTRICT context, RFX_TILE* WINPR_RESTRICT tile)
262
0
{
263
0
  union
264
0
  {
265
0
    const INT16** cpv;
266
0
    INT16** pv;
267
0
  } cnv;
268
0
  BYTE* pBuffer = NULL;
269
0
  INT16* pSrcDst[3];
270
0
  int YLen = 0;
271
0
  int CbLen = 0;
272
0
  int CrLen = 0;
273
0
  UINT32* YQuant = NULL;
274
0
  UINT32* CbQuant = NULL;
275
0
  UINT32* CrQuant = NULL;
276
0
  primitives_t* prims = primitives_get();
277
0
  static const prim_size_t roi_64x64 = { 64, 64 };
278
279
0
  if (!(pBuffer = (BYTE*)BufferPool_Take(context->priv->BufferPool, -1)))
280
0
    return;
281
282
0
  YLen = CbLen = CrLen = 0;
283
0
  YQuant = context->quants + (10ULL * tile->quantIdxY);
284
0
  CbQuant = context->quants + (10ULL * tile->quantIdxCb);
285
0
  CrQuant = context->quants + (10ULL * tile->quantIdxCr);
286
0
  pSrcDst[0] = (INT16*)((&pBuffer[((8192ULL + 32ULL) * 0ULL) + 16ULL])); /* y_r_buffer */
287
0
  pSrcDst[1] = (INT16*)((&pBuffer[((8192ULL + 32ULL) * 1ULL) + 16ULL])); /* cb_g_buffer */
288
0
  pSrcDst[2] = (INT16*)((&pBuffer[((8192ULL + 32ULL) * 2ULL) + 16ULL])); /* cr_b_buffer */
289
0
  PROFILER_ENTER(context->priv->prof_rfx_encode_rgb)
290
0
  PROFILER_ENTER(context->priv->prof_rfx_encode_format_rgb)
291
0
  rfx_encode_format_rgb(tile->data, tile->width, tile->height, tile->scanline,
292
0
                        context->pixel_format, context->palette, pSrcDst[0], pSrcDst[1],
293
0
                        pSrcDst[2]);
294
0
  PROFILER_EXIT(context->priv->prof_rfx_encode_format_rgb)
295
0
  PROFILER_ENTER(context->priv->prof_rfx_rgb_to_ycbcr)
296
297
0
  cnv.pv = pSrcDst;
298
0
  prims->RGBToYCbCr_16s16s_P3P3(cnv.cpv, 64 * sizeof(INT16), pSrcDst, 64 * sizeof(INT16),
299
0
                                &roi_64x64);
300
0
  PROFILER_EXIT(context->priv->prof_rfx_rgb_to_ycbcr)
301
  /**
302
   * We need to clear the buffers as the RLGR encoder expects it to be initialized to zero.
303
   * This allows simplifying and improving the performance of the encoding process.
304
   */
305
0
  ZeroMemory(tile->YData, 4096);
306
0
  ZeroMemory(tile->CbData, 4096);
307
0
  ZeroMemory(tile->CrData, 4096);
308
0
  rfx_encode_component(context, YQuant, pSrcDst[0], tile->YData, 4096, &YLen);
309
0
  rfx_encode_component(context, CbQuant, pSrcDst[1], tile->CbData, 4096, &CbLen);
310
0
  rfx_encode_component(context, CrQuant, pSrcDst[2], tile->CrData, 4096, &CrLen);
311
0
  tile->YLen = (UINT16)YLen;
312
0
  tile->CbLen = (UINT16)CbLen;
313
0
  tile->CrLen = (UINT16)CrLen;
314
0
  PROFILER_EXIT(context->priv->prof_rfx_encode_rgb)
315
0
  BufferPool_Return(context->priv->BufferPool, pBuffer);
316
0
}