From 7529ed684b268b0b03de0670608d4dc9e74a3560 Mon Sep 17 00:00:00 2001 From: qubit Date: Mon, 3 Oct 2011 00:56:33 +0530 Subject: [PATCH] finished codec and push with bugs --- include/freerdp/nsc/nsc.h | 73 +++++++ libfreerdp-nsc/CMakeLists.txt | 29 +++ libfreerdp-nsc/libnsc.c | 347 ++++++++++++++++++++++++++++++++++ 3 files changed, 449 insertions(+) create mode 100644 include/freerdp/nsc/nsc.h create mode 100644 libfreerdp-nsc/CMakeLists.txt create mode 100644 libfreerdp-nsc/libnsc.c diff --git a/include/freerdp/nsc/nsc.h b/include/freerdp/nsc/nsc.h new file mode 100644 index 000000000..e802296e6 --- /dev/null +++ b/include/freerdp/nsc/nsc.h @@ -0,0 +1,73 @@ +/** + * FreeRDP: A Remote Desktop Protocol client. + * NSCODEC Codec Library - API Header + * + * Copyright 2011 Samsung + * Author Jiten Pathy + * + * 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 __NSC_H +#define __NSC_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define BYTESUM(_bs) (_bs[0] + _bs[1] + _bs[2] + _bs[3]) +#define ROUND_UP_TO(_b, _n) (_b + ((~(_b & (_n-1)) + 0x1) & (_n-1))); + +/* NSCODEC_BITMAP_STREAM */ +struct _NSC_STREAM +{ + uint32 PlaneByteCount[4]; + uint8 colorLossLevel; + uint8 ChromaSubSamplingLevel; + uint16 Reserved; + STREAM* pdata; +}; +typedef struct _NSC_STREAM NSC_STREAM; + +struct _NSC_CONTEXT +{ + uint32 OrgByteCount[4]; /* original byte length of luma, chroma orange, chroma green, alpha variable in order */ + NSC_STREAM* nsc_stream; + uint16 width; + uint16 height; + uint8* bmpdata; /* final argb values in little endian order */ + STREAM* org_buf[4]; /* Decompressed Plane Buffers in the respective order */ +}; +typedef struct _NSC_CONTEXT NSC_CONTEXT; + +FREERDP_API NSC_CONTEXT* nsc_context_new(void); +FREERDP_API void nsc_process_message(NSC_CONTEXT* context, uint8* data, uint32 length); +FREERDP_API void nsc_context_initialize(NSC_CONTEXT* context, STREAM* s); +FREERDP_API void nsc_stream_initialize(NSC_CONTEXT* context, STREAM* s); +FREERDP_API void nsc_rle_decompress_data(NSC_CONTEXT* context); +FREERDP_API void nsc_ycocg_rgb_convert(NSC_CONTEXT* context); +FREERDP_API void nsc_rle_decode(STREAM* in, STREAM* out, uint32 origsz); +FREERDP_API void nsc_chroma_supersample(NSC_CONTEXT* context); +FREERDP_API void nsc_cl_expand(STREAM* stream, uint8 shiftcount, uint32 origsz); +FREERDP_API void nsc_colorloss_recover(NSC_CONTEXT* context); +FREERDP_API void nsc_ycocg_rgb(NSC_CONTEXT* context); +FREERDP_API void nsc_context_destroy(NSC_CONTEXT* context); +#ifdef __cplusplus +} +#endif + +#endif /* __NSC_H */ diff --git a/libfreerdp-nsc/CMakeLists.txt b/libfreerdp-nsc/CMakeLists.txt new file mode 100644 index 000000000..2b62105c1 --- /dev/null +++ b/libfreerdp-nsc/CMakeLists.txt @@ -0,0 +1,29 @@ +# FreeRDP: A Remote Desktop Protocol Client +# libfreerdp-nsc cmake build script +# +# CopyRight SamSung +# Author Jiten Pathy +# +# 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. + +set(LIBFREERDP_NSC_SRCS + libnsc.c +) + +add_library(freerdp-nsc ${LIBFREERDP_NSC_SRCS}) + +set_target_properties(freerdp-nsc PROPERTIES VERSION ${FREERDP_VERSION_FULL} SOVERSION ${FREERDP_VERSION} PREFIX "lib") + +target_link_libraries(freerdp-nsc freerdp-utils) + +install(TARGETS freerdp-nsc DESTINATION ${CMAKE_INSTALL_LIBDIR}) diff --git a/libfreerdp-nsc/libnsc.c b/libfreerdp-nsc/libnsc.c new file mode 100644 index 000000000..e296cec78 --- /dev/null +++ b/libfreerdp-nsc/libnsc.c @@ -0,0 +1,347 @@ +/** +* FreeRDP: A Remote Desktop Protocol client. +* NSCODEC Codec Library +* +* Copyright 2011 Samsung +* Author Jiten Pathy +* 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 +#include +#include +#include +#include +#include + +/* we store the 9 th bits at the end of stream as bitstream */ +void nsc_cl_expand(STREAM* stream, uint8 shiftcount, uint32 origsz) +{ + uint8* sbitstream; + uint8* temptr; + uint8 sign,bitoff; + uint32 bitno; + sbitstream = stream->data + origsz; + do{ + sign = (*(stream->p) << (shiftcount - 1)) & 0x80; + bitno = stream->p - stream->data; + *(stream->p++) <<= shiftcount; + temptr = sbitstream + ((bitno) >> 3); + bitoff = bitno % 0x8; + (*temptr) |= (sign >> bitoff); + }while(stream->p - stream->data < origsz); + stream->p = stream->data; +} + +void nsc_chroma_supersample(NSC_CONTEXT* context) +{ + int i; + uint8* cur; + uint8* tptr; + uint8* nbitstream; + uint8* sbitstream; + uint8 val, bitoff, sign; + uint16 w, h, pw, row; + uint32 alloclen, orglen, bytno; + STREAM* new_s; + STREAM* temp; + w = context->width; + h = context->height; + alloclen = orglen = w * h; + pw = ROUND_UP_TO(context->width, 8); + temp = stream_new(0); + for (i=0; i<3; i++) + { + if(i != 0) + alloclen = orglen + ((orglen & 0x7) ? (orglen >> 3) + 0x1 : (orglen >> 3)); + new_s = stream_new(alloclen); + stream_attach(temp, context->org_buf[i]->data, context->org_buf[i]->size); + sbitstream = temp->data + context->OrgByteCount[i]; + nbitstream = new_s->data + orglen; + cur = new_s->p; + if(i == 1) + pw >>= 1; + while((temp->p-temp->data) < context->OrgByteCount[i]) + { + bytno = temp->p - temp->data; + bitoff = bytno % 0x8; + stream_read_uint8(temp, val); + *cur = val; + row = (temp->p - temp->data) % pw; + if(i == 0) + { + cur++; + if(row >= w) + stream_seek(temp, pw-row); + } + else + { + tptr = sbitstream + ((bytno) >> 3); + sign = ((*tptr) << bitoff) & 0x80; + bytno = cur - new_s->data; + bitoff = bytno % 8; + *(nbitstream + (bytno >> 3)) |= (sign >> bitoff); + if((bytno+w) < orglen) + { + *(cur + w) = val; + bitoff = (bytno + w) % 8; + *(nbitstream + ((bytno + w) >> 3)) |= (sign >> bitoff); + } + if((bytno+1) % w) + { + *(cur+1) = val; + bitoff = (bytno + 1) % 8; + *(nbitstream + ((bytno + 1) >> 3)) |= (sign >> bitoff); + if((bytno+w) < orglen) + { + *(cur+w+1) = val; + bitoff = (bytno + w + 1) % 8; + *(nbitstream + ((bytno + w + 1) >> 3)) |= (sign >> bitoff); + } + } + cur += 2; + bytno = cur - new_s->data; + if(((bytno/w) < h) && ((bytno) % w) < 2 ) + { + if(w % 2) + cur += w-1; + else + cur += w; + } + if((row*2) >= w) + stream_seek(temp, pw-row); + } + } + xfree(temp->data); + stream_detach(temp); + stream_attach(context->org_buf[i], new_s->data, new_s->size); + context->OrgByteCount[i] = orglen; + } +} + +void nsc_ycocg_rgb(NSC_CONTEXT* context) +{ + uint8* sbitstream[2]; + uint8 bitoff, sign[2], ycocg[3], rgb[3], i; + uint32 bytno, size; + size = context->OrgByteCount[0]; + for(i = 1;i < 3;i++) + sbitstream[i-1] = context->org_buf[i]->data + context->OrgByteCount[i]; + do{ + for(i = 0;i < 3;i++) + ycocg[i] = *(context->org_buf[i]->p); + for(i = 1;i < 3;i++) + { + bytno = context->OrgByteCount[i] - size; + bitoff = bytno % 8; + sign[i-1] = (*(sbitstream[i-1] + (bytno >> 3)) >> (7 - bitoff)) & 0x1; + if(sign[i-1]) + ycocg[i] = ~(ycocg[i]) + 0x1; + } + if(sign[0] && sign[1]) + { + rgb[0] = ycocg[0] - (ycocg[1] >> 1) + (ycocg[2] >> 1); + rgb[1] = ycocg[0] - (ycocg[2] >> 1); + rgb[2] = ycocg[0] + (ycocg[1] >> 1) + (ycocg[2] >> 1); + } + else if(sign[0]) + { + rgb[0] = ycocg[0] - (ycocg[1] >> 1) - (ycocg[2] >> 1); + rgb[1] = ycocg[0] + (ycocg[2] >> 1); + rgb[2] = ycocg[0] + (ycocg[1] >> 1) - (ycocg[2] >> 1); + } + else if(sign[1]) + { + rgb[0] = ycocg[0] + (ycocg[1] >> 1) + (ycocg[2] >> 1); + rgb[1] = ycocg[0] - (ycocg[2] >> 1); + rgb[2] = ycocg[0] - (ycocg[1] >> 1) + (ycocg[2] >> 1); + } + else + { + rgb[0] = ycocg[0] + (ycocg[1] >> 1) - (ycocg[2] >> 1); + rgb[1] = ycocg[0] + (ycocg[2] >> 1); + rgb[2] = ycocg[0] - (ycocg[1] >> 1) - (ycocg[2] >> 1); + } + for(i = 0;i < 3;i++) + stream_write_uint8(context->org_buf[i], rgb[i]); + size--; + }while(size); + for(i = 0;i < 3;i++) + context->org_buf[i]->p = context->org_buf[i]->data; +} + +void nsc_colorloss_recover(NSC_CONTEXT* context) +{ + int i; + uint8 cllvl; + cllvl = context->nsc_stream->colorLossLevel; + for(i = 1;i < 3;i++) + { + nsc_cl_expand(context->org_buf[i], cllvl, context->OrgByteCount[i]); + } +} + +void nsc_rle_decode(STREAM* in, STREAM* out, uint32 origsz) +{ + uint32 i; + uint8 value; + i = origsz; + while( i > 4 ) + { + stream_read_uint8(in, value); + if( i == 5 ) + { + stream_write_uint8(out,value); + i-=1; + } + else if( value == *(in->p) ) + { + stream_seek(in, 1); + if( *(in->p) < 0xff ) + { + uint8 len; + stream_read_uint8(in, len); + stream_set_byte(out, value, len+2); + i -= (len+2); + } + else + { + uint32 len; + stream_seek(in, 1); + stream_read_uint32(in, len); + stream_set_byte(out, value, len); + i -= len; + } + } + else + { + stream_write_uint8(out, value); + i -= 1; + } + } + stream_copy(out, in, 4); +} + +void nsc_rle_decompress_data(NSC_CONTEXT* context) +{ + STREAM* rles; + uint16 i,origsize; + rles = stream_new(0); + rles->p = rles->data = context->nsc_stream->pdata->p; + rles->size = context->nsc_stream->pdata->size; + for (i=0; i<4 ;i++) + { + origsize = context->OrgByteCount[i]; + if( i==3 && context->nsc_stream->PlaneByteCount[i] == 0 ) + stream_set_byte(context->org_buf[i], 0xff, origsize); + else if(context->nsc_stream->PlaneByteCount[i] < origsize) + nsc_rle_decode(rles, context->org_buf[i], origsize); + else + stream_copy(context->org_buf[i], rles, origsize); + context->org_buf[i]->p = context->org_buf[i]->data; + } +} + +void nsc_combine_argb(NSC_CONTEXT* context) +{ + int i; + uint8* bmp; + bmp = context->bmpdata; + for(i = 0;i < (context->width * context->height);i++) + { + stream_read_uint8(context->org_buf[2], *bmp++); + stream_read_uint8(context->org_buf[1], *bmp++); + stream_read_uint8(context->org_buf[0], *bmp++); + stream_read_uint8(context->org_buf[3], *bmp++); + } +} + +void nsc_stream_initialize(NSC_CONTEXT* context, STREAM* s) +{ + int i; + for (i=0; i<4; i++) + stream_read_uint32(s, context->nsc_stream->PlaneByteCount[i]); + stream_read_uint8(s, context->nsc_stream->colorLossLevel); + stream_read_uint8(s, context->nsc_stream->ChromaSubSamplingLevel); + stream_seek(s, 2); + context->nsc_stream->pdata = stream_new(0); + stream_attach(context->nsc_stream->pdata, s->p, BYTESUM(context->nsc_stream->PlaneByteCount)); +} + +void nsc_context_initialize(NSC_CONTEXT* context, STREAM* s) +{ + uint32 tempsz; + int i; + nsc_stream_initialize(context, s); + context->bmpdata = xzalloc(context->width * context->height * 4); + for (i=0; i<4; i++) + context->OrgByteCount[i]=context->width * context->height; + if(context->nsc_stream->ChromaSubSamplingLevel > 0) /* [MS-RDPNSC] 2.2 */ + { + uint32 tempWidth,tempHeight; + tempWidth = ROUND_UP_TO(context->width, 8); + context->OrgByteCount[0] = tempWidth * context->height; + tempWidth = tempWidth >> 1 ; + tempHeight = ROUND_UP_TO(context->height, 2); + tempHeight = tempHeight >> 1; + context->OrgByteCount[1] = tempWidth * tempHeight; + context->OrgByteCount[2] = tempWidth * tempHeight; + } + for (i=0 ; i<4; i++) + { + tempsz = context->OrgByteCount[i]; + if (i == 1 || i == 2) + tempsz += (tempsz & 0x7) ? (tempsz >> 3) + 0x1 : (tempsz >> 3); /* extra bytes/8 bytes for bitstream to store the 9th bit after colorloss recover */ + context->org_buf[i] = stream_new(tempsz); + } +} + +void nsc_context_destroy(NSC_CONTEXT* context) +{ + int i; + for(i = 0;i < 4;i++) + stream_free(context->org_buf[i]); + stream_detach(context->nsc_stream->pdata); + xfree(context->bmpdata); +} + +NSC_CONTEXT* nsc_context_new(void) +{ + NSC_CONTEXT* nsc_context; + nsc_context = xnew(NSC_CONTEXT); + nsc_context->nsc_stream = xnew(NSC_STREAM); + return nsc_context; +} + +void nsc_process_message(NSC_CONTEXT* context, uint8* data, uint32 length) +{ + STREAM* s; + s = stream_new(0); + stream_attach(s, data, length); + nsc_context_initialize(context, s); + + /* RLE decode */ + nsc_rle_decompress_data(context); + + /* colorloss recover */ + nsc_colorloss_recover(context); + + /* Chroma supersample */ + if(context->nsc_stream->ChromaSubSamplingLevel > 0) + nsc_chroma_supersample(context); + + /* YCoCg to RGB Convert */ + nsc_ycocg_rgb(context); + + /* Combine ARGB planes */ + nsc_combine_argb(context); +}