FreeRDP
Loading...
Searching...
No Matches
rdpgfx_codec.c
1
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#define TAG CHANNELS_TAG("rdpgfx.client")
34
40static UINT rdpgfx_read_h264_metablock(WINPR_ATTR_UNUSED RDPGFX_PLUGIN* gfx, wStream* s,
42{
43 RECTANGLE_16* regionRect = NULL;
44 RDPGFX_H264_QUANT_QUALITY* quantQualityVal = NULL;
45 UINT error = ERROR_INVALID_DATA;
46 meta->regionRects = NULL;
47 meta->quantQualityVals = NULL;
48
49 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
50 goto error_out;
51
52 Stream_Read_UINT32(s, meta->numRegionRects); /* numRegionRects (4 bytes) */
53
54 if (!Stream_CheckAndLogRequiredLengthOfSize(TAG, s, meta->numRegionRects, 8ull))
55 goto error_out;
56
57 meta->regionRects = (RECTANGLE_16*)calloc(meta->numRegionRects, sizeof(RECTANGLE_16));
58
59 if (!meta->regionRects)
60 {
61 WLog_ERR(TAG, "malloc failed!");
62 error = CHANNEL_RC_NO_MEMORY;
63 goto error_out;
64 }
65
66 meta->quantQualityVals =
67 (RDPGFX_H264_QUANT_QUALITY*)calloc(meta->numRegionRects, sizeof(RDPGFX_H264_QUANT_QUALITY));
68
69 if (!meta->quantQualityVals)
70 {
71 WLog_ERR(TAG, "malloc failed!");
72 error = CHANNEL_RC_NO_MEMORY;
73 goto error_out;
74 }
75
76 WLog_DBG(TAG, "H264_METABLOCK: numRegionRects: %" PRIu32 "", meta->numRegionRects);
77
78 for (UINT32 index = 0; index < meta->numRegionRects; index++)
79 {
80 regionRect = &(meta->regionRects[index]);
81
82 if ((error = rdpgfx_read_rect16(s, regionRect)))
83 {
84 WLog_ERR(TAG, "rdpgfx_read_rect16 failed with error %" PRIu32 "!", error);
85 goto error_out;
86 }
87
88 WLog_DBG(TAG,
89 "regionRects[%" PRIu32 "]: left: %" PRIu16 " top: %" PRIu16 " right: %" PRIu16
90 " bottom: %" PRIu16 "",
91 index, regionRect->left, regionRect->top, regionRect->right, regionRect->bottom);
92 }
93
94 if (!Stream_CheckAndLogRequiredLengthOfSize(TAG, s, meta->numRegionRects, 2ull))
95 {
96 error = ERROR_INVALID_DATA;
97 goto error_out;
98 }
99
100 for (UINT32 index = 0; index < meta->numRegionRects; index++)
101 {
102 quantQualityVal = &(meta->quantQualityVals[index]);
103 Stream_Read_UINT8(s, quantQualityVal->qpVal); /* qpVal (1 byte) */
104 Stream_Read_UINT8(s, quantQualityVal->qualityVal); /* qualityVal (1 byte) */
105 quantQualityVal->qp = quantQualityVal->qpVal & 0x3F;
106 quantQualityVal->r = (quantQualityVal->qpVal >> 6) & 1;
107 quantQualityVal->p = (quantQualityVal->qpVal >> 7) & 1;
108 WLog_DBG(TAG,
109 "quantQualityVals[%" PRIu32 "]: qp: %" PRIu8 " r: %" PRIu8 " p: %" PRIu8
110 " qualityVal: %" PRIu8 "",
111 index, quantQualityVal->qp, quantQualityVal->r, quantQualityVal->p,
112 quantQualityVal->qualityVal);
113 }
114
115 return CHANNEL_RC_OK;
116error_out:
117 free_h264_metablock(meta);
118 return error;
119}
120
126static UINT rdpgfx_decode_AVC420(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd)
127{
128 UINT error = 0;
129 RDPGFX_AVC420_BITMAP_STREAM h264 = { 0 };
130 RdpgfxClientContext* context = gfx->context;
131 wStream* s = Stream_New(cmd->data, cmd->length);
132
133 if (!s)
134 {
135 WLog_ERR(TAG, "Stream_New failed!");
136 return CHANNEL_RC_NO_MEMORY;
137 }
138
139 if ((error = rdpgfx_read_h264_metablock(gfx, s, &(h264.meta))))
140 {
141 Stream_Free(s, FALSE);
142 WLog_ERR(TAG, "rdpgfx_read_h264_metablock failed with error %" PRIu32 "!", error);
143 return error;
144 }
145
146 h264.data = Stream_Pointer(s);
147 h264.length = (UINT32)Stream_GetRemainingLength(s);
148 Stream_Free(s, FALSE);
149 cmd->extra = (void*)&h264;
150
151 if (context)
152 {
153 IFCALLRET(context->SurfaceCommand, error, context, cmd);
154
155 if (error)
156 WLog_ERR(TAG, "context->SurfaceCommand failed with error %" PRIu32 "", error);
157 }
158
159 free_h264_metablock(&h264.meta);
160 cmd->extra = NULL;
161 return error;
162}
163
169static UINT rdpgfx_decode_AVC444(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd)
170{
171 UINT error = 0;
172 UINT32 tmp = 0;
173 size_t pos1 = 0;
174 size_t pos2 = 0;
175
176 RDPGFX_AVC444_BITMAP_STREAM h264 = { 0 };
177 RdpgfxClientContext* context = gfx->context;
178 wStream* s = Stream_New(cmd->data, cmd->length);
179
180 if (!s)
181 {
182 WLog_ERR(TAG, "Stream_New failed!");
183 return CHANNEL_RC_NO_MEMORY;
184 }
185
186 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
187 {
188 error = ERROR_INVALID_DATA;
189 goto fail;
190 }
191
192 Stream_Read_UINT32(s, tmp);
193 h264.cbAvc420EncodedBitstream1 = tmp & 0x3FFFFFFFUL;
194 h264.LC = (tmp >> 30UL) & 0x03UL;
195
196 if (h264.LC == 0x03)
197 {
198 error = ERROR_INVALID_DATA;
199 goto fail;
200 }
201
202 pos1 = Stream_GetPosition(s);
203
204 if ((error = rdpgfx_read_h264_metablock(gfx, s, &(h264.bitstream[0].meta))))
205 {
206 WLog_ERR(TAG, "rdpgfx_read_h264_metablock failed with error %" PRIu32 "!", error);
207 goto fail;
208 }
209
210 pos2 = Stream_GetPosition(s);
211 h264.bitstream[0].data = Stream_Pointer(s);
212
213 if (h264.LC == 0)
214 {
215 const size_t bitstreamLen = 1ULL * h264.cbAvc420EncodedBitstream1 - pos2 + pos1;
216
217 if ((bitstreamLen > UINT32_MAX) || !Stream_CheckAndLogRequiredLength(TAG, s, bitstreamLen))
218 {
219 error = ERROR_INVALID_DATA;
220 goto fail;
221 }
222
223 h264.bitstream[0].length = (UINT32)bitstreamLen;
224 Stream_Seek(s, bitstreamLen);
225
226 if ((error = rdpgfx_read_h264_metablock(gfx, s, &(h264.bitstream[1].meta))))
227 {
228 WLog_ERR(TAG, "rdpgfx_read_h264_metablock failed with error %" PRIu32 "!", error);
229 goto fail;
230 }
231
232 h264.bitstream[1].data = Stream_Pointer(s);
233
234 const size_t len = Stream_GetRemainingLength(s);
235 if (len > UINT32_MAX)
236 goto fail;
237 h264.bitstream[1].length = (UINT32)len;
238 }
239 else
240 {
241 const size_t len = Stream_GetRemainingLength(s);
242 if (len > UINT32_MAX)
243 goto fail;
244 h264.bitstream[0].length = (UINT32)len;
245 }
246
247 cmd->extra = (void*)&h264;
248
249 if (context)
250 {
251 IFCALLRET(context->SurfaceCommand, error, context, cmd);
252
253 if (error)
254 WLog_ERR(TAG, "context->SurfaceCommand failed with error %" PRIu32 "", error);
255 }
256
257fail:
258 Stream_Free(s, FALSE);
259 free_h264_metablock(&h264.bitstream[0].meta);
260 free_h264_metablock(&h264.bitstream[1].meta);
261 cmd->extra = NULL;
262 return error;
263}
264
270UINT rdpgfx_decode(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd)
271{
272 UINT error = CHANNEL_RC_OK;
273 RdpgfxClientContext* context = gfx->context;
274 PROFILER_ENTER(context->SurfaceProfiler)
275
276 switch (cmd->codecId)
277 {
278 case RDPGFX_CODECID_AVC420:
279 if ((error = rdpgfx_decode_AVC420(gfx, cmd)))
280 WLog_ERR(TAG, "rdpgfx_decode_AVC420 failed with error %" PRIu32 "", error);
281
282 break;
283
284 case RDPGFX_CODECID_AVC444:
285 case RDPGFX_CODECID_AVC444v2:
286 if ((error = rdpgfx_decode_AVC444(gfx, cmd)))
287 WLog_ERR(TAG, "rdpgfx_decode_AVC444 failed with error %" PRIu32 "", error);
288
289 break;
290
291 default:
292 if (context)
293 {
294 IFCALLRET(context->SurfaceCommand, error, context, cmd);
295
296 if (error)
297 WLog_ERR(TAG, "context->SurfaceCommand failed with error %" PRIu32 "", error);
298 }
299
300 break;
301 }
302
303 PROFILER_EXIT(context->SurfaceProfiler)
304 return error;
305}