Coverage Report

Created: 2026-10-15 06:31

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/FreeRDP/channels/rdpgfx/client/rdpgfx_codec.c
Line
Count
Source
1
/**
2
 * FreeRDP: A Remote Desktop Protocol Implementation
3
 * Graphics Pipeline Extension
4
 *
5
 * Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6
 * Copyright 2015 Thincast Technologies GmbH
7
 * Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
8
 *
9
 * Licensed under the Apache License, Version 2.0 (the "License");
10
 * you may not use this file except in compliance with the License.
11
 * You may obtain a copy of the License at
12
 *
13
 *     http://www.apache.org/licenses/LICENSE-2.0
14
 *
15
 * Unless required by applicable law or agreed to in writing, software
16
 * distributed under the License is distributed on an "AS IS" BASIS,
17
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18
 * See the License for the specific language governing permissions and
19
 * limitations under the License.
20
 */
21
22
#include <freerdp/config.h>
23
24
#include <winpr/crt.h>
25
#include <winpr/stream.h>
26
#include <freerdp/log.h>
27
#include <freerdp/utils/profiler.h>
28
29
#include "rdpgfx_common.h"
30
31
#include "rdpgfx_codec.h"
32
33
/**
34
 * Function description
35
 *
36
 * @return 0 on success, otherwise a Win32 error code
37
 */
38
static UINT rdpgfx_read_h264_metablock(WINPR_ATTR_UNUSED RDPGFX_PLUGIN* gfx, wStream* s,
39
                                       RDPGFX_H264_METABLOCK* meta)
40
1.17k
{
41
1.17k
  RECTANGLE_16* regionRect = nullptr;
42
1.17k
  RDPGFX_H264_QUANT_QUALITY* quantQualityVal = nullptr;
43
1.17k
  UINT error = ERROR_INVALID_DATA;
44
1.17k
  meta->regionRects = nullptr;
45
1.17k
  meta->quantQualityVals = nullptr;
46
47
1.17k
  if (!Stream_CheckAndLogRequiredLengthWLog(gfx->base.log, s, 4))
48
6
    goto error_out;
49
50
1.16k
  Stream_Read_UINT32(s, meta->numRegionRects); /* numRegionRects (4 bytes) */
51
52
1.16k
  if (!Stream_CheckAndLogRequiredLengthOfSizeWLog(gfx->base.log, s, meta->numRegionRects, 8ull))
53
27
    goto error_out;
54
55
1.14k
  meta->regionRects = (RECTANGLE_16*)calloc(meta->numRegionRects, sizeof(RECTANGLE_16));
56
57
1.14k
  if (!meta->regionRects)
58
0
  {
59
0
    WLog_Print(gfx->base.log, WLOG_ERROR, "malloc failed!");
60
0
    error = CHANNEL_RC_NO_MEMORY;
61
0
    goto error_out;
62
0
  }
63
64
1.14k
  meta->quantQualityVals =
65
1.14k
      (RDPGFX_H264_QUANT_QUALITY*)calloc(meta->numRegionRects, sizeof(RDPGFX_H264_QUANT_QUALITY));
66
67
1.14k
  if (!meta->quantQualityVals)
68
0
  {
69
0
    WLog_Print(gfx->base.log, WLOG_ERROR, "malloc failed!");
70
0
    error = CHANNEL_RC_NO_MEMORY;
71
0
    goto error_out;
72
0
  }
73
74
1.14k
  WLog_Print(gfx->base.log, WLOG_TRACE, "H264_METABLOCK: numRegionRects: %" PRIu32 "",
75
1.14k
             meta->numRegionRects);
76
77
1.20k
  for (UINT32 index = 0; index < meta->numRegionRects; index++)
78
76
  {
79
76
    regionRect = &(meta->regionRects[index]);
80
81
76
    if ((error = rdpgfx_read_rect16(gfx->base.log, s, regionRect)))
82
10
    {
83
10
      WLog_Print(gfx->base.log, WLOG_ERROR,
84
10
                 "rdpgfx_read_rect16 failed with error %" PRIu32 "!", error);
85
10
      goto error_out;
86
10
    }
87
88
66
    WLog_Print(gfx->base.log, WLOG_TRACE,
89
66
               "regionRects[%" PRIu32 "]: left: %" PRIu16 " top: %" PRIu16 " right: %" PRIu16
90
66
               " bottom: %" PRIu16 "",
91
66
               index, regionRect->left, regionRect->top, regionRect->right, regionRect->bottom);
92
66
  }
93
94
1.13k
  if (!Stream_CheckAndLogRequiredLengthOfSizeWLog(gfx->base.log, s, meta->numRegionRects, 2ull))
95
3
  {
96
3
    error = ERROR_INVALID_DATA;
97
3
    goto error_out;
98
3
  }
99
100
1.18k
  for (UINT32 index = 0; index < meta->numRegionRects; index++)
101
53
  {
102
53
    quantQualityVal = &(meta->quantQualityVals[index]);
103
53
    Stream_Read_UINT8(s, quantQualityVal->qpVal);      /* qpVal (1 byte) */
104
53
    Stream_Read_UINT8(s, quantQualityVal->qualityVal); /* qualityVal (1 byte) */
105
53
    quantQualityVal->qp = quantQualityVal->qpVal & 0x3F;
106
53
    quantQualityVal->r = (quantQualityVal->qpVal >> 6) & 1;
107
53
    quantQualityVal->p = (quantQualityVal->qpVal >> 7) & 1;
108
53
    WLog_Print(gfx->base.log, WLOG_TRACE,
109
53
               "quantQualityVals[%" PRIu32 "]: qp: %" PRIu8 " r: %" PRIu8 " p: %" PRIu8
110
53
               " qualityVal: %" PRIu8 "",
111
53
               index, quantQualityVal->qp, quantQualityVal->r, quantQualityVal->p,
112
53
               quantQualityVal->qualityVal);
113
53
  }
114
115
1.12k
  return CHANNEL_RC_OK;
116
46
error_out:
117
46
  free_h264_metablock(meta);
118
46
  return error;
119
1.13k
}
120
121
/**
122
 * Function description
123
 *
124
 * @return 0 on success, otherwise a Win32 error code
125
 */
126
static UINT rdpgfx_decode_AVC420(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd)
127
11
{
128
11
  RDPGFX_AVC420_BITMAP_STREAM h264 = WINPR_C_ARRAY_INIT;
129
11
  wStream* s = Stream_New(cmd->data, cmd->length);
130
131
11
  if (!s)
132
0
  {
133
0
    WLog_Print(gfx->base.log, WLOG_ERROR, "Stream_New failed!");
134
0
    return CHANNEL_RC_NO_MEMORY;
135
0
  }
136
137
11
  UINT error = rdpgfx_read_h264_metablock(gfx, s, &(h264.meta));
138
11
  if (error != CHANNEL_RC_OK)
139
7
  {
140
7
    Stream_Free(s, FALSE);
141
7
    WLog_Print(gfx->base.log, WLOG_ERROR,
142
7
               "rdpgfx_read_h264_metablock failed with error %" PRIu32 "!", error);
143
7
    return error;
144
7
  }
145
146
4
  h264.data = Stream_Pointer(s);
147
4
  h264.length = (UINT32)Stream_GetRemainingLength(s);
148
4
  Stream_Free(s, FALSE);
149
4
  cmd->extra = (void*)&h264;
150
151
4
  error = logSurfaceCommand(gfx, cmd);
152
153
4
  free_h264_metablock(&h264.meta);
154
4
  cmd->extra = nullptr;
155
4
  return error;
156
11
}
157
158
/**
159
 * Function description
160
 *
161
 * @return 0 on success, otherwise a Win32 error code
162
 */
163
static UINT rdpgfx_decode_AVC444(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd)
164
1.14k
{
165
1.14k
  UINT error = CHANNEL_RC_OK;
166
1.14k
  UINT32 tmp = 0;
167
1.14k
  size_t pos1 = 0;
168
1.14k
  size_t pos2 = 0;
169
170
1.14k
  RDPGFX_AVC444_BITMAP_STREAM h264 = WINPR_C_ARRAY_INIT;
171
1.14k
  wStream* s = Stream_New(cmd->data, cmd->length);
172
173
1.14k
  if (!s)
174
0
  {
175
0
    WLog_Print(gfx->base.log, WLOG_ERROR, "Stream_New failed!");
176
0
    return CHANNEL_RC_NO_MEMORY;
177
0
  }
178
179
1.14k
  if (!Stream_CheckAndLogRequiredLengthWLog(gfx->base.log, s, 4))
180
3
  {
181
3
    error = ERROR_INVALID_DATA;
182
3
    goto fail;
183
3
  }
184
185
1.13k
  Stream_Read_UINT32(s, tmp);
186
1.13k
  h264.cbAvc420EncodedBitstream1 = tmp & 0x3FFFFFFFUL;
187
1.13k
  h264.LC = (tmp >> 30UL) & 0x03UL;
188
189
1.13k
  if (h264.LC == 0x03)
190
3
  {
191
3
    error = ERROR_INVALID_DATA;
192
3
    goto fail;
193
3
  }
194
195
1.13k
  pos1 = Stream_GetPosition(s);
196
197
1.13k
  if ((error = rdpgfx_read_h264_metablock(gfx, s, &(h264.bitstream[0].meta))))
198
20
  {
199
20
    WLog_Print(gfx->base.log, WLOG_ERROR,
200
20
               "rdpgfx_read_h264_metablock failed with error %" PRIu32 "!", error);
201
20
    goto fail;
202
20
  }
203
204
1.11k
  pos2 = Stream_GetPosition(s);
205
1.11k
  h264.bitstream[0].data = Stream_Pointer(s);
206
207
1.11k
  if (h264.LC == 0)
208
74
  {
209
74
    const size_t bitstreamLen = 1ULL * h264.cbAvc420EncodedBitstream1 - pos2 + pos1;
210
211
74
    if ((bitstreamLen > UINT32_MAX) || (h264.cbAvc420EncodedBitstream1 < pos2 - pos1) ||
212
67
        !Stream_CheckAndLogRequiredLengthWLog(gfx->base.log, s, bitstreamLen))
213
46
    {
214
46
      error = ERROR_INVALID_DATA;
215
46
      goto fail;
216
46
    }
217
218
28
    h264.bitstream[0].length = (UINT32)bitstreamLen;
219
28
    Stream_Seek(s, bitstreamLen);
220
221
28
    if ((error = rdpgfx_read_h264_metablock(gfx, s, &(h264.bitstream[1].meta))))
222
19
    {
223
19
      WLog_Print(gfx->base.log, WLOG_ERROR,
224
19
                 "rdpgfx_read_h264_metablock failed with error %" PRIu32 "!", error);
225
19
      goto fail;
226
19
    }
227
228
9
    h264.bitstream[1].data = Stream_Pointer(s);
229
230
9
    const size_t len = Stream_GetRemainingLength(s);
231
9
    if (len > UINT32_MAX)
232
0
      goto fail;
233
9
    h264.bitstream[1].length = (UINT32)len;
234
9
  }
235
1.04k
  else
236
1.04k
  {
237
1.04k
    const size_t len = Stream_GetRemainingLength(s);
238
1.04k
    if (len > UINT32_MAX)
239
0
      goto fail;
240
1.04k
    h264.bitstream[0].length = (UINT32)len;
241
1.04k
  }
242
243
1.05k
  cmd->extra = (void*)&h264;
244
245
1.05k
  error = logSurfaceCommand(gfx, cmd);
246
247
1.14k
fail:
248
1.14k
  Stream_Free(s, FALSE);
249
1.14k
  free_h264_metablock(&h264.bitstream[0].meta);
250
1.14k
  free_h264_metablock(&h264.bitstream[1].meta);
251
1.14k
  cmd->extra = nullptr;
252
1.14k
  return error;
253
1.05k
}
254
255
/**
256
 * Function description
257
 *
258
 * @return 0 on success, otherwise a Win32 error code
259
 */
260
UINT rdpgfx_decode(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd)
261
1.26k
{
262
1.26k
  UINT error = CHANNEL_RC_OK;
263
1.26k
  WINPR_ASSERT(gfx);
264
1.26k
  WINPR_ASSERT(cmd);
265
266
1.26k
  PROFILER_ENTER(gfx->context->SurfaceProfiler)
267
268
1.26k
  switch (cmd->codecId)
269
1.26k
  {
270
#if defined(WITH_GFX_AV1)
271
    case RDPGFX_CODECID_AV1:
272
#endif
273
11
    case RDPGFX_CODECID_AVC420:
274
11
      if ((error = rdpgfx_decode_AVC420(gfx, cmd)))
275
7
        WLog_Print(gfx->base.log, WLOG_ERROR,
276
11
                   "rdpgfx_decode_AVC420 failed with error %" PRIu32 "", error);
277
278
11
      break;
279
280
1.06k
    case RDPGFX_CODECID_AVC444:
281
1.14k
    case RDPGFX_CODECID_AVC444v2:
282
1.14k
      if ((error = rdpgfx_decode_AVC444(gfx, cmd)))
283
91
        WLog_Print(gfx->base.log, WLOG_ERROR,
284
1.14k
                   "rdpgfx_decode_AVC444 failed with error %" PRIu32 "", error);
285
286
1.14k
      break;
287
288
117
    default:
289
117
      error = logSurfaceCommand(gfx, cmd);
290
117
      break;
291
1.26k
  }
292
293
1.26k
  PROFILER_EXIT(gfx->context->SurfaceProfiler)
294
1.26k
  return error;
295
1.26k
}