From c71e4e18a194819684287d11288f1c2abececc39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Wed, 10 Sep 2014 00:42:41 -0400 Subject: [PATCH] libfreerdp-core: refactor codec context management --- client/Windows/wf_graphics.c | 33 +++- client/Windows/wf_interface.c | 1 + client/Windows/wf_interface.h | 1 + client/X11/xf_client.c | 35 ++-- client/X11/xf_gdi.c | 8 +- client/X11/xf_gfx.c | 83 +++++---- client/X11/xf_graphics.c | 48 ++++-- client/X11/xfreerdp.h | 6 +- include/freerdp/codec/bitmap.h | 18 -- include/freerdp/codec/clear.h | 3 +- include/freerdp/codec/interleaved.h | 46 +++++ .../freerdp}/codec/planar.h | 23 ++- include/freerdp/codec/progressive.h | 3 +- include/freerdp/codec/rfx.h | 11 +- include/freerdp/codecs.h | 63 +++++++ include/freerdp/freerdp.h | 5 +- include/freerdp/gdi/gdi.h | 3 +- include/freerdp/types.h | 15 ++ include/freerdp/update.h | 15 -- libfreerdp/codec/CMakeLists.txt | 5 +- .../codec/{bitmap_encode.c => bitmap.c} | 1 + .../codec/{bitmap_decode.c => interleaved.c} | 136 +++++++++------ libfreerdp/codec/planar.c | 3 +- .../codec/test/TestFreeRDPCodecPlanar.c | 85 +++------- libfreerdp/core/CMakeLists.txt | 1 + libfreerdp/core/codecs.c | 157 ++++++++++++++++++ libfreerdp/core/freerdp.c | 2 + libfreerdp/gdi/gdi.c | 90 +++++----- libfreerdp/gdi/graphics.c | 50 ++++-- libfreerdp/primitives/test/prim_test.h | 10 +- 30 files changed, 659 insertions(+), 301 deletions(-) create mode 100644 include/freerdp/codec/interleaved.h rename {libfreerdp => include/freerdp}/codec/planar.h (73%) create mode 100644 include/freerdp/codecs.h rename libfreerdp/codec/{bitmap_encode.c => bitmap.c} (99%) rename libfreerdp/codec/{bitmap_decode.c => interleaved.c} (71%) create mode 100644 libfreerdp/core/codecs.c diff --git a/client/Windows/wf_graphics.c b/client/Windows/wf_graphics.c index c33f14a82..e0adc70ac 100644 --- a/client/Windows/wf_graphics.c +++ b/client/Windows/wf_graphics.c @@ -142,8 +142,9 @@ void wf_Bitmap_Paint(wfContext* wfc, rdpBitmap* bitmap) } void wf_Bitmap_Decompress(wfContext* wfc, rdpBitmap* bitmap, - BYTE* data, int width, int height, int bpp, int length, BOOL compressed, int codec_id) + BYTE* data, int width, int height, int bpp, int length, BOOL compressed, int codecId) { + int status; UINT16 size; size = width * height * (bpp / 8); @@ -155,13 +156,35 @@ void wf_Bitmap_Decompress(wfContext* wfc, rdpBitmap* bitmap, if (compressed) { - BOOL status; + BYTE* pDstData; + UINT32 SrcSize; - status = bitmap_decompress(data, bitmap->data, width, height, length, bpp, bpp); + SrcSize = (UINT32) length; + pDstData = bitmap->data; - if (status != TRUE) + if (bpp < 32) { - DEBUG_WARN( "Bitmap Decompression Failed\n"); + freerdp_client_codecs_prepare(wfc->codecs, FREERDP_CODEC_INTERLEAVED); + + status = interleaved_decompress(wfc->codecs->interleaved, data, SrcSize, bpp, + &pDstData, PIXEL_FORMAT_XRGB32_VF, width * 4, 0, 0, width, height); + + if (status < 0) + { + DEBUG_WARN("wf_Bitmap_Decompress: Bitmap Decompression Failed\n"); + } + } + else + { + freerdp_client_codecs_prepare(wfc->codecs, FREERDP_CODEC_PLANAR); + + status = planar_decompress(wfc->codecs->planar, data, SrcSize, &pDstData, + PIXEL_FORMAT_XRGB32_VF, width * 4, 0, 0, width, height); + + if (status < 0) + { + DEBUG_WARN("wf_Bitmap_Decompress: Bitmap Decompression Failed\n"); + } } } else diff --git a/client/Windows/wf_interface.c b/client/Windows/wf_interface.c index 3fb115d43..8821ae37d 100644 --- a/client/Windows/wf_interface.c +++ b/client/Windows/wf_interface.c @@ -190,6 +190,7 @@ BOOL wf_pre_connect(freerdp* instance) context = instance->context; wfc = (wfContext*) instance->context; wfc->instance = instance; + wfc->codecs = instance->context->codecs; settings = instance->settings; diff --git a/client/Windows/wf_interface.h b/client/Windows/wf_interface.h index b9aa4056c..ff291e0f8 100644 --- a/client/Windows/wf_interface.h +++ b/client/Windows/wf_interface.h @@ -97,6 +97,7 @@ struct wf_context HGDI_DC hdc; UINT16 srcBpp; UINT16 dstBpp; + rdpCodecs* codecs; freerdp* instance; wfBitmap* primary; wfBitmap* drawing; diff --git a/client/X11/xf_client.c b/client/X11/xf_client.c index d43ed6359..e1f3d996e 100644 --- a/client/X11/xf_client.c +++ b/client/X11/xf_client.c @@ -695,17 +695,22 @@ static void xf_post_disconnect(freerdp *instance) * @return TRUE if successful. FALSE otherwise. * Can exit with error code XF_EXIT_PARSE_ARGUMENTS if there is an error in the parameters. */ -BOOL xf_pre_connect(freerdp *instance) +BOOL xf_pre_connect(freerdp* instance) { - rdpChannels *channels; - rdpSettings *settings; - xfContext *xfc = (xfContext *) instance->context; + rdpChannels* channels; + rdpSettings* settings; + xfContext* xfc = (xfContext*) instance->context; + + xfc->codecs = instance->context->codecs; xfc->settings = instance->settings; xfc->instance = instance; + settings = instance->settings; channels = instance->context->channels; + settings->OsMajorType = OSMAJORTYPE_UNIX; settings->OsMinorType = OSMINORTYPE_NATIVE_XSERVER; + ZeroMemory(settings->OrderSupport, 32); settings->OrderSupport[NEG_DSTBLT_INDEX] = TRUE; settings->OrderSupport[NEG_PATBLT_INDEX] = TRUE; @@ -861,12 +866,12 @@ BOOL xf_post_connect(freerdp *instance) if (settings->RemoteFxCodec) { - xfc->rfx = rfx_context_new(FALSE); + xfc->codecs->rfx = rfx_context_new(FALSE); } if (settings->NSCodec) { - xfc->nsc = nsc_context_new(); + xfc->codecs->nsc = nsc_context_new(); } } @@ -1103,22 +1108,22 @@ void xf_window_free(xfContext *xfc) context->rail = NULL; } - if (xfc->rfx) + if (xfc->codecs->rfx) { - rfx_context_free(xfc->rfx); - xfc->rfx = NULL; + rfx_context_free(xfc->codecs->rfx); + xfc->codecs->rfx = NULL; } - if (xfc->nsc) + if (xfc->codecs->nsc) { - nsc_context_free(xfc->nsc); - xfc->nsc = NULL; + nsc_context_free(xfc->codecs->nsc); + xfc->codecs->nsc = NULL; } - if (xfc->clear) + if (xfc->codecs->clear) { - clear_context_free(xfc->clear); - xfc->clear = NULL; + clear_context_free(xfc->codecs->clear); + xfc->codecs->clear = NULL; } if (xfc->clrconv) diff --git a/client/X11/xf_gdi.c b/client/X11/xf_gdi.c index c18846370..3ae2db472 100644 --- a/client/X11/xf_gdi.c +++ b/client/X11/xf_gdi.c @@ -1033,7 +1033,7 @@ void xf_gdi_surface_bits(rdpContext* context, SURFACE_BITS_COMMAND* surface_bits if (surface_bits_command->codecID == RDP_CODEC_ID_REMOTEFX) { - message = rfx_process_message(xfc->rfx, + message = rfx_process_message(xfc->codecs->rfx, surface_bits_command->bitmapData, surface_bits_command->bitmapDataLength); XSetFunction(xfc->display, xfc->gc, GXcopy); @@ -1070,11 +1070,11 @@ void xf_gdi_surface_bits(rdpContext* context, SURFACE_BITS_COMMAND* surface_bits } XSetClipMask(xfc->display, xfc->gc, None); - rfx_message_free(xfc->rfx, message); + rfx_message_free(xfc->codecs->rfx, message); } else if (surface_bits_command->codecID == RDP_CODEC_ID_NSCODEC) { - nsc_process_message(xfc->nsc, surface_bits_command->bpp, surface_bits_command->width, surface_bits_command->height, + nsc_process_message(xfc->codecs->nsc, surface_bits_command->bpp, surface_bits_command->width, surface_bits_command->height, surface_bits_command->bitmapData, surface_bits_command->bitmapDataLength); XSetFunction(xfc->display, xfc->gc, GXcopy); @@ -1083,7 +1083,7 @@ void xf_gdi_surface_bits(rdpContext* context, SURFACE_BITS_COMMAND* surface_bits xfc->bmp_codec_nsc = (BYTE*) realloc(xfc->bmp_codec_nsc, surface_bits_command->width * surface_bits_command->height * 4); - freerdp_image_flip(xfc->nsc->BitmapData, xfc->bmp_codec_nsc, + freerdp_image_flip(xfc->codecs->nsc->BitmapData, xfc->bmp_codec_nsc, surface_bits_command->width, surface_bits_command->height, 32); image = XCreateImage(xfc->display, xfc->visual, 24, ZPixmap, 0, diff --git a/client/X11/xf_gfx.c b/client/X11/xf_gfx.c index c54ff6201..476679364 100644 --- a/client/X11/xf_gfx.c +++ b/client/X11/xf_gfx.c @@ -27,53 +27,53 @@ int xf_ResetGraphics(RdpgfxClientContext* context, RDPGFX_RESET_GRAPHICS_PDU* re { xfContext* xfc = (xfContext*) context->custom; - if (xfc->rfx) + if (xfc->codecs->rfx) { - rfx_context_free(xfc->rfx); - xfc->rfx = NULL; + rfx_context_free(xfc->codecs->rfx); + xfc->codecs->rfx = NULL; } - xfc->rfx = rfx_context_new(FALSE); + xfc->codecs->rfx = rfx_context_new(FALSE); - xfc->rfx->width = resetGraphics->width; - xfc->rfx->height = resetGraphics->height; - rfx_context_set_pixel_format(xfc->rfx, RDP_PIXEL_FORMAT_B8G8R8A8); + xfc->codecs->rfx->width = resetGraphics->width; + xfc->codecs->rfx->height = resetGraphics->height; + rfx_context_set_pixel_format(xfc->codecs->rfx, RDP_PIXEL_FORMAT_B8G8R8A8); - if (xfc->nsc) + if (xfc->codecs->nsc) { - nsc_context_free(xfc->nsc); - xfc->nsc = NULL; + nsc_context_free(xfc->codecs->nsc); + xfc->codecs->nsc = NULL; } - xfc->nsc = nsc_context_new(); + xfc->codecs->nsc = nsc_context_new(); - xfc->nsc->width = resetGraphics->width; - xfc->nsc->height = resetGraphics->height; - nsc_context_set_pixel_format(xfc->nsc, RDP_PIXEL_FORMAT_B8G8R8A8); + xfc->codecs->nsc->width = resetGraphics->width; + xfc->codecs->nsc->height = resetGraphics->height; + nsc_context_set_pixel_format(xfc->codecs->nsc, RDP_PIXEL_FORMAT_B8G8R8A8); - if (xfc->clear) + if (xfc->codecs->clear) { - clear_context_free(xfc->clear); - xfc->clear = NULL; + clear_context_free(xfc->codecs->clear); + xfc->codecs->clear = NULL; } - xfc->clear = clear_context_new(FALSE); + xfc->codecs->clear = clear_context_new(FALSE); - if (xfc->h264) + if (xfc->codecs->h264) { - h264_context_free(xfc->h264); - xfc->h264 = NULL; + h264_context_free(xfc->codecs->h264); + xfc->codecs->h264 = NULL; } - xfc->h264 = h264_context_new(FALSE); + xfc->codecs->h264 = h264_context_new(FALSE); - if (xfc->progressive) + if (xfc->codecs->progressive) { - progressive_context_free(xfc->progressive); - xfc->progressive = NULL; + progressive_context_free(xfc->codecs->progressive); + xfc->codecs->progressive = NULL; } - xfc->progressive = progressive_context_new(TRUE); + xfc->codecs->progressive = progressive_context_new(TRUE); region16_init(&(xfc->invalidRegion)); @@ -216,12 +216,14 @@ int xf_SurfaceCommand_RemoteFX(xfContext* xfc, RdpgfxClientContext* context, RDP REGION16 clippingRects; RECTANGLE_16 clippingRect; + freerdp_client_codecs_prepare(xfc->codecs, FREERDP_CODEC_REMOTEFX); + surface = (xfGfxSurface*) context->GetSurfaceData(context, cmd->surfaceId); if (!surface) return -1; - message = rfx_process_message(xfc->rfx, cmd->data, cmd->length); + message = rfx_process_message(xfc->codecs->rfx, cmd->data, cmd->length); if (!message) return -1; @@ -270,7 +272,7 @@ int xf_SurfaceCommand_RemoteFX(xfContext* xfc, RdpgfxClientContext* context, RDP region16_uninit(&updateRegion); } - rfx_message_free(xfc->rfx, message); + rfx_message_free(xfc->codecs->rfx, message); if (!xfc->inGfxFrame) xf_OutputUpdate(xfc); @@ -285,6 +287,8 @@ int xf_SurfaceCommand_ClearCodec(xfContext* xfc, RdpgfxClientContext* context, R xfGfxSurface* surface; RECTANGLE_16 invalidRect; + freerdp_client_codecs_prepare(xfc->codecs, FREERDP_CODEC_CLEARCODEC); + surface = (xfGfxSurface*) context->GetSurfaceData(context, cmd->surfaceId); if (!surface) @@ -292,7 +296,7 @@ int xf_SurfaceCommand_ClearCodec(xfContext* xfc, RdpgfxClientContext* context, R DstData = surface->data; - status = clear_decompress(xfc->clear, cmd->data, cmd->length, &DstData, + status = clear_decompress(xfc->codecs->clear, cmd->data, cmd->length, &DstData, PIXEL_FORMAT_XRGB32, surface->scanline, cmd->left, cmd->top, cmd->width, cmd->height); if (status < 0) @@ -322,6 +326,8 @@ int xf_SurfaceCommand_Planar(xfContext* xfc, RdpgfxClientContext* context, RDPGF xfGfxSurface* surface; RECTANGLE_16 invalidRect; + freerdp_client_codecs_prepare(xfc->codecs, FREERDP_CODEC_PLANAR); + surface = (xfGfxSurface*) context->GetSurfaceData(context, cmd->surfaceId); if (!surface) @@ -329,7 +335,7 @@ int xf_SurfaceCommand_Planar(xfContext* xfc, RdpgfxClientContext* context, RDPGF DstData = surface->data; - status = planar_decompress(NULL, cmd->data, cmd->length, &DstData, + status = planar_decompress(xfc->codecs->planar, cmd->data, cmd->length, &DstData, PIXEL_FORMAT_XRGB32, surface->scanline, cmd->left, cmd->top, cmd->width, cmd->height); invalidRect.left = cmd->left; @@ -355,8 +361,9 @@ int xf_SurfaceCommand_H264(xfContext* xfc, RdpgfxClientContext* context, RDPGFX_ RDPGFX_H264_METABLOCK* meta; RDPGFX_H264_BITMAP_STREAM* bs; + freerdp_client_codecs_prepare(xfc->codecs, FREERDP_CODEC_H264); - h264 = xfc->h264; + h264 = xfc->codecs->h264; bs = (RDPGFX_H264_BITMAP_STREAM*) cmd->extra; @@ -372,7 +379,7 @@ int xf_SurfaceCommand_H264(xfContext* xfc, RdpgfxClientContext* context, RDPGFX_ DstData = surface->data; - status = h264_decompress(xfc->h264, bs->data, bs->length, &DstData, + status = h264_decompress(xfc->codecs->h264, bs->data, bs->length, &DstData, PIXEL_FORMAT_XRGB32, surface->scanline , surface->height, meta->regionRects, meta->numRegionRects); if (status < 0) @@ -398,6 +405,8 @@ int xf_SurfaceCommand_Alpha(xfContext* xfc, RdpgfxClientContext* context, RDPGFX xfGfxSurface* surface; RECTANGLE_16 invalidRect; + freerdp_client_codecs_prepare(xfc->codecs, FREERDP_CODEC_ALPHACODEC); + surface = (xfGfxSurface*) context->GetSurfaceData(context, cmd->surfaceId); if (!surface) @@ -442,16 +451,18 @@ int xf_SurfaceCommand_Progressive(xfContext* xfc, RdpgfxClientContext* context, RFX_PROGRESSIVE_TILE* tile; PROGRESSIVE_BLOCK_REGION* region; + freerdp_client_codecs_prepare(xfc->codecs, FREERDP_CODEC_PROGRESSIVE); + surface = (xfGfxSurface*) context->GetSurfaceData(context, cmd->surfaceId); if (!surface) return -1; - progressive_create_surface_context(xfc->progressive, cmd->surfaceId, surface->width, surface->height); + progressive_create_surface_context(xfc->codecs->progressive, cmd->surfaceId, surface->width, surface->height); DstData = surface->data; - status = progressive_decompress(xfc->progressive, cmd->data, cmd->length, &DstData, + status = progressive_decompress(xfc->codecs->progressive, cmd->data, cmd->length, &DstData, PIXEL_FORMAT_XRGB32, surface->scanline, cmd->left, cmd->top, cmd->width, cmd->height, cmd->surfaceId); if (status < 0) @@ -460,7 +471,7 @@ int xf_SurfaceCommand_Progressive(xfContext* xfc, RdpgfxClientContext* context, return -1; } - region = &(xfc->progressive->region); + region = &(xfc->codecs->progressive->region); region16_init(&clippingRects); @@ -607,7 +618,7 @@ int xf_DeleteSurface(RdpgfxClientContext* context, RDPGFX_DELETE_SURFACE_PDU* de context->SetSurfaceData(context, deleteSurface->surfaceId, NULL); - progressive_delete_surface_context(xfc->progressive, deleteSurface->surfaceId); + progressive_delete_surface_context(xfc->codecs->progressive, deleteSurface->surfaceId); return 1; } diff --git a/client/X11/xf_graphics.c b/client/X11/xf_graphics.c index 330977684..9fc2cc7d4 100644 --- a/client/X11/xf_graphics.c +++ b/client/X11/xf_graphics.c @@ -120,14 +120,14 @@ void xf_Bitmap_Paint(rdpContext* context, rdpBitmap* bitmap) void xf_Bitmap_Decompress(rdpContext* context, rdpBitmap* bitmap, BYTE* data, int width, int height, int bpp, int length, - BOOL compressed, int codec_id) + BOOL compressed, int codecId) { + int status; UINT16 size; BYTE* src; BYTE* dst; int yindex; int xindex; - BOOL status; RFX_MESSAGE* msg; xfContext* xfc = (xfContext*) context; @@ -138,19 +138,21 @@ void xf_Bitmap_Decompress(rdpContext* context, rdpBitmap* bitmap, else bitmap->data = (BYTE*) _aligned_realloc(bitmap->data, size, 16); - switch (codec_id) + switch (codecId) { case RDP_CODEC_ID_NSCODEC: - DEBUG_WARN( "xf_Bitmap_Decompress: nsc not done\n"); + freerdp_client_codecs_prepare(xfc->codecs, FREERDP_CODEC_NSCODEC); + DEBUG_WARN("xf_Bitmap_Decompress: nsc not done\n"); break; case RDP_CODEC_ID_REMOTEFX: - rfx_context_set_pixel_format(xfc->rfx, RDP_PIXEL_FORMAT_B8G8R8A8); - msg = rfx_process_message(xfc->rfx, data, length); + freerdp_client_codecs_prepare(xfc->codecs, FREERDP_CODEC_REMOTEFX); + rfx_context_set_pixel_format(xfc->codecs->rfx, RDP_PIXEL_FORMAT_B8G8R8A8); + msg = rfx_process_message(xfc->codecs->rfx, data, length); if (!msg) { - DEBUG_WARN( "xf_Bitmap_Decompress: rfx Decompression Failed\n"); + DEBUG_WARN("xf_Bitmap_Decompress: rfx Decompression Failed\n"); } else { @@ -166,7 +168,7 @@ void xf_Bitmap_Decompress(rdpContext* context, rdpBitmap* bitmap, src++; } } - rfx_message_free(xfc->rfx, msg); + rfx_message_free(xfc->codecs->rfx, msg); } break; @@ -180,11 +182,35 @@ void xf_Bitmap_Decompress(rdpContext* context, rdpBitmap* bitmap, default: if (compressed) { - status = bitmap_decompress(data, bitmap->data, width, height, length, bpp, bpp); + BYTE* pDstData; + UINT32 SrcSize; - if (!status) + SrcSize = (UINT32) length; + pDstData = bitmap->data; + + if (bpp < 32) { - DEBUG_WARN( "xf_Bitmap_Decompress: Bitmap Decompression Failed\n"); + freerdp_client_codecs_prepare(xfc->codecs, FREERDP_CODEC_INTERLEAVED); + + status = interleaved_decompress(xfc->codecs->interleaved, data, SrcSize, bpp, + &pDstData, PIXEL_FORMAT_XRGB32_VF, width * 4, 0, 0, width, height); + + if (status < 0) + { + DEBUG_WARN("xf_Bitmap_Decompress: Bitmap Decompression Failed\n"); + } + } + else + { + freerdp_client_codecs_prepare(xfc->codecs, FREERDP_CODEC_PLANAR); + + status = planar_decompress(xfc->codecs->planar, data, SrcSize, &pDstData, + PIXEL_FORMAT_XRGB32_VF, width * 4, 0, 0, width, height); + + if (status < 0) + { + DEBUG_WARN("gdi_Bitmap_Decompress: Bitmap Decompression Failed\n"); + } } } else diff --git a/client/X11/xfreerdp.h b/client/X11/xfreerdp.h index a2d89b0df..ab1eef974 100644 --- a/client/X11/xfreerdp.h +++ b/client/X11/xfreerdp.h @@ -75,6 +75,7 @@ struct xf_context freerdp* instance; rdpSettings* settings; + rdpCodecs* codecs; GC gc; int bpp; @@ -152,11 +153,6 @@ struct xf_context VIRTUAL_SCREEN vscreen; BYTE* bmp_codec_none; BYTE* bmp_codec_nsc; - RFX_CONTEXT* rfx; - NSC_CONTEXT* nsc; - CLEAR_CONTEXT* clear; - H264_CONTEXT* h264; - PROGRESSIVE_CONTEXT* progressive; void* xv_context; void* clipboard_context; diff --git a/include/freerdp/codec/bitmap.h b/include/freerdp/codec/bitmap.h index d36917cad..507829253 100644 --- a/include/freerdp/codec/bitmap.h +++ b/include/freerdp/codec/bitmap.h @@ -32,27 +32,9 @@ extern "C" { #endif -FREERDP_API BOOL bitmap_decompress(BYTE* srcData, BYTE* dstData, int width, int height, int size, int srcBpp, int dstBpp); - FREERDP_API int freerdp_bitmap_compress(char* in_data, int width, int height, wStream* s, int bpp, int byte_limit, int start_line, wStream* temp_s, int e); -#define PLANAR_FORMAT_HEADER_CS (1 << 3) -#define PLANAR_FORMAT_HEADER_RLE (1 << 4) -#define PLANAR_FORMAT_HEADER_NA (1 << 5) -#define PLANAR_FORMAT_HEADER_CLL_MASK 0x07 - -typedef struct _BITMAP_PLANAR_CONTEXT BITMAP_PLANAR_CONTEXT; - -FREERDP_API BYTE* freerdp_bitmap_compress_planar(BITMAP_PLANAR_CONTEXT* context, BYTE* data, UINT32 format, - int width, int height, int scanline, BYTE* dstData, int* dstSize); - -FREERDP_API BITMAP_PLANAR_CONTEXT* freerdp_bitmap_planar_context_new(DWORD flags, int maxWidth, int maxHeight); -FREERDP_API void freerdp_bitmap_planar_context_free(BITMAP_PLANAR_CONTEXT* context); - -FREERDP_API int planar_decompress(BITMAP_PLANAR_CONTEXT* planar, BYTE* pSrcData, UINT32 SrcSize, - BYTE** ppDstData, DWORD DstFormat, int nDstStep, int nXDst, int nYDst, int nWidth, int nHeight); - #ifdef __cplusplus } #endif diff --git a/include/freerdp/codec/clear.h b/include/freerdp/codec/clear.h index 857975b9f..e49d1d572 100644 --- a/include/freerdp/codec/clear.h +++ b/include/freerdp/codec/clear.h @@ -20,6 +20,8 @@ #ifndef FREERDP_CODEC_CLEAR_H #define FREERDP_CODEC_CLEAR_H +typedef struct _CLEAR_CONTEXT CLEAR_CONTEXT; + #include #include @@ -59,7 +61,6 @@ struct _CLEAR_CONTEXT UINT32 ShortVBarStorageCursor; CLEAR_VBAR_ENTRY ShortVBarStorage[16384]; }; -typedef struct _CLEAR_CONTEXT CLEAR_CONTEXT; #ifdef __cplusplus extern "C" { diff --git a/include/freerdp/codec/interleaved.h b/include/freerdp/codec/interleaved.h new file mode 100644 index 000000000..5f6662b6a --- /dev/null +++ b/include/freerdp/codec/interleaved.h @@ -0,0 +1,46 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Interleaved RLE Bitmap Codec + * + * Copyright 2014 Marc-Andre Moreau + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FREERDP_CODEC_INTERLEAVED_H +#define FREERDP_CODEC_INTERLEAVED_H + +typedef struct _BITMAP_INTERLEAVED_CONTEXT BITMAP_INTERLEAVED_CONTEXT; + +#include +#include + +#include +#include + +struct _BITMAP_INTERLEAVED_CONTEXT +{ + BOOL Compressor; + + UINT32 FlipSize; + BYTE* FlipBuffer; +}; + +int interleaved_decompress(BITMAP_INTERLEAVED_CONTEXT* interleaved, BYTE* pSrcData, UINT32 SrcSize, int bpp, + BYTE** ppDstData, DWORD DstFormat, int nDstStep, int nXDst, int nYDst, int nWidth, int nHeight); + +FREERDP_API BITMAP_INTERLEAVED_CONTEXT* bitmap_interleaved_context_new(BOOL Compressor); +FREERDP_API void bitmap_interleaved_context_free(BITMAP_INTERLEAVED_CONTEXT* interleaved); + +#endif /* FREERDP_CODEC_INTERLEAVED_H */ + diff --git a/libfreerdp/codec/planar.h b/include/freerdp/codec/planar.h similarity index 73% rename from libfreerdp/codec/planar.h rename to include/freerdp/codec/planar.h index a8e34c87a..a06f2db3d 100644 --- a/libfreerdp/codec/planar.h +++ b/include/freerdp/codec/planar.h @@ -17,14 +17,21 @@ * limitations under the License. */ -#ifndef FREERDP_CODEC_PLANAR_PRIVATE_H -#define FREERDP_CODEC_PLANAR_PRIVATE_H +#ifndef FREERDP_CODEC_PLANAR_H +#define FREERDP_CODEC_PLANAR_H #include +typedef struct _BITMAP_PLANAR_CONTEXT BITMAP_PLANAR_CONTEXT; + #include #include +#define PLANAR_FORMAT_HEADER_CS (1 << 3) +#define PLANAR_FORMAT_HEADER_RLE (1 << 4) +#define PLANAR_FORMAT_HEADER_NA (1 << 5) +#define PLANAR_FORMAT_HEADER_CLL_MASK 0x07 + #define PLANAR_CONTROL_BYTE(_nRunLength, _cRawBytes) \ (_nRunLength & 0x0F) | ((_cRawBytes & 0x0F) << 4) @@ -92,4 +99,14 @@ FREERDP_API BYTE* freerdp_bitmap_planar_compress_plane_rle(BYTE* plane, int widt FREERDP_API BYTE* freerdp_bitmap_planar_delta_encode_plane(BYTE* inPlane, int width, int height, BYTE* outPlane); FREERDP_API int freerdp_bitmap_planar_delta_encode_planes(BYTE* inPlanes[4], int width, int height, BYTE* outPlanes[4]); -#endif /* FREERDP_CODEC_PLANAR_PRIVATE_H */ +FREERDP_API BYTE* freerdp_bitmap_compress_planar(BITMAP_PLANAR_CONTEXT* context, BYTE* data, UINT32 format, + int width, int height, int scanline, BYTE* dstData, int* dstSize); + +FREERDP_API BITMAP_PLANAR_CONTEXT* freerdp_bitmap_planar_context_new(DWORD flags, int maxWidth, int maxHeight); +FREERDP_API void freerdp_bitmap_planar_context_free(BITMAP_PLANAR_CONTEXT* context); + +FREERDP_API int planar_decompress(BITMAP_PLANAR_CONTEXT* planar, BYTE* pSrcData, UINT32 SrcSize, + BYTE** ppDstData, DWORD DstFormat, int nDstStep, int nXDst, int nYDst, int nWidth, int nHeight); + +#endif /* FREERDP_CODEC_PLANAR_H */ + diff --git a/include/freerdp/codec/progressive.h b/include/freerdp/codec/progressive.h index e18310ed8..be702a158 100644 --- a/include/freerdp/codec/progressive.h +++ b/include/freerdp/codec/progressive.h @@ -20,6 +20,8 @@ #ifndef FREERDP_CODEC_PROGRESSIVE_H #define FREERDP_CODEC_PROGRESSIVE_H +typedef struct _PROGRESSIVE_CONTEXT PROGRESSIVE_CONTEXT; + #include #include @@ -301,7 +303,6 @@ struct _PROGRESSIVE_CONTEXT wHashTable* SurfaceContexts; }; -typedef struct _PROGRESSIVE_CONTEXT PROGRESSIVE_CONTEXT; #ifdef __cplusplus extern "C" { diff --git a/include/freerdp/codec/rfx.h b/include/freerdp/codec/rfx.h index 08480bec2..2a68d14d7 100644 --- a/include/freerdp/codec/rfx.h +++ b/include/freerdp/codec/rfx.h @@ -20,6 +20,12 @@ #ifndef FREERDP_CODEC_REMOTEFX_H #define FREERDP_CODEC_REMOTEFX_H +typedef enum _RLGR_MODE RLGR_MODE; +typedef struct _RFX_RECT RFX_RECT; +typedef struct _RFX_TILE RFX_TILE; +typedef struct _RFX_MESSAGE RFX_MESSAGE; +typedef struct _RFX_CONTEXT RFX_CONTEXT; + #include #include #include @@ -36,7 +42,6 @@ enum _RLGR_MODE RLGR1, RLGR3 }; -typedef enum _RLGR_MODE RLGR_MODE; struct _RFX_RECT { @@ -45,7 +50,6 @@ struct _RFX_RECT UINT16 width; UINT16 height; }; -typedef struct _RFX_RECT RFX_RECT; struct _RFX_TILE { @@ -69,7 +73,6 @@ struct _RFX_TILE BYTE* CrData; BYTE* YCbCrData; }; -typedef struct _RFX_TILE RFX_TILE; struct _RFX_MESSAGE { @@ -99,7 +102,6 @@ struct _RFX_MESSAGE BOOL freeArray; }; -typedef struct _RFX_MESSAGE RFX_MESSAGE; typedef struct _RFX_CONTEXT_PRIV RFX_CONTEXT_PRIV; @@ -150,7 +152,6 @@ struct _RFX_CONTEXT /* private definitions */ RFX_CONTEXT_PRIV* priv; }; -typedef struct _RFX_CONTEXT RFX_CONTEXT; FREERDP_API RFX_CONTEXT* rfx_context_new(BOOL encoder); FREERDP_API void rfx_context_free(RFX_CONTEXT* context); diff --git a/include/freerdp/codecs.h b/include/freerdp/codecs.h new file mode 100644 index 000000000..15b311415 --- /dev/null +++ b/include/freerdp/codecs.h @@ -0,0 +1,63 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * RDP Codecs + * + * Copyright 2014 Marc-Andre Moreau + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FREERDP_CODECS_H +#define FREERDP_CODECS_H + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#define FREERDP_CODEC_INTERLEAVED 0x00000001 +#define FREERDP_CODEC_PLANAR 0x00000002 +#define FREERDP_CODEC_NSCODEC 0x00000004 +#define FREERDP_CODEC_REMOTEFX 0x00000008 +#define FREERDP_CODEC_CLEARCODEC 0x00000010 +#define FREERDP_CODEC_ALPHACODEC 0x00000020 +#define FREERDP_CODEC_PROGRESSIVE 0x00000040 +#define FREERDP_CODEC_H264 0x00000080 + +struct rdp_codecs +{ + rdpContext* context; + + RFX_CONTEXT* rfx; + NSC_CONTEXT* nsc; + H264_CONTEXT* h264; + CLEAR_CONTEXT* clear; + PROGRESSIVE_CONTEXT* progressive; + BITMAP_PLANAR_CONTEXT* planar; + BITMAP_INTERLEAVED_CONTEXT* interleaved; +}; + +FREERDP_API int freerdp_client_codecs_prepare(rdpCodecs* codecs, UINT32 flags); + +FREERDP_API rdpCodecs* codecs_new(rdpContext* context); +FREERDP_API void codecs_free(rdpCodecs* codecs); + +#endif /* FREERDP_CODECS_H */ + diff --git a/include/freerdp/freerdp.h b/include/freerdp/freerdp.h index b306fd0a6..bd5846db8 100644 --- a/include/freerdp/freerdp.h +++ b/include/freerdp/freerdp.h @@ -27,6 +27,7 @@ typedef struct rdp_cache rdpCache; typedef struct rdp_channels rdpChannels; typedef struct rdp_graphics rdpGraphics; typedef struct rdp_metrics rdpMetrics; +typedef struct rdp_codecs rdpCodecs; typedef struct rdp_freerdp freerdp; typedef struct rdp_context rdpContext; @@ -40,6 +41,7 @@ typedef RDP_CLIENT_ENTRY_POINTS_V1 RDP_CLIENT_ENTRY_POINTS; #include #include #include +#include #include #include #include @@ -120,7 +122,8 @@ struct rdp_context ALIGN64 rdpUpdate* update; /* 39 */ ALIGN64 rdpSettings* settings; /* 40 */ ALIGN64 rdpMetrics* metrics; /* 41 */ - UINT64 paddingC[64 - 42]; /* 42 */ + ALIGN64 rdpCodecs* codecs; /* 42 */ + UINT64 paddingC[64 - 43]; /* 43 */ UINT64 paddingD[96 - 64]; /* 64 */ UINT64 paddingE[128 - 96]; /* 96 */ diff --git a/include/freerdp/gdi/gdi.h b/include/freerdp/gdi/gdi.h index 9352278bd..8d574b815 100644 --- a/include/freerdp/gdi/gdi.h +++ b/include/freerdp/gdi/gdi.h @@ -279,6 +279,7 @@ struct rdp_gdi int cursor_x; int cursor_y; int bytesPerPixel; + rdpCodecs* codecs; HGDI_DC hdc; HCLRCONV clrconv; @@ -286,8 +287,6 @@ struct rdp_gdi gdiBitmap* drawing; BYTE* primary_buffer; GDI_COLOR textColor; - void* rfx_context; - void* nsc_context; gdiBitmap* tile; gdiBitmap* image; }; diff --git a/include/freerdp/types.h b/include/freerdp/types.h index 3d26e0bf9..a2ccb9c01 100644 --- a/include/freerdp/types.h +++ b/include/freerdp/types.h @@ -32,6 +32,21 @@ #define MAX(x,y) (((x) > (y)) ? (x) : (y)) #endif +struct _PALETTE_ENTRY +{ + BYTE red; + BYTE green; + BYTE blue; +}; +typedef struct _PALETTE_ENTRY PALETTE_ENTRY; + +struct rdp_palette +{ + UINT32 count; + PALETTE_ENTRY entries[256]; +}; +typedef struct rdp_palette rdpPalette; + #include struct _RDP_PLUGIN_DATA diff --git a/include/freerdp/update.h b/include/freerdp/update.h index b311e07e5..8428ab6a9 100644 --- a/include/freerdp/update.h +++ b/include/freerdp/update.h @@ -73,14 +73,6 @@ typedef struct _BITMAP_UPDATE BITMAP_UPDATE; /* Palette Updates */ -struct _PALETTE_ENTRY -{ - BYTE red; - BYTE green; - BYTE blue; -}; -typedef struct _PALETTE_ENTRY PALETTE_ENTRY; - struct _PALETTE_UPDATE { UINT32 number; @@ -88,13 +80,6 @@ struct _PALETTE_UPDATE }; typedef struct _PALETTE_UPDATE PALETTE_UPDATE; -struct rdp_palette -{ - UINT32 count; - PALETTE_ENTRY entries[256]; -}; -typedef struct rdp_palette rdpPalette; - /* Play Sound (System Beep) Updates */ struct _PLAY_SOUND_UPDATE diff --git a/libfreerdp/codec/CMakeLists.txt b/libfreerdp/codec/CMakeLists.txt index 75999d262..bab5714f6 100644 --- a/libfreerdp/codec/CMakeLists.txt +++ b/libfreerdp/codec/CMakeLists.txt @@ -23,10 +23,9 @@ set(${MODULE_PREFIX}_SRCS color.c audio.c planar.c - planar.h + bitmap.c + interleaved.c progressive.c - bitmap_decode.c - bitmap_encode.c rfx_bitstream.h rfx_constants.h rfx_decode.c diff --git a/libfreerdp/codec/bitmap_encode.c b/libfreerdp/codec/bitmap.c similarity index 99% rename from libfreerdp/codec/bitmap_encode.c rename to libfreerdp/codec/bitmap.c index 9db6f1a14..ccb104ed2 100644 --- a/libfreerdp/codec/bitmap_encode.c +++ b/libfreerdp/codec/bitmap.c @@ -22,6 +22,7 @@ #endif #include +#include #define GETPIXEL16(d, x, y, w) (*(((unsigned short*)d) + ((y) * (w) + (x)))) #define GETPIXEL32(d, x, y, w) (*(((unsigned int*)d) + ((y) * (w) + (x)))) diff --git a/libfreerdp/codec/bitmap_decode.c b/libfreerdp/codec/interleaved.c similarity index 71% rename from libfreerdp/codec/bitmap_decode.c rename to libfreerdp/codec/interleaved.c index ee6e672e6..68a224b90 100644 --- a/libfreerdp/codec/bitmap_decode.c +++ b/libfreerdp/codec/interleaved.c @@ -1,8 +1,8 @@ /** * FreeRDP: A Remote Desktop Protocol Implementation - * Bitmap Decompression + * Interleaved RLE Bitmap Codec * - * Copyright 2011 Jay Sorg + * Copyright 2014 Marc-Andre Moreau * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,14 +21,7 @@ #include "config.h" #endif -#include -#include - -#include "planar.h" - -#include - -#include +#include /* RLE Compressed Bitmap Stream (RLE_BITMAP_STREAM) @@ -242,57 +235,104 @@ static INLINE UINT32 ExtractRunLength(UINT32 code, BYTE* pbOrderHdr, UINT32* adv #define RLEEXTRA #include "include/bitmap.c" -/** - * bitmap decompression routine - */ -BOOL bitmap_decompress(BYTE* srcData, BYTE* dstData, int width, int height, int size, int srcBpp, int dstBpp) +int interleaved_decompress(BITMAP_INTERLEAVED_CONTEXT* interleaved, BYTE* pSrcData, UINT32 SrcSize, int bpp, + BYTE** ppDstData, DWORD DstFormat, int nDstStep, int nXDst, int nYDst, int nWidth, int nHeight) { - int status; - BYTE* TmpBfr; + BOOL vFlip; + int scanline; BYTE* pDstData; + UINT32 BufferSize; + int dstBitsPerPixel; + int dstBytesPerPixel; - if (srcBpp == 16 && dstBpp == 16) - { - TmpBfr = (BYTE*) _aligned_malloc(width * height * 2, 16); - RleDecompress16to16(srcData, size, TmpBfr, width * 2, width, height); - freerdp_bitmap_flip(TmpBfr, dstData, width * 2, height); - _aligned_free(TmpBfr); - } - else if (srcBpp == 32 && dstBpp == 32) - { - pDstData = dstData; + pDstData = *ppDstData; + dstBitsPerPixel = FREERDP_PIXEL_FORMAT_DEPTH(DstFormat); + dstBytesPerPixel = (FREERDP_PIXEL_FORMAT_BPP(DstFormat) / 8); + vFlip = FREERDP_PIXEL_FORMAT_FLIP(DstFormat) ? TRUE : FALSE; - status = planar_decompress(NULL, srcData, size, &pDstData, - PIXEL_FORMAT_XRGB32_VF, width * 4, 0, 0, width, height); + if (!interleaved) + return -1; - if (status < 0) - return FALSE; - } - else if (srcBpp == 15 && dstBpp == 15) + if (bpp == 24) { - TmpBfr = (BYTE*) _aligned_malloc(width * height * 2, 16); - RleDecompress16to16(srcData, size, TmpBfr, width * 2, width, height); - freerdp_bitmap_flip(TmpBfr, dstData, width * 2, height); - _aligned_free(TmpBfr); + scanline = nWidth * 3; + BufferSize = scanline * nHeight; + + if (BufferSize > interleaved->FlipSize) + { + interleaved->FlipBuffer = _aligned_realloc(interleaved->FlipBuffer, BufferSize, 16); + interleaved->FlipSize = BufferSize; + } + + if (!interleaved->FlipBuffer) + return -1; + + RleDecompress24to24(pSrcData, SrcSize, interleaved->FlipBuffer, scanline, nWidth, nHeight); + freerdp_bitmap_flip(interleaved->FlipBuffer, pDstData, scanline, nHeight); } - else if (srcBpp == 8 && dstBpp == 8) + else if ((bpp == 16) || (bpp == 15)) { - TmpBfr = (BYTE*) _aligned_malloc(width * height, 16); - RleDecompress8to8(srcData, size, TmpBfr, width, width, height); - freerdp_bitmap_flip(TmpBfr, dstData, width, height); - _aligned_free(TmpBfr); + scanline = nWidth * 2; + BufferSize = scanline * nHeight; + + if (BufferSize > interleaved->FlipSize) + { + interleaved->FlipBuffer = _aligned_realloc(interleaved->FlipBuffer, BufferSize, 16); + interleaved->FlipSize = BufferSize; + } + + if (!interleaved->FlipBuffer) + return -1; + + RleDecompress16to16(pSrcData, SrcSize, interleaved->FlipBuffer, scanline, nWidth, nHeight); + freerdp_bitmap_flip(interleaved->FlipBuffer, pDstData, scanline, nHeight); } - else if (srcBpp == 24 && dstBpp == 24) + else if (bpp == 8) { - TmpBfr = (BYTE*) _aligned_malloc(width * height * 3, 16); - RleDecompress24to24(srcData, size, TmpBfr, width * 3, width, height); - freerdp_bitmap_flip(TmpBfr, dstData, width * 3, height); - _aligned_free(TmpBfr); + scanline = nWidth; + BufferSize = scanline * nHeight; + + if (BufferSize > interleaved->FlipSize) + { + interleaved->FlipBuffer = _aligned_realloc(interleaved->FlipBuffer, BufferSize, 16); + interleaved->FlipSize = BufferSize; + } + + if (!interleaved->FlipBuffer) + return -1; + + RleDecompress8to8(pSrcData, SrcSize, interleaved->FlipBuffer, scanline, nWidth, nHeight); + freerdp_bitmap_flip(interleaved->FlipBuffer, pDstData, scanline, nHeight); } else { - return FALSE; + return -1; } - return TRUE; + return 1; +} + +BITMAP_INTERLEAVED_CONTEXT* bitmap_interleaved_context_new(BOOL Compressor) +{ + BITMAP_INTERLEAVED_CONTEXT* interleaved; + + interleaved = (BITMAP_INTERLEAVED_CONTEXT*) calloc(1, sizeof(BITMAP_INTERLEAVED_CONTEXT*)); + + if (interleaved) + { + interleaved->FlipSize = 64 * 64 * 3; + interleaved->FlipBuffer = _aligned_malloc(interleaved->FlipSize, 16); + } + + return interleaved; +} + +void bitmap_interleaved_context_free(BITMAP_INTERLEAVED_CONTEXT* interleaved) +{ + if (!interleaved) + return; + + _aligned_free(interleaved->FlipBuffer); + + free(interleaved); } diff --git a/libfreerdp/codec/planar.c b/libfreerdp/codec/planar.c index 37ce3ed7e..7c08cc0eb 100644 --- a/libfreerdp/codec/planar.c +++ b/libfreerdp/codec/planar.c @@ -27,8 +27,7 @@ #include #include #include - -#include "planar.h" +#include static int planar_skip_plane_rle(const BYTE* pSrcData, UINT32 SrcSize, int nWidth, int nHeight) { diff --git a/libfreerdp/codec/test/TestFreeRDPCodecPlanar.c b/libfreerdp/codec/test/TestFreeRDPCodecPlanar.c index 976b655a6..8d10e9cca 100644 --- a/libfreerdp/codec/test/TestFreeRDPCodecPlanar.c +++ b/libfreerdp/codec/test/TestFreeRDPCodecPlanar.c @@ -5,6 +5,7 @@ #include #include #include +#include /** * Experimental Case 01: 64x64 (32bpp) @@ -2864,16 +2865,6 @@ const BYTE TEST_RDP6_SCANLINES_DELTA_2C_ENCODED_UNSIGNED[3][6] = { 0x01, 0x67, 0x8B, 0xA3, 0x78, 0xAF } }; -#include "../planar.h" - -static unsigned long next = 1; - -static int simple_rand(void) -{ - next = next * 1103515245 + 12345; - return ((unsigned int) (next / 65536) % 32768); -} - static void fill_bitmap_alpha_channel(BYTE* data, int width, int height, BYTE value) { int i, j; @@ -3095,9 +3086,10 @@ int test_individual_planes_encoding_rle() int TestFreeRDPCodecPlanar(int argc, char* argv[]) { - int i, j; + int i; int dstSize; UINT32 format; + BYTE* pDstData; HCLRCONV clrconv; DWORD planarFlags; BYTE* srcBitmap32; @@ -3105,7 +3097,6 @@ int TestFreeRDPCodecPlanar(int argc, char* argv[]) int width, height; BYTE* blackBitmap; BYTE* whiteBitmap; - BYTE* randomBitmap; BYTE* compressedBitmap; BYTE* decompressedBitmap; BITMAP_PLANAR_CONTEXT* planar; @@ -3147,7 +3138,10 @@ int TestFreeRDPCodecPlanar(int argc, char* argv[]) decompressedBitmap = (BYTE*) malloc(width * height * 4); ZeroMemory(decompressedBitmap, width * height * 4); - if (!bitmap_decompress(compressedBitmap, decompressedBitmap, width, height, dstSize, 32, 32)) + pDstData = decompressedBitmap; + + if (planar_decompress(planar, compressedBitmap, dstSize, &pDstData, + PIXEL_FORMAT_XRGB32, width * 4, 0, 0, width, height) < 0) { printf("failed to decompress white bitmap: width: %d height: %d\n", width, height); return -1; @@ -3187,7 +3181,10 @@ int TestFreeRDPCodecPlanar(int argc, char* argv[]) decompressedBitmap = (BYTE*) malloc(width * height * 4); ZeroMemory(decompressedBitmap, width * height * 4); - if (!bitmap_decompress(compressedBitmap, decompressedBitmap, width, height, dstSize, 32, 32)) + pDstData = decompressedBitmap; + + if (planar_decompress(planar, compressedBitmap, dstSize, &pDstData, + PIXEL_FORMAT_XRGB32, width * 4, 0, 0, width, height) < 0) { printf("failed to decompress black bitmap: width: %d height: %d\n", width, height); return -1; @@ -3213,50 +3210,7 @@ int TestFreeRDPCodecPlanar(int argc, char* argv[]) free(decompressedBitmap); } - for (i = 4; i < 64; i += 4) - { - width = i; - height = i; - - randomBitmap = (BYTE*) malloc(width * height * 4); - - for (j = 0; j < width * height * 4; j++) - { - randomBitmap[j] = (BYTE) (simple_rand() % 256); - } - - fill_bitmap_alpha_channel(randomBitmap, width, height, 0x00); - - compressedBitmap = freerdp_bitmap_compress_planar(planar, randomBitmap, format, width, height, width * 4, NULL, &dstSize); - - decompressedBitmap = (BYTE*) malloc(width * height * 4); - ZeroMemory(decompressedBitmap, width * height * 4); - - if (!bitmap_decompress(compressedBitmap, decompressedBitmap, width, height, dstSize, 32, 32)) - { - printf("failed to decompress random bitmap: width: %d height: %d\n", width, height); - return -1; - } - else - { - printf("success decompressing random bitmap: width: %d height: %d\n", width, height); - } - - if (memcmp(decompressedBitmap, randomBitmap, width * height * 4) != 0) - { - printf("random bitmap\n"); - winpr_HexDump(randomBitmap, width * height * 4); - - printf("decompressed bitmap\n"); - winpr_HexDump(decompressedBitmap, width * height * 4); - - printf("error decompressed random bitmap corrupted: width: %d height: %d\n", width, height); - return -1; - } - - free(compressedBitmap); - free(decompressedBitmap); - } + return 0; /* Experimental Case 01 */ @@ -3269,7 +3223,10 @@ int TestFreeRDPCodecPlanar(int argc, char* argv[]) decompressedBitmap = (BYTE*) malloc(width * height * 4); ZeroMemory(decompressedBitmap, width * height * 4); - if (!bitmap_decompress(compressedBitmap, decompressedBitmap, width, height, dstSize, 32, 32)) + pDstData = decompressedBitmap; + + if (planar_decompress(planar, compressedBitmap, dstSize, &pDstData, + PIXEL_FORMAT_XRGB32, width * 4, 0, 0, width, height) < 0) { printf("failed to decompress experimental bitmap 01: width: %d height: %d\n", width, height); return -1; @@ -3310,7 +3267,10 @@ int TestFreeRDPCodecPlanar(int argc, char* argv[]) decompressedBitmap = (BYTE*) malloc(width * height * 4); ZeroMemory(decompressedBitmap, width * height * 4); - if (!bitmap_decompress(compressedBitmap, decompressedBitmap, width, height, dstSize, 32, 32)) + pDstData = decompressedBitmap; + + if (planar_decompress(planar, compressedBitmap, dstSize, &pDstData, + PIXEL_FORMAT_XRGB32, width * 4, 0, 0, width, height) < 0) { printf("failed to decompress experimental bitmap 02: width: %d height: %d\n", width, height); return -1; @@ -3357,7 +3317,10 @@ int TestFreeRDPCodecPlanar(int argc, char* argv[]) decompressedBitmap = (BYTE*) malloc(width * height * 4); ZeroMemory(decompressedBitmap, width * height * 4); - if (!bitmap_decompress(compressedBitmap, decompressedBitmap, width, height, dstSize, 32, 32)) + pDstData = decompressedBitmap; + + if (planar_decompress(planar, compressedBitmap, dstSize, &pDstData, + PIXEL_FORMAT_XRGB32, width * 4, 0, 0, width, height) < 0) { printf("failed to decompress experimental bitmap 03: width: %d height: %d\n", width, height); return -1; diff --git a/libfreerdp/core/CMakeLists.txt b/libfreerdp/core/CMakeLists.txt index 6504599d8..20961a213 100644 --- a/libfreerdp/core/CMakeLists.txt +++ b/libfreerdp/core/CMakeLists.txt @@ -79,6 +79,7 @@ set(${MODULE_PREFIX}_SRCS client.h server.c server.h + codecs.c metrics.c capabilities.c capabilities.h diff --git a/libfreerdp/core/codecs.c b/libfreerdp/core/codecs.c new file mode 100644 index 000000000..7aaf1367a --- /dev/null +++ b/libfreerdp/core/codecs.c @@ -0,0 +1,157 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * RDP Codecs + * + * Copyright 2014 Marc-Andre Moreau + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "rdp.h" + +#include + +int freerdp_client_codecs_prepare(rdpCodecs* codecs, UINT32 flags) +{ + if (flags & FREERDP_CODEC_INTERLEAVED) + { + if (!codecs->interleaved) + { + codecs->interleaved = bitmap_interleaved_context_new(FALSE); + } + } + + if (flags & FREERDP_CODEC_PLANAR) + { + if (!codecs->planar) + { + codecs->planar = freerdp_bitmap_planar_context_new(FALSE, 64, 64); + } + } + + if (flags & FREERDP_CODEC_NSCODEC) + { + if (!codecs->nsc) + { + codecs->nsc = nsc_context_new(); + } + } + + if (flags & FREERDP_CODEC_REMOTEFX) + { + if (!codecs->rfx) + { + codecs->rfx = rfx_context_new(FALSE); + } + } + + if (flags & FREERDP_CODEC_CLEARCODEC) + { + if (!codecs->clear) + { + codecs->clear = clear_context_new(FALSE); + } + } + + if (flags & FREERDP_CODEC_ALPHACODEC) + { + + } + + if (flags & FREERDP_CODEC_PROGRESSIVE) + { + if (!codecs->progressive) + { + codecs->progressive = progressive_context_new(FALSE); + } + } + + if (flags & FREERDP_CODEC_H264) + { + if (!codecs->h264) + { + codecs->h264 = h264_context_new(FALSE); + } + } + + return 1; +} + +rdpCodecs* codecs_new(rdpContext* context) +{ + rdpCodecs* codecs; + + codecs = (rdpCodecs*) calloc(1, sizeof(rdpCodecs)); + + if (codecs) + { + codecs->context = context; + } + + return codecs; +} + +void codecs_free(rdpCodecs* codecs) +{ + if (!codecs) + return; + + if (codecs->rfx) + { + rfx_context_free(codecs->rfx); + codecs->rfx = NULL; + } + + if (codecs->nsc) + { + nsc_context_free(codecs->nsc); + codecs->nsc = NULL; + } + + if (codecs->h264) + { + h264_context_free(codecs->h264); + codecs->h264 = NULL; + } + + if (codecs->clear) + { + clear_context_free(codecs->clear); + codecs->clear = NULL; + } + + if (codecs->progressive) + { + progressive_context_free(codecs->progressive); + codecs->progressive = NULL; + } + + if (codecs->planar) + { + freerdp_bitmap_planar_context_free(codecs->planar); + codecs->planar = NULL; + } + + if (codecs->interleaved) + { + bitmap_interleaved_context_free(codecs->interleaved); + codecs->interleaved = NULL; + } + + free(codecs); +} + diff --git a/libfreerdp/core/freerdp.c b/libfreerdp/core/freerdp.c index eeec2a7ae..65a201e2b 100644 --- a/libfreerdp/core/freerdp.c +++ b/libfreerdp/core/freerdp.c @@ -410,6 +410,7 @@ int freerdp_context_new(freerdp* instance) PubSub_AddEventTypes(context->pubSub, FreeRDP_Events, sizeof(FreeRDP_Events) / sizeof(wEventType)); context->metrics = metrics_new(context); + context->codecs = codecs_new(context); rdp = rdp_new(context); instance->input = rdp->input; @@ -465,6 +466,7 @@ void freerdp_context_free(freerdp* instance) PubSub_Free(instance->context->pubSub); metrics_free(instance->context->metrics); + codecs_free(instance->context->codecs); free(instance->context); instance->context = NULL; diff --git a/libfreerdp/gdi/gdi.c b/libfreerdp/gdi/gdi.c index 140bad8e4..24f96a924 100644 --- a/libfreerdp/gdi/gdi.c +++ b/libfreerdp/gdi/gdi.c @@ -793,55 +793,49 @@ void gdi_surface_frame_marker(rdpContext* context, SURFACE_FRAME_MARKER* surface int tilenum = 0; -void gdi_surface_bits(rdpContext* context, SURFACE_BITS_COMMAND* surface_bits_command) +void gdi_surface_bits(rdpContext* context, SURFACE_BITS_COMMAND* cmd) { int i, j; int tx, ty; char* tile_bitmap; RFX_MESSAGE* message; rdpGdi* gdi = context->gdi; - RFX_CONTEXT* rfx_context = (RFX_CONTEXT*) gdi->rfx_context; - NSC_CONTEXT* nsc_context = (NSC_CONTEXT*) gdi->nsc_context; DEBUG_GDI("destLeft %d destTop %d destRight %d destBottom %d " "bpp %d codecID %d width %d height %d length %d", - surface_bits_command->destLeft, surface_bits_command->destTop, - surface_bits_command->destRight, surface_bits_command->destBottom, - surface_bits_command->bpp, surface_bits_command->codecID, - surface_bits_command->width, surface_bits_command->height, - surface_bits_command->bitmapDataLength); + cmd->destLeft, cmd->destTop, + cmd->destRight, cmd->destBottom, + cmd->bpp, cmd->codecID, + cmd->width, cmd->height, + cmd->bitmapDataLength); tile_bitmap = (char*) _aligned_malloc(32, 16); if (!tile_bitmap) return; - if (surface_bits_command->codecID == RDP_CODEC_ID_REMOTEFX) + if (cmd->codecID == RDP_CODEC_ID_REMOTEFX) { - message = rfx_process_message(rfx_context, - surface_bits_command->bitmapData, surface_bits_command->bitmapDataLength); + freerdp_client_codecs_prepare(gdi->codecs, FREERDP_CODEC_REMOTEFX); + + message = rfx_process_message(gdi->codecs->rfx, + cmd->bitmapData, cmd->bitmapDataLength); DEBUG_GDI("num_rects %d num_tiles %d", message->numRects, message->numTiles); /* blit each tile */ for (i = 0; i < message->numTiles; i++) { - tx = message->tiles[i]->x + surface_bits_command->destLeft; - ty = message->tiles[i]->y + surface_bits_command->destTop; + tx = message->tiles[i]->x + cmd->destLeft; + ty = message->tiles[i]->y + cmd->destTop; freerdp_image_convert(message->tiles[i]->data, gdi->tile->bitmap->data, 64, 64, 32, 32, gdi->clrconv); -#ifdef DUMP_REMOTEFX_TILES - sprintf(tile_bitmap, "/tmp/rfx/tile_%d.bmp", tilenum++); - winpr_bitmap_write(tile_bitmap, gdi->tile->bitmap->data, 64, 64, 32); -#endif - - for (j = 0; j < message->numRects; j++) { gdi_SetClipRgn(gdi->primary->hdc, - surface_bits_command->destLeft + message->rects[j].x, - surface_bits_command->destTop + message->rects[j].y, + cmd->destLeft + message->rects[j].x, + cmd->destTop + message->rects[j].y, message->rects[j].width, message->rects[j].height); gdi_BitBlt(gdi->primary->hdc, tx, ty, 64, 64, gdi->tile->hdc, 0, 0, GDI_SRCCOPY); @@ -849,43 +843,45 @@ void gdi_surface_bits(rdpContext* context, SURFACE_BITS_COMMAND* surface_bits_co } gdi_SetNullClipRgn(gdi->primary->hdc); - rfx_message_free(rfx_context, message); + rfx_message_free(gdi->codecs->rfx, message); } - else if (surface_bits_command->codecID == RDP_CODEC_ID_NSCODEC) + else if (cmd->codecID == RDP_CODEC_ID_NSCODEC) { - nsc_process_message(nsc_context, surface_bits_command->bpp, surface_bits_command->width, surface_bits_command->height, - surface_bits_command->bitmapData, surface_bits_command->bitmapDataLength); - gdi->image->bitmap->width = surface_bits_command->width; - gdi->image->bitmap->height = surface_bits_command->height; - gdi->image->bitmap->bitsPerPixel = surface_bits_command->bpp; + freerdp_client_codecs_prepare(gdi->codecs, FREERDP_CODEC_NSCODEC); + + nsc_process_message(gdi->codecs->nsc, cmd->bpp, cmd->width, cmd->height, + cmd->bitmapData, cmd->bitmapDataLength); + gdi->image->bitmap->width = cmd->width; + gdi->image->bitmap->height = cmd->height; + gdi->image->bitmap->bitsPerPixel = cmd->bpp; gdi->image->bitmap->bytesPerPixel = gdi->image->bitmap->bitsPerPixel / 8; gdi->image->bitmap->data = (BYTE*) _aligned_realloc(gdi->image->bitmap->data, gdi->image->bitmap->width * gdi->image->bitmap->height * 4, 16); - freerdp_image_convert(nsc_context->BitmapData, gdi->image->bitmap->data, - surface_bits_command->width, surface_bits_command->height, - surface_bits_command->bpp, gdi->dstBpp, gdi->clrconv); + freerdp_image_convert(gdi->codecs->nsc->BitmapData, gdi->image->bitmap->data, + cmd->width, cmd->height, + cmd->bpp, gdi->dstBpp, gdi->clrconv); freerdp_image_flip(gdi->image->bitmap->data, gdi->image->bitmap->data, gdi->image->bitmap->width, gdi->image->bitmap->height, gdi->dstBpp); - gdi_BitBlt(gdi->primary->hdc, surface_bits_command->destLeft, surface_bits_command->destTop, surface_bits_command->width, surface_bits_command->height, gdi->image->hdc, 0, 0, GDI_SRCCOPY); + gdi_BitBlt(gdi->primary->hdc, cmd->destLeft, cmd->destTop, cmd->width, cmd->height, gdi->image->hdc, 0, 0, GDI_SRCCOPY); } - else if (surface_bits_command->codecID == RDP_CODEC_ID_NONE) + else if (cmd->codecID == RDP_CODEC_ID_NONE) { - gdi->image->bitmap->width = surface_bits_command->width; - gdi->image->bitmap->height = surface_bits_command->height; - gdi->image->bitmap->bitsPerPixel = surface_bits_command->bpp; + gdi->image->bitmap->width = cmd->width; + gdi->image->bitmap->height = cmd->height; + gdi->image->bitmap->bitsPerPixel = cmd->bpp; gdi->image->bitmap->bytesPerPixel = gdi->image->bitmap->bitsPerPixel / 8; gdi->image->bitmap->data = (BYTE*) _aligned_realloc(gdi->image->bitmap->data, gdi->image->bitmap->width * gdi->image->bitmap->height * 4, 16); - if ((surface_bits_command->bpp != 32) || (gdi->clrconv->alpha == TRUE)) + if ((cmd->bpp != 32) || (gdi->clrconv->alpha)) { BYTE* temp_image; - freerdp_image_convert(surface_bits_command->bitmapData, gdi->image->bitmap->data, + freerdp_image_convert(cmd->bitmapData, gdi->image->bitmap->data, gdi->image->bitmap->width, gdi->image->bitmap->height, gdi->image->bitmap->bitsPerPixel, 32, gdi->clrconv); - surface_bits_command->bpp = 32; - surface_bits_command->bitmapData = gdi->image->bitmap->data; + cmd->bpp = 32; + cmd->bitmapData = gdi->image->bitmap->data; temp_image = (BYTE*) _aligned_malloc(gdi->image->bitmap->width * gdi->image->bitmap->height * 4, 16); freerdp_image_flip(gdi->image->bitmap->data, temp_image, gdi->image->bitmap->width, gdi->image->bitmap->height, 32); @@ -894,16 +890,16 @@ void gdi_surface_bits(rdpContext* context, SURFACE_BITS_COMMAND* surface_bits_co } else { - freerdp_image_flip(surface_bits_command->bitmapData, gdi->image->bitmap->data, + freerdp_image_flip(cmd->bitmapData, gdi->image->bitmap->data, gdi->image->bitmap->width, gdi->image->bitmap->height, 32); } - gdi_BitBlt(gdi->primary->hdc, surface_bits_command->destLeft, surface_bits_command->destTop, - surface_bits_command->width, surface_bits_command->height, gdi->image->hdc, 0, 0, GDI_SRCCOPY); + gdi_BitBlt(gdi->primary->hdc, cmd->destLeft, cmd->destTop, + cmd->width, cmd->height, gdi->image->hdc, 0, 0, GDI_SRCCOPY); } else { - DEBUG_WARN( "Unsupported codecID %d\n", surface_bits_command->codecID); + DEBUG_WARN( "Unsupported codecID %d\n", cmd->codecID); } if (tile_bitmap) @@ -1020,6 +1016,7 @@ int gdi_init(freerdp* instance, UINT32 flags, BYTE* buffer) instance->context->gdi = gdi; cache = instance->context->cache; + gdi->codecs = instance->context->codecs; gdi->width = instance->settings->DesktopWidth; gdi->height = instance->settings->DesktopHeight; gdi->srcBpp = instance->settings->ColorDepth; @@ -1103,9 +1100,6 @@ int gdi_init(freerdp* instance, UINT32 flags, BYTE* buffer) gdi_register_graphics(instance->context->graphics); - gdi->rfx_context = rfx_context_new(FALSE); - gdi->nsc_context = nsc_context_new(); - return 0; } @@ -1119,8 +1113,6 @@ void gdi_free(freerdp* instance) gdi_bitmap_free_ex(gdi->tile); gdi_bitmap_free_ex(gdi->image); gdi_DeleteDC(gdi->hdc); - rfx_context_free((RFX_CONTEXT*) gdi->rfx_context); - nsc_context_free((NSC_CONTEXT*) gdi->nsc_context); free(gdi->clrconv->palette); free(gdi->clrconv); free(gdi); diff --git a/libfreerdp/gdi/graphics.c b/libfreerdp/gdi/graphics.c index f68e62c11..2a8e0617c 100644 --- a/libfreerdp/gdi/graphics.c +++ b/libfreerdp/gdi/graphics.c @@ -98,7 +98,7 @@ void gdi_Bitmap_Decompress(rdpContext* context, rdpBitmap* bitmap, BYTE* data, int width, int height, int bpp, int length, BOOL compressed, int codecId) { - BOOL status; + int status; UINT16 size; BYTE* src; BYTE* dst; @@ -107,6 +107,8 @@ void gdi_Bitmap_Decompress(rdpContext* context, rdpBitmap* bitmap, rdpGdi* gdi; RFX_MESSAGE* msg; + gdi = context->gdi; + size = width * height * ((bpp + 7) / 8); if (!bitmap->data) @@ -117,15 +119,16 @@ void gdi_Bitmap_Decompress(rdpContext* context, rdpBitmap* bitmap, switch (codecId) { case RDP_CODEC_ID_NSCODEC: - gdi = context->gdi; - nsc_process_message(gdi->nsc_context, bpp, width, height, data, length); - freerdp_image_flip(((NSC_CONTEXT*) gdi->nsc_context)->BitmapData, bitmap->data, width, height, bpp); + freerdp_client_codecs_prepare(gdi->codecs, FREERDP_CODEC_NSCODEC); + nsc_process_message(gdi->codecs->nsc, bpp, width, height, data, length); + freerdp_image_flip(gdi->codecs->nsc->BitmapData, bitmap->data, width, height, bpp); break; case RDP_CODEC_ID_REMOTEFX: - gdi = context->gdi; - rfx_context_set_pixel_format(gdi->rfx_context, RDP_PIXEL_FORMAT_B8G8R8A8); - msg = rfx_process_message(gdi->rfx_context, data, length); + freerdp_client_codecs_prepare(gdi->codecs, FREERDP_CODEC_REMOTEFX); + rfx_context_set_pixel_format(gdi->codecs->rfx, RDP_PIXEL_FORMAT_B8G8R8A8); + msg = rfx_process_message(gdi->codecs->rfx, data, length); + if (!msg) { DEBUG_WARN( "gdi_Bitmap_Decompress: rfx Decompression Failed\n"); @@ -136,6 +139,7 @@ void gdi_Bitmap_Decompress(rdpContext* context, rdpBitmap* bitmap, { src = msg->tiles[0]->data + yindex * 64 * 4; dst = bitmap->data + yindex * width * 3; + for (xindex = 0; xindex < width; xindex++) { *(dst++) = *(src++); @@ -144,7 +148,7 @@ void gdi_Bitmap_Decompress(rdpContext* context, rdpBitmap* bitmap, src++; } } - rfx_message_free(gdi->rfx_context, msg); + rfx_message_free(gdi->codecs->rfx, msg); } break; case RDP_CODEC_ID_JPEG: @@ -158,11 +162,35 @@ void gdi_Bitmap_Decompress(rdpContext* context, rdpBitmap* bitmap, default: if (compressed) { - status = bitmap_decompress(data, bitmap->data, width, height, length, bpp, bpp); + BYTE* pDstData; + UINT32 SrcSize; - if (!status) + SrcSize = (UINT32) length; + pDstData = bitmap->data; + + if (bpp < 32) { - DEBUG_WARN( "gdi_Bitmap_Decompress: Bitmap Decompression Failed\n"); + freerdp_client_codecs_prepare(gdi->codecs, FREERDP_CODEC_INTERLEAVED); + + status = interleaved_decompress(gdi->codecs->interleaved, data, SrcSize, bpp, + &pDstData, PIXEL_FORMAT_XRGB32_VF, width * 4, 0, 0, width, height); + + if (status < 0) + { + DEBUG_WARN("gdi_Bitmap_Decompress: Bitmap Decompression Failed\n"); + } + } + else + { + freerdp_client_codecs_prepare(gdi->codecs, FREERDP_CODEC_PLANAR); + + status = planar_decompress(gdi->codecs->planar, data, SrcSize, &pDstData, + PIXEL_FORMAT_XRGB32_VF, width * 4, 0, 0, width, height); + + if (status < 0) + { + DEBUG_WARN("gdi_Bitmap_Decompress: Bitmap Decompression Failed\n"); + } } } else diff --git a/libfreerdp/primitives/test/prim_test.h b/libfreerdp/primitives/test/prim_test.h index 37db6a9b6..e535b4710 100644 --- a/libfreerdp/primitives/test/prim_test.h +++ b/libfreerdp/primitives/test/prim_test.h @@ -112,7 +112,7 @@ extern int test_or_32u_speed(void); int size = size_array[s]; \ _prework_; \ iter = iterations/size; \ - sprintf_s(label, "%s-%-4d", oplabel, size); \ + sprintf(label, "%s-%-4d", oplabel, size); \ MEASURE_TIMED(label, iter, test_time, resultNormal[s], \ _funcNormal_); \ } \ @@ -128,7 +128,7 @@ extern int test_or_32u_speed(void); int size = size_array[s]; \ _prework_; \ iter = iterations/size; \ - sprintf_s(label, "%s-%s-%-4d", SIMD_TYPE, oplabel, size); \ + sprintf(label, "%s-%s-%-4d", SIMD_TYPE, oplabel, size); \ MEASURE_TIMED(label, iter, test_time, resultOpt[s], \ _funcOpt_); \ } \ @@ -147,7 +147,7 @@ extern int test_or_32u_speed(void); int size = size_array[s]; \ _prework_; \ iter = iterations/size; \ - sprintf_s(label, "IPP-%s-%-4d", oplabel, size); \ + sprintf(label, "IPP-%s-%-4d", oplabel, size); \ MEASURE_TIMED(label, iter, test_time, resultIPP[s], \ _funcIPP_); \ } \ @@ -218,7 +218,7 @@ static void _name_( \ _floatprint(resultOpt[s], sSN); \ if (resultNormal[s] > 0.0) \ { \ - sprintf_s(sSNp, "%d%%", \ + sprintf(sSNp, "%d%%", \ (int) (resultOpt[s] / resultNormal[s] * 100.0 + 0.5)); \ } \ } \ @@ -227,7 +227,7 @@ static void _name_( \ _floatprint(resultIPP[s], sIPP); \ if (resultNormal[s] > 0.0) \ { \ - sprintf_s(sIPPp, "%d%%", \ + sprintf(sIPPp, "%d%%", \ (int) (resultIPP[s] / resultNormal[s] * 100.0 + 0.5)); \ } \ } \