Initial commit - from Precise source
[freerdp-ubuntu-pcb-backport.git] / libfreerdp-codec / nsc.c
1 /**
2  * FreeRDP: A Remote Desktop Protocol client.
3  * NSCodec Codec
4  *
5  * Copyright 2011 Samsung, Author Jiten Pathy
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *       http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <stdint.h>
24 #include <freerdp/codec/nsc.h>
25 #include <freerdp/utils/memory.h>
26
27 /* we store the 9th bits at the end of stream as bitstream */
28 void nsc_cl_expand(STREAM* stream, uint8 shiftcount, uint32 origsz)
29 {
30         uint8* sbitstream;
31         uint8* temptr;
32         uint8 sign,bitoff;
33         uint32 bitno;
34         sbitstream = stream->data + origsz;
35
36         do
37         {
38                 sign = (*(stream->p) << (shiftcount - 1)) & 0x80;
39                 bitno = stream->p - stream->data;
40                 *(stream->p++) <<= shiftcount;
41                 temptr = sbitstream + ((bitno) >> 3);
42                 bitoff = bitno % 0x8; 
43                 (*temptr) |= (sign >> bitoff);
44         }
45         while (((uint32)(stream->p - stream->data)) < origsz);
46
47         stream->p = stream->data;
48 }
49
50 void nsc_chroma_supersample(NSC_CONTEXT* context)
51 {
52         int i;
53         uint8* cur;
54         uint8* tptr;
55         uint8* nbitstream;
56         uint8* sbitstream;
57         uint8 val, bitoff, sign;
58         uint16 w, h, pw, row;
59         uint32 alloclen, orglen, bytno;
60         STREAM* new_s;
61         STREAM* temp;
62
63         w = context->width;
64         h = context->height;
65         alloclen = orglen = w * h;
66         pw = ROUND_UP_TO(context->width, 8);
67         temp = stream_new(0);
68
69         for (i = 0; i < 3; i++)
70         {
71                 if (i != 0)
72                         alloclen = orglen + ((orglen & 0x7) ? (orglen >> 3) + 0x1 : (orglen >> 3));
73
74                 new_s = stream_new(alloclen);
75                 stream_attach(temp, context->org_buf[i]->data, context->org_buf[i]->size);
76
77                 sbitstream = temp->data + context->OrgByteCount[i];
78                 nbitstream = new_s->data + orglen;
79                 cur  = new_s->p;
80
81                 if (i == 1)
82                         pw >>= 1;
83
84                 while (((uint32)(temp->p - temp->data)) < context->OrgByteCount[i])
85                 {
86                         bytno = temp->p - temp->data;
87                         bitoff = bytno % 0x8; 
88                         stream_read_uint8(temp, val);
89                         *cur = val;
90                         row = (temp->p - temp->data) % pw;
91
92                         if (i == 0)
93                         {
94                                 cur++;
95                                 if (row >= w)
96                                         stream_seek(temp, pw-row);
97                         }
98                         else
99                         {
100                                 tptr = sbitstream + ((bytno) >> 3);
101                                 sign = ((*tptr) << bitoff) & 0x80;
102                                 bytno = cur - new_s->data;
103                                 bitoff = bytno % 8;
104                                 *(nbitstream + (bytno >> 3)) |= (sign >> bitoff);
105
106                                 if ((bytno+w) < orglen)
107                                 {
108                                         *(cur + w) = val;
109                                         bitoff = (bytno + w) % 8;
110                                         *(nbitstream + ((bytno + w) >> 3)) |= (sign >> bitoff);
111                                 }
112
113                                 if ((bytno+1) % w)
114                                 {
115                                         *(cur+1) = val;
116                                         bitoff = (bytno + 1) % 8;
117                                         *(nbitstream + ((bytno + 1) >> 3)) |= (sign >> bitoff);
118                                         if ((bytno+w) < orglen)
119                                         {
120                                                 *(cur+w+1) = val;
121                                                 bitoff = (bytno + w + 1) % 8;
122                                                 *(nbitstream + ((bytno + w + 1) >> 3)) |= (sign >> bitoff);
123                                         }
124                                 }
125
126                                 cur += 2;
127                                 bytno = cur - new_s->data;
128
129                                 if (((bytno/w) < h) && ((bytno) % w) < 2 )
130                                 {
131                                         if (w % 2)
132                                                 cur += w-1;
133                                         else
134                                                 cur += w;
135                                 }
136
137                                 if ((row*2) >= w)
138                                         stream_seek(temp, pw-row);
139                         }
140                 }
141
142                 xfree(temp->data);
143                 stream_detach(temp);
144                 stream_attach(context->org_buf[i], new_s->data, new_s->size);
145                 context->OrgByteCount[i] = orglen;
146         }
147 }
148
149 void nsc_ycocg_rgb(NSC_CONTEXT* context)
150 {
151         uint8* sbitstream[2];
152         uint8 bitoff, sign[2], i, val, tmp;
153         sint16 rgb[3], ycocg[3];
154         uint32 bytno, size;
155         size = context->OrgByteCount[0];
156
157         for (i = 1; i < 3; i++)
158                 sbitstream[i-1] = context->org_buf[i]->data + context->OrgByteCount[i];
159
160         do
161         {
162                 for (i = 0; i < 3; i++)
163                         ycocg[i] = *(context->org_buf[i]->p);
164
165                 for (i = 1; i < 3; i++)
166                 {
167                         bytno = context->OrgByteCount[i] - size;
168                         bitoff = bytno % 8;
169                         sign[i-1] = (*(sbitstream[i-1] + (bytno >> 3)) >> (7 - bitoff)) & 0x1;
170                         ycocg[i] = (((sint16)(0 - sign[i-1])) << 8) | ycocg[i];
171                 }
172
173                 rgb[0] = ycocg[0] + (ycocg[1] >> 1) - (ycocg[2] >> 1);
174                 rgb[1] = ycocg[0] + (ycocg[2] >> 1);
175                 rgb[2] = ycocg[0] - (ycocg[1] >> 1) - (ycocg[2] >> 1);
176
177                 for (i = 0; i < 3; i++)
178                 {
179                         tmp = (rgb[i] >> 8) & 0xff;
180                         if (tmp == 0xff)
181                                 val = 0x00;
182                         else if (tmp == 0x1)
183                                 val = 0xff;
184                         else
185                                 val = (uint8) rgb[i];
186
187                         stream_write_uint8(context->org_buf[i], val);
188                 }
189
190                 size--;
191         }
192         while (size);
193
194         for (i = 0; i < 3; i++)
195                 context->org_buf[i]->p = context->org_buf[i]->data;
196 }
197
198 void nsc_colorloss_recover(NSC_CONTEXT* context)
199 {
200         int i;
201         uint8 cllvl;
202         cllvl = context->nsc_stream->colorLossLevel;
203
204         for (i = 1; i < 3; i++)
205                 nsc_cl_expand(context->org_buf[i], cllvl, context->OrgByteCount[i]);
206 }
207
208 void nsc_rle_decode(STREAM* in, STREAM* out, uint32 origsz)
209 {
210         uint32 i;
211         uint8 value;
212         i = origsz;
213
214         while (i > 4)
215         {
216                 stream_read_uint8(in, value);
217
218                 if (i == 5)
219                 {
220                         stream_write_uint8(out,value);
221                         i-=1;
222                 }
223                 else if (value == *(in->p))
224                 {
225                         stream_seek(in, 1);
226
227                         if (*(in->p) < 0xFF)
228                         {
229                                 uint8 len;
230                                 stream_read_uint8(in, len);
231                                 stream_set_byte(out, value, len+2);
232                                 i -= (len+2);
233                         }
234                         else
235                         {
236                                 uint32 len;
237                                 stream_seek(in, 1);
238                                 stream_read_uint32(in, len);
239                                 stream_set_byte(out, value, len);
240                                 i -= len;
241                         }
242                 }
243                 else
244                 {
245                         stream_write_uint8(out, value);
246                         i -= 1;
247                 }
248         }
249
250         stream_copy(out, in, 4);
251 }
252
253 void nsc_rle_decompress_data(NSC_CONTEXT* context)
254 {
255         STREAM* rles;
256         uint16 i;
257         uint32 origsize;
258         rles = stream_new(0);
259         rles->p = rles->data = context->nsc_stream->pdata->p;
260         rles->size = context->nsc_stream->pdata->size;
261
262         for (i = 0; i < 4; i++)
263         {
264                 origsize = context->OrgByteCount[i];
265
266                 if (i == 3 && context->nsc_stream->PlaneByteCount[i] == 0)
267                         stream_set_byte(context->org_buf[i], 0xff, origsize);
268                 else if (context->nsc_stream->PlaneByteCount[i] < origsize)
269                         nsc_rle_decode(rles, context->org_buf[i], origsize);
270                 else
271                         stream_copy(context->org_buf[i], rles, origsize);
272
273                 context->org_buf[i]->p = context->org_buf[i]->data;
274         }
275 }
276
277 void nsc_combine_argb(NSC_CONTEXT* context)
278 {
279         int i;
280         uint8* bmp;
281         bmp = context->bmpdata;
282
283         for (i = 0; i < (context->width * context->height); i++)
284         {
285                 stream_read_uint8(context->org_buf[2], *bmp++);
286                 stream_read_uint8(context->org_buf[1], *bmp++);
287                 stream_read_uint8(context->org_buf[0], *bmp++);
288                 stream_read_uint8(context->org_buf[3], *bmp++);
289         }
290 }
291
292 void nsc_stream_initialize(NSC_CONTEXT* context, STREAM* s)
293 {
294         int i;
295
296         for (i = 0; i < 4; i++)
297                 stream_read_uint32(s, context->nsc_stream->PlaneByteCount[i]);
298
299         stream_read_uint8(s, context->nsc_stream->colorLossLevel);
300         stream_read_uint8(s, context->nsc_stream->ChromaSubSamplingLevel);
301         stream_seek(s, 2);
302
303         context->nsc_stream->pdata = stream_new(0);
304         stream_attach(context->nsc_stream->pdata, s->p, BYTESUM(context->nsc_stream->PlaneByteCount));
305 }
306
307 void nsc_context_initialize(NSC_CONTEXT* context, STREAM* s)
308 {
309         int i;
310         uint32 tempsz;
311         nsc_stream_initialize(context, s);
312         context->bmpdata = xzalloc(context->width * context->height * 4);
313
314         for (i = 0; i < 4; i++)
315                 context->OrgByteCount[i]=context->width * context->height;
316
317         if (context->nsc_stream->ChromaSubSamplingLevel > 0)    /* [MS-RDPNSC] 2.2 */
318         {
319                 uint32 tempWidth,tempHeight;
320                 tempWidth = ROUND_UP_TO(context->width, 8);
321                 context->OrgByteCount[0] = tempWidth * context->height;
322                 tempWidth = tempWidth >> 1 ;
323                 tempHeight = ROUND_UP_TO(context->height, 2);
324                 tempHeight = tempHeight >> 1;
325                 context->OrgByteCount[1] = tempWidth * tempHeight;
326                 context->OrgByteCount[2] = tempWidth * tempHeight;
327         }
328         for (i = 0; i < 4; i++)
329         {
330                 tempsz = context->OrgByteCount[i];
331
332                 if (i == 1 || i == 2)
333                         tempsz += (tempsz & 0x7) ? (tempsz >> 3) + 0x1 : (tempsz >> 3); /* extra bytes/8 bytes for bitstream to store the 9th bit after colorloss recover */
334
335                 context->org_buf[i] = stream_new(tempsz);
336         }
337 }
338
339 void nsc_context_destroy(NSC_CONTEXT* context)
340 {
341         int i;
342
343         for (i = 0;i < 4; i++)
344                 stream_free(context->org_buf[i]);
345
346         stream_detach(context->nsc_stream->pdata);
347         xfree(context->bmpdata);
348 }
349
350 NSC_CONTEXT* nsc_context_new(void)
351 {
352         NSC_CONTEXT* nsc_context;
353         nsc_context = xnew(NSC_CONTEXT);
354         nsc_context->nsc_stream = xnew(NSC_STREAM);
355         return nsc_context;
356 }
357
358 void nsc_process_message(NSC_CONTEXT* context, uint8* data, uint32 length)
359 {
360         STREAM* s;
361         s = stream_new(0);
362         stream_attach(s, data, length);
363         nsc_context_initialize(context, s);
364
365         /* RLE decode */
366         nsc_rle_decompress_data(context);
367
368         /* colorloss recover */
369         nsc_colorloss_recover(context);
370
371         /* Chroma supersample */
372         if (context->nsc_stream->ChromaSubSamplingLevel > 0)
373                 nsc_chroma_supersample(context);
374         
375         /* YCoCg to RGB Convert */
376         nsc_ycocg_rgb(context);
377
378         /* Combine ARGB planes */
379         nsc_combine_argb(context);
380 }