Coverage Report

Created: 2023-09-25 06:56

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