libfreerdp-codec: initial working fragmented NSCodec encoder
authorMarc-André Moreau <marcandre.moreau@gmail.com>
Thu, 15 Aug 2013 17:13:02 +0000 (13:13 -0400)
committerMarc-André Moreau <marcandre.moreau@gmail.com>
Thu, 15 Aug 2013 17:13:02 +0000 (13:13 -0400)
include/freerdp/codec/nsc.h
libfreerdp/codec/nsc_encode.c
winpr/libwinpr/crt/alignment.c
winpr/libwinpr/utils/collections/BufferPool.c

index 78952d4..9601fb8 100644 (file)
@@ -51,8 +51,9 @@ struct _NSC_MESSAGE
        BYTE* data;
        int scanline;
        UINT32 MaxPlaneSize;
+       BYTE* PlaneBuffers[5];
        UINT32 OrgByteCount[4];
-       BYTE* PlaneBuffers[4];
+       UINT32 PlaneByteCount[4];
 };
 typedef struct _NSC_MESSAGE NSC_MESSAGE;
 
@@ -88,6 +89,11 @@ FREERDP_API void nsc_compose_message(NSC_CONTEXT* context, wStream* s,
        BYTE* bmpdata, int width, int height, int rowstride);
 FREERDP_API void nsc_context_free(NSC_CONTEXT* context);
 
+FREERDP_API NSC_MESSAGE* nsc_encode_messages(NSC_CONTEXT* context, BYTE* data, int x, int y,
+               int width, int height, int scanline, int* numMessages, int maxDataSize);
+FREERDP_API int nsc_write_message(NSC_CONTEXT* context, wStream* s, NSC_MESSAGE* message);
+FREERDP_API int nsc_message_free(NSC_CONTEXT* context, NSC_MESSAGE* message);
+
 #ifdef __cplusplus
 }
 #endif
index f495664..627d032 100644 (file)
@@ -24,6 +24,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+
 #ifdef HAVE_STDINT_H
 #include <stdint.h>
 #endif
@@ -72,7 +73,7 @@ static void nsc_context_initialize_encode(NSC_CONTEXT* context)
        }
 }
 
-static void nsc_encode_argb_to_aycocg(NSC_CONTEXT* context, BYTE* bmpdata, int rowstride)
+static void nsc_encode_argb_to_aycocg(NSC_CONTEXT* context, BYTE* data, int scanline)
 {
        UINT16 x;
        UINT16 y;
@@ -101,7 +102,7 @@ static void nsc_encode_argb_to_aycocg(NSC_CONTEXT* context, BYTE* bmpdata, int r
 
        for (y = 0; y < context->height; y++)
        {
-               src = bmpdata + (context->height - 1 - y) * rowstride;
+               src = data + (context->height - 1 - y) * scanline;
                yplane = context->priv->PlaneBuffers[0] + y * rw;
                coplane = context->priv->PlaneBuffers[1] + y * rw;
                cgplane = context->priv->PlaneBuffers[2] + y * rw;
@@ -322,12 +323,9 @@ static UINT32 nsc_rle_encode(BYTE* in, BYTE* out, UINT32 originalSize)
 static void nsc_rle_compress_data(NSC_CONTEXT* context)
 {
        UINT16 i;
-       BYTE* rle;
        UINT32 planeSize;
        UINT32 originalSize;
 
-       rle = context->nsc_stream.Planes;
-
        for (i = 0; i < 4; i++)
        {
                originalSize = context->OrgByteCount[i];
@@ -382,83 +380,136 @@ UINT32 nsc_compute_byte_count(NSC_CONTEXT* context, UINT32* ByteCount, UINT32 wi
 NSC_MESSAGE* nsc_encode_messages(NSC_CONTEXT* context, BYTE* data, int x, int y,
                int width, int height, int scanline, int* numMessages, int maxDataSize)
 {
-       int step;
-       int i, j;
+       int i, j, k;
+       int dataOffset;
+       int rows, cols;
+       int BytesPerPixel;
+       int MaxRegionWidth;
+       int MaxRegionHeight;
        UINT32 ByteCount[4];
        UINT32 MaxPlaneSize;
        UINT32 MaxMessageSize;
        NSC_MESSAGE* messages;
 
-       MaxPlaneSize = nsc_compute_byte_count(context, (UINT32*) ByteCount, width, height);
-       MaxMessageSize = MaxPlaneSize + 20;
+       k = 0;
+       MaxRegionWidth = 64 * 4;
+       MaxRegionHeight = 64 * 2;
+       BytesPerPixel = (context->bpp / 8);
 
-       maxDataSize -= 1024; /* reserve enough space for headers */
+       rows = (width + (MaxRegionWidth - (width % MaxRegionWidth))) / MaxRegionWidth;
+       cols = (height + (MaxRegionHeight - (height % MaxRegionHeight))) / MaxRegionHeight;
+       *numMessages = rows * cols;
 
-       if (MaxMessageSize > maxDataSize)
-               *numMessages = MaxMessageSize / maxDataSize;
+       MaxPlaneSize = nsc_compute_byte_count(context, (UINT32*) ByteCount, width, height);
+       MaxMessageSize = ByteCount[0] + ByteCount[1] + ByteCount[2] + ByteCount[3] + 20;
 
-       if (*numMessages < 1)
-               *numMessages = 1;
+       maxDataSize -= 1024; /* reserve enough space for headers */
 
        messages = (NSC_MESSAGE*) malloc(sizeof(NSC_MESSAGE) * (*numMessages));
        ZeroMemory(messages, sizeof(sizeof(NSC_MESSAGE) * (*numMessages)));
 
-       if (width > height)
+       for (i = 0; i < rows; i++)
        {
-               /**
-                * Horizontal Split
-                */
-
-               step = height / *numMessages;
-               step += (step % 4);
-
-               for (i = 0; i < *numMessages; i++)
+               for (j = 0; j < cols; j++)
                {
-                       messages[i].x = x;
-                       messages[i].width = width;
-                       messages[i].data = data;
-                       messages[i].scanline = scanline;
+                       messages[k].x = x + (i * MaxRegionWidth);
+                       messages[k].y = y + (j * MaxRegionHeight);
+                       messages[k].width = (i < (rows - 1)) ? MaxRegionWidth : width - (i * MaxRegionWidth);
+                       messages[k].height = (j < (cols - 1)) ? MaxRegionHeight : height - (j * MaxRegionHeight);
+                       messages[k].data = data;
+                       messages[k].scanline = scanline;
 
-                       messages[i].y = y + (i * step);
-                       messages[i].height = height - (i * step);
+                       messages[k].MaxPlaneSize = nsc_compute_byte_count(context,
+                                       (UINT32*) messages[k].OrgByteCount, messages[k].width, messages[k].height);
 
-                       messages[i].MaxPlaneSize = nsc_compute_byte_count(context,
-                                       (UINT32*) messages[i].OrgByteCount, messages[i].width, messages[i].height);
+                       k++;
                }
        }
-       else
+
+       *numMessages = k;
+
+       for (i = 0; i < *numMessages; i++)
        {
-               /**
-                * Vertical Split
-                */
+               messages[i].PlaneBuffers[0] = (BYTE*) BufferPool_Take(context->priv->PlanePool, messages[i].MaxPlaneSize);
+               messages[i].PlaneBuffers[1] = (BYTE*) BufferPool_Take(context->priv->PlanePool, messages[i].MaxPlaneSize);
+               messages[i].PlaneBuffers[2] = (BYTE*) BufferPool_Take(context->priv->PlanePool, messages[i].MaxPlaneSize);
+               messages[i].PlaneBuffers[3] = (BYTE*) BufferPool_Take(context->priv->PlanePool, messages[i].MaxPlaneSize);
+               messages[i].PlaneBuffers[4] = (BYTE*) BufferPool_Take(context->priv->PlanePool, messages[i].MaxPlaneSize);
+       }
 
-               step = width / *numMessages;
-               step += (step % 4);
+       for (i = 0; i < *numMessages; i++)
+       {
+               context->width = messages[i].width;
+               context->height = messages[i].height;
+               context->OrgByteCount[0] = messages[i].OrgByteCount[0];
+               context->OrgByteCount[1] = messages[i].OrgByteCount[1];
+               context->OrgByteCount[2] = messages[i].OrgByteCount[2];
+               context->OrgByteCount[3] = messages[i].OrgByteCount[3];
+               context->priv->PlaneBuffersLength = messages[i].MaxPlaneSize;
+               context->priv->PlaneBuffers[0] = messages[i].PlaneBuffers[0];
+               context->priv->PlaneBuffers[1] = messages[i].PlaneBuffers[1];
+               context->priv->PlaneBuffers[2] = messages[i].PlaneBuffers[2];
+               context->priv->PlaneBuffers[3] = messages[i].PlaneBuffers[3];
+               context->priv->PlaneBuffers[4] = messages[i].PlaneBuffers[4];
+
+               dataOffset = (messages[i].y * messages[i].scanline) + (messages[i].x * BytesPerPixel);
+
+               PROFILER_ENTER(context->priv->prof_nsc_encode);
+               context->encode(context, &data[dataOffset], scanline);
+               PROFILER_EXIT(context->priv->prof_nsc_encode);
+
+               PROFILER_ENTER(context->priv->prof_nsc_rle_compress_data);
+               nsc_rle_compress_data(context);
+               PROFILER_EXIT(context->priv->prof_nsc_rle_compress_data);
+
+               messages[i].PlaneByteCount[0] = context->nsc_stream.PlaneByteCount[0];
+               messages[i].PlaneByteCount[1] = context->nsc_stream.PlaneByteCount[1];
+               messages[i].PlaneByteCount[2] = context->nsc_stream.PlaneByteCount[2];
+               messages[i].PlaneByteCount[3] = context->nsc_stream.PlaneByteCount[3];
+       }
 
-               for (i = 0; i < *numMessages; i++)
-               {
-                       messages[i].y = y;
-                       messages[i].height = height;
-                       messages[i].data = data;
-                       messages[i].scanline = scanline;
+       context->priv->PlaneBuffers[0] = NULL;
+       context->priv->PlaneBuffers[1] = NULL;
+       context->priv->PlaneBuffers[2] = NULL;
+       context->priv->PlaneBuffers[3] = NULL;
+       context->priv->PlaneBuffers[4] = NULL;
 
-                       messages[i].x = x + (i * step);
-                       messages[i].width = width - (i * step);
+       return messages;
+}
 
-                       messages[i].MaxPlaneSize = nsc_compute_byte_count(context,
-                                       (UINT32*) messages[i].OrgByteCount, messages[i].width, messages[i].height);
-               }
-       }
+int nsc_write_message(NSC_CONTEXT* context, wStream* s, NSC_MESSAGE* message)
+{
+       int i;
 
-       for (i = 0; i < *numMessages; i++)
+       Stream_EnsureRemainingCapacity(s, 20);
+       Stream_Write_UINT32(s, message->PlaneByteCount[0]); /* LumaPlaneByteCount (4 bytes) */
+       Stream_Write_UINT32(s, message->PlaneByteCount[1]); /* OrangeChromaPlaneByteCount (4 bytes) */
+       Stream_Write_UINT32(s, message->PlaneByteCount[2]); /* GreenChromaPlaneByteCount (4 bytes) */
+       Stream_Write_UINT32(s, message->PlaneByteCount[3]); /* AlphaPlaneByteCount (4 bytes) */
+       Stream_Write_UINT8(s, context->nsc_stream.ColorLossLevel); /* ColorLossLevel (1 byte) */
+       Stream_Write_UINT8(s, context->nsc_stream.ChromaSubSamplingLevel); /* ChromaSubsamplingLevel (1 byte) */
+       Stream_Write_UINT16(s, 0); /* Reserved (2 bytes) */
+
+       for (i = 0; i < 4; i++)
        {
-               for (j = 0; j < 4; j++)
+               if (message->PlaneByteCount[i] > 0)
                {
-                       messages[i].PlaneBuffers[j] = NULL;
+                       Stream_EnsureRemainingCapacity(s, (int) message->PlaneByteCount[i]);
+                       Stream_Write(s, message->PlaneBuffers[i], message->PlaneByteCount[i]);
                }
        }
 
-       return messages;
+       return 0;
+}
+
+int nsc_message_free(NSC_CONTEXT* context, NSC_MESSAGE* message)
+{
+       BufferPool_Return(context->priv->PlanePool, message->PlaneBuffers[0]);
+       BufferPool_Return(context->priv->PlanePool, message->PlaneBuffers[1]);
+       BufferPool_Return(context->priv->PlanePool, message->PlaneBuffers[2]);
+       BufferPool_Return(context->priv->PlanePool, message->PlaneBuffers[3]);
+       BufferPool_Return(context->priv->PlanePool, message->PlaneBuffers[4]);
+       return 0;
 }
 
 void nsc_compose_message(NSC_CONTEXT* context, wStream* s, BYTE* data, int width, int height, int scanline)
index 1ee3d38..bf01e6b 100644 (file)
 #include <malloc.h>
 #endif
 
-struct _aligned_meminfo {
+struct _aligned_meminfo
+{
        size_t size;
-       void *base_addr;
+       voidbase_addr;
 };
 
-
 void* _aligned_malloc(size_t size, size_t alignment)
 {
        return _aligned_offset_malloc(size, alignment, 0);
@@ -75,13 +75,13 @@ void* _aligned_offset_malloc(size_t size, size_t alignment, size_t offset)
 
        /* malloc size + alignment to make sure we can align afterwards */
        tmpptr = malloc(size + alignment + sizeof(struct _aligned_meminfo));
+
        if (!tmpptr)
                return NULL;
 
-
        memptr = (void *)((((size_t)((PBYTE)tmpptr + alignment + offset + sizeof(struct _aligned_meminfo)) & ~(alignment - 1)) - offset));
 
-       ameminfo = (struct _aligned_meminfo *) (((size_t)((PBYTE)memptr - sizeof(struct _aligned_meminfo))));
+       ameminfo = (struct _aligned_meminfo*) (((size_t)((PBYTE)memptr - sizeof(struct _aligned_meminfo))));
        ameminfo->base_addr = tmpptr;
        ameminfo->size = size;
 
@@ -90,8 +90,8 @@ void* _aligned_offset_malloc(size_t size, size_t alignment, size_t offset)
 
 void* _aligned_offset_realloc(void* memblock, size_t size, size_t alignment, size_t offset)
 {
-       struct _aligned_meminfo *ameminfo;
-       void *newmem;
+       void* newmem;
+       struct _aligned_meminfo* ameminfo;
 
        if (!memblock)
                return _aligned_offset_malloc(size, alignment, offset);
@@ -101,15 +101,17 @@ void* _aligned_offset_realloc(void* memblock, size_t size, size_t alignment, siz
                _aligned_free(memblock);
                return NULL;
        }
+
        /*  The following is not very performant but a simple and working solution */
        newmem = _aligned_offset_malloc(size, alignment, offset);
 
        if (!newmem)
                return NULL;
 
-       ameminfo = (struct _aligned_meminfo *) (((size_t)((PBYTE)memblock - sizeof(struct _aligned_meminfo))));
-       memcpy(newmem, memblock, ameminfo->size);
+       ameminfo = (struct _aligned_meminfo*) (((size_t)((PBYTE)memblock - sizeof(struct _aligned_meminfo))));
+       CopyMemory(newmem, memblock, ameminfo->size);
        _aligned_free(memblock);
+
        return newmem;
 }
 
@@ -125,11 +127,12 @@ size_t _aligned_msize(void* memblock, size_t alignment, size_t offset)
 
 void _aligned_free(void* memblock)
 {
-       struct _aligned_meminfo *ameminfo;
+       struct _aligned_meminfo* ameminfo;
+
        if (!memblock)
                return;
 
-       ameminfo = (struct _aligned_meminfo *) (((size_t)((PBYTE)memblock - sizeof(struct _aligned_meminfo))));
+       ameminfo = (struct _aligned_meminfo*) (((size_t)((PBYTE)memblock - sizeof(struct _aligned_meminfo))));
 
        free(ameminfo->base_addr);
 }
index 0c075d9..e5b3911 100644 (file)
@@ -148,8 +148,8 @@ void* BufferPool_Take(wBufferPool* pool, int size)
        {
                if (pool->aArray[index].size > maxSize)
                {
-                       maxSize = pool->aArray[index].size;
                        maxIndex = index;
+                       maxSize = pool->aArray[index].size;
                }
 
                if (pool->aArray[index].size >= size)
@@ -160,28 +160,31 @@ void* BufferPool_Take(wBufferPool* pool, int size)
                }
        }
 
+       if (!found && maxSize)
+       {
+               foundIndex = maxIndex;
+               found = TRUE;
+       }
+
        if (!found)
        {
-               if (!maxSize)
-               {
-                       if (pool->alignment)
-                               buffer = _aligned_malloc(size, pool->alignment);
-                       else
-                               buffer = malloc(size);
-               }
+               if (pool->alignment)
+                       buffer = _aligned_malloc(size, pool->alignment);
                else
-               {
-                       buffer = pool->aArray[maxIndex].buffer;
+                       buffer = malloc(size);
+       }
+       else
+       {
+               buffer = pool->aArray[index].buffer;
 
+               if (maxSize < size)
+               {
                        if (pool->alignment)
                                buffer = _aligned_realloc(buffer, size, pool->alignment);
                        else
                                buffer = realloc(buffer, size);
                }
-       }
-       else
-       {
-               buffer = pool->aArray[index].buffer;
+
                BufferPool_ShiftAvailable(pool, foundIndex, -1);
        }