Blame libfreerdp/codec/planar.c

Packit 1fb8d4
/**
Packit 1fb8d4
 * FreeRDP: A Remote Desktop Protocol Implementation
Packit 1fb8d4
 * RDP6 Planar Codec
Packit 1fb8d4
 *
Packit 1fb8d4
 * Copyright 2013 Marc-Andre Moreau <marcandre.moreau@gmail.com>
Packit 1fb8d4
 * Copyright 2016 Armin Novak <armin.novak@thincast.com>
Packit 1fb8d4
 * Copyright 2016 Thincast Technologies GmbH
Packit 1fb8d4
 *
Packit 1fb8d4
 * Licensed under the Apache License, Version 2.0 (the "License");
Packit 1fb8d4
 * you may not use this file except in compliance with the License.
Packit 1fb8d4
 * You may obtain a copy of the License at
Packit 1fb8d4
 *
Packit 1fb8d4
 *     http://www.apache.org/licenses/LICENSE-2.0
Packit 1fb8d4
 *
Packit 1fb8d4
 * Unless required by applicable law or agreed to in writing, software
Packit 1fb8d4
 * distributed under the License is distributed on an "AS IS" BASIS,
Packit 1fb8d4
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit 1fb8d4
 * See the License for the specific language governing permissions and
Packit 1fb8d4
 * limitations under the License.
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
#ifdef HAVE_CONFIG_H
Packit 1fb8d4
#include "config.h"
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
#include <winpr/crt.h>
Packit 1fb8d4
#include <winpr/print.h>
Packit 1fb8d4
Packit 1fb8d4
#include <freerdp/primitives.h>
Packit 1fb8d4
#include <freerdp/log.h>
Packit 1fb8d4
#include <freerdp/codec/bitmap.h>
Packit 1fb8d4
#include <freerdp/codec/planar.h>
Packit 1fb8d4
Packit 1fb8d4
#define TAG FREERDP_TAG("codec")
Packit 1fb8d4
Packit 1fb8d4
static INLINE BOOL freerdp_bitmap_planar_compress_plane_rle(
Packit 1fb8d4
    const BYTE* plane, UINT32 width, UINT32 height,
Packit 1fb8d4
    BYTE* outPlane, UINT32* dstSize);
Packit 1fb8d4
static INLINE BYTE* freerdp_bitmap_planar_delta_encode_plane(
Packit 1fb8d4
    const BYTE* inPlane, UINT32 width, UINT32 height, BYTE* outPlane);
Packit 1fb8d4
Packit 1fb8d4
static INLINE INT32 planar_skip_plane_rle(const BYTE* pSrcData, UINT32 SrcSize,
Packit 1fb8d4
        UINT32 nWidth, UINT32 nHeight)
Packit 1fb8d4
{
Packit 883aa4
	UINT32 used = 0;
Packit 1fb8d4
	UINT32 x, y;
Packit 1fb8d4
	BYTE controlByte;
Packit 1fb8d4
Packit 1fb8d4
	for (y = 0; y < nHeight; y++)
Packit 1fb8d4
	{
Packit 1fb8d4
		for (x = 0; x < nWidth;)
Packit 1fb8d4
		{
Packit 1fb8d4
			int cRawBytes;
Packit 1fb8d4
			int nRunLength;
Packit 1fb8d4
Packit 883aa4
			if (used >= SrcSize)
Packit 1fb8d4
				return -1;
Packit 1fb8d4
Packit 883aa4
			controlByte = pSrcData[used++];
Packit 1fb8d4
			nRunLength = PLANAR_CONTROL_BYTE_RUN_LENGTH(controlByte);
Packit 1fb8d4
			cRawBytes = PLANAR_CONTROL_BYTE_RAW_BYTES(controlByte);
Packit 1fb8d4
Packit 1fb8d4
			if (nRunLength == 1)
Packit 1fb8d4
			{
Packit 1fb8d4
				nRunLength = cRawBytes + 16;
Packit 1fb8d4
				cRawBytes = 0;
Packit 1fb8d4
			}
Packit 1fb8d4
			else if (nRunLength == 2)
Packit 1fb8d4
			{
Packit 1fb8d4
				nRunLength = cRawBytes + 32;
Packit 1fb8d4
				cRawBytes = 0;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 883aa4
			used += cRawBytes;
Packit 1fb8d4
			x += cRawBytes;
Packit 1fb8d4
			x += nRunLength;
Packit 1fb8d4
Packit 1fb8d4
			if (x > nWidth)
Packit 1fb8d4
				return -1;
Packit 1fb8d4
Packit 883aa4
			if (used > SrcSize)
Packit 1fb8d4
				return -1;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 883aa4
	if (used > INT32_MAX)
Packit 883aa4
		return -1;
Packit 883aa4
	return (INT32)used;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static INLINE INT32 planar_decompress_plane_rle(const BYTE* pSrcData, UINT32 SrcSize,
Packit 1fb8d4
        BYTE* pDstData, INT32 nDstStep,
Packit 1fb8d4
        UINT32 nXDst, UINT32 nYDst,
Packit 1fb8d4
        UINT32 nWidth, UINT32 nHeight,
Packit 1fb8d4
        UINT32 nChannel, BOOL vFlip)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT32 x, y;
Packit 1fb8d4
	UINT32 pixel;
Packit 1fb8d4
	UINT32 cRawBytes;
Packit 1fb8d4
	UINT32 nRunLength;
Packit 1fb8d4
	INT32 deltaValue;
Packit 1fb8d4
	INT32 beg, end, inc;
Packit 1fb8d4
	BYTE controlByte;
Packit 1fb8d4
	BYTE* currentScanline;
Packit 1fb8d4
	BYTE* previousScanline;
Packit 1fb8d4
	const BYTE* srcp = pSrcData;
Packit 1fb8d4
	previousScanline = NULL;
Packit 1fb8d4
Packit 1fb8d4
	if (vFlip)
Packit 1fb8d4
	{
Packit 1fb8d4
		beg = nHeight - 1;
Packit 1fb8d4
		end = -1;
Packit 1fb8d4
		inc = -1;
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		beg = 0;
Packit 1fb8d4
		end = nHeight;
Packit 1fb8d4
		inc = 1;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	for (y = beg; y != end; y += inc)
Packit 1fb8d4
	{
Packit 1fb8d4
		BYTE* dstp = &pDstData[((nYDst + y) * nDstStep) + (nXDst * 4) + nChannel];
Packit 1fb8d4
		pixel = 0;
Packit 1fb8d4
		currentScanline = dstp;
Packit 1fb8d4
Packit 1fb8d4
		for (x = 0; x < nWidth;)
Packit 1fb8d4
		{
Packit 1fb8d4
			controlByte = *srcp;
Packit 1fb8d4
			srcp++;
Packit 1fb8d4
Packit 1fb8d4
			if ((srcp - pSrcData) > SrcSize)
Packit 1fb8d4
			{
Packit 1fb8d4
				WLog_ERR(TAG,  "error reading input buffer");
Packit 1fb8d4
				return -1;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			nRunLength = PLANAR_CONTROL_BYTE_RUN_LENGTH(controlByte);
Packit 1fb8d4
			cRawBytes = PLANAR_CONTROL_BYTE_RAW_BYTES(controlByte);
Packit 1fb8d4
Packit 1fb8d4
			if (nRunLength == 1)
Packit 1fb8d4
			{
Packit 1fb8d4
				nRunLength = cRawBytes + 16;
Packit 1fb8d4
				cRawBytes = 0;
Packit 1fb8d4
			}
Packit 1fb8d4
			else if (nRunLength == 2)
Packit 1fb8d4
			{
Packit 1fb8d4
				nRunLength = cRawBytes + 32;
Packit 1fb8d4
				cRawBytes = 0;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			if (((dstp + (cRawBytes + nRunLength)) - currentScanline) > nWidth * 4)
Packit 1fb8d4
			{
Packit 1fb8d4
				WLog_ERR(TAG,  "too many pixels in scanline");
Packit 1fb8d4
				return -1;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			if (!previousScanline)
Packit 1fb8d4
			{
Packit 1fb8d4
				/* first scanline, absolute values */
Packit 1fb8d4
				while (cRawBytes > 0)
Packit 1fb8d4
				{
Packit 1fb8d4
					pixel = *srcp;
Packit 1fb8d4
					srcp++;
Packit 1fb8d4
					*dstp = pixel;
Packit 1fb8d4
					dstp += 4;
Packit 1fb8d4
					x++;
Packit 1fb8d4
					cRawBytes--;
Packit 1fb8d4
				}
Packit 1fb8d4
Packit 1fb8d4
				while (nRunLength > 0)
Packit 1fb8d4
				{
Packit 1fb8d4
					*dstp = pixel;
Packit 1fb8d4
					dstp += 4;
Packit 1fb8d4
					x++;
Packit 1fb8d4
					nRunLength--;
Packit 1fb8d4
				}
Packit 1fb8d4
			}
Packit 1fb8d4
			else
Packit 1fb8d4
			{
Packit 1fb8d4
				/* delta values relative to previous scanline */
Packit 1fb8d4
				while (cRawBytes > 0)
Packit 1fb8d4
				{
Packit 1fb8d4
					deltaValue = *srcp;
Packit 1fb8d4
					srcp++;
Packit 1fb8d4
Packit 1fb8d4
					if (deltaValue & 1)
Packit 1fb8d4
					{
Packit 1fb8d4
						deltaValue = deltaValue >> 1;
Packit 1fb8d4
						deltaValue = deltaValue + 1;
Packit 1fb8d4
						pixel = -deltaValue;
Packit 1fb8d4
					}
Packit 1fb8d4
					else
Packit 1fb8d4
					{
Packit 1fb8d4
						deltaValue = deltaValue >> 1;
Packit 1fb8d4
						pixel = deltaValue;
Packit 1fb8d4
					}
Packit 1fb8d4
Packit 1fb8d4
					deltaValue = previousScanline[x * 4] + pixel;
Packit 1fb8d4
					*dstp = deltaValue;
Packit 1fb8d4
					dstp += 4;
Packit 1fb8d4
					x++;
Packit 1fb8d4
					cRawBytes--;
Packit 1fb8d4
				}
Packit 1fb8d4
Packit 1fb8d4
				while (nRunLength > 0)
Packit 1fb8d4
				{
Packit 1fb8d4
					deltaValue = previousScanline[x * 4] + pixel;
Packit 1fb8d4
					*dstp = deltaValue;
Packit 1fb8d4
					dstp += 4;
Packit 1fb8d4
					x++;
Packit 1fb8d4
					nRunLength--;
Packit 1fb8d4
				}
Packit 1fb8d4
			}
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		previousScanline = currentScanline;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return (INT32)(srcp - pSrcData);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static INLINE BOOL writeLine(BYTE** ppRgba, UINT32 DstFormat, UINT32 width, const BYTE** ppR,
Packit 1fb8d4
                             const BYTE** ppG, const BYTE** ppB, const BYTE** ppA)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT32 x;
Packit 1fb8d4
Packit 1fb8d4
	if (!ppRgba || !ppR || !ppG || !ppB)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	switch (DstFormat)
Packit 1fb8d4
	{
Packit 1fb8d4
		case PIXEL_FORMAT_BGRA32:
Packit 1fb8d4
			for (x = 0; x < width; x++)
Packit 1fb8d4
			{
Packit 1fb8d4
				*(*ppRgba)++ = *(*ppB)++;
Packit 1fb8d4
				*(*ppRgba)++ = *(*ppG)++;
Packit 1fb8d4
				*(*ppRgba)++ = *(*ppR)++;
Packit 1fb8d4
				*(*ppRgba)++ = *(*ppA)++;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			return TRUE;
Packit 1fb8d4
Packit 1fb8d4
		case PIXEL_FORMAT_BGRX32:
Packit 1fb8d4
			for (x = 0; x < width; x++)
Packit 1fb8d4
			{
Packit 1fb8d4
				*(*ppRgba)++ = *(*ppB)++;
Packit 1fb8d4
				*(*ppRgba)++ = *(*ppG)++;
Packit 1fb8d4
				*(*ppRgba)++ = *(*ppR)++;
Packit 1fb8d4
				*(*ppRgba)++ = 0xFF;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			return TRUE;
Packit 1fb8d4
Packit 1fb8d4
		default:
Packit 1fb8d4
			if (ppA)
Packit 1fb8d4
			{
Packit 1fb8d4
				for (x = 0; x < width; x++)
Packit 1fb8d4
				{
Packit 1fb8d4
					BYTE alpha = *(*ppA)++;
Packit 1fb8d4
					UINT32 color = FreeRDPGetColor(DstFormat, *(*ppR)++, *(*ppG)++, *(*ppB)++, alpha);
Packit 1fb8d4
					WriteColor(*ppRgba, DstFormat, color);
Packit 1fb8d4
					*ppRgba += GetBytesPerPixel(DstFormat);
Packit 1fb8d4
				}
Packit 1fb8d4
			}
Packit 1fb8d4
			else
Packit 1fb8d4
			{
Packit 1fb8d4
				const BYTE alpha = 0xFF;
Packit 1fb8d4
Packit 1fb8d4
				for (x = 0; x < width; x++)
Packit 1fb8d4
				{
Packit 1fb8d4
					UINT32 color = FreeRDPGetColor(DstFormat, *(*ppR)++, *(*ppG)++, *(*ppB)++, alpha);
Packit 1fb8d4
					WriteColor(*ppRgba, DstFormat, color);
Packit 1fb8d4
					*ppRgba += GetBytesPerPixel(DstFormat);
Packit 1fb8d4
				}
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			return TRUE;
Packit 1fb8d4
	}
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static INLINE BOOL planar_decompress_planes_raw(const BYTE* pSrcData[4],
Packit 1fb8d4
        BYTE* pDstData, UINT32 DstFormat,
Packit 1fb8d4
        UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst, UINT32 nWidth, UINT32 nHeight,
Packit 1fb8d4
        BOOL vFlip)
Packit 1fb8d4
{
Packit 1fb8d4
	INT32 y;
Packit 1fb8d4
	INT32 beg, end, inc;
Packit 1fb8d4
	const BYTE* pR = pSrcData[0];
Packit 1fb8d4
	const BYTE* pG = pSrcData[1];
Packit 1fb8d4
	const BYTE* pB = pSrcData[2];
Packit 1fb8d4
	const BYTE* pA = pSrcData[3];
Packit 1fb8d4
Packit 1fb8d4
	if (vFlip)
Packit 1fb8d4
	{
Packit 1fb8d4
		beg = nHeight - 1;
Packit 1fb8d4
		end = -1;
Packit 1fb8d4
		inc = -1;
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		beg = 0;
Packit 1fb8d4
		end = nHeight;
Packit 1fb8d4
		inc = 1;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	for (y = beg; y != end; y += inc)
Packit 1fb8d4
	{
Packit 1fb8d4
		BYTE* pRGB = &pDstData[((nYDst + y) * nDstStep) + (nXDst * GetBytesPerPixel(
Packit 1fb8d4
		                                        DstFormat))];
Packit 1fb8d4
Packit 1fb8d4
		if (!writeLine(&pRGB, DstFormat, nWidth, &pR, &pG, &pB, &pA))
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
BOOL planar_decompress(BITMAP_PLANAR_CONTEXT* planar,
Packit 1fb8d4
                       const BYTE* pSrcData, UINT32 SrcSize,
Packit 1fb8d4
                       UINT32 nSrcWidth, UINT32 nSrcHeight,
Packit 1fb8d4
                       BYTE* pDstData, UINT32 DstFormat,
Packit 1fb8d4
                       UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst,
Packit 1fb8d4
                       UINT32 nDstWidth, UINT32 nDstHeight, BOOL vFlip)
Packit 1fb8d4
{
Packit 1fb8d4
	BOOL cs;
Packit 1fb8d4
	BOOL rle;
Packit 1fb8d4
	UINT32 cll;
Packit 1fb8d4
	BOOL alpha;
Packit 1fb8d4
	BOOL useAlpha = FALSE;
Packit 1fb8d4
	INT32 status;
Packit 1fb8d4
	const BYTE* srcp;
Packit 1fb8d4
	UINT32 subSize;
Packit 1fb8d4
	UINT32 subWidth;
Packit 1fb8d4
	UINT32 subHeight;
Packit 1fb8d4
	UINT32 planeSize;
Packit 1fb8d4
	INT32 rleSizes[4] = { 0, 0, 0, 0 };
Packit 1fb8d4
	UINT32 rawSizes[4];
Packit 1fb8d4
	UINT32 rawWidths[4];
Packit 1fb8d4
	UINT32 rawHeights[4];
Packit 1fb8d4
	BYTE FormatHeader;
Packit 1fb8d4
	const BYTE* planes[4];
Packit 1fb8d4
	const UINT32 w = MIN(nSrcWidth, nDstWidth);
Packit 1fb8d4
	const UINT32 h = MIN(nSrcHeight, nDstHeight);
Packit 1fb8d4
	const primitives_t* prims = primitives_get();
Packit 1fb8d4
Packit 1fb8d4
	if (nDstStep <= 0)
Packit 1fb8d4
		nDstStep = nDstWidth * GetBytesPerPixel(DstFormat);
Packit 1fb8d4
Packit 1fb8d4
	srcp = pSrcData;
Packit 1fb8d4
Packit 1fb8d4
	if (!pDstData)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "Invalid argument pDstData=NULL");
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	FormatHeader = *srcp++;
Packit 1fb8d4
	cll = (FormatHeader & PLANAR_FORMAT_HEADER_CLL_MASK);
Packit 1fb8d4
	cs = (FormatHeader & PLANAR_FORMAT_HEADER_CS) ? TRUE : FALSE;
Packit 1fb8d4
	rle = (FormatHeader & PLANAR_FORMAT_HEADER_RLE) ? TRUE : FALSE;
Packit 1fb8d4
	alpha = (FormatHeader & PLANAR_FORMAT_HEADER_NA) ? FALSE : TRUE;
Packit 1fb8d4
Packit 1fb8d4
	if (alpha)
Packit 1fb8d4
		useAlpha = ColorHasAlpha(DstFormat);
Packit 1fb8d4
Packit 1fb8d4
	//WLog_INFO(TAG, "CLL: %"PRIu32" CS: %"PRIu8" RLE: %"PRIu8" ALPHA: %"PRIu8"", cll, cs, rle, alpha);
Packit 1fb8d4
Packit 1fb8d4
	if (!cll && cs)
Packit 1fb8d4
		return FALSE; /* Chroma subsampling requires YCoCg */
Packit 1fb8d4
Packit 1fb8d4
	subWidth = (nSrcWidth / 2) + (nSrcWidth % 2);
Packit 1fb8d4
	subHeight = (nSrcHeight / 2) + (nSrcHeight % 2);
Packit 1fb8d4
	planeSize = nSrcWidth * nSrcHeight;
Packit 1fb8d4
	subSize = subWidth * subHeight;
Packit 1fb8d4
Packit 1fb8d4
	if (!cs)
Packit 1fb8d4
	{
Packit 1fb8d4
		rawSizes[0] = planeSize; /* LumaOrRedPlane */
Packit 1fb8d4
		rawWidths[0] = nSrcWidth;
Packit 1fb8d4
		rawHeights[0] = nSrcHeight;
Packit 1fb8d4
		rawSizes[1] = planeSize; /* OrangeChromaOrGreenPlane */
Packit 1fb8d4
		rawWidths[1] = nSrcWidth;
Packit 1fb8d4
		rawHeights[1] = nSrcHeight;
Packit 1fb8d4
		rawSizes[2] = planeSize; /* GreenChromaOrBluePlane */
Packit 1fb8d4
		rawWidths[2] = nSrcWidth;
Packit 1fb8d4
		rawHeights[2] = nSrcHeight;
Packit 1fb8d4
		rawSizes[3] = planeSize; /* AlphaPlane */
Packit 1fb8d4
		rawWidths[3] = nSrcWidth;
Packit 1fb8d4
		rawHeights[3] = nSrcHeight;
Packit 1fb8d4
	}
Packit 1fb8d4
	else /* Chroma Subsampling */
Packit 1fb8d4
	{
Packit 1fb8d4
		rawSizes[0] = planeSize; /* LumaOrRedPlane */
Packit 1fb8d4
		rawWidths[0] = nSrcWidth;
Packit 1fb8d4
		rawHeights[0] = nSrcHeight;
Packit 1fb8d4
		rawSizes[1] = subSize; /* OrangeChromaOrGreenPlane */
Packit 1fb8d4
		rawWidths[1] = subWidth;
Packit 1fb8d4
		rawHeights[1] = subHeight;
Packit 1fb8d4
		rawSizes[2] = subSize; /* GreenChromaOrBluePlane */
Packit 1fb8d4
		rawWidths[2] = subWidth;
Packit 1fb8d4
		rawHeights[2] = subHeight;
Packit 1fb8d4
		rawSizes[3] = planeSize; /* AlphaPlane */
Packit 1fb8d4
		rawWidths[3] = nSrcWidth;
Packit 1fb8d4
		rawHeights[3] = nSrcHeight;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (!rle) /* RAW */
Packit 1fb8d4
	{
Packit 1fb8d4
		if (alpha)
Packit 1fb8d4
		{
Packit 1fb8d4
			if ((SrcSize - (srcp - pSrcData)) < (planeSize * 4))
Packit 1fb8d4
				return FALSE;
Packit 1fb8d4
Packit 1fb8d4
			planes[3] = srcp; /* AlphaPlane */
Packit 1fb8d4
			planes[0] = planes[3] + rawSizes[3]; /* LumaOrRedPlane */
Packit 1fb8d4
			planes[1] = planes[0] + rawSizes[0]; /* OrangeChromaOrGreenPlane */
Packit 1fb8d4
			planes[2] = planes[1] + rawSizes[1]; /* GreenChromaOrBluePlane */
Packit 1fb8d4
Packit 1fb8d4
			if ((planes[2] + rawSizes[2]) > &pSrcData[SrcSize])
Packit 1fb8d4
				return FALSE;
Packit 1fb8d4
		}
Packit 1fb8d4
		else
Packit 1fb8d4
		{
Packit 1fb8d4
			if ((SrcSize - (srcp - pSrcData)) < (planeSize * 3))
Packit 1fb8d4
				return FALSE;
Packit 1fb8d4
Packit 1fb8d4
			planes[0] = srcp; /* LumaOrRedPlane */
Packit 1fb8d4
			planes[1] = planes[0] + rawSizes[0]; /* OrangeChromaOrGreenPlane */
Packit 1fb8d4
			planes[2] = planes[1] + rawSizes[1]; /* GreenChromaOrBluePlane */
Packit 1fb8d4
Packit 1fb8d4
			if ((planes[2] + rawSizes[2]) > &pSrcData[SrcSize])
Packit 1fb8d4
				return FALSE;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
	else /* RLE */
Packit 1fb8d4
	{
Packit 1fb8d4
		if (alpha)
Packit 1fb8d4
		{
Packit 1fb8d4
			planes[3] = srcp;
Packit 1fb8d4
			rleSizes[3] = planar_skip_plane_rle(planes[3], SrcSize - (planes[3] - pSrcData),
Packit 1fb8d4
			                                    rawWidths[3], rawHeights[3]); /* AlphaPlane */
Packit 1fb8d4
Packit 1fb8d4
			if (rleSizes[3] < 0)
Packit 1fb8d4
				return FALSE;
Packit 1fb8d4
Packit 1fb8d4
			planes[0] = planes[3] + rleSizes[3];
Packit 1fb8d4
		}
Packit 1fb8d4
		else
Packit 1fb8d4
			planes[0] = srcp;
Packit 1fb8d4
Packit 1fb8d4
		rleSizes[0] = planar_skip_plane_rle(planes[0], SrcSize - (planes[0] - pSrcData),
Packit 1fb8d4
		                                    rawWidths[0], rawHeights[0]); /* RedPlane */
Packit 1fb8d4
Packit 1fb8d4
		if (rleSizes[0] < 0)
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
Packit 1fb8d4
		planes[1] = planes[0] + rleSizes[0];
Packit 1fb8d4
		rleSizes[1] = planar_skip_plane_rle(planes[1], SrcSize - (planes[1] - pSrcData),
Packit 1fb8d4
		                                    rawWidths[1], rawHeights[1]); /* GreenPlane */
Packit 1fb8d4
Packit 1fb8d4
		if (rleSizes[1] < 1)
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
Packit 1fb8d4
		planes[2] = planes[1] + rleSizes[1];
Packit 1fb8d4
		rleSizes[2] = planar_skip_plane_rle(planes[2], SrcSize - (planes[2] - pSrcData),
Packit 1fb8d4
		                                    rawWidths[2], rawHeights[2]); /* BluePlane */
Packit 1fb8d4
Packit 1fb8d4
		if (rleSizes[2] < 1)
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (!cll) /* RGB */
Packit 1fb8d4
	{
Packit 1fb8d4
		UINT32 TempFormat;
Packit 1fb8d4
		BYTE* pTempData = pDstData;
Packit 1fb8d4
		UINT32 nTempStep = nDstStep;
Packit 1fb8d4
Packit 1fb8d4
		if (useAlpha)
Packit 1fb8d4
			TempFormat = PIXEL_FORMAT_BGRA32;
Packit 1fb8d4
		else
Packit 1fb8d4
			TempFormat = PIXEL_FORMAT_BGRX32;
Packit 1fb8d4
Packit 1fb8d4
		if ((TempFormat != DstFormat) || (nSrcWidth != nDstWidth)
Packit 1fb8d4
		    || (nSrcHeight != nDstHeight))
Packit 1fb8d4
		{
Packit 1fb8d4
			pTempData = planar->pTempData;
Packit 1fb8d4
			nTempStep = planar->nTempStep;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		if (!rle) /* RAW */
Packit 1fb8d4
		{
Packit 1fb8d4
			if (!planar_decompress_planes_raw(planes, pTempData, TempFormat, nTempStep,
Packit 1fb8d4
			                                  nXDst, nYDst, nSrcWidth, nSrcHeight, vFlip))
Packit 1fb8d4
				return FALSE;
Packit 1fb8d4
Packit 1fb8d4
			if (alpha)
Packit 1fb8d4
				srcp += rawSizes[0] + rawSizes[1] + rawSizes[2] + rawSizes[3];
Packit 1fb8d4
			else /* NoAlpha */
Packit 1fb8d4
				srcp += rawSizes[0] + rawSizes[1] + rawSizes[2];
Packit 1fb8d4
Packit 1fb8d4
			if ((SrcSize - (srcp - pSrcData)) == 1)
Packit 1fb8d4
				srcp++; /* pad */
Packit 1fb8d4
		}
Packit 1fb8d4
		else /* RLE */
Packit 1fb8d4
		{
Packit 1fb8d4
			status = planar_decompress_plane_rle(planes[0], rleSizes[0],
Packit 1fb8d4
			                                     pTempData, nTempStep, nXDst, nYDst, nSrcWidth, nSrcHeight, 2,
Packit 1fb8d4
			                                     vFlip); /* RedPlane */
Packit 1fb8d4
Packit 1fb8d4
			if (status < 0)
Packit 1fb8d4
				return FALSE;
Packit 1fb8d4
Packit 1fb8d4
			status = planar_decompress_plane_rle(planes[1], rleSizes[1],
Packit 1fb8d4
			                                     pTempData, nTempStep, nXDst, nYDst, nSrcWidth, nSrcHeight, 1,
Packit 1fb8d4
			                                     vFlip); /* GreenPlane */
Packit 1fb8d4
Packit 1fb8d4
			if (status < 0)
Packit 1fb8d4
				return FALSE;
Packit 1fb8d4
Packit 1fb8d4
			status = planar_decompress_plane_rle(planes[2], rleSizes[2],
Packit 1fb8d4
			                                     pTempData, nTempStep, nXDst, nYDst, nSrcWidth, nSrcHeight, 0,
Packit 1fb8d4
			                                     vFlip); /* BluePlane */
Packit 1fb8d4
Packit 1fb8d4
			if (status < 0)
Packit 1fb8d4
				return FALSE;
Packit 1fb8d4
Packit 1fb8d4
			srcp += rleSizes[0] + rleSizes[1] + rleSizes[2];
Packit 1fb8d4
Packit 1fb8d4
			if (useAlpha)
Packit 1fb8d4
			{
Packit 1fb8d4
				status = planar_decompress_plane_rle(planes[3], rleSizes[3],
Packit 1fb8d4
				                                     pTempData, nTempStep, nXDst, nYDst, nSrcWidth, nSrcHeight, 3,
Packit 1fb8d4
				                                     vFlip); /* AlphaPlane */
Packit 1fb8d4
Packit 1fb8d4
				if (status < 0)
Packit 1fb8d4
					return FALSE;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			if (alpha)
Packit 1fb8d4
				srcp += rleSizes[3];
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		if (pTempData != pDstData)
Packit 1fb8d4
		{
Packit 1fb8d4
			if (!freerdp_image_copy(pDstData, DstFormat, nDstStep, nXDst, nYDst, w,
Packit 1fb8d4
			                        h, pTempData,
Packit 1fb8d4
			                        TempFormat, nTempStep, nXDst, nYDst, NULL, FREERDP_FLIP_NONE))
Packit 1fb8d4
				return FALSE;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
	else /* YCoCg */
Packit 1fb8d4
	{
Packit 1fb8d4
		UINT32 TempFormat;
Packit 1fb8d4
		BYTE* pTempData = planar->pTempData;
Packit 1fb8d4
		UINT32 nTempStep = planar->nTempStep;
Packit 1fb8d4
Packit 1fb8d4
		if (useAlpha)
Packit 1fb8d4
			TempFormat = PIXEL_FORMAT_BGRA32;
Packit 1fb8d4
		else
Packit 1fb8d4
			TempFormat = PIXEL_FORMAT_BGRX32;
Packit 1fb8d4
Packit 1fb8d4
		if (!pTempData)
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
Packit 1fb8d4
		if (cs)
Packit 1fb8d4
		{
Packit 1fb8d4
			WLog_ERR(TAG, "Chroma subsampling unimplemented");
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		if (!rle) /* RAW */
Packit 1fb8d4
		{
Packit 1fb8d4
			if (!planar_decompress_planes_raw(planes, pTempData, TempFormat, nTempStep,
Packit 1fb8d4
			                                  nXDst, nYDst, nSrcWidth, nSrcHeight, vFlip))
Packit 1fb8d4
				return FALSE;
Packit 1fb8d4
Packit 1fb8d4
			if (alpha)
Packit 1fb8d4
				srcp += rawSizes[0] + rawSizes[1] + rawSizes[2] + rawSizes[3];
Packit 1fb8d4
			else /* NoAlpha */
Packit 1fb8d4
				srcp += rawSizes[0] + rawSizes[1] + rawSizes[2];
Packit 1fb8d4
Packit 1fb8d4
			if ((SrcSize - (srcp - pSrcData)) == 1)
Packit 1fb8d4
				srcp++; /* pad */
Packit 1fb8d4
		}
Packit 1fb8d4
		else /* RLE */
Packit 1fb8d4
		{
Packit 1fb8d4
			if (useAlpha)
Packit 1fb8d4
			{
Packit 1fb8d4
				status = planar_decompress_plane_rle(planes[3], rleSizes[3],
Packit 1fb8d4
				                                     pTempData, nTempStep, nXDst, nYDst, nSrcWidth, nSrcHeight, 3,
Packit 1fb8d4
				                                     vFlip); /* AlphaPlane */
Packit 1fb8d4
Packit 1fb8d4
				if (status < 0)
Packit 1fb8d4
					return FALSE;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			if (alpha)
Packit 1fb8d4
				srcp += rleSizes[3];
Packit 1fb8d4
Packit 1fb8d4
			status = planar_decompress_plane_rle(planes[0], rleSizes[0],
Packit 1fb8d4
			                                     pTempData, nTempStep, nXDst, nYDst, nSrcWidth, nSrcHeight, 2,
Packit 1fb8d4
			                                     vFlip); /* LumaPlane */
Packit 1fb8d4
Packit 1fb8d4
			if (status < 0)
Packit 1fb8d4
				return FALSE;
Packit 1fb8d4
Packit 1fb8d4
			status = planar_decompress_plane_rle(planes[1], rleSizes[1],
Packit 1fb8d4
			                                     pTempData, nTempStep, nXDst, nYDst, nSrcWidth, nSrcHeight, 1,
Packit 1fb8d4
			                                     vFlip); /* OrangeChromaPlane */
Packit 1fb8d4
Packit 1fb8d4
			if (status < 0)
Packit 1fb8d4
				return FALSE;
Packit 1fb8d4
Packit 1fb8d4
			status = planar_decompress_plane_rle(planes[2], rleSizes[2],
Packit 1fb8d4
			                                     pTempData, nTempStep, nXDst, nYDst, nSrcWidth, nSrcHeight, 0,
Packit 1fb8d4
			                                     vFlip); /* GreenChromaPlane */
Packit 1fb8d4
Packit 1fb8d4
			if (status < 0)
Packit 1fb8d4
				return FALSE;
Packit 1fb8d4
Packit 1fb8d4
			srcp += rleSizes[0] + rleSizes[1] + rleSizes[2];
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		if (prims->YCoCgToRGB_8u_AC4R(pTempData, nTempStep, pDstData, DstFormat,
Packit 1fb8d4
		                              nDstStep,
Packit 1fb8d4
		                              w, h, cll, useAlpha) != PRIMITIVES_SUCCESS)
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return (SrcSize == (srcp - pSrcData)) ? TRUE : FALSE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static INLINE BOOL freerdp_split_color_planes(const BYTE* data, UINT32 format,
Packit 1fb8d4
        UINT32 width, UINT32 height,
Packit 1fb8d4
        UINT32 scanline, BYTE* planes[4])
Packit 1fb8d4
{
Packit 1fb8d4
	INT32 i, j, k;
Packit 1fb8d4
	k = 0;
Packit 1fb8d4
Packit 1fb8d4
	if (scanline == 0)
Packit 1fb8d4
		scanline = width * GetBytesPerPixel(format);
Packit 1fb8d4
Packit 1fb8d4
	for (i = height - 1; i >= 0; i--)
Packit 1fb8d4
	{
Packit 1fb8d4
		const BYTE* pixel = &data[scanline * i];
Packit 1fb8d4
Packit 1fb8d4
		for (j = 0; j < width; j++)
Packit 1fb8d4
		{
Packit 1fb8d4
			const UINT32 color = ReadColor(pixel, format);
Packit 1fb8d4
			pixel += GetBytesPerPixel(format);
Packit 1fb8d4
			SplitColor(color, format, &planes[1][k], &planes[2][k],
Packit 1fb8d4
			           &planes[3][k], &planes[0][k], NULL);
Packit 1fb8d4
			k++;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static INLINE UINT32 freerdp_bitmap_planar_write_rle_bytes(
Packit 1fb8d4
    const BYTE* pInBuffer, UINT32 cRawBytes, UINT32 nRunLength,
Packit 1fb8d4
    BYTE* pOutBuffer, UINT32 outBufferSize)
Packit 1fb8d4
{
Packit 1fb8d4
	const BYTE* pInput;
Packit 1fb8d4
	BYTE* pOutput;
Packit 1fb8d4
	BYTE controlByte;
Packit 1fb8d4
	UINT32 nBytesToWrite;
Packit 1fb8d4
	pInput = pInBuffer;
Packit 1fb8d4
	pOutput = pOutBuffer;
Packit 1fb8d4
Packit 1fb8d4
	if (!cRawBytes && !nRunLength)
Packit 1fb8d4
		return 0;
Packit 1fb8d4
Packit 1fb8d4
	if (nRunLength < 3)
Packit 1fb8d4
	{
Packit 1fb8d4
		cRawBytes += nRunLength;
Packit 1fb8d4
		nRunLength = 0;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	while (cRawBytes)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (cRawBytes < 16)
Packit 1fb8d4
		{
Packit 1fb8d4
			if (nRunLength > 15)
Packit 1fb8d4
			{
Packit 1fb8d4
				if (nRunLength < 18)
Packit 1fb8d4
				{
Packit 1fb8d4
					controlByte = PLANAR_CONTROL_BYTE(13, cRawBytes);
Packit 1fb8d4
					nRunLength -= 13;
Packit 1fb8d4
					cRawBytes = 0;
Packit 1fb8d4
				}
Packit 1fb8d4
				else
Packit 1fb8d4
				{
Packit 1fb8d4
					controlByte = PLANAR_CONTROL_BYTE(15, cRawBytes);
Packit 1fb8d4
					nRunLength -= 15;
Packit 1fb8d4
					cRawBytes = 0;
Packit 1fb8d4
				}
Packit 1fb8d4
			}
Packit 1fb8d4
			else
Packit 1fb8d4
			{
Packit 1fb8d4
				controlByte = PLANAR_CONTROL_BYTE(nRunLength, cRawBytes);
Packit 1fb8d4
				nRunLength = 0;
Packit 1fb8d4
				cRawBytes = 0;
Packit 1fb8d4
			}
Packit 1fb8d4
		}
Packit 1fb8d4
		else
Packit 1fb8d4
		{
Packit 1fb8d4
			controlByte = PLANAR_CONTROL_BYTE(0, 15);
Packit 1fb8d4
			cRawBytes -= 15;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		if (outBufferSize < 1)
Packit 1fb8d4
			return 0;
Packit 1fb8d4
Packit 1fb8d4
		outBufferSize--;
Packit 1fb8d4
		*pOutput = controlByte;
Packit 1fb8d4
		pOutput++;
Packit 1fb8d4
		nBytesToWrite = (int)(controlByte >> 4);
Packit 1fb8d4
Packit 1fb8d4
		if (nBytesToWrite)
Packit 1fb8d4
		{
Packit 1fb8d4
			if (outBufferSize < nBytesToWrite)
Packit 1fb8d4
				return 0;
Packit 1fb8d4
Packit 1fb8d4
			outBufferSize -= nBytesToWrite;
Packit 1fb8d4
			CopyMemory(pOutput, pInput, nBytesToWrite);
Packit 1fb8d4
			pOutput += nBytesToWrite;
Packit 1fb8d4
			pInput += nBytesToWrite;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	while (nRunLength)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (nRunLength > 47)
Packit 1fb8d4
		{
Packit 1fb8d4
			if (nRunLength < 50)
Packit 1fb8d4
			{
Packit 1fb8d4
				controlByte = PLANAR_CONTROL_BYTE(2, 13);
Packit 1fb8d4
				nRunLength -= 45;
Packit 1fb8d4
			}
Packit 1fb8d4
			else
Packit 1fb8d4
			{
Packit 1fb8d4
				controlByte = PLANAR_CONTROL_BYTE(2, 15);
Packit 1fb8d4
				nRunLength -= 47;
Packit 1fb8d4
			}
Packit 1fb8d4
		}
Packit 1fb8d4
		else if (nRunLength > 31)
Packit 1fb8d4
		{
Packit 1fb8d4
			controlByte = PLANAR_CONTROL_BYTE(2, (nRunLength - 32));
Packit 1fb8d4
			nRunLength = 0;
Packit 1fb8d4
		}
Packit 1fb8d4
		else if (nRunLength > 15)
Packit 1fb8d4
		{
Packit 1fb8d4
			controlByte = PLANAR_CONTROL_BYTE(1, (nRunLength - 16));
Packit 1fb8d4
			nRunLength = 0;
Packit 1fb8d4
		}
Packit 1fb8d4
		else
Packit 1fb8d4
		{
Packit 1fb8d4
			controlByte = PLANAR_CONTROL_BYTE(nRunLength, 0);
Packit 1fb8d4
			nRunLength = 0;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		if (outBufferSize < 1)
Packit 1fb8d4
			return 0;
Packit 1fb8d4
Packit 1fb8d4
		--outBufferSize;
Packit 1fb8d4
		*pOutput = controlByte;
Packit 1fb8d4
		pOutput++;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return (pOutput - pOutBuffer);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static INLINE UINT32 freerdp_bitmap_planar_encode_rle_bytes(const BYTE* pInBuffer,
Packit 1fb8d4
        UINT32 inBufferSize,
Packit 1fb8d4
        BYTE* pOutBuffer,
Packit 1fb8d4
        UINT32 outBufferSize)
Packit 1fb8d4
{
Packit 1fb8d4
	BYTE symbol;
Packit 1fb8d4
	const BYTE* pInput;
Packit 1fb8d4
	BYTE* pOutput;
Packit 1fb8d4
	const BYTE* pBytes;
Packit 1fb8d4
	UINT32 cRawBytes;
Packit 1fb8d4
	UINT32 nRunLength;
Packit 1fb8d4
	UINT32 bSymbolMatch;
Packit 1fb8d4
	UINT32 nBytesWritten;
Packit 1fb8d4
	UINT32 nTotalBytesWritten;
Packit 1fb8d4
	symbol = 0;
Packit 1fb8d4
	cRawBytes = 0;
Packit 1fb8d4
	nRunLength = 0;
Packit 1fb8d4
	pInput = pInBuffer;
Packit 1fb8d4
	pOutput = pOutBuffer;
Packit 1fb8d4
	nTotalBytesWritten = 0;
Packit 1fb8d4
Packit 1fb8d4
	if (!outBufferSize)
Packit 1fb8d4
		return 0;
Packit 1fb8d4
Packit 1fb8d4
	do
Packit 1fb8d4
	{
Packit 1fb8d4
		if (!inBufferSize)
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		bSymbolMatch = (symbol == *pInput) ? TRUE : FALSE;
Packit 1fb8d4
		symbol = *pInput;
Packit 1fb8d4
		pInput++;
Packit 1fb8d4
		inBufferSize--;
Packit 1fb8d4
Packit 1fb8d4
		if (nRunLength && !bSymbolMatch)
Packit 1fb8d4
		{
Packit 1fb8d4
			if (nRunLength < 3)
Packit 1fb8d4
			{
Packit 1fb8d4
				cRawBytes += nRunLength;
Packit 1fb8d4
				nRunLength = 0;
Packit 1fb8d4
			}
Packit 1fb8d4
			else
Packit 1fb8d4
			{
Packit 1fb8d4
				pBytes = pInput - (cRawBytes + nRunLength + 1);
Packit 1fb8d4
				nBytesWritten = freerdp_bitmap_planar_write_rle_bytes(
Packit 1fb8d4
				                    pBytes, cRawBytes,
Packit 1fb8d4
				                    nRunLength, pOutput,
Packit 1fb8d4
				                    outBufferSize);
Packit 1fb8d4
				nRunLength = 0;
Packit 1fb8d4
Packit 1fb8d4
				if (!nBytesWritten || (nBytesWritten > outBufferSize))
Packit 1fb8d4
					return nRunLength;
Packit 1fb8d4
Packit 1fb8d4
				nTotalBytesWritten += nBytesWritten;
Packit 1fb8d4
				outBufferSize -= nBytesWritten;
Packit 1fb8d4
				pOutput += nBytesWritten;
Packit 1fb8d4
				cRawBytes = 0;
Packit 1fb8d4
			}
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		nRunLength += bSymbolMatch;
Packit 1fb8d4
		cRawBytes += (!bSymbolMatch) ? TRUE : FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
	while (outBufferSize);
Packit 1fb8d4
Packit 1fb8d4
	if (cRawBytes || nRunLength)
Packit 1fb8d4
	{
Packit 1fb8d4
		pBytes = pInput - (cRawBytes + nRunLength);
Packit 1fb8d4
		nBytesWritten = freerdp_bitmap_planar_write_rle_bytes(pBytes,
Packit 1fb8d4
		                cRawBytes, nRunLength, pOutput, outBufferSize);
Packit 1fb8d4
Packit 1fb8d4
		if (!nBytesWritten)
Packit 1fb8d4
			return 0;
Packit 1fb8d4
Packit 1fb8d4
		nTotalBytesWritten += nBytesWritten;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (inBufferSize)
Packit 1fb8d4
		return 0;
Packit 1fb8d4
Packit 1fb8d4
	return nTotalBytesWritten;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
BOOL freerdp_bitmap_planar_compress_plane_rle(const BYTE* inPlane,
Packit 1fb8d4
        UINT32 width, UINT32 height,
Packit 1fb8d4
        BYTE* outPlane, UINT32* dstSize)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT32 index;
Packit 1fb8d4
	const BYTE* pInput;
Packit 1fb8d4
	BYTE* pOutput;
Packit 1fb8d4
	UINT32 outBufferSize;
Packit 1fb8d4
	UINT32 nBytesWritten;
Packit 1fb8d4
	UINT32 nTotalBytesWritten;
Packit 1fb8d4
Packit 1fb8d4
	if (!outPlane)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	index = 0;
Packit 1fb8d4
	pInput = inPlane;
Packit 1fb8d4
	pOutput = outPlane;
Packit 1fb8d4
	outBufferSize = *dstSize;
Packit 1fb8d4
	nTotalBytesWritten = 0;
Packit 1fb8d4
Packit 1fb8d4
	while (outBufferSize)
Packit 1fb8d4
	{
Packit 1fb8d4
		nBytesWritten = freerdp_bitmap_planar_encode_rle_bytes(
Packit 1fb8d4
		                    pInput, width, pOutput, outBufferSize);
Packit 1fb8d4
Packit 1fb8d4
		if ((!nBytesWritten) || (nBytesWritten > outBufferSize))
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
Packit 1fb8d4
		outBufferSize -= nBytesWritten;
Packit 1fb8d4
		nTotalBytesWritten += nBytesWritten;
Packit 1fb8d4
		pOutput += nBytesWritten;
Packit 1fb8d4
		pInput += width;
Packit 1fb8d4
		index++;
Packit 1fb8d4
Packit 1fb8d4
		if (index >= height)
Packit 1fb8d4
			break;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	*dstSize = nTotalBytesWritten;
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static INLINE BOOL freerdp_bitmap_planar_compress_planes_rle(
Packit 1fb8d4
    BYTE* inPlanes[4], UINT32 width, UINT32 height,
Packit 1fb8d4
    BYTE* outPlanes, UINT32* dstSizes, BOOL skipAlpha)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT32 outPlanesSize = width * height * 4;
Packit 1fb8d4
Packit 1fb8d4
	/* AlphaPlane */
Packit 1fb8d4
	if (skipAlpha)
Packit 1fb8d4
	{
Packit 1fb8d4
		dstSizes[0] = 0;
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		dstSizes[0] = outPlanesSize;
Packit 1fb8d4
Packit 1fb8d4
		if (!freerdp_bitmap_planar_compress_plane_rle(
Packit 1fb8d4
		        inPlanes[0], width, height, outPlanes, &dstSizes[0]))
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
Packit 1fb8d4
		outPlanes += dstSizes[0];
Packit 1fb8d4
		outPlanesSize -= dstSizes[0];
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	/* LumaOrRedPlane */
Packit 1fb8d4
	dstSizes[1] = outPlanesSize;
Packit 1fb8d4
Packit 1fb8d4
	if (!freerdp_bitmap_planar_compress_plane_rle(inPlanes[1], width, height,
Packit 1fb8d4
	        outPlanes, &dstSizes[1]))
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	outPlanes += dstSizes[1];
Packit 1fb8d4
	outPlanesSize -= dstSizes[1];
Packit 1fb8d4
	/* OrangeChromaOrGreenPlane */
Packit 1fb8d4
	dstSizes[2] = outPlanesSize;
Packit 1fb8d4
Packit 1fb8d4
	if (!freerdp_bitmap_planar_compress_plane_rle(inPlanes[2], width, height,
Packit 1fb8d4
	        outPlanes, &dstSizes[2]))
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	outPlanes += dstSizes[2];
Packit 1fb8d4
	outPlanesSize -= dstSizes[2];
Packit 1fb8d4
	/* GreenChromeOrBluePlane */
Packit 1fb8d4
	dstSizes[3] = outPlanesSize;
Packit 1fb8d4
Packit 1fb8d4
	if (!freerdp_bitmap_planar_compress_plane_rle(inPlanes[3], width, height,
Packit 1fb8d4
	        outPlanes, &dstSizes[3]))
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
BYTE* freerdp_bitmap_planar_delta_encode_plane(const BYTE* inPlane,
Packit 1fb8d4
        UINT32 width, UINT32 height,
Packit 1fb8d4
        BYTE* outPlane)
Packit 1fb8d4
{
Packit 1fb8d4
	char s2c;
Packit 1fb8d4
	INT32 delta;
Packit 1fb8d4
	UINT32 y, x;
Packit 1fb8d4
	BYTE* outPtr;
Packit 1fb8d4
	const BYTE* srcPtr, *prevLinePtr;
Packit 1fb8d4
Packit 1fb8d4
	if (!outPlane)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (width * height == 0)
Packit 1fb8d4
			return NULL;
Packit 1fb8d4
Packit 1fb8d4
		if (!(outPlane = (BYTE*) calloc(height, width)))
Packit 1fb8d4
			return NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	// first line is copied as is
Packit 1fb8d4
	CopyMemory(outPlane, inPlane, width);
Packit 1fb8d4
	outPtr = outPlane + width;
Packit 1fb8d4
	srcPtr = inPlane + width;
Packit 1fb8d4
	prevLinePtr = inPlane;
Packit 1fb8d4
Packit 1fb8d4
	for (y = 1; y < height; y++)
Packit 1fb8d4
	{
Packit 1fb8d4
		for (x = 0; x < width; x++, outPtr++, srcPtr++, prevLinePtr++)
Packit 1fb8d4
		{
Packit 1fb8d4
			delta = *srcPtr - *prevLinePtr;
Packit 1fb8d4
			s2c = (delta >= 0) ? (char) delta : (char)(~((BYTE)(-delta)) + 1);
Packit 1fb8d4
			s2c = (s2c >= 0) ? (s2c << 1) : (char)(((~((BYTE) s2c) + 1) << 1) - 1);
Packit 1fb8d4
			*outPtr = (BYTE)s2c;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return outPlane;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static INLINE BOOL freerdp_bitmap_planar_delta_encode_planes(BYTE* inPlanes[4],
Packit 1fb8d4
        UINT32 width, UINT32 height,
Packit 1fb8d4
        BYTE* outPlanes[4])
Packit 1fb8d4
{
Packit 1fb8d4
	UINT32 i;
Packit 1fb8d4
Packit 1fb8d4
	for (i = 0; i < 4; i++)
Packit 1fb8d4
	{
Packit 1fb8d4
		outPlanes[i] = freerdp_bitmap_planar_delta_encode_plane(
Packit 1fb8d4
		                   inPlanes[i], width, height, outPlanes[i]);
Packit 1fb8d4
Packit 1fb8d4
		if (!outPlanes[i])
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
BYTE* freerdp_bitmap_compress_planar(BITMAP_PLANAR_CONTEXT* context,
Packit 1fb8d4
                                     const BYTE* data, UINT32 format,
Packit 1fb8d4
                                     UINT32 width, UINT32 height, UINT32 scanline,
Packit 1fb8d4
                                     BYTE* dstData, UINT32* pDstSize)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT32 size;
Packit 1fb8d4
	BYTE* dstp;
Packit 1fb8d4
	UINT32 planeSize;
Packit 1fb8d4
	UINT32 dstSizes[4] = { 0 };
Packit 1fb8d4
	BYTE FormatHeader = 0;
Packit 1fb8d4
Packit 1fb8d4
	if (!context || !context->rlePlanesBuffer)
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
Packit 1fb8d4
	if (context->AllowSkipAlpha)
Packit 1fb8d4
		FormatHeader |= PLANAR_FORMAT_HEADER_NA;
Packit 1fb8d4
Packit 1fb8d4
	planeSize = width * height;
Packit 1fb8d4
Packit 1fb8d4
	if (!freerdp_split_color_planes(data, format, width, height, scanline,
Packit 1fb8d4
	                                context->planes))
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
Packit 1fb8d4
	if (context->AllowRunLengthEncoding)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (!freerdp_bitmap_planar_delta_encode_planes(
Packit 1fb8d4
		        context->planes, width, height,
Packit 1fb8d4
		        context->deltaPlanes))
Packit 1fb8d4
			return NULL;
Packit 1fb8d4
Packit 1fb8d4
		if (!freerdp_bitmap_planar_compress_planes_rle(
Packit 1fb8d4
		        context->deltaPlanes, width, height,
Packit 1fb8d4
		        context->rlePlanesBuffer, dstSizes,
Packit 1fb8d4
		        context->AllowSkipAlpha))
Packit 1fb8d4
			return NULL;
Packit 1fb8d4
Packit 1fb8d4
		{
Packit 1fb8d4
			int offset = 0;
Packit 1fb8d4
			FormatHeader |= PLANAR_FORMAT_HEADER_RLE;
Packit 1fb8d4
			context->rlePlanes[0] = &context->rlePlanesBuffer[offset];
Packit 1fb8d4
			offset += dstSizes[0];
Packit 1fb8d4
			context->rlePlanes[1] = &context->rlePlanesBuffer[offset];
Packit 1fb8d4
			offset += dstSizes[1];
Packit 1fb8d4
			context->rlePlanes[2] = &context->rlePlanesBuffer[offset];
Packit 1fb8d4
			offset += dstSizes[2];
Packit 1fb8d4
			context->rlePlanes[3] = &context->rlePlanesBuffer[offset];
Packit 1fb8d4
			//WLog_DBG(TAG, "R: [%"PRIu32"/%"PRIu32"] G: [%"PRIu32"/%"PRIu32"] B: [%"PRIu32"/%"PRIu32"]",
Packit 1fb8d4
			//		dstSizes[1], planeSize, dstSizes[2], planeSize, dstSizes[3], planeSize);
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (FormatHeader & PLANAR_FORMAT_HEADER_RLE)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (!context->AllowRunLengthEncoding)
Packit 1fb8d4
			return NULL;
Packit 1fb8d4
Packit 1fb8d4
		if (context->rlePlanes[0] == NULL)
Packit 1fb8d4
			return NULL;
Packit 1fb8d4
Packit 1fb8d4
		if (context->rlePlanes[1] == NULL)
Packit 1fb8d4
			return NULL;
Packit 1fb8d4
Packit 1fb8d4
		if (context->rlePlanes[2] == NULL)
Packit 1fb8d4
			return NULL;
Packit 1fb8d4
Packit 1fb8d4
		if (context->rlePlanes[3] == NULL)
Packit 1fb8d4
			return NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (!dstData)
Packit 1fb8d4
	{
Packit 1fb8d4
		size = 1;
Packit 1fb8d4
Packit 1fb8d4
		if (!(FormatHeader & PLANAR_FORMAT_HEADER_NA))
Packit 1fb8d4
		{
Packit 1fb8d4
			if (FormatHeader & PLANAR_FORMAT_HEADER_RLE)
Packit 1fb8d4
				size += dstSizes[0];
Packit 1fb8d4
			else
Packit 1fb8d4
				size += planeSize;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		if (FormatHeader & PLANAR_FORMAT_HEADER_RLE)
Packit 1fb8d4
			size += (dstSizes[1] + dstSizes[2] + dstSizes[3]);
Packit 1fb8d4
		else
Packit 1fb8d4
			size += (planeSize * 3);
Packit 1fb8d4
Packit 1fb8d4
		if (!(FormatHeader & PLANAR_FORMAT_HEADER_RLE))
Packit 1fb8d4
			size++;
Packit 1fb8d4
Packit 1fb8d4
		dstData = malloc(size);
Packit 1fb8d4
Packit 1fb8d4
		if (!dstData)
Packit 1fb8d4
			return NULL;
Packit 1fb8d4
Packit 1fb8d4
		*pDstSize = size;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	dstp = dstData;
Packit 1fb8d4
	*dstp = FormatHeader; /* FormatHeader */
Packit 1fb8d4
	dstp++;
Packit 1fb8d4
Packit 1fb8d4
	/* AlphaPlane */
Packit 1fb8d4
Packit 1fb8d4
	if (!(FormatHeader & PLANAR_FORMAT_HEADER_NA))
Packit 1fb8d4
	{
Packit 1fb8d4
		if (FormatHeader & PLANAR_FORMAT_HEADER_RLE)
Packit 1fb8d4
		{
Packit 1fb8d4
			CopyMemory(dstp, context->rlePlanes[0], dstSizes[0]); /* Alpha */
Packit 1fb8d4
			dstp += dstSizes[0];
Packit 1fb8d4
		}
Packit 1fb8d4
		else
Packit 1fb8d4
		{
Packit 1fb8d4
			CopyMemory(dstp, context->planes[0], planeSize); /* Alpha */
Packit 1fb8d4
			dstp += planeSize;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	/* LumaOrRedPlane */
Packit 1fb8d4
Packit 1fb8d4
	if (FormatHeader & PLANAR_FORMAT_HEADER_RLE)
Packit 1fb8d4
	{
Packit 1fb8d4
		CopyMemory(dstp, context->rlePlanes[1], dstSizes[1]); /* Red */
Packit 1fb8d4
		dstp += dstSizes[1];
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		CopyMemory(dstp, context->planes[1], planeSize); /* Red */
Packit 1fb8d4
		dstp += planeSize;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	/* OrangeChromaOrGreenPlane */
Packit 1fb8d4
Packit 1fb8d4
	if (FormatHeader & PLANAR_FORMAT_HEADER_RLE)
Packit 1fb8d4
	{
Packit 1fb8d4
		CopyMemory(dstp, context->rlePlanes[2], dstSizes[2]); /* Green */
Packit 1fb8d4
		dstp += dstSizes[2];
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		CopyMemory(dstp, context->planes[2], planeSize); /* Green */
Packit 1fb8d4
		dstp += planeSize;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	/* GreenChromeOrBluePlane */
Packit 1fb8d4
Packit 1fb8d4
	if (FormatHeader & PLANAR_FORMAT_HEADER_RLE)
Packit 1fb8d4
	{
Packit 1fb8d4
		CopyMemory(dstp, context->rlePlanes[3], dstSizes[3]); /* Blue */
Packit 1fb8d4
		dstp += dstSizes[3];
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		CopyMemory(dstp, context->planes[3], planeSize); /* Blue */
Packit 1fb8d4
		dstp += planeSize;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	/* Pad1 (1 byte) */
Packit 1fb8d4
Packit 1fb8d4
	if (!(FormatHeader & PLANAR_FORMAT_HEADER_RLE))
Packit 1fb8d4
	{
Packit 1fb8d4
		*dstp = 0;
Packit 1fb8d4
		dstp++;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	size = (dstp - dstData);
Packit 1fb8d4
	*pDstSize = size;
Packit 1fb8d4
	return dstData;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
BOOL freerdp_bitmap_planar_context_reset(
Packit 1fb8d4
    BITMAP_PLANAR_CONTEXT* context, UINT32 width, UINT32 height)
Packit 1fb8d4
{
Packit 1fb8d4
	if (!context)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	context->maxWidth = width;
Packit 1fb8d4
	context->maxHeight = height;
Packit 1fb8d4
	context->maxPlaneSize = context->maxWidth * context->maxHeight;
Packit 1fb8d4
	context->nTempStep = context->maxWidth * 4;
Packit 1fb8d4
	free(context->planesBuffer);
Packit 1fb8d4
	free(context->pTempData);
Packit 1fb8d4
	free(context->deltaPlanesBuffer);
Packit 1fb8d4
	free(context->rlePlanesBuffer);
Packit 1fb8d4
	context->planesBuffer = calloc(context->maxPlaneSize, 4);
Packit 1fb8d4
	context->pTempData = calloc(context->maxPlaneSize, 4);
Packit 1fb8d4
	context->deltaPlanesBuffer = calloc(context->maxPlaneSize, 4);
Packit 1fb8d4
	context->rlePlanesBuffer = calloc(context->maxPlaneSize, 4);
Packit 1fb8d4
Packit 1fb8d4
	if (!context->planesBuffer || !context->pTempData ||
Packit 1fb8d4
	    !context->deltaPlanesBuffer || !context->rlePlanesBuffer)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	context->planes[0] = &context->planesBuffer[context->maxPlaneSize * 0];
Packit 1fb8d4
	context->planes[1] = &context->planesBuffer[context->maxPlaneSize * 1];
Packit 1fb8d4
	context->planes[2] = &context->planesBuffer[context->maxPlaneSize * 2];
Packit 1fb8d4
	context->planes[3] = &context->planesBuffer[context->maxPlaneSize * 3];
Packit 1fb8d4
	context->deltaPlanes[0] = &context->deltaPlanesBuffer[context->maxPlaneSize *
Packit 1fb8d4
	                          0];
Packit 1fb8d4
	context->deltaPlanes[1] = &context->deltaPlanesBuffer[context->maxPlaneSize *
Packit 1fb8d4
	                          1];
Packit 1fb8d4
	context->deltaPlanes[2] = &context->deltaPlanesBuffer[context->maxPlaneSize *
Packit 1fb8d4
	                          2];
Packit 1fb8d4
	context->deltaPlanes[3] = &context->deltaPlanesBuffer[context->maxPlaneSize *
Packit 1fb8d4
	                          3];
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
BITMAP_PLANAR_CONTEXT* freerdp_bitmap_planar_context_new(
Packit 1fb8d4
    DWORD flags, UINT32 maxWidth, UINT32 maxHeight)
Packit 1fb8d4
{
Packit 1fb8d4
	BITMAP_PLANAR_CONTEXT* context;
Packit 1fb8d4
	context = (BITMAP_PLANAR_CONTEXT*) calloc(1, sizeof(BITMAP_PLANAR_CONTEXT));
Packit 1fb8d4
Packit 1fb8d4
	if (!context)
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
Packit 1fb8d4
	if (flags & PLANAR_FORMAT_HEADER_NA)
Packit 1fb8d4
		context->AllowSkipAlpha = TRUE;
Packit 1fb8d4
Packit 1fb8d4
	if (flags & PLANAR_FORMAT_HEADER_RLE)
Packit 1fb8d4
		context->AllowRunLengthEncoding = TRUE;
Packit 1fb8d4
Packit 1fb8d4
	if (flags & PLANAR_FORMAT_HEADER_CS)
Packit 1fb8d4
		context->AllowColorSubsampling = TRUE;
Packit 1fb8d4
Packit 1fb8d4
	context->ColorLossLevel = flags & PLANAR_FORMAT_HEADER_CLL_MASK;
Packit 1fb8d4
Packit 1fb8d4
	if (context->ColorLossLevel)
Packit 1fb8d4
		context->AllowDynamicColorFidelity = TRUE;
Packit 1fb8d4
Packit 1fb8d4
	if (!freerdp_bitmap_planar_context_reset(context, maxWidth, maxHeight))
Packit 1fb8d4
	{
Packit 1fb8d4
		freerdp_bitmap_planar_context_free(context);
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return context;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
void freerdp_bitmap_planar_context_free(BITMAP_PLANAR_CONTEXT* context)
Packit 1fb8d4
{
Packit 1fb8d4
	if (!context)
Packit 1fb8d4
		return;
Packit 1fb8d4
Packit 1fb8d4
	free(context->pTempData);
Packit 1fb8d4
	free(context->planesBuffer);
Packit 1fb8d4
	free(context->deltaPlanesBuffer);
Packit 1fb8d4
	free(context->rlePlanesBuffer);
Packit 1fb8d4
	free(context);
Packit 1fb8d4
}