Coverage Report

Created: 2024-05-20 06:11

/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* rgb_data, int width, int height, int rowstride,
43
                                  UINT32 pixel_format, const BYTE* palette, INT16* r_buf,
44
                                  INT16* g_buf, INT16* b_buf)
45
0
{
46
0
  int x_exceed = 0;
47
0
  int y_exceed = 0;
48
0
  const BYTE* src = NULL;
49
0
  INT16 r = 0;
50
0
  INT16 g = 0;
51
0
  INT16 b = 0;
52
0
  INT16* r_last = NULL;
53
0
  INT16* g_last = NULL;
54
0
  INT16* b_last = NULL;
55
0
  x_exceed = 64 - width;
56
0
  y_exceed = 64 - height;
57
58
0
  for (int y = 0; y < height; y++)
59
0
  {
60
0
    src = rgb_data + y * rowstride;
61
62
0
    switch (pixel_format)
63
0
    {
64
0
      case PIXEL_FORMAT_BGRX32:
65
0
      case PIXEL_FORMAT_BGRA32:
66
0
        for (int x = 0; x < width; x++)
67
0
        {
68
0
          *b_buf++ = (INT16)(*src++);
69
0
          *g_buf++ = (INT16)(*src++);
70
0
          *r_buf++ = (INT16)(*src++);
71
0
          src++;
72
0
        }
73
74
0
        break;
75
76
0
      case PIXEL_FORMAT_XBGR32:
77
0
      case PIXEL_FORMAT_ABGR32:
78
0
        for (int x = 0; x < width; x++)
79
0
        {
80
0
          src++;
81
0
          *b_buf++ = (INT16)(*src++);
82
0
          *g_buf++ = (INT16)(*src++);
83
0
          *r_buf++ = (INT16)(*src++);
84
0
        }
85
86
0
        break;
87
88
0
      case PIXEL_FORMAT_RGBX32:
89
0
      case PIXEL_FORMAT_RGBA32:
90
0
        for (int x = 0; x < width; x++)
91
0
        {
92
0
          *r_buf++ = (INT16)(*src++);
93
0
          *g_buf++ = (INT16)(*src++);
94
0
          *b_buf++ = (INT16)(*src++);
95
0
          src++;
96
0
        }
97
98
0
        break;
99
100
0
      case PIXEL_FORMAT_XRGB32:
101
0
      case PIXEL_FORMAT_ARGB32:
102
0
        for (int x = 0; x < width; x++)
103
0
        {
104
0
          src++;
105
0
          *r_buf++ = (INT16)(*src++);
106
0
          *g_buf++ = (INT16)(*src++);
107
0
          *b_buf++ = (INT16)(*src++);
108
0
        }
109
110
0
        break;
111
112
0
      case PIXEL_FORMAT_BGR24:
113
0
        for (int x = 0; x < width; x++)
114
0
        {
115
0
          *b_buf++ = (INT16)(*src++);
116
0
          *g_buf++ = (INT16)(*src++);
117
0
          *r_buf++ = (INT16)(*src++);
118
0
        }
119
120
0
        break;
121
122
0
      case PIXEL_FORMAT_RGB24:
123
0
        for (int x = 0; x < width; x++)
124
0
        {
125
0
          *r_buf++ = (INT16)(*src++);
126
0
          *g_buf++ = (INT16)(*src++);
127
0
          *b_buf++ = (INT16)(*src++);
128
0
        }
129
130
0
        break;
131
132
0
      case PIXEL_FORMAT_BGR16:
133
0
        for (int x = 0; x < width; x++)
134
0
        {
135
0
          *b_buf++ = (INT16)(((*(src + 1)) & 0xF8) | ((*(src + 1)) >> 5));
136
0
          *g_buf++ = (INT16)((((*(src + 1)) & 0x07) << 5) | (((*src) & 0xE0) >> 3));
137
0
          *r_buf++ = (INT16)((((*src) & 0x1F) << 3) | (((*src) >> 2) & 0x07));
138
0
          src += 2;
139
0
        }
140
141
0
        break;
142
143
0
      case PIXEL_FORMAT_RGB16:
144
0
        for (int x = 0; x < width; x++)
145
0
        {
146
0
          *r_buf++ = (INT16)(((*(src + 1)) & 0xF8) | ((*(src + 1)) >> 5));
147
0
          *g_buf++ = (INT16)((((*(src + 1)) & 0x07) << 5) | (((*src) & 0xE0) >> 3));
148
0
          *b_buf++ = (INT16)((((*src) & 0x1F) << 3) | (((*src) >> 2) & 0x07));
149
0
          src += 2;
150
0
        }
151
152
0
        break;
153
154
0
      case PIXEL_FORMAT_RGB8:
155
0
        if (!palette)
156
0
          break;
157
158
0
        for (int x = 0; x < width; x++)
159
0
        {
160
0
          int shift = 0;
161
0
          BYTE idx = 0;
162
0
          shift = (7 - (x % 8));
163
0
          idx = ((*src) >> shift) & 1;
164
0
          idx |= (((*(src + 1)) >> shift) & 1) << 1;
165
0
          idx |= (((*(src + 2)) >> shift) & 1) << 2;
166
0
          idx |= (((*(src + 3)) >> shift) & 1) << 3;
167
0
          idx *= 3;
168
0
          *r_buf++ = (INT16)palette[idx];
169
0
          *g_buf++ = (INT16)palette[idx + 1];
170
0
          *b_buf++ = (INT16)palette[idx + 2];
171
172
0
          if (shift == 0)
173
0
            src += 4;
174
0
        }
175
176
0
        break;
177
178
0
      case PIXEL_FORMAT_A4:
179
0
        if (!palette)
180
0
          break;
181
182
0
        for (int x = 0; x < width; x++)
183
0
        {
184
0
          int idx = (*src) * 3;
185
0
          *r_buf++ = (INT16)palette[idx];
186
0
          *g_buf++ = (INT16)palette[idx + 1];
187
0
          *b_buf++ = (INT16)palette[idx + 2];
188
0
          src++;
189
0
        }
190
191
0
        break;
192
193
0
      default:
194
0
        break;
195
0
    }
196
197
    /* Fill the horizontal region outside of 64x64 tile size with the right-most pixel for best
198
     * quality */
199
0
    if (x_exceed > 0)
200
0
    {
201
0
      r = *(r_buf - 1);
202
0
      g = *(g_buf - 1);
203
0
      b = *(b_buf - 1);
204
205
0
      for (int x = 0; x < x_exceed; x++)
206
0
      {
207
0
        *r_buf++ = r;
208
0
        *g_buf++ = g;
209
0
        *b_buf++ = b;
210
0
      }
211
0
    }
212
0
  }
213
214
  /* Fill the vertical region outside of 64x64 tile size with the last line. */
215
0
  if (y_exceed > 0)
216
0
  {
217
0
    r_last = r_buf - 64;
218
0
    g_last = g_buf - 64;
219
0
    b_last = b_buf - 64;
220
221
0
    while (y_exceed > 0)
222
0
    {
223
0
      CopyMemory(r_buf, r_last, 64 * sizeof(INT16));
224
0
      CopyMemory(g_buf, g_last, 64 * sizeof(INT16));
225
0
      CopyMemory(b_buf, b_last, 64 * sizeof(INT16));
226
0
      r_buf += 64;
227
0
      g_buf += 64;
228
0
      b_buf += 64;
229
0
      y_exceed--;
230
0
    }
231
0
  }
232
0
}
233
234
/* rfx_encode_rgb_to_ycbcr code now resides in the primitives library. */
235
236
static void rfx_encode_component(RFX_CONTEXT* context, const UINT32* quantization_values,
237
                                 INT16* data, BYTE* buffer, int buffer_size, int* size)
238
0
{
239
0
  INT16* dwt_buffer = NULL;
240
0
  dwt_buffer = BufferPool_Take(context->priv->BufferPool, -1); /* dwt_buffer */
241
0
  PROFILER_ENTER(context->priv->prof_rfx_encode_component)
242
0
  PROFILER_ENTER(context->priv->prof_rfx_dwt_2d_encode)
243
0
  context->dwt_2d_encode(data, dwt_buffer);
244
0
  PROFILER_EXIT(context->priv->prof_rfx_dwt_2d_encode)
245
0
  PROFILER_ENTER(context->priv->prof_rfx_quantization_encode)
246
0
  context->quantization_encode(data, quantization_values);
247
0
  PROFILER_EXIT(context->priv->prof_rfx_quantization_encode)
248
0
  PROFILER_ENTER(context->priv->prof_rfx_differential_encode)
249
0
  rfx_differential_encode(data + 4032, 64);
250
0
  PROFILER_EXIT(context->priv->prof_rfx_differential_encode)
251
0
  PROFILER_ENTER(context->priv->prof_rfx_rlgr_encode)
252
0
  *size = context->rlgr_encode(context->mode, data, 4096, buffer, buffer_size);
253
0
  PROFILER_EXIT(context->priv->prof_rfx_rlgr_encode)
254
0
  PROFILER_EXIT(context->priv->prof_rfx_encode_component)
255
0
  BufferPool_Return(context->priv->BufferPool, dwt_buffer);
256
0
}
257
258
void rfx_encode_rgb(RFX_CONTEXT* context, RFX_TILE* tile)
259
0
{
260
0
  union
261
0
  {
262
0
    const INT16** cpv;
263
0
    INT16** pv;
264
0
  } cnv;
265
0
  BYTE* pBuffer = NULL;
266
0
  INT16* pSrcDst[3];
267
0
  int YLen = 0;
268
0
  int CbLen = 0;
269
0
  int CrLen = 0;
270
0
  UINT32* YQuant = NULL;
271
0
  UINT32* CbQuant = NULL;
272
0
  UINT32* CrQuant = NULL;
273
0
  primitives_t* prims = primitives_get();
274
0
  static const prim_size_t roi_64x64 = { 64, 64 };
275
276
0
  if (!(pBuffer = (BYTE*)BufferPool_Take(context->priv->BufferPool, -1)))
277
0
    return;
278
279
0
  YLen = CbLen = CrLen = 0;
280
0
  YQuant = context->quants + (tile->quantIdxY * 10);
281
0
  CbQuant = context->quants + (tile->quantIdxCb * 10);
282
0
  CrQuant = context->quants + (tile->quantIdxCr * 10);
283
0
  pSrcDst[0] = (INT16*)((BYTE*)(&pBuffer[((8192 + 32) * 0) + 16])); /* y_r_buffer */
284
0
  pSrcDst[1] = (INT16*)((BYTE*)(&pBuffer[((8192 + 32) * 1) + 16])); /* cb_g_buffer */
285
0
  pSrcDst[2] = (INT16*)((BYTE*)(&pBuffer[((8192 + 32) * 2) + 16])); /* cr_b_buffer */
286
0
  PROFILER_ENTER(context->priv->prof_rfx_encode_rgb)
287
0
  PROFILER_ENTER(context->priv->prof_rfx_encode_format_rgb)
288
0
  rfx_encode_format_rgb(tile->data, tile->width, tile->height, tile->scanline,
289
0
                        context->pixel_format, context->palette, pSrcDst[0], pSrcDst[1],
290
0
                        pSrcDst[2]);
291
0
  PROFILER_EXIT(context->priv->prof_rfx_encode_format_rgb)
292
0
  PROFILER_ENTER(context->priv->prof_rfx_rgb_to_ycbcr)
293
294
0
  cnv.pv = pSrcDst;
295
0
  prims->RGBToYCbCr_16s16s_P3P3(cnv.cpv, 64 * sizeof(INT16), pSrcDst, 64 * sizeof(INT16),
296
0
                                &roi_64x64);
297
0
  PROFILER_EXIT(context->priv->prof_rfx_rgb_to_ycbcr)
298
  /**
299
   * We need to clear the buffers as the RLGR encoder expects it to be initialized to zero.
300
   * This allows simplifying and improving the performance of the encoding process.
301
   */
302
0
  ZeroMemory(tile->YData, 4096);
303
0
  ZeroMemory(tile->CbData, 4096);
304
0
  ZeroMemory(tile->CrData, 4096);
305
0
  rfx_encode_component(context, YQuant, pSrcDst[0], tile->YData, 4096, &YLen);
306
0
  rfx_encode_component(context, CbQuant, pSrcDst[1], tile->CbData, 4096, &CbLen);
307
0
  rfx_encode_component(context, CrQuant, pSrcDst[2], tile->CrData, 4096, &CrLen);
308
0
  tile->YLen = (UINT16)YLen;
309
0
  tile->CbLen = (UINT16)CbLen;
310
0
  tile->CrLen = (UINT16)CrLen;
311
0
  PROFILER_EXIT(context->priv->prof_rfx_encode_rgb)
312
0
  BufferPool_Return(context->priv->BufferPool, pBuffer);
313
0
}