nsc: Fix memory leak
[platform/upstream/freerdp.git] / libfreerdp / codec / nsc.c
1 /**
2  * FreeRDP: A Remote Desktop Protocol Implementation
3  * NSCodec Codec
4  *
5  * Copyright 2011 Samsung, Author Jiten Pathy
6  * Copyright 2012 Vic Lee
7  * Copyright 2016 Armin Novak <armin.novak@thincast.com>
8  * Copyright 2016 Thincast Technologies GmbH
9  *
10  * Licensed under the Apache License, Version 2.0 (the "License");
11  * you may not use this file except in compliance with the License.
12  * You may obtain a copy of the License at
13  *
14  *       http://www.apache.org/licenses/LICENSE-2.0
15  *
16  * Unless required by applicable law or agreed to in writing, software
17  * distributed under the License is distributed on an "AS IS" BASIS,
18  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19  * See the License for the specific language governing permissions and
20  * limitations under the License.
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30
31 #include <winpr/crt.h>
32
33 #include <freerdp/codec/nsc.h>
34 #include <freerdp/codec/color.h>
35
36 #include "nsc_types.h"
37 #include "nsc_encode.h"
38
39 #include "nsc_sse2.h"
40
41 #ifndef NSC_INIT_SIMD
42 #define NSC_INIT_SIMD(_nsc_context) \
43         do                              \
44         {                               \
45         } while (0)
46 #endif
47
48 static BOOL nsc_decode(NSC_CONTEXT* context)
49 {
50         UINT16 x;
51         UINT16 y;
52         UINT16 rw;
53         BYTE shift;
54         BYTE* bmpdata;
55         size_t pos = 0;
56
57         if (!context)
58                 return FALSE;
59
60         rw = ROUND_UP_TO(context->width, 8);
61         shift = context->ColorLossLevel - 1; /* colorloss recovery + YCoCg shift */
62         bmpdata = context->BitmapData;
63
64         if (!bmpdata)
65                 return FALSE;
66
67         for (y = 0; y < context->height; y++)
68         {
69                 const BYTE* yplane;
70                 const BYTE* coplane;
71                 const BYTE* cgplane;
72                 const BYTE* aplane = context->priv->PlaneBuffers[3] + y * context->width; /* A */
73
74                 if (context->ChromaSubsamplingLevel)
75                 {
76                         yplane = context->priv->PlaneBuffers[0] + y * rw;                /* Y */
77                         coplane = context->priv->PlaneBuffers[1] + (y >> 1) * (rw >> 1); /* Co, supersampled */
78                         cgplane = context->priv->PlaneBuffers[2] + (y >> 1) * (rw >> 1); /* Cg, supersampled */
79                 }
80                 else
81                 {
82                         yplane = context->priv->PlaneBuffers[0] + y * context->width;  /* Y */
83                         coplane = context->priv->PlaneBuffers[1] + y * context->width; /* Co */
84                         cgplane = context->priv->PlaneBuffers[2] + y * context->width; /* Cg */
85                 }
86
87                 for (x = 0; x < context->width; x++)
88                 {
89                         INT16 y_val = (INT16)*yplane;
90                         INT16 co_val = (INT16)(INT8)(*coplane << shift);
91                         INT16 cg_val = (INT16)(INT8)(*cgplane << shift);
92                         INT16 r_val = y_val + co_val - cg_val;
93                         INT16 g_val = y_val + cg_val;
94                         INT16 b_val = y_val - co_val - cg_val;
95
96                         if (pos + 4 > context->BitmapDataLength)
97                                 return FALSE;
98
99                         pos += 4;
100                         *bmpdata++ = MINMAX(b_val, 0, 0xFF);
101                         *bmpdata++ = MINMAX(g_val, 0, 0xFF);
102                         *bmpdata++ = MINMAX(r_val, 0, 0xFF);
103                         *bmpdata++ = *aplane;
104                         yplane++;
105                         coplane += (context->ChromaSubsamplingLevel ? x % 2 : 1);
106                         cgplane += (context->ChromaSubsamplingLevel ? x % 2 : 1);
107                         aplane++;
108                 }
109         }
110
111         return TRUE;
112 }
113
114 static BOOL nsc_rle_decode(BYTE* in, BYTE* out, UINT32 outSize, UINT32 originalSize)
115 {
116         UINT32 left = originalSize;
117
118         while (left > 4)
119         {
120                 const BYTE value = *in++;
121                 UINT32 len = 0;
122
123                 if (left == 5)
124                 {
125                         if (outSize < 1)
126                                 return FALSE;
127
128                         outSize--;
129                         *out++ = value;
130                         left--;
131                 }
132                 else if (value == *in)
133                 {
134                         in++;
135
136                         if (*in < 0xFF)
137                         {
138                                 len = (UINT32)*in++;
139                                 len += 2;
140                         }
141                         else
142                         {
143                                 in++;
144                                 len = ((UINT32)(*in++));
145                                 len |= ((UINT32)(*in++)) << 8U;
146                                 len |= ((UINT32)(*in++)) << 16U;
147                                 len |= ((UINT32)(*in++)) << 24U;
148                         }
149
150                         if (outSize < len)
151                                 return FALSE;
152
153                         outSize -= len;
154                         FillMemory(out, len, value);
155                         out += len;
156                         left -= len;
157                 }
158                 else
159                 {
160                         if (outSize < 1)
161                                 return FALSE;
162
163                         outSize--;
164                         *out++ = value;
165                         left--;
166                 }
167         }
168
169         if ((outSize < 4) || (left < 4))
170                 return FALSE;
171
172         memcpy(out, in, 4);
173         return TRUE;
174 }
175
176 static BOOL nsc_rle_decompress_data(NSC_CONTEXT* context)
177 {
178         UINT16 i;
179         BYTE* rle;
180         UINT32 planeSize;
181         UINT32 originalSize;
182
183         if (!context)
184                 return FALSE;
185
186         rle = context->Planes;
187
188         for (i = 0; i < 4; i++)
189         {
190                 originalSize = context->OrgByteCount[i];
191                 planeSize = context->PlaneByteCount[i];
192
193                 if (planeSize == 0)
194                 {
195                         if (context->priv->PlaneBuffersLength < originalSize)
196                                 return FALSE;
197
198                         FillMemory(context->priv->PlaneBuffers[i], originalSize, 0xFF);
199                 }
200                 else if (planeSize < originalSize)
201                 {
202                         if (!nsc_rle_decode(rle, context->priv->PlaneBuffers[i],
203                                             context->priv->PlaneBuffersLength, originalSize))
204                                 return FALSE;
205                 }
206                 else
207                 {
208                         if (context->priv->PlaneBuffersLength < originalSize)
209                                 return FALSE;
210
211                         CopyMemory(context->priv->PlaneBuffers[i], rle, originalSize);
212                 }
213
214                 rle += planeSize;
215         }
216
217         return TRUE;
218 }
219
220 static BOOL nsc_stream_initialize(NSC_CONTEXT* context, wStream* s)
221 {
222         int i;
223
224         if (Stream_GetRemainingLength(s) < 20)
225                 return FALSE;
226
227         for (i = 0; i < 4; i++)
228                 Stream_Read_UINT32(s, context->PlaneByteCount[i]);
229
230         Stream_Read_UINT8(s, context->ColorLossLevel);         /* ColorLossLevel (1 byte) */
231         Stream_Read_UINT8(s, context->ChromaSubsamplingLevel); /* ChromaSubsamplingLevel (1 byte) */
232         Stream_Seek(s, 2);                                     /* Reserved (2 bytes) */
233         context->Planes = Stream_Pointer(s);
234         return TRUE;
235 }
236
237 static BOOL nsc_context_initialize(NSC_CONTEXT* context, wStream* s)
238 {
239         int i;
240         UINT32 length;
241         UINT32 tempWidth;
242         UINT32 tempHeight;
243
244         if (!nsc_stream_initialize(context, s))
245                 return FALSE;
246
247         length = context->width * context->height * 4;
248
249         if (!context->BitmapData)
250         {
251                 context->BitmapData = calloc(1, length + 16);
252
253                 if (!context->BitmapData)
254                         return FALSE;
255
256                 context->BitmapDataLength = length;
257         }
258         else if (length > context->BitmapDataLength)
259         {
260                 void* tmp;
261                 tmp = realloc(context->BitmapData, length + 16);
262
263                 if (!tmp)
264                         return FALSE;
265
266                 context->BitmapData = tmp;
267                 context->BitmapDataLength = length;
268         }
269
270         tempWidth = ROUND_UP_TO(context->width, 8);
271         tempHeight = ROUND_UP_TO(context->height, 2);
272         /* The maximum length a decoded plane can reach in all cases */
273         length = tempWidth * tempHeight;
274
275         if (length > context->priv->PlaneBuffersLength)
276         {
277                 for (i = 0; i < 4; i++)
278                 {
279                         void* tmp = (BYTE*)realloc(context->priv->PlaneBuffers[i], length);
280
281                         if (!tmp)
282                                 return FALSE;
283
284                         context->priv->PlaneBuffers[i] = tmp;
285                 }
286
287                 context->priv->PlaneBuffersLength = length;
288         }
289
290         for (i = 0; i < 4; i++)
291         {
292                 context->OrgByteCount[i] = context->width * context->height;
293         }
294
295         if (context->ChromaSubsamplingLevel)
296         {
297                 context->OrgByteCount[0] = tempWidth * context->height;
298                 context->OrgByteCount[1] = (tempWidth >> 1) * (tempHeight >> 1);
299                 context->OrgByteCount[2] = context->OrgByteCount[1];
300         }
301
302         return TRUE;
303 }
304
305 static void nsc_profiler_print(NSC_CONTEXT_PRIV* priv){
306         PROFILER_PRINT_HEADER PROFILER_PRINT(priv->prof_nsc_rle_decompress_data)
307             PROFILER_PRINT(priv->prof_nsc_decode) PROFILER_PRINT(priv->prof_nsc_rle_compress_data)
308                 PROFILER_PRINT(priv->prof_nsc_encode) PROFILER_PRINT_FOOTER
309 }
310
311 BOOL nsc_context_reset(NSC_CONTEXT* context, UINT32 width, UINT32 height)
312 {
313         if (!context)
314                 return FALSE;
315
316         if ((width > UINT16_MAX) || (height > UINT16_MAX))
317                 return FALSE;
318
319         context->width = (UINT16)width;
320         context->height = (UINT16)height;
321         return TRUE;
322 }
323
324 NSC_CONTEXT* nsc_context_new(void)
325 {
326         NSC_CONTEXT* context;
327         context = (NSC_CONTEXT*)calloc(1, sizeof(NSC_CONTEXT));
328
329         if (!context)
330                 return NULL;
331
332         context->priv = (NSC_CONTEXT_PRIV*)calloc(1, sizeof(NSC_CONTEXT_PRIV));
333
334         if (!context->priv)
335                 goto error;
336
337         context->priv->log = WLog_Get("com.freerdp.codec.nsc");
338         WLog_OpenAppender(context->priv->log);
339         context->BitmapData = NULL;
340         context->decode = nsc_decode;
341         context->encode = nsc_encode;
342
343         PROFILER_CREATE(context->priv->prof_nsc_rle_decompress_data, "nsc_rle_decompress_data")
344         PROFILER_CREATE(context->priv->prof_nsc_decode, "nsc_decode")
345         PROFILER_CREATE(context->priv->prof_nsc_rle_compress_data, "nsc_rle_compress_data")
346         PROFILER_CREATE(context->priv->prof_nsc_encode, "nsc_encode")
347         /* Default encoding parameters */
348         context->ColorLossLevel = 3;
349         context->ChromaSubsamplingLevel = 1;
350         /* init optimized methods */
351         NSC_INIT_SIMD(context);
352         return context;
353 error:
354         nsc_context_free(context);
355         return NULL;
356 }
357
358 void nsc_context_free(NSC_CONTEXT* context)
359 {
360         size_t i;
361
362         if (!context)
363                 return;
364
365         if (context->priv)
366         {
367                 for (i = 0; i < 5; i++)
368                         free(context->priv->PlaneBuffers[i]);
369
370                 nsc_profiler_print(context->priv);
371                 PROFILER_FREE(context->priv->prof_nsc_rle_decompress_data)
372                 PROFILER_FREE(context->priv->prof_nsc_decode)
373                 PROFILER_FREE(context->priv->prof_nsc_rle_compress_data)
374                 PROFILER_FREE(context->priv->prof_nsc_encode)
375                 free(context->priv);
376         }
377
378         free(context->BitmapData);
379         free(context);
380 }
381
382 BOOL nsc_context_set_pixel_format(NSC_CONTEXT* context, UINT32 pixel_format)
383 {
384         return nsc_context_set_parameters(context, NSC_COLOR_FORMAT, pixel_format);
385 }
386
387 BOOL nsc_context_set_parameters(NSC_CONTEXT* context, NSC_PARAMETER what, UINT32 value)
388 {
389         if (!context)
390                 return FALSE;
391
392         switch (what)
393         {
394                 case NSC_COLOR_LOSS_LEVEL:
395                         context->ColorLossLevel = value;
396                         break;
397                 case NSC_ALLOW_SUBSAMPLING:
398                         context->ChromaSubsamplingLevel = value;
399                         break;
400                 case NSC_DYNAMIC_COLOR_FIDELITY:
401                         context->DynamicColorFidelity = value != 0;
402                         break;
403                 case NSC_COLOR_FORMAT:
404                         context->format = value;
405                         break;
406                 default:
407                         return FALSE;
408         }
409         return TRUE;
410 }
411
412 BOOL nsc_process_message(NSC_CONTEXT* context, UINT16 bpp, UINT32 width, UINT32 height,
413                          const BYTE* data, UINT32 length, BYTE* pDstData, UINT32 DstFormat,
414                          UINT32 nDstStride, UINT32 nXDst, UINT32 nYDst, UINT32 nWidth,
415                          UINT32 nHeight, UINT32 flip)
416 {
417         wStream* s;
418         BOOL ret;
419         if (!context || !data || !pDstData)
420                 return FALSE;
421
422         s = Stream_New((BYTE*)data, length);
423
424         if (!s)
425                 return FALSE;
426
427         if (nDstStride == 0)
428                 nDstStride = nWidth * GetBytesPerPixel(DstFormat);
429
430         switch (bpp)
431         {
432                 case 32:
433                         context->format = PIXEL_FORMAT_BGRA32;
434                         break;
435
436                 case 24:
437                         context->format = PIXEL_FORMAT_BGR24;
438                         break;
439
440                 case 16:
441                         context->format = PIXEL_FORMAT_BGR16;
442                         break;
443
444                 case 8:
445                         context->format = PIXEL_FORMAT_RGB8;
446                         break;
447
448                 case 4:
449                         context->format = PIXEL_FORMAT_A4;
450                         break;
451
452                 default:
453                         Stream_Free(s, TRUE);
454                         return FALSE;
455         }
456
457         context->width = width;
458         context->height = height;
459         ret = nsc_context_initialize(context, s);
460         Stream_Free(s, FALSE);
461
462         if (!ret)
463                 return FALSE;
464
465         /* RLE decode */
466         {
467                 BOOL rc;
468                 PROFILER_ENTER(context->priv->prof_nsc_rle_decompress_data)
469                 rc = nsc_rle_decompress_data(context);
470                 PROFILER_EXIT(context->priv->prof_nsc_rle_decompress_data)
471
472                 if (!rc)
473                         return FALSE;
474         }
475         /* Colorloss recover, Chroma supersample and AYCoCg to ARGB Conversion in one step */
476         {
477                 BOOL rc;
478                 PROFILER_ENTER(context->priv->prof_nsc_decode)
479                 rc = context->decode(context);
480                 PROFILER_EXIT(context->priv->prof_nsc_decode)
481
482                 if (!rc)
483                         return FALSE;
484         }
485
486         if (!freerdp_image_copy(pDstData, DstFormat, nDstStride, nXDst, nYDst, width, height,
487                                 context->BitmapData, PIXEL_FORMAT_BGRA32, 0, 0, 0, NULL, flip))
488                 return FALSE;
489
490         return TRUE;
491 }