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