2 * FreeRDP: A Remote Desktop Protocol client.
3 * RemoteFX Codec Library
5 * Copyright 2011 Vic Lee
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
24 #include <freerdp/codec/rfx.h>
25 #include <freerdp/utils/memory.h>
26 #include <freerdp/constants.h>
28 #include "rfx_constants.h"
29 #include "rfx_types.h"
31 #include "rfx_decode.h"
32 #include "rfx_encode.h"
33 #include "rfx_quantization.h"
45 #define RFX_INIT_SIMD(_rfx_context) do { } while (0)
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
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.
57 * The order of the values are:
58 * LL3, LH3, HL3, HH3, LH2, HL2, HH2, LH1, HL1, HH1
60 static const uint32 rfx_default_quantization_values[] =
62 6, 6, 6, 6, 7, 7, 8, 8, 8, 9
65 static void rfx_profiler_create(RFX_CONTEXT* context)
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");
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");
86 static void rfx_profiler_free(RFX_CONTEXT* context)
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);
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);
107 static void rfx_profiler_print(RFX_CONTEXT* context)
109 PROFILER_PRINT_HEADER;
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);
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);
129 PROFILER_PRINT_FOOTER;
132 RFX_CONTEXT* rfx_context_new(void)
134 RFX_CONTEXT* context;
136 context = xnew(RFX_CONTEXT);
137 context->priv = xnew(RFX_CONTEXT_PRIV);
138 context->priv->pool = rfx_pool_new();
140 /* initialize the default pixel format */
141 rfx_context_set_pixel_format(context, RFX_PIXEL_FORMAT_BGRA);
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);
148 context->priv->dwt_buffer = (sint16*)(((uintptr_t)context->priv->dwt_mem + 16) & ~ 0x0F);
150 /* create profilers for default decoding routines */
151 rfx_profiler_create(context);
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;
164 void rfx_context_set_cpu_opt(RFX_CONTEXT* context, uint32 cpu_opt)
166 /* enable SIMD CPU acceleration if detected */
167 if (cpu_opt & CPU_SSE2)
168 RFX_INIT_SIMD(context);
171 void rfx_context_free(RFX_CONTEXT* context)
173 xfree(context->quants);
175 rfx_pool_free(context->priv->pool);
177 rfx_profiler_print(context);
178 rfx_profiler_free(context);
180 xfree(context->priv);
184 void rfx_context_set_pixel_format(RFX_CONTEXT* context, RFX_PIXEL_FORMAT pixel_format)
186 context->pixel_format = pixel_format;
187 switch (pixel_format)
189 case RFX_PIXEL_FORMAT_BGRA:
190 case RFX_PIXEL_FORMAT_RGBA:
191 context->bits_per_pixel = 32;
193 case RFX_PIXEL_FORMAT_BGR:
194 case RFX_PIXEL_FORMAT_RGB:
195 context->bits_per_pixel = 24;
197 case RFX_PIXEL_FORMAT_BGR565_LE:
198 case RFX_PIXEL_FORMAT_RGB565_LE:
199 context->bits_per_pixel = 16;
201 case RFX_PIXEL_FORMAT_PALETTE4_PLANER:
202 context->bits_per_pixel = 4;
204 case RFX_PIXEL_FORMAT_PALETTE8:
205 context->bits_per_pixel = 8;
208 context->bits_per_pixel = 0;
213 void rfx_context_reset(RFX_CONTEXT* context)
215 context->header_processed = false;
216 context->frame_idx = 0;
219 static void rfx_process_message_sync(RFX_CONTEXT* context, STREAM* s)
224 stream_read_uint32(s, magic); /* magic (4 bytes), 0xCACCACCA */
226 if (magic != WF_MAGIC)
228 DEBUG_WARN("invalid magic number 0x%X", magic);
232 stream_read_uint16(s, context->version); /* version (2 bytes), WF_VERSION_1_0 (0x0100) */
234 if (context->version != WF_VERSION_1_0)
236 DEBUG_WARN("unknown version number 0x%X", context->version);
240 DEBUG_RFX("version 0x%X", context->version);
243 static void rfx_process_message_codec_versions(RFX_CONTEXT* context, STREAM* s)
247 stream_read_uint8(s, numCodecs); /* numCodecs (1 byte), must be set to 0x01 */
251 DEBUG_WARN("numCodecs: %d, expected:1", numCodecs);
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) */
259 DEBUG_RFX("id %d version 0x%X.", context->codec_id, context->codec_version);
262 static void rfx_process_message_channels(RFX_CONTEXT* context, STREAM* s)
267 stream_read_uint8(s, numChannels); /* numChannels (1 byte), must bet set to 0x01 */
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.
274 DEBUG_WARN("numChannels:%d, expected:1", numChannels);
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) */
283 /* Now, only the first monitor can be used, therefore the other channels will be ignored. */
284 stream_seek(s, 5 * (numChannels - 1));
286 DEBUG_RFX("numChannels %d id %d, %dx%d.",
287 numChannels, channelId, context->width, context->height);
290 static void rfx_process_message_context(RFX_CONTEXT* context, STREAM* s)
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) */
300 DEBUG_RFX("ctxId %d tileSize %d properties 0x%X.", ctxId, tileSize, properties);
302 context->properties = properties;
303 context->flags = (properties & 0x0007);
305 if (context->flags == CODEC_MODE)
306 DEBUG_RFX("codec is in image mode.");
308 DEBUG_RFX("codec is in video mode.");
310 switch ((properties & 0x1E00) >> 9)
312 case CLW_ENTROPY_RLGR1:
313 context->mode = RLGR1;
317 case CLW_ENTROPY_RLGR3:
318 context->mode = RLGR3;
323 DEBUG_WARN("unknown RLGR algorithm.");
328 static void rfx_process_message_frame_begin(RFX_CONTEXT* context, RFX_MESSAGE* message, STREAM* s)
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) */
336 DEBUG_RFX("RFX_FRAME_BEGIN: frameIdx:%d numRegions:%d", frameIdx, numRegions);
339 static void rfx_process_message_frame_end(RFX_CONTEXT* context, RFX_MESSAGE* message, STREAM* s)
341 DEBUG_RFX("RFX_FRAME_END");
344 static void rfx_process_message_region(RFX_CONTEXT* context, RFX_MESSAGE* message, STREAM* s)
348 stream_seek_uint8(s); /* regionFlags (1 byte) */
349 stream_read_uint16(s, message->num_rects); /* numRects (2 bytes) */
351 if (message->num_rects < 1)
353 DEBUG_WARN("no rects.");
357 if (message->rects != NULL)
358 message->rects = (RFX_RECT*) xrealloc(message->rects, message->num_rects * sizeof(RFX_RECT));
360 message->rects = (RFX_RECT*) xmalloc(message->num_rects * sizeof(RFX_RECT));
363 for (i = 0; i < message->num_rects; i++)
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) */
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);
376 static void rfx_process_message_tile(RFX_CONTEXT* context, RFX_TILE* tile, STREAM* s)
382 uint16 YLen, CbLen, CrLen;
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) */
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);
400 rfx_decode_rgb(context, s,
401 YLen, context->quants + (quantIdxY * 10),
402 CbLen, context->quants + (quantIdxCb * 10),
403 CrLen, context->quants + (quantIdxCr * 10),
407 static void rfx_process_message_tileset(RFX_CONTEXT* context, RFX_MESSAGE* message, STREAM* s)
413 uint32 tilesDataSize;
418 stream_read_uint16(s, subtype); /* subtype (2 bytes) must be set to CBT_TILESET (0xCAC2) */
420 if (subtype != CBT_TILESET)
422 DEBUG_WARN("invalid subtype, expected CBT_TILESET.");
426 stream_seek_uint16(s); /* idx (2 bytes), must be set to 0x0000 */
427 stream_seek_uint16(s); /* properties (2 bytes) */
429 stream_read_uint8(s, context->num_quants); /* numQuant (1 byte) */
430 stream_seek_uint8(s); /* tileSize (1 byte), must be set to 0x40 */
432 if (context->num_quants < 1)
434 DEBUG_WARN("no quantization value.");
438 stream_read_uint16(s, message->num_tiles); /* numTiles (2 bytes) */
440 if (message->num_tiles < 1)
442 DEBUG_WARN("no tiles.");
446 stream_read_uint32(s, tilesDataSize); /* tilesDataSize (4 bytes) */
448 if (context->quants != NULL)
449 context->quants = (uint32*) xrealloc((void*) context->quants, context->num_quants * 10 * sizeof(uint32));
451 context->quants = (uint32*) xmalloc(context->num_quants * 10 * sizeof(uint32));
452 quants = context->quants;
455 for (i = 0; i < context->num_quants; i++)
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);
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]);
482 message->tiles = rfx_pool_get_tiles(context->priv->pool, message->num_tiles);
485 for (i = 0; i < message->num_tiles; i++)
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) */
491 pos = stream_get_pos(s) - 6 + blockLen;
493 if (blockType != CBT_TILE)
495 DEBUG_WARN("unknown block type 0x%X, expected CBT_TILE (0xCAC3).", blockType);
499 rfx_process_message_tile(context, message->tiles[i], s);
501 stream_set_pos(s, pos);
505 RFX_MESSAGE* rfx_process_message(RFX_CONTEXT* context, uint8* data, uint32 length)
511 RFX_MESSAGE* message;
514 message = xnew(RFX_MESSAGE);
515 stream_attach(s, data, length);
517 while (stream_get_left(s) > 6)
520 stream_read_uint16(s, blockType); /* blockType (2 bytes) */
521 stream_read_uint32(s, blockLen); /* blockLen (4 bytes) */
523 DEBUG_RFX("blockType 0x%X blockLen %d", blockType, blockLen);
527 DEBUG_WARN("zero blockLen");
531 pos = stream_get_pos(s) - 6 + blockLen;
533 if (blockType >= WBT_CONTEXT && blockType <= WBT_EXTENSION)
535 /* RFX_CODEC_CHANNELT */
536 /* codecId (1 byte) must be set to 0x01 */
537 /* channelId (1 byte) must be set to 0x00 */
544 rfx_process_message_sync(context, s);
547 case WBT_CODEC_VERSIONS:
548 rfx_process_message_codec_versions(context, s);
552 rfx_process_message_channels(context, s);
556 rfx_process_message_context(context, s);
559 case WBT_FRAME_BEGIN:
560 rfx_process_message_frame_begin(context, message, s);
564 rfx_process_message_frame_end(context, message, s);
568 rfx_process_message_region(context, message, s);
572 rfx_process_message_tileset(context, message, s);
576 DEBUG_WARN("unknown blockType 0x%X", blockType);
580 stream_set_pos(s, pos);
589 uint16 rfx_message_get_tile_count(RFX_MESSAGE* message)
591 return message->num_tiles;
594 RFX_TILE* rfx_message_get_tile(RFX_MESSAGE* message, int index)
596 return message->tiles[index];
599 uint16 rfx_message_get_rect_count(RFX_MESSAGE* message)
601 return message->num_rects;
604 RFX_RECT* rfx_message_get_rect(RFX_MESSAGE* message, int index)
606 return &message->rects[index];
609 void rfx_message_free(RFX_CONTEXT* context, RFX_MESSAGE* message)
613 xfree(message->rects);
615 if (message->tiles != NULL)
617 rfx_pool_put_tiles(context->priv->pool, message->tiles, message->num_tiles);
618 xfree(message->tiles);
625 static void rfx_compose_message_sync(RFX_CONTEXT* context, STREAM* s)
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 */
633 static void rfx_compose_message_codec_versions(RFX_CONTEXT* context, STREAM* s)
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 */
642 static void rfx_compose_message_channels(RFX_CONTEXT* context, STREAM* s)
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 */
652 static void rfx_compose_message_context(RFX_CONTEXT* context, STREAM* s)
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 */
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);
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;
681 void rfx_compose_message_header(RFX_CONTEXT* context, STREAM* s)
683 stream_check_size(s, 12 + 10 + 12 + 13);
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);
690 context->header_processed = true;
693 static void rfx_compose_message_frame_begin(RFX_CONTEXT* context, STREAM* s)
695 stream_check_size(s, 14);
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 */
704 context->frame_idx++;
707 static void rfx_compose_message_region(RFX_CONTEXT* context, STREAM* s,
708 const RFX_RECT* rects, int num_rects)
713 size = 15 + num_rects * 8;
714 stream_check_size(s, size);
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 */
723 for (i = 0; i < num_rects; i++)
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);
731 stream_write_uint16(s, CBT_REGION); /* regionType */
732 stream_write_uint16(s, 1); /* numTilesets */
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,
743 int start_pos, end_pos;
745 stream_check_size(s, 19);
746 start_pos = stream_get_pos(s);
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);
756 stream_seek(s, 6); /* YLen, CbLen, CrLen */
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);
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);
765 end_pos = stream_get_pos(s);
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);
774 stream_set_pos(s, end_pos);
777 static void rfx_compose_message_tileset(RFX_CONTEXT* context, STREAM* s,
778 uint8* image_data, int width, int height, int rowstride)
781 int start_pos, end_pos;
784 const uint32* quantVals;
785 const uint32* quantValsPtr;
796 if (context->num_quants == 0)
799 quantVals = rfx_default_quantization_values;
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;
813 numTilesX = (width + 63) / 64;
814 numTilesY = (height + 63) / 64;
815 numTiles = numTilesX * numTilesY;
817 size = 22 + numQuants * 5;
818 stream_check_size(s, size);
819 start_pos = stream_get_pos(s);
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 */
833 quantValsPtr = quantVals;
834 for (i = 0; i < numQuants * 5; i++)
836 stream_write_uint8(s, quantValsPtr[0] + (quantValsPtr[1] << 4));
840 DEBUG_RFX("width:%d height:%d rowstride:%d", width, height, rowstride);
842 end_pos = stream_get_pos(s);
843 for (yIdx = 0; yIdx < numTilesY; yIdx++)
845 for (xIdx = 0; xIdx < numTilesX; xIdx++)
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);
854 tilesDataSize = stream_get_pos(s) - end_pos;
855 size += tilesDataSize;
856 end_pos = stream_get_pos(s);
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);
863 stream_set_pos(s, end_pos);
866 static void rfx_compose_message_frame_end(RFX_CONTEXT* context, STREAM* s)
868 stream_check_size(s, 8);
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 */
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)
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);
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)
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);
892 rfx_compose_message_data(context, s, rects, num_rects, image_data, width, height, rowstride);