22#include <freerdp/config.h>
28#include <winpr/assert.h>
29#include <winpr/cast.h>
32#include <freerdp/codec/nsc.h>
33#include <freerdp/codec/color.h>
36#include "nsc_encode.h"
48 BYTE* PlaneBuffers[5];
49 UINT32 OrgByteCount[4];
51 UINT32 LumaPlaneByteCount;
52 UINT32 OrangeChromaPlaneByteCount;
53 UINT32 GreenChromaPlaneByteCount;
54 UINT32 AlphaPlaneByteCount;
56 UINT8 ChromaSubsamplingLevel;
59static BOOL nsc_write_message(NSC_CONTEXT* WINPR_RESTRICT context,
wStream* WINPR_RESTRICT s,
60 const NSC_MESSAGE* WINPR_RESTRICT message);
62static BOOL nsc_context_initialize_encode(NSC_CONTEXT* WINPR_RESTRICT context)
64 const UINT32 tempWidth = ROUND_UP_TO(context->width, 8);
65 const UINT32 tempHeight = ROUND_UP_TO(context->height, 2);
67 const UINT32 length = tempWidth * tempHeight + 16;
69 if (length > context->priv->PlaneBuffersLength)
71 for (
int i = 0; i < 5; i++)
73 BYTE* tmp = (BYTE*)winpr_aligned_recalloc(context->priv->PlaneBuffers[i], length,
78 nsc_context_planebuffers_free(context->priv);
82 context->priv->PlaneBuffers[i] = tmp;
85 context->priv->PlaneBuffersLength = length;
88 if (context->ChromaSubsamplingLevel)
90 context->OrgByteCount[0] = tempWidth * context->height;
91 context->OrgByteCount[1] = tempWidth * tempHeight / 4;
92 context->OrgByteCount[2] = tempWidth * tempHeight / 4;
93 context->OrgByteCount[3] = context->width * context->height;
97 context->OrgByteCount[0] = context->width * context->height;
98 context->OrgByteCount[1] = context->width * context->height;
99 context->OrgByteCount[2] = context->width * context->height;
100 context->OrgByteCount[3] = context->width * context->height;
106static BOOL nsc_encode_argb_to_aycocg(NSC_CONTEXT* WINPR_RESTRICT context,
107 const BYTE* WINPR_RESTRICT data, UINT32 scanline)
110 const BYTE* src =
nullptr;
111 BYTE* yplane =
nullptr;
112 BYTE* coplane =
nullptr;
113 BYTE* cgplane =
nullptr;
114 BYTE* aplane =
nullptr;
120 UINT16 tempWidth = ROUND_UP_TO(context->width, 8);
121 const UINT16 rw = (context->ChromaSubsamplingLevel ? tempWidth : context->width);
122 const BYTE ccl = WINPR_ASSERTING_INT_CAST(BYTE, context->ColorLossLevel);
124 for (; y < context->height; y++)
126 src = data + (context->height - 1 - y) * scanline;
127 yplane = context->priv->PlaneBuffers[0] + y * rw;
128 coplane = context->priv->PlaneBuffers[1] + y * rw;
129 cgplane = context->priv->PlaneBuffers[2] + y * rw;
130 aplane = context->priv->PlaneBuffers[3] + y * context->width;
133 for (; x < context->width; x++)
135 switch (context->format)
137 case PIXEL_FORMAT_BGRX32:
145 case PIXEL_FORMAT_BGRA32:
152 case PIXEL_FORMAT_RGBX32:
160 case PIXEL_FORMAT_RGBA32:
167 case PIXEL_FORMAT_BGR24:
174 case PIXEL_FORMAT_RGB24:
181 case PIXEL_FORMAT_BGR16:
182 b_val = (INT16)(((*(src + 1)) & 0xF8) | ((*(src + 1)) >> 5));
183 g_val = (INT16)((((*(src + 1)) & 0x07) << 5) | (((*src) & 0xE0) >> 3));
184 r_val = (INT16)((((*src) & 0x1F) << 3) | (((*src) >> 2) & 0x07));
189 case PIXEL_FORMAT_RGB16:
190 r_val = (INT16)(((*(src + 1)) & 0xF8) | ((*(src + 1)) >> 5));
191 g_val = (INT16)((((*(src + 1)) & 0x07) << 5) | (((*src) & 0xE0) >> 3));
192 b_val = (INT16)((((*src) & 0x1F) << 3) | (((*src) >> 2) & 0x07));
197 case PIXEL_FORMAT_A4:
201 shift = (7 - (x % 8));
202 idx = ((*src) >> shift) & 1;
203 idx |= (((*(src + 1)) >> shift) & 1) << 1;
204 idx |= (((*(src + 2)) >> shift) & 1) << 2;
205 idx |= (((*(src + 3)) >> shift) & 1) << 3;
207 r_val = (INT16)context->palette[idx];
208 g_val = (INT16)context->palette[idx + 1];
209 b_val = (INT16)context->palette[idx + 2];
218 case PIXEL_FORMAT_RGB8:
220 int idx = (*src) * 3;
221 r_val = (INT16)context->palette[idx];
222 g_val = (INT16)context->palette[idx + 1];
223 b_val = (INT16)context->palette[idx + 2];
231 r_val = g_val = b_val = a_val = 0;
235 *yplane++ = (BYTE)((r_val >> 2) + (g_val >> 1) + (b_val >> 2));
237 *coplane++ = (BYTE)((r_val - b_val) >> ccl);
238 *cgplane++ = (BYTE)((-(r_val >> 1) + g_val - (b_val >> 1)) >> ccl);
242 if (context->ChromaSubsamplingLevel && (x % 2) == 1)
244 *yplane = *(yplane - 1);
245 *coplane = *(coplane - 1);
246 *cgplane = *(cgplane - 1);
250 if (context->ChromaSubsamplingLevel && (y % 2) == 1)
252 yplane = context->priv->PlaneBuffers[0] + y * rw;
253 coplane = context->priv->PlaneBuffers[1] + y * rw;
254 cgplane = context->priv->PlaneBuffers[2] + y * rw;
255 CopyMemory(yplane, yplane - rw, rw);
256 CopyMemory(coplane, coplane - rw, rw);
257 CopyMemory(cgplane, cgplane - rw, rw);
263static BOOL nsc_encode_subsampling(NSC_CONTEXT* WINPR_RESTRICT context)
265 UINT32 tempWidth = 0;
266 UINT32 tempHeight = 0;
271 tempWidth = ROUND_UP_TO(context->width, 8);
272 tempHeight = ROUND_UP_TO(context->height, 2);
277 if (tempWidth > context->priv->PlaneBuffersLength / tempHeight)
280 for (
size_t y = 0; y < tempHeight >> 1; y++)
282 BYTE* co_dst = context->priv->PlaneBuffers[1] + y * (tempWidth >> 1);
283 BYTE* cg_dst = context->priv->PlaneBuffers[2] + y * (tempWidth >> 1);
284 const INT8* co_src0 = (INT8*)context->priv->PlaneBuffers[1] + (y << 1) * tempWidth;
285 const INT8* co_src1 = co_src0 + tempWidth;
286 const INT8* cg_src0 = (INT8*)context->priv->PlaneBuffers[2] + (y << 1) * tempWidth;
287 const INT8* cg_src1 = cg_src0 + tempWidth;
289 for (UINT32 x = 0; x < tempWidth >> 1; x++)
291 *co_dst++ = (BYTE)(((INT16)*co_src0 + (INT16) * (co_src0 + 1) + (INT16)*co_src1 +
292 (INT16) * (co_src1 + 1)) >>
294 *cg_dst++ = (BYTE)(((INT16)*cg_src0 + (INT16) * (cg_src0 + 1) + (INT16)*cg_src1 +
295 (INT16) * (cg_src1 + 1)) >>
307BOOL nsc_encode(NSC_CONTEXT* WINPR_RESTRICT context,
const BYTE* WINPR_RESTRICT bmpdata,
310 if (!context || !bmpdata || (rowstride == 0))
313 if (!nsc_encode_argb_to_aycocg(context, bmpdata, rowstride))
316 if (context->ChromaSubsamplingLevel)
318 if (!nsc_encode_subsampling(context))
325static UINT32 nsc_rle_encode(
const BYTE* WINPR_RESTRICT in, BYTE* WINPR_RESTRICT out,
329 UINT32 runlength = 1;
330 UINT32 planeSize = 0;
337 while (left > 4 && planeSize < originalSize - 4)
339 if (left > 5 && *in == *(in + 1))
343 else if (runlength == 1)
348 else if (runlength < 256)
352 WINPR_ASSERT(runlength >= 2);
353 *out++ = WINPR_ASSERTING_INT_CAST(BYTE, runlength - 2);
362 *out++ = (runlength & 0x000000FF);
363 *out++ = (runlength & 0x0000FF00) >> 8;
364 *out++ = (runlength & 0x00FF0000) >> 16;
365 *out++ = (runlength & 0xFF000000) >> 24;
374 if (planeSize < originalSize - 4)
375 CopyMemory(out, in, 4);
381static void nsc_rle_compress_data(NSC_CONTEXT* WINPR_RESTRICT context)
383 UINT32 planeSize = 0;
384 UINT32 originalSize = 0;
386 for (UINT16 i = 0; i < 4; i++)
388 originalSize = context->OrgByteCount[i];
390 if (originalSize == 0)
396 planeSize = nsc_rle_encode(context->priv->PlaneBuffers[i],
397 context->priv->PlaneBuffers[4], originalSize);
399 if (planeSize < originalSize)
400 CopyMemory(context->priv->PlaneBuffers[i], context->priv->PlaneBuffers[4],
403 planeSize = originalSize;
406 context->PlaneByteCount[i] = planeSize;
410BOOL nsc_write_message(WINPR_ATTR_UNUSED NSC_CONTEXT* WINPR_RESTRICT context,
411 wStream* WINPR_RESTRICT s,
const NSC_MESSAGE* WINPR_RESTRICT message)
413 UINT32 totalPlaneByteCount = 0;
414 totalPlaneByteCount = message->LumaPlaneByteCount + message->OrangeChromaPlaneByteCount +
415 message->GreenChromaPlaneByteCount + message->AlphaPlaneByteCount;
417 if (!Stream_EnsureRemainingCapacity(s, 20 + totalPlaneByteCount))
420 Stream_Write_UINT32(s, message->LumaPlaneByteCount);
422 s, message->OrangeChromaPlaneByteCount);
424 s, message->GreenChromaPlaneByteCount);
425 Stream_Write_UINT32(s, message->AlphaPlaneByteCount);
426 Stream_Write_UINT8(s, message->ColorLossLevel);
427 Stream_Write_UINT8(s, message->ChromaSubsamplingLevel);
428 Stream_Write_UINT16(s, 0);
430 if (message->LumaPlaneByteCount)
431 Stream_Write(s, message->PlaneBuffers[0], message->LumaPlaneByteCount);
433 if (message->OrangeChromaPlaneByteCount)
434 Stream_Write(s, message->PlaneBuffers[1],
435 message->OrangeChromaPlaneByteCount);
437 if (message->GreenChromaPlaneByteCount)
438 Stream_Write(s, message->PlaneBuffers[2],
439 message->GreenChromaPlaneByteCount);
441 if (message->AlphaPlaneByteCount)
442 Stream_Write(s, message->PlaneBuffers[3], message->AlphaPlaneByteCount);
447BOOL nsc_compose_message(NSC_CONTEXT* WINPR_RESTRICT context,
wStream* WINPR_RESTRICT s,
448 const BYTE* WINPR_RESTRICT data, UINT32 width, UINT32 height,
452 NSC_MESSAGE message = WINPR_C_ARRAY_INIT;
454 if (!context || !s || !data)
458 scanline = width * FreeRDPGetBytesPerPixel(context->format);
460 context->width = WINPR_ASSERTING_INT_CAST(UINT16, width);
461 context->height = WINPR_ASSERTING_INT_CAST(UINT16, height);
463 if (!nsc_context_initialize_encode(context))
467 PROFILER_ENTER(context->priv->prof_nsc_encode)
468 rc = context->encode(context, data, scanline);
469 PROFILER_EXIT(context->priv->prof_nsc_encode)
474 PROFILER_ENTER(context->priv->prof_nsc_rle_compress_data)
475 nsc_rle_compress_data(context);
476 PROFILER_EXIT(context->priv->prof_nsc_rle_compress_data)
477 message.PlaneBuffers[0] = context->priv->PlaneBuffers[0];
478 message.PlaneBuffers[1] = context->priv->PlaneBuffers[1];
479 message.PlaneBuffers[2] = context->priv->PlaneBuffers[2];
480 message.PlaneBuffers[3] = context->priv->PlaneBuffers[3];
481 message.LumaPlaneByteCount = context->PlaneByteCount[0];
482 message.OrangeChromaPlaneByteCount = context->PlaneByteCount[1];
483 message.GreenChromaPlaneByteCount = context->PlaneByteCount[2];
484 message.AlphaPlaneByteCount = context->PlaneByteCount[3];
486 message.ColorLossLevel = WINPR_ASSERTING_INT_CAST(BYTE, context->ColorLossLevel);
487 message.ChromaSubsamplingLevel =
488 WINPR_ASSERTING_INT_CAST(BYTE, context->ChromaSubsamplingLevel);
489 return nsc_write_message(context, s, &message);
492#if !defined(WITHOUT_FREERDP_3x_DEPRECATED)
493BOOL nsc_decompose_message(NSC_CONTEXT* WINPR_RESTRICT context,
wStream* WINPR_RESTRICT s,
494 BYTE* WINPR_RESTRICT bmpdata, UINT32 x, UINT32 y, UINT32 width,
495 UINT32 height, UINT32 rowstride, UINT32 format, UINT32 flip)
497 size_t size = Stream_GetRemainingLength(s);
499 if (size > UINT32_MAX)
502 if (!nsc_process_message(context, (UINT16)FreeRDPGetBitsPerPixel(context->format), width,
503 height, Stream_Pointer(s), (UINT32)size, bmpdata, format, rowstride, x,
504 y, width, height, flip))
506 Stream_Seek(s, size);