diff options
Diffstat (limited to 'libfreerdp/codec/rfx_encode.c')
-rw-r--r-- | libfreerdp/codec/rfx_encode.c | 313 |
1 files changed, 313 insertions, 0 deletions
diff --git a/libfreerdp/codec/rfx_encode.c b/libfreerdp/codec/rfx_encode.c new file mode 100644 index 0000000..12bc77b --- /dev/null +++ b/libfreerdp/codec/rfx_encode.c @@ -0,0 +1,313 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * RemoteFX Codec Library - Encode + * + * Copyright 2011 Vic Lee + * Copyright 2011 Norbert Federa <norbert.federa@thincast.com> + * + * 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. + */ + +#include <freerdp/config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <winpr/crt.h> +#include <winpr/collections.h> + +#include <freerdp/primitives.h> + +#include "rfx_types.h" +#include "rfx_rlgr.h" +#include "rfx_differential.h" +#include "rfx_quantization.h" +#include "rfx_dwt.h" + +#include "rfx_encode.h" + +#define MINMAX(_v, _l, _h) ((_v) < (_l) ? (_l) : ((_v) > (_h) ? (_h) : (_v))) + +static void rfx_encode_format_rgb(const BYTE* rgb_data, int width, int height, int rowstride, + UINT32 pixel_format, const BYTE* palette, INT16* r_buf, + INT16* g_buf, INT16* b_buf) +{ + int x_exceed = 0; + int y_exceed = 0; + const BYTE* src = NULL; + INT16 r = 0; + INT16 g = 0; + INT16 b = 0; + INT16* r_last = NULL; + INT16* g_last = NULL; + INT16* b_last = NULL; + x_exceed = 64 - width; + y_exceed = 64 - height; + + for (int y = 0; y < height; y++) + { + src = rgb_data + y * rowstride; + + switch (pixel_format) + { + case PIXEL_FORMAT_BGRX32: + case PIXEL_FORMAT_BGRA32: + for (int x = 0; x < width; x++) + { + *b_buf++ = (INT16)(*src++); + *g_buf++ = (INT16)(*src++); + *r_buf++ = (INT16)(*src++); + src++; + } + + break; + + case PIXEL_FORMAT_XBGR32: + case PIXEL_FORMAT_ABGR32: + for (int x = 0; x < width; x++) + { + src++; + *b_buf++ = (INT16)(*src++); + *g_buf++ = (INT16)(*src++); + *r_buf++ = (INT16)(*src++); + } + + break; + + case PIXEL_FORMAT_RGBX32: + case PIXEL_FORMAT_RGBA32: + for (int x = 0; x < width; x++) + { + *r_buf++ = (INT16)(*src++); + *g_buf++ = (INT16)(*src++); + *b_buf++ = (INT16)(*src++); + src++; + } + + break; + + case PIXEL_FORMAT_XRGB32: + case PIXEL_FORMAT_ARGB32: + for (int x = 0; x < width; x++) + { + src++; + *r_buf++ = (INT16)(*src++); + *g_buf++ = (INT16)(*src++); + *b_buf++ = (INT16)(*src++); + } + + break; + + case PIXEL_FORMAT_BGR24: + for (int x = 0; x < width; x++) + { + *b_buf++ = (INT16)(*src++); + *g_buf++ = (INT16)(*src++); + *r_buf++ = (INT16)(*src++); + } + + break; + + case PIXEL_FORMAT_RGB24: + for (int x = 0; x < width; x++) + { + *r_buf++ = (INT16)(*src++); + *g_buf++ = (INT16)(*src++); + *b_buf++ = (INT16)(*src++); + } + + break; + + case PIXEL_FORMAT_BGR16: + for (int x = 0; x < width; x++) + { + *b_buf++ = (INT16)(((*(src + 1)) & 0xF8) | ((*(src + 1)) >> 5)); + *g_buf++ = (INT16)((((*(src + 1)) & 0x07) << 5) | (((*src) & 0xE0) >> 3)); + *r_buf++ = (INT16)((((*src) & 0x1F) << 3) | (((*src) >> 2) & 0x07)); + src += 2; + } + + break; + + case PIXEL_FORMAT_RGB16: + for (int x = 0; x < width; x++) + { + *r_buf++ = (INT16)(((*(src + 1)) & 0xF8) | ((*(src + 1)) >> 5)); + *g_buf++ = (INT16)((((*(src + 1)) & 0x07) << 5) | (((*src) & 0xE0) >> 3)); + *b_buf++ = (INT16)((((*src) & 0x1F) << 3) | (((*src) >> 2) & 0x07)); + src += 2; + } + + break; + + case PIXEL_FORMAT_RGB8: + if (!palette) + break; + + for (int x = 0; x < width; x++) + { + int shift = 0; + BYTE idx = 0; + shift = (7 - (x % 8)); + idx = ((*src) >> shift) & 1; + idx |= (((*(src + 1)) >> shift) & 1) << 1; + idx |= (((*(src + 2)) >> shift) & 1) << 2; + idx |= (((*(src + 3)) >> shift) & 1) << 3; + idx *= 3; + *r_buf++ = (INT16)palette[idx]; + *g_buf++ = (INT16)palette[idx + 1]; + *b_buf++ = (INT16)palette[idx + 2]; + + if (shift == 0) + src += 4; + } + + break; + + case PIXEL_FORMAT_A4: + if (!palette) + break; + + for (int x = 0; x < width; x++) + { + int idx = (*src) * 3; + *r_buf++ = (INT16)palette[idx]; + *g_buf++ = (INT16)palette[idx + 1]; + *b_buf++ = (INT16)palette[idx + 2]; + src++; + } + + break; + + default: + break; + } + + /* Fill the horizontal region outside of 64x64 tile size with the right-most pixel for best + * quality */ + if (x_exceed > 0) + { + r = *(r_buf - 1); + g = *(g_buf - 1); + b = *(b_buf - 1); + + for (int x = 0; x < x_exceed; x++) + { + *r_buf++ = r; + *g_buf++ = g; + *b_buf++ = b; + } + } + } + + /* Fill the vertical region outside of 64x64 tile size with the last line. */ + if (y_exceed > 0) + { + r_last = r_buf - 64; + g_last = g_buf - 64; + b_last = b_buf - 64; + + while (y_exceed > 0) + { + CopyMemory(r_buf, r_last, 64 * sizeof(INT16)); + CopyMemory(g_buf, g_last, 64 * sizeof(INT16)); + CopyMemory(b_buf, b_last, 64 * sizeof(INT16)); + r_buf += 64; + g_buf += 64; + b_buf += 64; + y_exceed--; + } + } +} + +/* rfx_encode_rgb_to_ycbcr code now resides in the primitives library. */ + +static void rfx_encode_component(RFX_CONTEXT* context, const UINT32* quantization_values, + INT16* data, BYTE* buffer, int buffer_size, int* size) +{ + INT16* dwt_buffer = NULL; + dwt_buffer = BufferPool_Take(context->priv->BufferPool, -1); /* dwt_buffer */ + PROFILER_ENTER(context->priv->prof_rfx_encode_component) + PROFILER_ENTER(context->priv->prof_rfx_dwt_2d_encode) + context->dwt_2d_encode(data, dwt_buffer); + PROFILER_EXIT(context->priv->prof_rfx_dwt_2d_encode) + PROFILER_ENTER(context->priv->prof_rfx_quantization_encode) + context->quantization_encode(data, quantization_values); + PROFILER_EXIT(context->priv->prof_rfx_quantization_encode) + PROFILER_ENTER(context->priv->prof_rfx_differential_encode) + rfx_differential_encode(data + 4032, 64); + PROFILER_EXIT(context->priv->prof_rfx_differential_encode) + PROFILER_ENTER(context->priv->prof_rfx_rlgr_encode) + *size = context->rlgr_encode(context->mode, data, 4096, buffer, buffer_size); + PROFILER_EXIT(context->priv->prof_rfx_rlgr_encode) + PROFILER_EXIT(context->priv->prof_rfx_encode_component) + BufferPool_Return(context->priv->BufferPool, dwt_buffer); +} + +void rfx_encode_rgb(RFX_CONTEXT* context, RFX_TILE* tile) +{ + union + { + const INT16** cpv; + INT16** pv; + } cnv; + BYTE* pBuffer = NULL; + INT16* pSrcDst[3]; + int YLen = 0; + int CbLen = 0; + int CrLen = 0; + UINT32* YQuant = NULL; + UINT32* CbQuant = NULL; + UINT32* CrQuant = NULL; + primitives_t* prims = primitives_get(); + static const prim_size_t roi_64x64 = { 64, 64 }; + + if (!(pBuffer = (BYTE*)BufferPool_Take(context->priv->BufferPool, -1))) + return; + + YLen = CbLen = CrLen = 0; + YQuant = context->quants + (tile->quantIdxY * 10); + CbQuant = context->quants + (tile->quantIdxCb * 10); + CrQuant = context->quants + (tile->quantIdxCr * 10); + pSrcDst[0] = (INT16*)((BYTE*)(&pBuffer[((8192 + 32) * 0) + 16])); /* y_r_buffer */ + pSrcDst[1] = (INT16*)((BYTE*)(&pBuffer[((8192 + 32) * 1) + 16])); /* cb_g_buffer */ + pSrcDst[2] = (INT16*)((BYTE*)(&pBuffer[((8192 + 32) * 2) + 16])); /* cr_b_buffer */ + PROFILER_ENTER(context->priv->prof_rfx_encode_rgb) + PROFILER_ENTER(context->priv->prof_rfx_encode_format_rgb) + rfx_encode_format_rgb(tile->data, tile->width, tile->height, tile->scanline, + context->pixel_format, context->palette, pSrcDst[0], pSrcDst[1], + pSrcDst[2]); + PROFILER_EXIT(context->priv->prof_rfx_encode_format_rgb) + PROFILER_ENTER(context->priv->prof_rfx_rgb_to_ycbcr) + + cnv.pv = pSrcDst; + prims->RGBToYCbCr_16s16s_P3P3(cnv.cpv, 64 * sizeof(INT16), pSrcDst, 64 * sizeof(INT16), + &roi_64x64); + PROFILER_EXIT(context->priv->prof_rfx_rgb_to_ycbcr) + /** + * We need to clear the buffers as the RLGR encoder expects it to be initialized to zero. + * This allows simplifying and improving the performance of the encoding process. + */ + ZeroMemory(tile->YData, 4096); + ZeroMemory(tile->CbData, 4096); + ZeroMemory(tile->CrData, 4096); + rfx_encode_component(context, YQuant, pSrcDst[0], tile->YData, 4096, &YLen); + rfx_encode_component(context, CbQuant, pSrcDst[1], tile->CbData, 4096, &CbLen); + rfx_encode_component(context, CrQuant, pSrcDst[2], tile->CrData, 4096, &CrLen); + tile->YLen = (UINT16)YLen; + tile->CbLen = (UINT16)CbLen; + tile->CrLen = (UINT16)CrLen; + PROFILER_EXIT(context->priv->prof_rfx_encode_rgb) + BufferPool_Return(context->priv->BufferPool, pBuffer); +} |