diff --git a/client/X11/xf_graphics.c b/client/X11/xf_graphics.c index ce9e028e6..cc14ffd29 100644 --- a/client/X11/xf_graphics.c +++ b/client/X11/xf_graphics.c @@ -25,6 +25,7 @@ #endif #include +#include #include #include "xf_graphics.h" @@ -61,7 +62,7 @@ void xf_Bitmap_New(rdpContext* context, rdpBitmap* bitmap) { if (data != bitmap->data) xfree(bitmap->data); - + bitmap->data = data; } } @@ -106,9 +107,14 @@ void xf_Bitmap_Paint(rdpContext* context, rdpBitmap* bitmap) } void xf_Bitmap_Decompress(rdpContext* context, rdpBitmap* bitmap, - uint8* data, int width, int height, int bpp, int length, boolean compressed) + uint8* data, int width, int height, int bpp, int length, int compressed) { uint16 size; + RFX_MESSAGE* msg; + uint8* src; + uint8* dst; + int yindex; + int xindex; size = width * height * (bpp + 7) / 8; @@ -117,22 +123,52 @@ void xf_Bitmap_Decompress(rdpContext* context, rdpBitmap* bitmap, else bitmap->data = (uint8*) xrealloc(bitmap->data, size); - if (compressed == 2) + if (compressed == 4) + { + printf("xf_Bitmap_Decompress: nsc not done\n"); + } + else if (compressed == 3) + { + xfInfo* xfi = ((xfContext*)context)->xfi; + rfx_context_set_pixel_format(xfi->rfx_context, RDP_PIXEL_FORMAT_B8G8R8A8); + msg = rfx_process_message(xfi->rfx_context, data, length); + if (msg == NULL) + { + printf("xf_Bitmap_Decompress: rfx Decompression Failed\n"); + } + else + { + for (yindex = 0; yindex < height; yindex++) + { + src = msg->tiles[0]->data + yindex * 64 * 4; + dst = bitmap->data + yindex * width * 3; + for (xindex = 0; xindex < width; xindex++) + { + *(dst++) = *(src++); + *(dst++) = *(src++); + *(dst++) = *(src++); + src++; + } + } + rfx_message_free(xfi->rfx_context, msg); + } + } + else if (compressed == 2) { if (!jpeg_decompress(data, bitmap->data, width, height, length, bpp)) { - printf("jpeg Decompression Failed\n"); + printf("xf_Bitmap_Decompress: jpeg Decompression Failed\n"); } } - else if (compressed) + else if (compressed == 1) { boolean status; status = bitmap_decompress(data, bitmap->data, width, height, length, bpp, bpp); - if (status != true) + if (status == false) { - printf("Bitmap Decompression Failed\n"); + printf("xf_Bitmap_Decompress: Bitmap Decompression Failed\n"); } } else diff --git a/include/freerdp/constants.h b/include/freerdp/constants.h index 88b3c321f..c9bcf67c7 100644 --- a/include/freerdp/constants.h +++ b/include/freerdp/constants.h @@ -27,6 +27,7 @@ enum RDP_CODEC_ID { CODEC_ID_NONE = 0x00, CODEC_ID_NSCODEC = 0x01, + CODEC_ID_JPEG = 0x02, CODEC_ID_REMOTEFX = 0x03 }; diff --git a/include/freerdp/graphics.h b/include/freerdp/graphics.h index 033ff3a23..bf0a00a84 100644 --- a/include/freerdp/graphics.h +++ b/include/freerdp/graphics.h @@ -35,7 +35,7 @@ typedef void (*pBitmap_New)(rdpContext* context, rdpBitmap* bitmap); typedef void (*pBitmap_Free)(rdpContext* context, rdpBitmap* bitmap); typedef void (*pBitmap_Paint)(rdpContext* context, rdpBitmap* bitmap); typedef void (*pBitmap_Decompress)(rdpContext* context, rdpBitmap* bitmap, - uint8* data, int width, int height, int bpp, int length, boolean compressed); + uint8* data, int width, int height, int bpp, int length, int compressed); typedef void (*pBitmap_SetSurface)(rdpContext* context, rdpBitmap* bitmap, boolean primary); struct rdp_bitmap diff --git a/include/freerdp/settings.h b/include/freerdp/settings.h index 5ff5a0d4e..572be4cba 100644 --- a/include/freerdp/settings.h +++ b/include/freerdp/settings.h @@ -388,7 +388,11 @@ struct rdp_settings ALIGN64 uint32 ns_codec_id; /* 283 */ ALIGN64 uint32 rfx_codec_mode; /* 284 */ ALIGN64 boolean frame_acknowledge; /* 285 */ - ALIGN64 uint64 paddingM[296 - 286]; /* 286 */ + ALIGN64 boolean jpeg_codec; /* 286 */ + ALIGN64 uint32 jpeg_codec_id; /* 287 */ + ALIGN64 uint32 jpeg_quality; /* 288 */ + ALIGN64 uint32 preferred_codec_id; /* 289 */ + ALIGN64 uint64 paddingM[296 - 290]; /* 290 */ /* Recording */ ALIGN64 boolean dump_rfx; /* 296 */ diff --git a/libfreerdp-cache/bitmap.c b/libfreerdp-cache/bitmap.c index 6d42d263d..dede3a715 100644 --- a/libfreerdp-cache/bitmap.c +++ b/libfreerdp-cache/bitmap.c @@ -18,6 +18,7 @@ */ #include +#include #include #include @@ -125,6 +126,54 @@ void update_gdi_cache_bitmap_v2(rdpContext* context, CACHE_BITMAP_V2_ORDER* cach bitmap_cache_put(cache->bitmap, cache_bitmap_v2->cacheId, cache_bitmap_v2->cacheIndex, bitmap); } +void update_gdi_cache_bitmap_v3(rdpContext* context, CACHE_BITMAP_V3_ORDER* cache_bitmap_v3) +{ + rdpBitmap* bitmap; + rdpBitmap* prevBitmap; + rdpCache* cache = context->cache; + BITMAP_DATA_EX* bitmapData = &cache_bitmap_v3->bitmapData; + boolean compression; + + bitmap = Bitmap_Alloc(context); + + Bitmap_SetDimensions(context, bitmap, bitmapData->width, bitmapData->height); + + if (cache_bitmap_v3->bitmapData.bpp == 0) + { + /* Workaround for Windows 8 bug where bitmapBpp is not set */ + cache_bitmap_v3->bitmapData.bpp = context->instance->settings->color_depth; + } + + switch (bitmapData->codecID) + { + case CODEC_ID_JPEG: + compression = 2; + break; + case CODEC_ID_REMOTEFX: + compression = 3; + break; + case CODEC_ID_NSCODEC: + compression = 4; + break; + default: + compression = 1; + break; + } + + bitmap->Decompress(context, bitmap, + bitmapData->data, bitmap->width, bitmap->height, + bitmapData->bpp, bitmapData->length, compression); + + bitmap->New(context, bitmap); + + prevBitmap = bitmap_cache_get(cache->bitmap, cache_bitmap_v3->cacheId, cache_bitmap_v3->cacheIndex); + + if (prevBitmap != NULL) + Bitmap_Free(context, prevBitmap); + + bitmap_cache_put(cache->bitmap, cache_bitmap_v3->cacheId, cache_bitmap_v3->cacheIndex, bitmap); +} + void update_gdi_bitmap_update(rdpContext* context, BITMAP_UPDATE* bitmap_update) { int i; @@ -229,6 +278,7 @@ void bitmap_cache_register_callbacks(rdpUpdate* update) update->secondary->CacheBitmap = update_gdi_cache_bitmap; update->secondary->CacheBitmapV2 = update_gdi_cache_bitmap_v2; + update->secondary->CacheBitmapV3 = update_gdi_cache_bitmap_v3; update->BitmapUpdate = update_gdi_bitmap_update; } diff --git a/libfreerdp-core/capabilities.c b/libfreerdp-core/capabilities.c index 43615cdad..080ad9525 100644 --- a/libfreerdp-core/capabilities.c +++ b/libfreerdp-core/capabilities.c @@ -62,6 +62,9 @@ static const char* const CAPSET_TYPE_STRINGS[] = /* CODEC_GUID_NSCODEC 0xCA8D1BB9000F154F589FAE2D1A87E2D6 */ #define CODEC_GUID_NSCODEC "\xb9\x1b\x8d\xca\x0f\x00\x4f\x15\x58\x9f\xae\x2d\x1a\x87\xe2\xd6" +/* CODEC_GUID_JPEG 0x430C9EED1BAF4CE6869ACB8B37B66237*/ +#define CODEC_GUID_JPEG "\xE6\x4C\xAF\x1B\xED\x9E\x0C\x43\x86\x9A\xCB\x8B\x37\xB6\x62\x37" + void rdp_read_capability_set_header(STREAM* s, uint16* length, uint16* type) { stream_read_uint16(s, *type); /* capabilitySetType */ @@ -1014,7 +1017,6 @@ void rdp_write_bitmap_cache_v2_capability_set(STREAM* s, rdpSettings* settings) header = rdp_capability_set_start(s); cacheFlags = ALLOW_CACHE_WAITING_LIST_FLAG; - cacheFlags |= 0x80; /* jpeg hack */ if (settings->persistent_bitmap_cache) cacheFlags |= PERSISTENT_KEYS_EXPECTED_FLAG; @@ -1529,6 +1531,12 @@ void rdp_write_nsc_client_capability_container(STREAM* s, rdpSettings* settings) stream_write_uint8(s, 3); /* colorLossLevel */ } +void rdp_write_jpeg_client_capability_container(STREAM* s, rdpSettings* settings) +{ + stream_write_uint16(s, 1); /* codecPropertiesLength */ + stream_write_uint8(s, settings->jpeg_quality); +} + /** * Write RemoteFX Server Capability Container.\n * @param s stream @@ -1540,6 +1548,12 @@ void rdp_write_rfx_server_capability_container(STREAM* s, rdpSettings* settings) stream_write_uint32(s, 0); /* reserved */ } +void rdp_write_jpeg_server_capability_container(STREAM* s, rdpSettings* settings) +{ + stream_write_uint16(s, 1); /* codecPropertiesLength */ + stream_write_uint8(s, 75); +} + /** * Write NSCODEC Server Capability Container.\n * @param s stream @@ -1571,6 +1585,8 @@ void rdp_write_bitmap_codecs_capability_set(STREAM* s, rdpSettings* settings) bitmapCodecCount++; if (settings->ns_codec) bitmapCodecCount++; + if (settings->jpeg_codec) + bitmapCodecCount++; stream_write_uint8(s, bitmapCodecCount); @@ -1603,6 +1619,20 @@ void rdp_write_bitmap_codecs_capability_set(STREAM* s, rdpSettings* settings) rdp_write_nsc_client_capability_container(s, settings); } } + if (settings->jpeg_codec) + { + stream_write(s, CODEC_GUID_JPEG, 16); + if (settings->server_mode) + { + stream_write_uint8(s, 0); /* codecID is defined by the client */ + rdp_write_jpeg_server_capability_container(s, settings); + } + else + { + stream_write_uint8(s, CODEC_ID_JPEG); /* codecID */ + rdp_write_jpeg_client_capability_container(s, settings); + } + } rdp_capability_set_finish(s, header, CAPSET_TYPE_BITMAP_CODECS); } @@ -2098,4 +2128,3 @@ boolean rdp_send_confirm_active(rdpRdp* rdp) return rdp_send_pdu(rdp, s, PDU_TYPE_CONFIRM_ACTIVE, rdp->mcs->user_id); } - diff --git a/libfreerdp-gdi/graphics.c b/libfreerdp-gdi/graphics.c index d83ed2031..1ea61d793 100644 --- a/libfreerdp-gdi/graphics.c +++ b/libfreerdp-gdi/graphics.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -88,9 +89,14 @@ void gdi_Bitmap_Paint(rdpContext* context, rdpBitmap* bitmap) } void gdi_Bitmap_Decompress(rdpContext* context, rdpBitmap* bitmap, - uint8* data, int width, int height, int bpp, int length, boolean compressed) + uint8* data, int width, int height, int bpp, int length, int compressed) { uint16 size; + RFX_MESSAGE* msg; + uint8* src; + uint8* dst; + int yindex; + int xindex; size = width * height * (bpp + 7) / 8; @@ -99,11 +105,41 @@ void gdi_Bitmap_Decompress(rdpContext* context, rdpBitmap* bitmap, else bitmap->data = (uint8*) xrealloc(bitmap->data, size); - if (compressed == 2) + if (compressed == 4) + { + printf("gdi_Bitmap_Decompress: nsc not done\n"); + } + else if (compressed == 3) + { + rdpGdi* gdi = context->gdi; + rfx_context_set_pixel_format(gdi->rfx_context, RDP_PIXEL_FORMAT_B8G8R8A8); + msg = rfx_process_message(gdi->rfx_context, data, length); + if (msg == NULL) + { + printf("gdi_Bitmap_Decompress: rfx Decompression Failed\n"); + } + else + { + for (yindex = 0; yindex < height; yindex++) + { + src = msg->tiles[0]->data + yindex * 64 * 4; + dst = bitmap->data + yindex * width * 3; + for (xindex = 0; xindex < width; xindex++) + { + *(dst++) = *(src++); + *(dst++) = *(src++); + *(dst++) = *(src++); + src++; + } + } + rfx_message_free(gdi->rfx_context, msg); + } + } + else if (compressed == 2) { if (!jpeg_decompress(data, bitmap->data, width, height, length, bpp)) { - printf("jpeg Decompression Failed\n"); + printf("gdi_Bitmap_Decompress: jpeg Decompression Failed\n"); } } else if (compressed) @@ -112,9 +148,9 @@ void gdi_Bitmap_Decompress(rdpContext* context, rdpBitmap* bitmap, status = bitmap_decompress(data, bitmap->data, width, height, length, bpp, bpp); - if (status != true) + if (status == false) { - printf("Bitmap Decompression Failed\n"); + printf("gdi_Bitmap_Decompress: Bitmap Decompression Failed\n"); } } else @@ -244,4 +280,3 @@ void gdi_register_graphics(rdpGraphics* graphics) graphics_register_glyph(graphics, glyph); xfree(glyph); } - diff --git a/libfreerdp-gdi/graphics.h b/libfreerdp-gdi/graphics.h index 3940a44be..35d26855c 100644 --- a/libfreerdp-gdi/graphics.h +++ b/libfreerdp-gdi/graphics.h @@ -28,7 +28,7 @@ HGDI_BITMAP gdi_create_bitmap(rdpGdi* gdi, int width, int height, int bpp, uint8 void gdi_Bitmap_New(rdpContext* context, rdpBitmap* bitmap); void gdi_Bitmap_Free(rdpContext* context, rdpBitmap* bitmap); void gdi_Bitmap_Decompress(rdpContext* context, rdpBitmap* bitmap, - uint8* data, int width, int height, int bpp, int length, boolean compressed); + uint8* data, int width, int height, int bpp, int length, int compressed); void gdi_register_graphics(rdpGraphics* graphics); #endif /* __GDI_GRAPHICS_H */ diff --git a/libfreerdp-utils/args.c b/libfreerdp-utils/args.c index 8e510f9b5..ce7eb4ade 100644 --- a/libfreerdp-utils/args.c +++ b/libfreerdp-utils/args.c @@ -86,10 +86,13 @@ int freerdp_parse_args(rdpSettings* settings, int argc, char** argv, " --gdi: graphics rendering (hw, sw)\n" " --no-osb: disable offscreen bitmaps\n" " --no-bmp-cache: disable bitmap cache\n" + " --bcv3: codec for bitmap cache v3 (rfx, nsc, jpeg)\n" " --plugin: load a virtual channel plugin\n" " --rfx: enable RemoteFX\n" " --rfx-mode: RemoteFX operational flags (v[ideo], i[mage]), default is video\n" " --nsc: enable NSCodec (experimental)\n" + " --jpeg: enable jpeg codec, uses 75 quality\n" + " --jpegex: enable jpeg and set quality(1..99)\n" " --disable-wallpaper: disables wallpaper\n" " --composition: enable desktop composition\n" " --disable-full-window-drag: disables full window drag\n" @@ -346,6 +349,47 @@ int freerdp_parse_args(rdpSettings* settings, int argc, char** argv, return FREERDP_ARGS_PARSE_FAILURE; } } + else if (strcmp("--bcv3", argv[index]) == 0) + { + index++; + if (index == argc) + { + printf("missing codec name\n"); + return FREERDP_ARGS_PARSE_FAILURE; + } + settings->bitmap_cache_v3 = true; + if (strcmp("rfx", argv[index]) == 0) + { + printf("setting rfx\n"); + settings->preferred_codec_id = 3; /* CODEC_ID_REMOTEFX */ + } + else if (strcmp("nsc", argv[index]) == 0) + { + printf("setting codec nsc\n"); + settings->preferred_codec_id = 1; /* CODEC_ID_NSCODEC */ + } + else if (strcmp("jpeg", argv[index]) == 0) + { + printf("setting codec jpeg\n"); + settings->preferred_codec_id = 2; + } + } + else if (strcmp("--jpeg", argv[index]) == 0) + { + settings->jpeg_codec = true; + settings->jpeg_quality = 75; + } + else if (strcmp("--jpegex", argv[index]) == 0) + { + index++; + if (index == argc) + { + printf("missing codec name\n"); + return FREERDP_ARGS_PARSE_FAILURE; + } + settings->jpeg_codec = true; + settings->jpeg_quality = atoi(argv[index]); + } else if (strcmp("--rfx", argv[index]) == 0) { settings->rfx_codec = true;