Initial commit - from Precise source
[freerdp-ubuntu-pcb-backport.git] / libfreerdp-codec / rfx.c
1 /**
2  * FreeRDP: A Remote Desktop Protocol client.
3  * RemoteFX Codec Library
4  *
5  * Copyright 2011 Vic Lee
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *     http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <stdint.h>
24 #include <freerdp/codec/rfx.h>
25 #include <freerdp/utils/memory.h>
26 #include <freerdp/constants.h>
27
28 #include "rfx_constants.h"
29 #include "rfx_types.h"
30 #include "rfx_pool.h"
31 #include "rfx_decode.h"
32 #include "rfx_encode.h"
33 #include "rfx_quantization.h"
34 #include "rfx_dwt.h"
35
36 #ifdef WITH_SSE2
37 #include "rfx_sse2.h"
38 #endif
39
40 #ifdef WITH_NEON
41 #include "rfx_neon.h"
42 #endif
43
44 #ifndef RFX_INIT_SIMD
45 #define RFX_INIT_SIMD(_rfx_context) do { } while (0)
46 #endif
47
48 /**
49  * The quantization values control the compression rate and quality. The value
50  * range is between 6 and 15. The higher value, the higher compression rate
51  * and lower quality.
52  *
53  * This is the default values being use by the MS RDP server, and we will also
54  * use it as our default values for the encoder. It can be overrided by setting
55  * the context->num_quants and context->quants member.
56  *
57  * The order of the values are:
58  * LL3, LH3, HL3, HH3, LH2, HL2, HH2, LH1, HL1, HH1
59  */
60 static const uint32 rfx_default_quantization_values[] =
61 {
62         6, 6, 6, 6, 7, 7, 8, 8, 8, 9
63 };
64
65 static void rfx_profiler_create(RFX_CONTEXT* context)
66 {
67         PROFILER_CREATE(context->priv->prof_rfx_decode_rgb, "rfx_decode_rgb");
68         PROFILER_CREATE(context->priv->prof_rfx_decode_component, "rfx_decode_component");
69         PROFILER_CREATE(context->priv->prof_rfx_rlgr_decode, "rfx_rlgr_decode");
70         PROFILER_CREATE(context->priv->prof_rfx_differential_decode, "rfx_differential_decode");
71         PROFILER_CREATE(context->priv->prof_rfx_quantization_decode, "rfx_quantization_decode");
72         PROFILER_CREATE(context->priv->prof_rfx_dwt_2d_decode, "rfx_dwt_2d_decode");
73         PROFILER_CREATE(context->priv->prof_rfx_decode_ycbcr_to_rgb, "rfx_decode_ycbcr_to_rgb");
74         PROFILER_CREATE(context->priv->prof_rfx_decode_format_rgb, "rfx_decode_format_rgb");
75
76         PROFILER_CREATE(context->priv->prof_rfx_encode_rgb, "rfx_encode_rgb");
77         PROFILER_CREATE(context->priv->prof_rfx_encode_component, "rfx_encode_component");
78         PROFILER_CREATE(context->priv->prof_rfx_rlgr_encode, "rfx_rlgr_encode");
79         PROFILER_CREATE(context->priv->prof_rfx_differential_encode, "rfx_differential_encode");
80         PROFILER_CREATE(context->priv->prof_rfx_quantization_encode, "rfx_quantization_encode");
81         PROFILER_CREATE(context->priv->prof_rfx_dwt_2d_encode, "rfx_dwt_2d_encode");
82         PROFILER_CREATE(context->priv->prof_rfx_encode_rgb_to_ycbcr, "rfx_encode_rgb_to_ycbcr");
83         PROFILER_CREATE(context->priv->prof_rfx_encode_format_rgb, "rfx_encode_format_rgb");
84 }
85
86 static void rfx_profiler_free(RFX_CONTEXT* context)
87 {
88         PROFILER_FREE(context->priv->prof_rfx_decode_rgb);
89         PROFILER_FREE(context->priv->prof_rfx_decode_component);
90         PROFILER_FREE(context->priv->prof_rfx_rlgr_decode);
91         PROFILER_FREE(context->priv->prof_rfx_differential_decode);
92         PROFILER_FREE(context->priv->prof_rfx_quantization_decode);
93         PROFILER_FREE(context->priv->prof_rfx_dwt_2d_decode);
94         PROFILER_FREE(context->priv->prof_rfx_decode_ycbcr_to_rgb);
95         PROFILER_FREE(context->priv->prof_rfx_decode_format_rgb);
96
97         PROFILER_FREE(context->priv->prof_rfx_encode_rgb);
98         PROFILER_FREE(context->priv->prof_rfx_encode_component);
99         PROFILER_FREE(context->priv->prof_rfx_rlgr_encode);
100         PROFILER_FREE(context->priv->prof_rfx_differential_encode);
101         PROFILER_FREE(context->priv->prof_rfx_quantization_encode);
102         PROFILER_FREE(context->priv->prof_rfx_dwt_2d_encode);
103         PROFILER_FREE(context->priv->prof_rfx_encode_rgb_to_ycbcr);
104         PROFILER_FREE(context->priv->prof_rfx_encode_format_rgb);
105 }
106
107 static void rfx_profiler_print(RFX_CONTEXT* context)
108 {
109         PROFILER_PRINT_HEADER;
110
111         PROFILER_PRINT(context->priv->prof_rfx_decode_rgb);
112         PROFILER_PRINT(context->priv->prof_rfx_decode_component);
113         PROFILER_PRINT(context->priv->prof_rfx_rlgr_decode);
114         PROFILER_PRINT(context->priv->prof_rfx_differential_decode);
115         PROFILER_PRINT(context->priv->prof_rfx_quantization_decode);
116         PROFILER_PRINT(context->priv->prof_rfx_dwt_2d_decode);
117         PROFILER_PRINT(context->priv->prof_rfx_decode_ycbcr_to_rgb);
118         PROFILER_PRINT(context->priv->prof_rfx_decode_format_rgb);
119
120         PROFILER_PRINT(context->priv->prof_rfx_encode_rgb);
121         PROFILER_PRINT(context->priv->prof_rfx_encode_component);
122         PROFILER_PRINT(context->priv->prof_rfx_rlgr_encode);
123         PROFILER_PRINT(context->priv->prof_rfx_differential_encode);
124         PROFILER_PRINT(context->priv->prof_rfx_quantization_encode);
125         PROFILER_PRINT(context->priv->prof_rfx_dwt_2d_encode);
126         PROFILER_PRINT(context->priv->prof_rfx_encode_rgb_to_ycbcr);
127         PROFILER_PRINT(context->priv->prof_rfx_encode_format_rgb);
128
129         PROFILER_PRINT_FOOTER;
130 }
131
132 RFX_CONTEXT* rfx_context_new(void)
133 {
134         RFX_CONTEXT* context;
135
136         context = xnew(RFX_CONTEXT);
137         context->priv = xnew(RFX_CONTEXT_PRIV);
138         context->priv->pool = rfx_pool_new();
139
140         /* initialize the default pixel format */
141         rfx_context_set_pixel_format(context, RFX_PIXEL_FORMAT_BGRA);
142
143         /* align buffers to 16 byte boundary (needed for SSE/SSE2 instructions) */
144         context->priv->y_r_buffer = (sint16*)(((uintptr_t)context->priv->y_r_mem + 16) & ~ 0x0F);
145         context->priv->cb_g_buffer = (sint16*)(((uintptr_t)context->priv->cb_g_mem + 16) & ~ 0x0F);
146         context->priv->cr_b_buffer = (sint16*)(((uintptr_t)context->priv->cr_b_mem + 16) & ~ 0x0F);
147
148         context->priv->dwt_buffer = (sint16*)(((uintptr_t)context->priv->dwt_mem + 16) & ~ 0x0F);
149
150         /* create profilers for default decoding routines */
151         rfx_profiler_create(context);
152         
153         /* set up default routines */
154         context->decode_ycbcr_to_rgb = rfx_decode_ycbcr_to_rgb;
155         context->encode_rgb_to_ycbcr = rfx_encode_rgb_to_ycbcr;
156         context->quantization_decode = rfx_quantization_decode; 
157         context->quantization_encode = rfx_quantization_encode; 
158         context->dwt_2d_decode = rfx_dwt_2d_decode;
159         context->dwt_2d_encode = rfx_dwt_2d_encode;
160
161         return context;
162 }
163
164 void rfx_context_set_cpu_opt(RFX_CONTEXT* context, uint32 cpu_opt)
165 {
166         /* enable SIMD CPU acceleration if detected */
167         if (cpu_opt & CPU_SSE2)
168                 RFX_INIT_SIMD(context);
169 }
170
171 void rfx_context_free(RFX_CONTEXT* context)
172 {
173         xfree(context->quants);
174
175         rfx_pool_free(context->priv->pool);
176
177         rfx_profiler_print(context);
178         rfx_profiler_free(context);
179
180         xfree(context->priv);
181         xfree(context);
182 }
183
184 void rfx_context_set_pixel_format(RFX_CONTEXT* context, RFX_PIXEL_FORMAT pixel_format)
185 {
186         context->pixel_format = pixel_format;
187         switch (pixel_format)
188         {
189                 case RFX_PIXEL_FORMAT_BGRA:
190                 case RFX_PIXEL_FORMAT_RGBA:
191                         context->bits_per_pixel = 32;
192                         break;
193                 case RFX_PIXEL_FORMAT_BGR:
194                 case RFX_PIXEL_FORMAT_RGB:
195                         context->bits_per_pixel = 24;
196                         break;
197                 case RFX_PIXEL_FORMAT_BGR565_LE:
198                 case RFX_PIXEL_FORMAT_RGB565_LE:
199                         context->bits_per_pixel = 16;
200                         break;
201                 case RFX_PIXEL_FORMAT_PALETTE4_PLANER:
202                         context->bits_per_pixel = 4;
203                         break;
204                 case RFX_PIXEL_FORMAT_PALETTE8:
205                         context->bits_per_pixel = 8;
206                         break;
207                 default:
208                         context->bits_per_pixel = 0;
209                         break;
210         }
211 }
212
213 void rfx_context_reset(RFX_CONTEXT* context)
214 {
215         context->header_processed = false;
216         context->frame_idx = 0;
217 }
218
219 static void rfx_process_message_sync(RFX_CONTEXT* context, STREAM* s)
220 {
221         uint32 magic;
222
223         /* RFX_SYNC */
224         stream_read_uint32(s, magic); /* magic (4 bytes), 0xCACCACCA */
225
226         if (magic != WF_MAGIC)
227         {
228                 DEBUG_WARN("invalid magic number 0x%X", magic);
229                 return;
230         }
231
232         stream_read_uint16(s, context->version); /* version (2 bytes), WF_VERSION_1_0 (0x0100) */
233
234         if (context->version != WF_VERSION_1_0)
235         {
236                 DEBUG_WARN("unknown version number 0x%X", context->version);
237                 return;
238         }
239
240         DEBUG_RFX("version 0x%X", context->version);
241 }
242
243 static void rfx_process_message_codec_versions(RFX_CONTEXT* context, STREAM* s)
244 {
245         uint8 numCodecs;
246
247         stream_read_uint8(s, numCodecs); /* numCodecs (1 byte), must be set to 0x01 */
248
249         if (numCodecs != 1)
250         {
251                 DEBUG_WARN("numCodecs: %d, expected:1", numCodecs);
252                 return;
253         }
254
255         /* RFX_CODEC_VERSIONT */
256         stream_read_uint8(s, context->codec_id); /* codecId (1 byte) */
257         stream_read_uint8(s, context->codec_version); /* version (2 bytes) */
258
259         DEBUG_RFX("id %d version 0x%X.", context->codec_id, context->codec_version);
260 }
261
262 static void rfx_process_message_channels(RFX_CONTEXT* context, STREAM* s)
263 {
264         uint8 channelId;
265         uint8 numChannels;
266
267         stream_read_uint8(s, numChannels); /* numChannels (1 byte), must bet set to 0x01 */
268
269         /* In RDVH sessions, numChannels will represent the number of virtual monitors 
270          * configured and does not always be set to 0x01 as [MS-RDPRFX] said.
271          */
272         if (numChannels < 1)
273         {
274                 DEBUG_WARN("numChannels:%d, expected:1", numChannels);
275                 return;
276         }
277
278         /* RFX_CHANNELT */
279         stream_read_uint8(s, channelId); /* channelId (1 byte) */
280         stream_read_uint16(s, context->width); /* width (2 bytes) */
281         stream_read_uint16(s, context->height); /* height (2 bytes) */
282
283         /* Now, only the first monitor can be used, therefore the other channels will be ignored. */
284         stream_seek(s, 5 * (numChannels - 1));
285
286         DEBUG_RFX("numChannels %d id %d, %dx%d.",
287                 numChannels, channelId, context->width, context->height);
288 }
289
290 static void rfx_process_message_context(RFX_CONTEXT* context, STREAM* s)
291 {
292         uint8 ctxId;
293         uint16 tileSize;
294         uint16 properties;
295
296         stream_read_uint8(s, ctxId); /* ctxId (1 byte), must be set to 0x00 */
297         stream_read_uint16(s, tileSize); /* tileSize (2 bytes), must be set to CT_TILE_64x64 (0x0040) */
298         stream_read_uint16(s, properties); /* properties (2 bytes) */
299
300         DEBUG_RFX("ctxId %d tileSize %d properties 0x%X.", ctxId, tileSize, properties);
301
302         context->properties = properties;
303         context->flags = (properties & 0x0007);
304
305         if (context->flags == CODEC_MODE)
306                 DEBUG_RFX("codec is in image mode.");
307         else
308                 DEBUG_RFX("codec is in video mode.");
309
310         switch ((properties & 0x1E00) >> 9)
311         {
312                 case CLW_ENTROPY_RLGR1:
313                         context->mode = RLGR1;
314                         DEBUG_RFX("RLGR1.");
315                         break;
316
317                 case CLW_ENTROPY_RLGR3:
318                         context->mode = RLGR3;
319                         DEBUG_RFX("RLGR3.");
320                         break;
321
322                 default:
323                         DEBUG_WARN("unknown RLGR algorithm.");
324                         break;
325         }
326 }
327
328 static void rfx_process_message_frame_begin(RFX_CONTEXT* context, RFX_MESSAGE* message, STREAM* s)
329 {
330         uint32 frameIdx;
331         uint16 numRegions;
332
333         stream_read_uint32(s, frameIdx); /* frameIdx (4 bytes), if codec is in video mode, must be ignored */
334         stream_read_uint16(s, numRegions); /* numRegions (2 bytes) */
335
336         DEBUG_RFX("RFX_FRAME_BEGIN: frameIdx:%d numRegions:%d", frameIdx, numRegions);
337 }
338
339 static void rfx_process_message_frame_end(RFX_CONTEXT* context, RFX_MESSAGE* message, STREAM* s)
340 {
341         DEBUG_RFX("RFX_FRAME_END");
342 }
343
344 static void rfx_process_message_region(RFX_CONTEXT* context, RFX_MESSAGE* message, STREAM* s)
345 {
346         int i;
347
348         stream_seek_uint8(s); /* regionFlags (1 byte) */
349         stream_read_uint16(s, message->num_rects); /* numRects (2 bytes) */
350
351         if (message->num_rects < 1)
352         {
353                 DEBUG_WARN("no rects.");
354                 return;
355         }
356
357         if (message->rects != NULL)
358                 message->rects = (RFX_RECT*) xrealloc(message->rects, message->num_rects * sizeof(RFX_RECT));
359         else
360                 message->rects = (RFX_RECT*) xmalloc(message->num_rects * sizeof(RFX_RECT));
361
362         /* rects */
363         for (i = 0; i < message->num_rects; i++)
364         {
365                 /* RFX_RECT */
366                 stream_read_uint16(s, message->rects[i].x); /* x (2 bytes) */
367                 stream_read_uint16(s, message->rects[i].y); /* y (2 bytes) */
368                 stream_read_uint16(s, message->rects[i].width); /* width (2 bytes) */
369                 stream_read_uint16(s, message->rects[i].height); /* height (2 bytes) */
370
371                 DEBUG_RFX("rect %d (%d %d %d %d).",
372                         i, message->rects[i].x, message->rects[i].y, message->rects[i].width, message->rects[i].height);
373         }
374 }
375
376 static void rfx_process_message_tile(RFX_CONTEXT* context, RFX_TILE* tile, STREAM* s)
377 {
378         uint8 quantIdxY;
379         uint8 quantIdxCb;
380         uint8 quantIdxCr;
381         uint16 xIdx, yIdx;
382         uint16 YLen, CbLen, CrLen;
383
384         /* RFX_TILE */
385         stream_read_uint8(s, quantIdxY); /* quantIdxY (1 byte) */
386         stream_read_uint8(s, quantIdxCb); /* quantIdxCb (1 byte) */
387         stream_read_uint8(s, quantIdxCr); /* quantIdxCr (1 byte) */
388         stream_read_uint16(s, xIdx); /* xIdx (2 bytes) */
389         stream_read_uint16(s, yIdx); /* yIdx (2 bytes) */
390         stream_read_uint16(s, YLen); /* YLen (2 bytes) */
391         stream_read_uint16(s, CbLen); /* CbLen (2 bytes) */
392         stream_read_uint16(s, CrLen); /* CrLen (2 bytes) */
393
394         DEBUG_RFX("quantIdxY:%d quantIdxCb:%d quantIdxCr:%d xIdx:%d yIdx:%d YLen:%d CbLen:%d CrLen:%d",
395                 quantIdxY, quantIdxCb, quantIdxCr, xIdx, yIdx, YLen, CbLen, CrLen);
396
397         tile->x = xIdx * 64;
398         tile->y = yIdx * 64;
399
400         rfx_decode_rgb(context, s,
401                 YLen, context->quants + (quantIdxY * 10),
402                 CbLen, context->quants + (quantIdxCb * 10),
403                 CrLen, context->quants + (quantIdxCr * 10),
404                 tile->data);
405 }
406
407 static void rfx_process_message_tileset(RFX_CONTEXT* context, RFX_MESSAGE* message, STREAM* s)
408 {
409         int i;
410         uint16 subtype;
411         uint32 blockLen;
412         uint32 blockType;
413         uint32 tilesDataSize;
414         uint32* quants;
415         uint8 quant;
416         int pos;
417
418         stream_read_uint16(s, subtype); /* subtype (2 bytes) must be set to CBT_TILESET (0xCAC2) */
419
420         if (subtype != CBT_TILESET)
421         {
422                 DEBUG_WARN("invalid subtype, expected CBT_TILESET.");
423                 return;
424         }
425
426         stream_seek_uint16(s); /* idx (2 bytes), must be set to 0x0000 */
427         stream_seek_uint16(s); /* properties (2 bytes) */
428
429         stream_read_uint8(s, context->num_quants); /* numQuant (1 byte) */
430         stream_seek_uint8(s); /* tileSize (1 byte), must be set to 0x40 */
431
432         if (context->num_quants < 1)
433         {
434                 DEBUG_WARN("no quantization value.");
435                 return;
436         }
437
438         stream_read_uint16(s, message->num_tiles); /* numTiles (2 bytes) */
439
440         if (message->num_tiles < 1)
441         {
442                 DEBUG_WARN("no tiles.");
443                 return;
444         }
445
446         stream_read_uint32(s, tilesDataSize); /* tilesDataSize (4 bytes) */
447
448         if (context->quants != NULL)
449                 context->quants = (uint32*) xrealloc((void*) context->quants, context->num_quants * 10 * sizeof(uint32));
450         else
451                 context->quants = (uint32*) xmalloc(context->num_quants * 10 * sizeof(uint32));
452         quants = context->quants;
453
454         /* quantVals */
455         for (i = 0; i < context->num_quants; i++)
456         {
457                 /* RFX_CODEC_QUANT */
458                 stream_read_uint8(s, quant);
459                 *quants++ = (quant & 0x0F);
460                 *quants++ = (quant >> 4);
461                 stream_read_uint8(s, quant);
462                 *quants++ = (quant & 0x0F);
463                 *quants++ = (quant >> 4);
464                 stream_read_uint8(s, quant);
465                 *quants++ = (quant & 0x0F);
466                 *quants++ = (quant >> 4);
467                 stream_read_uint8(s, quant);
468                 *quants++ = (quant & 0x0F);
469                 *quants++ = (quant >> 4);
470                 stream_read_uint8(s, quant);
471                 *quants++ = (quant & 0x0F);
472                 *quants++ = (quant >> 4);
473
474                 DEBUG_RFX("quant %d (%d %d %d %d %d %d %d %d %d %d).",
475                         i, context->quants[i * 10], context->quants[i * 10 + 1],
476                         context->quants[i * 10 + 2], context->quants[i * 10 + 3],
477                         context->quants[i * 10 + 4], context->quants[i * 10 + 5],
478                         context->quants[i * 10 + 6], context->quants[i * 10 + 7],
479                         context->quants[i * 10 + 8], context->quants[i * 10 + 9]);
480         }
481
482         message->tiles = rfx_pool_get_tiles(context->priv->pool, message->num_tiles);
483
484         /* tiles */
485         for (i = 0; i < message->num_tiles; i++)
486         {
487                 /* RFX_TILE */
488                 stream_read_uint16(s, blockType); /* blockType (2 bytes), must be set to CBT_TILE (0xCAC3) */
489                 stream_read_uint32(s, blockLen); /* blockLen (4 bytes) */
490
491                 pos = stream_get_pos(s) - 6 + blockLen;
492
493                 if (blockType != CBT_TILE)
494                 {
495                         DEBUG_WARN("unknown block type 0x%X, expected CBT_TILE (0xCAC3).", blockType);
496                         break;
497                 }
498
499                 rfx_process_message_tile(context, message->tiles[i], s);
500
501                 stream_set_pos(s, pos);
502         }
503 }
504
505 RFX_MESSAGE* rfx_process_message(RFX_CONTEXT* context, uint8* data, uint32 length)
506 {
507         int pos;
508         STREAM* s;
509         uint32 blockLen;
510         uint32 blockType;
511         RFX_MESSAGE* message;
512
513         s = stream_new(0);
514         message = xnew(RFX_MESSAGE);
515         stream_attach(s, data, length);
516
517         while (stream_get_left(s) > 6)
518         {
519                 /* RFX_BLOCKT */
520                 stream_read_uint16(s, blockType); /* blockType (2 bytes) */
521                 stream_read_uint32(s, blockLen); /* blockLen (4 bytes) */
522
523                 DEBUG_RFX("blockType 0x%X blockLen %d", blockType, blockLen);
524
525                 if (blockLen == 0)
526                 {
527                         DEBUG_WARN("zero blockLen");
528                         break;
529                 }
530
531                 pos = stream_get_pos(s) - 6 + blockLen;
532
533                 if (blockType >= WBT_CONTEXT && blockType <= WBT_EXTENSION)
534                 {
535                         /* RFX_CODEC_CHANNELT */
536                         /* codecId (1 byte) must be set to 0x01 */
537                         /* channelId (1 byte) must be set to 0x00 */
538                         stream_seek(s, 2);
539                 }
540
541                 switch (blockType)
542                 {
543                         case WBT_SYNC:
544                                 rfx_process_message_sync(context, s);
545                                 break;
546
547                         case WBT_CODEC_VERSIONS:
548                                 rfx_process_message_codec_versions(context, s);
549                                 break;
550
551                         case WBT_CHANNELS:
552                                 rfx_process_message_channels(context, s);
553                                 break;
554
555                         case WBT_CONTEXT:
556                                 rfx_process_message_context(context, s);
557                                 break;
558
559                         case WBT_FRAME_BEGIN:
560                                 rfx_process_message_frame_begin(context, message, s);
561                                 break;
562
563                         case WBT_FRAME_END:
564                                 rfx_process_message_frame_end(context, message, s);
565                                 break;
566
567                         case WBT_REGION:
568                                 rfx_process_message_region(context, message, s);
569                                 break;
570
571                         case WBT_EXTENSION:
572                                 rfx_process_message_tileset(context, message, s);
573                                 break;
574
575                         default:
576                                 DEBUG_WARN("unknown blockType 0x%X", blockType);
577                                 break;
578                 }
579
580                 stream_set_pos(s, pos);
581         }
582
583         stream_detach(s);
584         stream_free(s);
585
586         return message;
587 }
588
589 uint16 rfx_message_get_tile_count(RFX_MESSAGE* message)
590 {
591         return message->num_tiles;
592 }
593
594 RFX_TILE* rfx_message_get_tile(RFX_MESSAGE* message, int index)
595 {
596         return message->tiles[index];
597 }
598
599 uint16 rfx_message_get_rect_count(RFX_MESSAGE* message)
600 {
601         return message->num_rects;
602 }
603
604 RFX_RECT* rfx_message_get_rect(RFX_MESSAGE* message, int index)
605 {
606         return &message->rects[index];
607 }
608
609 void rfx_message_free(RFX_CONTEXT* context, RFX_MESSAGE* message)
610 {
611         if (message != NULL)
612         {
613                 xfree(message->rects);
614
615                 if (message->tiles != NULL)
616                 {
617                         rfx_pool_put_tiles(context->priv->pool, message->tiles, message->num_tiles);
618                         xfree(message->tiles);
619                 }
620
621                 xfree(message);
622         }
623 }
624
625 static void rfx_compose_message_sync(RFX_CONTEXT* context, STREAM* s)
626 {
627         stream_write_uint16(s, WBT_SYNC); /* BlockT.blockType */
628         stream_write_uint32(s, 12); /* BlockT.blockLen */
629         stream_write_uint32(s, WF_MAGIC); /* magic */
630         stream_write_uint16(s, WF_VERSION_1_0); /* version */
631 }
632
633 static void rfx_compose_message_codec_versions(RFX_CONTEXT* context, STREAM* s)
634 {
635         stream_write_uint16(s, WBT_CODEC_VERSIONS); /* BlockT.blockType */
636         stream_write_uint32(s, 10); /* BlockT.blockLen */
637         stream_write_uint8(s, 1); /* numCodecs */
638         stream_write_uint8(s, 1); /* codecs.codecId */
639         stream_write_uint16(s, WF_VERSION_1_0); /* codecs.version */
640 }
641
642 static void rfx_compose_message_channels(RFX_CONTEXT* context, STREAM* s)
643 {
644         stream_write_uint16(s, WBT_CHANNELS); /* BlockT.blockType */
645         stream_write_uint32(s, 12); /* BlockT.blockLen */
646         stream_write_uint8(s, 1); /* numChannels */
647         stream_write_uint8(s, 0); /* Channel.channelId */
648         stream_write_uint16(s, context->width); /* Channel.width */
649         stream_write_uint16(s, context->height); /* Channel.height */
650 }
651
652 static void rfx_compose_message_context(RFX_CONTEXT* context, STREAM* s)
653 {
654         uint16 properties;
655
656         stream_write_uint16(s, WBT_CONTEXT); /* CodecChannelT.blockType */
657         stream_write_uint32(s, 13); /* CodecChannelT.blockLen */
658         stream_write_uint8(s, 1); /* CodecChannelT.codecId */
659         stream_write_uint8(s, 0); /* CodecChannelT.channelId */
660         stream_write_uint8(s, 0); /* ctxId */
661         stream_write_uint16(s, CT_TILE_64x64); /* tileSize */
662
663         /* properties */
664         properties = context->flags; /* flags */
665         properties |= (COL_CONV_ICT << 3); /* cct */
666         properties |= (CLW_XFORM_DWT_53_A << 5); /* xft */
667         properties |= ((context->mode == RLGR1 ? CLW_ENTROPY_RLGR1 : CLW_ENTROPY_RLGR3) << 9); /* et */
668         properties |= (SCALAR_QUANTIZATION << 13); /* qt */
669         stream_write_uint16(s, properties);
670
671         /* properties in tilesets: note that this has different format from the one in TS_RFX_CONTEXT */
672         properties = 1; /* lt */
673         properties |= (context->flags << 1); /* flags */
674         properties |= (COL_CONV_ICT << 4); /* cct */
675         properties |= (CLW_XFORM_DWT_53_A << 6); /* xft */
676         properties |= ((context->mode == RLGR1 ? CLW_ENTROPY_RLGR1 : CLW_ENTROPY_RLGR3) << 10); /* et */
677         properties |= (SCALAR_QUANTIZATION << 14); /* qt */
678         context->properties = properties;
679 }
680
681 void rfx_compose_message_header(RFX_CONTEXT* context, STREAM* s)
682 {
683         stream_check_size(s, 12 + 10 + 12 + 13);
684
685         rfx_compose_message_sync(context, s);
686         rfx_compose_message_context(context, s);
687         rfx_compose_message_codec_versions(context, s);
688         rfx_compose_message_channels(context, s);
689
690         context->header_processed = true;
691 }
692
693 static void rfx_compose_message_frame_begin(RFX_CONTEXT* context, STREAM* s)
694 {
695         stream_check_size(s, 14);
696
697         stream_write_uint16(s, WBT_FRAME_BEGIN); /* CodecChannelT.blockType */
698         stream_write_uint32(s, 14); /* CodecChannelT.blockLen */
699         stream_write_uint8(s, 1); /* CodecChannelT.codecId */
700         stream_write_uint8(s, 0); /* CodecChannelT.channelId */
701         stream_write_uint32(s, context->frame_idx); /* frameIdx */
702         stream_write_uint16(s, 1); /* numRegions */
703
704         context->frame_idx++;
705 }
706
707 static void rfx_compose_message_region(RFX_CONTEXT* context, STREAM* s,
708         const RFX_RECT* rects, int num_rects)
709 {
710         int size;
711         int i;
712
713         size = 15 + num_rects * 8;
714         stream_check_size(s, size);
715
716         stream_write_uint16(s, WBT_REGION); /* CodecChannelT.blockType */
717         stream_write_uint32(s, size); /* set CodecChannelT.blockLen later */
718         stream_write_uint8(s, 1); /* CodecChannelT.codecId */
719         stream_write_uint8(s, 0); /* CodecChannelT.channelId */
720         stream_write_uint8(s, 1); /* regionFlags */
721         stream_write_uint16(s, num_rects); /* numRects */
722
723         for (i = 0; i < num_rects; i++)
724         {
725                 stream_write_uint16(s, rects[i].x);
726                 stream_write_uint16(s, rects[i].y);
727                 stream_write_uint16(s, rects[i].width);
728                 stream_write_uint16(s, rects[i].height);
729         }
730
731         stream_write_uint16(s, CBT_REGION); /* regionType */
732         stream_write_uint16(s, 1); /* numTilesets */
733 }
734
735 static void rfx_compose_message_tile(RFX_CONTEXT* context, STREAM* s,
736         uint8* tile_data, int tile_width, int tile_height, int rowstride,
737         const uint32* quantVals, int quantIdxY, int quantIdxCb, int quantIdxCr,
738         int xIdx, int yIdx)
739 {
740         int YLen = 0;
741         int CbLen = 0;
742         int CrLen = 0;
743         int start_pos, end_pos;
744
745         stream_check_size(s, 19);
746         start_pos = stream_get_pos(s);
747
748         stream_write_uint16(s, CBT_TILE); /* BlockT.blockType */
749         stream_seek_uint32(s); /* set BlockT.blockLen later */
750         stream_write_uint8(s, quantIdxY);
751         stream_write_uint8(s, quantIdxCb);
752         stream_write_uint8(s, quantIdxCr);
753         stream_write_uint16(s, xIdx);
754         stream_write_uint16(s, yIdx);
755
756         stream_seek(s, 6); /* YLen, CbLen, CrLen */
757
758         rfx_encode_rgb(context, tile_data, tile_width, tile_height, rowstride,
759                 quantVals + quantIdxY * 10, quantVals + quantIdxCb * 10, quantVals + quantIdxCr * 10,
760                 s, &YLen, &CbLen, &CrLen);
761
762         DEBUG_RFX("xIdx=%d yIdx=%d width=%d height=%d YLen=%d CbLen=%d CrLen=%d",
763                 xIdx, yIdx, tile_width, tile_height, YLen, CbLen, CrLen);
764
765         end_pos = stream_get_pos(s);
766
767         stream_set_pos(s, start_pos + 2);
768         stream_write_uint32(s, 19 + YLen + CbLen + CrLen); /* BlockT.blockLen */
769         stream_set_pos(s, start_pos + 13);
770         stream_write_uint16(s, YLen);
771         stream_write_uint16(s, CbLen);
772         stream_write_uint16(s, CrLen);
773
774         stream_set_pos(s, end_pos);
775 }
776
777 static void rfx_compose_message_tileset(RFX_CONTEXT* context, STREAM* s,
778         uint8* image_data, int width, int height, int rowstride)
779 {
780         int size;
781         int start_pos, end_pos;
782         int i;
783         int numQuants;
784         const uint32* quantVals;
785         const uint32* quantValsPtr;
786         int quantIdxY;
787         int quantIdxCb;
788         int quantIdxCr;
789         int numTiles;
790         int numTilesX;
791         int numTilesY;
792         int xIdx;
793         int yIdx;
794         int tilesDataSize;
795
796         if (context->num_quants == 0)
797         {
798                 numQuants = 1;
799                 quantVals = rfx_default_quantization_values;
800                 quantIdxY = 0;
801                 quantIdxCb = 0;
802                 quantIdxCr = 0;
803         }
804         else
805         {
806                 numQuants = context->num_quants;
807                 quantVals = context->quants;
808                 quantIdxY = context->quant_idx_y;
809                 quantIdxCb = context->quant_idx_cb;
810                 quantIdxCr = context->quant_idx_cr;
811         }
812
813         numTilesX = (width + 63) / 64;
814         numTilesY = (height + 63) / 64;
815         numTiles = numTilesX * numTilesY;
816
817         size = 22 + numQuants * 5;
818         stream_check_size(s, size);
819         start_pos = stream_get_pos(s);
820
821         stream_write_uint16(s, WBT_EXTENSION); /* CodecChannelT.blockType */
822         stream_seek_uint32(s); /* set CodecChannelT.blockLen later */
823         stream_write_uint8(s, 1); /* CodecChannelT.codecId */
824         stream_write_uint8(s, 0); /* CodecChannelT.channelId */
825         stream_write_uint16(s, CBT_TILESET); /* subtype */
826         stream_write_uint16(s, 0); /* idx */
827         stream_write_uint16(s, context->properties); /* properties */
828         stream_write_uint8(s, numQuants); /* numQuants */
829         stream_write_uint8(s, 0x40); /* tileSize */
830         stream_write_uint16(s, numTiles); /* numTiles */
831         stream_seek_uint32(s); /* set tilesDataSize later */
832
833         quantValsPtr = quantVals;
834         for (i = 0; i < numQuants * 5; i++)
835         {
836                 stream_write_uint8(s, quantValsPtr[0] + (quantValsPtr[1] << 4));
837                 quantValsPtr += 2;
838         }
839
840         DEBUG_RFX("width:%d height:%d rowstride:%d", width, height, rowstride);
841
842         end_pos = stream_get_pos(s);
843         for (yIdx = 0; yIdx < numTilesY; yIdx++)
844         {
845                 for (xIdx = 0; xIdx < numTilesX; xIdx++)
846                 {
847                         rfx_compose_message_tile(context, s,
848                                 image_data + yIdx * 64 * rowstride + xIdx * 8 * context->bits_per_pixel,
849                                 (xIdx < numTilesX - 1) ? 64 : width - xIdx * 64,
850                                 (yIdx < numTilesY - 1) ? 64 : height - yIdx * 64,
851                                 rowstride, quantVals, quantIdxY, quantIdxCb, quantIdxCr, xIdx, yIdx);
852                 }
853         }
854         tilesDataSize = stream_get_pos(s) - end_pos;
855         size += tilesDataSize;
856         end_pos = stream_get_pos(s);
857
858         stream_set_pos(s, start_pos + 2);
859         stream_write_uint32(s, size); /* CodecChannelT.blockLen */
860         stream_set_pos(s, start_pos + 18);
861         stream_write_uint32(s, tilesDataSize);
862
863         stream_set_pos(s, end_pos);
864 }
865
866 static void rfx_compose_message_frame_end(RFX_CONTEXT* context, STREAM* s)
867 {
868         stream_check_size(s, 8);
869
870         stream_write_uint16(s, WBT_FRAME_END); /* CodecChannelT.blockType */
871         stream_write_uint32(s, 8); /* CodecChannelT.blockLen */
872         stream_write_uint8(s, 1); /* CodecChannelT.codecId */
873         stream_write_uint8(s, 0); /* CodecChannelT.channelId */
874 }
875
876 static void rfx_compose_message_data(RFX_CONTEXT* context, STREAM* s,
877         const RFX_RECT* rects, int num_rects, uint8* image_data, int width, int height, int rowstride)
878 {
879         rfx_compose_message_frame_begin(context, s);
880         rfx_compose_message_region(context, s, rects, num_rects);
881         rfx_compose_message_tileset(context, s, image_data, width, height, rowstride);
882         rfx_compose_message_frame_end(context, s);
883 }
884
885 FREERDP_API void rfx_compose_message(RFX_CONTEXT* context, STREAM* s,
886         const RFX_RECT* rects, int num_rects, uint8* image_data, int width, int height, int rowstride)
887 {
888         /* Only the first frame should send the RemoteFX header */
889         if (context->frame_idx == 0 && !context->header_processed)
890                 rfx_compose_message_header(context, s);
891
892         rfx_compose_message_data(context, s, rects, num_rects, image_data, width, height, rowstride);
893 }
894