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*)&params[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, &regionNbRects);
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, &currentTileRect))
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, &currentTileRect))
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