1 /**
2 * FreeRDP: A Remote Desktop Protocol Implementation
3 * RemoteFX Codec Library
4 *
5 * Copyright 2011 Vic Lee
6 * Copyright 2015 Thincast Technologies GmbH
7 * Copyright 2015 Norbert Federa <norbert.federa@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 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include <assert.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30
31 #include <winpr/crt.h>
32 #include <winpr/tchar.h>
33 #include <winpr/sysinfo.h>
34 #include <winpr/registry.h>
35 #include <winpr/tchar.h>
36
37 #include <freerdp/log.h>
38 #include <freerdp/codec/rfx.h>
39 #include <freerdp/constants.h>
40 #include <freerdp/primitives.h>
41 #include <freerdp/codec/region.h>
42 #include <freerdp/build-config.h>
43 #include <freerdp/codec/region.h>
44
45 #include "rfx_constants.h"
46 #include "rfx_types.h"
47 #include "rfx_decode.h"
48 #include "rfx_encode.h"
49 #include "rfx_quantization.h"
50 #include "rfx_dwt.h"
51 #include "rfx_rlgr.h"
52
53 #include "rfx_sse2.h"
54 #include "rfx_neon.h"
55
56 #define TAG FREERDP_TAG("codec")
57
58 #ifndef RFX_INIT_SIMD
59 #define RFX_INIT_SIMD(_rfx_context) \
60 do \
61 { \
62 } while (0)
63 #endif
64
65 #define RFX_KEY "Software\\" FREERDP_VENDOR_STRING "\\" FREERDP_PRODUCT_STRING "\\RemoteFX"
66
67 /**
68 * The quantization values control the compression rate and quality. The value
69 * range is between 6 and 15. The higher value, the higher compression rate
70 * and lower quality.
71 *
72 * This is the default values being use by the MS RDP server, and we will also
73 * use it as our default values for the encoder. It can be overrided by setting
74 * the context->num_quants and context->quants member.
75 *
76 * The order of the values are:
77 * LL3, LH3, HL3, HH3, LH2, HL2, HH2, LH1, HL1, HH1
78 */
79 static const UINT32 rfx_default_quantization_values[] = { 6, 6, 6, 6, 7, 7, 8, 8, 8, 9 };
80
rfx_profiler_create(RFX_CONTEXT * context)81 static void rfx_profiler_create(RFX_CONTEXT* context)
82 {
83 PROFILER_CREATE(context->priv->prof_rfx_decode_rgb, "rfx_decode_rgb")
84 PROFILER_CREATE(context->priv->prof_rfx_decode_component, "rfx_decode_component")
85 PROFILER_CREATE(context->priv->prof_rfx_rlgr_decode, "rfx_rlgr_decode")
86 PROFILER_CREATE(context->priv->prof_rfx_differential_decode, "rfx_differential_decode")
87 PROFILER_CREATE(context->priv->prof_rfx_quantization_decode, "rfx_quantization_decode")
88 PROFILER_CREATE(context->priv->prof_rfx_dwt_2d_decode, "rfx_dwt_2d_decode")
89 PROFILER_CREATE(context->priv->prof_rfx_ycbcr_to_rgb, "prims->yCbCrToRGB")
90 PROFILER_CREATE(context->priv->prof_rfx_encode_rgb, "rfx_encode_rgb")
91 PROFILER_CREATE(context->priv->prof_rfx_encode_component, "rfx_encode_component")
92 PROFILER_CREATE(context->priv->prof_rfx_rlgr_encode, "rfx_rlgr_encode")
93 PROFILER_CREATE(context->priv->prof_rfx_differential_encode, "rfx_differential_encode")
94 PROFILER_CREATE(context->priv->prof_rfx_quantization_encode, "rfx_quantization_encode")
95 PROFILER_CREATE(context->priv->prof_rfx_dwt_2d_encode, "rfx_dwt_2d_encode")
96 PROFILER_CREATE(context->priv->prof_rfx_rgb_to_ycbcr, "prims->RGBToYCbCr")
97 PROFILER_CREATE(context->priv->prof_rfx_encode_format_rgb, "rfx_encode_format_rgb")
98 }
99
rfx_profiler_free(RFX_CONTEXT * context)100 static void rfx_profiler_free(RFX_CONTEXT* context)
101 {
102 PROFILER_FREE(context->priv->prof_rfx_decode_rgb)
103 PROFILER_FREE(context->priv->prof_rfx_decode_component)
104 PROFILER_FREE(context->priv->prof_rfx_rlgr_decode)
105 PROFILER_FREE(context->priv->prof_rfx_differential_decode)
106 PROFILER_FREE(context->priv->prof_rfx_quantization_decode)
107 PROFILER_FREE(context->priv->prof_rfx_dwt_2d_decode)
108 PROFILER_FREE(context->priv->prof_rfx_ycbcr_to_rgb)
109 PROFILER_FREE(context->priv->prof_rfx_encode_rgb)
110 PROFILER_FREE(context->priv->prof_rfx_encode_component)
111 PROFILER_FREE(context->priv->prof_rfx_rlgr_encode)
112 PROFILER_FREE(context->priv->prof_rfx_differential_encode)
113 PROFILER_FREE(context->priv->prof_rfx_quantization_encode)
114 PROFILER_FREE(context->priv->prof_rfx_dwt_2d_encode)
115 PROFILER_FREE(context->priv->prof_rfx_rgb_to_ycbcr)
116 PROFILER_FREE(context->priv->prof_rfx_encode_format_rgb)
117 }
118
rfx_profiler_print(RFX_CONTEXT * context)119 static void rfx_profiler_print(RFX_CONTEXT* context)
120 {
121 PROFILER_PRINT_HEADER
122 PROFILER_PRINT(context->priv->prof_rfx_decode_rgb)
123 PROFILER_PRINT(context->priv->prof_rfx_decode_component)
124 PROFILER_PRINT(context->priv->prof_rfx_rlgr_decode)
125 PROFILER_PRINT(context->priv->prof_rfx_differential_decode)
126 PROFILER_PRINT(context->priv->prof_rfx_quantization_decode)
127 PROFILER_PRINT(context->priv->prof_rfx_dwt_2d_decode)
128 PROFILER_PRINT(context->priv->prof_rfx_ycbcr_to_rgb)
129 PROFILER_PRINT(context->priv->prof_rfx_encode_rgb)
130 PROFILER_PRINT(context->priv->prof_rfx_encode_component)
131 PROFILER_PRINT(context->priv->prof_rfx_rlgr_encode)
132 PROFILER_PRINT(context->priv->prof_rfx_differential_encode)
133 PROFILER_PRINT(context->priv->prof_rfx_quantization_encode)
134 PROFILER_PRINT(context->priv->prof_rfx_dwt_2d_encode)
135 PROFILER_PRINT(context->priv->prof_rfx_rgb_to_ycbcr)
136 PROFILER_PRINT(context->priv->prof_rfx_encode_format_rgb)
137 PROFILER_PRINT_FOOTER
138 }
139
rfx_tile_init(void * obj)140 static void rfx_tile_init(void* obj)
141 {
142 RFX_TILE* tile = (RFX_TILE*)obj;
143 if (tile)
144 {
145 tile->x = 0;
146 tile->y = 0;
147 tile->YLen = 0;
148 tile->YData = NULL;
149 tile->CbLen = 0;
150 tile->CbData = NULL;
151 tile->CrLen = 0;
152 tile->CrData = NULL;
153 }
154 }
155
rfx_decoder_tile_new(void * val)156 static void* rfx_decoder_tile_new(void* val)
157 {
158 RFX_TILE* tile = NULL;
159 WINPR_UNUSED(val);
160
161 if (!(tile = (RFX_TILE*)calloc(1, sizeof(RFX_TILE))))
162 return NULL;
163
164 if (!(tile->data = (BYTE*)_aligned_malloc(4 * 64 * 64, 16)))
165 {
166 free(tile);
167 return NULL;
168 }
169
170 tile->allocated = TRUE;
171 return tile;
172 }
173
rfx_decoder_tile_free(void * obj)174 static void rfx_decoder_tile_free(void* obj)
175 {
176 RFX_TILE* tile = (RFX_TILE*)obj;
177
178 if (tile)
179 {
180 if (tile->allocated)
181 _aligned_free(tile->data);
182
183 free(tile);
184 }
185 }
186
rfx_encoder_tile_new(void * val)187 static void* rfx_encoder_tile_new(void* val)
188 {
189 WINPR_UNUSED(val);
190 return calloc(1, sizeof(RFX_TILE));
191 }
192
rfx_encoder_tile_free(void * obj)193 static void rfx_encoder_tile_free(void* obj)
194 {
195 free(obj);
196 }
197
rfx_context_new(BOOL encoder)198 RFX_CONTEXT* rfx_context_new(BOOL encoder)
199 {
200 HKEY hKey;
201 LONG status;
202 DWORD dwType;
203 DWORD dwSize;
204 DWORD dwValue;
205 SYSTEM_INFO sysinfo;
206 RFX_CONTEXT* context;
207 wObject* pool;
208 RFX_CONTEXT_PRIV* priv;
209 context = (RFX_CONTEXT*)calloc(1, sizeof(RFX_CONTEXT));
210
211 if (!context)
212 return NULL;
213
214 context->encoder = encoder;
215 context->currentMessage.freeArray = TRUE;
216 context->priv = priv = (RFX_CONTEXT_PRIV*)calloc(1, sizeof(RFX_CONTEXT_PRIV));
217
218 if (!priv)
219 goto error_priv;
220
221 priv->log = WLog_Get("com.freerdp.codec.rfx");
222 WLog_OpenAppender(priv->log);
223 priv->TilePool = ObjectPool_New(TRUE);
224
225 if (!priv->TilePool)
226 goto error_tilePool;
227
228 pool = ObjectPool_Object(priv->TilePool);
229 pool->fnObjectInit = rfx_tile_init;
230
231 if (context->encoder)
232 {
233 pool->fnObjectNew = rfx_encoder_tile_new;
234 pool->fnObjectFree = rfx_encoder_tile_free;
235 }
236 else
237 {
238 pool->fnObjectNew = rfx_decoder_tile_new;
239 pool->fnObjectFree = rfx_decoder_tile_free;
240 }
241
242 /*
243 * align buffers to 16 byte boundary (needed for SSE/NEON instructions)
244 *
245 * y_r_buffer, cb_g_buffer, cr_b_buffer: 64 * 64 * sizeof(INT16) = 8192 (0x2000)
246 * dwt_buffer: 32 * 32 * 2 * 2 * sizeof(INT16) = 8192, maximum sub-band width is 32
247 *
248 * Additionally we add 32 bytes (16 in front and 16 at the back of the buffer)
249 * in order to allow optimized functions (SEE, NEON) to read from positions
250 * that are actually in front/beyond the buffer. Offset calculations are
251 * performed at the BufferPool_Take function calls in rfx_encode/decode.c.
252 *
253 * We then multiply by 3 to use a single, partioned buffer for all 3 channels.
254 */
255 priv->BufferPool = BufferPool_New(TRUE, (8192 + 32) * 3, 16);
256
257 if (!priv->BufferPool)
258 goto error_BufferPool;
259
260 #ifdef _WIN32
261 {
262 BOOL isVistaOrLater;
263 OSVERSIONINFOA verinfo;
264 ZeroMemory(&verinfo, sizeof(OSVERSIONINFOA));
265 verinfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
266 GetVersionExA(&verinfo);
267 isVistaOrLater =
268 ((verinfo.dwMajorVersion >= 6) && (verinfo.dwMinorVersion >= 0)) ? TRUE : FALSE;
269 priv->UseThreads = isVistaOrLater;
270 }
271 #else
272 priv->UseThreads = TRUE;
273 #endif
274 GetNativeSystemInfo(&sysinfo);
275 priv->MinThreadCount = sysinfo.dwNumberOfProcessors;
276 priv->MaxThreadCount = 0;
277 status = RegOpenKeyExA(HKEY_LOCAL_MACHINE, RFX_KEY, 0, KEY_READ | KEY_WOW64_64KEY, &hKey);
278
279 if (status == ERROR_SUCCESS)
280 {
281 dwSize = sizeof(dwValue);
282
283 if (RegQueryValueEx(hKey, _T("UseThreads"), NULL, &dwType, (BYTE*)&dwValue, &dwSize) ==
284 ERROR_SUCCESS)
285 priv->UseThreads = dwValue ? 1 : 0;
286
287 if (RegQueryValueEx(hKey, _T("MinThreadCount"), NULL, &dwType, (BYTE*)&dwValue, &dwSize) ==
288 ERROR_SUCCESS)
289 priv->MinThreadCount = dwValue;
290
291 if (RegQueryValueEx(hKey, _T("MaxThreadCount"), NULL, &dwType, (BYTE*)&dwValue, &dwSize) ==
292 ERROR_SUCCESS)
293 priv->MaxThreadCount = dwValue;
294
295 RegCloseKey(hKey);
296 }
297
298 if (priv->UseThreads)
299 {
300 /* Call primitives_get here in order to avoid race conditions when using primitives_get */
301 /* from multiple threads. This call will initialize all function pointers correctly */
302 /* before any decoding threads are started */
303 primitives_get();
304 priv->ThreadPool = CreateThreadpool(NULL);
305
306 if (!priv->ThreadPool)
307 goto error_threadPool;
308
309 InitializeThreadpoolEnvironment(&priv->ThreadPoolEnv);
310 SetThreadpoolCallbackPool(&priv->ThreadPoolEnv, priv->ThreadPool);
311
312 if (priv->MinThreadCount)
313 if (!SetThreadpoolThreadMinimum(priv->ThreadPool, priv->MinThreadCount))
314 goto error_threadPool_minimum;
315
316 if (priv->MaxThreadCount)
317 SetThreadpoolThreadMaximum(priv->ThreadPool, priv->MaxThreadCount);
318 }
319
320 /* initialize the default pixel format */
321 rfx_context_set_pixel_format(context, PIXEL_FORMAT_BGRX32);
322 /* create profilers for default decoding routines */
323 rfx_profiler_create(context);
324 /* set up default routines */
325 context->quantization_decode = rfx_quantization_decode;
326 context->quantization_encode = rfx_quantization_encode;
327 context->dwt_2d_decode = rfx_dwt_2d_decode;
328 context->dwt_2d_encode = rfx_dwt_2d_encode;
329 context->rlgr_decode = rfx_rlgr_decode;
330 context->rlgr_encode = rfx_rlgr_encode;
331 RFX_INIT_SIMD(context);
332 context->state = RFX_STATE_SEND_HEADERS;
333 context->expectedDataBlockType = WBT_FRAME_BEGIN;
334 return context;
335 error_threadPool_minimum:
336 CloseThreadpool(priv->ThreadPool);
337 error_threadPool:
338 BufferPool_Free(priv->BufferPool);
339 error_BufferPool:
340 ObjectPool_Free(priv->TilePool);
341 error_tilePool:
342 free(priv);
343 error_priv:
344 free(context);
345 return NULL;
346 }
347
rfx_context_free(RFX_CONTEXT * context)348 void rfx_context_free(RFX_CONTEXT* context)
349 {
350 RFX_CONTEXT_PRIV* priv;
351
352 if (!context)
353 return;
354
355 assert(NULL != context);
356 assert(NULL != context->priv);
357 assert(NULL != context->priv->TilePool);
358 assert(NULL != context->priv->BufferPool);
359 priv = context->priv;
360 rfx_message_free(context, &context->currentMessage);
361 free(context->quants);
362 ObjectPool_Free(priv->TilePool);
363 rfx_profiler_print(context);
364 rfx_profiler_free(context);
365
366 if (priv->UseThreads)
367 {
368 CloseThreadpool(context->priv->ThreadPool);
369 DestroyThreadpoolEnvironment(&context->priv->ThreadPoolEnv);
370 free(priv->workObjects);
371 free(priv->tileWorkParams);
372 #ifdef WITH_PROFILER
373 WLog_VRB(TAG,
374 "WARNING: Profiling results probably unusable with multithreaded RemoteFX codec!");
375 #endif
376 }
377
378 BufferPool_Free(context->priv->BufferPool);
379 free(context->priv);
380 free(context);
381 }
382
rfx_message_get_tile(RFX_MESSAGE * message,UINT32 index)383 static RFX_TILE* rfx_message_get_tile(RFX_MESSAGE* message, UINT32 index)
384 {
385 return message->tiles[index];
386 }
387
rfx_message_get_rect_const(const RFX_MESSAGE * message,UINT32 index)388 static const RFX_RECT* rfx_message_get_rect_const(const RFX_MESSAGE* message, UINT32 index)
389 {
390 return &message->rects[index];
391 }
392
rfx_message_get_rect(RFX_MESSAGE * message,UINT32 index)393 static RFX_RECT* rfx_message_get_rect(RFX_MESSAGE* message, UINT32 index)
394 {
395 return &message->rects[index];
396 }
397
rfx_context_set_pixel_format(RFX_CONTEXT * context,UINT32 pixel_format)398 void rfx_context_set_pixel_format(RFX_CONTEXT* context, UINT32 pixel_format)
399 {
400 context->pixel_format = pixel_format;
401 context->bits_per_pixel = GetBitsPerPixel(pixel_format);
402 }
403
rfx_context_reset(RFX_CONTEXT * context,UINT32 width,UINT32 height)404 BOOL rfx_context_reset(RFX_CONTEXT* context, UINT32 width, UINT32 height)
405 {
406 if (!context)
407 return FALSE;
408
409 context->width = width;
410 context->height = height;
411 context->state = RFX_STATE_SEND_HEADERS;
412 context->expectedDataBlockType = WBT_FRAME_BEGIN;
413 context->frameIdx = 0;
414 return TRUE;
415 }
416
rfx_process_message_sync(RFX_CONTEXT * context,wStream * s)417 static BOOL rfx_process_message_sync(RFX_CONTEXT* context, wStream* s)
418 {
419 UINT32 magic;
420 context->decodedHeaderBlocks &= ~_RFX_DECODED_SYNC;
421
422 /* RFX_SYNC */
423 if (Stream_GetRemainingLength(s) < 6)
424 {
425 WLog_ERR(TAG, "RfxSync packet too small");
426 return FALSE;
427 }
428
429 Stream_Read_UINT32(s, magic); /* magic (4 bytes), 0xCACCACCA */
430 if (magic != WF_MAGIC)
431 {
432 WLog_ERR(TAG, "invalid magic number 0x%08" PRIX32 "", magic);
433 return FALSE;
434 }
435
436 Stream_Read_UINT16(s, context->version); /* version (2 bytes), WF_VERSION_1_0 (0x0100) */
437 if (context->version != WF_VERSION_1_0)
438 {
439 WLog_ERR(TAG, "invalid version number 0x%08" PRIX32 "", context->version);
440 return FALSE;
441 }
442
443 WLog_Print(context->priv->log, WLOG_DEBUG, "version 0x%08" PRIX32 "", context->version);
444 context->decodedHeaderBlocks |= _RFX_DECODED_SYNC;
445 return TRUE;
446 }
447
rfx_process_message_codec_versions(RFX_CONTEXT * context,wStream * s)448 static BOOL rfx_process_message_codec_versions(RFX_CONTEXT* context, wStream* s)
449 {
450 BYTE numCodecs;
451 context->decodedHeaderBlocks &= ~_RFX_DECODED_VERSIONS;
452
453 if (Stream_GetRemainingLength(s) < 4)
454 {
455 WLog_ERR(TAG, "%s: packet too small for reading codec versions", __FUNCTION__);
456 return FALSE;
457 }
458
459 Stream_Read_UINT8(s, numCodecs); /* numCodecs (1 byte), must be set to 0x01 */
460 Stream_Read_UINT8(s, context->codec_id); /* codecId (1 byte), must be set to 0x01 */
461 Stream_Read_UINT16(
462 s, context->codec_version); /* version (2 bytes), must be set to WF_VERSION_1_0 (0x0100) */
463
464 if (numCodecs != 1)
465 {
466 WLog_ERR(TAG, "%s: numCodes is 0x%02" PRIX8 " (must be 0x01)", __FUNCTION__, numCodecs);
467 return FALSE;
468 }
469
470 if (context->codec_id != 0x01)
471 {
472 WLog_ERR(TAG, "%s: invalid codec id (0x%02" PRIX32 ")", __FUNCTION__, context->codec_id);
473 return FALSE;
474 }
475
476 if (context->codec_version != WF_VERSION_1_0)
477 {
478 WLog_ERR(TAG, "%s: invalid codec version (0x%08" PRIX32 ")", __FUNCTION__,
479 context->codec_version);
480 return FALSE;
481 }
482
483 WLog_Print(context->priv->log, WLOG_DEBUG, "id %" PRIu32 " version 0x%" PRIX32 ".",
484 context->codec_id, context->codec_version);
485 context->decodedHeaderBlocks |= _RFX_DECODED_VERSIONS;
486 return TRUE;
487 }
488
rfx_process_message_channels(RFX_CONTEXT * context,wStream * s)489 static BOOL rfx_process_message_channels(RFX_CONTEXT* context, wStream* s)
490 {
491 BYTE channelId;
492 BYTE numChannels;
493 context->decodedHeaderBlocks &= ~_RFX_DECODED_CHANNELS;
494
495 if (Stream_GetRemainingLength(s) < 1)
496 {
497 WLog_ERR(TAG, "RfxMessageChannels packet too small");
498 return FALSE;
499 }
500
501 Stream_Read_UINT8(s, numChannels); /* numChannels (1 byte), must bet set to 0x01 */
502
503 /* In RDVH sessions, numChannels will represent the number of virtual monitors
504 * configured and does not always be set to 0x01 as [MS-RDPRFX] said.
505 */
506 if (numChannels < 1)
507 {
508 WLog_ERR(TAG, "no channels announced");
509 return FALSE;
510 }
511
512 if (Stream_GetRemainingLength(s) < (size_t)(numChannels * 5))
513 {
514 WLog_ERR(TAG, "RfxMessageChannels packet too small for numChannels=%" PRIu8 "",
515 numChannels);
516 return FALSE;
517 }
518
519 /* RFX_CHANNELT */
520 Stream_Read_UINT8(s, channelId); /* channelId (1 byte), must be set to 0x00 */
521
522 if (channelId != 0x00)
523 {
524 WLog_ERR(TAG, "channelId:0x%02" PRIX8 ", expected:0x00", channelId);
525 return FALSE;
526 }
527
528 Stream_Read_UINT16(s, context->width); /* width (2 bytes) */
529 Stream_Read_UINT16(s, context->height); /* height (2 bytes) */
530
531 if (!context->width || !context->height)
532 {
533 WLog_ERR(TAG, "%s: invalid channel with/height: %" PRIu16 "x%" PRIu16 "", __FUNCTION__,
534 context->width, context->height);
535 return FALSE;
536 }
537
538 /* Now, only the first monitor can be used, therefore the other channels will be ignored. */
539 Stream_Seek(s, 5 * (numChannels - 1));
540 WLog_Print(context->priv->log, WLOG_DEBUG,
541 "numChannels %" PRIu8 " id %" PRIu8 ", %" PRIu16 "x%" PRIu16 ".", numChannels,
542 channelId, context->width, context->height);
543 context->decodedHeaderBlocks |= _RFX_DECODED_CHANNELS;
544 return TRUE;
545 }
546
rfx_process_message_context(RFX_CONTEXT * context,wStream * s)547 static BOOL rfx_process_message_context(RFX_CONTEXT* context, wStream* s)
548 {
549 BYTE ctxId;
550 UINT16 tileSize;
551 UINT16 properties;
552 context->decodedHeaderBlocks &= ~_RFX_DECODED_CONTEXT;
553
554 if (Stream_GetRemainingLength(s) < 5)
555 {
556 WLog_ERR(TAG, "RfxMessageContext packet too small");
557 return FALSE;
558 }
559
560 Stream_Read_UINT8(s, ctxId); /* ctxId (1 byte), must be set to 0x00 */
561 Stream_Read_UINT16(s, tileSize); /* tileSize (2 bytes), must be set to CT_TILE_64x64 (0x0040) */
562 Stream_Read_UINT16(s, properties); /* properties (2 bytes) */
563 WLog_Print(context->priv->log, WLOG_DEBUG,
564 "ctxId %" PRIu8 " tileSize %" PRIu16 " properties 0x%04" PRIX16 ".", ctxId, tileSize,
565 properties);
566 context->properties = properties;
567 context->flags = (properties & 0x0007);
568
569 if (context->flags == CODEC_MODE)
570 {
571 WLog_Print(context->priv->log, WLOG_DEBUG, "codec is in image mode.");
572 }
573 else
574 {
575 WLog_Print(context->priv->log, WLOG_DEBUG, "codec is in video mode.");
576 }
577
578 switch ((properties & 0x1E00) >> 9)
579 {
580 case CLW_ENTROPY_RLGR1:
581 context->mode = RLGR1;
582 WLog_Print(context->priv->log, WLOG_DEBUG, "RLGR1.");
583 break;
584
585 case CLW_ENTROPY_RLGR3:
586 context->mode = RLGR3;
587 WLog_Print(context->priv->log, WLOG_DEBUG, "RLGR3.");
588 break;
589
590 default:
591 WLog_ERR(TAG, "unknown RLGR algorithm.");
592 return FALSE;
593 }
594
595 context->decodedHeaderBlocks |= _RFX_DECODED_CONTEXT;
596 return TRUE;
597 }
598
rfx_process_message_frame_begin(RFX_CONTEXT * context,RFX_MESSAGE * message,wStream * s,UINT16 * pExpectedBlockType)599 static BOOL rfx_process_message_frame_begin(RFX_CONTEXT* context, RFX_MESSAGE* message, wStream* s,
600 UINT16* pExpectedBlockType)
601 {
602 UINT32 frameIdx;
603 UINT16 numRegions;
604
605 if (*pExpectedBlockType != WBT_FRAME_BEGIN)
606 {
607 WLog_ERR(TAG, "%s: message unexpected wants WBT_FRAME_BEGIN", __FUNCTION__);
608 return FALSE;
609 }
610
611 *pExpectedBlockType = WBT_REGION;
612
613 if (Stream_GetRemainingLength(s) < 6)
614 {
615 WLog_ERR(TAG, "RfxMessageFrameBegin packet too small");
616 return FALSE;
617 }
618
619 Stream_Read_UINT32(
620 s, frameIdx); /* frameIdx (4 bytes), if codec is in video mode, must be ignored */
621 Stream_Read_UINT16(s, numRegions); /* numRegions (2 bytes) */
622 WLog_Print(context->priv->log, WLOG_DEBUG,
623 "RFX_FRAME_BEGIN: frameIdx: %" PRIu32 " numRegions: %" PRIu16 "", frameIdx,
624 numRegions);
625 return TRUE;
626 }
627
rfx_process_message_frame_end(RFX_CONTEXT * context,RFX_MESSAGE * message,wStream * s,UINT16 * pExpectedBlockType)628 static BOOL rfx_process_message_frame_end(RFX_CONTEXT* context, RFX_MESSAGE* message, wStream* s,
629 UINT16* pExpectedBlockType)
630 {
631 if (*pExpectedBlockType != WBT_FRAME_END)
632 {
633 WLog_ERR(TAG, "%s: message unexpected, wants WBT_FRAME_END", __FUNCTION__);
634 return FALSE;
635 }
636
637 *pExpectedBlockType = WBT_FRAME_BEGIN;
638 WLog_Print(context->priv->log, WLOG_DEBUG, "RFX_FRAME_END");
639 return TRUE;
640 }
641
rfx_process_message_region(RFX_CONTEXT * context,RFX_MESSAGE * message,wStream * s,UINT16 * pExpectedBlockType)642 static BOOL rfx_process_message_region(RFX_CONTEXT* context, RFX_MESSAGE* message, wStream* s,
643 UINT16* pExpectedBlockType)
644 {
645 UINT16 i;
646 UINT16 regionType;
647 UINT16 numTileSets;
648 RFX_RECT* tmpRects;
649
650 if (*pExpectedBlockType != WBT_REGION)
651 {
652 WLog_ERR(TAG, "%s: message unexpected wants WBT_REGION", __FUNCTION__);
653 return FALSE;
654 }
655
656 *pExpectedBlockType = WBT_EXTENSION;
657
658 if (Stream_GetRemainingLength(s) < 3)
659 {
660 WLog_ERR(TAG, "%s: packet too small (regionFlags/numRects)", __FUNCTION__);
661 return FALSE;
662 }
663
664 Stream_Seek_UINT8(s); /* regionFlags (1 byte) */
665 Stream_Read_UINT16(s, message->numRects); /* numRects (2 bytes) */
666
667 if (message->numRects < 1)
668 {
669 /*
670 If numRects is zero the decoder must generate a rectangle with
671 coordinates (0, 0, width, height).
672 See [MS-RDPRFX] (revision >= 17.0) 2.2.2.3.3 TS_RFX_REGION
673 https://msdn.microsoft.com/en-us/library/ff635233.aspx
674 */
675 tmpRects = realloc(message->rects, sizeof(RFX_RECT));
676 if (!tmpRects)
677 return FALSE;
678
679 message->numRects = 1;
680 message->rects = tmpRects;
681 message->rects->x = 0;
682 message->rects->y = 0;
683 message->rects->width = context->width;
684 message->rects->height = context->height;
685 return TRUE;
686 }
687
688 if (Stream_GetRemainingLength(s) < (size_t)(8 * message->numRects))
689 {
690 WLog_ERR(TAG, "%s: packet too small for num_rects=%" PRIu16 "", __FUNCTION__,
691 message->numRects);
692 return FALSE;
693 }
694
695 tmpRects = realloc(message->rects, message->numRects * sizeof(RFX_RECT));
696 if (!tmpRects)
697 return FALSE;
698 message->rects = tmpRects;
699
700 /* rects */
701 for (i = 0; i < message->numRects; i++)
702 {
703 RFX_RECT* rect = rfx_message_get_rect(message, i);
704 /* RFX_RECT */
705 Stream_Read_UINT16(s, rect->x); /* x (2 bytes) */
706 Stream_Read_UINT16(s, rect->y); /* y (2 bytes) */
707 Stream_Read_UINT16(s, rect->width); /* width (2 bytes) */
708 Stream_Read_UINT16(s, rect->height); /* height (2 bytes) */
709 WLog_Print(context->priv->log, WLOG_DEBUG,
710 "rect %d (x,y=%" PRIu16 ",%" PRIu16 " w,h=%" PRIu16 " %" PRIu16 ").", i, rect->x,
711 rect->y, rect->width, rect->height);
712 }
713
714 if (Stream_GetRemainingLength(s) < 4)
715 {
716 WLog_ERR(TAG, "%s: packet too small (regionType/numTileSets)", __FUNCTION__);
717 return FALSE;
718 }
719
720 Stream_Read_UINT16(s, regionType); /*regionType (2 bytes): MUST be set to CBT_REGION (0xCAC1)*/
721 Stream_Read_UINT16(s, numTileSets); /*numTilesets (2 bytes): MUST be set to 0x0001.*/
722
723 if (regionType != CBT_REGION)
724 {
725 WLog_ERR(TAG, "%s: invalid region type 0x%04" PRIX16 "", __FUNCTION__, regionType);
726 return TRUE;
727 }
728
729 if (numTileSets != 0x0001)
730 {
731 WLog_ERR(TAG, "%s: invalid number of tilesets (%" PRIu16 ")", __FUNCTION__, numTileSets);
732 return FALSE;
733 }
734
735 return TRUE;
736 }
737
738 struct _RFX_TILE_PROCESS_WORK_PARAM
739 {
740 RFX_TILE* tile;
741 RFX_CONTEXT* context;
742 };
743 typedef struct _RFX_TILE_PROCESS_WORK_PARAM RFX_TILE_PROCESS_WORK_PARAM;
744
rfx_process_message_tile_work_callback(PTP_CALLBACK_INSTANCE instance,void * context,PTP_WORK work)745 static void CALLBACK rfx_process_message_tile_work_callback(PTP_CALLBACK_INSTANCE instance,
746 void* context, PTP_WORK work)
747 {
748 RFX_TILE_PROCESS_WORK_PARAM* param = (RFX_TILE_PROCESS_WORK_PARAM*)context;
749 rfx_decode_rgb(param->context, param->tile, param->tile->data, 64 * 4);
750 }
751
rfx_process_message_tileset(RFX_CONTEXT * context,RFX_MESSAGE * message,wStream * s,UINT16 * pExpectedBlockType)752 static BOOL rfx_process_message_tileset(RFX_CONTEXT* context, RFX_MESSAGE* message, wStream* s,
753 UINT16* pExpectedBlockType)
754 {
755 BOOL rc;
756 int i, close_cnt;
757 BYTE quant;
758 RFX_TILE* tile;
759 RFX_TILE** tmpTiles;
760 UINT32* quants;
761 UINT16 subtype, numTiles;
762 UINT32 blockLen;
763 UINT32 blockType;
764 UINT32 tilesDataSize;
765 PTP_WORK* work_objects = NULL;
766 RFX_TILE_PROCESS_WORK_PARAM* params = NULL;
767 void* pmem;
768
769 if (*pExpectedBlockType != WBT_EXTENSION)
770 {
771 WLog_ERR(TAG, "%s: message unexpected wants a tileset", __FUNCTION__);
772 return FALSE;
773 }
774
775 *pExpectedBlockType = WBT_FRAME_END;
776
777 if (Stream_GetRemainingLength(s) < 14)
778 {
779 WLog_ERR(TAG, "RfxMessageTileSet packet too small");
780 return FALSE;
781 }
782
783 Stream_Read_UINT16(s, subtype); /* subtype (2 bytes) must be set to CBT_TILESET (0xCAC2) */
784 if (subtype != CBT_TILESET)
785 {
786 WLog_ERR(TAG, "invalid subtype, expected CBT_TILESET.");
787 return FALSE;
788 }
789
790 Stream_Seek_UINT16(s); /* idx (2 bytes), must be set to 0x0000 */
791 Stream_Seek_UINT16(s); /* properties (2 bytes) */
792 Stream_Read_UINT8(s, context->numQuant); /* numQuant (1 byte) */
793 Stream_Seek_UINT8(s); /* tileSize (1 byte), must be set to 0x40 */
794
795 if (context->numQuant < 1)
796 {
797 WLog_ERR(TAG, "no quantization value.");
798 return FALSE;
799 }
800
801 Stream_Read_UINT16(s, numTiles); /* numTiles (2 bytes) */
802 if (numTiles < 1)
803 {
804 /* Windows Server 2012 (not R2) can send empty tile sets */
805 return TRUE;
806 }
807
808 Stream_Read_UINT32(s, tilesDataSize); /* tilesDataSize (4 bytes) */
809
810 if (!(pmem = realloc((void*)context->quants, context->numQuant * 10 * sizeof(UINT32))))
811 return FALSE;
812
813 quants = context->quants = (UINT32*)pmem;
814
815 /* quantVals */
816 if (Stream_GetRemainingLength(s) < (size_t)(context->numQuant * 5))
817 {
818 WLog_ERR(TAG, "RfxMessageTileSet packet too small for num_quants=%" PRIu8 "",
819 context->numQuant);
820 return FALSE;
821 }
822
823 for (i = 0; i < context->numQuant; i++)
824 {
825 /* RFX_CODEC_QUANT */
826 Stream_Read_UINT8(s, quant);
827 *quants++ = (quant & 0x0F);
828 *quants++ = (quant >> 4);
829 Stream_Read_UINT8(s, quant);
830 *quants++ = (quant & 0x0F);
831 *quants++ = (quant >> 4);
832 Stream_Read_UINT8(s, quant);
833 *quants++ = (quant & 0x0F);
834 *quants++ = (quant >> 4);
835 Stream_Read_UINT8(s, quant);
836 *quants++ = (quant & 0x0F);
837 *quants++ = (quant >> 4);
838 Stream_Read_UINT8(s, quant);
839 *quants++ = (quant & 0x0F);
840 *quants++ = (quant >> 4);
841 WLog_Print(context->priv->log, WLOG_DEBUG,
842 "quant %d (%" PRIu32 " %" PRIu32 " %" PRIu32 " %" PRIu32 " %" PRIu32 " %" PRIu32
843 " %" PRIu32 " %" PRIu32 " %" PRIu32 " %" PRIu32 ").",
844 i, context->quants[i * 10], context->quants[i * 10 + 1],
845 context->quants[i * 10 + 2], context->quants[i * 10 + 3],
846 context->quants[i * 10 + 4], context->quants[i * 10 + 5],
847 context->quants[i * 10 + 6], context->quants[i * 10 + 7],
848 context->quants[i * 10 + 8], context->quants[i * 10 + 9]);
849 }
850
851 for (i = 0; i < message->numTiles; i++)
852 {
853 ObjectPool_Return(context->priv->TilePool, message->tiles[i]);
854 message->tiles[i] = NULL;
855 }
856
857 tmpTiles = (RFX_TILE**)realloc(message->tiles, numTiles * sizeof(RFX_TILE*));
858 if (!tmpTiles)
859 return FALSE;
860
861 message->tiles = tmpTiles;
862 message->numTiles = numTiles;
863
864 if (context->priv->UseThreads)
865 {
866 work_objects = (PTP_WORK*)calloc(message->numTiles, sizeof(PTP_WORK));
867 params = (RFX_TILE_PROCESS_WORK_PARAM*)calloc(message->numTiles,
868 sizeof(RFX_TILE_PROCESS_WORK_PARAM));
869
870 if (!work_objects)
871 {
872 free(params);
873 return FALSE;
874 }
875
876 if (!params)
877 {
878 free(work_objects);
879 return FALSE;
880 }
881 }
882
883 /* tiles */
884 close_cnt = 0;
885 rc = TRUE;
886
887 for (i = 0; i < message->numTiles; i++)
888 {
889 wStream sub;
890 if (!(tile = (RFX_TILE*)ObjectPool_Take(context->priv->TilePool)))
891 {
892 WLog_ERR(TAG, "RfxMessageTileSet failed to get tile from object pool");
893 rc = FALSE;
894 break;
895 }
896
897 message->tiles[i] = tile;
898
899 /* RFX_TILE */
900 if (Stream_GetRemainingLength(s) < 6)
901 {
902 WLog_ERR(TAG, "RfxMessageTileSet packet too small to read tile %d/%" PRIu16 "", i,
903 message->numTiles);
904 rc = FALSE;
905 break;
906 }
907
908 Stream_StaticInit(&sub, Stream_Pointer(s), Stream_GetRemainingLength(s));
909 Stream_Read_UINT16(&sub,
910 blockType); /* blockType (2 bytes), must be set to CBT_TILE (0xCAC3) */
911 Stream_Read_UINT32(&sub, blockLen); /* blockLen (4 bytes) */
912
913 if (!Stream_SafeSeek(s, blockLen))
914 {
915 rc = FALSE;
916 break;
917 }
918 if ((blockLen < 6 + 13) || (Stream_GetRemainingLength(&sub) < blockLen - 6))
919 {
920 WLog_ERR(TAG,
921 "RfxMessageTileSet not enough bytes to read tile %d/%" PRIu16
922 " with blocklen=%" PRIu32 "",
923 i, message->numTiles, blockLen);
924 rc = FALSE;
925 break;
926 }
927
928 if (blockType != CBT_TILE)
929 {
930 WLog_ERR(TAG, "unknown block type 0x%" PRIX32 ", expected CBT_TILE (0xCAC3).",
931 blockType);
932 rc = FALSE;
933 break;
934 }
935
936 Stream_Read_UINT8(&sub, tile->quantIdxY); /* quantIdxY (1 byte) */
937 Stream_Read_UINT8(&sub, tile->quantIdxCb); /* quantIdxCb (1 byte) */
938 Stream_Read_UINT8(&sub, tile->quantIdxCr); /* quantIdxCr (1 byte) */
939 Stream_Read_UINT16(&sub, tile->xIdx); /* xIdx (2 bytes) */
940 Stream_Read_UINT16(&sub, tile->yIdx); /* yIdx (2 bytes) */
941 Stream_Read_UINT16(&sub, tile->YLen); /* YLen (2 bytes) */
942 Stream_Read_UINT16(&sub, tile->CbLen); /* CbLen (2 bytes) */
943 Stream_Read_UINT16(&sub, tile->CrLen); /* CrLen (2 bytes) */
944 Stream_GetPointer(&sub, tile->YData);
945 if (!Stream_SafeSeek(&sub, tile->YLen))
946 {
947 rc = FALSE;
948 break;
949 }
950 Stream_GetPointer(&sub, tile->CbData);
951 if (!Stream_SafeSeek(&sub, tile->CbLen))
952 {
953 rc = FALSE;
954 break;
955 }
956 Stream_GetPointer(&sub, tile->CrData);
957 if (!Stream_SafeSeek(&sub, tile->CrLen))
958 {
959 rc = FALSE;
960 break;
961 }
962 tile->x = tile->xIdx * 64;
963 tile->y = tile->yIdx * 64;
964
965 if (context->priv->UseThreads)
966 {
967 if (!params)
968 {
969 rc = FALSE;
970 break;
971 }
972
973 params[i].context = context;
974 params[i].tile = message->tiles[i];
975
976 if (!(work_objects[i] =
977 CreateThreadpoolWork(rfx_process_message_tile_work_callback,
978 (void*)¶ms[i], &context->priv->ThreadPoolEnv)))
979 {
980 WLog_ERR(TAG, "CreateThreadpoolWork failed.");
981 rc = FALSE;
982 break;
983 }
984
985 SubmitThreadpoolWork(work_objects[i]);
986 close_cnt = i + 1;
987 }
988 else
989 {
990 rfx_decode_rgb(context, tile, tile->data, 64 * 4);
991 }
992 }
993
994 if (context->priv->UseThreads)
995 {
996 for (i = 0; i < close_cnt; i++)
997 {
998 WaitForThreadpoolWorkCallbacks(work_objects[i], FALSE);
999 CloseThreadpoolWork(work_objects[i]);
1000 }
1001 }
1002
1003 free(work_objects);
1004 free(params);
1005
1006 for (i = 0; i < message->numTiles; i++)
1007 {
1008 if (!(tile = message->tiles[i]))
1009 continue;
1010
1011 tile->YLen = tile->CbLen = tile->CrLen = 0;
1012 tile->YData = tile->CbData = tile->CrData = NULL;
1013 }
1014
1015 return rc;
1016 }
1017
rfx_process_message(RFX_CONTEXT * context,const BYTE * data,UINT32 length,UINT32 left,UINT32 top,BYTE * dst,UINT32 dstFormat,UINT32 dstStride,UINT32 dstHeight,REGION16 * invalidRegion)1018 BOOL rfx_process_message(RFX_CONTEXT* context, const BYTE* data, UINT32 length, UINT32 left,
1019 UINT32 top, BYTE* dst, UINT32 dstFormat, UINT32 dstStride,
1020 UINT32 dstHeight, REGION16* invalidRegion)
1021 {
1022 REGION16 updateRegion;
1023 UINT32 blockLen;
1024 UINT32 blockType;
1025 wStream inStream, *s = &inStream;
1026 BOOL ok = TRUE;
1027 RFX_MESSAGE* message;
1028
1029 if (!context || !data || !length)
1030 return FALSE;
1031
1032 message = &context->currentMessage;
1033
1034 Stream_StaticInit(s, (BYTE*)data, length);
1035
1036 message->freeRects = TRUE;
1037
1038 while (ok && Stream_GetRemainingLength(s) > 6)
1039 {
1040 wStream subStream;
1041 size_t extraBlockLen = 0;
1042
1043 /* RFX_BLOCKT */
1044 Stream_Read_UINT16(s, blockType); /* blockType (2 bytes) */
1045 Stream_Read_UINT32(s, blockLen); /* blockLen (4 bytes) */
1046 WLog_Print(context->priv->log, WLOG_DEBUG, "blockType 0x%" PRIX32 " blockLen %" PRIu32 "",
1047 blockType, blockLen);
1048
1049 if (blockLen < 6)
1050 {
1051 WLog_ERR(TAG, "blockLen too small(%" PRIu32 ")", blockLen);
1052 return FALSE;
1053 }
1054
1055 if (Stream_GetRemainingLength(s) < blockLen - 6)
1056 {
1057 WLog_ERR(TAG, "%s: packet too small for blocklen=%" PRIu32 "", __FUNCTION__, blockLen);
1058 return FALSE;
1059 }
1060
1061 if (blockType > WBT_CONTEXT && context->decodedHeaderBlocks != _RFX_DECODED_HEADERS)
1062 {
1063 WLog_ERR(TAG, "%s: incomplete header blocks processing", __FUNCTION__);
1064 return FALSE;
1065 }
1066
1067 if (blockType >= WBT_CONTEXT && blockType <= WBT_EXTENSION)
1068 {
1069 /* RFX_CODEC_CHANNELT */
1070 UINT8 codecId;
1071 UINT8 channelId;
1072
1073 if (Stream_GetRemainingLength(s) < 2)
1074 return FALSE;
1075
1076 extraBlockLen = 2;
1077 Stream_Read_UINT8(s, codecId); /* codecId (1 byte) must be set to 0x01 */
1078 Stream_Read_UINT8(s, channelId); /* channelId (1 byte) 0xFF or 0x00, see below */
1079
1080 if (codecId != 0x01)
1081 {
1082 WLog_ERR(TAG, "%s: invalid codecId 0x%02" PRIX8 "", __FUNCTION__, codecId);
1083 return FALSE;
1084 }
1085
1086 if (blockType == WBT_CONTEXT)
1087 {
1088 /* If the blockType is set to WBT_CONTEXT, then channelId MUST be set to 0xFF.*/
1089 if (channelId != 0xFF)
1090 {
1091 WLog_ERR(TAG,
1092 "%s: invalid channelId 0x%02" PRIX8 " for blockType 0x%08" PRIX32 "",
1093 __FUNCTION__, channelId, blockType);
1094 return FALSE;
1095 }
1096 }
1097 else
1098 {
1099 /* For all other values of blockType, channelId MUST be set to 0x00. */
1100 if (channelId != 0x00)
1101 {
1102 WLog_ERR(TAG, "%s: invalid channelId 0x%02" PRIX8 " for blockType WBT_CONTEXT",
1103 __FUNCTION__, channelId);
1104 return FALSE;
1105 }
1106 }
1107 }
1108
1109 Stream_StaticInit(&subStream, Stream_Pointer(s), blockLen - (6 + extraBlockLen));
1110 Stream_Seek(s, blockLen - (6 + extraBlockLen));
1111
1112 switch (blockType)
1113 {
1114 /* Header messages:
1115 * The stream MUST start with the header messages and any of these headers can appear
1116 * in the stream at a later stage. The header messages can be repeated.
1117 */
1118 case WBT_SYNC:
1119 ok = rfx_process_message_sync(context, &subStream);
1120 break;
1121
1122 case WBT_CONTEXT:
1123 ok = rfx_process_message_context(context, &subStream);
1124 break;
1125
1126 case WBT_CODEC_VERSIONS:
1127 ok = rfx_process_message_codec_versions(context, &subStream);
1128 break;
1129
1130 case WBT_CHANNELS:
1131 ok = rfx_process_message_channels(context, &subStream);
1132 break;
1133
1134 /* Data messages:
1135 * The data associated with each encoded frame or image is always bracketed by the
1136 * TS_RFX_FRAME_BEGIN (section 2.2.2.3.1) and TS_RFX_FRAME_END (section 2.2.2.3.2)
1137 * messages. There MUST only be one TS_RFX_REGION (section 2.2.2.3.3) message per
1138 * frame and one TS_RFX_TILESET (section 2.2.2.3.4) message per TS_RFX_REGION.
1139 */
1140
1141 case WBT_FRAME_BEGIN:
1142 ok = rfx_process_message_frame_begin(context, message, &subStream,
1143 &context->expectedDataBlockType);
1144 break;
1145
1146 case WBT_REGION:
1147 ok = rfx_process_message_region(context, message, &subStream,
1148 &context->expectedDataBlockType);
1149 break;
1150
1151 case WBT_EXTENSION:
1152 ok = rfx_process_message_tileset(context, message, &subStream,
1153 &context->expectedDataBlockType);
1154 break;
1155
1156 case WBT_FRAME_END:
1157 ok = rfx_process_message_frame_end(context, message, &subStream,
1158 &context->expectedDataBlockType);
1159 break;
1160
1161 default:
1162 WLog_ERR(TAG, "%s: unknown blockType 0x%" PRIX32 "", __FUNCTION__, blockType);
1163 return FALSE;
1164 }
1165 }
1166
1167 if (ok)
1168 {
1169 UINT32 i, j;
1170 UINT32 nbUpdateRects;
1171 REGION16 clippingRects;
1172 const RECTANGLE_16* updateRects;
1173 const DWORD formatSize = GetBytesPerPixel(context->pixel_format);
1174 const UINT32 dstWidth = dstStride / GetBytesPerPixel(dstFormat);
1175 region16_init(&clippingRects);
1176
1177 for (i = 0; i < message->numRects; i++)
1178 {
1179 RECTANGLE_16 clippingRect;
1180 const RFX_RECT* rect = &(message->rects[i]);
1181 clippingRect.left = MIN(left + rect->x, dstWidth);
1182 clippingRect.top = MIN(top + rect->y, dstHeight);
1183 clippingRect.right = MIN(clippingRect.left + rect->width, dstWidth);
1184 clippingRect.bottom = MIN(clippingRect.top + rect->height, dstHeight);
1185 region16_union_rect(&clippingRects, &clippingRects, &clippingRect);
1186 }
1187
1188 for (i = 0; i < message->numTiles; i++)
1189 {
1190 RECTANGLE_16 updateRect;
1191 const RFX_TILE* tile = rfx_message_get_tile(message, i);
1192 updateRect.left = left + tile->x;
1193 updateRect.top = top + tile->y;
1194 updateRect.right = updateRect.left + 64;
1195 updateRect.bottom = updateRect.top + 64;
1196 region16_init(&updateRegion);
1197 region16_intersect_rect(&updateRegion, &clippingRects, &updateRect);
1198 updateRects = region16_rects(&updateRegion, &nbUpdateRects);
1199
1200 for (j = 0; j < nbUpdateRects; j++)
1201 {
1202 const UINT32 stride = 64 * formatSize;
1203 const UINT32 nXDst = updateRects[j].left;
1204 const UINT32 nYDst = updateRects[j].top;
1205 const UINT32 nXSrc = nXDst - updateRect.left;
1206 const UINT32 nYSrc = nYDst - updateRect.top;
1207 const UINT32 nWidth = updateRects[j].right - updateRects[j].left;
1208 const UINT32 nHeight = updateRects[j].bottom - updateRects[j].top;
1209
1210 if (!freerdp_image_copy(dst, dstFormat, dstStride, nXDst, nYDst, nWidth, nHeight,
1211 tile->data, context->pixel_format, stride, nXSrc, nYSrc,
1212 NULL, FREERDP_FLIP_NONE))
1213 {
1214 region16_uninit(&updateRegion);
1215 return FALSE;
1216 }
1217
1218 if (invalidRegion)
1219 region16_union_rect(invalidRegion, invalidRegion, &updateRects[j]);
1220 }
1221
1222 region16_uninit(&updateRegion);
1223 }
1224
1225 region16_uninit(&clippingRects);
1226 return TRUE;
1227 }
1228
1229 return FALSE;
1230 }
1231
rfx_message_get_tile_count(RFX_MESSAGE * message)1232 UINT16 rfx_message_get_tile_count(RFX_MESSAGE* message)
1233 {
1234 return message->numTiles;
1235 }
1236
rfx_message_get_rect_count(RFX_MESSAGE * message)1237 UINT16 rfx_message_get_rect_count(RFX_MESSAGE* message)
1238 {
1239 return message->numRects;
1240 }
1241
rfx_message_free(RFX_CONTEXT * context,RFX_MESSAGE * message)1242 void rfx_message_free(RFX_CONTEXT* context, RFX_MESSAGE* message)
1243 {
1244 int i;
1245 RFX_TILE* tile;
1246
1247 if (message)
1248 {
1249 if ((message->rects) && (message->freeRects))
1250 {
1251 free(message->rects);
1252 }
1253
1254 if (message->tiles)
1255 {
1256 for (i = 0; i < message->numTiles; i++)
1257 {
1258 if (!(tile = message->tiles[i]))
1259 continue;
1260
1261 if (tile->YCbCrData)
1262 {
1263 BufferPool_Return(context->priv->BufferPool, tile->YCbCrData);
1264 tile->YCbCrData = NULL;
1265 }
1266
1267 ObjectPool_Return(context->priv->TilePool, (void*)tile);
1268 }
1269
1270 free(message->tiles);
1271 }
1272
1273 if (!message->freeArray)
1274 free(message);
1275 }
1276 }
1277
rfx_update_context_properties(RFX_CONTEXT * context)1278 static void rfx_update_context_properties(RFX_CONTEXT* context)
1279 {
1280 UINT16 properties;
1281 /* properties in tilesets: note that this has different format from the one in TS_RFX_CONTEXT */
1282 properties = 1; /* lt */
1283 properties |= (context->flags << 1); /* flags */
1284 properties |= (COL_CONV_ICT << 4); /* cct */
1285 properties |= (CLW_XFORM_DWT_53_A << 6); /* xft */
1286 properties |= ((context->mode == RLGR1 ? CLW_ENTROPY_RLGR1 : CLW_ENTROPY_RLGR3) << 10); /* et */
1287 properties |= (SCALAR_QUANTIZATION << 14); /* qt */
1288 context->properties = properties;
1289 }
1290
rfx_write_message_sync(RFX_CONTEXT * context,wStream * s)1291 static void rfx_write_message_sync(RFX_CONTEXT* context, wStream* s)
1292 {
1293 Stream_Write_UINT16(s, WBT_SYNC); /* BlockT.blockType (2 bytes) */
1294 Stream_Write_UINT32(s, 12); /* BlockT.blockLen (4 bytes) */
1295 Stream_Write_UINT32(s, WF_MAGIC); /* magic (4 bytes) */
1296 Stream_Write_UINT16(s, WF_VERSION_1_0); /* version (2 bytes) */
1297 }
1298
rfx_write_message_codec_versions(RFX_CONTEXT * context,wStream * s)1299 static void rfx_write_message_codec_versions(RFX_CONTEXT* context, wStream* s)
1300 {
1301 Stream_Write_UINT16(s, WBT_CODEC_VERSIONS); /* BlockT.blockType (2 bytes) */
1302 Stream_Write_UINT32(s, 10); /* BlockT.blockLen (4 bytes) */
1303 Stream_Write_UINT8(s, 1); /* numCodecs (1 byte) */
1304 Stream_Write_UINT8(s, 1); /* codecs.codecId (1 byte) */
1305 Stream_Write_UINT16(s, WF_VERSION_1_0); /* codecs.version (2 bytes) */
1306 }
1307
rfx_write_message_channels(RFX_CONTEXT * context,wStream * s)1308 static void rfx_write_message_channels(RFX_CONTEXT* context, wStream* s)
1309 {
1310 Stream_Write_UINT16(s, WBT_CHANNELS); /* BlockT.blockType (2 bytes) */
1311 Stream_Write_UINT32(s, 12); /* BlockT.blockLen (4 bytes) */
1312 Stream_Write_UINT8(s, 1); /* numChannels (1 byte) */
1313 Stream_Write_UINT8(s, 0); /* Channel.channelId (1 byte) */
1314 Stream_Write_UINT16(s, context->width); /* Channel.width (2 bytes) */
1315 Stream_Write_UINT16(s, context->height); /* Channel.height (2 bytes) */
1316 }
1317
rfx_write_message_context(RFX_CONTEXT * context,wStream * s)1318 static void rfx_write_message_context(RFX_CONTEXT* context, wStream* s)
1319 {
1320 UINT16 properties;
1321 Stream_Write_UINT16(s, WBT_CONTEXT); /* CodecChannelT.blockType (2 bytes) */
1322 Stream_Write_UINT32(s, 13); /* CodecChannelT.blockLen (4 bytes) */
1323 Stream_Write_UINT8(s, 1); /* CodecChannelT.codecId (1 byte) */
1324 Stream_Write_UINT8(s, 0xFF); /* CodecChannelT.channelId (1 byte) */
1325 Stream_Write_UINT8(s, 0); /* ctxId (1 byte) */
1326 Stream_Write_UINT16(s, CT_TILE_64x64); /* tileSize (2 bytes) */
1327 /* properties */
1328 properties = context->flags; /* flags */
1329 properties |= (COL_CONV_ICT << 3); /* cct */
1330 properties |= (CLW_XFORM_DWT_53_A << 5); /* xft */
1331 properties |= ((context->mode == RLGR1 ? CLW_ENTROPY_RLGR1 : CLW_ENTROPY_RLGR3) << 9); /* et */
1332 properties |= (SCALAR_QUANTIZATION << 13); /* qt */
1333 Stream_Write_UINT16(s, properties); /* properties (2 bytes) */
1334 rfx_update_context_properties(context);
1335 }
1336
rfx_compose_message_header(RFX_CONTEXT * context,wStream * s)1337 static BOOL rfx_compose_message_header(RFX_CONTEXT* context, wStream* s)
1338 {
1339 if (!Stream_EnsureRemainingCapacity(s, 12 + 10 + 12 + 13))
1340 return FALSE;
1341
1342 rfx_write_message_sync(context, s);
1343 rfx_write_message_context(context, s);
1344 rfx_write_message_codec_versions(context, s);
1345 rfx_write_message_channels(context, s);
1346 return TRUE;
1347 }
1348
rfx_tile_length(RFX_TILE * tile)1349 static int rfx_tile_length(RFX_TILE* tile)
1350 {
1351 return 19 + tile->YLen + tile->CbLen + tile->CrLen;
1352 }
1353
rfx_write_tile(RFX_CONTEXT * context,wStream * s,RFX_TILE * tile)1354 static BOOL rfx_write_tile(RFX_CONTEXT* context, wStream* s, RFX_TILE* tile)
1355 {
1356 UINT32 blockLen;
1357 blockLen = rfx_tile_length(tile);
1358
1359 if (!Stream_EnsureRemainingCapacity(s, blockLen))
1360 return FALSE;
1361
1362 Stream_Write_UINT16(s, CBT_TILE); /* BlockT.blockType (2 bytes) */
1363 Stream_Write_UINT32(s, blockLen); /* BlockT.blockLen (4 bytes) */
1364 Stream_Write_UINT8(s, tile->quantIdxY); /* quantIdxY (1 byte) */
1365 Stream_Write_UINT8(s, tile->quantIdxCb); /* quantIdxCb (1 byte) */
1366 Stream_Write_UINT8(s, tile->quantIdxCr); /* quantIdxCr (1 byte) */
1367 Stream_Write_UINT16(s, tile->xIdx); /* xIdx (2 bytes) */
1368 Stream_Write_UINT16(s, tile->yIdx); /* yIdx (2 bytes) */
1369 Stream_Write_UINT16(s, tile->YLen); /* YLen (2 bytes) */
1370 Stream_Write_UINT16(s, tile->CbLen); /* CbLen (2 bytes) */
1371 Stream_Write_UINT16(s, tile->CrLen); /* CrLen (2 bytes) */
1372 Stream_Write(s, tile->YData, tile->YLen); /* YData */
1373 Stream_Write(s, tile->CbData, tile->CbLen); /* CbData */
1374 Stream_Write(s, tile->CrData, tile->CrLen); /* CrData */
1375 return TRUE;
1376 }
1377
1378 struct _RFX_TILE_COMPOSE_WORK_PARAM
1379 {
1380 RFX_TILE* tile;
1381 RFX_CONTEXT* context;
1382 };
1383
rfx_compose_message_tile_work_callback(PTP_CALLBACK_INSTANCE instance,void * context,PTP_WORK work)1384 static void CALLBACK rfx_compose_message_tile_work_callback(PTP_CALLBACK_INSTANCE instance,
1385 void* context, PTP_WORK work)
1386 {
1387 RFX_TILE_COMPOSE_WORK_PARAM* param = (RFX_TILE_COMPOSE_WORK_PARAM*)context;
1388 rfx_encode_rgb(param->context, param->tile);
1389 }
1390
computeRegion(const RFX_RECT * rects,int numRects,REGION16 * region,int width,int height)1391 static BOOL computeRegion(const RFX_RECT* rects, int numRects, REGION16* region, int width,
1392 int height)
1393 {
1394 int i;
1395 const RFX_RECT* rect = rects;
1396 const RECTANGLE_16 mainRect = { 0, 0, width, height };
1397
1398 for (i = 0; i < numRects; i++, rect++)
1399 {
1400 RECTANGLE_16 rect16;
1401 rect16.left = rect->x;
1402 rect16.top = rect->y;
1403 rect16.right = rect->x + rect->width;
1404 rect16.bottom = rect->y + rect->height;
1405
1406 if (!region16_union_rect(region, region, &rect16))
1407 return FALSE;
1408 }
1409
1410 return region16_intersect_rect(region, region, &mainRect);
1411 }
1412
1413 #define TILE_NO(v) ((v) / 64)
1414
setupWorkers(RFX_CONTEXT * context,int nbTiles)1415 static BOOL setupWorkers(RFX_CONTEXT* context, int nbTiles)
1416 {
1417 RFX_CONTEXT_PRIV* priv = context->priv;
1418 void* pmem;
1419
1420 if (!context->priv->UseThreads)
1421 return TRUE;
1422
1423 if (!(pmem = realloc((void*)priv->workObjects, sizeof(PTP_WORK) * nbTiles)))
1424 return FALSE;
1425
1426 priv->workObjects = (PTP_WORK*)pmem;
1427
1428 if (!(pmem =
1429 realloc((void*)priv->tileWorkParams, sizeof(RFX_TILE_COMPOSE_WORK_PARAM) * nbTiles)))
1430 return FALSE;
1431
1432 priv->tileWorkParams = (RFX_TILE_COMPOSE_WORK_PARAM*)pmem;
1433 return TRUE;
1434 }
1435
rfx_encode_message(RFX_CONTEXT * context,const RFX_RECT * rects,size_t numRects,const BYTE * data,UINT32 w,UINT32 h,size_t s)1436 RFX_MESSAGE* rfx_encode_message(RFX_CONTEXT* context, const RFX_RECT* rects, size_t numRects,
1437 const BYTE* data, UINT32 w, UINT32 h, size_t s)
1438 {
1439 const UINT32 width = (UINT32)w;
1440 const UINT32 height = (UINT32)h;
1441 const UINT32 scanline = (UINT32)s;
1442 UINT32 i, maxNbTiles, maxTilesX, maxTilesY;
1443 UINT32 xIdx, yIdx, regionNbRects;
1444 UINT32 gridRelX, gridRelY, ax, ay, bytesPerPixel;
1445 RFX_TILE* tile;
1446 RFX_RECT* rfxRect;
1447 RFX_MESSAGE* message = NULL;
1448 PTP_WORK* workObject = NULL;
1449 RFX_TILE_COMPOSE_WORK_PARAM* workParam = NULL;
1450 BOOL success = FALSE;
1451 REGION16 rectsRegion, tilesRegion;
1452 RECTANGLE_16 currentTileRect;
1453 const RECTANGLE_16* regionRect;
1454 const RECTANGLE_16* extents;
1455 assert(data);
1456 assert(rects);
1457 assert(numRects > 0);
1458 assert(w > 0);
1459 assert(h > 0);
1460 assert(s > 0);
1461
1462 if (!(message = (RFX_MESSAGE*)calloc(1, sizeof(RFX_MESSAGE))))
1463 return NULL;
1464
1465 region16_init(&tilesRegion);
1466 region16_init(&rectsRegion);
1467
1468 if (context->state == RFX_STATE_SEND_HEADERS)
1469 rfx_update_context_properties(context);
1470
1471 message->frameIdx = context->frameIdx++;
1472
1473 if (!context->numQuant)
1474 {
1475 if (!(context->quants = (UINT32*)malloc(sizeof(rfx_default_quantization_values))))
1476 goto skip_encoding_loop;
1477
1478 CopyMemory(context->quants, &rfx_default_quantization_values,
1479 sizeof(rfx_default_quantization_values));
1480 context->numQuant = 1;
1481 context->quantIdxY = 0;
1482 context->quantIdxCb = 0;
1483 context->quantIdxCr = 0;
1484 }
1485
1486 message->numQuant = context->numQuant;
1487 message->quantVals = context->quants;
1488 bytesPerPixel = (context->bits_per_pixel / 8);
1489
1490 if (!computeRegion(rects, numRects, &rectsRegion, width, height))
1491 goto skip_encoding_loop;
1492
1493 extents = region16_extents(&rectsRegion);
1494 assert(extents->right - extents->left > 0);
1495 assert(extents->bottom - extents->top > 0);
1496 maxTilesX = 1 + TILE_NO(extents->right - 1) - TILE_NO(extents->left);
1497 maxTilesY = 1 + TILE_NO(extents->bottom - 1) - TILE_NO(extents->top);
1498 maxNbTiles = maxTilesX * maxTilesY;
1499
1500 if (!(message->tiles = calloc(maxNbTiles, sizeof(RFX_TILE*))))
1501 goto skip_encoding_loop;
1502
1503 if (!setupWorkers(context, maxNbTiles))
1504 goto skip_encoding_loop;
1505
1506 if (context->priv->UseThreads)
1507 {
1508 workObject = context->priv->workObjects;
1509 workParam = context->priv->tileWorkParams;
1510 }
1511
1512 regionRect = region16_rects(&rectsRegion, ®ionNbRects);
1513
1514 if (!(message->rects = calloc(regionNbRects, sizeof(RFX_RECT))))
1515 goto skip_encoding_loop;
1516
1517 message->numRects = regionNbRects;
1518
1519 for (i = 0, rfxRect = message->rects; i < regionNbRects; i++, regionRect++, rfxRect++)
1520 {
1521 UINT32 startTileX = regionRect->left / 64;
1522 UINT32 endTileX = (regionRect->right - 1) / 64;
1523 UINT32 startTileY = regionRect->top / 64;
1524 UINT32 endTileY = (regionRect->bottom - 1) / 64;
1525 rfxRect->x = regionRect->left;
1526 rfxRect->y = regionRect->top;
1527 rfxRect->width = (regionRect->right - regionRect->left);
1528 rfxRect->height = (regionRect->bottom - regionRect->top);
1529
1530 for (yIdx = startTileY, gridRelY = startTileY * 64; yIdx <= endTileY;
1531 yIdx++, gridRelY += 64)
1532 {
1533 UINT32 tileHeight = 64;
1534
1535 if ((yIdx == endTileY) && (gridRelY + 64 > height))
1536 tileHeight = height - gridRelY;
1537
1538 currentTileRect.top = gridRelY;
1539 currentTileRect.bottom = gridRelY + tileHeight;
1540
1541 for (xIdx = startTileX, gridRelX = startTileX * 64; xIdx <= endTileX;
1542 xIdx++, gridRelX += 64)
1543 {
1544 int tileWidth = 64;
1545
1546 if ((xIdx == endTileX) && (gridRelX + 64 > width))
1547 tileWidth = width - gridRelX;
1548
1549 currentTileRect.left = gridRelX;
1550 currentTileRect.right = gridRelX + tileWidth;
1551
1552 /* checks if this tile is already treated */
1553 if (region16_intersects_rect(&tilesRegion, ¤tTileRect))
1554 continue;
1555
1556 if (!(tile = (RFX_TILE*)ObjectPool_Take(context->priv->TilePool)))
1557 goto skip_encoding_loop;
1558
1559 tile->xIdx = xIdx;
1560 tile->yIdx = yIdx;
1561 tile->x = gridRelX;
1562 tile->y = gridRelY;
1563 tile->scanline = scanline;
1564 tile->width = tileWidth;
1565 tile->height = tileHeight;
1566 ax = gridRelX;
1567 ay = gridRelY;
1568
1569 if (tile->data && tile->allocated)
1570 {
1571 free(tile->data);
1572 tile->allocated = FALSE;
1573 }
1574
1575 /* Cast away const */
1576 tile->data = (BYTE*)&data[(ay * scanline) + (ax * bytesPerPixel)];
1577 tile->quantIdxY = context->quantIdxY;
1578 tile->quantIdxCb = context->quantIdxCb;
1579 tile->quantIdxCr = context->quantIdxCr;
1580 tile->YLen = tile->CbLen = tile->CrLen = 0;
1581
1582 if (!(tile->YCbCrData = (BYTE*)BufferPool_Take(context->priv->BufferPool, -1)))
1583 goto skip_encoding_loop;
1584
1585 tile->YData = (BYTE*)&(tile->YCbCrData[((8192 + 32) * 0) + 16]);
1586 tile->CbData = (BYTE*)&(tile->YCbCrData[((8192 + 32) * 1) + 16]);
1587 tile->CrData = (BYTE*)&(tile->YCbCrData[((8192 + 32) * 2) + 16]);
1588 message->tiles[message->numTiles] = tile;
1589 message->numTiles++;
1590
1591 if (context->priv->UseThreads)
1592 {
1593 workParam->context = context;
1594 workParam->tile = tile;
1595
1596 if (!(*workObject = CreateThreadpoolWork(rfx_compose_message_tile_work_callback,
1597 (void*)workParam,
1598 &context->priv->ThreadPoolEnv)))
1599 {
1600 goto skip_encoding_loop;
1601 }
1602
1603 SubmitThreadpoolWork(*workObject);
1604 workObject++;
1605 workParam++;
1606 }
1607 else
1608 {
1609 rfx_encode_rgb(context, tile);
1610 }
1611
1612 if (!region16_union_rect(&tilesRegion, &tilesRegion, ¤tTileRect))
1613 goto skip_encoding_loop;
1614 } /* xIdx */
1615 } /* yIdx */
1616 } /* rects */
1617
1618 success = TRUE;
1619 skip_encoding_loop:
1620
1621 if (success && message->numTiles != maxNbTiles)
1622 {
1623 if (message->numTiles > 0)
1624 {
1625 void* pmem = realloc((void*)message->tiles, sizeof(RFX_TILE*) * message->numTiles);
1626
1627 if (pmem)
1628 message->tiles = (RFX_TILE**)pmem;
1629 else
1630 success = FALSE;
1631 }
1632 else
1633 success = FALSE;
1634 }
1635
1636 /* when using threads ensure all computations are done */
1637 if (success)
1638 {
1639 message->tilesDataSize = 0;
1640 workObject = context->priv->workObjects;
1641
1642 for (i = 0; i < message->numTiles; i++)
1643 {
1644 tile = message->tiles[i];
1645
1646 if (context->priv->UseThreads)
1647 {
1648 if (*workObject)
1649 {
1650 WaitForThreadpoolWorkCallbacks(*workObject, FALSE);
1651 CloseThreadpoolWork(*workObject);
1652 }
1653
1654 workObject++;
1655 }
1656
1657 message->tilesDataSize += rfx_tile_length(tile);
1658 }
1659
1660 region16_uninit(&tilesRegion);
1661 region16_uninit(&rectsRegion);
1662
1663 return message;
1664 }
1665
1666 WLog_ERR(TAG, "%s: failed", __FUNCTION__);
1667 message->freeRects = TRUE;
1668 rfx_message_free(context, message);
1669 return NULL;
1670 }
1671
rfx_split_message(RFX_CONTEXT * context,RFX_MESSAGE * message,size_t * numMessages,size_t maxDataSize)1672 static RFX_MESSAGE* rfx_split_message(RFX_CONTEXT* context, RFX_MESSAGE* message,
1673 size_t* numMessages, size_t maxDataSize)
1674 {
1675 size_t i, j;
1676 UINT32 tileDataSize;
1677 RFX_MESSAGE* messages;
1678 maxDataSize -= 1024; /* reserve enough space for headers */
1679 *numMessages = ((message->tilesDataSize + maxDataSize) / maxDataSize) * 4;
1680
1681 if (!(messages = (RFX_MESSAGE*)calloc((*numMessages), sizeof(RFX_MESSAGE))))
1682 return NULL;
1683
1684 j = 0;
1685
1686 for (i = 0; i < message->numTiles; i++)
1687 {
1688 tileDataSize = rfx_tile_length(message->tiles[i]);
1689
1690 if ((messages[j].tilesDataSize + tileDataSize) > ((UINT32)maxDataSize))
1691 j++;
1692
1693 if (!messages[j].numTiles)
1694 {
1695 messages[j].frameIdx = message->frameIdx + j;
1696 messages[j].numQuant = message->numQuant;
1697 messages[j].quantVals = message->quantVals;
1698 messages[j].numRects = message->numRects;
1699 messages[j].rects = message->rects;
1700 messages[j].freeRects = FALSE;
1701 messages[j].freeArray = TRUE;
1702
1703 if (!(messages[j].tiles = (RFX_TILE**)calloc(message->numTiles, sizeof(RFX_TILE*))))
1704 goto free_messages;
1705 }
1706
1707 messages[j].tilesDataSize += tileDataSize;
1708 messages[j].tiles[messages[j].numTiles++] = message->tiles[i];
1709 message->tiles[i] = NULL;
1710 }
1711
1712 *numMessages = j + 1;
1713 context->frameIdx += j;
1714 message->numTiles = 0;
1715 return messages;
1716 free_messages:
1717
1718 for (i = 0; i < j; i++)
1719 free(messages[i].tiles);
1720
1721 free(messages);
1722 return NULL;
1723 }
1724
rfx_encode_messages_ex(RFX_CONTEXT * context,const RFX_RECT * rects,size_t numRects,const BYTE * data,UINT32 width,UINT32 height,UINT32 scanline,size_t * numMessages,size_t maxDataSize)1725 RFX_MESSAGE* rfx_encode_messages_ex(RFX_CONTEXT* context, const RFX_RECT* rects, size_t numRects,
1726 const BYTE* data, UINT32 width, UINT32 height, UINT32 scanline,
1727 size_t* numMessages, size_t maxDataSize)
1728 {
1729 RFX_MESSAGE* message;
1730 RFX_MESSAGE* messageList;
1731
1732 if (!(message = rfx_encode_message(context, rects, numRects, data, width, height, scanline)))
1733 return NULL;
1734
1735 if (!(messageList = rfx_split_message(context, message, numMessages, maxDataSize)))
1736 {
1737 message->freeRects = TRUE;
1738 rfx_message_free(context, message);
1739 return NULL;
1740 }
1741
1742 rfx_message_free(context, message);
1743 return messageList;
1744 }
1745
rfx_write_message_tileset(RFX_CONTEXT * context,wStream * s,const RFX_MESSAGE * message)1746 static BOOL rfx_write_message_tileset(RFX_CONTEXT* context, wStream* s, const RFX_MESSAGE* message)
1747 {
1748 int i;
1749 RFX_TILE* tile;
1750 UINT32 blockLen;
1751 UINT32* quantVals;
1752 blockLen = 22 + (message->numQuant * 5) + message->tilesDataSize;
1753
1754 if (!Stream_EnsureRemainingCapacity(s, blockLen))
1755 return FALSE;
1756
1757 Stream_Write_UINT16(s, WBT_EXTENSION); /* CodecChannelT.blockType (2 bytes) */
1758 Stream_Write_UINT32(s, blockLen); /* set CodecChannelT.blockLen (4 bytes) */
1759 Stream_Write_UINT8(s, 1); /* CodecChannelT.codecId (1 byte) */
1760 Stream_Write_UINT8(s, 0); /* CodecChannelT.channelId (1 byte) */
1761 Stream_Write_UINT16(s, CBT_TILESET); /* subtype (2 bytes) */
1762 Stream_Write_UINT16(s, 0); /* idx (2 bytes) */
1763 Stream_Write_UINT16(s, context->properties); /* properties (2 bytes) */
1764 Stream_Write_UINT8(s, message->numQuant); /* numQuant (1 byte) */
1765 Stream_Write_UINT8(s, 0x40); /* tileSize (1 byte) */
1766 Stream_Write_UINT16(s, message->numTiles); /* numTiles (2 bytes) */
1767 Stream_Write_UINT32(s, message->tilesDataSize); /* tilesDataSize (4 bytes) */
1768 quantVals = message->quantVals;
1769
1770 for (i = 0; i < message->numQuant * 5; i++)
1771 {
1772 Stream_Write_UINT8(s, quantVals[0] + (quantVals[1] << 4));
1773 quantVals += 2;
1774 }
1775
1776 for (i = 0; i < message->numTiles; i++)
1777 {
1778 if (!(tile = message->tiles[i]))
1779 return FALSE;
1780
1781 if (!rfx_write_tile(context, s, tile))
1782 return FALSE;
1783 }
1784
1785 #ifdef WITH_DEBUG_RFX
1786 WLog_Print(context->priv->log, WLOG_DEBUG,
1787 "numQuant: %" PRIu16 " numTiles: %" PRIu16 " tilesDataSize: %" PRIu32 "",
1788 message->numQuant, message->numTiles, message->tilesDataSize);
1789 #endif
1790 return TRUE;
1791 }
1792
rfx_write_message_frame_begin(RFX_CONTEXT * context,wStream * s,const RFX_MESSAGE * message)1793 static BOOL rfx_write_message_frame_begin(RFX_CONTEXT* context, wStream* s,
1794 const RFX_MESSAGE* message)
1795 {
1796 if (!Stream_EnsureRemainingCapacity(s, 14))
1797 return FALSE;
1798
1799 Stream_Write_UINT16(s, WBT_FRAME_BEGIN); /* CodecChannelT.blockType */
1800 Stream_Write_UINT32(s, 14); /* CodecChannelT.blockLen */
1801 Stream_Write_UINT8(s, 1); /* CodecChannelT.codecId */
1802 Stream_Write_UINT8(s, 0); /* CodecChannelT.channelId */
1803 Stream_Write_UINT32(s, message->frameIdx); /* frameIdx */
1804 Stream_Write_UINT16(s, 1); /* numRegions */
1805 return TRUE;
1806 }
1807
rfx_write_message_region(RFX_CONTEXT * context,wStream * s,const RFX_MESSAGE * message)1808 static BOOL rfx_write_message_region(RFX_CONTEXT* context, wStream* s, const RFX_MESSAGE* message)
1809 {
1810 int i;
1811 UINT32 blockLen;
1812 blockLen = 15 + (message->numRects * 8);
1813
1814 if (!Stream_EnsureRemainingCapacity(s, blockLen))
1815 return FALSE;
1816
1817 Stream_Write_UINT16(s, WBT_REGION); /* CodecChannelT.blockType (2 bytes) */
1818 Stream_Write_UINT32(s, blockLen); /* set CodecChannelT.blockLen (4 bytes) */
1819 Stream_Write_UINT8(s, 1); /* CodecChannelT.codecId (1 byte) */
1820 Stream_Write_UINT8(s, 0); /* CodecChannelT.channelId (1 byte) */
1821 Stream_Write_UINT8(s, 1); /* regionFlags (1 byte) */
1822 Stream_Write_UINT16(s, message->numRects); /* numRects (2 bytes) */
1823
1824 for (i = 0; i < message->numRects; i++)
1825 {
1826 const RFX_RECT* rect = rfx_message_get_rect_const(message, i);
1827 /* Clipping rectangles are relative to destLeft, destTop */
1828 Stream_Write_UINT16(s, rect->x); /* x (2 bytes) */
1829 Stream_Write_UINT16(s, rect->y); /* y (2 bytes) */
1830 Stream_Write_UINT16(s, rect->width); /* width (2 bytes) */
1831 Stream_Write_UINT16(s, rect->height); /* height (2 bytes) */
1832 }
1833
1834 Stream_Write_UINT16(s, CBT_REGION); /* regionType (2 bytes) */
1835 Stream_Write_UINT16(s, 1); /* numTilesets (2 bytes) */
1836 return TRUE;
1837 }
1838
rfx_write_message_frame_end(RFX_CONTEXT * context,wStream * s,const RFX_MESSAGE * message)1839 static BOOL rfx_write_message_frame_end(RFX_CONTEXT* context, wStream* s,
1840 const RFX_MESSAGE* message)
1841 {
1842 if (!Stream_EnsureRemainingCapacity(s, 8))
1843 return FALSE;
1844
1845 Stream_Write_UINT16(s, WBT_FRAME_END); /* CodecChannelT.blockType */
1846 Stream_Write_UINT32(s, 8); /* CodecChannelT.blockLen */
1847 Stream_Write_UINT8(s, 1); /* CodecChannelT.codecId */
1848 Stream_Write_UINT8(s, 0); /* CodecChannelT.channelId */
1849 return TRUE;
1850 }
1851
rfx_write_message(RFX_CONTEXT * context,wStream * s,const RFX_MESSAGE * message)1852 BOOL rfx_write_message(RFX_CONTEXT* context, wStream* s, const RFX_MESSAGE* message)
1853 {
1854 if (context->state == RFX_STATE_SEND_HEADERS)
1855 {
1856 if (!rfx_compose_message_header(context, s))
1857 return FALSE;
1858
1859 context->state = RFX_STATE_SEND_FRAME_DATA;
1860 }
1861
1862 if (!rfx_write_message_frame_begin(context, s, message) ||
1863 !rfx_write_message_region(context, s, message) ||
1864 !rfx_write_message_tileset(context, s, message) ||
1865 !rfx_write_message_frame_end(context, s, message))
1866 {
1867 return FALSE;
1868 }
1869
1870 return TRUE;
1871 }
1872
rfx_compose_message(RFX_CONTEXT * context,wStream * s,const RFX_RECT * rects,size_t numRects,const BYTE * data,UINT32 width,UINT32 height,UINT32 scanline)1873 BOOL rfx_compose_message(RFX_CONTEXT* context, wStream* s, const RFX_RECT* rects, size_t numRects,
1874 const BYTE* data, UINT32 width, UINT32 height, UINT32 scanline)
1875 {
1876 RFX_MESSAGE* message;
1877 BOOL ret = TRUE;
1878
1879 if (!(message = rfx_encode_message(context, rects, numRects, data, width, height, scanline)))
1880 return FALSE;
1881
1882 ret = rfx_write_message(context, s, message);
1883 message->freeRects = TRUE;
1884 rfx_message_free(context, message);
1885 return ret;
1886 }
1887
rfx_encode_messages(RFX_CONTEXT * context,const RFX_RECT * rects,int numRects,const BYTE * data,int width,int height,int scanline,int * numMessages,int maxDataSize)1888 RFX_MESSAGE* rfx_encode_messages(RFX_CONTEXT* context, const RFX_RECT* rects, int numRects,
1889 const BYTE* data, int width, int height, int scanline,
1890 int* numMessages, int maxDataSize)
1891 {
1892 size_t tmp;
1893 RFX_MESSAGE* msg = rfx_encode_messages_ex(context, rects, numRects, data, width, height,
1894 scanline, &tmp, maxDataSize);
1895 if (numMessages)
1896 *numMessages = tmp;
1897 return msg;
1898 }
1899