Milestone 5: deliver embedded RDP sessions and lifecycle hardening

This commit is contained in:
Keith Smith
2026-03-03 18:59:26 -07:00
parent 230a401386
commit 36006bd4aa
2941 changed files with 724359 additions and 77 deletions
+142
View File
@@ -0,0 +1,142 @@
# codec
option(WITH_CURSOR_DUMP "Dump mouse cursor data to binary directory" OFF)
if(WITH_CURSOR_DUMP)
add_compile_definitions(WITH_CURSOR_DUMP)
add_compile_definitions(CURSOR_DUMP_DIR="${CMAKE_CURRENT_BINARY_DIR}")
endif()
set(CODEC_SRCS
bulk.c
bulk.h
dsp.c
color.c
color.h
audio.c
planar.c
bitmap.c
interleaved.c
progressive.c
rfx_bitstream.h
rfx_constants.h
rfx_decode.c
rfx_decode.h
rfx_differential.h
rfx_dwt.c
rfx_dwt.h
rfx_encode.c
rfx_encode.h
rfx_quantization.c
rfx_quantization.h
rfx_rlgr.c
rfx_rlgr.h
rfx_types.h
rfx.c
region.c
nsc.c
nsc_encode.c
nsc_encode.h
nsc_types.h
ncrush.c
xcrush.c
mppc.c
zgfx.c
clear.c
jpeg.c
h264.c
yuv.c
)
set(CODEC_SSE3_SRCS sse/rfx_sse2.c sse/rfx_sse2.h sse/nsc_sse2.c sse/nsc_sse2.h)
set(CODEC_NEON_SRCS neon/rfx_neon.c neon/rfx_neon.h neon/nsc_neon.c neon/nsc_neon.h)
# Append initializers
set(CODEC_LIBS "")
list(APPEND CODEC_SRCS ${CODEC_SSE3_SRCS})
list(APPEND CODEC_SRCS ${CODEC_NEON_SRCS})
include(CompilerDetect)
include(DetectIntrinsicSupport)
if(WITH_SIMD)
set_simd_source_file_properties("sse3" ${CODEC_SSE3_SRCS})
set_simd_source_file_properties("neon" ${CODEC_NEON_SRCS})
endif()
if(WITH_DSP_FFMPEG)
set(CODEC_SRCS ${CODEC_SRCS} dsp_ffmpeg.c dsp_ffmpeg.h)
include_directories(SYSTEM ${FFMPEG_INCLUDE_DIRS})
list(APPEND CODEC_LIBS ${FFMPEG_LIBRARIES})
freerdp_pc_add_requires_private("libavfilter;libavformat;libavcodec;libavutil;libswresample")
endif(WITH_DSP_FFMPEG)
if(WITH_SOXR)
list(APPEND CODEC_LIBS ${SOXR_LIBRARIES})
include_directories(SYSTEM ${SOXR_INCLUDE_DIR})
freerdp_pc_add_requires_private("soxr")
endif(WITH_SOXR)
if(GSM_FOUND)
list(APPEND CODEC_LIBS ${GSM_LIBRARIES})
include_directories(SYSTEM ${GSM_INCLUDE_DIRS})
freerdp_pc_add_library_private("gsm")
endif()
if(LAME_FOUND)
list(APPEND CODEC_LIBS ${LAME_LIBRARIES})
include_directories(SYSTEM ${LAME_INCLUDE_DIRS})
freerdp_pc_add_requires_private("lame")
endif()
if(WITH_FDK_AAC)
list(APPEND CODEC_SRCS dsp_fdk_impl.c dsp_fdk_impl.h dsp_fdk_aac.c dsp_fdk_aac.h)
freerdp_pc_add_requires_private("fdk-aac")
endif()
if(FAAD2_FOUND)
list(APPEND CODEC_LIBS ${FAAD2_LIBRARIES})
include_directories(SYSTEM ${FAAD2_INCLUDE_DIRS})
freerdp_pc_add_requires_private("faad2")
endif()
if(FAAC_FOUND)
list(APPEND CODEC_LIBS ${FAAC_LIBRARIES})
include_directories(SYSTEM ${FAAC_INCLUDE_DIRS})
freerdp_pc_add_requires_private("faac")
endif()
if(WITH_OPENH264)
set(CODEC_SRCS ${CODEC_SRCS} h264_openh264.c)
include_directories(SYSTEM ${OPENH264_INCLUDE_DIR})
if(NOT WITH_OPENH264_LOADING)
list(APPEND CODEC_LIBS ${OPENH264_LIBRARIES})
freerdp_pc_add_requires_private("openh264")
endif(NOT WITH_OPENH264_LOADING)
endif()
if(WITH_VIDEO_FFMPEG)
set(CODEC_SRCS ${CODEC_SRCS} h264_ffmpeg.c)
include_directories(SYSTEM ${FFMPEG_INCLUDE_DIRS})
list(APPEND CODEC_LIBS ${FFMPEG_LIBRARIES})
freerdp_pc_add_requires_private("libavfilter;libavformat;libavcodec;libavutil")
endif()
if(WIN32 AND WITH_MEDIA_FOUNDATION)
set(CODEC_SRCS ${CODEC_SRCS} h264_mf.c)
endif()
if(ANDROID AND WITH_MEDIACODEC)
list(APPEND CODEC_SRCS h264_mediacodec.c)
find_library(MEDIACODEC mediandk REQUIRED)
list(APPEND CODEC_LIBS ${MEDIACODEC})
endif()
add_library(freerdp-codecs OBJECT ${CODEC_SRCS})
freerdp_library_add(${CODEC_LIBS})
freerdp_object_library_add(freerdp-codecs)
if(BUILD_TESTING_INTERNAL OR BUILD_TESTING)
add_subdirectory(test)
endif()
+285
View File
@@ -0,0 +1,285 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Audio Formats
*
* Copyright 2013 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* 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 <freerdp/config.h>
#include <winpr/crt.h>
#include <freerdp/log.h>
#include <freerdp/codec/audio.h>
#define TAG FREERDP_TAG("codec")
UINT32 audio_format_compute_time_length(const AUDIO_FORMAT* format, size_t size)
{
UINT32 mstime = 0;
UINT32 wSamples = 0;
/**
* [MSDN-AUDIOFORMAT]:
* http://msdn.microsoft.com/en-us/library/ms713497.aspx
*/
if (format->wBitsPerSample)
{
const size_t samples = (size * 8) / format->wBitsPerSample;
WINPR_ASSERT(samples <= UINT32_MAX);
wSamples = (UINT32)samples;
mstime = (((wSamples * 1000) / format->nSamplesPerSec) / format->nChannels);
}
else
{
mstime = 0;
if (format->wFormatTag == WAVE_FORMAT_GSM610)
{
UINT16 nSamplesPerBlock = 0;
if ((format->cbSize == 2) && (format->data))
{
nSamplesPerBlock = *((UINT16*)format->data);
const size_t samples = (size / format->nBlockAlign) * nSamplesPerBlock;
WINPR_ASSERT(samples <= UINT32_MAX);
wSamples = (UINT32)samples;
mstime = (((wSamples * 1000) / format->nSamplesPerSec) / format->nChannels);
}
else
{
WLog_ERR(TAG,
"audio_format_compute_time_length: invalid WAVE_FORMAT_GSM610 format");
}
}
else
{
WLog_ERR(TAG, "audio_format_compute_time_length: unknown format %" PRIu16 "",
format->wFormatTag);
}
}
return mstime;
}
const char* audio_format_get_tag_string(UINT16 wFormatTag)
{
switch (wFormatTag)
{
case WAVE_FORMAT_PCM:
return "WAVE_FORMAT_PCM";
case WAVE_FORMAT_ADPCM:
return "WAVE_FORMAT_ADPCM";
case WAVE_FORMAT_ALAW:
return "WAVE_FORMAT_ALAW";
case WAVE_FORMAT_MULAW:
return "WAVE_FORMAT_MULAW";
case WAVE_FORMAT_DVI_ADPCM:
return "WAVE_FORMAT_DVI_ADPCM";
case WAVE_FORMAT_GSM610:
return "WAVE_FORMAT_GSM610";
case WAVE_FORMAT_MSG723:
return "WAVE_FORMAT_MSG723";
case WAVE_FORMAT_DSPGROUP_TRUESPEECH:
return "WAVE_FORMAT_DSPGROUP_TRUESPEECH ";
case WAVE_FORMAT_MPEGLAYER3:
return "WAVE_FORMAT_MPEGLAYER3";
case WAVE_FORMAT_WMAUDIO2:
return "WAVE_FORMAT_WMAUDIO2";
case WAVE_FORMAT_AAC_MS:
return "WAVE_FORMAT_AAC_MS";
default:
return "WAVE_FORMAT_UNKNOWN";
}
}
void audio_format_print(wLog* log, DWORD level, const AUDIO_FORMAT* format)
{
WLog_Print(log, level,
"%s:\t wFormatTag: 0x%04" PRIX16 " nChannels: %" PRIu16 " nSamplesPerSec: %" PRIu32
" "
"nAvgBytesPerSec: %" PRIu32 " nBlockAlign: %" PRIu16 " wBitsPerSample: %" PRIu16
" cbSize: %" PRIu16 "",
audio_format_get_tag_string(format->wFormatTag), format->wFormatTag,
format->nChannels, format->nSamplesPerSec, format->nAvgBytesPerSec,
format->nBlockAlign, format->wBitsPerSample, format->cbSize);
}
void audio_formats_print(wLog* log, DWORD level, const AUDIO_FORMAT* formats, UINT16 count)
{
if (formats)
{
WLog_Print(log, level, "AUDIO_FORMATS (%" PRIu16 ") ={", count);
for (UINT32 index = 0; index < count; index++)
{
const AUDIO_FORMAT* format = &formats[index];
WLog_Print(log, level, "\t");
audio_format_print(log, level, format);
}
WLog_Print(log, level, "}");
}
}
BOOL audio_format_read(wStream* s, AUDIO_FORMAT* format)
{
if (!s || !format)
return FALSE;
if (!Stream_CheckAndLogRequiredLength(TAG, s, 18))
return FALSE;
Stream_Read_UINT16(s, format->wFormatTag);
Stream_Read_UINT16(s, format->nChannels);
Stream_Read_UINT32(s, format->nSamplesPerSec);
Stream_Read_UINT32(s, format->nAvgBytesPerSec);
Stream_Read_UINT16(s, format->nBlockAlign);
Stream_Read_UINT16(s, format->wBitsPerSample);
Stream_Read_UINT16(s, format->cbSize);
if (!Stream_CheckAndLogRequiredLength(TAG, s, format->cbSize))
return FALSE;
format->data = nullptr;
if (format->cbSize > 0)
{
format->data = malloc(format->cbSize);
if (!format->data)
return FALSE;
Stream_Read(s, format->data, format->cbSize);
}
return TRUE;
}
BOOL audio_format_write(wStream* s, const AUDIO_FORMAT* format)
{
if (!s || !format)
return FALSE;
if (!Stream_EnsureRemainingCapacity(s, 18 + format->cbSize))
return FALSE;
Stream_Write_UINT16(s, format->wFormatTag); /* wFormatTag (WAVE_FORMAT_PCM) */
Stream_Write_UINT16(s, format->nChannels); /* nChannels */
Stream_Write_UINT32(s, format->nSamplesPerSec); /* nSamplesPerSec */
Stream_Write_UINT32(s, format->nAvgBytesPerSec); /* nAvgBytesPerSec */
Stream_Write_UINT16(s, format->nBlockAlign); /* nBlockAlign */
Stream_Write_UINT16(s, format->wBitsPerSample); /* wBitsPerSample */
Stream_Write_UINT16(s, format->cbSize); /* cbSize */
if (format->cbSize > 0)
Stream_Write(s, format->data, format->cbSize);
return TRUE;
}
BOOL audio_format_copy(const AUDIO_FORMAT* WINPR_RESTRICT srcFormat,
AUDIO_FORMAT* WINPR_RESTRICT dstFormat)
{
if (!srcFormat || !dstFormat)
return FALSE;
*dstFormat = *srcFormat;
if (srcFormat->cbSize > 0)
{
dstFormat->data = malloc(srcFormat->cbSize);
if (!dstFormat->data)
return FALSE;
memcpy(dstFormat->data, srcFormat->data, dstFormat->cbSize);
}
return TRUE;
}
BOOL audio_format_compatible(const AUDIO_FORMAT* with, const AUDIO_FORMAT* what)
{
if (!with || !what)
return FALSE;
if (with->wFormatTag != WAVE_FORMAT_UNKNOWN)
{
if (with->wFormatTag != what->wFormatTag)
return FALSE;
}
if (with->nChannels != 0)
{
if (with->nChannels != what->nChannels)
return FALSE;
}
if (with->nSamplesPerSec != 0)
{
if (with->nSamplesPerSec != what->nSamplesPerSec)
return FALSE;
}
if (with->wBitsPerSample != 0)
{
if (with->wBitsPerSample != what->wBitsPerSample)
return FALSE;
}
return TRUE;
}
AUDIO_FORMAT* audio_format_new(void)
{
return audio_formats_new(1);
}
AUDIO_FORMAT* audio_formats_new(size_t count)
{
return calloc(count, sizeof(AUDIO_FORMAT));
}
void audio_format_free(AUDIO_FORMAT* format)
{
if (format)
free(format->data);
}
void audio_formats_free(AUDIO_FORMAT* formats, size_t count)
{
if (formats)
{
for (size_t index = 0; index < count; index++)
{
AUDIO_FORMAT* format = &formats[index];
audio_format_free(format);
}
free(formats);
}
}
File diff suppressed because it is too large Load Diff
+391
View File
@@ -0,0 +1,391 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Bulk Compression
*
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* 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 <math.h>
#include <winpr/assert.h>
#include <freerdp/config.h>
#include "../core/settings.h"
#include "bulk.h"
#include "../codec/mppc.h"
#include "../codec/ncrush.h"
#include "../codec/xcrush.h"
#include <freerdp/log.h>
#define TAG FREERDP_TAG("core")
//#define WITH_BULK_DEBUG 1
struct rdp_bulk
{
ALIGN64 rdpContext* context;
ALIGN64 UINT32 CompressionLevel;
ALIGN64 UINT16 CompressionMaxSize;
ALIGN64 MPPC_CONTEXT* mppcSend;
ALIGN64 MPPC_CONTEXT* mppcRecv;
ALIGN64 NCRUSH_CONTEXT* ncrushRecv;
ALIGN64 NCRUSH_CONTEXT* ncrushSend;
ALIGN64 XCRUSH_CONTEXT* xcrushRecv;
ALIGN64 XCRUSH_CONTEXT* xcrushSend;
ALIGN64 BYTE OutputBuffer[65536];
};
#if defined(WITH_BULK_DEBUG)
static inline const char* bulk_get_compression_flags_string(UINT32 flags)
{
flags &= BULK_COMPRESSION_FLAGS_MASK;
if (flags == 0)
return "PACKET_UNCOMPRESSED";
else if (flags == PACKET_COMPRESSED)
return "PACKET_COMPRESSED";
else if (flags == PACKET_AT_FRONT)
return "PACKET_AT_FRONT";
else if (flags == PACKET_FLUSHED)
return "PACKET_FLUSHED";
else if (flags == (PACKET_COMPRESSED | PACKET_AT_FRONT))
return "PACKET_COMPRESSED | PACKET_AT_FRONT";
else if (flags == (PACKET_COMPRESSED | PACKET_FLUSHED))
return "PACKET_COMPRESSED | PACKET_FLUSHED";
else if (flags == (PACKET_AT_FRONT | PACKET_FLUSHED))
return "PACKET_AT_FRONT | PACKET_FLUSHED";
else if (flags == (PACKET_COMPRESSED | PACKET_AT_FRONT | PACKET_FLUSHED))
return "PACKET_COMPRESSED | PACKET_AT_FRONT | PACKET_FLUSHED";
return "PACKET_UNKNOWN";
}
#endif
WINPR_ATTR_NODISCARD
static UINT32 bulk_compression_level(rdpBulk* WINPR_RESTRICT bulk)
{
WINPR_ASSERT(bulk);
WINPR_ASSERT(bulk->context);
const rdpSettings* settings = bulk->context->settings;
WINPR_ASSERT(settings);
bulk->CompressionLevel = (settings->CompressionLevel >= PACKET_COMPR_TYPE_RDP61)
? PACKET_COMPR_TYPE_RDP61
: settings->CompressionLevel;
WINPR_ASSERT(bulk->CompressionLevel <= UINT16_MAX);
return bulk->CompressionLevel;
}
static void bulk_update_compression_max_size(rdpBulk* WINPR_RESTRICT bulk)
{
WINPR_ASSERT(bulk);
const UINT32 CompressionLevel = bulk_compression_level(bulk);
bulk->CompressionMaxSize = (CompressionLevel < PACKET_COMPR_TYPE_64K) ? 8192 : UINT16_MAX;
}
UINT16 bulk_compression_max_size(rdpBulk* WINPR_RESTRICT bulk)
{
bulk_update_compression_max_size(bulk);
return bulk->CompressionMaxSize;
}
#if defined(WITH_BULK_DEBUG)
static inline int bulk_compress_validate(rdpBulk* bulk, const BYTE* pSrcData, UINT32 SrcSize,
const BYTE* pDstData, UINT32 DstSize, UINT32 Flags)
{
int status;
const BYTE* v_pSrcData = nullptr;
const BYTE* v_pDstData = nullptr;
UINT32 v_SrcSize = 0;
UINT32 v_DstSize = 0;
UINT32 v_Flags = 0;
WINPR_ASSERT(bulk);
WINPR_ASSERT(pSrcData);
WINPR_ASSERT(pDstData);
v_pSrcData = pDstData;
v_SrcSize = DstSize;
v_Flags = Flags | bulk->CompressionLevel;
status = bulk_decompress(bulk, v_pSrcData, v_SrcSize, &v_pDstData, &v_DstSize, v_Flags);
if (status < 0)
{
WLog_DBG(TAG, "compression/decompression failure");
return status;
}
if (v_DstSize != SrcSize)
{
WLog_DBG(TAG,
"compression/decompression size mismatch: Actual: %" PRIu32 ", Expected: %" PRIu32
"",
v_DstSize, SrcSize);
return -1;
}
if (memcmp(v_pDstData, pSrcData, SrcSize) != 0)
{
WLog_DBG(TAG, "compression/decompression input/output mismatch! flags: 0x%08" PRIX32 "",
v_Flags);
#if 1
WLog_DBG(TAG, "Actual:");
winpr_HexDump(TAG, WLOG_DEBUG, v_pDstData, SrcSize);
WLog_DBG(TAG, "Expected:");
winpr_HexDump(TAG, WLOG_DEBUG, pSrcData, SrcSize);
#endif
return -1;
}
return status;
}
#endif
int bulk_decompress(rdpBulk* WINPR_RESTRICT bulk, const BYTE* WINPR_RESTRICT pSrcData,
UINT32 SrcSize, const BYTE** WINPR_RESTRICT ppDstData,
UINT32* WINPR_RESTRICT pDstSize, UINT32 flags)
{
int status = -1;
WINPR_ASSERT(bulk);
WINPR_ASSERT(bulk->context);
WINPR_ASSERT(pSrcData);
WINPR_ASSERT(ppDstData);
WINPR_ASSERT(pDstSize);
rdpMetrics* metrics = bulk->context->metrics;
WINPR_ASSERT(metrics);
bulk_update_compression_max_size(bulk);
const UINT32 type = flags & BULK_COMPRESSION_TYPE_MASK;
if (flags & BULK_COMPRESSION_FLAGS_MASK)
{
switch (type)
{
case PACKET_COMPR_TYPE_8K:
mppc_set_compression_level(bulk->mppcRecv, 0);
status =
mppc_decompress(bulk->mppcRecv, pSrcData, SrcSize, ppDstData, pDstSize, flags);
break;
case PACKET_COMPR_TYPE_64K:
mppc_set_compression_level(bulk->mppcRecv, 1);
status =
mppc_decompress(bulk->mppcRecv, pSrcData, SrcSize, ppDstData, pDstSize, flags);
break;
case PACKET_COMPR_TYPE_RDP6:
status = ncrush_decompress(bulk->ncrushRecv, pSrcData, SrcSize, ppDstData, pDstSize,
flags);
break;
case PACKET_COMPR_TYPE_RDP61:
status = xcrush_decompress(bulk->xcrushRecv, pSrcData, SrcSize, ppDstData, pDstSize,
flags);
break;
case PACKET_COMPR_TYPE_RDP8:
WLog_ERR(TAG, "Unsupported bulk compression type %08" PRIx32,
bulk->CompressionLevel);
status = -1;
break;
default:
WLog_ERR(TAG, "Unknown bulk compression type %08" PRIx32, bulk->CompressionLevel);
status = -1;
break;
}
}
else
{
*ppDstData = pSrcData;
*pDstSize = SrcSize;
status = 0;
}
if (status >= 0)
{
const UINT32 CompressedBytes = SrcSize;
const UINT32 UncompressedBytes = *pDstSize;
const double CompressionRatio =
metrics_write_bytes(metrics, UncompressedBytes, CompressedBytes);
#ifdef WITH_BULK_DEBUG
{
WLog_DBG(TAG,
"Decompress Type: %" PRIu32 " Flags: %s (0x%08" PRIX32
") Compression Ratio: %f (%" PRIu32 " / %" PRIu32 "), Total: %f (%" PRIu64
" / %" PRIu64 ")",
type, bulk_get_compression_flags_string(flags), flags, CompressionRatio,
CompressedBytes, UncompressedBytes, metrics->TotalCompressionRatio,
metrics->TotalCompressedBytes, metrics->TotalUncompressedBytes);
}
#else
WINPR_UNUSED(CompressionRatio);
#endif
}
else
{
WLog_ERR(TAG, "Decompression failure!");
}
return status;
}
int bulk_compress(rdpBulk* WINPR_RESTRICT bulk, const BYTE* WINPR_RESTRICT pSrcData, UINT32 SrcSize,
const BYTE** WINPR_RESTRICT ppDstData, UINT32* WINPR_RESTRICT pDstSize,
UINT32* WINPR_RESTRICT pFlags)
{
int status = -1;
WINPR_ASSERT(bulk);
WINPR_ASSERT(bulk->context);
WINPR_ASSERT(pSrcData);
WINPR_ASSERT(ppDstData);
WINPR_ASSERT(pDstSize);
rdpMetrics* metrics = bulk->context->metrics;
WINPR_ASSERT(metrics);
if ((SrcSize <= 50) || (SrcSize >= 16384))
{
*ppDstData = pSrcData;
*pDstSize = SrcSize;
return 0;
}
*pDstSize = sizeof(bulk->OutputBuffer);
const UINT32 CompressionLevel = bulk_compression_level(bulk);
bulk_update_compression_max_size(bulk);
switch (CompressionLevel)
{
case PACKET_COMPR_TYPE_8K:
case PACKET_COMPR_TYPE_64K:
mppc_set_compression_level(bulk->mppcSend, CompressionLevel);
status = mppc_compress(bulk->mppcSend, pSrcData, SrcSize, bulk->OutputBuffer, ppDstData,
pDstSize, pFlags);
break;
case PACKET_COMPR_TYPE_RDP6:
status = ncrush_compress(bulk->ncrushSend, pSrcData, SrcSize, bulk->OutputBuffer,
ppDstData, pDstSize, pFlags);
break;
case PACKET_COMPR_TYPE_RDP61:
status = xcrush_compress(bulk->xcrushSend, pSrcData, SrcSize, bulk->OutputBuffer,
ppDstData, pDstSize, pFlags);
break;
case PACKET_COMPR_TYPE_RDP8:
WLog_ERR(TAG, "Unsupported bulk compression type %08" PRIx32, CompressionLevel);
status = -1;
break;
default:
WLog_ERR(TAG, "Unknown bulk compression type %08" PRIx32, CompressionLevel);
status = -1;
break;
}
if (status >= 0)
{
const UINT32 CompressedBytes = *pDstSize;
const UINT32 UncompressedBytes = SrcSize;
const double CompressionRatio =
metrics_write_bytes(metrics, UncompressedBytes, CompressedBytes);
#ifdef WITH_BULK_DEBUG
{
WLog_DBG(TAG,
"Compress Type: %" PRIu32 " Flags: %s (0x%08" PRIX32
") Compression Ratio: %f (%" PRIu32 " / %" PRIu32 "), Total: %f (%" PRIu64
" / %" PRIu64 ")",
bulk->CompressionLevel, bulk_get_compression_flags_string(*pFlags), *pFlags,
CompressionRatio, CompressedBytes, UncompressedBytes,
metrics->TotalCompressionRatio, metrics->TotalCompressedBytes,
metrics->TotalUncompressedBytes);
}
#else
WINPR_UNUSED(CompressionRatio);
#endif
}
#if defined(WITH_BULK_DEBUG)
if (bulk_compress_validate(bulk, pSrcData, SrcSize, *ppDstData, *pDstSize, *pFlags) < 0)
status = -1;
#endif
return status;
}
void bulk_reset(rdpBulk* WINPR_RESTRICT bulk)
{
WINPR_ASSERT(bulk);
mppc_context_reset(bulk->mppcSend, FALSE);
mppc_context_reset(bulk->mppcRecv, FALSE);
ncrush_context_reset(bulk->ncrushRecv, FALSE);
ncrush_context_reset(bulk->ncrushSend, FALSE);
xcrush_context_reset(bulk->xcrushRecv, FALSE);
xcrush_context_reset(bulk->xcrushSend, FALSE);
}
rdpBulk* bulk_new(rdpContext* context)
{
rdpBulk* bulk = nullptr;
WINPR_ASSERT(context);
bulk = (rdpBulk*)calloc(1, sizeof(rdpBulk));
if (!bulk)
goto fail;
bulk->context = context;
bulk->mppcSend = mppc_context_new(1, TRUE);
if (!bulk->mppcSend)
goto fail;
bulk->mppcRecv = mppc_context_new(1, FALSE);
if (!bulk->mppcRecv)
goto fail;
bulk->ncrushRecv = ncrush_context_new(FALSE);
if (!bulk->ncrushRecv)
goto fail;
bulk->ncrushSend = ncrush_context_new(TRUE);
if (!bulk->ncrushSend)
goto fail;
bulk->xcrushRecv = xcrush_context_new(FALSE);
if (!bulk->xcrushRecv)
goto fail;
bulk->xcrushSend = xcrush_context_new(TRUE);
if (!bulk->xcrushSend)
goto fail;
bulk->CompressionLevel = context->settings->CompressionLevel;
return bulk;
fail:
WINPR_PRAGMA_DIAG_PUSH
WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
bulk_free(bulk);
WINPR_PRAGMA_DIAG_POP
return nullptr;
}
void bulk_free(rdpBulk* bulk)
{
if (!bulk)
return;
mppc_context_free(bulk->mppcSend);
mppc_context_free(bulk->mppcRecv);
ncrush_context_free(bulk->ncrushRecv);
ncrush_context_free(bulk->ncrushSend);
xcrush_context_free(bulk->xcrushRecv);
xcrush_context_free(bulk->xcrushSend);
free(bulk);
}
+52
View File
@@ -0,0 +1,52 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Bulk Compression
*
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* 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 FREERDP_LIB_CORE_BULK_H
#define FREERDP_LIB_CORE_BULK_H
typedef struct rdp_bulk rdpBulk;
#include <freerdp/api.h>
#include <freerdp/freerdp.h>
#define BULK_COMPRESSION_FLAGS_MASK 0xE0
#define BULK_COMPRESSION_TYPE_MASK 0x0F
WINPR_ATTR_NODISCARD
FREERDP_LOCAL UINT16 bulk_compression_max_size(rdpBulk* WINPR_RESTRICT bulk);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL int bulk_decompress(rdpBulk* WINPR_RESTRICT bulk, const BYTE* WINPR_RESTRICT pSrcData,
UINT32 SrcSize, const BYTE** WINPR_RESTRICT ppDstData,
UINT32* WINPR_RESTRICT pDstSize, UINT32 flags);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL int bulk_compress(rdpBulk* WINPR_RESTRICT bulk, const BYTE* WINPR_RESTRICT pSrcData,
UINT32 SrcSize, const BYTE** WINPR_RESTRICT ppDstData,
UINT32* WINPR_RESTRICT pDstSize, UINT32* WINPR_RESTRICT pFlags);
FREERDP_LOCAL void bulk_reset(rdpBulk* WINPR_RESTRICT bulk);
FREERDP_LOCAL void bulk_free(rdpBulk* bulk);
WINPR_ATTR_MALLOC(bulk_free, 1)
WINPR_ATTR_NODISCARD
FREERDP_LOCAL rdpBulk* bulk_new(rdpContext* context);
#endif /* FREERDP_LIB_CORE_BULK_H */
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+151
View File
@@ -0,0 +1,151 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* codec color
*
* Copyright 2024 Armin Novak <anovak@thincast.com>
* Copyright 2024 Thincast Technologies GmbH
*
* 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 FREERDP_LIB_CODEC_COLOR_H
#define FREERDP_LIB_CODEC_COLOR_H
#include <winpr/winpr.h>
#include <winpr/wtypes.h>
#include <freerdp/codec/color.h>
#include <freerdp/log.h>
#define INT_COLOR_TAG FREERDP_TAG("codec.color.h")
WINPR_ATTR_NODISCARD
static inline DWORD FreeRDPAreColorFormatsEqualNoAlpha_int(DWORD first, DWORD second)
{
const DWORD mask = (DWORD) ~(8UL << 12UL);
return (first & mask) == (second & mask);
}
WINPR_ATTR_NODISCARD
static inline BOOL FreeRDPWriteColor_int(BYTE* WINPR_RESTRICT dst, UINT32 format, UINT32 color)
{
switch (FreeRDPGetBitsPerPixel(format))
{
case 32:
dst[0] = (BYTE)(color >> 24);
dst[1] = (BYTE)(color >> 16);
dst[2] = (BYTE)(color >> 8);
dst[3] = (BYTE)color;
break;
case 24:
dst[0] = (BYTE)(color >> 16);
dst[1] = (BYTE)(color >> 8);
dst[2] = (BYTE)color;
break;
case 16:
dst[1] = (BYTE)(color >> 8);
dst[0] = (BYTE)color;
break;
case 15:
if (!FreeRDPColorHasAlpha(format))
color = color & 0x7FFF;
dst[1] = (BYTE)(color >> 8);
dst[0] = (BYTE)color;
break;
case 8:
dst[0] = (BYTE)color;
break;
default:
WLog_ERR(INT_COLOR_TAG, "Unsupported format %s", FreeRDPGetColorFormatName(format));
return FALSE;
}
return TRUE;
}
WINPR_ATTR_NODISCARD
static inline BOOL FreeRDPWriteColorIgnoreAlpha_int(BYTE* WINPR_RESTRICT dst, UINT32 format,
UINT32 color)
{
switch (format)
{
case PIXEL_FORMAT_XBGR32:
case PIXEL_FORMAT_XRGB32:
case PIXEL_FORMAT_ABGR32:
case PIXEL_FORMAT_ARGB32:
{
const UINT32 tmp = ((UINT32)dst[0] << 24ULL) | (color & 0x00FFFFFFULL);
return FreeRDPWriteColor_int(dst, format, tmp);
}
case PIXEL_FORMAT_BGRX32:
case PIXEL_FORMAT_RGBX32:
case PIXEL_FORMAT_BGRA32:
case PIXEL_FORMAT_RGBA32:
{
const UINT32 tmp = ((UINT32)dst[3]) | (color & 0xFFFFFF00ULL);
return FreeRDPWriteColor_int(dst, format, tmp);
}
default:
return FreeRDPWriteColor_int(dst, format, color);
}
}
WINPR_ATTR_NODISCARD
static inline UINT32 FreeRDPReadColor_int(const BYTE* WINPR_RESTRICT src, UINT32 format)
{
UINT32 color = 0;
switch (FreeRDPGetBitsPerPixel(format))
{
case 32:
color =
((UINT32)src[0] << 24) | ((UINT32)src[1] << 16) | ((UINT32)src[2] << 8) | src[3];
break;
case 24:
color = ((UINT32)src[0] << 16) | ((UINT32)src[1] << 8) | src[2];
break;
case 16:
color = ((UINT32)src[1] << 8) | src[0];
break;
case 15:
color = ((UINT32)src[1] << 8) | src[0];
if (!FreeRDPColorHasAlpha(format))
color = color & 0x7FFF;
break;
case 8:
case 4:
case 1:
color = *src;
break;
default:
WLog_ERR(INT_COLOR_TAG, "Unsupported format %s", FreeRDPGetColorFormatName(format));
color = 0;
break;
}
return color;
}
#endif
File diff suppressed because it is too large Load Diff
+49
View File
@@ -0,0 +1,49 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Digital Sound Processing - backend
*
* Copyright 2018 Armin Novak <armin.novak@thincast.com>
* Copyright 2018 Thincast Technologies GmbH
*
* 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 FREERDP_LIB_CODEC_DSP_H
#define FREERDP_LIB_CODEC_DSP_H
#include <freerdp/api.h>
#include <freerdp/codec/audio.h>
#include <freerdp/codec/dsp.h>
typedef struct
{
ALIGN64 AUDIO_FORMAT format;
ALIGN64 BOOL encoder;
ALIGN64 wStream* buffer;
ALIGN64 wStream* resample;
ALIGN64 wStream* channelmix;
#if defined(WITH_FDK_AAC)
ALIGN64 BOOL fdkSetup;
ALIGN64 void* fdkAacInstance;
ALIGN64 size_t buffersize;
ALIGN64 unsigned frames_per_packet;
#endif
} FREERDP_DSP_COMMON_CONTEXT;
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL freerdp_dsp_common_context_init(FREERDP_DSP_COMMON_CONTEXT* context,
BOOL encode);
FREERDP_LOCAL void freerdp_dsp_common_context_uninit(FREERDP_DSP_COMMON_CONTEXT* context);
#endif /* FREERDP_LIB_CODEC_DSP_H */
+154
View File
@@ -0,0 +1,154 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Digital Sound Processing
*
* Copyright 2022 Armin Novak <anovak@thincast.com>
* Copyright 2022 Thincast Technologies GmbH
*
* 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 "dsp_fdk_aac.h"
#include "dsp_fdk_impl.h"
#include <freerdp/log.h>
#define TAG FREERDP_TAG("dsp.fdk")
WINPR_ATTR_FORMAT_ARG(2, 3)
static void write_log(unsigned log_level, WINPR_FORMAT_ARG const char* fmt, ...)
{
wLog* log = WLog_Get(TAG);
if (WLog_IsLevelActive(log, log_level))
{
char buffer[1024] = WINPR_C_ARRAY_INIT;
va_list ap = WINPR_C_ARRAY_INIT;
va_start(ap, fmt);
(void)vsnprintf(buffer, sizeof(buffer), fmt, ap);
va_end(ap);
WLog_PrintTextMessage(log, log_level, __LINE__, __FILE__, __func__, "%s", buffer);
}
}
BOOL fdk_aac_dsp_encode(FREERDP_DSP_COMMON_CONTEXT* context, const AUDIO_FORMAT* srcFormat,
const BYTE* data, size_t length, wStream* out)
{
WINPR_ASSERT(context);
WINPR_ASSERT(srcFormat);
if (srcFormat->wFormatTag != WAVE_FORMAT_PCM)
{
WLog_WARN(TAG, "Feeding %s format data to encoder function, but require %s",
audio_format_get_tag_string(srcFormat->wFormatTag),
audio_format_get_tag_string(WAVE_FORMAT_PCM));
return FALSE;
}
if (!context->fdkSetup)
{
ssize_t rc = fdk_aac_dsp_impl_config(
context->fdkAacInstance, &context->buffersize, context->encoder,
context->format.nSamplesPerSec, context->format.nChannels,
context->format.nAvgBytesPerSec, context->frames_per_packet, write_log);
if (rc < 0)
return FALSE;
context->fdkSetup = TRUE;
}
if (!Stream_EnsureRemainingCapacity(out, context->buffersize))
return FALSE;
{
const ssize_t encoded =
fdk_aac_dsp_impl_encode(context->fdkAacInstance, data, length, Stream_Pointer(out),
Stream_GetRemainingCapacity(out), write_log);
if (encoded < 0)
return FALSE;
Stream_Seek(out, (size_t)encoded);
return TRUE;
}
}
BOOL fdk_aac_dsp_decode(FREERDP_DSP_COMMON_CONTEXT* context, const AUDIO_FORMAT* srcFormat,
const BYTE* data, size_t length, wStream* out)
{
WINPR_ASSERT(context);
WINPR_ASSERT(srcFormat);
if (srcFormat->wFormatTag != WAVE_FORMAT_AAC_MS)
{
WLog_WARN(TAG, "Feeding %s format data to encoder function, but require %s",
audio_format_get_tag_string(srcFormat->wFormatTag),
audio_format_get_tag_string(WAVE_FORMAT_AAC_MS));
return FALSE;
}
if (!context->fdkSetup)
{
ssize_t rc = fdk_aac_dsp_impl_config(
context->fdkAacInstance, &context->buffersize, context->encoder,
context->format.nSamplesPerSec, context->format.nChannels,
context->format.nAvgBytesPerSec, context->frames_per_packet, write_log);
if (rc < 0)
return FALSE;
context->fdkSetup = TRUE;
}
ssize_t rest = 0;
do
{
rest = fdk_aac_dsp_impl_decode_fill(context->fdkAacInstance, data, length, write_log);
if (rest < 0)
{
WLog_WARN(TAG, "DecodeFill() failed");
return FALSE;
}
ssize_t ret = -1;
do
{
const size_t expect = context->buffersize;
if (!Stream_EnsureRemainingCapacity(out, expect))
return FALSE;
ret = fdk_aac_dsp_impl_decode_read(context->fdkAacInstance, Stream_Pointer(out), expect,
write_log);
if (ret < 0)
return FALSE;
Stream_Seek(out, (size_t)ret);
} while (ret > 0);
} while (rest > 0);
return TRUE;
}
void fdk_aac_dsp_uninit(FREERDP_DSP_COMMON_CONTEXT* context)
{
WINPR_ASSERT(context);
fdk_aac_dsp_impl_uninit(&context->fdkAacInstance, context->encoder, write_log);
}
BOOL fdk_aac_dsp_init(FREERDP_DSP_COMMON_CONTEXT* context, size_t frames_per_packet)
{
WINPR_ASSERT(context);
context->fdkSetup = FALSE;
WINPR_ASSERT(frames_per_packet <= UINT_MAX);
context->frames_per_packet = (unsigned)frames_per_packet;
return fdk_aac_dsp_impl_init(&context->fdkAacInstance, context->encoder, write_log);
}
+45
View File
@@ -0,0 +1,45 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Digital Sound Processing
*
* Copyright 2022 Armin Novak <anovak@thincast.com>
* Copyright 2022 Thincast Technologies GmbH
*
* 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 FREERDP_DSP_FDK_AAC_H_
#define FREERDP_DSP_FDK_AAC_H_
#include <winpr/stream.h>
#include <freerdp/codec/audio.h>
#include "dsp.h"
WINPR_ATTR_NODISCARD FREERDP_LOCAL BOOL fdk_aac_dsp_init(FREERDP_DSP_COMMON_CONTEXT* context,
size_t frames_per_packet);
FREERDP_LOCAL
void fdk_aac_dsp_uninit(FREERDP_DSP_COMMON_CONTEXT* context);
WINPR_ATTR_NODISCARD FREERDP_LOCAL BOOL fdk_aac_dsp_encode(FREERDP_DSP_COMMON_CONTEXT* context,
const AUDIO_FORMAT* srcFormat,
const BYTE* data, size_t length,
wStream* out);
WINPR_ATTR_NODISCARD FREERDP_LOCAL BOOL fdk_aac_dsp_decode(FREERDP_DSP_COMMON_CONTEXT* context,
const AUDIO_FORMAT* srcFormat,
const BYTE* data, size_t length,
wStream* out);
#endif
+616
View File
@@ -0,0 +1,616 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Digital Sound Processing
*
* Copyright 2022 Armin Novak <anovak@thincast.com>
* Copyright 2022 Thincast Technologies GmbH
*
* 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 <assert.h>
#include <string.h>
#include <stdio.h>
#include <limits.h>
#include <inttypes.h>
#include <fdk-aac/aacdecoder_lib.h>
#include <fdk-aac/aacenc_lib.h>
#include "dsp_fdk_impl.h"
#if (defined(__STDC_VERSION__) && (__STDC_VERSION__ < 202003L))
#define nullptr NULL
#endif
#define WLOG_TRACE 0
#define WLOG_DEBUG 1
#define WLOG_INFO 2
#define WLOG_WARN 3
#define WLOG_ERROR 4
#define WLOG_FATAL 5
static const char* enc_err_str(AACENC_ERROR err)
{
switch (err)
{
case AACENC_OK:
return "AACENC_OK";
case AACENC_INVALID_HANDLE:
return "AACENC_INVALID_HANDLE";
case AACENC_MEMORY_ERROR:
return "AACENC_MEMORY_ERROR";
case AACENC_UNSUPPORTED_PARAMETER:
return "AACENC_UNSUPPORTED_PARAMETER";
case AACENC_INVALID_CONFIG:
return "AACENC_INVALID_CONFIG";
case AACENC_INIT_ERROR:
return "AACENC_INIT_ERROR";
case AACENC_INIT_AAC_ERROR:
return "AACENC_INIT_AAC_ERROR";
case AACENC_INIT_SBR_ERROR:
return "AACENC_INIT_SBR_ERROR";
case AACENC_INIT_TP_ERROR:
return "AACENC_INIT_TP_ERROR";
case AACENC_INIT_META_ERROR:
return "AACENC_INIT_META_ERROR";
#ifdef AACENC_INIT_MPS_ERROR
case AACENC_INIT_MPS_ERROR:
return "AACENC_INIT_MPS_ERROR";
#endif
case AACENC_ENCODE_ERROR:
return "AACENC_ENCODE_ERROR";
case AACENC_ENCODE_EOF:
return "AACENC_ENCODE_EOF";
default:
return "AACENC_UNKNOWN";
}
}
static const char* dec_err_str(AAC_DECODER_ERROR err)
{
switch (err)
{
case AAC_DEC_OK:
return "AAC_DEC_OK";
case AAC_DEC_OUT_OF_MEMORY:
return "AAC_DEC_OUT_OF_MEMORY";
case AAC_DEC_UNKNOWN:
return "AAC_DEC_UNKNOWN";
case aac_dec_sync_error_start:
return "aac_dec_sync_error_start";
case AAC_DEC_TRANSPORT_SYNC_ERROR:
return "AAC_DEC_TRANSPORT_SYNC_ERROR";
case AAC_DEC_NOT_ENOUGH_BITS:
return "AAC_DEC_NOT_ENOUGH_BITS";
case aac_dec_sync_error_end:
return "aac_dec_sync_error_end";
case aac_dec_init_error_start:
return "aac_dec_init_error_start";
case AAC_DEC_INVALID_HANDLE:
return "AAC_DEC_INVALID_HANDLE";
case AAC_DEC_UNSUPPORTED_FORMAT:
return "AAC_DEC_UNSUPPORTED_FORMAT";
case AAC_DEC_UNSUPPORTED_ER_FORMAT:
return "AAC_DEC_UNSUPPORTED_ER_FORMAT";
case AAC_DEC_UNSUPPORTED_EPCONFIG:
return "AAC_DEC_UNSUPPORTED_EPCONFIG";
case AAC_DEC_UNSUPPORTED_MULTILAYER:
return "AAC_DEC_UNSUPPORTED_MULTILAYER";
case AAC_DEC_UNSUPPORTED_CHANNELCONFIG:
return "AAC_DEC_UNSUPPORTED_CHANNELCONFIG";
case AAC_DEC_UNSUPPORTED_SAMPLINGRATE:
return "AAC_DEC_UNSUPPORTED_SAMPLINGRATE";
case AAC_DEC_INVALID_SBR_CONFIG:
return "AAC_DEC_INVALID_SBR_CONFIG";
case AAC_DEC_SET_PARAM_FAIL:
return "AAC_DEC_SET_PARAM_FAIL";
case AAC_DEC_NEED_TO_RESTART:
return "AAC_DEC_NEED_TO_RESTART";
case AAC_DEC_OUTPUT_BUFFER_TOO_SMALL:
return "AAC_DEC_OUTPUT_BUFFER_TOO_SMALL";
case aac_dec_init_error_end:
return "aac_dec_init_error_end";
case aac_dec_decode_error_start:
return "aac_dec_decode_error_start";
case AAC_DEC_TRANSPORT_ERROR:
return "AAC_DEC_TRANSPORT_ERROR";
case AAC_DEC_PARSE_ERROR:
return "AAC_DEC_PARSE_ERROR";
case AAC_DEC_UNSUPPORTED_EXTENSION_PAYLOAD:
return "AAC_DEC_UNSUPPORTED_EXTENSION_PAYLOAD";
case AAC_DEC_DECODE_FRAME_ERROR:
return "AAC_DEC_DECODE_FRAME_ERROR";
case AAC_DEC_CRC_ERROR:
return "AAC_DEC_CRC_ERROR";
case AAC_DEC_INVALID_CODE_BOOK:
return "AAC_DEC_INVALID_CODE_BOOK";
case AAC_DEC_UNSUPPORTED_PREDICTION:
return "AAC_DEC_UNSUPPORTED_PREDICTION";
case AAC_DEC_UNSUPPORTED_CCE:
return "AAC_DEC_UNSUPPORTED_CCE";
case AAC_DEC_UNSUPPORTED_LFE:
return "AAC_DEC_UNSUPPORTED_LFE";
case AAC_DEC_UNSUPPORTED_GAIN_CONTROL_DATA:
return "AAC_DEC_UNSUPPORTED_GAIN_CONTROL_DATA";
case AAC_DEC_UNSUPPORTED_SBA:
return "AAC_DEC_UNSUPPORTED_SBA";
case AAC_DEC_TNS_READ_ERROR:
return "AAC_DEC_TNS_READ_ERROR";
case AAC_DEC_RVLC_ERROR:
return "AAC_DEC_RVLC_ERROR";
case aac_dec_decode_error_end:
return "aac_dec_decode_error_end";
case aac_dec_anc_data_error_start:
return "aac_dec_anc_data_error_start";
case AAC_DEC_ANC_DATA_ERROR:
return "AAC_DEC_ANC_DATA_ERROR";
case AAC_DEC_TOO_SMALL_ANC_BUFFER:
return "AAC_DEC_TOO_SMALL_ANC_BUFFER";
case AAC_DEC_TOO_MANY_ANC_ELEMENTS:
return "AAC_DEC_TOO_MANY_ANC_ELEMENTS";
case aac_dec_anc_data_error_end:
return "aac_dec_anc_data_error_end";
default:
return "AAC_DEC unknown value";
}
}
static void log_dec_info(const CStreamInfo* info, void (*log)(const char* fmt, ...))
{
assert(info);
assert(log);
log("info:"
"aacSampleRate: %d, "
"frameSize: %d, "
"numChannels: %d, "
"pChannelType: %p, "
"pChannelIndices: %p, "
"aacSampleRate: %d, "
"profile: %d, "
"aot: %d, " /* TODO: Enum 2 string */
"channelConfig: %d, "
"bitRate: %d, "
"aacSamplesPerFrame: %d, "
"aacNumChannels: %d, "
"extAot: %d" /* TODO: Enum 2 string */
"extSamplingRate: %d, "
"outputDelay: %u, "
"flags: %u, "
"epConfig: %d, "
"numLostAccessUnits: %d, "
"numTotalBytes: %" PRIu64 ", "
"numBadBytes: %" PRIu64 ", "
"numTotalAccessUnits: %" PRIu64 ", "
"numBadAccessUnits: %" PRIu64 ", "
"drcProgRefLev: %d, "
"drcPresMode: %d, ",
info->aacSampleRate, info->frameSize, info->numChannels, info->pChannelType,
info->pChannelIndices, info->aacSampleRate, info->profile, info->aot, info->channelConfig,
info->bitRate, info->aacSamplesPerFrame, info->aacNumChannels, info->extAot,
info->extSamplingRate, info->outputDelay, info->flags, (int)info->epConfig,
info->numLostAccessUnits,
info->numTotalBytes, info->numBadBytes, info->numTotalAccessUnits, info->numBadAccessUnits,
(int)info->drcProgRefLev, (int)info->drcPresMode);
}
static void log_enc_info(const AACENC_InfoStruct* info, fdk_log_fkt_t log)
{
char confBuf[1024] = { 0 };
assert(info);
assert(log);
size_t offset = 0;
size_t remain = sizeof(confBuf) - 1;
int rc = snprintf(confBuf, remain, "{");
if (rc <= 0)
return;
offset += (size_t)rc;
for (size_t x = 0; x < 64; x++)
{
rc = snprintf(&confBuf[offset], remain - offset, "0x%02x%s", (int)info->confBuf[x],
(x > 0) ? ", " : "");
if (rc <= 0)
return;
}
rc = snprintf(confBuf, remain - offset, "}");
if (rc <= 0)
return;
log(WLOG_DEBUG,
"[encoder info] "
"maxOutBufBytes : %u, "
"maxAncBytes : %u, "
"inBufFillLevel : %u, "
"inputChannels : %u, "
"frameLength : %u, "
#ifdef MODE_7_1_BACK
"nDelay : %u, "
"nDelayCore : %u, "
#endif
"confBuf[64] : %s, "
"confSize : %u",
info->maxOutBufBytes, info->maxAncBytes, info->inBufFillLevel, info->inputChannels,
info->frameLength,
#ifdef MODE_7_1_BACK
info->nDelay, info->nDelayCore,
#endif
confBuf, info->confSize);
}
static const char* aac_enc_param_str(AACENC_PARAM param)
{
switch (param)
{
case AACENC_AOT:
return "AACENC_AOT";
case AACENC_BITRATE:
return "AACENC_BITRATE";
case AACENC_BITRATEMODE:
return "AACENC_BITRATEMODE";
case AACENC_SAMPLERATE:
return "AACENC_SAMPLERATE";
case AACENC_SBR_MODE:
return "AACENC_SBR_MODE";
case AACENC_GRANULE_LENGTH:
return "AACENC_GRANULE_LENGTH";
case AACENC_CHANNELMODE:
return "AACENC_CHANNELMODE";
case AACENC_CHANNELORDER:
return "AACENC_CHANNELORDER";
case AACENC_SBR_RATIO:
return "AACENC_SBR_RATIO";
case AACENC_AFTERBURNER:
return "AACENC_AFTERBURNER";
case AACENC_BANDWIDTH:
return "AACENC_BANDWIDTH";
case AACENC_PEAK_BITRATE:
return "AACENC_PEAK_BITRATE";
case AACENC_TRANSMUX:
return "AACENC_TRANSMUX";
case AACENC_HEADER_PERIOD:
return "AACENC_HEADER_PERIOD";
case AACENC_SIGNALING_MODE:
return "AACENC_SIGNALING_MODE";
case AACENC_TPSUBFRAMES:
return "AACENC_TPSUBFRAMES";
case AACENC_AUDIOMUXVER:
return "AACENC_AUDIOMUXVER";
case AACENC_PROTECTION:
return "AACENC_PROTECTION";
case AACENC_ANCILLARY_BITRATE:
return "AACENC_ANCILLARY_BITRATE";
case AACENC_METADATA_MODE:
return "AACENC_METADATA_MODE";
case AACENC_CONTROL_STATE:
return "AACENC_CONTROL_STATE";
default:
return "AACENC_UNKNOWN";
}
}
int fdk_aac_dsp_impl_init(void** handle, int encoder, fdk_log_fkt_t log)
{
assert(handle);
assert(log);
if (encoder)
{
HANDLE_AACENCODER* h = (HANDLE_AACENCODER*)handle;
AACENC_ERROR err = aacEncOpen(h, 0, 0);
if (err != AACENC_OK)
{
log(WLOG_ERROR, "aacEncOpen failed with %s", enc_err_str(err));
return 0;
}
}
else
{
HANDLE_AACDECODER* h = (HANDLE_AACDECODER*)handle;
assert(nullptr == *h);
*h = aacDecoder_Open(TT_MP4_RAW, 1);
if (!*h)
{
log(WLOG_ERROR, "aacDecoder_Open failed");
return 0;
}
}
return 1;
}
void fdk_aac_dsp_impl_uninit(void** handle, int encoder, fdk_log_fkt_t log)
{
assert(handle);
assert(log);
if (encoder)
{
HANDLE_AACENCODER* h = (HANDLE_AACENCODER*)handle;
AACENC_ERROR err = aacEncClose(h);
if (err != AACENC_OK)
log(WLOG_ERROR, "aacEncClose failed with %s", enc_err_str(err));
}
else
{
HANDLE_AACDECODER* h = (HANDLE_AACDECODER*)handle;
if (h)
aacDecoder_Close(*h);
}
*handle = nullptr;
}
ssize_t fdk_aac_dsp_impl_decode_read(void* handle, void* dst, size_t dstSize, fdk_log_fkt_t log)
{
assert(handle);
assert((dstSize / sizeof(INT_PCM)) <= INT_MAX);
const INT nrsamples = (INT)(dstSize / sizeof(INT_PCM));
UINT flags = 0;
HANDLE_AACDECODER self = (HANDLE_AACDECODER)handle;
AAC_DECODER_ERROR err = aacDecoder_DecodeFrame(self, dst, nrsamples, flags);
switch (err)
{
case AAC_DEC_OK:
return fdk_aac_dsp_impl_stream_info(handle, 0, log);
case AAC_DEC_NOT_ENOUGH_BITS:
return 0;
default:
log(WLOG_ERROR, "aacDecoder_DecodeFrame failed with %s", dec_err_str(err));
return -1;
}
}
static unsigned get_channelmode(unsigned channels)
{
switch (channels)
{
case 1:
return MODE_1;
case 2:
return MODE_2;
case 3:
return MODE_1_2;
case 4:
return MODE_1_2_1;
case 5:
return MODE_1_2_2;
case 6:
return MODE_1_2_2_1;
case 7:
return MODE_1_2_2_2_1;
#ifdef MODE_7_1_BACK
case 8:
return MODE_7_1_BACK;
#endif
default:
return MODE_2;
}
}
int fdk_aac_dsp_impl_config(void* handle, size_t* pbuffersize, int encoder, unsigned samplerate,
unsigned channels, unsigned bytes_per_second,
unsigned frames_per_packet, fdk_log_fkt_t log)
{
assert(handle);
assert(log);
assert(pbuffersize);
log(WLOG_DEBUG,
"fdk_aac_dsp_impl_config: samplerate: %ld, channels: %ld, bytes_pers_second: %ld",
samplerate, channels, bytes_per_second);
struct t_param_pair
{
AACENC_PARAM param;
UINT value;
};
const struct t_param_pair params[] = { { AACENC_AOT, 2 },
{ AACENC_SAMPLERATE, samplerate },
{ AACENC_CHANNELMODE, get_channelmode(channels) },
{ AACENC_CHANNELORDER, 0 },
{ AACENC_BITRATE, bytes_per_second * 8 },
{ AACENC_TRANSMUX, 0 },
{ AACENC_AFTERBURNER, 1 } };
HANDLE_AACENCODER self = nullptr;
if (encoder)
self = (HANDLE_AACENCODER)handle;
else
{
AACENC_ERROR err = aacEncOpen(&self, 0, channels);
if (err != AACENC_OK)
{
log(WLOG_ERROR, "aacEncOpen failed with %s", enc_err_str(err));
return -1;
}
}
for (size_t x = 0; x < sizeof(params) / sizeof(params[0]); x++)
{
const struct t_param_pair* param = &params[x];
AACENC_ERROR err = aacEncoder_SetParam(self, param->param, param->value);
if (err != AACENC_OK)
{
log(WLOG_ERROR, "aacEncoder_SetParam(%s, %d) failed with %s",
aac_enc_param_str(param->param), param->value, enc_err_str(err));
return -1;
}
}
AACENC_ERROR err = aacEncEncode(self, nullptr, nullptr, nullptr, nullptr);
if (err != AACENC_OK)
{
log(WLOG_ERROR, "aacEncEncode failed with %s", enc_err_str(err));
return -1;
}
AACENC_InfoStruct info = { 0 };
err = aacEncInfo(self, &info);
if (err != AACENC_OK)
{
log(WLOG_ERROR, "aacEncInfo failed with %s", enc_err_str(err));
return -1;
}
if (encoder)
{
*pbuffersize = info.maxOutBufBytes;
log_enc_info(&info, log);
return 0;
}
else
{
err = aacEncClose(&self);
if (err != AACENC_OK)
log(WLOG_WARN, "aacEncClose failed with %s", enc_err_str(err));
*pbuffersize = sizeof(INT_PCM) * info.frameLength * info.inputChannels;
HANDLE_AACDECODER aacdec = (HANDLE_AACDECODER)handle;
UCHAR* asc[] = { info.confBuf };
UINT ascSize[] = { info.confSize };
assert(handle);
AAC_DECODER_ERROR decerr = aacDecoder_ConfigRaw(aacdec, asc, ascSize);
if (decerr != AAC_DEC_OK)
{
log(WLOG_ERROR, "aacDecoder_ConfigRaw failed with %s", dec_err_str(decerr));
return -1;
}
return 0;
}
}
ssize_t fdk_aac_dsp_impl_decode_fill(void* handle, const void* data, size_t size, fdk_log_fkt_t log)
{
assert(handle);
assert(log);
UINT leftBytes = size;
HANDLE_AACDECODER self = (HANDLE_AACDECODER)handle;
union
{
const void* cpv;
UCHAR* puc;
} cnv;
cnv.cpv = data;
UCHAR* pBuffer[] = { cnv.puc };
const UINT bufferSize[] = { size };
assert(handle);
assert(data || (size == 0));
AAC_DECODER_ERROR err = aacDecoder_Fill(self, pBuffer, bufferSize, &leftBytes);
if (err != AAC_DEC_OK)
{
log(WLOG_ERROR, "aacDecoder_Fill failed with %s", dec_err_str(err));
return -1;
}
return leftBytes;
}
ssize_t fdk_aac_dsp_impl_stream_info(void* handle, int encoder, fdk_log_fkt_t log)
{
assert(handle);
assert(log);
if (encoder)
{
AACENC_InfoStruct info = { 0 };
HANDLE_AACENCODER self = (HANDLE_AACENCODER)handle;
AACENC_ERROR err = aacEncInfo(self, &info);
if (err != AACENC_OK)
{
log(WLOG_ERROR, "aacEncInfo failed with %s", enc_err_str(err));
return -1;
}
return info.maxOutBufBytes;
}
else
{
HANDLE_AACDECODER self = (HANDLE_AACDECODER)handle;
CStreamInfo* info = aacDecoder_GetStreamInfo(self);
if (!info)
{
log(WLOG_ERROR, "aacDecoder_GetStreamInfo failed");
return -1;
}
const size_t rsize = sizeof(INT_PCM) * info->numChannels * info->frameSize;
return (ssize_t)rsize;
}
}
ssize_t fdk_aac_dsp_impl_encode(void* handle, const void* data, size_t size, void* dst,
size_t dstSize, fdk_log_fkt_t log)
{
INT inSizes[] = { (INT)size };
INT inElSizes[] = { sizeof(INT_PCM) };
INT inIdentifiers[] = { IN_AUDIO_DATA };
union
{
const void* cpv;
void* pv;
} cnv;
cnv.cpv = data;
void* inBuffers[] = { cnv.pv };
const AACENC_BufDesc inBufDesc = {
.numBufs = 1,
.bufs = inBuffers,
.bufferIdentifiers = inIdentifiers,
.bufSizes = inSizes,
.bufElSizes = inElSizes /* TODO: 8/16 bit input? */
};
INT outSizes[] = { (INT)dstSize };
INT outElSizes[] = { 1 };
INT outIdentifiers[] = { OUT_BITSTREAM_DATA };
void* outBuffers[] = { dst };
const AACENC_BufDesc outBufDesc = { .numBufs = 1,
.bufs = outBuffers,
.bufferIdentifiers = outIdentifiers,
.bufSizes = outSizes,
.bufElSizes = outElSizes };
const AACENC_InArgs inArgs = { .numInSamples =
(INT)(size / sizeof(INT_PCM)), /* TODO: 8/16 bit input? */
.numAncBytes = 0 };
AACENC_OutArgs outArgs = { 0 };
HANDLE_AACENCODER self = (HANDLE_AACENCODER)handle;
assert(handle);
assert(log);
AACENC_ERROR err = aacEncEncode(self, &inBufDesc, &outBufDesc, &inArgs, &outArgs);
if (err != AACENC_OK)
{
log(WLOG_ERROR, "aacEncEncode failed with %s", enc_err_str(err));
return -1;
}
return outArgs.numOutBytes;
}
+45
View File
@@ -0,0 +1,45 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Digital Sound Processing
*
* Copyright 2022 Armin Novak <anovak@thincast.com>
* Copyright 2022 Thincast Technologies GmbH
*
* 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 FREERDP_DSP_FDK_IMPL_H_
#define FREERDP_DSP_FDK_IMPL_H_
#include <stdlib.h>
typedef void (*fdk_log_fkt_t)(unsigned log_level, const char* fmt, ...);
int fdk_aac_dsp_impl_init(void** handle, int encoder, fdk_log_fkt_t log);
void fdk_aac_dsp_impl_uninit(void** handle, int encoder, fdk_log_fkt_t log);
ssize_t fdk_aac_dsp_impl_stream_info(void* handle, int encoder, fdk_log_fkt_t log);
int fdk_aac_dsp_impl_config(void* handle, size_t* pbuffersize, int encoder, unsigned samplerate,
unsigned channels, unsigned bytes_per_second,
unsigned frames_per_packet, fdk_log_fkt_t log);
ssize_t fdk_aac_dsp_impl_decode_fill(void* handle, const void* data, size_t size,
fdk_log_fkt_t log);
ssize_t fdk_aac_dsp_impl_encode(void* handle, const void* data, size_t size, void* dst,
size_t dstSize, fdk_log_fkt_t log);
ssize_t fdk_aac_dsp_impl_decode_read(void* handle, void* dst, size_t dstSize, fdk_log_fkt_t log);
#endif
+898
View File
@@ -0,0 +1,898 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Digital Sound Processing - FFMPEG backend
*
* Copyright 2018 Armin Novak <armin.novak@thincast.com>
* Copyright 2018 Thincast Technologies GmbH
*
* 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 <freerdp/config.h>
#include <freerdp/log.h>
#include <libavcodec/avcodec.h>
#include <libavutil/avutil.h>
#include <libavutil/opt.h>
#if defined(SWRESAMPLE_FOUND)
#include <libswresample/swresample.h>
#elif defined(AVRESAMPLE_FOUND)
#include <libavresample/avresample.h>
#else
#error "libswresample or libavresample required"
#endif
#include "dsp.h"
#include "dsp_ffmpeg.h"
#define TAG FREERDP_TAG("dsp.ffmpeg")
struct S_FREERDP_DSP_CONTEXT
{
FREERDP_DSP_COMMON_CONTEXT common;
BOOL isOpen;
UINT32 bufferedSamples;
enum AVCodecID id;
const AVCodec* codec;
AVCodecContext* context;
AVFrame* frame;
AVFrame* resampled;
AVFrame* buffered;
AVPacket* packet;
#if defined(SWRESAMPLE_FOUND)
SwrContext* rcontext;
#else
AVAudioResampleContext* rcontext;
#endif
};
static BOOL ffmpeg_codec_is_filtered(enum AVCodecID id, WINPR_ATTR_UNUSED BOOL encoder)
{
switch (id)
{
#if !defined(WITH_DSP_EXPERIMENTAL)
case AV_CODEC_ID_ADPCM_IMA_OKI:
case AV_CODEC_ID_MP3:
case AV_CODEC_ID_ADPCM_MS:
case AV_CODEC_ID_G723_1:
case AV_CODEC_ID_GSM_MS:
case AV_CODEC_ID_PCM_ALAW:
case AV_CODEC_ID_PCM_MULAW:
return TRUE;
#endif
case AV_CODEC_ID_NONE:
return TRUE;
case AV_CODEC_ID_AAC:
case AV_CODEC_ID_AAC_LATM:
return FALSE;
default:
return FALSE;
}
}
static enum AVCodecID ffmpeg_get_avcodec(const AUDIO_FORMAT* WINPR_RESTRICT format)
{
if (!format)
return AV_CODEC_ID_NONE;
switch (format->wFormatTag)
{
case WAVE_FORMAT_UNKNOWN:
return AV_CODEC_ID_NONE;
case WAVE_FORMAT_PCM:
switch (format->wBitsPerSample)
{
case 16:
return AV_CODEC_ID_PCM_U16LE;
case 8:
return AV_CODEC_ID_PCM_U8;
default:
return AV_CODEC_ID_NONE;
}
case WAVE_FORMAT_DVI_ADPCM:
return AV_CODEC_ID_ADPCM_IMA_OKI;
case WAVE_FORMAT_ADPCM:
return AV_CODEC_ID_ADPCM_MS;
case WAVE_FORMAT_ALAW:
return AV_CODEC_ID_PCM_ALAW;
case WAVE_FORMAT_MULAW:
return AV_CODEC_ID_PCM_MULAW;
case WAVE_FORMAT_GSM610:
return AV_CODEC_ID_GSM_MS;
case WAVE_FORMAT_MSG723:
return AV_CODEC_ID_G723_1;
case WAVE_FORMAT_AAC_MS:
return AV_CODEC_ID_AAC;
case WAVE_FORMAT_OPUS:
return AV_CODEC_ID_OPUS;
default:
return AV_CODEC_ID_NONE;
}
}
static enum AVSampleFormat ffmpeg_sample_format(const AUDIO_FORMAT* WINPR_RESTRICT format)
{
switch (format->wFormatTag)
{
case WAVE_FORMAT_PCM:
switch (format->wBitsPerSample)
{
case 8:
return AV_SAMPLE_FMT_U8;
case 16:
return AV_SAMPLE_FMT_S16;
default:
return AV_SAMPLE_FMT_NONE;
}
case WAVE_FORMAT_DVI_ADPCM:
case WAVE_FORMAT_ADPCM:
return AV_SAMPLE_FMT_S16P;
case WAVE_FORMAT_MPEGLAYER3:
case WAVE_FORMAT_AAC_MS:
return AV_SAMPLE_FMT_FLTP;
case WAVE_FORMAT_OPUS:
return AV_SAMPLE_FMT_S16;
case WAVE_FORMAT_MSG723:
case WAVE_FORMAT_GSM610:
return AV_SAMPLE_FMT_S16P;
case WAVE_FORMAT_ALAW:
return AV_SAMPLE_FMT_S16;
default:
return AV_SAMPLE_FMT_NONE;
}
}
static void ffmpeg_close_context(FREERDP_DSP_CONTEXT* WINPR_RESTRICT context)
{
if (context)
{
if (context->context)
avcodec_free_context(&context->context);
if (context->frame)
av_frame_free(&context->frame);
if (context->resampled)
av_frame_free(&context->resampled);
if (context->buffered)
av_frame_free(&context->buffered);
if (context->packet)
av_packet_free(&context->packet);
if (context->rcontext)
{
#if defined(SWRESAMPLE_FOUND)
swr_free(&context->rcontext);
#else
avresample_free(&context->rcontext);
#endif
}
context->id = AV_CODEC_ID_NONE;
context->codec = nullptr;
context->isOpen = FALSE;
context->context = nullptr;
context->frame = nullptr;
context->resampled = nullptr;
context->packet = nullptr;
context->rcontext = nullptr;
}
}
static void ffmpeg_setup_resample_frame(FREERDP_DSP_CONTEXT* WINPR_RESTRICT context,
const AUDIO_FORMAT* WINPR_RESTRICT format)
{
if (context->resampled->buf[0] != nullptr)
av_frame_unref(context->resampled);
if (context->common.encoder)
{
context->resampled->format = context->context->sample_fmt;
context->resampled->sample_rate = context->context->sample_rate;
}
else
{
context->resampled->format = AV_SAMPLE_FMT_S16;
WINPR_ASSERT(format->nSamplesPerSec <= INT_MAX);
context->resampled->sample_rate = (int)format->nSamplesPerSec;
}
#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(57, 28, 100)
av_channel_layout_default(&context->resampled->ch_layout, format->nChannels);
#else
const int64_t layout = av_get_default_channel_layout(format->nChannels);
context->resampled->channel_layout = layout;
context->resampled->channels = format->nChannels;
#endif
}
static BOOL ffmpeg_open_context(FREERDP_DSP_CONTEXT* WINPR_RESTRICT context)
{
int ret = 0;
if (!context || context->isOpen)
return FALSE;
const AUDIO_FORMAT* format = &context->common.format;
if (!format)
return FALSE;
context->id = ffmpeg_get_avcodec(format);
if (ffmpeg_codec_is_filtered(context->id, context->common.encoder))
goto fail;
if (context->common.encoder)
context->codec = avcodec_find_encoder(context->id);
else
context->codec = avcodec_find_decoder(context->id);
if (!context->codec)
goto fail;
context->context = avcodec_alloc_context3(context->codec);
if (!context->context)
goto fail;
switch (context->id)
{
/* We need support for multichannel and sample rates != 8000 */
case AV_CODEC_ID_GSM_MS:
context->context->strict_std_compliance = FF_COMPLIANCE_UNOFFICIAL;
break;
case AV_CODEC_ID_AAC:
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(60, 31, 102)
context->context->profile = FF_PROFILE_AAC_MAIN;
#elif LIBAVCODEC_VERSION_INT < AV_VERSION_INT(62, 11, 100)
context->context->profile = AV_PROFILE_AAC_MAIN;
#else
context->context->profile = AV_PROFILE_AAC_LOW;
#endif
break;
default:
break;
}
context->context->max_b_frames = 1;
context->context->delay = 0;
#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(57, 28, 100)
av_channel_layout_default(&context->context->ch_layout, format->nChannels);
#else
context->context->channels = format->nChannels;
const int64_t layout = av_get_default_channel_layout(format->nChannels);
context->context->channel_layout = layout;
#endif
context->context->sample_rate = (int)format->nSamplesPerSec;
context->context->block_align = format->nBlockAlign;
context->context->bit_rate = format->nAvgBytesPerSec * 8LL;
context->context->sample_fmt = ffmpeg_sample_format(format);
context->context->time_base = av_make_q(1, context->context->sample_rate);
if ((ret = avcodec_open2(context->context, context->codec, nullptr)) < 0)
{
const char* err = av_err2str(ret);
WLog_ERR(TAG, "Error avcodec_open2 %s [%d]", err, ret);
goto fail;
}
context->packet = av_packet_alloc();
if (!context->packet)
goto fail;
context->frame = av_frame_alloc();
if (!context->frame)
goto fail;
context->resampled = av_frame_alloc();
if (!context->resampled)
goto fail;
context->buffered = av_frame_alloc();
if (!context->buffered)
goto fail;
#if defined(SWRESAMPLE_FOUND)
context->rcontext = swr_alloc();
#else
context->rcontext = avresample_alloc_context();
#endif
if (!context->rcontext)
goto fail;
#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(57, 28, 100)
av_channel_layout_default(&context->frame->ch_layout, format->nChannels);
#else
context->frame->channel_layout = layout;
context->frame->channels = format->nChannels;
#endif
WINPR_ASSERT(format->nSamplesPerSec <= INT_MAX);
context->frame->sample_rate = (int)format->nSamplesPerSec;
context->frame->format = AV_SAMPLE_FMT_S16;
ffmpeg_setup_resample_frame(context, format);
if (context->context->frame_size > 0)
{
#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(57, 28, 100)
ret = av_channel_layout_copy(&context->buffered->ch_layout, &context->resampled->ch_layout);
if (ret != 0)
goto fail;
#else
context->buffered->channel_layout = context->resampled->channel_layout;
context->buffered->channels = context->resampled->channels;
#endif
context->buffered->format = context->resampled->format;
context->buffered->nb_samples = context->context->frame_size;
ret = av_frame_get_buffer(context->buffered, 1);
if (ret < 0)
goto fail;
}
context->isOpen = TRUE;
return TRUE;
fail:
ffmpeg_close_context(context);
return FALSE;
}
#if defined(SWRESAMPLE_FOUND)
static BOOL ffmpeg_resample_frame(SwrContext* WINPR_RESTRICT context, AVFrame* WINPR_RESTRICT in,
AVFrame* WINPR_RESTRICT out)
{
int ret = 0;
if (!swr_is_initialized(context))
{
if ((ret = swr_config_frame(context, out, in)) < 0)
{
const char* err = av_err2str(ret);
WLog_ERR(TAG, "Error during resampling %s [%d]", err, ret);
return FALSE;
}
if ((ret = (swr_init(context))) < 0)
{
const char* err = av_err2str(ret);
WLog_ERR(TAG, "Error during resampling %s [%d]", err, ret);
return FALSE;
}
}
if ((ret = swr_convert_frame(context, out, in)) < 0)
{
const char* err = av_err2str(ret);
WLog_ERR(TAG, "Error during resampling %s [%d]", err, ret);
return FALSE;
}
return TRUE;
}
#else
static BOOL ffmpeg_resample_frame(AVAudioResampleContext* WINPR_RESTRICT context,
AVFrame* WINPR_RESTRICT in, AVFrame* WINPR_RESTRICT out)
{
int ret;
if (!avresample_is_open(context))
{
if ((ret = avresample_config(context, out, in)) < 0)
{
const char* err = av_err2str(ret);
WLog_ERR(TAG, "Error during resampling %s [%d]", err, ret);
return FALSE;
}
if ((ret = (avresample_open(context))) < 0)
{
const char* err = av_err2str(ret);
WLog_ERR(TAG, "Error during resampling %s [%d]", err, ret);
return FALSE;
}
}
if ((ret = avresample_convert_frame(context, out, in)) < 0)
{
const char* err = av_err2str(ret);
WLog_ERR(TAG, "Error during resampling %s [%d]", err, ret);
return FALSE;
}
return TRUE;
}
#endif
static BOOL ffmpeg_encode_frame(AVCodecContext* WINPR_RESTRICT context, AVFrame* WINPR_RESTRICT in,
AVPacket* WINPR_RESTRICT packet, wStream* WINPR_RESTRICT out)
{
if (in->format == AV_SAMPLE_FMT_FLTP)
{
uint8_t** pp = in->extended_data;
#if LIBAVUTIL_VERSION_INT < AV_VERSION_INT(57, 28, 100)
const int nr_channels = in->channels;
#else
const int nr_channels = in->ch_layout.nb_channels;
#endif
for (int y = 0; y < nr_channels; y++)
{
float* data = (float*)pp[y];
for (int x = 0; x < in->nb_samples; x++)
{
const float val1 = data[x];
if (isnan(val1))
data[x] = 0.0f;
else if (isinf(val1))
{
if (val1 < 0.0f)
data[x] = -1.0f;
else
data[x] = 1.0f;
}
}
}
}
/* send the packet with the compressed data to the encoder */
int ret = avcodec_send_frame(context, in);
if (ret < 0)
{
const char* err = av_err2str(ret);
// Ignore errors: AAC encoder sometimes returns -22
// The log message from ffmpeg is '[aac @ 0x7f140db753c0] Input contains (near) NaN/+-Inf'
if (ret == AVERROR(EINVAL))
{
WLog_DBG(TAG, "Error submitting the packet to the encoder %s [%d], ignoring", err, ret);
return TRUE;
}
WLog_ERR(TAG, "Error submitting the packet to the encoder %s [%d]", err, ret);
return FALSE;
}
/* read all the output frames (in general there may be any number of them */
while (TRUE)
{
ret = avcodec_receive_packet(context, packet);
if ((ret == AVERROR(EAGAIN)) || (ret == AVERROR_EOF))
break;
if (ret < 0)
{
const char* err = av_err2str(ret);
WLog_ERR(TAG, "Error during encoding %s [%d]", err, ret);
return FALSE;
}
WINPR_ASSERT(packet->size >= 0);
if (!Stream_EnsureRemainingCapacity(out, (size_t)packet->size))
return FALSE;
Stream_Write(out, packet->data, (size_t)packet->size);
av_packet_unref(packet);
}
return TRUE;
}
static BOOL ffmpeg_fill_frame(AVFrame* WINPR_RESTRICT frame,
const AUDIO_FORMAT* WINPR_RESTRICT inputFormat,
const BYTE* WINPR_RESTRICT data, size_t size)
{
int ret = 0;
#if LIBAVUTIL_VERSION_INT < AV_VERSION_INT(57, 28, 100)
frame->channels = inputFormat->nChannels;
frame->channel_layout = av_get_default_channel_layout(frame->channels);
#else
av_channel_layout_default(&frame->ch_layout, inputFormat->nChannels);
#endif
WINPR_ASSERT(inputFormat->nSamplesPerSec <= INT_MAX);
frame->sample_rate = (int)inputFormat->nSamplesPerSec;
frame->format = ffmpeg_sample_format(inputFormat);
const int bpp =
av_get_bytes_per_sample(WINPR_ASSERTING_INT_CAST(enum AVSampleFormat, frame->format));
WINPR_ASSERT(bpp >= 0);
WINPR_ASSERT(size <= INT_MAX);
const size_t nb_samples = size / inputFormat->nChannels / (size_t)bpp;
frame->nb_samples = (int)nb_samples;
if ((ret = avcodec_fill_audio_frame(
frame, inputFormat->nChannels,
WINPR_ASSERTING_INT_CAST(enum AVSampleFormat, frame->format), data, (int)size, 1)) < 0)
{
const char* err = av_err2str(ret);
WLog_ERR(TAG, "Error during audio frame fill %s [%d]", err, ret);
return FALSE;
}
return TRUE;
}
#if defined(SWRESAMPLE_FOUND)
static BOOL ffmpeg_decode(AVCodecContext* WINPR_RESTRICT dec_ctx, AVPacket* WINPR_RESTRICT pkt,
AVFrame* WINPR_RESTRICT frame, SwrContext* WINPR_RESTRICT resampleContext,
AVFrame* WINPR_RESTRICT resampled, wStream* WINPR_RESTRICT out)
#else
static BOOL ffmpeg_decode(AVCodecContext* dec_ctx, AVPacket* pkt, AVFrame* frame,
AVAudioResampleContext* resampleContext, AVFrame* resampled, wStream* out)
#endif
{
/* send the packet with the compressed data to the decoder */
int ret = avcodec_send_packet(dec_ctx, pkt);
if (ret < 0)
{
const char* err = av_err2str(ret);
WLog_ERR(TAG, "Error submitting the packet to the decoder %s [%d]", err, ret);
return FALSE;
}
/* read all the output frames (in general there may be any number of them */
while (ret >= 0)
{
ret = avcodec_receive_frame(dec_ctx, frame);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
break;
if (ret < 0)
{
const char* err = av_err2str(ret);
WLog_ERR(TAG, "Error during decoding %s [%d]", err, ret);
return FALSE;
}
#if defined(SWRESAMPLE_FOUND)
if (!swr_is_initialized(resampleContext))
{
if ((ret = swr_config_frame(resampleContext, resampled, frame)) < 0)
{
#else
if (!avresample_is_open(resampleContext))
{
if ((ret = avresample_config(resampleContext, resampled, frame)) < 0)
{
#endif
const char* err = av_err2str(ret);
WLog_ERR(TAG, "Error during resampling %s [%d]", err, ret);
return FALSE;
}
#if defined(SWRESAMPLE_FOUND)
ret = (swr_init(resampleContext));
#else
ret = (avresample_open(resampleContext));
#endif
if (ret < 0)
{
const char* err = av_err2str(ret);
WLog_ERR(TAG, "Error during resampling %s [%d]", err, ret);
return FALSE;
}
}
#if defined(SWRESAMPLE_FOUND)
ret = swr_convert_frame(resampleContext, resampled, frame);
#else
ret = avresample_convert_frame(resampleContext, resampled, frame);
#endif
if (ret < 0)
{
const char* err = av_err2str(ret);
WLog_ERR(TAG, "Error during resampling %s [%d]", err, ret);
return FALSE;
}
{
#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(57, 28, 100)
WINPR_ASSERT(resampled->ch_layout.nb_channels >= 0);
const size_t nrchannels = (size_t)resampled->ch_layout.nb_channels;
#else
const size_t nrchannels = resampled->channels;
#endif
WINPR_ASSERT(resampled->nb_samples >= 0);
const size_t data_size = nrchannels * (size_t)resampled->nb_samples * 2ull;
if (!Stream_EnsureRemainingCapacity(out, data_size))
return FALSE;
Stream_Write(out, resampled->data[0], data_size);
}
}
return TRUE;
}
BOOL freerdp_dsp_ffmpeg_supports_format(const AUDIO_FORMAT* WINPR_RESTRICT format, BOOL encode)
{
enum AVCodecID id = ffmpeg_get_avcodec(format);
if (ffmpeg_codec_is_filtered(id, encode))
return FALSE;
if (encode)
return avcodec_find_encoder(id) != nullptr;
else
return avcodec_find_decoder(id) != nullptr;
}
FREERDP_DSP_CONTEXT* freerdp_dsp_ffmpeg_context_new(BOOL encode)
{
FREERDP_DSP_CONTEXT* context = nullptr;
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 10, 100)
avcodec_register_all();
#endif
context = calloc(1, sizeof(FREERDP_DSP_CONTEXT));
if (!context)
goto fail;
if (!freerdp_dsp_common_context_init(&context->common, encode))
goto fail;
return context;
fail:
WINPR_PRAGMA_DIAG_PUSH
WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
freerdp_dsp_ffmpeg_context_free(context);
WINPR_PRAGMA_DIAG_POP
return nullptr;
}
void freerdp_dsp_ffmpeg_context_free(FREERDP_DSP_CONTEXT* context)
{
if (context)
{
ffmpeg_close_context(context);
freerdp_dsp_common_context_uninit(&context->common);
free(context);
}
}
BOOL freerdp_dsp_ffmpeg_context_reset(FREERDP_DSP_CONTEXT* WINPR_RESTRICT context,
const AUDIO_FORMAT* WINPR_RESTRICT targetFormat)
{
if (!context || !targetFormat)
return FALSE;
ffmpeg_close_context(context);
context->common.format = *targetFormat;
return ffmpeg_open_context(context);
}
static BOOL freerdp_dsp_channel_mix(FREERDP_DSP_CONTEXT* WINPR_RESTRICT context,
const BYTE* WINPR_RESTRICT src, size_t size,
const AUDIO_FORMAT* WINPR_RESTRICT srcFormat,
const BYTE** WINPR_RESTRICT data, size_t* WINPR_RESTRICT length,
AUDIO_FORMAT* WINPR_RESTRICT dstFormat)
{
UINT32 bpp = 0;
size_t samples = 0;
if (!context || !data || !length || !dstFormat)
return FALSE;
if (srcFormat->wFormatTag != WAVE_FORMAT_PCM)
return FALSE;
bpp = srcFormat->wBitsPerSample > 8 ? 2 : 1;
samples = size / bpp / srcFormat->nChannels;
*dstFormat = *srcFormat;
if (context->common.format.nChannels == srcFormat->nChannels)
{
*data = src;
*length = size;
return TRUE;
}
Stream_ResetPosition(context->common.channelmix);
/* Destination has more channels than source */
if (context->common.format.nChannels > srcFormat->nChannels)
{
switch (srcFormat->nChannels)
{
case 1:
if (!Stream_EnsureCapacity(context->common.channelmix, size * 2))
return FALSE;
for (size_t x = 0; x < samples; x++)
{
for (size_t y = 0; y < bpp; y++)
Stream_Write_UINT8(context->common.channelmix, src[x * bpp + y]);
for (size_t y = 0; y < bpp; y++)
Stream_Write_UINT8(context->common.channelmix, src[x * bpp + y]);
}
Stream_SealLength(context->common.channelmix);
*data = Stream_Buffer(context->common.channelmix);
*length = Stream_Length(context->common.channelmix);
dstFormat->nChannels = 2;
return TRUE;
case 2: /* We only support stereo, so we can not handle this case. */
default: /* Unsupported number of channels */
WLog_WARN(TAG, "[%s] unsupported source channel count %" PRIu16, __func__,
srcFormat->nChannels);
return FALSE;
}
}
/* Destination has less channels than source */
switch (srcFormat->nChannels)
{
case 2:
if (!Stream_EnsureCapacity(context->common.channelmix, size / 2))
return FALSE;
/* Simply drop second channel.
* TODO: Calculate average */
for (size_t x = 0; x < samples; x++)
{
for (size_t y = 0; y < bpp; y++)
Stream_Write_UINT8(context->common.channelmix, src[2 * x * bpp + y]);
}
Stream_SealLength(context->common.channelmix);
*data = Stream_Buffer(context->common.channelmix);
*length = Stream_Length(context->common.channelmix);
dstFormat->nChannels = 1;
return TRUE;
case 1: /* Invalid, do we want to use a 0 channel sound? */
default: /* Unsupported number of channels */
WLog_WARN(TAG, "[%s] unsupported channel count %" PRIu16, __func__,
srcFormat->nChannels);
return FALSE;
}
return FALSE;
}
BOOL freerdp_dsp_ffmpeg_encode(FREERDP_DSP_CONTEXT* WINPR_RESTRICT context,
const AUDIO_FORMAT* WINPR_RESTRICT format,
const BYTE* WINPR_RESTRICT sdata, size_t length,
wStream* WINPR_RESTRICT out)
{
AUDIO_FORMAT fmt = WINPR_C_ARRAY_INIT;
if (!context || !format || !sdata || !out || !context->common.encoder)
return FALSE;
/* https://github.com/FreeRDP/FreeRDP/issues/7607
*
* we get noisy data with channel transformation, so do it ourselves.
*/
const BYTE* data = nullptr;
if (!freerdp_dsp_channel_mix(context, sdata, length, format, &data, &length, &fmt))
return FALSE;
/* Create input frame */
if (!ffmpeg_fill_frame(context->frame, format, data, length))
return FALSE;
ffmpeg_setup_resample_frame(context, format);
/* Resample to desired format. */
if (!ffmpeg_resample_frame(context->rcontext, context->frame, context->resampled))
return FALSE;
if (context->context->frame_size <= 0)
{
return ffmpeg_encode_frame(context->context, context->resampled, context->packet, out);
}
else
{
int copied = 0;
int rest = context->resampled->nb_samples;
do
{
int inSamples = rest;
if ((inSamples < 0) || (context->bufferedSamples > (UINT32)(INT_MAX - inSamples)))
return FALSE;
if (inSamples + (int)context->bufferedSamples > context->context->frame_size)
inSamples = context->context->frame_size - (int)context->bufferedSamples;
#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(57, 28, 100)
const int nrchannels = context->context->ch_layout.nb_channels;
#else
const int nrchannels = context->context->channels;
#endif
const int rc =
av_samples_copy(context->buffered->extended_data, context->resampled->extended_data,
(int)context->bufferedSamples, copied, inSamples, nrchannels,
context->context->sample_fmt);
if (rc < 0)
return FALSE;
rest -= inSamples;
copied += inSamples;
context->bufferedSamples += (UINT32)inSamples;
if (context->context->frame_size <= (int)context->bufferedSamples)
{
/* Encode in desired format. */
if (!ffmpeg_encode_frame(context->context, context->buffered, context->packet, out))
return FALSE;
context->bufferedSamples = 0;
}
} while (rest > 0);
return TRUE;
}
}
BOOL freerdp_dsp_ffmpeg_decode(FREERDP_DSP_CONTEXT* WINPR_RESTRICT context,
const AUDIO_FORMAT* WINPR_RESTRICT srcFormat,
const BYTE* WINPR_RESTRICT data, size_t length,
wStream* WINPR_RESTRICT out)
{
if (!context || !srcFormat || !data || !out || context->common.encoder)
return FALSE;
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 133, 100)
av_init_packet(context->packet);
#endif
context->packet->data = WINPR_CAST_CONST_PTR_AWAY(data, uint8_t*);
WINPR_ASSERT(length <= INT_MAX);
context->packet->size = (int)length;
return ffmpeg_decode(context->context, context->packet, context->frame, context->rcontext,
context->resampled, out);
}
+57
View File
@@ -0,0 +1,57 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Digital Sound Processing - FFMPEG backend
*
* Copyright 2018 Armin Novak <armin.novak@thincast.com>
* Copyright 2018 Thincast Technologies GmbH
*
* 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 FREERDP_LIB_CODEC_DSP_FFMPEG_H
#define FREERDP_LIB_CODEC_DSP_FFMPEG_H
#include <freerdp/api.h>
#include <freerdp/codec/audio.h>
#include <freerdp/codec/dsp.h>
#include <libavcodec/version.h>
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(57, 48, 101)
#error \
"DSP module requires libavcodec version >= 57.48.101. Upgrade or set WITH_DSP_FFMPEG=OFF to continue"
#endif
FREERDP_LOCAL void freerdp_dsp_ffmpeg_context_free(FREERDP_DSP_CONTEXT* context);
WINPR_ATTR_MALLOC(freerdp_dsp_ffmpeg_context_free, 1)
WINPR_ATTR_NODISCARD
FREERDP_LOCAL FREERDP_DSP_CONTEXT* freerdp_dsp_ffmpeg_context_new(BOOL encode);
WINPR_ATTR_NODISCARD FREERDP_LOCAL BOOL
freerdp_dsp_ffmpeg_supports_format(const AUDIO_FORMAT* format, BOOL encode);
WINPR_ATTR_NODISCARD FREERDP_LOCAL BOOL freerdp_dsp_ffmpeg_encode(FREERDP_DSP_CONTEXT* context,
const AUDIO_FORMAT* srcFormat,
const BYTE* data, size_t length,
wStream* out);
WINPR_ATTR_NODISCARD FREERDP_LOCAL BOOL freerdp_dsp_ffmpeg_decode(FREERDP_DSP_CONTEXT* context,
const AUDIO_FORMAT* srcFormat,
const BYTE* data, size_t length,
wStream* out);
WINPR_ATTR_NODISCARD FREERDP_LOCAL BOOL
freerdp_dsp_ffmpeg_context_reset(FREERDP_DSP_CONTEXT* context, const AUDIO_FORMAT* targetFormat);
#endif /* FREERDP_LIB_CODEC_DSP_FFMPEG_H */
+895
View File
@@ -0,0 +1,895 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* H.264 Bitmap Compression
*
* Copyright 2014 Mike McDonald <Mike.McDonald@software.dell.com>
* Copyright 2017 David Fort <contact@hardening-consulting.com>
*
* 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 <freerdp/config.h>
#include <winpr/crt.h>
#include <winpr/print.h>
#include <winpr/library.h>
#include <winpr/bitstream.h>
#include <winpr/synch.h>
#include <freerdp/primitives.h>
#include <freerdp/codec/h264.h>
#include <freerdp/codec/yuv.h>
#include <freerdp/log.h>
#include "h264.h"
#define TAG FREERDP_TAG("codec")
static BOOL avc444_ensure_buffer(H264_CONTEXT* h264, DWORD nDstHeight);
static BOOL yuv_ensure_buffer(H264_CONTEXT* h264, UINT32 stride, UINT32 width, UINT32 height)
{
BOOL isNull = FALSE;
UINT32 pheight = height;
if (!h264)
return FALSE;
if (stride == 0)
stride = width;
if (stride % 16 != 0)
stride += 16 - stride % 16;
if (pheight % 16 != 0)
pheight += 16 - pheight % 16;
const size_t nPlanes = h264->hwAccel ? 2 : 3;
for (size_t x = 0; x < nPlanes; x++)
{
if (!h264->pYUVData[x] || !h264->pOldYUVData[x])
isNull = TRUE;
}
if (pheight == 0)
return FALSE;
if (stride == 0)
return FALSE;
if (isNull || (width != h264->width) || (height != h264->height) ||
(stride != h264->iStride[0]))
{
if (h264->hwAccel) /* NV12 */
{
h264->iStride[0] = stride;
h264->iStride[1] = stride;
h264->iStride[2] = 0;
}
else /* I420 */
{
h264->iStride[0] = stride;
h264->iStride[1] = (stride + 1) / 2;
h264->iStride[2] = (stride + 1) / 2;
}
h264->width = width;
h264->height = height;
for (size_t x = 0; x < nPlanes; x++)
{
BYTE* tmp1 = winpr_aligned_recalloc(h264->pYUVData[x], h264->iStride[x], pheight, 16);
BYTE* tmp2 =
winpr_aligned_recalloc(h264->pOldYUVData[x], h264->iStride[x], pheight, 16);
if (tmp1)
h264->pYUVData[x] = tmp1;
if (tmp2)
h264->pOldYUVData[x] = tmp2;
if (!tmp1 || !tmp2)
return FALSE;
}
}
return TRUE;
}
BOOL avc420_ensure_buffer(H264_CONTEXT* h264, UINT32 stride, UINT32 width, UINT32 height)
{
return yuv_ensure_buffer(h264, stride, width, height);
}
static BOOL isRectValid(UINT32 width, UINT32 height, const RECTANGLE_16* rect)
{
WINPR_ASSERT(rect);
if (rect->left > width)
return FALSE;
if (rect->right > width)
return FALSE;
if (rect->left >= rect->right)
return FALSE;
if (rect->top > height)
return FALSE;
if (rect->bottom > height)
return FALSE;
if (rect->top >= rect->bottom)
return FALSE;
return TRUE;
}
static BOOL areRectsValid(UINT32 width, UINT32 height, const RECTANGLE_16* rects, UINT32 count)
{
WINPR_ASSERT(rects || (count == 0));
for (size_t x = 0; x < count; x++)
{
const RECTANGLE_16* rect = &rects[x];
if (!isRectValid(width, height, rect))
return FALSE;
}
return TRUE;
}
INT32 avc420_decompress(H264_CONTEXT* h264, const BYTE* pSrcData, UINT32 SrcSize, BYTE* pDstData,
DWORD DstFormat, UINT32 nDstStep, WINPR_ATTR_UNUSED UINT32 nDstWidth,
WINPR_ATTR_UNUSED UINT32 nDstHeight, const RECTANGLE_16* regionRects,
UINT32 numRegionRects)
{
int status = 0;
const BYTE* pYUVData[3];
if (!h264 || h264->Compressor)
return -1001;
if (!areRectsValid(nDstWidth, nDstHeight, regionRects, numRegionRects))
return -1013;
status = h264->subsystem->Decompress(h264, pSrcData, SrcSize);
if (status == 0)
return 1;
if (status < 0)
return status;
pYUVData[0] = h264->pYUVData[0];
pYUVData[1] = h264->pYUVData[1];
pYUVData[2] = h264->pYUVData[2];
if (!yuv420_context_decode(h264->yuv, pYUVData, h264->iStride, h264->height, DstFormat,
pDstData, nDstStep, regionRects, numRegionRects))
return -1002;
return 1;
}
static BOOL allocate_h264_metablock(UINT32 QP, RECTANGLE_16* rectangles,
RDPGFX_H264_METABLOCK* meta, size_t count)
{
/* [MS-RDPEGFX] 2.2.4.4.2 RDPGFX_AVC420_QUANT_QUALITY */
if (!meta || (QP > UINT8_MAX))
{
free(rectangles);
return FALSE;
}
meta->regionRects = rectangles;
if (count == 0)
return TRUE;
if (count > UINT32_MAX)
return FALSE;
meta->quantQualityVals = calloc(count, sizeof(RDPGFX_H264_QUANT_QUALITY));
if (!meta->quantQualityVals || !meta->regionRects)
return FALSE;
meta->numRegionRects = (UINT32)count;
for (size_t x = 0; x < count; x++)
{
RDPGFX_H264_QUANT_QUALITY* cur = &meta->quantQualityVals[x];
cur->qp = (UINT8)QP;
/* qpVal bit 6 and 7 are flags, so mask them out here.
* qualityVal is [0-100] so 100 - qpVal [0-64] is always in range */
cur->qualityVal = 100 - (QP & 0x3F);
}
return TRUE;
}
static inline BOOL diff_tile(const RECTANGLE_16* regionRect, BYTE* pYUVData[3],
BYTE* pOldYUVData[3], UINT32 const iStride[3])
{
size_t size = 0;
if (!regionRect || !pYUVData || !pOldYUVData || !iStride)
return FALSE;
size = regionRect->right - regionRect->left;
if (regionRect->right > iStride[0])
return FALSE;
if (regionRect->right / 2u > iStride[1])
return FALSE;
if (regionRect->right / 2u > iStride[2])
return FALSE;
for (size_t y = regionRect->top; y < regionRect->bottom; y++)
{
const BYTE* cur0 = &pYUVData[0][y * iStride[0]];
const BYTE* cur1 = &pYUVData[1][y * iStride[1]];
const BYTE* cur2 = &pYUVData[2][y * iStride[2]];
const BYTE* old0 = &pOldYUVData[0][y * iStride[0]];
const BYTE* old1 = &pOldYUVData[1][y * iStride[1]];
const BYTE* old2 = &pOldYUVData[2][y * iStride[2]];
if (memcmp(&cur0[regionRect->left], &old0[regionRect->left], size) != 0)
return TRUE;
if (memcmp(&cur1[regionRect->left / 2], &old1[regionRect->left / 2], size / 2) != 0)
return TRUE;
if (memcmp(&cur2[regionRect->left / 2], &old2[regionRect->left / 2], size / 2) != 0)
return TRUE;
}
return FALSE;
}
static BOOL detect_changes(BOOL firstFrameDone, const UINT32 QP, const RECTANGLE_16* regionRect,
BYTE* pYUVData[3], BYTE* pOldYUVData[3], UINT32 const iStride[3],
RDPGFX_H264_METABLOCK* meta)
{
size_t count = 0;
size_t wc = 0;
size_t hc = 0;
RECTANGLE_16* rectangles = nullptr;
if (!regionRect || !pYUVData || !pOldYUVData || !iStride || !meta)
return FALSE;
wc = (regionRect->right - regionRect->left) / 64 + 1;
hc = (regionRect->bottom - regionRect->top) / 64 + 1;
rectangles = calloc(wc * hc, sizeof(RECTANGLE_16));
if (!rectangles)
return FALSE;
if (!firstFrameDone)
{
rectangles[0] = *regionRect;
count = 1;
}
else
{
for (size_t y = regionRect->top; y < regionRect->bottom; y += 64)
{
for (size_t x = regionRect->left; x < regionRect->right; x += 64)
{
RECTANGLE_16 rect;
rect.left = (UINT16)MIN(UINT16_MAX, regionRect->left + x);
rect.top = (UINT16)MIN(UINT16_MAX, regionRect->top + y);
rect.right =
(UINT16)MIN(UINT16_MAX, MIN(regionRect->left + x + 64, regionRect->right));
rect.bottom =
(UINT16)MIN(UINT16_MAX, MIN(regionRect->top + y + 64, regionRect->bottom));
if (diff_tile(&rect, pYUVData, pOldYUVData, iStride))
rectangles[count++] = rect;
}
}
}
if (!allocate_h264_metablock(QP, rectangles, meta, count))
return FALSE;
return TRUE;
}
INT32 h264_get_yuv_buffer(H264_CONTEXT* h264, UINT32 nSrcStride, UINT32 nSrcWidth,
UINT32 nSrcHeight, BYTE* YUVData[3], UINT32 stride[3])
{
if (!h264 || !h264->Compressor || !h264->subsystem || !h264->subsystem->Compress)
return -1;
if (!yuv_ensure_buffer(h264, nSrcStride, nSrcWidth, nSrcHeight))
return -1;
for (size_t x = 0; x < 3; x++)
{
YUVData[x] = h264->pYUVData[x];
stride[x] = h264->iStride[x];
}
return 0;
}
INT32 h264_compress(H264_CONTEXT* h264, BYTE** ppDstData, UINT32* pDstSize)
{
if (!h264 || !h264->Compressor || !h264->subsystem || !h264->subsystem->Compress)
return -1;
const BYTE* pcYUVData[3] = { h264->pYUVData[0], h264->pYUVData[1], h264->pYUVData[2] };
return h264->subsystem->Compress(h264, pcYUVData, h264->iStride, ppDstData, pDstSize);
}
INT32 avc420_compress(H264_CONTEXT* h264, const BYTE* pSrcData, DWORD SrcFormat, UINT32 nSrcStep,
UINT32 nSrcWidth, UINT32 nSrcHeight, const RECTANGLE_16* regionRect,
BYTE** ppDstData, UINT32* pDstSize, RDPGFX_H264_METABLOCK* meta)
{
INT32 rc = -1;
BYTE* pYUVData[3] = WINPR_C_ARRAY_INIT;
const BYTE* pcYUVData[3] = WINPR_C_ARRAY_INIT;
BYTE* pOldYUVData[3] = WINPR_C_ARRAY_INIT;
if (!h264 || !regionRect || !meta || !h264->Compressor)
return -1;
if (!h264->subsystem->Compress)
return -1;
if (!avc420_ensure_buffer(h264, nSrcStep, nSrcWidth, nSrcHeight))
return -1;
if (h264->encodingBuffer)
{
for (size_t x = 0; x < 3; x++)
{
pYUVData[x] = h264->pYUVData[x];
pOldYUVData[x] = h264->pOldYUVData[x];
}
}
else
{
for (size_t x = 0; x < 3; x++)
{
pYUVData[x] = h264->pOldYUVData[x];
pOldYUVData[x] = h264->pYUVData[x];
}
}
h264->encodingBuffer = !h264->encodingBuffer;
if (!yuv420_context_encode(h264->yuv, pSrcData, nSrcStep, SrcFormat, h264->iStride, pYUVData,
regionRect, 1))
goto fail;
if (!detect_changes(h264->firstLumaFrameDone, h264->QP, regionRect, pYUVData, pOldYUVData,
h264->iStride, meta))
goto fail;
if (meta->numRegionRects == 0)
{
rc = 0;
goto fail;
}
for (size_t x = 0; x < 3; x++)
pcYUVData[x] = pYUVData[x];
rc = h264->subsystem->Compress(h264, pcYUVData, h264->iStride, ppDstData, pDstSize);
if (rc >= 0)
h264->firstLumaFrameDone = TRUE;
fail:
if (rc < 0)
free_h264_metablock(meta);
return rc;
}
INT32 avc444_compress(H264_CONTEXT* h264, const BYTE* pSrcData, DWORD SrcFormat, UINT32 nSrcStep,
UINT32 nSrcWidth, UINT32 nSrcHeight, BYTE version, const RECTANGLE_16* region,
BYTE* op, BYTE** ppDstData, UINT32* pDstSize, BYTE** ppAuxDstData,
UINT32* pAuxDstSize, RDPGFX_H264_METABLOCK* meta,
RDPGFX_H264_METABLOCK* auxMeta)
{
int rc = -1;
BYTE* coded = nullptr;
UINT32 codedSize = 0;
BYTE** pYUV444Data = nullptr;
BYTE** pOldYUV444Data = nullptr;
BYTE** pYUVData = nullptr;
BYTE** pOldYUVData = nullptr;
if (!h264 || !h264->Compressor)
return -1;
if (!h264->subsystem->Compress)
return -1;
if (!avc420_ensure_buffer(h264, nSrcStep, nSrcWidth, nSrcHeight))
return -1;
if (!avc444_ensure_buffer(h264, nSrcHeight))
return -1;
if (h264->encodingBuffer)
{
pYUV444Data = h264->pOldYUV444Data;
pOldYUV444Data = h264->pYUV444Data;
pYUVData = h264->pOldYUVData;
pOldYUVData = h264->pYUVData;
}
else
{
pYUV444Data = h264->pYUV444Data;
pOldYUV444Data = h264->pOldYUV444Data;
pYUVData = h264->pYUVData;
pOldYUVData = h264->pOldYUVData;
}
h264->encodingBuffer = !h264->encodingBuffer;
if (!yuv444_context_encode(h264->yuv, version, pSrcData, nSrcStep, SrcFormat, h264->iStride,
pYUV444Data, pYUVData, region, 1))
goto fail;
if (!detect_changes(h264->firstLumaFrameDone, h264->QP, region, pYUV444Data, pOldYUV444Data,
h264->iStride, meta))
goto fail;
if (!detect_changes(h264->firstChromaFrameDone, h264->QP, region, pYUVData, pOldYUVData,
h264->iStride, auxMeta))
goto fail;
/* [MS-RDPEGFX] 2.2.4.5 RFX_AVC444_BITMAP_STREAM
* LC:
* 0 ... Luma & Chroma
* 1 ... Luma
* 2 ... Chroma
*/
if ((meta->numRegionRects > 0) && (auxMeta->numRegionRects > 0))
*op = 0;
else if (meta->numRegionRects > 0)
*op = 1;
else if (auxMeta->numRegionRects > 0)
*op = 2;
else
{
WLog_INFO(TAG, "no changes detected for luma or chroma frame");
rc = 0;
goto fail;
}
if ((*op == 0) || (*op == 1))
{
const BYTE* pcYUV444Data[3] = { pYUV444Data[0], pYUV444Data[1], pYUV444Data[2] };
if (h264->subsystem->Compress(h264, pcYUV444Data, h264->iStride, &coded, &codedSize) < 0)
goto fail;
h264->firstLumaFrameDone = TRUE;
memcpy(h264->lumaData, coded, codedSize);
*ppDstData = h264->lumaData;
*pDstSize = codedSize;
}
if ((*op == 0) || (*op == 2))
{
const BYTE* pcYUVData[3] = { pYUVData[0], pYUVData[1], pYUVData[2] };
if (h264->subsystem->Compress(h264, pcYUVData, h264->iStride, &coded, &codedSize) < 0)
goto fail;
h264->firstChromaFrameDone = TRUE;
*ppAuxDstData = coded;
*pAuxDstSize = codedSize;
}
rc = 1;
fail:
if (rc < 0)
{
free_h264_metablock(meta);
free_h264_metablock(auxMeta);
}
return rc;
}
static BOOL avc444_ensure_buffer(H264_CONTEXT* h264, DWORD nDstHeight)
{
WINPR_ASSERT(h264);
const UINT32* piMainStride = h264->iStride;
UINT32* piDstSize = h264->iYUV444Size;
UINT32* piDstStride = h264->iYUV444Stride;
BYTE** ppYUVDstData = h264->pYUV444Data;
BYTE** ppOldYUVDstData = h264->pOldYUV444Data;
nDstHeight = MAX(h264->height, nDstHeight);
const UINT32 pad = nDstHeight % 16;
UINT32 padDstHeight = nDstHeight; /* Need alignment to 16x16 blocks */
if (pad != 0)
padDstHeight += 16 - pad;
if ((piMainStride[0] != piDstStride[0]) ||
(piDstSize[0] != 1ull * piMainStride[0] * padDstHeight))
{
for (UINT32 x = 0; x < 3; x++)
{
piDstStride[x] = piMainStride[0];
piDstSize[x] = piDstStride[x] * padDstHeight;
if (piDstSize[x] == 0)
return FALSE;
BYTE* tmp1 = winpr_aligned_recalloc(ppYUVDstData[x], piDstSize[x], 1, 16);
if (!tmp1)
return FALSE;
ppYUVDstData[x] = tmp1;
BYTE* tmp2 = winpr_aligned_recalloc(ppOldYUVDstData[x], piDstSize[x], 1, 16);
if (!tmp2)
return FALSE;
ppOldYUVDstData[x] = tmp2;
}
{
BYTE* tmp = winpr_aligned_recalloc(h264->lumaData, piDstSize[0], 4, 16);
if (!tmp)
goto fail;
h264->lumaData = tmp;
}
}
for (UINT32 x = 0; x < 3; x++)
{
if (!ppOldYUVDstData[x] || !ppYUVDstData[x] || (piDstSize[x] == 0) || (piDstStride[x] == 0))
{
WLog_Print(h264->log, WLOG_ERROR,
"YUV buffer not initialized! check your decoder settings");
goto fail;
}
}
if (!h264->lumaData)
goto fail;
return TRUE;
fail:
return FALSE;
}
static BOOL avc444_process_rects(H264_CONTEXT* h264, const BYTE* pSrcData, UINT32 SrcSize,
BYTE* pDstData, UINT32 DstFormat, UINT32 nDstStep,
WINPR_ATTR_UNUSED UINT32 nDstWidth, UINT32 nDstHeight,
const RECTANGLE_16* rects, UINT32 nrRects, avc444_frame_type type)
{
const BYTE* pYUVData[3];
BYTE* pYUVDstData[3];
UINT32* piDstStride = h264->iYUV444Stride;
BYTE** ppYUVDstData = h264->pYUV444Data;
const UINT32* piStride = h264->iStride;
if (h264->subsystem->Decompress(h264, pSrcData, SrcSize) < 0)
return FALSE;
pYUVData[0] = h264->pYUVData[0];
pYUVData[1] = h264->pYUVData[1];
pYUVData[2] = h264->pYUVData[2];
if (!avc444_ensure_buffer(h264, nDstHeight))
return FALSE;
pYUVDstData[0] = ppYUVDstData[0];
pYUVDstData[1] = ppYUVDstData[1];
pYUVDstData[2] = ppYUVDstData[2];
return (yuv444_context_decode(h264->yuv, (BYTE)type, pYUVData, piStride, h264->height,
pYUVDstData, piDstStride, DstFormat, pDstData, nDstStep, rects,
nrRects));
}
#if defined(AVC444_FRAME_STAT)
static UINT64 op1 = 0;
static double op1sum = 0;
static UINT64 op2 = 0;
static double op2sum = 0;
static UINT64 op3 = 0;
static double op3sum = 0;
static double avg(UINT64* count, double old, double size)
{
double tmp = size + *count * old;
(*count)++;
tmp = tmp / *count;
return tmp;
}
#endif
INT32 avc444_decompress(H264_CONTEXT* h264, BYTE op, const RECTANGLE_16* regionRects,
UINT32 numRegionRects, const BYTE* pSrcData, UINT32 SrcSize,
const RECTANGLE_16* auxRegionRects, UINT32 numAuxRegionRect,
const BYTE* pAuxSrcData, UINT32 AuxSrcSize, BYTE* pDstData, DWORD DstFormat,
UINT32 nDstStep, UINT32 nDstWidth, UINT32 nDstHeight, UINT32 codecId)
{
INT32 status = -1;
avc444_frame_type chroma =
(codecId == RDPGFX_CODECID_AVC444) ? AVC444_CHROMAv1 : AVC444_CHROMAv2;
if (!h264 || !regionRects || !pSrcData || !pDstData || h264->Compressor)
return -1001;
if (!areRectsValid(nDstWidth, nDstHeight, regionRects, numRegionRects))
return -1013;
if (!areRectsValid(nDstWidth, nDstHeight, auxRegionRects, numAuxRegionRect))
return -1014;
switch (op)
{
case 0: /* YUV420 in stream 1
* Chroma420 in stream 2 */
if (!avc444_process_rects(h264, pSrcData, SrcSize, pDstData, DstFormat, nDstStep,
nDstWidth, nDstHeight, regionRects, numRegionRects,
AVC444_LUMA))
status = -1;
else if (!avc444_process_rects(h264, pAuxSrcData, AuxSrcSize, pDstData, DstFormat,
nDstStep, nDstWidth, nDstHeight, auxRegionRects,
numAuxRegionRect, chroma))
status = -1;
else
status = 0;
break;
case 2: /* Chroma420 in stream 1 */
if (!avc444_process_rects(h264, pSrcData, SrcSize, pDstData, DstFormat, nDstStep,
nDstWidth, nDstHeight, regionRects, numRegionRects, chroma))
status = -1;
else
status = 0;
break;
case 1: /* YUV420 in stream 1 */
if (!avc444_process_rects(h264, pSrcData, SrcSize, pDstData, DstFormat, nDstStep,
nDstWidth, nDstHeight, regionRects, numRegionRects,
AVC444_LUMA))
status = -1;
else
status = 0;
break;
default: /* WTF? */
break;
}
#if defined(AVC444_FRAME_STAT)
switch (op)
{
case 0:
op1sum = avg(&op1, op1sum, SrcSize + AuxSrcSize);
break;
case 1:
op2sum = avg(&op2, op2sum, SrcSize);
break;
case 2:
op3sum = avg(&op3, op3sum, SrcSize);
break;
default:
break;
}
WLog_Print(h264->log, WLOG_INFO,
"luma=%" PRIu64 " [avg=%lf] chroma=%" PRIu64 " [avg=%lf] combined=%" PRIu64
" [avg=%lf]",
op1, op1sum, op2, op2sum, op3, op3sum);
#endif
return status;
}
#define MAX_SUBSYSTEMS 10
static INIT_ONCE subsystems_once = INIT_ONCE_STATIC_INIT;
static const H264_CONTEXT_SUBSYSTEM* subSystems[MAX_SUBSYSTEMS] = WINPR_C_ARRAY_INIT;
static BOOL CALLBACK h264_register_subsystems(WINPR_ATTR_UNUSED PINIT_ONCE once,
WINPR_ATTR_UNUSED PVOID param,
WINPR_ATTR_UNUSED PVOID* context)
{
int i = 0;
#ifdef WITH_MEDIACODEC
{
subSystems[i] = &g_Subsystem_mediacodec;
i++;
}
#endif
#if defined(_WIN32) && defined(WITH_MEDIA_FOUNDATION)
{
subSystems[i] = &g_Subsystem_MF;
i++;
}
#endif
#ifdef WITH_OPENH264
{
subSystems[i] = &g_Subsystem_OpenH264;
i++;
}
#endif
#ifdef WITH_VIDEO_FFMPEG
{
subSystems[i] = &g_Subsystem_libavcodec;
i++;
}
#endif
return i > 0;
}
static BOOL h264_context_init(H264_CONTEXT* h264)
{
if (!h264)
return FALSE;
h264->subsystem = nullptr;
if (!InitOnceExecuteOnce(&subsystems_once, h264_register_subsystems, nullptr, nullptr))
return FALSE;
for (size_t i = 0; i < MAX_SUBSYSTEMS; i++)
{
const H264_CONTEXT_SUBSYSTEM* subsystem = subSystems[i];
if (!subsystem || !subsystem->Init)
break;
if (subsystem->Init(h264))
{
h264->subsystem = subsystem;
return TRUE;
}
}
return FALSE;
}
BOOL h264_context_reset(H264_CONTEXT* h264, UINT32 width, UINT32 height)
{
if (!h264)
return FALSE;
h264->width = width;
h264->height = height;
if (h264->subsystem && h264->subsystem->Uninit)
h264->subsystem->Uninit(h264);
if (!h264_context_init(h264))
return FALSE;
return yuv_context_reset(h264->yuv, width, height);
}
H264_CONTEXT* h264_context_new(BOOL Compressor)
{
H264_CONTEXT* h264 = (H264_CONTEXT*)calloc(1, sizeof(H264_CONTEXT));
if (!h264)
return nullptr;
h264->log = WLog_Get(TAG);
if (!h264->log)
goto fail;
h264->Compressor = Compressor;
if (Compressor)
{
/* Default compressor settings, may be changed by caller */
h264->BitRate = 1000000;
h264->FrameRate = 30;
}
if (!h264_context_init(h264))
goto fail;
h264->yuv = yuv_context_new(Compressor, 0);
if (!h264->yuv)
goto fail;
return h264;
fail:
WINPR_PRAGMA_DIAG_PUSH
WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
h264_context_free(h264);
WINPR_PRAGMA_DIAG_POP
return nullptr;
}
void h264_context_free(H264_CONTEXT* h264)
{
if (h264)
{
if (h264->subsystem)
{
WINPR_ASSERT(h264->subsystem->Uninit);
h264->subsystem->Uninit(h264);
}
for (size_t x = 0; x < 3; x++)
{
if (h264->Compressor)
{
winpr_aligned_free(h264->pYUVData[x]);
winpr_aligned_free(h264->pOldYUVData[x]);
}
winpr_aligned_free(h264->pYUV444Data[x]);
winpr_aligned_free(h264->pOldYUV444Data[x]);
}
winpr_aligned_free(h264->lumaData);
yuv_context_free(h264->yuv);
free(h264);
}
}
void free_h264_metablock(RDPGFX_H264_METABLOCK* meta)
{
RDPGFX_H264_METABLOCK m = WINPR_C_ARRAY_INIT;
if (!meta)
return;
free(meta->quantQualityVals);
free(meta->regionRects);
*meta = m;
}
BOOL h264_context_set_option(H264_CONTEXT* h264, H264_CONTEXT_OPTION option, UINT32 value)
{
WINPR_ASSERT(h264);
switch (option)
{
case H264_CONTEXT_OPTION_BITRATE:
h264->BitRate = value;
return TRUE;
case H264_CONTEXT_OPTION_FRAMERATE:
h264->FrameRate = value;
return TRUE;
case H264_CONTEXT_OPTION_RATECONTROL:
{
switch (value)
{
case H264_RATECONTROL_VBR:
h264->RateControlMode = H264_RATECONTROL_VBR;
return TRUE;
case H264_RATECONTROL_CQP:
h264->RateControlMode = H264_RATECONTROL_CQP;
return TRUE;
default:
WLog_Print(h264->log, WLOG_WARN,
"Unknown H264_CONTEXT_OPTION_RATECONTROL value [0x%08" PRIx32 "]",
value);
return FALSE;
}
return TRUE;
}
case H264_CONTEXT_OPTION_QP:
h264->QP = value;
return TRUE;
case H264_CONTEXT_OPTION_USAGETYPE:
h264->UsageType = value;
return TRUE;
case H264_CONTEXT_OPTION_HW_ACCEL:
h264->hwAccel = (value);
return TRUE;
default:
WLog_Print(h264->log, WLOG_WARN, "Unknown H264_CONTEXT_OPTION[0x%08" PRIx32 "]",
option);
return FALSE;
}
}
UINT32 h264_context_get_option(H264_CONTEXT* h264, H264_CONTEXT_OPTION option)
{
WINPR_ASSERT(h264);
switch (option)
{
case H264_CONTEXT_OPTION_BITRATE:
return h264->BitRate;
case H264_CONTEXT_OPTION_FRAMERATE:
return h264->FrameRate;
case H264_CONTEXT_OPTION_RATECONTROL:
return h264->RateControlMode;
case H264_CONTEXT_OPTION_QP:
return h264->QP;
case H264_CONTEXT_OPTION_USAGETYPE:
return h264->UsageType;
case H264_CONTEXT_OPTION_HW_ACCEL:
return h264->hwAccel;
default:
WLog_Print(h264->log, WLOG_WARN, "Unknown H264_CONTEXT_OPTION[0x%08" PRIx32 "]",
option);
return 0;
}
}
+111
View File
@@ -0,0 +1,111 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* RemoteFX Codec Library - Decode
*
* Copyright 2018 Armin Novak <anovak@thincast.com>
* Copyright 2018 Thincast Technologies GmbH
*
* 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 FREERDP_LIB_CODEC_H264_H
#define FREERDP_LIB_CODEC_H264_H
#include <freerdp/api.h>
#include <freerdp/config.h>
#include <freerdp/codec/h264.h>
#ifdef __cplusplus
extern "C"
{
#endif
typedef BOOL (*pfnH264SubsystemInit)(H264_CONTEXT* h264);
typedef void (*pfnH264SubsystemUninit)(H264_CONTEXT* h264);
typedef int (*pfnH264SubsystemDecompress)(H264_CONTEXT* WINPR_RESTRICT h264,
const BYTE* WINPR_RESTRICT pSrcData, UINT32 SrcSize);
typedef int (*pfnH264SubsystemCompress)(H264_CONTEXT* WINPR_RESTRICT h264,
const BYTE** WINPR_RESTRICT pSrcYuv,
const UINT32* WINPR_RESTRICT pStride,
BYTE** WINPR_RESTRICT ppDstData,
UINT32* WINPR_RESTRICT pDstSize);
struct S_H264_CONTEXT_SUBSYSTEM
{
const char* name;
WINPR_ATTR_NODISCARD pfnH264SubsystemInit Init;
pfnH264SubsystemUninit Uninit;
WINPR_ATTR_NODISCARD pfnH264SubsystemDecompress Decompress;
WINPR_ATTR_NODISCARD pfnH264SubsystemCompress Compress;
};
struct S_H264_CONTEXT
{
BOOL Compressor;
UINT32 width;
UINT32 height;
H264_RATECONTROL_MODE RateControlMode;
UINT32 BitRate;
UINT32 FrameRate;
UINT32 QP;
UINT32 UsageType;
UINT32 hwAccel;
UINT32 NumberOfThreads;
UINT32 iStride[3];
BYTE* pOldYUVData[3];
BYTE* pYUVData[3];
UINT32 iYUV444Size[3];
UINT32 iYUV444Stride[3];
BYTE* pOldYUV444Data[3];
BYTE* pYUV444Data[3];
UINT32 numSystemData;
void* pSystemData;
const H264_CONTEXT_SUBSYSTEM* subsystem;
YUV_CONTEXT* yuv;
BOOL encodingBuffer;
BOOL firstLumaFrameDone;
BOOL firstChromaFrameDone;
void* lumaData;
wLog* log;
};
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL avc420_ensure_buffer(H264_CONTEXT* h264, UINT32 stride, UINT32 width,
UINT32 height);
#ifdef WITH_MEDIACODEC
extern const H264_CONTEXT_SUBSYSTEM g_Subsystem_mediacodec;
#endif
#if defined(_WIN32) && defined(WITH_MEDIA_FOUNDATION)
extern const H264_CONTEXT_SUBSYSTEM g_Subsystem_MF;
#endif
#ifdef WITH_OPENH264
extern const H264_CONTEXT_SUBSYSTEM g_Subsystem_OpenH264;
#endif
#ifdef WITH_VIDEO_FFMPEG
extern const H264_CONTEXT_SUBSYSTEM g_Subsystem_libavcodec;
#endif
#ifdef __cplusplus
}
#endif
#endif /* FREERDP_LIB_CODEC_H264_H */
+812
View File
@@ -0,0 +1,812 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* H.264 Bitmap Compression
*
* Copyright 2015 Marc-André Moreau <marcandre.moreau@gmail.com>
* Copyright 2014 Mike McDonald <Mike.McDonald@software.dell.com>
* Copyright 2014 erbth <t.erbesdobler@team103.com>
*
* 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 <freerdp/config.h>
#include <winpr/wlog.h>
#include <freerdp/log.h>
#include <freerdp/codec/h264.h>
#include <libavcodec/avcodec.h>
#include <libavutil/opt.h>
#include "h264.h"
#ifdef WITH_VAAPI
#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(55, 9, 0)
#include <libavutil/hwcontext.h>
#else
#pragma warning You have asked for VA - API decoding, \
but your version of libavutil is too old !Disabling.
#undef WITH_VAAPI
#endif
#endif
/* Fallback support for older libavcodec versions */
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(54, 59, 100)
#define AV_CODEC_ID_H264 CODEC_ID_H264
#endif
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(56, 34, 2)
#define AV_CODEC_FLAG_LOOP_FILTER CODEC_FLAG_LOOP_FILTER
#define AV_CODEC_CAP_TRUNCATED CODEC_CAP_TRUNCATED
#define AV_CODEC_FLAG_TRUNCATED CODEC_FLAG_TRUNCATED
#endif
#if LIBAVUTIL_VERSION_MAJOR < 52
#define AV_PIX_FMT_YUV420P PIX_FMT_YUV420P
#endif
/* Ubuntu 14.04 ships without the functions provided by avutil,
* so define error to string methods here. */
#if !defined(av_err2str)
static inline char* error_string(char* errbuf, size_t errbuf_size, int errnum)
{
av_strerror(errnum, errbuf, errbuf_size);
return errbuf;
}
#define av_err2str(errnum) error_string((char[64]){ 0 }, 64, errnum)
#endif
#if defined(WITH_VAAPI) || defined(WITH_VAAPI_H264_ENCODING)
#define VAAPI_DEVICE "/dev/dri/renderD128"
#endif
typedef struct
{
const AVCodec* codecDecoder;
AVCodecContext* codecDecoderContext;
const AVCodec* codecEncoder;
AVCodecContext* codecEncoderContext;
AVCodecParserContext* codecParser;
AVFrame* videoFrame;
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 133, 100)
AVPacket bufferpacket;
#endif
AVPacket* packet;
#if defined(WITH_VAAPI) || defined(WITH_VAAPI_H264_ENCODING)
AVBufferRef* hwctx;
AVFrame* hwVideoFrame;
enum AVPixelFormat hw_pix_fmt;
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(57, 80, 100)
AVBufferRef* hw_frames_ctx;
#endif
#endif
} H264_CONTEXT_LIBAVCODEC;
static void libavcodec_destroy_encoder_context(H264_CONTEXT* WINPR_RESTRICT h264)
{
H264_CONTEXT_LIBAVCODEC* sys = nullptr;
if (!h264 || !h264->subsystem)
return;
sys = (H264_CONTEXT_LIBAVCODEC*)h264->pSystemData;
if (sys->codecEncoderContext)
{
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55, 69, 100)
avcodec_free_context(&sys->codecEncoderContext);
#else
avcodec_close(sys->codecEncoderContext);
av_free(sys->codecEncoderContext);
#endif
}
sys->codecEncoderContext = nullptr;
}
#ifdef WITH_VAAPI_H264_ENCODING
static int set_hw_frames_ctx(H264_CONTEXT* WINPR_RESTRICT h264)
{
H264_CONTEXT_LIBAVCODEC* sys = (H264_CONTEXT_LIBAVCODEC*)h264->pSystemData;
AVBufferRef* hw_frames_ref = nullptr;
AVHWFramesContext* frames_ctx = nullptr;
int err = 0;
if (!(hw_frames_ref = av_hwframe_ctx_alloc(sys->hwctx)))
{
WLog_Print(h264->log, WLOG_ERROR, "Failed to create VAAPI frame context");
return -1;
}
frames_ctx = (AVHWFramesContext*)(hw_frames_ref->data);
frames_ctx->format = AV_PIX_FMT_VAAPI;
frames_ctx->sw_format = AV_PIX_FMT_NV12;
frames_ctx->width = sys->codecEncoderContext->width;
frames_ctx->height = sys->codecEncoderContext->height;
frames_ctx->initial_pool_size = 20;
if ((err = av_hwframe_ctx_init(hw_frames_ref)) < 0)
{
WLog_Print(h264->log, WLOG_ERROR,
"Failed to initialize VAAPI frame context."
"Error code: %s",
av_err2str(err));
av_buffer_unref(&hw_frames_ref);
return err;
}
sys->codecEncoderContext->hw_frames_ctx = av_buffer_ref(hw_frames_ref);
if (!sys->codecEncoderContext->hw_frames_ctx)
err = AVERROR(ENOMEM);
av_buffer_unref(&hw_frames_ref);
return err;
}
#endif
static BOOL libavcodec_create_encoder_context(H264_CONTEXT* WINPR_RESTRICT h264)
{
BOOL recreate = FALSE;
H264_CONTEXT_LIBAVCODEC* sys = nullptr;
if (!h264 || !h264->subsystem)
return FALSE;
if ((h264->width > INT_MAX) || (h264->height > INT_MAX))
return FALSE;
sys = (H264_CONTEXT_LIBAVCODEC*)h264->pSystemData;
if (!sys || !sys->codecEncoder)
return FALSE;
recreate = !sys->codecEncoderContext;
if (sys->codecEncoderContext)
{
if ((sys->codecEncoderContext->width != (int)h264->width) ||
(sys->codecEncoderContext->height != (int)h264->height))
recreate = TRUE;
}
if (!recreate)
return TRUE;
libavcodec_destroy_encoder_context(h264);
sys->codecEncoderContext = avcodec_alloc_context3(sys->codecEncoder);
if (!sys->codecEncoderContext)
goto EXCEPTION;
switch (h264->RateControlMode)
{
case H264_RATECONTROL_VBR:
sys->codecEncoderContext->bit_rate = h264->BitRate;
break;
case H264_RATECONTROL_CQP:
if (av_opt_set_int(sys->codecEncoderContext, "qp", h264->QP, AV_OPT_SEARCH_CHILDREN) <
0)
{
WLog_Print(h264->log, WLOG_ERROR, "av_opt_set_int failed");
}
break;
default:
break;
}
sys->codecEncoderContext->width = (int)MIN(INT32_MAX, h264->width);
sys->codecEncoderContext->height = (int)MIN(INT32_MAX, h264->height);
sys->codecEncoderContext->delay = 0;
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(56, 13, 100)
sys->codecEncoderContext->framerate =
(AVRational){ WINPR_ASSERTING_INT_CAST(int, h264->FrameRate), 1 };
#endif
sys->codecEncoderContext->time_base =
(AVRational){ 1, WINPR_ASSERTING_INT_CAST(int, h264->FrameRate) };
av_opt_set(sys->codecEncoderContext, "tune", "zerolatency", AV_OPT_SEARCH_CHILDREN);
sys->codecEncoderContext->flags |= AV_CODEC_FLAG_LOOP_FILTER;
#ifdef WITH_VAAPI_H264_ENCODING
if (sys->hwctx)
{
av_opt_set(sys->codecEncoderContext, "preset", "veryslow", AV_OPT_SEARCH_CHILDREN);
sys->codecEncoderContext->pix_fmt = AV_PIX_FMT_VAAPI;
/* set hw_frames_ctx for encoder's AVCodecContext */
if (set_hw_frames_ctx(h264) < 0)
goto EXCEPTION;
}
else
#endif
{
av_opt_set(sys->codecEncoderContext, "preset", "medium", AV_OPT_SEARCH_CHILDREN);
sys->codecEncoderContext->pix_fmt = AV_PIX_FMT_YUV420P;
}
if (avcodec_open2(sys->codecEncoderContext, sys->codecEncoder, nullptr) < 0)
goto EXCEPTION;
return TRUE;
EXCEPTION:
libavcodec_destroy_encoder_context(h264);
return FALSE;
}
static int libavcodec_decompress(H264_CONTEXT* WINPR_RESTRICT h264,
const BYTE* WINPR_RESTRICT pSrcData, UINT32 SrcSize)
{
union
{
const BYTE* cpv;
BYTE* pv;
} cnv;
int rc = -1;
int status = 0;
int gotFrame = 0;
AVPacket* packet = nullptr;
WINPR_ASSERT(h264);
WINPR_ASSERT(pSrcData || (SrcSize == 0));
H264_CONTEXT_LIBAVCODEC* sys = (H264_CONTEXT_LIBAVCODEC*)h264->pSystemData;
BYTE** pYUVData = h264->pYUVData;
UINT32* iStride = h264->iStride;
WINPR_ASSERT(sys);
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 133, 100)
packet = &sys->bufferpacket;
WINPR_ASSERT(packet);
av_init_packet(packet);
#else
packet = av_packet_alloc();
#endif
if (!packet)
{
WLog_Print(h264->log, WLOG_ERROR, "Failed to allocate AVPacket");
goto fail;
}
cnv.cpv = pSrcData;
packet->data = cnv.pv;
packet->size = (int)MIN(SrcSize, INT32_MAX);
WINPR_ASSERT(sys->codecDecoderContext);
/* avcodec_decode_video2 is deprecated with libavcodec 57.48.101 */
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 48, 101)
status = avcodec_send_packet(sys->codecDecoderContext, packet);
if (status < 0)
{
WLog_Print(h264->log, WLOG_ERROR, "Failed to decode video frame (status=%d)", status);
goto fail;
}
sys->videoFrame->format = AV_PIX_FMT_YUV420P;
#ifdef WITH_VAAPI
status = avcodec_receive_frame(sys->codecDecoderContext,
sys->hwctx ? sys->hwVideoFrame : sys->videoFrame);
#else
status = avcodec_receive_frame(sys->codecDecoderContext, sys->videoFrame);
#endif
if (status == AVERROR(EAGAIN))
{
rc = 0;
goto fail;
}
gotFrame = (status == 0);
#else
#ifdef WITH_VAAPI
status =
avcodec_decode_video2(sys->codecDecoderContext,
sys->hwctx ? sys->hwVideoFrame : sys->videoFrame, &gotFrame, packet);
#else
status = avcodec_decode_video2(sys->codecDecoderContext, sys->videoFrame, &gotFrame, packet);
#endif
#endif
if (status < 0)
{
WLog_Print(h264->log, WLOG_ERROR, "Failed to decode video frame (status=%d)", status);
goto fail;
}
#ifdef WITH_VAAPI
if (sys->hwctx)
{
if (sys->hwVideoFrame->format == sys->hw_pix_fmt)
{
sys->videoFrame->width = sys->hwVideoFrame->width;
sys->videoFrame->height = sys->hwVideoFrame->height;
status = av_hwframe_transfer_data(sys->videoFrame, sys->hwVideoFrame, 0);
}
else
{
status = av_frame_copy(sys->videoFrame, sys->hwVideoFrame);
}
}
gotFrame = (status == 0);
if (status < 0)
{
WLog_Print(h264->log, WLOG_ERROR, "Failed to transfer video frame (status=%d) (%s)", status,
av_err2str(status));
goto fail;
}
#endif
if (gotFrame)
{
WINPR_ASSERT(sys->videoFrame);
pYUVData[0] = sys->videoFrame->data[0];
pYUVData[1] = sys->videoFrame->data[1];
pYUVData[2] = sys->videoFrame->data[2];
iStride[0] = (UINT32)MAX(0, sys->videoFrame->linesize[0]);
iStride[1] = (UINT32)MAX(0, sys->videoFrame->linesize[1]);
iStride[2] = (UINT32)MAX(0, sys->videoFrame->linesize[2]);
rc = 1;
}
else
rc = -2;
fail:
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 133, 100)
av_packet_unref(packet);
#else
av_packet_free(&packet);
#endif
return rc;
}
static int libavcodec_compress(H264_CONTEXT* WINPR_RESTRICT h264,
const BYTE** WINPR_RESTRICT pSrcYuv,
const UINT32* WINPR_RESTRICT pStride,
BYTE** WINPR_RESTRICT ppDstData, UINT32* WINPR_RESTRICT pDstSize)
{
union
{
const BYTE* cpv;
uint8_t* pv;
} cnv;
int rc = -1;
int status = 0;
int gotFrame = 0;
WINPR_ASSERT(h264);
H264_CONTEXT_LIBAVCODEC* sys = (H264_CONTEXT_LIBAVCODEC*)h264->pSystemData;
WINPR_ASSERT(sys);
if (!libavcodec_create_encoder_context(h264))
return -1;
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 133, 100)
sys->packet = &sys->bufferpacket;
av_packet_unref(sys->packet);
av_init_packet(sys->packet);
#else
av_packet_free(&sys->packet);
sys->packet = av_packet_alloc();
#endif
if (!sys->packet)
{
WLog_Print(h264->log, WLOG_ERROR, "Failed to allocate AVPacket");
goto fail;
}
WINPR_ASSERT(sys->packet);
sys->packet->data = nullptr;
sys->packet->size = 0;
WINPR_ASSERT(sys->videoFrame);
WINPR_ASSERT(sys->codecEncoderContext);
sys->videoFrame->format = AV_PIX_FMT_YUV420P;
sys->videoFrame->width = sys->codecEncoderContext->width;
sys->videoFrame->height = sys->codecEncoderContext->height;
#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(52, 48, 100)
sys->videoFrame->colorspace = AVCOL_SPC_BT709;
#endif
#if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(52, 92, 100)
sys->videoFrame->chroma_location = AVCHROMA_LOC_LEFT;
#endif
cnv.cpv = pSrcYuv[0];
sys->videoFrame->data[0] = cnv.pv;
cnv.cpv = pSrcYuv[1];
sys->videoFrame->data[1] = cnv.pv;
cnv.cpv = pSrcYuv[2];
sys->videoFrame->data[2] = cnv.pv;
sys->videoFrame->linesize[0] = (int)pStride[0];
sys->videoFrame->linesize[1] = (int)pStride[1];
sys->videoFrame->linesize[2] = (int)pStride[2];
sys->videoFrame->pts++;
#ifdef WITH_VAAPI_H264_ENCODING
if (sys->hwctx)
{
av_frame_unref(sys->hwVideoFrame);
if ((status = av_hwframe_get_buffer(sys->codecEncoderContext->hw_frames_ctx,
sys->hwVideoFrame, 0)) < 0 ||
!sys->hwVideoFrame->hw_frames_ctx)
{
WLog_Print(h264->log, WLOG_ERROR, "av_hwframe_get_buffer failed (%s [%d])",
av_err2str(status), status);
goto fail;
}
sys->videoFrame->format = AV_PIX_FMT_NV12;
if ((status = av_hwframe_transfer_data(sys->hwVideoFrame, sys->videoFrame, 0)) < 0)
{
WLog_Print(h264->log, WLOG_ERROR, "av_hwframe_transfer_data failed (%s [%d])",
av_err2str(status), status);
goto fail;
}
}
#endif
/* avcodec_encode_video2 is deprecated with libavcodec 57.48.101 */
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 48, 101)
#ifdef WITH_VAAPI_H264_ENCODING
status = avcodec_send_frame(sys->codecEncoderContext,
sys->hwctx ? sys->hwVideoFrame : sys->videoFrame);
#else
status = avcodec_send_frame(sys->codecEncoderContext, sys->videoFrame);
#endif
if (status < 0)
{
WLog_Print(h264->log, WLOG_ERROR, "Failed to encode video frame (%s [%d])",
av_err2str(status), status);
goto fail;
}
status = avcodec_receive_packet(sys->codecEncoderContext, sys->packet);
if (status < 0)
{
WLog_Print(h264->log, WLOG_ERROR, "Failed to encode video frame (%s [%d])",
av_err2str(status), status);
goto fail;
}
gotFrame = (status == 0);
#elif LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(54, 59, 100)
do
{
status = avcodec_encode_video2(sys->codecEncoderContext, sys->packet, sys->videoFrame,
&gotFrame);
} while ((status >= 0) && (gotFrame == 0));
#else
sys->packet->size =
avpicture_get_size(sys->codecDecoderContext->pix_fmt, sys->codecDecoderContext->width,
sys->codecDecoderContext->height);
sys->packet->data = av_malloc(sys->packet->size);
if (!sys->packet->data)
status = -1;
else
{
status = avcodec_encode_video(sys->codecDecoderContext, sys->packet->data,
sys->packet->size, sys->videoFrame);
}
#endif
if (status < 0)
{
WLog_Print(h264->log, WLOG_ERROR, "Failed to encode video frame (%s [%d])",
av_err2str(status), status);
goto fail;
}
WINPR_ASSERT(sys->packet);
*ppDstData = sys->packet->data;
*pDstSize = (UINT32)MAX(0, sys->packet->size);
if (!gotFrame)
{
WLog_Print(h264->log, WLOG_ERROR, "Did not get frame! (%s [%d])", av_err2str(status),
status);
rc = -2;
}
else
rc = 1;
fail:
return rc;
}
static void libavcodec_uninit(H264_CONTEXT* h264)
{
WINPR_ASSERT(h264);
H264_CONTEXT_LIBAVCODEC* sys = (H264_CONTEXT_LIBAVCODEC*)h264->pSystemData;
if (!sys)
return;
if (sys->packet)
{
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 133, 100)
av_packet_unref(sys->packet);
#else
av_packet_free(&sys->packet);
#endif
}
if (sys->videoFrame)
{
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55, 18, 102)
av_frame_free(&sys->videoFrame);
#else
av_free(sys->videoFrame);
#endif
}
#if defined(WITH_VAAPI) || defined(WITH_VAAPI_H264_ENCODING)
if (sys->hwVideoFrame)
{
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55, 18, 102)
av_frame_free(&sys->hwVideoFrame);
#else
av_free(sys->hwVideoFrame);
#endif
}
if (sys->hwctx)
av_buffer_unref(&sys->hwctx);
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(57, 80, 100)
if (sys->hw_frames_ctx)
av_buffer_unref(&sys->hw_frames_ctx);
#endif
#endif
if (sys->codecParser)
av_parser_close(sys->codecParser);
if (sys->codecDecoderContext)
{
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55, 69, 100)
avcodec_free_context(&sys->codecDecoderContext);
#else
avcodec_close(sys->codecDecoderContext);
av_free(sys->codecDecoderContext);
#endif
}
libavcodec_destroy_encoder_context(h264);
free(sys);
h264->pSystemData = nullptr;
}
#ifdef WITH_VAAPI
static enum AVPixelFormat libavcodec_get_format(struct AVCodecContext* ctx,
const enum AVPixelFormat* fmts)
{
WINPR_ASSERT(ctx);
H264_CONTEXT* h264 = (H264_CONTEXT*)ctx->opaque;
WINPR_ASSERT(h264);
H264_CONTEXT_LIBAVCODEC* sys = (H264_CONTEXT_LIBAVCODEC*)h264->pSystemData;
WINPR_ASSERT(sys);
for (const enum AVPixelFormat* p = fmts; *p != AV_PIX_FMT_NONE; p++)
{
if (*p == sys->hw_pix_fmt)
{
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(57, 80, 100)
sys->hw_frames_ctx = av_hwframe_ctx_alloc(sys->hwctx);
if (!sys->hw_frames_ctx)
{
return AV_PIX_FMT_NONE;
}
sys->codecDecoderContext->pix_fmt = *p;
AVHWFramesContext* frames = (AVHWFramesContext*)sys->hw_frames_ctx->data;
frames->format = *p;
frames->height = sys->codecDecoderContext->coded_height;
frames->width = sys->codecDecoderContext->coded_width;
frames->sw_format =
(sys->codecDecoderContext->sw_pix_fmt == AV_PIX_FMT_YUV420P10 ? AV_PIX_FMT_P010
: AV_PIX_FMT_NV12);
frames->initial_pool_size = 20;
if (sys->codecDecoderContext->active_thread_type & FF_THREAD_FRAME)
frames->initial_pool_size += sys->codecDecoderContext->thread_count;
int err = av_hwframe_ctx_init(sys->hw_frames_ctx);
if (err < 0)
{
WLog_Print(h264->log, WLOG_ERROR, "Could not init hwframes context: %s",
av_err2str(err));
return AV_PIX_FMT_NONE;
}
sys->codecDecoderContext->hw_frames_ctx = av_buffer_ref(sys->hw_frames_ctx);
#endif
return *p;
}
}
return AV_PIX_FMT_NONE;
}
#endif
static BOOL libavcodec_init(H264_CONTEXT* h264)
{
H264_CONTEXT_LIBAVCODEC* sys = nullptr;
WINPR_ASSERT(h264);
sys = (H264_CONTEXT_LIBAVCODEC*)calloc(1, sizeof(H264_CONTEXT_LIBAVCODEC));
if (!sys)
{
goto EXCEPTION;
}
h264->pSystemData = (void*)sys;
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 10, 100)
avcodec_register_all();
#endif
if (!h264->Compressor)
{
sys->codecDecoder = avcodec_find_decoder(AV_CODEC_ID_H264);
if (!sys->codecDecoder)
{
WLog_Print(h264->log, WLOG_ERROR, "Failed to find libav H.264 codec");
goto EXCEPTION;
}
sys->codecDecoderContext = avcodec_alloc_context3(sys->codecDecoder);
if (!sys->codecDecoderContext)
{
WLog_Print(h264->log, WLOG_ERROR, "Failed to allocate libav codec context");
goto EXCEPTION;
}
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(59, 18, 100)
if (sys->codecDecoder->capabilities & AV_CODEC_CAP_TRUNCATED)
{
sys->codecDecoderContext->flags |= AV_CODEC_FLAG_TRUNCATED;
}
#endif
#ifdef WITH_VAAPI
if (!sys->hwctx)
{
int ret = av_hwdevice_ctx_create(&sys->hwctx, AV_HWDEVICE_TYPE_VAAPI, VAAPI_DEVICE,
nullptr, 0);
if (ret < 0)
{
WLog_Print(h264->log, WLOG_ERROR,
"Could not initialize hardware decoder, falling back to software: %s",
av_err2str(ret));
sys->hwctx = nullptr;
goto fail_hwdevice_create;
}
}
WLog_Print(h264->log, WLOG_INFO, "Using VAAPI for accelerated H264 decoding");
sys->codecDecoderContext->get_format = libavcodec_get_format;
sys->hw_pix_fmt = AV_PIX_FMT_VAAPI;
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 80, 100)
sys->codecDecoderContext->hw_device_ctx = av_buffer_ref(sys->hwctx);
#endif
sys->codecDecoderContext->opaque = (void*)h264;
fail_hwdevice_create:
#endif
if (avcodec_open2(sys->codecDecoderContext, sys->codecDecoder, nullptr) < 0)
{
WLog_Print(h264->log, WLOG_ERROR, "Failed to open libav codec");
goto EXCEPTION;
}
sys->codecParser = av_parser_init(AV_CODEC_ID_H264);
if (!sys->codecParser)
{
WLog_Print(h264->log, WLOG_ERROR, "Failed to initialize libav parser");
goto EXCEPTION;
}
}
else
{
#ifdef WITH_VAAPI_H264_ENCODING
if (h264->hwAccel) /* user requested hw accel */
{
sys->codecEncoder = avcodec_find_encoder_by_name("h264_vaapi");
if (!sys->codecEncoder)
{
WLog_Print(h264->log, WLOG_ERROR, "H264 VAAPI encoder not found");
}
else if (av_hwdevice_ctx_create(&sys->hwctx, AV_HWDEVICE_TYPE_VAAPI, VAAPI_DEVICE,
nullptr, 0) < 0)
{
WLog_Print(h264->log, WLOG_ERROR, "av_hwdevice_ctx_create failed");
sys->codecEncoder = nullptr;
sys->hwctx = nullptr;
}
else
{
WLog_Print(h264->log, WLOG_INFO, "Using VAAPI for accelerated H264 encoding");
}
}
#endif
if (!sys->codecEncoder)
{
sys->codecEncoder = avcodec_find_encoder(AV_CODEC_ID_H264);
h264->hwAccel = FALSE; /* not supported */
}
if (!sys->codecEncoder)
{
WLog_Print(h264->log, WLOG_ERROR, "Failed to initialize H264 encoder");
goto EXCEPTION;
}
}
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(55, 18, 102)
sys->videoFrame = av_frame_alloc();
#if defined(WITH_VAAPI) || defined(WITH_VAAPI_H264_ENCODING)
sys->hwVideoFrame = av_frame_alloc();
#endif
#else
sys->videoFrame = avcodec_alloc_frame();
#endif
if (!sys->videoFrame)
{
WLog_Print(h264->log, WLOG_ERROR, "Failed to allocate libav frame");
goto EXCEPTION;
}
#if defined(WITH_VAAPI) || defined(WITH_VAAPI_H264_ENCODING)
if (!sys->hwVideoFrame)
{
WLog_Print(h264->log, WLOG_ERROR, "Failed to allocate libav hw frame");
goto EXCEPTION;
}
#endif
sys->videoFrame->pts = 0;
return TRUE;
EXCEPTION:
libavcodec_uninit(h264);
return FALSE;
}
const H264_CONTEXT_SUBSYSTEM g_Subsystem_libavcodec = { "libavcodec", libavcodec_init,
libavcodec_uninit, libavcodec_decompress,
libavcodec_compress };
+527
View File
@@ -0,0 +1,527 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* H.264 Bitmap Compression
*
* Copyright 2022 Ely Ronnen <elyronnen@gmail.com>
*
* 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 <winpr/wlog.h>
#include <winpr/assert.h>
#include <winpr/library.h>
#include <freerdp/log.h>
#include <freerdp/codec/h264.h>
#include <media/NdkMediaCodec.h>
#include <media/NdkMediaFormat.h>
#include "h264.h"
static const char* CODEC_NAME = "video/avc";
static const int COLOR_FormatYUV420Planar = 19;
static const int COLOR_FormatYUV420Flexible = 0x7f420888;
/* https://developer.android.com/reference/android/media/MediaCodec#qualityFloor */
static const int MEDIACODEC_MINIMUM_WIDTH = 320;
static const int MEDIACODEC_MINIMUM_HEIGHT = 240;
typedef struct
{
AMediaCodec* decoder;
AMediaFormat* inputFormat;
AMediaFormat* outputFormat;
int32_t width;
int32_t height;
int32_t outputWidth;
int32_t outputHeight;
ssize_t currentOutputBufferIndex;
} H264_CONTEXT_MEDIACODEC;
static AMediaFormat* mediacodec_format_new(wLog* log, int width, int height)
{
const char* media_format;
AMediaFormat* format = AMediaFormat_new();
if (format == nullptr)
{
WLog_Print(log, WLOG_ERROR, "AMediaFormat_new failed");
return nullptr;
}
AMediaFormat_setString(format, AMEDIAFORMAT_KEY_MIME, CODEC_NAME);
AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_WIDTH, width);
AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_HEIGHT, height);
AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_COLOR_FORMAT, COLOR_FormatYUV420Planar);
media_format = AMediaFormat_toString(format);
if (media_format == nullptr)
{
WLog_Print(log, WLOG_ERROR, "AMediaFormat_toString failed");
AMediaFormat_delete(format);
return nullptr;
}
WLog_Print(log, WLOG_DEBUG, "MediaCodec configuring with desired output format [%s]",
media_format);
return format;
}
static void set_mediacodec_format(H264_CONTEXT* h264, AMediaFormat** formatVariable,
AMediaFormat* newFormat)
{
media_status_t status = AMEDIA_OK;
H264_CONTEXT_MEDIACODEC* sys;
WINPR_ASSERT(h264);
WINPR_ASSERT(formatVariable);
sys = (H264_CONTEXT_MEDIACODEC*)h264->pSystemData;
WINPR_ASSERT(sys);
if (*formatVariable == newFormat)
return;
if (*formatVariable != nullptr)
{
status = AMediaFormat_delete(*formatVariable);
if (status != AMEDIA_OK)
{
WLog_Print(h264->log, WLOG_ERROR, "Error AMediaFormat_delete %d", status);
}
}
*formatVariable = newFormat;
}
static int update_mediacodec_inputformat(H264_CONTEXT* h264)
{
H264_CONTEXT_MEDIACODEC* sys;
AMediaFormat* inputFormat;
const char* mediaFormatName;
WINPR_ASSERT(h264);
sys = (H264_CONTEXT_MEDIACODEC*)h264->pSystemData;
WINPR_ASSERT(sys);
#if __ANDROID__ >= 21
inputFormat = AMediaCodec_getInputFormat(sys->decoder);
if (inputFormat == nullptr)
{
WLog_Print(h264->log, WLOG_ERROR, "AMediaCodec_getInputFormat failed");
return -1;
}
#else
inputFormat = sys->inputFormat;
#endif
set_mediacodec_format(h264, &sys->inputFormat, inputFormat);
mediaFormatName = AMediaFormat_toString(sys->inputFormat);
if (mediaFormatName == nullptr)
{
WLog_Print(h264->log, WLOG_ERROR, "AMediaFormat_toString failed");
return -1;
}
WLog_Print(h264->log, WLOG_DEBUG, "Using MediaCodec with input MediaFormat [%s]",
mediaFormatName);
return 1;
}
static int update_mediacodec_outputformat(H264_CONTEXT* h264)
{
H264_CONTEXT_MEDIACODEC* sys;
AMediaFormat* outputFormat;
const char* mediaFormatName;
int32_t outputWidth, outputHeight;
WINPR_ASSERT(h264);
sys = (H264_CONTEXT_MEDIACODEC*)h264->pSystemData;
WINPR_ASSERT(sys);
outputFormat = AMediaCodec_getOutputFormat(sys->decoder);
if (outputFormat == nullptr)
{
WLog_Print(h264->log, WLOG_ERROR, "AMediaCodec_getOutputFormat failed");
return -1;
}
set_mediacodec_format(h264, &sys->outputFormat, outputFormat);
mediaFormatName = AMediaFormat_toString(sys->outputFormat);
if (mediaFormatName == nullptr)
{
WLog_Print(h264->log, WLOG_ERROR, "AMediaFormat_toString failed");
return -1;
}
WLog_Print(h264->log, WLOG_DEBUG, "Using MediaCodec with output MediaFormat [%s]",
mediaFormatName);
if (!AMediaFormat_getInt32(sys->outputFormat, AMEDIAFORMAT_KEY_WIDTH, &outputWidth))
{
WLog_Print(h264->log, WLOG_ERROR, "fnAMediaFormat_getInt32 failed getting width");
return -1;
}
if (!AMediaFormat_getInt32(sys->outputFormat, AMEDIAFORMAT_KEY_HEIGHT, &outputHeight))
{
WLog_Print(h264->log, WLOG_ERROR, "fnAMediaFormat_getInt32 failed getting height");
return -1;
}
sys->outputWidth = outputWidth;
sys->outputHeight = outputHeight;
return 1;
}
static void release_current_outputbuffer(H264_CONTEXT* h264)
{
media_status_t status = AMEDIA_OK;
H264_CONTEXT_MEDIACODEC* sys;
WINPR_ASSERT(h264);
sys = (H264_CONTEXT_MEDIACODEC*)h264->pSystemData;
WINPR_ASSERT(sys);
if (sys->currentOutputBufferIndex < 0)
{
return;
}
status = AMediaCodec_releaseOutputBuffer(sys->decoder, sys->currentOutputBufferIndex, FALSE);
if (status != AMEDIA_OK)
{
WLog_Print(h264->log, WLOG_ERROR, "Error AMediaCodec_releaseOutputBuffer %d", status);
}
sys->currentOutputBufferIndex = -1;
}
static int mediacodec_compress(H264_CONTEXT* h264, const BYTE** pSrcYuv, const UINT32* pStride,
BYTE** ppDstData, UINT32* pDstSize)
{
WINPR_ASSERT(h264);
WINPR_ASSERT(pSrcYuv);
WINPR_ASSERT(pStride);
WINPR_ASSERT(ppDstData);
WINPR_ASSERT(pDstSize);
WLog_Print(h264->log, WLOG_ERROR, "MediaCodec is not supported as an encoder");
return -1;
}
static int mediacodec_decompress(H264_CONTEXT* h264, const BYTE* pSrcData, UINT32 SrcSize)
{
ssize_t inputBufferId = -1;
size_t inputBufferSize, outputBufferSize;
uint8_t* inputBuffer;
media_status_t status;
BYTE** pYUVData;
UINT32* iStride;
H264_CONTEXT_MEDIACODEC* sys;
WINPR_ASSERT(h264);
WINPR_ASSERT(pSrcData);
sys = (H264_CONTEXT_MEDIACODEC*)h264->pSystemData;
WINPR_ASSERT(sys);
pYUVData = h264->pYUVData;
WINPR_ASSERT(pYUVData);
iStride = h264->iStride;
WINPR_ASSERT(iStride);
release_current_outputbuffer(h264);
if (sys->width != h264->width || sys->height != h264->height)
{
sys->width = h264->width;
sys->height = h264->height;
if (sys->width < MEDIACODEC_MINIMUM_WIDTH || sys->height < MEDIACODEC_MINIMUM_HEIGHT)
{
WLog_Print(h264->log, WLOG_ERROR,
"MediaCodec got width or height smaller than minimum [%d,%d]", sys->width,
sys->height);
return -1;
}
WLog_Print(h264->log, WLOG_DEBUG, "MediaCodec setting new input width and height [%d,%d]",
sys->width, sys->height);
#if __ANDROID__ >= 26
AMediaFormat_setInt32(sys->inputFormat, AMEDIAFORMAT_KEY_WIDTH, sys->width);
AMediaFormat_setInt32(sys->inputFormat, AMEDIAFORMAT_KEY_HEIGHT, sys->height);
status = AMediaCodec_setParameters(sys->decoder, sys->inputFormat);
if (status != AMEDIA_OK)
{
WLog_Print(h264->log, WLOG_ERROR, "AMediaCodec_setParameters failed: %d", status);
return -1;
}
#else
set_mediacodec_format(h264, &sys->inputFormat,
mediacodec_format_new(h264->log, sys->width, sys->height));
#endif
// The codec can change output width and height
if (update_mediacodec_outputformat(h264) < 0)
{
WLog_Print(h264->log, WLOG_ERROR, "MediaCodec failed updating input format");
return -1;
}
}
while (true)
{
UINT32 inputBufferCurrnetOffset = 0;
while (inputBufferCurrnetOffset < SrcSize)
{
UINT32 numberOfBytesToCopy = SrcSize - inputBufferCurrnetOffset;
inputBufferId = AMediaCodec_dequeueInputBuffer(sys->decoder, -1);
if (inputBufferId < 0)
{
WLog_Print(h264->log, WLOG_ERROR, "AMediaCodec_dequeueInputBuffer failed [%d]",
inputBufferId);
// TODO: sleep?
continue;
}
inputBuffer = AMediaCodec_getInputBuffer(sys->decoder, inputBufferId, &inputBufferSize);
if (inputBuffer == nullptr)
{
WLog_Print(h264->log, WLOG_ERROR, "AMediaCodec_getInputBuffer failed");
return -1;
}
if (numberOfBytesToCopy > inputBufferSize)
{
WLog_Print(h264->log, WLOG_WARN,
"MediaCodec inputBufferSize: got [%d] but wanted [%d]", inputBufferSize,
numberOfBytesToCopy);
numberOfBytesToCopy = inputBufferSize;
}
memcpy(inputBuffer, pSrcData + inputBufferCurrnetOffset, numberOfBytesToCopy);
inputBufferCurrnetOffset += numberOfBytesToCopy;
status = AMediaCodec_queueInputBuffer(sys->decoder, inputBufferId, 0,
numberOfBytesToCopy, 0, 0);
if (status != AMEDIA_OK)
{
WLog_Print(h264->log, WLOG_ERROR, "Error AMediaCodec_queueInputBuffer %d", status);
return -1;
}
}
while (true)
{
AMediaCodecBufferInfo bufferInfo;
ssize_t outputBufferId = AMediaCodec_dequeueOutputBuffer(sys->decoder, &bufferInfo, -1);
if (outputBufferId >= 0)
{
sys->currentOutputBufferIndex = outputBufferId;
uint8_t* outputBuffer;
outputBuffer =
AMediaCodec_getOutputBuffer(sys->decoder, outputBufferId, &outputBufferSize);
sys->currentOutputBufferIndex = outputBufferId;
if (outputBufferSize !=
(sys->outputWidth * sys->outputHeight +
((sys->outputWidth + 1) / 2) * ((sys->outputHeight + 1) / 2) * 2))
{
WLog_Print(h264->log, WLOG_ERROR,
"Error MediaCodec unexpected output buffer size %d",
outputBufferSize);
return -1;
}
// TODO: work with AImageReader and get AImage object instead of
// COLOR_FormatYUV420Planar buffer.
iStride[0] = sys->outputWidth;
iStride[1] = (sys->outputWidth + 1) / 2;
iStride[2] = (sys->outputWidth + 1) / 2;
pYUVData[0] = outputBuffer;
pYUVData[1] = outputBuffer + iStride[0] * sys->outputHeight;
pYUVData[2] = outputBuffer + iStride[0] * sys->outputHeight +
iStride[1] * ((sys->outputHeight + 1) / 2);
break;
}
else if (outputBufferId == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED)
{
if (update_mediacodec_outputformat(h264) < 0)
{
WLog_Print(h264->log, WLOG_ERROR,
"MediaCodec failed updating output format in decompress");
return -1;
}
}
else if (outputBufferId == AMEDIACODEC_INFO_TRY_AGAIN_LATER)
{
WLog_Print(h264->log, WLOG_WARN,
"AMediaCodec_dequeueOutputBuffer need to try again later");
// TODO: sleep?
}
else if (outputBufferId == AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED)
{
WLog_Print(h264->log, WLOG_WARN,
"AMediaCodec_dequeueOutputBuffer returned deprecated value "
"AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED, ignoring");
}
else
{
WLog_Print(h264->log, WLOG_ERROR,
"AMediaCodec_dequeueOutputBuffer returned unknown value [%d]",
outputBufferId);
return -1;
}
}
break;
}
return 1;
}
static void mediacodec_uninit(H264_CONTEXT* h264)
{
media_status_t status = AMEDIA_OK;
H264_CONTEXT_MEDIACODEC* sys;
WINPR_ASSERT(h264);
sys = (H264_CONTEXT_MEDIACODEC*)h264->pSystemData;
WLog_Print(h264->log, WLOG_DEBUG, "Uninitializing MediaCodec");
if (!sys)
return;
if (sys->decoder != nullptr)
{
release_current_outputbuffer(h264);
status = AMediaCodec_stop(sys->decoder);
if (status != AMEDIA_OK)
{
WLog_Print(h264->log, WLOG_ERROR, "Error AMediaCodec_stop %d", status);
}
status = AMediaCodec_delete(sys->decoder);
if (status != AMEDIA_OK)
{
WLog_Print(h264->log, WLOG_ERROR, "Error AMediaCodec_delete %d", status);
}
sys->decoder = nullptr;
}
set_mediacodec_format(h264, &sys->inputFormat, nullptr);
set_mediacodec_format(h264, &sys->outputFormat, nullptr);
free(sys);
h264->pSystemData = nullptr;
}
static BOOL mediacodec_init(H264_CONTEXT* h264)
{
H264_CONTEXT_MEDIACODEC* sys;
media_status_t status;
WINPR_ASSERT(h264);
if (h264->Compressor)
{
WLog_Print(h264->log, WLOG_ERROR, "MediaCodec is not supported as an encoder");
goto EXCEPTION;
}
WLog_Print(h264->log, WLOG_DEBUG, "Initializing MediaCodec");
sys = (H264_CONTEXT_MEDIACODEC*)calloc(1, sizeof(H264_CONTEXT_MEDIACODEC));
if (!sys)
{
goto EXCEPTION;
}
h264->pSystemData = (void*)sys;
sys->currentOutputBufferIndex = -1;
// updated when we're given the height and width for the first time
sys->width = sys->outputWidth = MEDIACODEC_MINIMUM_WIDTH;
sys->height = sys->outputHeight = MEDIACODEC_MINIMUM_HEIGHT;
sys->decoder = AMediaCodec_createDecoderByType(CODEC_NAME);
if (sys->decoder == nullptr)
{
WLog_Print(h264->log, WLOG_ERROR, "AMediaCodec_createCodecByName failed");
goto EXCEPTION;
}
#if __ANDROID_API__ >= 28
char* codec_name;
status = AMediaCodec_getName(sys->decoder, &codec_name);
if (status != AMEDIA_OK)
{
WLog_Print(h264->log, WLOG_ERROR, "AMediaCodec_getName failed: %d", status);
goto EXCEPTION;
}
WLog_Print(h264->log, WLOG_DEBUG, "MediaCodec using %s codec [%s]", CODEC_NAME, codec_name);
AMediaCodec_releaseName(sys->decoder, codec_name);
#endif
set_mediacodec_format(h264, &sys->inputFormat,
mediacodec_format_new(h264->log, sys->width, sys->height));
status = AMediaCodec_configure(sys->decoder, sys->inputFormat, nullptr, nullptr, 0);
if (status != AMEDIA_OK)
{
WLog_Print(h264->log, WLOG_ERROR, "AMediaCodec_configure failed: %d", status);
goto EXCEPTION;
}
if (update_mediacodec_inputformat(h264) < 0)
{
WLog_Print(h264->log, WLOG_ERROR, "MediaCodec failed updating input format");
goto EXCEPTION;
}
if (update_mediacodec_outputformat(h264) < 0)
{
WLog_Print(h264->log, WLOG_ERROR, "MediaCodec failed updating output format");
goto EXCEPTION;
}
WLog_Print(h264->log, WLOG_DEBUG, "Starting MediaCodec");
status = AMediaCodec_start(sys->decoder);
if (status != AMEDIA_OK)
{
WLog_Print(h264->log, WLOG_ERROR, "AMediaCodec_start failed %d", status);
goto EXCEPTION;
}
return TRUE;
EXCEPTION:
mediacodec_uninit(h264);
return FALSE;
}
const H264_CONTEXT_SUBSYSTEM g_Subsystem_mediacodec = { "MediaCodec", mediacodec_init,
mediacodec_uninit, mediacodec_decompress,
mediacodec_compress };
+597
View File
@@ -0,0 +1,597 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* H.264 Bitmap Compression
*
* Copyright 2014 Mike McDonald <Mike.McDonald@software.dell.com>
*
* 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 <winpr/winpr.h>
#include <freerdp/log.h>
#include <freerdp/codec/h264.h>
#include <ks.h>
#include <codecapi.h>
#include <mfapi.h>
#include <mferror.h>
#include <wmcodecdsp.h>
#include <mftransform.h>
#include "h264.h"
#define TAG FREERDP_TAG("codec")
static const GUID sCLSID_CMSH264DecoderMFT = {
0x62CE7E72, 0x4C71, 0x4d20, { 0xB1, 0x5D, 0x45, 0x28, 0x31, 0xA8, 0x7D, 0x9D }
};
static const GUID sIID_IMFTransform = {
0xbf94c121, 0x5b05, 0x4e6f, { 0x80, 0x00, 0xba, 0x59, 0x89, 0x61, 0x41, 0x4d }
};
static const GUID sMF_MT_MAJOR_TYPE = {
0x48eba18e, 0xf8c9, 0x4687, { 0xbf, 0x11, 0x0a, 0x74, 0xc9, 0xf9, 0x6a, 0x8f }
};
static const GUID sMF_MT_FRAME_SIZE = {
0x1652c33d, 0xd6b2, 0x4012, { 0xb8, 0x34, 0x72, 0x03, 0x08, 0x49, 0xa3, 0x7d }
};
static const GUID sMF_MT_DEFAULT_STRIDE = {
0x644b4e48, 0x1e02, 0x4516, { 0xb0, 0xeb, 0xc0, 0x1c, 0xa9, 0xd4, 0x9a, 0xc6 }
};
static const GUID sMF_MT_SUBTYPE = {
0xf7e34c9a, 0x42e8, 0x4714, { 0xb7, 0x4b, 0xcb, 0x29, 0xd7, 0x2c, 0x35, 0xe5 }
};
static const GUID sMFMediaType_Video = {
0x73646976, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71 }
};
static const GUID sMFVideoFormat_H264 = {
0x34363248, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 }
};
static const GUID sMFVideoFormat_IYUV = {
0x56555949, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 }
};
static const GUID sIID_ICodecAPI = {
0x901db4c7, 0x31ce, 0x41a2, { 0x85, 0xdc, 0x8f, 0xa0, 0xbf, 0x41, 0xb8, 0xda }
};
static const GUID sCODECAPI_AVLowLatencyMode = {
0x9c27891a, 0xed7a, 0x40e1, { 0x88, 0xe8, 0xb2, 0x27, 0x27, 0xa0, 0x24, 0xee }
};
typedef HRESULT(__stdcall* pfnMFStartup)(ULONG Version, DWORD dwFlags);
typedef HRESULT(__stdcall* pfnMFShutdown)(void);
typedef HRESULT(__stdcall* pfnMFCreateSample)(IMFSample** ppIMFSample);
typedef HRESULT(__stdcall* pfnMFCreateMemoryBuffer)(DWORD cbMaxLength, IMFMediaBuffer** ppBuffer);
typedef HRESULT(__stdcall* pfnMFCreateMediaType)(IMFMediaType** ppMFType);
typedef struct
{
ICodecAPI* codecApi;
IMFTransform* transform;
IMFMediaType* inputType;
IMFMediaType* outputType;
IMFSample* sample;
UINT32 frameWidth;
UINT32 frameHeight;
IMFSample* outputSample;
IMFMediaBuffer* outputBuffer;
HMODULE mfplat;
pfnMFStartup MFStartup;
pfnMFShutdown MFShutdown;
pfnMFCreateSample MFCreateSample;
pfnMFCreateMemoryBuffer MFCreateMemoryBuffer;
pfnMFCreateMediaType MFCreateMediaType;
} H264_CONTEXT_MF;
static HRESULT mf_find_output_type(H264_CONTEXT_MF* sys, const GUID* guid,
IMFMediaType** ppMediaType)
{
DWORD idx = 0;
GUID mediaGuid;
HRESULT hr = S_OK;
IMFMediaType* pMediaType = nullptr;
while (1)
{
hr = sys->transform->lpVtbl->GetOutputAvailableType(sys->transform, 0, idx, &pMediaType);
if (FAILED(hr))
break;
pMediaType->lpVtbl->GetGUID(pMediaType, &sMF_MT_SUBTYPE, &mediaGuid);
if (IsEqualGUID(&mediaGuid, guid))
{
*ppMediaType = pMediaType;
return S_OK;
}
pMediaType->lpVtbl->Release(pMediaType);
idx++;
}
return hr;
}
static HRESULT mf_create_output_sample(H264_CONTEXT* h264, H264_CONTEXT_MF* sys)
{
HRESULT hr = S_OK;
MFT_OUTPUT_STREAM_INFO streamInfo;
if (sys->outputSample)
{
sys->outputSample->lpVtbl->Release(sys->outputSample);
sys->outputSample = nullptr;
}
hr = sys->MFCreateSample(&sys->outputSample);
if (FAILED(hr))
{
WLog_Print(h264->log, WLOG_ERROR, "MFCreateSample failure: 0x%08" PRIX32 "", hr);
goto error;
}
hr = sys->transform->lpVtbl->GetOutputStreamInfo(sys->transform, 0, &streamInfo);
if (FAILED(hr))
{
WLog_Print(h264->log, WLOG_ERROR, "GetOutputStreamInfo failure: 0x%08" PRIX32 "", hr);
goto error;
}
hr = sys->MFCreateMemoryBuffer(streamInfo.cbSize, &sys->outputBuffer);
if (FAILED(hr))
{
WLog_Print(h264->log, WLOG_ERROR, "MFCreateMemoryBuffer failure: 0x%08" PRIX32 "", hr);
goto error;
}
sys->outputSample->lpVtbl->AddBuffer(sys->outputSample, sys->outputBuffer);
if (FAILED(hr))
{
WLog_Print(h264->log, WLOG_ERROR, "AddBuffer failure: 0x%08" PRIX32 "", hr);
goto error;
}
sys->outputBuffer->lpVtbl->Release(sys->outputBuffer);
error:
return hr;
}
static int mf_decompress(H264_CONTEXT* h264, const BYTE* pSrcData, UINT32 SrcSize)
{
HRESULT hr;
BYTE* pbBuffer = nullptr;
DWORD cbMaxLength = 0;
DWORD cbCurrentLength = 0;
DWORD outputStatus = 0;
IMFSample* inputSample = nullptr;
IMFMediaBuffer* inputBuffer = nullptr;
IMFMediaBuffer* outputBuffer = nullptr;
MFT_OUTPUT_DATA_BUFFER outputDataBuffer;
H264_CONTEXT_MF* sys = (H264_CONTEXT_MF*)h264->pSystemData;
UINT32* iStride = h264->iStride;
BYTE** pYUVData = h264->pYUVData;
hr = sys->MFCreateMemoryBuffer(SrcSize, &inputBuffer);
if (FAILED(hr))
{
WLog_Print(h264->log, WLOG_ERROR, "MFCreateMemoryBuffer failure: 0x%08" PRIX32 "", hr);
goto error;
}
hr = inputBuffer->lpVtbl->Lock(inputBuffer, &pbBuffer, &cbMaxLength, &cbCurrentLength);
if (FAILED(hr))
{
WLog_Print(h264->log, WLOG_ERROR, "Lock failure: 0x%08" PRIX32 "", hr);
goto error;
}
CopyMemory(pbBuffer, pSrcData, SrcSize);
hr = inputBuffer->lpVtbl->SetCurrentLength(inputBuffer, SrcSize);
if (FAILED(hr))
{
WLog_Print(h264->log, WLOG_ERROR, "SetCurrentLength failure: 0x%08" PRIX32 "", hr);
goto error;
}
hr = inputBuffer->lpVtbl->Unlock(inputBuffer);
if (FAILED(hr))
{
WLog_Print(h264->log, WLOG_ERROR, "Unlock failure: 0x%08" PRIX32 "", hr);
goto error;
}
hr = sys->MFCreateSample(&inputSample);
if (FAILED(hr))
{
WLog_Print(h264->log, WLOG_ERROR, "MFCreateSample failure: 0x%08" PRIX32 "", hr);
goto error;
}
inputSample->lpVtbl->AddBuffer(inputSample, inputBuffer);
if (FAILED(hr))
{
WLog_Print(h264->log, WLOG_ERROR, "AddBuffer failure: 0x%08" PRIX32 "", hr);
goto error;
}
inputBuffer->lpVtbl->Release(inputBuffer);
hr = sys->transform->lpVtbl->ProcessInput(sys->transform, 0, inputSample, 0);
if (FAILED(hr))
{
WLog_Print(h264->log, WLOG_ERROR, "ProcessInput failure: 0x%08" PRIX32 "", hr);
goto error;
}
hr = mf_create_output_sample(h264, sys);
if (FAILED(hr))
{
WLog_Print(h264->log, WLOG_ERROR, "mf_create_output_sample failure: 0x%08" PRIX32 "", hr);
goto error;
}
outputDataBuffer.dwStreamID = 0;
outputDataBuffer.dwStatus = 0;
outputDataBuffer.pEvents = nullptr;
outputDataBuffer.pSample = sys->outputSample;
hr = sys->transform->lpVtbl->ProcessOutput(sys->transform, 0, 1, &outputDataBuffer,
&outputStatus);
if (hr == MF_E_TRANSFORM_STREAM_CHANGE)
{
UINT32 stride = 0;
UINT64 frameSize = 0;
if (sys->outputType)
{
sys->outputType->lpVtbl->Release(sys->outputType);
sys->outputType = nullptr;
}
hr = mf_find_output_type(sys, &sMFVideoFormat_IYUV, &sys->outputType);
if (FAILED(hr))
{
WLog_Print(h264->log, WLOG_ERROR, "mf_find_output_type failure: 0x%08" PRIX32 "", hr);
goto error;
}
hr = sys->transform->lpVtbl->SetOutputType(sys->transform, 0, sys->outputType, 0);
if (FAILED(hr))
{
WLog_Print(h264->log, WLOG_ERROR, "SetOutputType failure: 0x%08" PRIX32 "", hr);
goto error;
}
hr = mf_create_output_sample(h264, sys);
if (FAILED(hr))
{
WLog_Print(h264->log, WLOG_ERROR, "mf_create_output_sample failure: 0x%08" PRIX32 "",
hr);
goto error;
}
hr = sys->outputType->lpVtbl->GetUINT64(sys->outputType, &sMF_MT_FRAME_SIZE, &frameSize);
if (FAILED(hr))
{
WLog_Print(h264->log, WLOG_ERROR,
"GetUINT64(MF_MT_FRAME_SIZE) failure: 0x%08" PRIX32 "", hr);
goto error;
}
sys->frameWidth = (UINT32)(frameSize >> 32);
sys->frameHeight = (UINT32)frameSize;
hr = sys->outputType->lpVtbl->GetUINT32(sys->outputType, &sMF_MT_DEFAULT_STRIDE, &stride);
if (FAILED(hr))
{
WLog_Print(h264->log, WLOG_ERROR,
"GetUINT32(MF_MT_DEFAULT_STRIDE) failure: 0x%08" PRIX32 "", hr);
goto error;
}
if (!avc420_ensure_buffer(h264, stride, sys->frameWidth, sys->frameHeight))
goto error;
}
else if (hr == MF_E_TRANSFORM_NEED_MORE_INPUT)
{
}
else if (FAILED(hr))
{
WLog_Print(h264->log, WLOG_ERROR, "ProcessOutput failure: 0x%08" PRIX32 "", hr);
goto error;
}
else
{
int offset = 0;
BYTE* buffer = nullptr;
DWORD bufferCount = 0;
DWORD cbMaxLength = 0;
DWORD cbCurrentLength = 0;
hr = sys->outputSample->lpVtbl->GetBufferCount(sys->outputSample, &bufferCount);
if (FAILED(hr))
{
WLog_Print(h264->log, WLOG_ERROR, "GetBufferCount failure: 0x%08" PRIX32 "", hr);
goto error;
}
hr = sys->outputSample->lpVtbl->GetBufferByIndex(sys->outputSample, 0, &outputBuffer);
if (FAILED(hr))
{
WLog_Print(h264->log, WLOG_ERROR, "GetBufferByIndex failure: 0x%08" PRIX32 "", hr);
goto error;
}
hr = outputBuffer->lpVtbl->Lock(outputBuffer, &buffer, &cbMaxLength, &cbCurrentLength);
if (FAILED(hr))
{
WLog_Print(h264->log, WLOG_ERROR, "Lock failure: 0x%08" PRIX32 "", hr);
goto error;
}
CopyMemory(pYUVData[0], &buffer[offset], iStride[0] * sys->frameHeight);
offset += iStride[0] * sys->frameHeight;
CopyMemory(pYUVData[1], &buffer[offset], iStride[1] * (sys->frameHeight / 2));
offset += iStride[1] * (sys->frameHeight / 2);
CopyMemory(pYUVData[2], &buffer[offset], iStride[2] * (sys->frameHeight / 2));
offset += iStride[2] * (sys->frameHeight / 2);
hr = outputBuffer->lpVtbl->Unlock(outputBuffer);
if (FAILED(hr))
{
WLog_Print(h264->log, WLOG_ERROR, "Unlock failure: 0x%08" PRIX32 "", hr);
goto error;
}
outputBuffer->lpVtbl->Release(outputBuffer);
}
inputSample->lpVtbl->Release(inputSample);
return 1;
error:
(void)fprintf(stderr, "mf_decompress error\n");
return -1;
}
static int mf_compress(H264_CONTEXT* h264, const BYTE** ppSrcYuv, const UINT32* pStride,
BYTE** ppDstData, UINT32* pDstSize)
{
H264_CONTEXT_MF* sys = (H264_CONTEXT_MF*)h264->pSystemData;
return 1;
}
static BOOL mf_plat_loaded(H264_CONTEXT_MF* sys)
{
return sys->MFStartup && sys->MFShutdown && sys->MFCreateSample && sys->MFCreateMemoryBuffer &&
sys->MFCreateMediaType;
}
static void mf_uninit(H264_CONTEXT* h264)
{
H264_CONTEXT_MF* sys = (H264_CONTEXT_MF*)h264->pSystemData;
if (sys)
{
if (sys->transform)
{
sys->transform->lpVtbl->Release(sys->transform);
sys->transform = nullptr;
}
if (sys->codecApi)
{
sys->codecApi->lpVtbl->Release(sys->codecApi);
sys->codecApi = nullptr;
}
if (sys->inputType)
{
sys->inputType->lpVtbl->Release(sys->inputType);
sys->inputType = nullptr;
}
if (sys->outputType)
{
sys->outputType->lpVtbl->Release(sys->outputType);
sys->outputType = nullptr;
}
if (sys->outputSample)
{
sys->outputSample->lpVtbl->Release(sys->outputSample);
sys->outputSample = nullptr;
}
if (sys->mfplat)
{
if (mf_plat_loaded(sys))
sys->MFShutdown();
FreeLibrary(sys->mfplat);
sys->mfplat = nullptr;
if (mf_plat_loaded(sys))
CoUninitialize();
}
for (size_t x = 0; x < sizeof(h264->pYUVData) / sizeof(h264->pYUVData[0]); x++)
winpr_aligned_free(h264->pYUVData[x]);
memset(h264->pYUVData, 0, sizeof(h264->pYUVData));
memset(h264->iStride, 0, sizeof(h264->iStride));
free(sys);
h264->pSystemData = nullptr;
}
}
static BOOL mf_init(H264_CONTEXT* h264)
{
HRESULT hr;
H264_CONTEXT_MF* sys = (H264_CONTEXT_MF*)calloc(1, sizeof(H264_CONTEXT_MF));
if (!sys)
goto error;
h264->pSystemData = (void*)sys;
/* http://decklink-sdk-delphi.googlecode.com/svn/trunk/Blackmagic%20DeckLink%20SDK%209.7/Win/Samples/Streaming/StreamingPreview/DecoderMF.cpp
*/
sys->mfplat = LoadLibraryA("mfplat.dll");
if (!sys->mfplat)
goto error;
sys->MFStartup = GetProcAddressAs(sys->mfplat, "MFStartup", pfnMFStartup);
sys->MFShutdown = GetProcAddressAs(sys->mfplat, "MFShutdown", pfnMFShutdown);
sys->MFCreateSample = GetProcAddressAs(sys->mfplat, "MFCreateSample", pfnMFCreateSample);
sys->MFCreateMemoryBuffer =
GetProcAddressAs(sys->mfplat, "MFCreateMemoryBuffer", pfnMFCreateMemoryBuffer);
sys->MFCreateMediaType =
GetProcAddressAs(sys->mfplat, "MFCreateMediaType", pfnMFCreateMediaType);
if (!mf_plat_loaded(sys))
goto error;
CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
if (h264->Compressor)
{
}
else
{
VARIANT var = WINPR_C_ARRAY_INIT;
hr = sys->MFStartup(MF_VERSION, 0);
if (FAILED(hr))
{
WLog_Print(h264->log, WLOG_ERROR, "MFStartup failure: 0x%08" PRIX32 "", hr);
goto error;
}
hr = CoCreateInstance(&sCLSID_CMSH264DecoderMFT, nullptr, CLSCTX_INPROC_SERVER,
&sIID_IMFTransform, (void**)&sys->transform);
if (FAILED(hr))
{
WLog_Print(h264->log, WLOG_ERROR,
"CoCreateInstance(CLSID_CMSH264DecoderMFT) failure: 0x%08" PRIX32 "", hr);
goto error;
}
hr = sys->transform->lpVtbl->QueryInterface(sys->transform, &sIID_ICodecAPI,
(void**)&sys->codecApi);
if (FAILED(hr))
{
WLog_Print(h264->log, WLOG_ERROR,
"QueryInterface(IID_ICodecAPI) failure: 0x%08" PRIX32 "", hr);
goto error;
}
var.vt = VT_UI4;
var.ulVal = 1;
hr = sys->codecApi->lpVtbl->SetValue(sys->codecApi, &sCODECAPI_AVLowLatencyMode, &var);
if (FAILED(hr))
{
WLog_Print(h264->log, WLOG_ERROR,
"SetValue(CODECAPI_AVLowLatencyMode) failure: 0x%08" PRIX32 "", hr);
goto error;
}
hr = sys->MFCreateMediaType(&sys->inputType);
if (FAILED(hr))
{
WLog_Print(h264->log, WLOG_ERROR, "MFCreateMediaType failure: 0x%08" PRIX32 "", hr);
goto error;
}
hr = sys->inputType->lpVtbl->SetGUID(sys->inputType, &sMF_MT_MAJOR_TYPE,
&sMFMediaType_Video);
if (FAILED(hr))
{
WLog_Print(h264->log, WLOG_ERROR, "SetGUID(MF_MT_MAJOR_TYPE) failure: 0x%08" PRIX32 "",
hr);
goto error;
}
hr = sys->inputType->lpVtbl->SetGUID(sys->inputType, &sMF_MT_SUBTYPE, &sMFVideoFormat_H264);
if (FAILED(hr))
{
WLog_Print(h264->log, WLOG_ERROR, "SetGUID(MF_MT_SUBTYPE) failure: 0x%08" PRIX32 "",
hr);
goto error;
}
hr = sys->transform->lpVtbl->SetInputType(sys->transform, 0, sys->inputType, 0);
if (FAILED(hr))
{
WLog_Print(h264->log, WLOG_ERROR, "SetInputType failure: 0x%08" PRIX32 "", hr);
goto error;
}
hr = mf_find_output_type(sys, &sMFVideoFormat_IYUV, &sys->outputType);
if (FAILED(hr))
{
WLog_Print(h264->log, WLOG_ERROR, "mf_find_output_type failure: 0x%08" PRIX32 "", hr);
goto error;
}
hr = sys->transform->lpVtbl->SetOutputType(sys->transform, 0, sys->outputType, 0);
if (FAILED(hr))
{
WLog_Print(h264->log, WLOG_ERROR, "SetOutputType failure: 0x%08" PRIX32 "", hr);
goto error;
}
hr = mf_create_output_sample(h264, sys);
if (FAILED(hr))
{
WLog_Print(h264->log, WLOG_ERROR, "mf_create_output_sample failure: 0x%08" PRIX32 "",
hr);
goto error;
}
}
return TRUE;
error:
WLog_Print(h264->log, WLOG_ERROR, "mf_init failure");
mf_uninit(h264);
return FALSE;
}
const H264_CONTEXT_SUBSYSTEM g_Subsystem_MF = { "MediaFoundation", mf_init, mf_uninit,
mf_decompress, mf_compress };
+662
View File
@@ -0,0 +1,662 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* H.264 Bitmap Compression
*
* Copyright 2014 Mike McDonald <Mike.McDonald@software.dell.com>
* Copyright 2015 Vic Lee <llyzs.vic@gmail.com>
* Copyright 2014 Armin Novak <armin.novak@gmail.com>
*
* 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 <freerdp/config.h>
#include <winpr/winpr.h>
#include <winpr/library.h>
#include <winpr/assert.h>
#include <winpr/cast.h>
#include <freerdp/log.h>
#include <freerdp/codec/h264.h>
#include <wels/codec_def.h>
#include <wels/codec_api.h>
#include <wels/codec_ver.h>
#include "h264.h"
typedef void (*pWelsGetCodecVersionEx)(OpenH264Version* pVersion);
typedef long (*pWelsCreateDecoder)(ISVCDecoder** ppDecoder);
typedef void (*pWelsDestroyDecoder)(ISVCDecoder* pDecoder);
typedef int (*pWelsCreateSVCEncoder)(ISVCEncoder** ppEncoder);
typedef void (*pWelsDestroySVCEncoder)(ISVCEncoder* pEncoder);
typedef struct
{
#if defined(WITH_OPENH264_LOADING)
HMODULE lib;
OpenH264Version version;
#endif
WINPR_ATTR_NODISCARD pWelsGetCodecVersionEx WelsGetCodecVersionEx;
WINPR_ATTR_NODISCARD pWelsCreateDecoder WelsCreateDecoder;
pWelsDestroyDecoder WelsDestroyDecoder;
WINPR_ATTR_NODISCARD pWelsCreateSVCEncoder WelsCreateSVCEncoder;
pWelsDestroySVCEncoder WelsDestroySVCEncoder;
ISVCDecoder* pDecoder;
ISVCEncoder* pEncoder;
SEncParamExt EncParamExt;
} H264_CONTEXT_OPENH264;
#if defined(WITH_OPENH264_LOADING)
static const char* openh264_library_names[] = {
#if defined(_WIN32)
"openh264.dll"
#elif defined(__APPLE__)
"libopenh264.dylib"
#else
"libopenh264.so.7", "libopenh264.so.2.5.0", "libopenh264.so.2.4.1", "libopenh264.so.2.4.0",
"libopenh264.so.2.3.1", "libopenh264.so.2.3.0", "libopenh264.so",
#endif
};
#endif
static void openh264_trace_callback(void* ctx, int level, const char* message)
{
H264_CONTEXT* h264 = ctx;
if (h264)
WLog_Print(h264->log, WLOG_TRACE, "%d - %s", level, message);
}
static int openh264_decompress(H264_CONTEXT* WINPR_RESTRICT h264,
const BYTE* WINPR_RESTRICT pSrcData, UINT32 SrcSize)
{
DECODING_STATE state = dsInvalidArgument;
SBufferInfo sBufferInfo = WINPR_C_ARRAY_INIT;
SSysMEMBuffer* pSystemBuffer = nullptr;
H264_CONTEXT_OPENH264* sys = nullptr;
UINT32* iStride = nullptr;
BYTE** pYUVData = nullptr;
WINPR_ASSERT(h264);
WINPR_ASSERT(pSrcData || (SrcSize == 0));
sys = (H264_CONTEXT_OPENH264*)h264->pSystemData;
WINPR_ASSERT(sys);
iStride = h264->iStride;
WINPR_ASSERT(iStride);
pYUVData = h264->pYUVData;
WINPR_ASSERT(pYUVData);
if (!sys->pDecoder)
return -2001;
/*
* Decompress the image. The RDP host only seems to send I420 format.
*/
pYUVData[0] = nullptr;
pYUVData[1] = nullptr;
pYUVData[2] = nullptr;
WINPR_ASSERT(sys->pDecoder);
state = (*sys->pDecoder)
->DecodeFrame2(sys->pDecoder, pSrcData, WINPR_ASSERTING_INT_CAST(int, SrcSize),
pYUVData, &sBufferInfo);
if (sBufferInfo.iBufferStatus != 1)
{
if (state == dsNoParamSets)
{
/* this happens on the first frame due to missing parameter sets */
state =
(*sys->pDecoder)->DecodeFrame2(sys->pDecoder, nullptr, 0, pYUVData, &sBufferInfo);
}
else if (state == dsErrorFree)
{
/* call DecodeFrame2 again to decode without delay */
state =
(*sys->pDecoder)->DecodeFrame2(sys->pDecoder, nullptr, 0, pYUVData, &sBufferInfo);
}
else
{
WLog_Print(h264->log, WLOG_WARN, "DecodeFrame2 state: 0x%04X iBufferStatus: %d", state,
sBufferInfo.iBufferStatus);
return -2002;
}
}
if (state != dsErrorFree)
{
WLog_Print(h264->log, WLOG_WARN, "DecodeFrame2 state: 0x%02X", state);
return -2003;
}
#if OPENH264_MAJOR >= 2
state = (*sys->pDecoder)->FlushFrame(sys->pDecoder, pYUVData, &sBufferInfo);
if (state != dsErrorFree)
{
WLog_Print(h264->log, WLOG_WARN, "FlushFrame state: 0x%02X", state);
return -2003;
}
#endif
pSystemBuffer = &sBufferInfo.UsrData.sSystemBuffer;
iStride[0] = WINPR_ASSERTING_INT_CAST(uint32_t, pSystemBuffer->iStride[0]);
iStride[1] = WINPR_ASSERTING_INT_CAST(uint32_t, pSystemBuffer->iStride[1]);
iStride[2] = WINPR_ASSERTING_INT_CAST(uint32_t, pSystemBuffer->iStride[1]);
if (sBufferInfo.iBufferStatus != 1)
{
WLog_Print(h264->log, WLOG_WARN, "DecodeFrame2 iBufferStatus: %d",
sBufferInfo.iBufferStatus);
return 0;
}
if (state != dsErrorFree)
{
WLog_Print(h264->log, WLOG_WARN, "DecodeFrame2 state: 0x%02X", state);
return -2003;
}
if (pSystemBuffer->iFormat != videoFormatI420)
return -2004;
if (!pYUVData[0] || !pYUVData[1] || !pYUVData[2])
return -2005;
return 1;
}
static int openh264_compress(H264_CONTEXT* WINPR_RESTRICT h264,
const BYTE** WINPR_RESTRICT pYUVData,
const UINT32* WINPR_RESTRICT iStride, BYTE** WINPR_RESTRICT ppDstData,
UINT32* WINPR_RESTRICT pDstSize)
{
int status = 0;
SFrameBSInfo info = WINPR_C_ARRAY_INIT;
SSourcePicture pic = WINPR_C_ARRAY_INIT;
H264_CONTEXT_OPENH264* sys = nullptr;
WINPR_ASSERT(h264);
WINPR_ASSERT(pYUVData);
WINPR_ASSERT(iStride);
WINPR_ASSERT(ppDstData);
WINPR_ASSERT(pDstSize);
sys = &((H264_CONTEXT_OPENH264*)h264->pSystemData)[0];
WINPR_ASSERT(sys);
if (!sys->pEncoder)
return -1;
if (!pYUVData[0] || !pYUVData[1] || !pYUVData[2])
return -1;
if ((h264->width > INT_MAX) || (h264->height > INT_MAX))
return -1;
if ((h264->FrameRate > INT_MAX) || (h264->NumberOfThreads > INT_MAX) ||
(h264->BitRate > INT_MAX) || (h264->QP > INT_MAX))
return -1;
WINPR_ASSERT(sys->pEncoder);
if ((sys->EncParamExt.iPicWidth != (int)h264->width) ||
(sys->EncParamExt.iPicHeight != (int)h264->height))
{
WINPR_ASSERT((*sys->pEncoder)->GetDefaultParams);
status = (*sys->pEncoder)->GetDefaultParams(sys->pEncoder, &sys->EncParamExt);
if (status < 0)
{
WLog_Print(h264->log, WLOG_ERROR,
"Failed to get OpenH264 default parameters (status=%d)", status);
return status;
}
EUsageType usageType = SCREEN_CONTENT_REAL_TIME;
switch (h264->UsageType)
{
case H264_CAMERA_VIDEO_NON_REAL_TIME:
usageType = CAMERA_VIDEO_NON_REAL_TIME;
break;
case H264_CAMERA_VIDEO_REAL_TIME:
usageType = CAMERA_VIDEO_REAL_TIME;
break;
case H264_SCREEN_CONTENT_NON_REAL_TIME:
usageType = SCREEN_CONTENT_NON_REAL_TIME;
break;
case H264_SCREEN_CONTENT_REAL_TIME:
default:
break;
}
sys->EncParamExt.iUsageType = usageType;
sys->EncParamExt.iPicWidth = WINPR_ASSERTING_INT_CAST(int, h264->width);
sys->EncParamExt.iPicHeight = WINPR_ASSERTING_INT_CAST(int, h264->height);
sys->EncParamExt.fMaxFrameRate = WINPR_ASSERTING_INT_CAST(short, h264->FrameRate);
sys->EncParamExt.iMaxBitrate = UNSPECIFIED_BIT_RATE;
sys->EncParamExt.bEnableDenoise = 0;
sys->EncParamExt.bEnableLongTermReference = 0;
sys->EncParamExt.iSpatialLayerNum = 1;
sys->EncParamExt.iMultipleThreadIdc =
WINPR_ASSERTING_INT_CAST(unsigned short, h264->NumberOfThreads);
sys->EncParamExt.sSpatialLayers[0].fFrameRate =
WINPR_ASSERTING_INT_CAST(short, h264->FrameRate);
sys->EncParamExt.sSpatialLayers[0].iVideoWidth = sys->EncParamExt.iPicWidth;
sys->EncParamExt.sSpatialLayers[0].iVideoHeight = sys->EncParamExt.iPicHeight;
sys->EncParamExt.sSpatialLayers[0].iMaxSpatialBitrate = sys->EncParamExt.iMaxBitrate;
switch (h264->RateControlMode)
{
case H264_RATECONTROL_VBR:
sys->EncParamExt.iRCMode = RC_BITRATE_MODE;
sys->EncParamExt.iTargetBitrate = (int)h264->BitRate;
sys->EncParamExt.sSpatialLayers[0].iSpatialBitrate =
sys->EncParamExt.iTargetBitrate;
sys->EncParamExt.bEnableFrameSkip = 1;
break;
case H264_RATECONTROL_CQP:
sys->EncParamExt.iRCMode = RC_OFF_MODE;
sys->EncParamExt.sSpatialLayers[0].iDLayerQp = (int)h264->QP;
sys->EncParamExt.bEnableFrameSkip = 0;
break;
default:
break;
}
if (sys->EncParamExt.iMultipleThreadIdc > 1)
{
#if (OPENH264_MAJOR == 1) && (OPENH264_MINOR <= 5)
sys->EncParamExt.sSpatialLayers[0].sSliceCfg.uiSliceMode = SM_AUTO_SLICE;
#else
sys->EncParamExt.sSpatialLayers[0].sSliceArgument.uiSliceMode = SM_FIXEDSLCNUM_SLICE;
#endif
}
WINPR_ASSERT((*sys->pEncoder)->InitializeExt);
status = (*sys->pEncoder)->InitializeExt(sys->pEncoder, &sys->EncParamExt);
if (status < 0)
{
WLog_Print(h264->log, WLOG_ERROR, "Failed to initialize OpenH264 encoder (status=%d)",
status);
return status;
}
WINPR_ASSERT((*sys->pEncoder)->GetOption);
status =
(*sys->pEncoder)
->GetOption(sys->pEncoder, ENCODER_OPTION_SVC_ENCODE_PARAM_EXT, &sys->EncParamExt);
if (status < 0)
{
WLog_Print(h264->log, WLOG_ERROR,
"Failed to get initial OpenH264 encoder parameters (status=%d)", status);
return status;
}
}
else
{
switch (h264->RateControlMode)
{
case H264_RATECONTROL_VBR:
if (sys->EncParamExt.iTargetBitrate != (int)h264->BitRate)
{
SBitrateInfo bitrate = WINPR_C_ARRAY_INIT;
sys->EncParamExt.iTargetBitrate = (int)h264->BitRate;
bitrate.iLayer = SPATIAL_LAYER_ALL;
bitrate.iBitrate = (int)h264->BitRate;
WINPR_ASSERT((*sys->pEncoder)->SetOption);
status = (*sys->pEncoder)
->SetOption(sys->pEncoder, ENCODER_OPTION_BITRATE, &bitrate);
if (status < 0)
{
WLog_Print(h264->log, WLOG_ERROR,
"Failed to set encoder bitrate (status=%d)", status);
return status;
}
}
if ((uint32_t)sys->EncParamExt.fMaxFrameRate != h264->FrameRate)
{
sys->EncParamExt.fMaxFrameRate = WINPR_ASSERTING_INT_CAST(int, h264->FrameRate);
WINPR_ASSERT((*sys->pEncoder)->SetOption);
status = (*sys->pEncoder)
->SetOption(sys->pEncoder, ENCODER_OPTION_FRAME_RATE,
&sys->EncParamExt.fMaxFrameRate);
if (status < 0)
{
WLog_Print(h264->log, WLOG_ERROR,
"Failed to set encoder framerate (status=%d)", status);
return status;
}
}
break;
case H264_RATECONTROL_CQP:
if (sys->EncParamExt.sSpatialLayers[0].iDLayerQp != (int)h264->QP)
{
sys->EncParamExt.sSpatialLayers[0].iDLayerQp = (int)h264->QP;
WINPR_ASSERT((*sys->pEncoder)->SetOption);
status = (*sys->pEncoder)
->SetOption(sys->pEncoder, ENCODER_OPTION_SVC_ENCODE_PARAM_EXT,
&sys->EncParamExt);
if (status < 0)
{
WLog_Print(h264->log, WLOG_ERROR,
"Failed to set encoder parameters (status=%d)", status);
return status;
}
}
break;
default:
break;
}
}
pic.iPicWidth = (int)h264->width;
pic.iPicHeight = (int)h264->height;
pic.iColorFormat = videoFormatI420;
pic.iStride[0] = (int)iStride[0];
pic.iStride[1] = (int)iStride[1];
pic.iStride[2] = (int)iStride[2];
pic.pData[0] = WINPR_CAST_CONST_PTR_AWAY(pYUVData[0], BYTE*);
pic.pData[1] = WINPR_CAST_CONST_PTR_AWAY(pYUVData[1], BYTE*);
pic.pData[2] = WINPR_CAST_CONST_PTR_AWAY(pYUVData[2], BYTE*);
WINPR_ASSERT((*sys->pEncoder)->EncodeFrame);
status = (*sys->pEncoder)->EncodeFrame(sys->pEncoder, &pic, &info);
if (status < 0)
{
WLog_Print(h264->log, WLOG_ERROR, "Failed to encode frame (status=%d)", status);
return status;
}
*ppDstData = info.sLayerInfo[0].pBsBuf;
*pDstSize = 0;
for (int i = 0; i < info.iLayerNum; i++)
{
for (int j = 0; j < info.sLayerInfo[i].iNalCount; j++)
{
const int val = info.sLayerInfo[i].pNalLengthInByte[j];
*pDstSize += WINPR_ASSERTING_INT_CAST(uint32_t, val);
}
}
return 1;
}
static void openh264_uninit(H264_CONTEXT* h264)
{
H264_CONTEXT_OPENH264* sysContexts = nullptr;
WINPR_ASSERT(h264);
sysContexts = (H264_CONTEXT_OPENH264*)h264->pSystemData;
if (sysContexts)
{
for (UINT32 x = 0; x < h264->numSystemData; x++)
{
H264_CONTEXT_OPENH264* sys = &sysContexts[x];
if (sys->pDecoder)
{
(*sys->pDecoder)->Uninitialize(sys->pDecoder);
sysContexts->WelsDestroyDecoder(sys->pDecoder);
sys->pDecoder = nullptr;
}
if (sys->pEncoder)
{
(*sys->pEncoder)->Uninitialize(sys->pEncoder);
sysContexts->WelsDestroySVCEncoder(sys->pEncoder);
sys->pEncoder = nullptr;
}
}
#if defined(WITH_OPENH264_LOADING)
if (sysContexts->lib)
FreeLibrary(sysContexts->lib);
#endif
free(h264->pSystemData);
h264->pSystemData = nullptr;
}
}
#if defined(WITH_OPENH264_LOADING)
static BOOL openh264_load_functionpointers(H264_CONTEXT* h264, const char* name)
{
H264_CONTEXT_OPENH264* sysContexts;
WINPR_ASSERT(name);
if (!h264)
return FALSE;
sysContexts = h264->pSystemData;
if (!sysContexts)
return FALSE;
sysContexts->lib = LoadLibraryA(name);
if (!sysContexts->lib)
return FALSE;
sysContexts->WelsGetCodecVersionEx =
GetProcAddressAs(sysContexts->lib, "WelsGetCodecVersionEx", pWelsGetCodecVersionEx);
sysContexts->WelsCreateDecoder =
GetProcAddressAs(sysContexts->lib, "WelsCreateDecoder", pWelsCreateDecoder);
sysContexts->WelsDestroyDecoder =
GetProcAddressAs(sysContexts->lib, "WelsDestroyDecoder", pWelsDestroyDecoder);
sysContexts->WelsCreateSVCEncoder =
GetProcAddressAs(sysContexts->lib, "WelsCreateSVCEncoder", pWelsCreateSVCEncoder);
sysContexts->WelsDestroySVCEncoder =
GetProcAddressAs(sysContexts->lib, "WelsDestroySVCEncoder", pWelsDestroySVCEncoder);
if (!sysContexts->WelsCreateDecoder || !sysContexts->WelsDestroyDecoder ||
!sysContexts->WelsCreateSVCEncoder || !sysContexts->WelsDestroySVCEncoder ||
!sysContexts->WelsGetCodecVersionEx)
{
FreeLibrary(sysContexts->lib);
sysContexts->lib = nullptr;
return FALSE;
}
sysContexts->WelsGetCodecVersionEx(&sysContexts->version);
WLog_Print(h264->log, WLOG_INFO, "loaded %s %d.%d.%d", name, sysContexts->version.uMajor,
sysContexts->version.uMinor, sysContexts->version.uRevision);
if ((sysContexts->version.uMajor < 1) ||
((sysContexts->version.uMajor == 1) && (sysContexts->version.uMinor < 6)))
{
WLog_Print(
h264->log, WLOG_ERROR,
"OpenH264 %s %d.%d.%d is too old, need at least version 1.6.0 for dynamic loading",
name, sysContexts->version.uMajor, sysContexts->version.uMinor,
sysContexts->version.uRevision);
FreeLibrary(sysContexts->lib);
sysContexts->lib = nullptr;
return FALSE;
}
return TRUE;
}
#endif
static BOOL openh264_init(H264_CONTEXT* h264)
{
#if defined(WITH_OPENH264_LOADING)
BOOL success = FALSE;
#endif
long status = 0;
H264_CONTEXT_OPENH264* sysContexts = nullptr;
static int traceLevel = WELS_LOG_DEBUG;
#if (OPENH264_MAJOR == 1) && (OPENH264_MINOR <= 5)
static EVideoFormatType videoFormat = videoFormatI420;
#endif
static WelsTraceCallback traceCallback = openh264_trace_callback;
WINPR_ASSERT(h264);
h264->numSystemData = 1;
sysContexts =
(H264_CONTEXT_OPENH264*)calloc(h264->numSystemData, sizeof(H264_CONTEXT_OPENH264));
if (!sysContexts)
goto EXCEPTION;
h264->pSystemData = (void*)sysContexts;
#if defined(WITH_OPENH264_LOADING)
for (size_t i = 0; i < ARRAYSIZE(openh264_library_names); i++)
{
const char* current = openh264_library_names[i];
success = openh264_load_functionpointers(h264, current);
if (success)
break;
}
if (!success)
goto EXCEPTION;
#else
sysContexts->WelsGetCodecVersionEx = WelsGetCodecVersionEx;
sysContexts->WelsCreateDecoder = WelsCreateDecoder;
sysContexts->WelsDestroyDecoder = WelsDestroyDecoder;
sysContexts->WelsCreateSVCEncoder = WelsCreateSVCEncoder;
sysContexts->WelsDestroySVCEncoder = WelsDestroySVCEncoder;
#endif
for (UINT32 x = 0; x < h264->numSystemData; x++)
{
SDecodingParam sDecParam = WINPR_C_ARRAY_INIT;
H264_CONTEXT_OPENH264* sys = &sysContexts[x];
if (h264->Compressor)
{
sysContexts->WelsCreateSVCEncoder(&sys->pEncoder);
if (!sys->pEncoder)
{
WLog_Print(h264->log, WLOG_ERROR, "Failed to create OpenH264 encoder");
goto EXCEPTION;
}
}
else
{
sysContexts->WelsCreateDecoder(&sys->pDecoder);
if (!sys->pDecoder)
{
WLog_Print(h264->log, WLOG_ERROR, "Failed to create OpenH264 decoder");
goto EXCEPTION;
}
#if (OPENH264_MAJOR == 1) && (OPENH264_MINOR <= 5)
sDecParam.eOutputColorFormat = videoFormatI420;
#endif
sDecParam.eEcActiveIdc = ERROR_CON_FRAME_COPY;
sDecParam.sVideoProperty.eVideoBsType = VIDEO_BITSTREAM_AVC;
status = (*sys->pDecoder)->Initialize(sys->pDecoder, &sDecParam);
if (status != 0)
{
WLog_Print(h264->log, WLOG_ERROR,
"Failed to initialize OpenH264 decoder (status=%ld)", status);
goto EXCEPTION;
}
#if (OPENH264_MAJOR == 1) && (OPENH264_MINOR <= 5)
status =
(*sys->pDecoder)->SetOption(sys->pDecoder, DECODER_OPTION_DATAFORMAT, &videoFormat);
#endif
if (status != 0)
{
WLog_Print(h264->log, WLOG_ERROR,
"Failed to set data format option on OpenH264 decoder (status=%ld)",
status);
goto EXCEPTION;
}
if (WLog_GetLogLevel(h264->log) == WLOG_TRACE)
{
status = (*sys->pDecoder)
->SetOption(sys->pDecoder, DECODER_OPTION_TRACE_LEVEL, &traceLevel);
if (status != 0)
{
WLog_Print(h264->log, WLOG_ERROR,
"Failed to set trace level option on OpenH264 decoder (status=%ld)",
status);
goto EXCEPTION;
}
status = (*sys->pDecoder)
->SetOption(sys->pDecoder, DECODER_OPTION_TRACE_CALLBACK_CONTEXT,
(void*)&h264);
if (status != 0)
{
WLog_Print(h264->log, WLOG_ERROR,
"Failed to set trace callback context option on OpenH264 decoder "
"(status=%ld)",
status);
goto EXCEPTION;
}
status = (*sys->pDecoder)
->SetOption(sys->pDecoder, DECODER_OPTION_TRACE_CALLBACK,
(void*)&traceCallback);
if (status != 0)
{
WLog_Print(
h264->log, WLOG_ERROR,
"Failed to set trace callback option on OpenH264 decoder (status=%ld)",
status);
goto EXCEPTION;
}
}
}
}
h264->hwAccel = FALSE; /* not supported */
return TRUE;
EXCEPTION:
openh264_uninit(h264);
return FALSE;
}
const H264_CONTEXT_SUBSYSTEM g_Subsystem_OpenH264 = { "OpenH264", openh264_init, openh264_uninit,
openh264_decompress, openh264_compress };
+457
View File
@@ -0,0 +1,457 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* RLE Compressed Bitmap Stream
*
* Copyright 2011 Jay Sorg <jay.sorg@gmail.com>
* Copyright 2016 Armin Novak <armin.novak@thincast.com>
* Copyright 2016 Thincast Technologies GmbH
*
* 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 <winpr/assert.h>
#include <winpr/cast.h>
#include <winpr/wtypes.h>
/* do not compile the file directly */
/**
* Write a foreground/background image to a destination buffer.
*/
WINPR_ATTR_NODISCARD
static inline BYTE* WRITEFGBGIMAGE(BYTE* WINPR_RESTRICT pbDest,
const BYTE* WINPR_RESTRICT pbDestEnd, UINT32 rowDelta,
BYTE bitmask, PIXEL fgPel, UINT32 cBits)
{
PIXEL xorPixel = 0;
BYTE mask = 0x01;
if (cBits > 8)
{
WLog_ERR(TAG, "cBits %" PRIu32 " > 8", cBits);
return nullptr;
}
if (!ENSURE_CAPACITY(pbDest, pbDestEnd, cBits))
return nullptr;
UNROLL(cBits, {
PIXEL data = 0;
DESTREADPIXEL(xorPixel, pbDest - rowDelta);
if (bitmask & mask)
data = xorPixel ^ fgPel;
else
data = xorPixel;
DESTWRITEPIXEL(pbDest, data);
mask = WINPR_ASSERTING_INT_CAST(BYTE, (mask << 1) & 0xFF);
});
return pbDest;
}
/**
* Write a foreground/background image to a destination buffer
* for the first line of compressed data.
*/
WINPR_ATTR_NODISCARD
static inline BYTE* WRITEFIRSTLINEFGBGIMAGE(BYTE* WINPR_RESTRICT pbDest,
const BYTE* WINPR_RESTRICT pbDestEnd, BYTE bitmask,
PIXEL fgPel, UINT32 cBits)
{
BYTE mask = 0x01;
if (cBits > 8)
{
WLog_ERR(TAG, "cBits %" PRIu32 " > 8", cBits);
return nullptr;
}
if (!ENSURE_CAPACITY(pbDest, pbDestEnd, cBits))
return nullptr;
UNROLL(cBits, {
PIXEL data;
if (bitmask & mask)
data = fgPel;
else
data = BLACK_PIXEL;
DESTWRITEPIXEL(pbDest, data);
mask = WINPR_ASSERTING_INT_CAST(BYTE, (mask << 1) & 0xFF);
});
return pbDest;
}
/**
* Decompress an RLE compressed bitmap.
*/
WINPR_ATTR_NODISCARD
static inline BOOL RLEDECOMPRESS(const BYTE* WINPR_RESTRICT pbSrcBuffer, UINT32 cbSrcBuffer,
BYTE* WINPR_RESTRICT pbDestBuffer, UINT32 rowDelta, UINT32 width,
UINT32 height)
{
const BYTE* pbSrc = pbSrcBuffer;
BYTE* pbDest = pbDestBuffer;
PIXEL temp = 0;
PIXEL fgPel = WHITE_PIXEL;
BOOL fInsertFgPel = FALSE;
BOOL fFirstLine = TRUE;
BYTE bitmask = 0;
PIXEL pixelA = 0;
PIXEL pixelB = 0;
UINT32 runLength = 0;
UINT32 code = 0;
UINT32 advance = 0;
RLEEXTRA
if ((rowDelta == 0) || (rowDelta < width))
{
WLog_ERR(TAG, "Invalid arguments: rowDelta=%" PRIu32 " == 0 || < width=%" PRIu32, rowDelta,
width);
return FALSE;
}
if (!pbSrcBuffer || !pbDestBuffer)
{
WLog_ERR(TAG, "Invalid arguments: pbSrcBuffer=%p, pbDestBuffer=%p",
WINPR_CXX_COMPAT_CAST(const void*, pbSrcBuffer),
WINPR_CXX_COMPAT_CAST(const void*, pbDestBuffer));
return FALSE;
}
const BYTE* pbEnd = &pbSrcBuffer[cbSrcBuffer];
const BYTE* pbDestEnd = &pbDestBuffer[1ULL * rowDelta * height];
while (pbSrc < pbEnd)
{
/* Watch out for the end of the first scanline. */
if (fFirstLine)
{
if ((UINT32)(pbDest - pbDestBuffer) >= rowDelta)
{
fFirstLine = FALSE;
fInsertFgPel = FALSE;
}
}
/*
Extract the compression order code ID from the compression
order header.
*/
code = ExtractCodeId(*pbSrc);
#if defined(WITH_DEBUG_CODECS)
WLog_VRB(TAG, "pbSrc=%p code=%s, rem=%" PRIuz, pbSrc, rle_code_str(code), pbEnd - pbSrc);
#endif
/* Handle Background Run Orders. */
if ((code == REGULAR_BG_RUN) || (code == MEGA_MEGA_BG_RUN))
{
runLength = ExtractRunLength(code, pbSrc, pbEnd, &advance);
if (advance == 0)
return FALSE;
pbSrc = pbSrc + advance;
if (fFirstLine)
{
if (fInsertFgPel)
{
if (!ENSURE_CAPACITY(pbDest, pbDestEnd, 1))
return FALSE;
DESTWRITEPIXEL(pbDest, fgPel);
runLength = runLength - 1;
}
if (!ENSURE_CAPACITY(pbDest, pbDestEnd, runLength))
return FALSE;
UNROLL(runLength, { DESTWRITEPIXEL(pbDest, BLACK_PIXEL); });
}
else
{
if (fInsertFgPel)
{
DESTREADPIXEL(temp, pbDest - rowDelta);
if (!ENSURE_CAPACITY(pbDest, pbDestEnd, 1))
return FALSE;
DESTWRITEPIXEL(pbDest, temp ^ fgPel);
runLength--;
}
if (!ENSURE_CAPACITY(pbDest, pbDestEnd, runLength))
return FALSE;
UNROLL(runLength, {
DESTREADPIXEL(temp, pbDest - rowDelta);
DESTWRITEPIXEL(pbDest, temp);
});
}
/* A follow-on background run order will need a foreground pel inserted. */
fInsertFgPel = TRUE;
continue;
}
/* For any of the other run-types a follow-on background run
order does not need a foreground pel inserted. */
fInsertFgPel = FALSE;
switch (code)
{
/* Handle Foreground Run Orders. */
case REGULAR_FG_RUN:
case MEGA_MEGA_FG_RUN:
case LITE_SET_FG_FG_RUN:
case MEGA_MEGA_SET_FG_RUN:
runLength = ExtractRunLength(code, pbSrc, pbEnd, &advance);
if (advance == 0)
return FALSE;
pbSrc = pbSrc + advance;
if (code == LITE_SET_FG_FG_RUN || code == MEGA_MEGA_SET_FG_RUN)
{
if (!buffer_within_range(pbSrc, PIXEL_SIZE, pbEnd))
return FALSE;
SRCREADPIXEL(fgPel, pbSrc);
}
if (!ENSURE_CAPACITY(pbDest, pbDestEnd, runLength))
return FALSE;
if (fFirstLine)
{
UNROLL(runLength, { DESTWRITEPIXEL(pbDest, fgPel); });
}
else
{
UNROLL(runLength, {
DESTREADPIXEL(temp, pbDest - rowDelta);
DESTWRITEPIXEL(pbDest, temp ^ fgPel);
});
}
break;
/* Handle Dithered Run Orders. */
case LITE_DITHERED_RUN:
case MEGA_MEGA_DITHERED_RUN:
runLength = ExtractRunLength(code, pbSrc, pbEnd, &advance);
if (advance == 0)
return FALSE;
pbSrc = pbSrc + advance;
if (!buffer_within_range(pbSrc, PIXEL_SIZE, pbEnd))
return FALSE;
SRCREADPIXEL(pixelA, pbSrc);
if (!buffer_within_range(pbSrc, PIXEL_SIZE, pbEnd))
return FALSE;
SRCREADPIXEL(pixelB, pbSrc);
if (!ENSURE_CAPACITY(pbDest, pbDestEnd, runLength * 2))
return FALSE;
UNROLL(runLength, {
DESTWRITEPIXEL(pbDest, pixelA);
DESTWRITEPIXEL(pbDest, pixelB);
});
break;
/* Handle Color Run Orders. */
case REGULAR_COLOR_RUN:
case MEGA_MEGA_COLOR_RUN:
runLength = ExtractRunLength(code, pbSrc, pbEnd, &advance);
if (advance == 0)
return FALSE;
pbSrc = pbSrc + advance;
if (!buffer_within_range(pbSrc, PIXEL_SIZE, pbEnd))
return FALSE;
SRCREADPIXEL(pixelA, pbSrc);
if (!ENSURE_CAPACITY(pbDest, pbDestEnd, runLength))
return FALSE;
UNROLL(runLength, { DESTWRITEPIXEL(pbDest, pixelA); });
break;
/* Handle Foreground/Background Image Orders. */
case REGULAR_FGBG_IMAGE:
case MEGA_MEGA_FGBG_IMAGE:
case LITE_SET_FG_FGBG_IMAGE:
case MEGA_MEGA_SET_FGBG_IMAGE:
runLength = ExtractRunLength(code, pbSrc, pbEnd, &advance);
if (advance == 0)
return FALSE;
pbSrc = pbSrc + advance;
if (code == LITE_SET_FG_FGBG_IMAGE || code == MEGA_MEGA_SET_FGBG_IMAGE)
{
if (!buffer_within_range(pbSrc, PIXEL_SIZE, pbEnd))
return FALSE;
SRCREADPIXEL(fgPel, pbSrc);
}
if (!buffer_within_range(pbSrc, runLength / 8, pbEnd))
return FALSE;
if (fFirstLine)
{
while (runLength > 8)
{
bitmask = *pbSrc;
pbSrc = pbSrc + 1;
pbDest = WRITEFIRSTLINEFGBGIMAGE(pbDest, pbDestEnd, bitmask, fgPel, 8);
if (!pbDest)
return FALSE;
runLength = runLength - 8;
}
}
else
{
while (runLength > 8)
{
bitmask = *pbSrc++;
pbDest = WRITEFGBGIMAGE(pbDest, pbDestEnd, rowDelta, bitmask, fgPel, 8);
if (!pbDest)
return FALSE;
runLength = runLength - 8;
}
}
if (runLength > 0)
{
if (!buffer_within_range(pbSrc, 1, pbEnd))
return FALSE;
bitmask = *pbSrc++;
if (fFirstLine)
{
pbDest =
WRITEFIRSTLINEFGBGIMAGE(pbDest, pbDestEnd, bitmask, fgPel, runLength);
}
else
{
pbDest =
WRITEFGBGIMAGE(pbDest, pbDestEnd, rowDelta, bitmask, fgPel, runLength);
}
if (!pbDest)
return FALSE;
}
break;
/* Handle Color Image Orders. */
case REGULAR_COLOR_IMAGE:
case MEGA_MEGA_COLOR_IMAGE:
runLength = ExtractRunLength(code, pbSrc, pbEnd, &advance);
if (advance == 0)
return FALSE;
pbSrc = pbSrc + advance;
if (!ENSURE_CAPACITY(pbDest, pbDestEnd, runLength))
return FALSE;
if (!ENSURE_CAPACITY(pbSrc, pbEnd, runLength))
return FALSE;
UNROLL(runLength, {
SRCREADPIXEL(temp, pbSrc);
DESTWRITEPIXEL(pbDest, temp);
});
break;
/* Handle Special Order 1. */
case SPECIAL_FGBG_1:
if (!buffer_within_range(pbSrc, 1, pbEnd))
return FALSE;
pbSrc = pbSrc + 1;
if (fFirstLine)
{
pbDest =
WRITEFIRSTLINEFGBGIMAGE(pbDest, pbDestEnd, g_MaskSpecialFgBg1, fgPel, 8);
}
else
{
pbDest =
WRITEFGBGIMAGE(pbDest, pbDestEnd, rowDelta, g_MaskSpecialFgBg1, fgPel, 8);
}
if (!pbDest)
return FALSE;
break;
/* Handle Special Order 2. */
case SPECIAL_FGBG_2:
if (!buffer_within_range(pbSrc, 1, pbEnd))
return FALSE;
pbSrc = pbSrc + 1;
if (fFirstLine)
{
pbDest =
WRITEFIRSTLINEFGBGIMAGE(pbDest, pbDestEnd, g_MaskSpecialFgBg2, fgPel, 8);
}
else
{
pbDest =
WRITEFGBGIMAGE(pbDest, pbDestEnd, rowDelta, g_MaskSpecialFgBg2, fgPel, 8);
}
if (!pbDest)
return FALSE;
break;
/* Handle White Order. */
case SPECIAL_WHITE:
if (!buffer_within_range(pbSrc, 1, pbEnd))
return FALSE;
pbSrc = pbSrc + 1;
if (!ENSURE_CAPACITY(pbDest, pbDestEnd, 1))
return FALSE;
DESTWRITEPIXEL(pbDest, WHITE_PIXEL);
break;
/* Handle Black Order. */
case SPECIAL_BLACK:
if (!buffer_within_range(pbSrc, 1, pbEnd))
return FALSE;
pbSrc = pbSrc + 1;
if (!ENSURE_CAPACITY(pbDest, pbDestEnd, 1))
return FALSE;
DESTWRITEPIXEL(pbDest, BLACK_PIXEL);
break;
default:
WLog_ERR(TAG, "invalid code 0x%08" PRIx32 ", pbSrcBuffer=%p, pbSrc=%p, pbEnd=%p",
code, WINPR_CXX_COMPAT_CAST(const void*, pbSrcBuffer),
WINPR_CXX_COMPAT_CAST(const void*, pbSrc),
WINPR_CXX_COMPAT_CAST(const void*, pbEnd));
return FALSE;
}
}
return TRUE;
}
+755
View File
@@ -0,0 +1,755 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Interleaved RLE Bitmap Codec
*
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
* Copyright 2015 Thincast Technologies GmbH
* Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
* Copyright 2016 Armin Novak <armin.novak@thincast.com>
* Copyright 2016 Thincast Technologies GmbH
*
* 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 <winpr/assert.h>
#include <winpr/cast.h>
#include <freerdp/config.h>
#include <freerdp/codec/interleaved.h>
#include <freerdp/log.h>
#define TAG FREERDP_TAG("codec")
#define UNROLL_BODY(_exp, _count) \
do \
{ \
for (size_t x = 0; x < (_count); x++) \
{ \
do \
{ \
_exp \
} while (FALSE); \
} \
} while (FALSE)
#define UNROLL_MULTIPLE(_condition, _exp, _count) \
do \
{ \
while ((_condition) >= (_count)) \
{ \
UNROLL_BODY(_exp, _count); \
(_condition) -= (_count); \
} \
} while (FALSE)
#define UNROLL(_condition, _exp) \
do \
{ \
UNROLL_MULTIPLE(_condition, _exp, 16); \
UNROLL_MULTIPLE(_condition, _exp, 4); \
UNROLL_MULTIPLE(_condition, _exp, 1); \
} while (FALSE)
/*
RLE Compressed Bitmap Stream (RLE_BITMAP_STREAM)
http://msdn.microsoft.com/en-us/library/cc240895%28v=prot.10%29.aspx
pseudo-code
http://msdn.microsoft.com/en-us/library/dd240593%28v=prot.10%29.aspx
*/
#define REGULAR_BG_RUN 0x00
#define MEGA_MEGA_BG_RUN 0xF0
#define REGULAR_FG_RUN 0x01
#define MEGA_MEGA_FG_RUN 0xF1
#define LITE_SET_FG_FG_RUN 0x0C
#define MEGA_MEGA_SET_FG_RUN 0xF6
#define LITE_DITHERED_RUN 0x0E
#define MEGA_MEGA_DITHERED_RUN 0xF8
#define REGULAR_COLOR_RUN 0x03
#define MEGA_MEGA_COLOR_RUN 0xF3
#define REGULAR_FGBG_IMAGE 0x02
#define MEGA_MEGA_FGBG_IMAGE 0xF2
#define LITE_SET_FG_FGBG_IMAGE 0x0D
#define MEGA_MEGA_SET_FGBG_IMAGE 0xF7
#define REGULAR_COLOR_IMAGE 0x04
#define MEGA_MEGA_COLOR_IMAGE 0xF4
#define SPECIAL_FGBG_1 0xF9
#define SPECIAL_FGBG_2 0xFA
#define SPECIAL_WHITE 0xFD
#define SPECIAL_BLACK 0xFE
#define BLACK_PIXEL 0x000000
typedef UINT32 PIXEL;
static const BYTE g_MaskSpecialFgBg1 = 0x03;
static const BYTE g_MaskSpecialFgBg2 = 0x05;
static const BYTE g_MaskRegularRunLength = 0x1F;
static const BYTE g_MaskLiteRunLength = 0x0F;
#if defined(WITH_DEBUG_CODECS)
static const char* rle_code_str(UINT32 code)
{
switch (code)
{
case REGULAR_BG_RUN:
return "REGULAR_BG_RUN";
case MEGA_MEGA_BG_RUN:
return "MEGA_MEGA_BG_RUN";
case REGULAR_FG_RUN:
return "REGULAR_FG_RUN";
case MEGA_MEGA_FG_RUN:
return "MEGA_MEGA_FG_RUN";
case LITE_SET_FG_FG_RUN:
return "LITE_SET_FG_FG_RUN";
case MEGA_MEGA_SET_FG_RUN:
return "MEGA_MEGA_SET_FG_RUN";
case LITE_DITHERED_RUN:
return "LITE_DITHERED_RUN";
case MEGA_MEGA_DITHERED_RUN:
return "MEGA_MEGA_DITHERED_RUN";
case REGULAR_COLOR_RUN:
return "REGULAR_COLOR_RUN";
case MEGA_MEGA_COLOR_RUN:
return "MEGA_MEGA_COLOR_RUN";
case REGULAR_FGBG_IMAGE:
return "REGULAR_FGBG_IMAGE";
case MEGA_MEGA_FGBG_IMAGE:
return "MEGA_MEGA_FGBG_IMAGE";
case LITE_SET_FG_FGBG_IMAGE:
return "LITE_SET_FG_FGBG_IMAGE";
case MEGA_MEGA_SET_FGBG_IMAGE:
return "MEGA_MEGA_SET_FGBG_IMAGE";
case REGULAR_COLOR_IMAGE:
return "REGULAR_COLOR_IMAGE";
case MEGA_MEGA_COLOR_IMAGE:
return "MEGA_MEGA_COLOR_IMAGE";
case SPECIAL_FGBG_1:
return "SPECIAL_FGBG_1";
case SPECIAL_FGBG_2:
return "SPECIAL_FGBG_2";
case SPECIAL_WHITE:
return "SPECIAL_WHITE";
case SPECIAL_BLACK:
return "SPECIAL_BLACK";
default:
return "UNKNOWN";
}
}
#endif
#define buffer_within_range(pbSrc, size, pbEnd) \
buffer_within_range_((pbSrc), (size), (pbEnd), __func__, __FILE__, __LINE__)
static inline BOOL buffer_within_range_(const void* pbSrc, size_t size, const void* pbEnd,
const char* fkt, const char* file, size_t line)
{
WINPR_UNUSED(file);
WINPR_ASSERT(pbSrc);
WINPR_ASSERT(pbEnd);
if ((const char*)pbSrc + size > (const char*)pbEnd)
{
WLog_ERR(TAG, "[%s:%" PRIuz "] pbSrc=%p + %" PRIuz " > pbEnd=%p", fkt, line, pbSrc, size,
pbEnd);
return FALSE;
}
return TRUE;
}
/**
* Reads the supplied order header and extracts the compression
* order code ID.
*/
static inline UINT32 ExtractCodeId(BYTE bOrderHdr)
{
if ((bOrderHdr & 0xC0U) != 0xC0U)
{
/* REGULAR orders
* (000x xxxx, 001x xxxx, 010x xxxx, 011x xxxx, 100x xxxx)
*/
return bOrderHdr >> 5;
}
else if ((bOrderHdr & 0xF0U) == 0xF0U)
{
/* MEGA and SPECIAL orders (0xF*) */
return bOrderHdr;
}
else
{
/* LITE orders
* 1100 xxxx, 1101 xxxx, 1110 xxxx)
*/
return bOrderHdr >> 4;
}
}
/**
* Extract the run length of a compression order.
*/
static UINT ExtractRunLengthRegularFgBg(const BYTE* pbOrderHdr, const BYTE* pbEnd, UINT32* advance)
{
UINT runLength = 0;
WINPR_ASSERT(pbOrderHdr);
WINPR_ASSERT(pbEnd);
WINPR_ASSERT(advance);
runLength = (*pbOrderHdr) & g_MaskRegularRunLength;
if (runLength == 0)
{
if (!buffer_within_range(pbOrderHdr, 2, pbEnd))
{
*advance = 0;
return 0;
}
runLength = *(pbOrderHdr + 1) + 1;
(*advance)++;
}
else
runLength = runLength * 8;
return runLength;
}
static UINT ExtractRunLengthLiteFgBg(const BYTE* pbOrderHdr, const BYTE* pbEnd, UINT32* advance)
{
UINT runLength = 0;
WINPR_ASSERT(pbOrderHdr);
WINPR_ASSERT(pbEnd);
WINPR_ASSERT(advance);
runLength = *pbOrderHdr & g_MaskLiteRunLength;
if (runLength == 0)
{
if (!buffer_within_range(pbOrderHdr, 2, pbEnd))
{
*advance = 0;
return 0;
}
runLength = *(pbOrderHdr + 1) + 1;
(*advance)++;
}
else
runLength = runLength * 8;
return runLength;
}
static UINT ExtractRunLengthRegular(const BYTE* pbOrderHdr, const BYTE* pbEnd, UINT32* advance)
{
UINT runLength = 0;
WINPR_ASSERT(pbOrderHdr);
WINPR_ASSERT(pbEnd);
WINPR_ASSERT(advance);
runLength = *pbOrderHdr & g_MaskRegularRunLength;
if (runLength == 0)
{
if (!buffer_within_range(pbOrderHdr, 2, pbEnd))
{
*advance = 0;
return 0;
}
runLength = *(pbOrderHdr + 1) + 32;
(*advance)++;
}
return runLength;
}
static UINT ExtractRunLengthMegaMega(const BYTE* pbOrderHdr, const BYTE* pbEnd, UINT32* advance)
{
UINT runLength = 0;
WINPR_ASSERT(pbOrderHdr);
WINPR_ASSERT(pbEnd);
WINPR_ASSERT(advance);
if (!buffer_within_range(pbOrderHdr, 3, pbEnd))
{
*advance = 0;
return 0;
}
runLength = ((UINT16)pbOrderHdr[1]) | ((((UINT16)pbOrderHdr[2]) << 8) & 0xFF00);
(*advance) += 2;
return runLength;
}
static UINT ExtractRunLengthLite(const BYTE* pbOrderHdr, const BYTE* pbEnd, UINT32* advance)
{
UINT runLength = 0;
WINPR_ASSERT(pbOrderHdr);
WINPR_ASSERT(pbEnd);
WINPR_ASSERT(advance);
runLength = *pbOrderHdr & g_MaskLiteRunLength;
if (runLength == 0)
{
if (!buffer_within_range(pbOrderHdr, 2, pbEnd))
{
*advance = 0;
return 0;
}
runLength = *(pbOrderHdr + 1) + 16;
(*advance)++;
}
return runLength;
}
static inline UINT32 ExtractRunLength(UINT32 code, const BYTE* pbOrderHdr, const BYTE* pbEnd,
UINT32* advance)
{
UINT32 runLength = 0;
UINT32 ladvance = 1;
WINPR_ASSERT(pbOrderHdr);
WINPR_ASSERT(pbEnd);
WINPR_ASSERT(advance);
#if defined(WITH_DEBUG_CODECS)
WLog_VRB(TAG, "extracting %s", rle_code_str(code));
#endif
*advance = 0;
if (!buffer_within_range(pbOrderHdr, 0, pbEnd))
return 0;
switch (code)
{
case REGULAR_FGBG_IMAGE:
runLength = ExtractRunLengthRegularFgBg(pbOrderHdr, pbEnd, &ladvance);
break;
case LITE_SET_FG_FGBG_IMAGE:
runLength = ExtractRunLengthLiteFgBg(pbOrderHdr, pbEnd, &ladvance);
break;
case REGULAR_BG_RUN:
case REGULAR_FG_RUN:
case REGULAR_COLOR_RUN:
case REGULAR_COLOR_IMAGE:
runLength = ExtractRunLengthRegular(pbOrderHdr, pbEnd, &ladvance);
break;
case LITE_SET_FG_FG_RUN:
case LITE_DITHERED_RUN:
runLength = ExtractRunLengthLite(pbOrderHdr, pbEnd, &ladvance);
break;
case MEGA_MEGA_BG_RUN:
case MEGA_MEGA_FG_RUN:
case MEGA_MEGA_SET_FG_RUN:
case MEGA_MEGA_DITHERED_RUN:
case MEGA_MEGA_COLOR_RUN:
case MEGA_MEGA_FGBG_IMAGE:
case MEGA_MEGA_SET_FGBG_IMAGE:
case MEGA_MEGA_COLOR_IMAGE:
runLength = ExtractRunLengthMegaMega(pbOrderHdr, pbEnd, &ladvance);
break;
default:
runLength = 0;
ladvance = 0;
break;
}
*advance = ladvance;
return runLength;
}
#define ensure_capacity(start, end, size, base) \
ensure_capacity_((start), (end), (size), (base), __func__, __FILE__, __LINE__)
static inline BOOL ensure_capacity_(const BYTE* start, const BYTE* end, size_t size, size_t base,
const char* fkt, WINPR_ATTR_UNUSED const char* file,
size_t line)
{
const size_t available = (uintptr_t)end - (uintptr_t)start;
const BOOL rc = available >= size * base;
const BOOL res = rc && (start <= end);
if (!res)
WLog_ERR(TAG,
"[%s:%" PRIuz "] failed: start=%p <= end=%p, available=%" PRIuz " >= size=%" PRIuz
" * base=%" PRIuz,
fkt, line, WINPR_CXX_COMPAT_CAST(const void*, start),
WINPR_CXX_COMPAT_CAST(const void*, end), available, size, base);
return res;
}
static inline void write_pixel_8(BYTE* _buf, BYTE _pix)
{
WINPR_ASSERT(_buf);
*_buf = _pix;
}
static inline void write_pixel_24(BYTE* _buf, UINT32 _pix)
{
WINPR_ASSERT(_buf);
(_buf)[0] = (BYTE)(_pix);
(_buf)[1] = (BYTE)((_pix) >> 8);
(_buf)[2] = (BYTE)((_pix) >> 16);
}
static inline void write_pixel_16(BYTE* _buf, UINT16 _pix)
{
WINPR_ASSERT(_buf);
_buf[0] = _pix & 0xFF;
_buf[1] = (_pix >> 8) & 0xFF;
}
#undef DESTWRITEPIXEL
#undef DESTREADPIXEL
#undef SRCREADPIXEL
#undef WRITEFGBGIMAGE
#undef WRITEFIRSTLINEFGBGIMAGE
#undef RLEDECOMPRESS
#undef RLEEXTRA
#undef WHITE_PIXEL
#undef PIXEL_SIZE
#undef PIXEL
#define PIXEL_SIZE 1
#define PIXEL BYTE
#define WHITE_PIXEL 0xFF
#define DESTWRITEPIXEL(_buf, _pix) \
do \
{ \
write_pixel_8(_buf, _pix); \
(_buf) += 1; \
} while (0)
#define DESTREADPIXEL(_pix, _buf) _pix = (_buf)[0]
#define SRCREADPIXEL(_pix, _buf) \
do \
{ \
(_pix) = (_buf)[0]; \
(_buf) += 1; \
} while (0)
#define WRITEFGBGIMAGE WriteFgBgImage8to8
#define WRITEFIRSTLINEFGBGIMAGE WriteFirstLineFgBgImage8to8
#define RLEDECOMPRESS RleDecompress8to8
#define RLEEXTRA
#undef ENSURE_CAPACITY
#define ENSURE_CAPACITY(_start, _end, _size) ensure_capacity(_start, _end, _size, 1)
#include "include/bitmap.h"
#undef DESTWRITEPIXEL
#undef DESTREADPIXEL
#undef SRCREADPIXEL
#undef WRITEFGBGIMAGE
#undef WRITEFIRSTLINEFGBGIMAGE
#undef RLEDECOMPRESS
#undef RLEEXTRA
#undef WHITE_PIXEL
#undef PIXEL_SIZE
#undef PIXEL
#define PIXEL_SIZE 2
#define PIXEL UINT16
#define WHITE_PIXEL 0xFFFF
#define DESTWRITEPIXEL(_buf, _pix) \
do \
{ \
write_pixel_16(_buf, _pix); \
(_buf) += 2; \
} while (0)
#define DESTREADPIXEL(_pix, _buf) _pix = ((UINT16*)(_buf))[0]
#define SRCREADPIXEL(_pix, _buf) \
do \
{ \
(_pix) = WINPR_ASSERTING_INT_CAST(UINT16, (_buf)[0] | (((_buf)[1] << 8) & 0xFF00)); \
(_buf) += 2; \
} while (0)
#define WRITEFGBGIMAGE WriteFgBgImage16to16
#define WRITEFIRSTLINEFGBGIMAGE WriteFirstLineFgBgImage16to16
#define RLEDECOMPRESS RleDecompress16to16
#define RLEEXTRA
#undef ENSURE_CAPACITY
#define ENSURE_CAPACITY(_start, _end, _size) ensure_capacity(_start, _end, _size, 2)
#include "include/bitmap.h"
#undef DESTWRITEPIXEL
#undef DESTREADPIXEL
#undef SRCREADPIXEL
#undef WRITEFGBGIMAGE
#undef WRITEFIRSTLINEFGBGIMAGE
#undef RLEDECOMPRESS
#undef RLEEXTRA
#undef WHITE_PIXEL
#undef PIXEL_SIZE
#undef PIXEL
#define PIXEL_SIZE 3
#define PIXEL UINT32
#define WHITE_PIXEL 0xffffff
#define DESTWRITEPIXEL(_buf, _pix) \
do \
{ \
write_pixel_24(_buf, _pix); \
(_buf) += 3; \
} while (0)
#define DESTREADPIXEL(_pix, _buf) \
_pix = (_buf)[0] | (((_buf)[1] << 8) & 0xFF00) | (((_buf)[2] << 16) & 0xFF0000)
#define SRCREADPIXEL(_pix, _buf) \
do \
{ \
(_pix) = (_buf)[0] | (((_buf)[1] << 8) & 0xFF00) | (((_buf)[2] << 16) & 0xFF0000); \
(_buf) += 3; \
} while (0)
#define WRITEFGBGIMAGE WriteFgBgImage24to24
#define WRITEFIRSTLINEFGBGIMAGE WriteFirstLineFgBgImage24to24
#define RLEDECOMPRESS RleDecompress24to24
#define RLEEXTRA
#undef ENSURE_CAPACITY
#define ENSURE_CAPACITY(_start, _end, _size) ensure_capacity(_start, _end, _size, 3)
#include "include/bitmap.h"
struct S_BITMAP_INTERLEAVED_CONTEXT
{
BOOL Compressor;
UINT32 TempSize;
BYTE* TempBuffer;
wStream* bts;
};
BOOL interleaved_decompress(BITMAP_INTERLEAVED_CONTEXT* WINPR_RESTRICT interleaved,
const BYTE* WINPR_RESTRICT pSrcData, UINT32 SrcSize, UINT32 nSrcWidth,
UINT32 nSrcHeight, UINT32 bpp, BYTE* WINPR_RESTRICT pDstData,
UINT32 DstFormat, UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst,
UINT32 nDstWidth, UINT32 nDstHeight,
const gdiPalette* WINPR_RESTRICT palette)
{
UINT32 scanline = 0;
UINT32 SrcFormat = 0;
UINT32 BufferSize = 0;
if (!interleaved || !pSrcData || !pDstData)
{
WLog_ERR(TAG, "invalid arguments: interleaved=%p, pSrcData=%p, pDstData=%p",
WINPR_CXX_COMPAT_CAST(const void*, interleaved),
WINPR_CXX_COMPAT_CAST(const void*, pSrcData),
WINPR_CXX_COMPAT_CAST(const void*, pDstData));
return FALSE;
}
switch (bpp)
{
case 24:
scanline = nSrcWidth * 3;
SrcFormat = PIXEL_FORMAT_BGR24;
break;
case 16:
scanline = nSrcWidth * 2;
SrcFormat = PIXEL_FORMAT_RGB16;
break;
case 15:
scanline = nSrcWidth * 2;
SrcFormat = PIXEL_FORMAT_RGB15;
break;
case 8:
scanline = nSrcWidth;
SrcFormat = PIXEL_FORMAT_RGB8;
break;
default:
WLog_ERR(TAG, "Invalid color depth %" PRIu32 "", bpp);
return FALSE;
}
BufferSize = scanline * nSrcHeight;
if (BufferSize > interleaved->TempSize)
{
interleaved->TempBuffer =
winpr_aligned_recalloc(interleaved->TempBuffer, BufferSize, sizeof(BYTE), 16);
interleaved->TempSize = BufferSize;
}
if (!interleaved->TempBuffer)
{
WLog_ERR(TAG, "interleaved->TempBuffer=nullptr");
return FALSE;
}
switch (bpp)
{
case 24:
if (!RleDecompress24to24(pSrcData, SrcSize, interleaved->TempBuffer, scanline,
nSrcWidth, nSrcHeight))
{
WLog_ERR(TAG, "RleDecompress24to24 failed");
return FALSE;
}
break;
case 16:
case 15:
if (!RleDecompress16to16(pSrcData, SrcSize, interleaved->TempBuffer, scanline,
nSrcWidth, nSrcHeight))
{
WLog_ERR(TAG, "RleDecompress16to16 failed");
return FALSE;
}
break;
case 8:
if (!RleDecompress8to8(pSrcData, SrcSize, interleaved->TempBuffer, scanline, nSrcWidth,
nSrcHeight))
{
WLog_ERR(TAG, "RleDecompress8to8 failed");
return FALSE;
}
break;
default:
WLog_ERR(TAG, "Invalid color depth %" PRIu32 "", bpp);
return FALSE;
}
if (!freerdp_image_copy_no_overlap(pDstData, DstFormat, nDstStep, nXDst, nYDst, nDstWidth,
nDstHeight, interleaved->TempBuffer, SrcFormat, scanline, 0,
0, palette, FREERDP_FLIP_VERTICAL | FREERDP_KEEP_DST_ALPHA))
{
WLog_ERR(TAG, "freerdp_image_copy failed");
return FALSE;
}
return TRUE;
}
BOOL interleaved_compress(BITMAP_INTERLEAVED_CONTEXT* WINPR_RESTRICT interleaved,
BYTE* WINPR_RESTRICT pDstData, UINT32* WINPR_RESTRICT pDstSize,
UINT32 nWidth, UINT32 nHeight, const BYTE* WINPR_RESTRICT pSrcData,
UINT32 SrcFormat, UINT32 nSrcStep, UINT32 nXSrc, UINT32 nYSrc,
const gdiPalette* WINPR_RESTRICT palette, UINT32 bpp)
{
BOOL status = 0;
wStream* s = nullptr;
UINT32 DstFormat = 0;
const UINT32 maxSize = 64 * 64 * 4;
if (!interleaved || !pDstData || !pSrcData)
return FALSE;
if ((nWidth == 0) || (nHeight == 0))
return FALSE;
if (nWidth % 4)
{
WLog_ERR(TAG, "interleaved_compress: width is not a multiple of 4");
return FALSE;
}
if ((nWidth > 64) || (nHeight > 64))
{
WLog_ERR(TAG,
"interleaved_compress: width (%" PRIu32 ") or height (%" PRIu32
") is greater than 64",
nWidth, nHeight);
return FALSE;
}
switch (bpp)
{
case 24:
DstFormat = PIXEL_FORMAT_BGRX32;
break;
case 16:
DstFormat = PIXEL_FORMAT_RGB16;
break;
case 15:
DstFormat = PIXEL_FORMAT_RGB15;
break;
default:
return FALSE;
}
if (!freerdp_image_copy_no_overlap(interleaved->TempBuffer, DstFormat, 0, 0, 0, nWidth, nHeight,
pSrcData, SrcFormat, nSrcStep, nXSrc, nYSrc, palette,
FREERDP_KEEP_DST_ALPHA))
return FALSE;
s = Stream_New(pDstData, *pDstSize);
if (!s)
return FALSE;
Stream_ResetPosition(interleaved->bts);
status = (freerdp_bitmap_compress(interleaved->TempBuffer, nWidth, nHeight, s, bpp, maxSize,
nHeight - 1, interleaved->bts, 0) >= 0);
Stream_SealLength(s);
*pDstSize = (UINT32)Stream_Length(s);
Stream_Free(s, FALSE);
return status;
}
BOOL bitmap_interleaved_context_reset(BITMAP_INTERLEAVED_CONTEXT* WINPR_RESTRICT interleaved)
{
return (interleaved != nullptr);
}
BITMAP_INTERLEAVED_CONTEXT* bitmap_interleaved_context_new(WINPR_ATTR_UNUSED BOOL Compressor)
{
BITMAP_INTERLEAVED_CONTEXT* interleaved = nullptr;
interleaved = (BITMAP_INTERLEAVED_CONTEXT*)winpr_aligned_recalloc(
nullptr, 1, sizeof(BITMAP_INTERLEAVED_CONTEXT), 32);
if (interleaved)
{
interleaved->TempSize = 64 * 64 * 4;
interleaved->TempBuffer = winpr_aligned_calloc(interleaved->TempSize, sizeof(BYTE), 16);
if (!interleaved->TempBuffer)
goto fail;
interleaved->bts = Stream_New(nullptr, interleaved->TempSize);
if (!interleaved->bts)
goto fail;
}
return interleaved;
fail:
WINPR_PRAGMA_DIAG_PUSH
WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
bitmap_interleaved_context_free(interleaved);
WINPR_PRAGMA_DIAG_POP
return nullptr;
}
void bitmap_interleaved_context_free(BITMAP_INTERLEAVED_CONTEXT* WINPR_RESTRICT interleaved)
{
if (!interleaved)
return;
winpr_aligned_free(interleaved->TempBuffer);
Stream_Free(interleaved->bts, TRUE);
winpr_aligned_free(interleaved);
}
+67
View File
@@ -0,0 +1,67 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Compressed jpeg
*
* Copyright 2012 Jay Sorg <jay.sorg@gmail.com>
*
* 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 <freerdp/config.h>
#include <winpr/stream.h>
#include <winpr/image.h>
#include <freerdp/codec/color.h>
#include <freerdp/codec/jpeg.h>
#ifdef WITH_JPEG
/* jpeg decompress */
BOOL jpeg_decompress(const BYTE* input, BYTE* output, int width, int height, int size, int bpp)
{
BOOL rc = FALSE;
if (bpp != 24)
return FALSE;
wImage* image = winpr_image_new();
if (!image)
goto fail;
if (winpr_image_read_buffer(image, input, size) <= 0)
goto fail;
if ((image->width != width) || (image->height != height) || (image->bitsPerPixel != bpp))
goto fail;
memcpy(output, image->data, 1ull * image->scanline * image->height);
rc = TRUE;
fail:
winpr_image_free(image, TRUE);
return rc;
}
#else
BOOL jpeg_decompress(WINPR_ATTR_UNUSED const BYTE* input, WINPR_ATTR_UNUSED BYTE* output,
WINPR_ATTR_UNUSED int width, WINPR_ATTR_UNUSED int height,
WINPR_ATTR_UNUSED int size, WINPR_ATTR_UNUSED int bpp)
{
WLog_ERR("TODO", "TODO: implement");
return 0;
}
#endif
+860
View File
@@ -0,0 +1,860 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* MPPC Bulk Data Compression
*
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* 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 <winpr/assert.h>
#include <freerdp/config.h>
#include <winpr/crt.h>
#include <winpr/print.h>
#include <winpr/stream.h>
#include <winpr/bitstream.h>
#include <freerdp/log.h>
#include "mppc.h"
#define TAG FREERDP_TAG("codec.mppc")
//#define DEBUG_MPPC 1
#define MPPC_MATCH_INDEX(_sym1, _sym2, _sym3) \
((((MPPC_MATCH_TABLE[_sym3] << 16) + (MPPC_MATCH_TABLE[_sym2] << 8) + \
MPPC_MATCH_TABLE[_sym1]) & \
0x07FFF000) >> \
12)
struct s_MPPC_CONTEXT
{
ALIGN64 wBitStream* bs;
ALIGN64 BOOL Compressor;
ALIGN64 BYTE* HistoryPtr;
ALIGN64 UINT32 HistoryOffset;
ALIGN64 UINT32 HistoryBufferSize;
ALIGN64 BYTE HistoryBuffer[65536];
ALIGN64 UINT16 MatchBuffer[32768];
ALIGN64 UINT32 CompressionLevel;
};
static const UINT32 MPPC_MATCH_TABLE[256] = {
0x00000000, 0x009CCF93, 0x01399F26, 0x01D66EB9, 0x02733E4C, 0x03100DDF, 0x03ACDD72, 0x0449AD05,
0x04E67C98, 0x05834C2B, 0x06201BBE, 0x06BCEB51, 0x0759BAE4, 0x07F68A77, 0x08935A0A, 0x0930299D,
0x09CCF930, 0x0A69C8C3, 0x0B069856, 0x0BA367E9, 0x0C40377C, 0x0CDD070F, 0x0D79D6A2, 0x0E16A635,
0x0EB375C8, 0x0F50455B, 0x0FED14EE, 0x1089E481, 0x1126B414, 0x11C383A7, 0x1260533A, 0x12FD22CD,
0x1399F260, 0x1436C1F3, 0x14D39186, 0x15706119, 0x160D30AC, 0x16AA003F, 0x1746CFD2, 0x17E39F65,
0x18806EF8, 0x191D3E8B, 0x19BA0E1E, 0x1A56DDB1, 0x1AF3AD44, 0x1B907CD7, 0x1C2D4C6A, 0x1CCA1BFD,
0x1D66EB90, 0x1E03BB23, 0x1EA08AB6, 0x1F3D5A49, 0x1FDA29DC, 0x2076F96F, 0x2113C902, 0x21B09895,
0x224D6828, 0x22EA37BB, 0x2387074E, 0x2423D6E1, 0x24C0A674, 0x255D7607, 0x25FA459A, 0x2697152D,
0x2733E4C0, 0x27D0B453, 0x286D83E6, 0x290A5379, 0x29A7230C, 0x2A43F29F, 0x2AE0C232, 0x2B7D91C5,
0x2C1A6158, 0x2CB730EB, 0x2D54007E, 0x2DF0D011, 0x2E8D9FA4, 0x2F2A6F37, 0x2FC73ECA, 0x30640E5D,
0x3100DDF0, 0x319DAD83, 0x323A7D16, 0x32D74CA9, 0x33741C3C, 0x3410EBCF, 0x34ADBB62, 0x354A8AF5,
0x35E75A88, 0x36842A1B, 0x3720F9AE, 0x37BDC941, 0x385A98D4, 0x38F76867, 0x399437FA, 0x3A31078D,
0x3ACDD720, 0x3B6AA6B3, 0x3C077646, 0x3CA445D9, 0x3D41156C, 0x3DDDE4FF, 0x3E7AB492, 0x3F178425,
0x3FB453B8, 0x4051234B, 0x40EDF2DE, 0x418AC271, 0x42279204, 0x42C46197, 0x4361312A, 0x43FE00BD,
0x449AD050, 0x45379FE3, 0x45D46F76, 0x46713F09, 0x470E0E9C, 0x47AADE2F, 0x4847ADC2, 0x48E47D55,
0x49814CE8, 0x4A1E1C7B, 0x4ABAEC0E, 0x4B57BBA1, 0x4BF48B34, 0x4C915AC7, 0x4D2E2A5A, 0x4DCAF9ED,
0x4E67C980, 0x4F049913, 0x4FA168A6, 0x503E3839, 0x50DB07CC, 0x5177D75F, 0x5214A6F2, 0x52B17685,
0x534E4618, 0x53EB15AB, 0x5487E53E, 0x5524B4D1, 0x55C18464, 0x565E53F7, 0x56FB238A, 0x5797F31D,
0x5834C2B0, 0x58D19243, 0x596E61D6, 0x5A0B3169, 0x5AA800FC, 0x5B44D08F, 0x5BE1A022, 0x5C7E6FB5,
0x5D1B3F48, 0x5DB80EDB, 0x5E54DE6E, 0x5EF1AE01, 0x5F8E7D94, 0x602B4D27, 0x60C81CBA, 0x6164EC4D,
0x6201BBE0, 0x629E8B73, 0x633B5B06, 0x63D82A99, 0x6474FA2C, 0x6511C9BF, 0x65AE9952, 0x664B68E5,
0x66E83878, 0x6785080B, 0x6821D79E, 0x68BEA731, 0x695B76C4, 0x69F84657, 0x6A9515EA, 0x6B31E57D,
0x6BCEB510, 0x6C6B84A3, 0x6D085436, 0x6DA523C9, 0x6E41F35C, 0x6EDEC2EF, 0x6F7B9282, 0x70186215,
0x70B531A8, 0x7152013B, 0x71EED0CE, 0x728BA061, 0x73286FF4, 0x73C53F87, 0x74620F1A, 0x74FEDEAD,
0x759BAE40, 0x76387DD3, 0x76D54D66, 0x77721CF9, 0x780EEC8C, 0x78ABBC1F, 0x79488BB2, 0x79E55B45,
0x7A822AD8, 0x7B1EFA6B, 0x7BBBC9FE, 0x7C589991, 0x7CF56924, 0x7D9238B7, 0x7E2F084A, 0x7ECBD7DD,
0x7F68A770, 0x80057703, 0x80A24696, 0x813F1629, 0x81DBE5BC, 0x8278B54F, 0x831584E2, 0x83B25475,
0x844F2408, 0x84EBF39B, 0x8588C32E, 0x862592C1, 0x86C26254, 0x875F31E7, 0x87FC017A, 0x8898D10D,
0x8935A0A0, 0x89D27033, 0x8A6F3FC6, 0x8B0C0F59, 0x8BA8DEEC, 0x8C45AE7F, 0x8CE27E12, 0x8D7F4DA5,
0x8E1C1D38, 0x8EB8ECCB, 0x8F55BC5E, 0x8FF28BF1, 0x908F5B84, 0x912C2B17, 0x91C8FAAA, 0x9265CA3D,
0x930299D0, 0x939F6963, 0x943C38F6, 0x94D90889, 0x9575D81C, 0x9612A7AF, 0x96AF7742, 0x974C46D5,
0x97E91668, 0x9885E5FB, 0x9922B58E, 0x99BF8521, 0x9A5C54B4, 0x9AF92447, 0x9B95F3DA, 0x9C32C36D
};
int mppc_decompress(MPPC_CONTEXT* mppc, const BYTE* pSrcData, UINT32 SrcSize,
const BYTE** ppDstData, UINT32* pDstSize, UINT32 flags)
{
BYTE Literal = 0;
BYTE* SrcPtr = nullptr;
UINT32 CopyOffset = 0;
UINT32 LengthOfMatch = 0;
UINT32 accumulator = 0;
BYTE* HistoryPtr = nullptr;
BYTE* HistoryBuffer = nullptr;
BYTE* HistoryBufferEnd = nullptr;
UINT32 HistoryBufferSize = 0;
UINT32 CompressionLevel = 0;
wBitStream* bs = nullptr;
WINPR_ASSERT(mppc);
WINPR_ASSERT(pSrcData);
WINPR_ASSERT(ppDstData);
WINPR_ASSERT(pDstSize);
bs = mppc->bs;
WINPR_ASSERT(bs);
HistoryBuffer = mppc->HistoryBuffer;
WINPR_ASSERT(HistoryBuffer);
HistoryBufferSize = mppc->HistoryBufferSize;
HistoryBufferEnd = &HistoryBuffer[HistoryBufferSize - 1];
CompressionLevel = mppc->CompressionLevel;
BitStream_Attach(bs, pSrcData, SrcSize);
BitStream_Fetch(bs);
if (flags & PACKET_AT_FRONT)
{
mppc->HistoryOffset = 0;
mppc->HistoryPtr = HistoryBuffer;
}
if (flags & PACKET_FLUSHED)
{
mppc->HistoryOffset = 0;
mppc->HistoryPtr = HistoryBuffer;
ZeroMemory(HistoryBuffer, mppc->HistoryBufferSize);
}
HistoryPtr = mppc->HistoryPtr;
if (!(flags & PACKET_COMPRESSED))
{
*pDstSize = SrcSize;
*ppDstData = pSrcData;
return 1;
}
while ((bs->length - bs->position) >= 8)
{
accumulator = bs->accumulator;
/**
* Literal Encoding
*/
if (HistoryPtr > HistoryBufferEnd)
{
WLog_ERR(TAG, "history buffer index out of range");
return -1004;
}
if ((accumulator & 0x80000000) == 0x00000000)
{
/**
* Literal, less than 0x80
* bit 0 followed by the lower 7 bits of the literal
*/
Literal = ((accumulator & 0x7F000000) >> 24);
*(HistoryPtr) = Literal;
HistoryPtr++;
BitStream_Shift(bs, 8);
continue;
}
else if ((accumulator & 0xC0000000) == 0x80000000)
{
/**
* Literal, greater than 0x7F
* bits 10 followed by the lower 7 bits of the literal
*/
Literal = ((accumulator & 0x3F800000) >> 23) + 0x80;
*(HistoryPtr) = Literal;
HistoryPtr++;
BitStream_Shift(bs, 9);
continue;
}
/**
* CopyOffset Encoding
*/
if (CompressionLevel) /* RDP5 */
{
if ((accumulator & 0xF8000000) == 0xF8000000)
{
/**
* CopyOffset, range [0, 63]
* bits 11111 + lower 6 bits of CopyOffset
*/
CopyOffset = ((accumulator >> 21) & 0x3F);
BitStream_Shift(bs, 11);
}
else if ((accumulator & 0xF8000000) == 0xF0000000)
{
/**
* CopyOffset, range [64, 319]
* bits 11110 + lower 8 bits of (CopyOffset - 64)
*/
CopyOffset = ((accumulator >> 19) & 0xFF) + 64;
BitStream_Shift(bs, 13);
}
else if ((accumulator & 0xF0000000) == 0xE0000000)
{
/**
* CopyOffset, range [320, 2367]
* bits 1110 + lower 11 bits of (CopyOffset - 320)
*/
CopyOffset = ((accumulator >> 17) & 0x7FF) + 320;
BitStream_Shift(bs, 15);
}
else if ((accumulator & 0xE0000000) == 0xC0000000)
{
/**
* CopyOffset, range [2368, ]
* bits 110 + lower 16 bits of (CopyOffset - 2368)
*/
CopyOffset = ((accumulator >> 13) & 0xFFFF) + 2368;
BitStream_Shift(bs, 19);
}
else
{
/* Invalid CopyOffset Encoding */
return -1001;
}
}
else /* RDP4 */
{
if ((accumulator & 0xF0000000) == 0xF0000000)
{
/**
* CopyOffset, range [0, 63]
* bits 1111 + lower 6 bits of CopyOffset
*/
CopyOffset = ((accumulator >> 22) & 0x3F);
BitStream_Shift(bs, 10);
}
else if ((accumulator & 0xF0000000) == 0xE0000000)
{
/**
* CopyOffset, range [64, 319]
* bits 1110 + lower 8 bits of (CopyOffset - 64)
*/
CopyOffset = ((accumulator >> 20) & 0xFF) + 64;
BitStream_Shift(bs, 12);
}
else if ((accumulator & 0xE0000000) == 0xC0000000)
{
/**
* CopyOffset, range [320, 8191]
* bits 110 + lower 13 bits of (CopyOffset - 320)
*/
CopyOffset = ((accumulator >> 16) & 0x1FFF) + 320;
BitStream_Shift(bs, 16);
}
else
{
/* Invalid CopyOffset Encoding */
return -1002;
}
}
/**
* LengthOfMatch Encoding
*/
accumulator = bs->accumulator;
if ((accumulator & 0x80000000) == 0x00000000)
{
/**
* LengthOfMatch [3]
* bit 0 + 0 lower bits of LengthOfMatch
*/
LengthOfMatch = 3;
BitStream_Shift(bs, 1);
}
else if ((accumulator & 0xC0000000) == 0x80000000)
{
/**
* LengthOfMatch [4, 7]
* bits 10 + 2 lower bits of LengthOfMatch
*/
LengthOfMatch = ((accumulator >> 28) & 0x0003) + 0x0004;
BitStream_Shift(bs, 4);
}
else if ((accumulator & 0xE0000000) == 0xC0000000)
{
/**
* LengthOfMatch [8, 15]
* bits 110 + 3 lower bits of LengthOfMatch
*/
LengthOfMatch = ((accumulator >> 26) & 0x0007) + 0x0008;
BitStream_Shift(bs, 6);
}
else if ((accumulator & 0xF0000000) == 0xE0000000)
{
/**
* LengthOfMatch [16, 31]
* bits 1110 + 4 lower bits of LengthOfMatch
*/
LengthOfMatch = ((accumulator >> 24) & 0x000F) + 0x0010;
BitStream_Shift(bs, 8);
}
else if ((accumulator & 0xF8000000) == 0xF0000000)
{
/**
* LengthOfMatch [32, 63]
* bits 11110 + 5 lower bits of LengthOfMatch
*/
LengthOfMatch = ((accumulator >> 22) & 0x001F) + 0x0020;
BitStream_Shift(bs, 10);
}
else if ((accumulator & 0xFC000000) == 0xF8000000)
{
/**
* LengthOfMatch [64, 127]
* bits 111110 + 6 lower bits of LengthOfMatch
*/
LengthOfMatch = ((accumulator >> 20) & 0x003F) + 0x0040;
BitStream_Shift(bs, 12);
}
else if ((accumulator & 0xFE000000) == 0xFC000000)
{
/**
* LengthOfMatch [128, 255]
* bits 1111110 + 7 lower bits of LengthOfMatch
*/
LengthOfMatch = ((accumulator >> 18) & 0x007F) + 0x0080;
BitStream_Shift(bs, 14);
}
else if ((accumulator & 0xFF000000) == 0xFE000000)
{
/**
* LengthOfMatch [256, 511]
* bits 11111110 + 8 lower bits of LengthOfMatch
*/
LengthOfMatch = ((accumulator >> 16) & 0x00FF) + 0x0100;
BitStream_Shift(bs, 16);
}
else if ((accumulator & 0xFF800000) == 0xFF000000)
{
/**
* LengthOfMatch [512, 1023]
* bits 111111110 + 9 lower bits of LengthOfMatch
*/
LengthOfMatch = ((accumulator >> 14) & 0x01FF) + 0x0200;
BitStream_Shift(bs, 18);
}
else if ((accumulator & 0xFFC00000) == 0xFF800000)
{
/**
* LengthOfMatch [1024, 2047]
* bits 1111111110 + 10 lower bits of LengthOfMatch
*/
LengthOfMatch = ((accumulator >> 12) & 0x03FF) + 0x0400;
BitStream_Shift(bs, 20);
}
else if ((accumulator & 0xFFE00000) == 0xFFC00000)
{
/**
* LengthOfMatch [2048, 4095]
* bits 11111111110 + 11 lower bits of LengthOfMatch
*/
LengthOfMatch = ((accumulator >> 10) & 0x07FF) + 0x0800;
BitStream_Shift(bs, 22);
}
else if ((accumulator & 0xFFF00000) == 0xFFE00000)
{
/**
* LengthOfMatch [4096, 8191]
* bits 111111111110 + 12 lower bits of LengthOfMatch
*/
LengthOfMatch = ((accumulator >> 8) & 0x0FFF) + 0x1000;
BitStream_Shift(bs, 24);
}
else if (((accumulator & 0xFFF80000) == 0xFFF00000) && CompressionLevel) /* RDP5 */
{
/**
* LengthOfMatch [8192, 16383]
* bits 1111111111110 + 13 lower bits of LengthOfMatch
*/
LengthOfMatch = ((accumulator >> 6) & 0x1FFF) + 0x2000;
BitStream_Shift(bs, 26);
}
else if (((accumulator & 0xFFFC0000) == 0xFFF80000) && CompressionLevel) /* RDP5 */
{
/**
* LengthOfMatch [16384, 32767]
* bits 11111111111110 + 14 lower bits of LengthOfMatch
*/
LengthOfMatch = ((accumulator >> 4) & 0x3FFF) + 0x4000;
BitStream_Shift(bs, 28);
}
else if (((accumulator & 0xFFFE0000) == 0xFFFC0000) && CompressionLevel) /* RDP5 */
{
/**
* LengthOfMatch [32768, 65535]
* bits 111111111111110 + 15 lower bits of LengthOfMatch
*/
LengthOfMatch = ((accumulator >> 2) & 0x7FFF) + 0x8000;
BitStream_Shift(bs, 30);
}
else
{
/* Invalid LengthOfMatch Encoding */
return -1003;
}
#if defined(DEBUG_MPPC)
WLog_DBG(TAG, "<%" PRIu32 ",%" PRIu32 ">", CopyOffset, LengthOfMatch);
#endif
if ((HistoryPtr + LengthOfMatch - 1) > HistoryBufferEnd)
{
WLog_ERR(TAG, "history buffer overflow");
return -1005;
}
SrcPtr = &HistoryBuffer[(HistoryPtr - HistoryBuffer - CopyOffset) &
(CompressionLevel ? 0xFFFF : 0x1FFF)];
do
{
*HistoryPtr++ = *SrcPtr++;
} while (--LengthOfMatch);
}
*pDstSize = (UINT32)(HistoryPtr - mppc->HistoryPtr);
*ppDstData = mppc->HistoryPtr;
mppc->HistoryPtr = HistoryPtr;
return 1;
}
int mppc_compress(MPPC_CONTEXT* mppc, const BYTE* pSrcData, UINT32 SrcSize, BYTE* pDstBuffer,
const BYTE** ppDstData, UINT32* pDstSize, UINT32* pFlags)
{
const BYTE* pSrcPtr = nullptr;
const BYTE* pSrcEnd = nullptr;
BYTE* MatchPtr = nullptr;
UINT32 DstSize = 0;
BYTE* pDstData = nullptr;
UINT32 MatchIndex = 0;
UINT32 accumulator = 0;
BOOL PacketFlushed = 0;
BOOL PacketAtFront = 0;
DWORD CopyOffset = 0;
DWORD LengthOfMatch = 0;
BYTE* HistoryBuffer = nullptr;
BYTE* HistoryPtr = nullptr;
UINT32 HistoryOffset = 0;
UINT32 HistoryBufferSize = 0;
BYTE Sym1 = 0;
BYTE Sym2 = 0;
BYTE Sym3 = 0;
UINT32 CompressionLevel = 0;
wBitStream* bs = nullptr;
WINPR_ASSERT(mppc);
WINPR_ASSERT(pSrcData);
WINPR_ASSERT(pDstBuffer);
WINPR_ASSERT(ppDstData);
WINPR_ASSERT(pDstSize);
WINPR_ASSERT(pFlags);
bs = mppc->bs;
WINPR_ASSERT(bs);
HistoryBuffer = mppc->HistoryBuffer;
WINPR_ASSERT(HistoryBuffer);
HistoryBufferSize = mppc->HistoryBufferSize;
CompressionLevel = mppc->CompressionLevel;
HistoryOffset = mppc->HistoryOffset;
*pFlags = 0;
PacketFlushed = FALSE;
if (((HistoryOffset + SrcSize) < (HistoryBufferSize - 3)) && HistoryOffset)
{
PacketAtFront = FALSE;
}
else
{
if (HistoryOffset == (HistoryBufferSize + 1))
PacketFlushed = TRUE;
HistoryOffset = 0;
PacketAtFront = TRUE;
}
HistoryPtr = &(HistoryBuffer[HistoryOffset]);
pDstData = pDstBuffer;
*ppDstData = pDstBuffer;
if (!pDstData)
return -1;
if (*pDstSize > SrcSize)
DstSize = SrcSize;
else
DstSize = *pDstSize;
BitStream_Attach(bs, pDstData, DstSize);
pSrcPtr = pSrcData;
pSrcEnd = &(pSrcData[SrcSize - 1]);
while (pSrcPtr < (pSrcEnd - 2))
{
Sym1 = pSrcPtr[0];
Sym2 = pSrcPtr[1];
Sym3 = pSrcPtr[2];
*HistoryPtr++ = *pSrcPtr++;
MatchIndex = MPPC_MATCH_INDEX(Sym1, Sym2, Sym3);
MatchPtr = &(HistoryBuffer[mppc->MatchBuffer[MatchIndex]]);
if (MatchPtr != (HistoryPtr - 1))
mppc->MatchBuffer[MatchIndex] = (UINT16)(HistoryPtr - HistoryBuffer);
if (mppc->HistoryPtr < HistoryPtr)
mppc->HistoryPtr = HistoryPtr;
if ((Sym1 != *(MatchPtr - 1)) || (Sym2 != MatchPtr[0]) || (Sym3 != MatchPtr[1]) ||
(&MatchPtr[1] > mppc->HistoryPtr) || (MatchPtr == HistoryBuffer) ||
(MatchPtr == (HistoryPtr - 1)) || (MatchPtr == HistoryPtr))
{
if (((bs->position / 8) + 2) > (DstSize - 1))
{
mppc_context_reset(mppc, TRUE);
*pFlags |= PACKET_FLUSHED;
*pFlags |= CompressionLevel;
*ppDstData = pSrcData;
*pDstSize = SrcSize;
return 1;
}
accumulator = Sym1;
#if defined(DEBUG_MPPC)
WLog_DBG(TAG, "%" PRIu32 "", accumulator);
#endif
if (accumulator < 0x80)
{
/* 8 bits of literal are encoded as-is */
BitStream_Write_Bits(bs, accumulator, 8);
}
else
{
/* bits 10 followed by lower 7 bits of literal */
accumulator = 0x100 | (accumulator & 0x7F);
BitStream_Write_Bits(bs, accumulator, 9);
}
}
else
{
CopyOffset = (HistoryBufferSize - 1) & (HistoryPtr - MatchPtr);
*HistoryPtr++ = Sym2;
*HistoryPtr++ = Sym3;
pSrcPtr += 2;
LengthOfMatch = 3;
MatchPtr += 2;
while ((*pSrcPtr == *MatchPtr) && (pSrcPtr < pSrcEnd) && (MatchPtr <= mppc->HistoryPtr))
{
MatchPtr++;
*HistoryPtr++ = *pSrcPtr++;
LengthOfMatch++;
}
#if defined(DEBUG_MPPC)
WLog_DBG(TAG, "<%" PRIu32 ",%" PRIu32 ">", CopyOffset, LengthOfMatch);
#endif
/* Encode CopyOffset */
if (((bs->position / 8) + 7) > (DstSize - 1))
{
mppc_context_reset(mppc, TRUE);
*pFlags |= PACKET_FLUSHED;
*pFlags |= CompressionLevel;
*ppDstData = pSrcData;
*pDstSize = SrcSize;
return 1;
}
if (CompressionLevel) /* RDP5 */
{
if (CopyOffset < 64)
{
/* bits 11111 + lower 6 bits of CopyOffset */
accumulator = 0x07C0 | (CopyOffset & 0x003F);
BitStream_Write_Bits(bs, accumulator, 11);
}
else if ((CopyOffset >= 64) && (CopyOffset < 320))
{
/* bits 11110 + lower 8 bits of (CopyOffset - 64) */
accumulator = 0x1E00 | ((CopyOffset - 64) & 0x00FF);
BitStream_Write_Bits(bs, accumulator, 13);
}
else if ((CopyOffset >= 320) && (CopyOffset < 2368))
{
/* bits 1110 + lower 11 bits of (CopyOffset - 320) */
accumulator = 0x7000 | ((CopyOffset - 320) & 0x07FF);
BitStream_Write_Bits(bs, accumulator, 15);
}
else
{
/* bits 110 + lower 16 bits of (CopyOffset - 2368) */
accumulator = 0x060000 | ((CopyOffset - 2368) & 0xFFFF);
BitStream_Write_Bits(bs, accumulator, 19);
}
}
else /* RDP4 */
{
if (CopyOffset < 64)
{
/* bits 1111 + lower 6 bits of CopyOffset */
accumulator = 0x03C0 | (CopyOffset & 0x003F);
BitStream_Write_Bits(bs, accumulator, 10);
}
else if ((CopyOffset >= 64) && (CopyOffset < 320))
{
/* bits 1110 + lower 8 bits of (CopyOffset - 64) */
accumulator = 0x0E00 | ((CopyOffset - 64) & 0x00FF);
BitStream_Write_Bits(bs, accumulator, 12);
}
else if ((CopyOffset >= 320) && (CopyOffset < 8192))
{
/* bits 110 + lower 13 bits of (CopyOffset - 320) */
accumulator = 0xC000 | ((CopyOffset - 320) & 0x1FFF);
BitStream_Write_Bits(bs, accumulator, 16);
}
}
/* Encode LengthOfMatch */
if (LengthOfMatch == 3)
{
/* 0 + 0 lower bits of LengthOfMatch */
BitStream_Write_Bits(bs, 0, 1);
}
else if ((LengthOfMatch >= 4) && (LengthOfMatch < 8))
{
/* 10 + 2 lower bits of LengthOfMatch */
accumulator = 0x0008 | (LengthOfMatch & 0x0003);
BitStream_Write_Bits(bs, accumulator, 4);
}
else if ((LengthOfMatch >= 8) && (LengthOfMatch < 16))
{
/* 110 + 3 lower bits of LengthOfMatch */
accumulator = 0x0030 | (LengthOfMatch & 0x0007);
BitStream_Write_Bits(bs, accumulator, 6);
}
else if ((LengthOfMatch >= 16) && (LengthOfMatch < 32))
{
/* 1110 + 4 lower bits of LengthOfMatch */
accumulator = 0x00E0 | (LengthOfMatch & 0x000F);
BitStream_Write_Bits(bs, accumulator, 8);
}
else if ((LengthOfMatch >= 32) && (LengthOfMatch < 64))
{
/* 11110 + 5 lower bits of LengthOfMatch */
accumulator = 0x03C0 | (LengthOfMatch & 0x001F);
BitStream_Write_Bits(bs, accumulator, 10);
}
else if ((LengthOfMatch >= 64) && (LengthOfMatch < 128))
{
/* 111110 + 6 lower bits of LengthOfMatch */
accumulator = 0x0F80 | (LengthOfMatch & 0x003F);
BitStream_Write_Bits(bs, accumulator, 12);
}
else if ((LengthOfMatch >= 128) && (LengthOfMatch < 256))
{
/* 1111110 + 7 lower bits of LengthOfMatch */
accumulator = 0x3F00 | (LengthOfMatch & 0x007F);
BitStream_Write_Bits(bs, accumulator, 14);
}
else if ((LengthOfMatch >= 256) && (LengthOfMatch < 512))
{
/* 11111110 + 8 lower bits of LengthOfMatch */
accumulator = 0xFE00 | (LengthOfMatch & 0x00FF);
BitStream_Write_Bits(bs, accumulator, 16);
}
else if ((LengthOfMatch >= 512) && (LengthOfMatch < 1024))
{
/* 111111110 + 9 lower bits of LengthOfMatch */
accumulator = 0x3FC00 | (LengthOfMatch & 0x01FF);
BitStream_Write_Bits(bs, accumulator, 18);
}
else if ((LengthOfMatch >= 1024) && (LengthOfMatch < 2048))
{
/* 1111111110 + 10 lower bits of LengthOfMatch */
accumulator = 0xFF800 | (LengthOfMatch & 0x03FF);
BitStream_Write_Bits(bs, accumulator, 20);
}
else if ((LengthOfMatch >= 2048) && (LengthOfMatch < 4096))
{
/* 11111111110 + 11 lower bits of LengthOfMatch */
accumulator = 0x3FF000 | (LengthOfMatch & 0x07FF);
BitStream_Write_Bits(bs, accumulator, 22);
}
else if ((LengthOfMatch >= 4096) && (LengthOfMatch < 8192))
{
/* 111111111110 + 12 lower bits of LengthOfMatch */
accumulator = 0xFFE000 | (LengthOfMatch & 0x0FFF);
BitStream_Write_Bits(bs, accumulator, 24);
}
else if (((LengthOfMatch >= 8192) && (LengthOfMatch < 16384)) &&
CompressionLevel) /* RDP5 */
{
/* 1111111111110 + 13 lower bits of LengthOfMatch */
accumulator = 0x3FFC000 | (LengthOfMatch & 0x1FFF);
BitStream_Write_Bits(bs, accumulator, 26);
}
else if (((LengthOfMatch >= 16384) && (LengthOfMatch < 32768)) &&
CompressionLevel) /* RDP5 */
{
/* 11111111111110 + 14 lower bits of LengthOfMatch */
accumulator = 0xFFF8000 | (LengthOfMatch & 0x3FFF);
BitStream_Write_Bits(bs, accumulator, 28);
}
else if (((LengthOfMatch >= 32768) && (LengthOfMatch < 65536)) &&
CompressionLevel) /* RDP5 */
{
/* 111111111111110 + 15 lower bits of LengthOfMatch */
accumulator = 0x3FFF0000 | (LengthOfMatch & 0x7FFF);
BitStream_Write_Bits(bs, accumulator, 30);
}
}
}
/* Encode trailing symbols as literals */
while (pSrcPtr <= pSrcEnd)
{
if (((bs->position / 8) + 2) > (DstSize - 1))
{
mppc_context_reset(mppc, TRUE);
*pFlags |= PACKET_FLUSHED;
*pFlags |= CompressionLevel;
*ppDstData = pSrcData;
*pDstSize = SrcSize;
return 1;
}
accumulator = *pSrcPtr;
#if defined(DEBUG_MPPC)
WLog_DBG(TAG, "%" PRIu32 "", accumulator);
#endif
if (accumulator < 0x80)
{
/* 8 bits of literal are encoded as-is */
BitStream_Write_Bits(bs, accumulator, 8);
}
else
{
/* bits 10 followed by lower 7 bits of literal */
accumulator = 0x100 | (accumulator & 0x7F);
BitStream_Write_Bits(bs, accumulator, 9);
}
*HistoryPtr++ = *pSrcPtr++;
}
BitStream_Flush(bs);
*pFlags |= PACKET_COMPRESSED;
*pFlags |= CompressionLevel;
if (PacketAtFront)
*pFlags |= PACKET_AT_FRONT;
if (PacketFlushed)
*pFlags |= PACKET_FLUSHED;
*pDstSize = ((bs->position + 7) / 8);
mppc->HistoryPtr = HistoryPtr;
const intptr_t diff = HistoryPtr - HistoryBuffer;
if (diff > UINT32_MAX)
return -1;
mppc->HistoryOffset = (UINT32)diff;
return 1;
}
void mppc_set_compression_level(MPPC_CONTEXT* mppc, DWORD CompressionLevel)
{
WINPR_ASSERT(mppc);
if (CompressionLevel < 1)
{
mppc->CompressionLevel = 0;
mppc->HistoryBufferSize = 8192;
}
else
{
mppc->CompressionLevel = 1;
mppc->HistoryBufferSize = 65536;
}
}
void mppc_context_reset(MPPC_CONTEXT* mppc, BOOL flush)
{
WINPR_ASSERT(mppc);
ZeroMemory(&(mppc->HistoryBuffer), sizeof(mppc->HistoryBuffer));
ZeroMemory(&(mppc->MatchBuffer), sizeof(mppc->MatchBuffer));
if (flush)
{
mppc->HistoryOffset = mppc->HistoryBufferSize + 1;
mppc->HistoryPtr = mppc->HistoryBuffer;
}
else
{
mppc->HistoryOffset = 0;
mppc->HistoryPtr = &(mppc->HistoryBuffer[mppc->HistoryOffset]);
}
}
MPPC_CONTEXT* mppc_context_new(DWORD CompressionLevel, BOOL Compressor)
{
MPPC_CONTEXT* mppc = calloc(1, sizeof(MPPC_CONTEXT));
if (!mppc)
goto fail;
mppc->Compressor = Compressor;
if (CompressionLevel < 1)
{
mppc->CompressionLevel = 0;
mppc->HistoryBufferSize = 8192;
}
else
{
mppc->CompressionLevel = 1;
mppc->HistoryBufferSize = 65536;
}
mppc->bs = BitStream_New();
if (!mppc->bs)
goto fail;
mppc_context_reset(mppc, FALSE);
return mppc;
fail:
mppc_context_free(mppc);
return nullptr;
}
void mppc_context_free(MPPC_CONTEXT* mppc)
{
if (mppc)
{
BitStream_Free(mppc->bs);
free(mppc);
}
}
+60
View File
@@ -0,0 +1,60 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* MPPC Bulk Data Compression
*
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* 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 FREERDP_MPPC_H
#define FREERDP_MPPC_H
#include <freerdp/api.h>
#include <freerdp/types.h>
#include <winpr/bitstream.h>
#include <freerdp/codec/bulk.h>
typedef struct s_MPPC_CONTEXT MPPC_CONTEXT;
#ifdef __cplusplus
extern "C"
{
#endif
WINPR_ATTR_NODISCARD
FREERDP_LOCAL int mppc_compress(MPPC_CONTEXT* mppc, const BYTE* pSrcData, UINT32 SrcSize,
BYTE* pDstBuffer, const BYTE** ppDstData, UINT32* pDstSize,
UINT32* pFlags);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL int mppc_decompress(MPPC_CONTEXT* mppc, const BYTE* pSrcData, UINT32 SrcSize,
const BYTE** ppDstData, UINT32* pDstSize, UINT32 flags);
FREERDP_LOCAL void mppc_set_compression_level(MPPC_CONTEXT* mppc, DWORD CompressionLevel);
FREERDP_LOCAL void mppc_context_reset(MPPC_CONTEXT* mppc, BOOL flush);
FREERDP_LOCAL void mppc_context_free(MPPC_CONTEXT* mppc);
WINPR_ATTR_MALLOC(mppc_context_free, 1)
WINPR_ATTR_NODISCARD
FREERDP_LOCAL MPPC_CONTEXT* mppc_context_new(DWORD CompressionLevel, BOOL Compressor);
#ifdef __cplusplus
}
#endif
#endif /* FREERDP_MPPC_H */
File diff suppressed because it is too large Load Diff
+58
View File
@@ -0,0 +1,58 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* NCrush (RDP6) Bulk Data Compression
*
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* 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 FREERDP_CODEC_NCRUSH_H
#define FREERDP_CODEC_NCRUSH_H
#include <freerdp/api.h>
#include <freerdp/types.h>
#include "mppc.h"
#include <winpr/bitstream.h>
typedef struct s_NCRUSH_CONTEXT NCRUSH_CONTEXT;
#ifdef __cplusplus
extern "C"
{
#endif
WINPR_ATTR_NODISCARD
FREERDP_LOCAL int ncrush_compress(NCRUSH_CONTEXT* ncrush, const BYTE* pSrcData, UINT32 SrcSize,
BYTE* pDstBuffer, const BYTE** ppDstData, UINT32* pDstSize,
UINT32* pFlags);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL int ncrush_decompress(NCRUSH_CONTEXT* ncrush, const BYTE* pSrcData,
UINT32 SrcSize, const BYTE** ppDstData, UINT32* pDstSize,
UINT32 flags);
FREERDP_LOCAL void ncrush_context_reset(NCRUSH_CONTEXT* ncrush, BOOL flush);
FREERDP_LOCAL void ncrush_context_free(NCRUSH_CONTEXT* ncrush);
WINPR_ATTR_MALLOC(ncrush_context_free, 1)
WINPR_ATTR_NODISCARD
FREERDP_LOCAL NCRUSH_CONTEXT* ncrush_context_new(BOOL Compressor);
#ifdef __cplusplus
}
#endif
#endif /* FREERDP_CODEC_NCRUSH_H */
+43
View File
@@ -0,0 +1,43 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* NSCodec Library - SSE2 Optimizations
*
* Copyright 2024 Armin Novak <anovak@thincast.com>
* Copyright 2024 Thincast Technologies GmbH
*
* 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 <winpr/platform.h>
#include <winpr/sysinfo.h>
#include <freerdp/config.h>
#include <freerdp/codec/nsc.h>
#include <freerdp/log.h>
#include "../nsc_types.h"
#include "nsc_neon.h"
#include "../../core/simd.h"
#if defined(NEON_INTRINSICS_ENABLED)
#define TAG FREERDP_TAG("codec.nsc.neon")
#endif
void nsc_init_neon_int(WINPR_ATTR_UNUSED NSC_CONTEXT* WINPR_RESTRICT context)
{
#if defined(NEON_INTRINSICS_ENABLED)
WLog_WARN(TAG, "TODO: Implement neon optimized version of this function");
#else
WLog_VRB(PRIM_TAG, "undefined WITH_SIMD or NEON intrinsics not available");
#endif
}
+37
View File
@@ -0,0 +1,37 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* NSCodec Library - NEON Optimizations
*
* Copyright 2012 Vic Lee
*
* 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 FREERDP_LIB_CODEC_NSC_NEON_H
#define FREERDP_LIB_CODEC_NSC_NEON_H
#include <winpr/sysinfo.h>
#include <freerdp/codec/nsc.h>
#include <freerdp/api.h>
FREERDP_LOCAL void nsc_init_neon_int(NSC_CONTEXT* WINPR_RESTRICT context);
static inline void nsc_init_neon(NSC_CONTEXT* WINPR_RESTRICT context)
{
if (!IsProcessorFeaturePresent(PF_ARM_NEON_INSTRUCTIONS_AVAILABLE))
return;
nsc_init_neon_int(context);
}
#endif /* FREERDP_LIB_CODEC_NSC_NEON_H */
+540
View File
@@ -0,0 +1,540 @@
/*
FreeRDP: A Remote Desktop Protocol Implementation
RemoteFX Codec Library - NEON Optimizations
Copyright 2011 Martin Fleisz <martin.fleisz@thincast.com>
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 <winpr/platform.h>
#include <freerdp/config.h>
#include <freerdp/log.h>
#include "../rfx_types.h"
#include "rfx_neon.h"
#include "../../core/simd.h"
#if defined(NEON_INTRINSICS_ENABLED)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <arm_neon.h>
#include <winpr/sysinfo.h>
/* rfx_decode_YCbCr_to_RGB_NEON code now resides in the primitives library. */
static inline void __attribute__((__gnu_inline__, __always_inline__, __artificial__))
rfx_quantization_decode_block_NEON(INT16* buffer, const size_t buffer_size, const UINT32 factor)
{
int16x8_t quantFactors = vdupq_n_s16(factor);
int16x8_t* buf = (int16x8_t*)buffer;
int16x8_t* buf_end = (int16x8_t*)(buffer + buffer_size);
do
{
int16x8_t val = vld1q_s16((INT16*)buf);
val = vshlq_s16(val, quantFactors);
vst1q_s16((INT16*)buf, val);
buf++;
} while (buf < buf_end);
}
static void rfx_quantization_decode_NEON(INT16* buffer, const UINT32* WINPR_RESTRICT quantVals)
{
WINPR_ASSERT(buffer);
WINPR_ASSERT(quantVals);
rfx_quantization_decode_block_NEON(&buffer[0], 1024, quantVals[8] - 1); /* HL1 */
rfx_quantization_decode_block_NEON(&buffer[1024], 1024, quantVals[7] - 1); /* LH1 */
rfx_quantization_decode_block_NEON(&buffer[2048], 1024, quantVals[9] - 1); /* HH1 */
rfx_quantization_decode_block_NEON(&buffer[3072], 256, quantVals[5] - 1); /* HL2 */
rfx_quantization_decode_block_NEON(&buffer[3328], 256, quantVals[4] - 1); /* LH2 */
rfx_quantization_decode_block_NEON(&buffer[3584], 256, quantVals[6] - 1); /* HH2 */
rfx_quantization_decode_block_NEON(&buffer[3840], 64, quantVals[2] - 1); /* HL3 */
rfx_quantization_decode_block_NEON(&buffer[3904], 64, quantVals[1] - 1); /* LH3 */
rfx_quantization_decode_block_NEON(&buffer[3968], 64, quantVals[3] - 1); /* HH3 */
rfx_quantization_decode_block_NEON(&buffer[4032], 64, quantVals[0] - 1); /* LL3 */
}
static inline void __attribute__((__gnu_inline__, __always_inline__, __artificial__))
rfx_dwt_2d_decode_block_horiz_NEON(INT16* WINPR_RESTRICT l, INT16* WINPR_RESTRICT h,
INT16* WINPR_RESTRICT dst, size_t subband_width)
{
INT16* l_ptr = l;
INT16* h_ptr = h;
INT16* dst_ptr = dst;
for (size_t y = 0; y < subband_width; y++)
{
/* Even coefficients */
for (size_t n = 0; n < subband_width; n += 8)
{
// dst[2n] = l[n] - ((h[n-1] + h[n] + 1) >> 1);
int16x8_t l_n = vld1q_s16(l_ptr);
int16x8_t h_n = vld1q_s16(h_ptr);
int16x8_t h_n_m = vld1q_s16(h_ptr - 1);
if (n == 0)
{
int16_t first = vgetq_lane_s16(h_n_m, 1);
h_n_m = vsetq_lane_s16(first, h_n_m, 0);
}
int16x8_t tmp_n = vaddq_s16(h_n, h_n_m);
tmp_n = vaddq_s16(tmp_n, vdupq_n_s16(1));
tmp_n = vshrq_n_s16(tmp_n, 1);
int16x8_t dst_n = vsubq_s16(l_n, tmp_n);
vst1q_s16(l_ptr, dst_n);
l_ptr += 8;
h_ptr += 8;
}
l_ptr -= subband_width;
h_ptr -= subband_width;
/* Odd coefficients */
for (size_t n = 0; n < subband_width; n += 8)
{
// dst[2n + 1] = (h[n] << 1) + ((dst[2n] + dst[2n + 2]) >> 1);
int16x8_t h_n = vld1q_s16(h_ptr);
h_n = vshlq_n_s16(h_n, 1);
int16x8x2_t dst_n;
dst_n.val[0] = vld1q_s16(l_ptr);
int16x8_t dst_n_p = vld1q_s16(l_ptr + 1);
if (n == subband_width - 8)
{
int16_t last = vgetq_lane_s16(dst_n_p, 6);
dst_n_p = vsetq_lane_s16(last, dst_n_p, 7);
}
dst_n.val[1] = vaddq_s16(dst_n_p, dst_n.val[0]);
dst_n.val[1] = vshrq_n_s16(dst_n.val[1], 1);
dst_n.val[1] = vaddq_s16(dst_n.val[1], h_n);
vst2q_s16(dst_ptr, dst_n);
l_ptr += 8;
h_ptr += 8;
dst_ptr += 16;
}
}
}
static inline void __attribute__((__gnu_inline__, __always_inline__, __artificial__))
rfx_dwt_2d_decode_block_vert_NEON(INT16* WINPR_RESTRICT l, INT16* WINPR_RESTRICT h,
INT16* WINPR_RESTRICT dst, size_t subband_width)
{
INT16* l_ptr = l;
INT16* h_ptr = h;
INT16* dst_ptr = dst;
const size_t total_width = subband_width + subband_width;
/* Even coefficients */
for (size_t n = 0; n < subband_width; n++)
{
for (size_t x = 0; x < total_width; x += 8)
{
// dst[2n] = l[n] - ((h[n-1] + h[n] + 1) >> 1);
int16x8_t l_n = vld1q_s16(l_ptr);
int16x8_t h_n = vld1q_s16(h_ptr);
int16x8_t tmp_n = vaddq_s16(h_n, vdupq_n_s16(1));
if (n == 0)
tmp_n = vaddq_s16(tmp_n, h_n);
else
{
int16x8_t h_n_m = vld1q_s16((h_ptr - total_width));
tmp_n = vaddq_s16(tmp_n, h_n_m);
}
tmp_n = vshrq_n_s16(tmp_n, 1);
int16x8_t dst_n = vsubq_s16(l_n, tmp_n);
vst1q_s16(dst_ptr, dst_n);
l_ptr += 8;
h_ptr += 8;
dst_ptr += 8;
}
dst_ptr += total_width;
}
h_ptr = h;
dst_ptr = dst + total_width;
/* Odd coefficients */
for (size_t n = 0; n < subband_width; n++)
{
for (size_t x = 0; x < total_width; x += 8)
{
// dst[2n + 1] = (h[n] << 1) + ((dst[2n] + dst[2n + 2]) >> 1);
int16x8_t h_n = vld1q_s16(h_ptr);
int16x8_t dst_n_m = vld1q_s16(dst_ptr - total_width);
h_n = vshlq_n_s16(h_n, 1);
int16x8_t tmp_n = dst_n_m;
if (n == subband_width - 1)
tmp_n = vaddq_s16(tmp_n, dst_n_m);
else
{
int16x8_t dst_n_p = vld1q_s16((dst_ptr + total_width));
tmp_n = vaddq_s16(tmp_n, dst_n_p);
}
tmp_n = vshrq_n_s16(tmp_n, 1);
int16x8_t dst_n = vaddq_s16(tmp_n, h_n);
vst1q_s16(dst_ptr, dst_n);
h_ptr += 8;
dst_ptr += 8;
}
dst_ptr += total_width;
}
}
static inline void __attribute__((__gnu_inline__, __always_inline__, __artificial__))
rfx_dwt_2d_decode_block_NEON(INT16* WINPR_RESTRICT buffer, INT16* WINPR_RESTRICT idwt,
size_t subband_width)
{
INT16 *hl, *lh, *hh, *ll;
INT16 *l_dst, *h_dst;
/* Inverse DWT in horizontal direction, results in 2 sub-bands in L, H order in tmp buffer idwt.
*/
/* The 4 sub-bands are stored in HL(0), LH(1), HH(2), LL(3) order. */
/* The lower part L uses LL(3) and HL(0). */
/* The higher part H uses LH(1) and HH(2). */
ll = buffer + subband_width * subband_width * 3;
hl = buffer;
l_dst = idwt;
rfx_dwt_2d_decode_block_horiz_NEON(ll, hl, l_dst, subband_width);
lh = buffer + subband_width * subband_width;
hh = buffer + subband_width * subband_width * 2;
h_dst = idwt + subband_width * subband_width * 2;
rfx_dwt_2d_decode_block_horiz_NEON(lh, hh, h_dst, subband_width);
/* Inverse DWT in vertical direction, results are stored in original buffer. */
rfx_dwt_2d_decode_block_vert_NEON(l_dst, h_dst, buffer, subband_width);
}
static void rfx_dwt_2d_decode_NEON(INT16* buffer, INT16* dwt_buffer)
{
rfx_dwt_2d_decode_block_NEON(buffer + 3840, dwt_buffer, 8);
rfx_dwt_2d_decode_block_NEON(buffer + 3072, dwt_buffer, 16);
rfx_dwt_2d_decode_block_NEON(buffer, dwt_buffer, 32);
}
static inline void rfx_idwt_extrapolate_horiz_neon(INT16* restrict pLowBand, size_t nLowStep,
const INT16* restrict pHighBand,
size_t nHighStep, INT16* restrict pDstBand,
size_t nDstStep, size_t nLowCount,
size_t nHighCount, size_t nDstCount)
{
WINPR_ASSERT(pLowBand);
WINPR_ASSERT(pHighBand);
WINPR_ASSERT(pDstBand);
INT16* l_ptr = pLowBand;
const INT16* h_ptr = pHighBand;
INT16* dst_ptr = pDstBand;
size_t batchSize = (nLowCount + nHighCount) >> 1;
for (size_t y = 0; y < nDstCount; y++)
{
/* Even coefficients */
size_t n = 0;
for (; n < batchSize; n += 8)
{
// dst[2n] = l[n] - ((h[n-1] + h[n] + 1) >> 1);
int16x8_t l_n = vld1q_s16(l_ptr);
int16x8_t h_n = vld1q_s16(h_ptr);
int16x8_t h_n_m = vld1q_s16(h_ptr - 1);
if (n == 0)
{
int16_t first = vgetq_lane_s16(h_n_m, 1);
h_n_m = vsetq_lane_s16(first, h_n_m, 0);
}
else if (n == 24)
h_n = vsetq_lane_s16(0, h_n, 7);
int16x8_t tmp_n = vaddq_s16(h_n, h_n_m);
tmp_n = vaddq_s16(tmp_n, vdupq_n_s16(1));
tmp_n = vshrq_n_s16(tmp_n, 1);
int16x8_t dst_n = vsubq_s16(l_n, tmp_n);
vst1q_s16(l_ptr, dst_n);
l_ptr += 8;
h_ptr += 8;
}
if (n < 32)
*l_ptr -= *(h_ptr - 1);
l_ptr -= batchSize;
h_ptr -= batchSize;
/* Odd coefficients */
n = 0;
for (; n < batchSize; n += 8)
{
// dst[2n + 1] = (h[n] << 1) + ((dst[2n] + dst[2n + 2]) >> 1);
int16x8_t h_n = vld1q_s16(h_ptr);
h_n = vshlq_n_s16(h_n, 1);
int16x8x2_t dst_n;
dst_n.val[0] = vld1q_s16(l_ptr);
int16x8_t dst_n_p = vld1q_s16(l_ptr + 1);
if (n == 24)
h_n = vsetq_lane_s16(0, h_n, 7);
dst_n.val[1] = vaddq_s16(dst_n_p, dst_n.val[0]);
dst_n.val[1] = vshrq_n_s16(dst_n.val[1], 1);
dst_n.val[1] = vaddq_s16(dst_n.val[1], h_n);
vst2q_s16(dst_ptr, dst_n);
l_ptr += 8;
h_ptr += 8;
dst_ptr += 16;
}
if (n == 32)
{
h_ptr -= 1;
l_ptr += 1;
}
else
{
*dst_ptr = *l_ptr;
l_ptr += 1;
dst_ptr += 1;
}
}
}
static inline void rfx_idwt_extrapolate_vert_neon(const INT16* restrict pLowBand, size_t nLowStep,
const INT16* restrict pHighBand, size_t nHighStep,
INT16* restrict pDstBand, size_t nDstStep,
size_t nLowCount, size_t nHighCount,
size_t nDstCount)
{
WINPR_ASSERT(pLowBand);
WINPR_ASSERT(pHighBand);
WINPR_ASSERT(pDstBand);
const INT16* l_ptr = pLowBand;
const INT16* h_ptr = pHighBand;
INT16* dst_ptr = pDstBand;
size_t batchSize = (nDstCount >> 3) << 3;
size_t forceBandSize = (nLowCount + nHighCount) >> 1;
/* Even coefficients */
for (size_t n = 0; n < forceBandSize; n++)
{
for (size_t x = 0; x < batchSize; x += 8)
{
// dst[2n] = l[n] - ((h[n-1] + h[n] + 1) >> 1);
int16x8_t l_n = vld1q_s16(l_ptr);
int16x8_t h_n = vld1q_s16((n == 31) ? (h_ptr - nHighStep) : h_ptr);
int16x8_t tmp_n = vaddq_s16(h_n, vdupq_n_s16(1));
if (n == 0)
tmp_n = vaddq_s16(tmp_n, h_n);
else if (n < 31)
{
int16x8_t h_n_m = vld1q_s16((h_ptr - nHighStep));
tmp_n = vaddq_s16(tmp_n, h_n_m);
}
tmp_n = vshrq_n_s16(tmp_n, 1);
int16x8_t dst_n = vsubq_s16(l_n, tmp_n);
vst1q_s16(dst_ptr, dst_n);
l_ptr += 8;
h_ptr += 8;
dst_ptr += 8;
}
if (nDstCount > batchSize)
{
int16_t h_n = (n == 31) ? *(h_ptr - nHighStep) : *h_ptr;
int16_t tmp_n = h_n + 1;
if (n == 0)
tmp_n += h_n;
else if (n < 31)
tmp_n += *(h_ptr - nHighStep);
tmp_n >>= 1;
*dst_ptr = *l_ptr - tmp_n;
l_ptr += 1;
h_ptr += 1;
dst_ptr += 1;
}
dst_ptr += nDstStep;
}
if (forceBandSize < 32)
{
for (size_t x = 0; x < batchSize; x += 8)
{
int16x8_t l_n = vld1q_s16(l_ptr);
int16x8_t h_n = vld1q_s16(h_ptr - nHighStep);
int16x8_t tmp_n = vsubq_s16(l_n, h_n);
vst1q_s16(dst_ptr, tmp_n);
l_ptr += 8;
h_ptr += 8;
dst_ptr += 8;
}
if (nDstCount > batchSize)
{
*dst_ptr = *l_ptr - *(h_ptr - nHighStep);
l_ptr += 1;
h_ptr += 1;
dst_ptr += 1;
}
}
h_ptr = pHighBand;
dst_ptr = pDstBand + nDstStep;
/* Odd coefficients */
for (size_t n = 0; n < forceBandSize; n++)
{
for (size_t x = 0; x < batchSize; x += 8)
{
// dst[2n + 1] = (h[n] << 1) + ((dst[2n] + dst[2n + 2]) >> 1);
int16x8_t tmp_n = vld1q_s16(dst_ptr - nDstStep);
if (n == 31)
{
int16x8_t dst_n_p = vld1q_s16(l_ptr);
l_ptr += 8;
tmp_n = vaddq_s16(tmp_n, dst_n_p);
tmp_n = vshrq_n_s16(tmp_n, 1);
}
else
{
int16x8_t dst_n_p = vld1q_s16(dst_ptr + nDstStep);
tmp_n = vaddq_s16(tmp_n, dst_n_p);
tmp_n = vshrq_n_s16(tmp_n, 1);
int16x8_t h_n = vld1q_s16(h_ptr);
h_n = vshlq_n_s16(h_n, 1);
tmp_n = vaddq_s16(tmp_n, h_n);
}
vst1q_s16(dst_ptr, tmp_n);
h_ptr += 8;
dst_ptr += 8;
}
if (nDstCount > batchSize)
{
int16_t tmp_n = *(dst_ptr - nDstStep);
if (n == 31)
{
int16_t dst_n_p = *l_ptr;
l_ptr += 1;
tmp_n += dst_n_p;
tmp_n >>= 1;
}
else
{
int16_t dst_n_p = *(dst_ptr + nDstStep);
tmp_n += dst_n_p;
tmp_n >>= 1;
int16_t h_n = *h_ptr;
h_n <<= 1;
tmp_n += h_n;
}
*dst_ptr = tmp_n;
h_ptr += 1;
dst_ptr += 1;
}
dst_ptr += nDstStep;
}
}
static inline size_t prfx_get_band_l_count(size_t level)
{
return (64 >> level) + 1;
}
static inline size_t prfx_get_band_h_count(size_t level)
{
if (level == 1)
return (64 >> 1) - 1;
else
return (64 + (1 << (level - 1))) >> level;
}
static inline void rfx_dwt_2d_decode_extrapolate_block_neon(INT16* buffer, INT16* temp,
size_t level)
{
size_t nDstStepX;
size_t nDstStepY;
INT16 *HL, *LH;
INT16 *HH, *LL;
INT16 *L, *H, *LLx;
const size_t nBandL = prfx_get_band_l_count(level);
const size_t nBandH = prfx_get_band_h_count(level);
size_t offset = 0;
WINPR_ASSERT(buffer);
WINPR_ASSERT(temp);
HL = &buffer[offset];
offset += (nBandH * nBandL);
LH = &buffer[offset];
offset += (nBandL * nBandH);
HH = &buffer[offset];
offset += (nBandH * nBandH);
LL = &buffer[offset];
nDstStepX = (nBandL + nBandH);
nDstStepY = (nBandL + nBandH);
offset = 0;
L = &temp[offset];
offset += (nBandL * nDstStepX);
H = &temp[offset];
LLx = &buffer[0];
/* horizontal (LL + HL -> L) */
rfx_idwt_extrapolate_horiz_neon(LL, nBandL, HL, nBandH, L, nDstStepX, nBandL, nBandH, nBandL);
/* horizontal (LH + HH -> H) */
rfx_idwt_extrapolate_horiz_neon(LH, nBandL, HH, nBandH, H, nDstStepX, nBandL, nBandH, nBandH);
/* vertical (L + H -> LL) */
rfx_idwt_extrapolate_vert_neon(L, nDstStepX, H, nDstStepX, LLx, nDstStepY, nBandL, nBandH,
nBandL + nBandH);
}
static void rfx_dwt_2d_extrapolate_decode_neon(INT16* buffer, INT16* temp)
{
WINPR_ASSERT(buffer);
WINPR_ASSERT(temp);
rfx_dwt_2d_decode_extrapolate_block_neon(&buffer[3807], temp, 3);
rfx_dwt_2d_decode_extrapolate_block_neon(&buffer[3007], temp, 2);
rfx_dwt_2d_decode_extrapolate_block_neon(&buffer[0], temp, 1);
}
#endif // NEON_INTRINSICS_ENABLED
void rfx_init_neon_int(RFX_CONTEXT* WINPR_RESTRICT context)
{
#if defined(NEON_INTRINSICS_ENABLED)
WLog_VRB(PRIM_TAG, "NEON optimizations");
PROFILER_RENAME(context->priv->prof_rfx_ycbcr_to_rgb, "rfx_decode_YCbCr_to_RGB_NEON");
PROFILER_RENAME(context->priv->prof_rfx_quantization_decode, "rfx_quantization_decode_NEON");
PROFILER_RENAME(context->priv->prof_rfx_dwt_2d_decode, "rfx_dwt_2d_decode_NEON");
context->quantization_decode = rfx_quantization_decode_NEON;
context->dwt_2d_decode = rfx_dwt_2d_decode_NEON;
context->dwt_2d_extrapolate_decode = rfx_dwt_2d_extrapolate_decode_neon;
#else
WLog_VRB(PRIM_TAG, "undefined WITH_SIMD or NEON intrinsics not available");
WINPR_UNUSED(context);
#endif
}
+37
View File
@@ -0,0 +1,37 @@
/*
FreeRDP: A Remote Desktop Protocol Implementation
RemoteFX Codec Library - NEON Optimizations
Copyright 2011 Martin Fleisz <martin.fleisz@thincast.com>
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 FREERDP_LIB_CODEC_RFX_NEON_H
#define FREERDP_LIB_CODEC_RFX_NEON_H
#include <winpr/sysinfo.h>
#include <freerdp/codec/rfx.h>
#include <freerdp/api.h>
FREERDP_LOCAL void rfx_init_neon_int(RFX_CONTEXT* WINPR_RESTRICT context);
static inline void rfx_init_neon(RFX_CONTEXT* WINPR_RESTRICT context)
{
if (!IsProcessorFeaturePresent(PF_ARM_NEON_INSTRUCTIONS_AVAILABLE))
return;
rfx_init_neon_int(context);
}
#endif /* FREERDP_LIB_CODEC_RFX_NEON_H */
+534
View File
@@ -0,0 +1,534 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* NSCodec Codec
*
* Copyright 2011 Samsung, Author Jiten Pathy
* Copyright 2012 Vic Lee
* Copyright 2016 Armin Novak <armin.novak@thincast.com>
* Copyright 2016 Thincast Technologies GmbH
*
* 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 <freerdp/config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winpr/assert.h>
#include <winpr/cast.h>
#include <winpr/crt.h>
#include <freerdp/codec/nsc.h>
#include <freerdp/codec/color.h>
#include "nsc_types.h"
#include "nsc_encode.h"
#include "sse/nsc_sse2.h"
#include "neon/nsc_neon.h"
#include <freerdp/log.h>
static BOOL nsc_decode(NSC_CONTEXT* WINPR_RESTRICT context)
{
size_t pos = 0;
if (!context)
return FALSE;
const UINT16 rw = ROUND_UP_TO(context->width, 8);
WINPR_ASSERT(context->ColorLossLevel >= 1);
const BYTE shift = WINPR_ASSERTING_INT_CAST(BYTE, context->ColorLossLevel -
1); /* colorloss recovery + YCoCg shift */
BYTE* bmpdata = context->BitmapData;
if (!bmpdata)
return FALSE;
for (size_t y = 0; y < context->height; y++)
{
const BYTE* yplane = nullptr;
const BYTE* coplane = nullptr;
const BYTE* cgplane = nullptr;
const BYTE* aplane = context->priv->PlaneBuffers[3] + y * context->width; /* A */
if (context->ChromaSubsamplingLevel)
{
yplane = context->priv->PlaneBuffers[0] + y * rw; /* Y */
coplane = context->priv->PlaneBuffers[1] + (y >> 1) * (rw >> 1); /* Co, supersampled */
cgplane = context->priv->PlaneBuffers[2] + (y >> 1) * (rw >> 1); /* Cg, supersampled */
}
else
{
yplane = context->priv->PlaneBuffers[0] + y * context->width; /* Y */
coplane = context->priv->PlaneBuffers[1] + y * context->width; /* Co */
cgplane = context->priv->PlaneBuffers[2] + y * context->width; /* Cg */
}
for (UINT32 x = 0; x < context->width; x++)
{
INT16 y_val = (INT16)*yplane;
INT16 co_val = (INT16)(INT8)(((INT16)*coplane) << shift);
INT16 cg_val = (INT16)(INT8)(((INT16)*cgplane) << shift);
INT16 r_val = WINPR_ASSERTING_INT_CAST(int16_t, y_val + co_val - cg_val);
INT16 g_val = WINPR_ASSERTING_INT_CAST(int16_t, y_val + cg_val);
INT16 b_val = WINPR_ASSERTING_INT_CAST(int16_t, y_val - co_val - cg_val);
if (pos + 4 > context->BitmapDataLength)
return FALSE;
pos += 4;
*bmpdata++ = MINMAX(b_val, 0, 0xFF);
*bmpdata++ = MINMAX(g_val, 0, 0xFF);
*bmpdata++ = MINMAX(r_val, 0, 0xFF);
*bmpdata++ = *aplane;
yplane++;
coplane += (context->ChromaSubsamplingLevel ? x % 2 : 1);
cgplane += (context->ChromaSubsamplingLevel ? x % 2 : 1);
aplane++;
}
}
return TRUE;
}
static BOOL nsc_rle_decode(const BYTE* WINPR_RESTRICT in, size_t inSize, BYTE* WINPR_RESTRICT out,
UINT32 outSize, UINT32 originalSize)
{
UINT32 left = originalSize;
while (left > 4)
{
if (inSize < 1)
return FALSE;
inSize--;
const BYTE value = *in++;
UINT32 len = 0;
if (left == 5)
{
if (outSize < 1)
return FALSE;
outSize--;
*out++ = value;
left--;
}
else if (inSize < 1)
return FALSE;
else if (value == *in)
{
inSize--;
in++;
if (inSize < 1)
return FALSE;
else if (*in < 0xFF)
{
inSize--;
len = (UINT32)*in++;
len += 2;
}
else
{
if (inSize < 5)
return FALSE;
inSize -= 5;
in++;
len = ((UINT32)(*in++));
len |= ((UINT32)(*in++)) << 8U;
len |= ((UINT32)(*in++)) << 16U;
len |= ((UINT32)(*in++)) << 24U;
}
if ((outSize < len) || (left < len))
return FALSE;
outSize -= len;
FillMemory(out, len, value);
out += len;
left -= len;
}
else
{
if (outSize < 1)
return FALSE;
outSize--;
*out++ = value;
left--;
}
}
if ((outSize < 4) || (left < 4))
return FALSE;
if (inSize < 4)
return FALSE;
memcpy(out, in, 4);
return TRUE;
}
static BOOL nsc_rle_decompress_data(NSC_CONTEXT* WINPR_RESTRICT context)
{
if (!context)
return FALSE;
const BYTE* rle = context->Planes;
size_t rleSize = context->PlanesSize;
WINPR_ASSERT(rle);
for (size_t i = 0; i < 4; i++)
{
const UINT32 originalSize = context->OrgByteCount[i];
const UINT32 planeSize = context->PlaneByteCount[i];
if (rleSize < planeSize)
return FALSE;
if (planeSize == 0)
{
if (context->priv->PlaneBuffersLength < originalSize)
return FALSE;
FillMemory(context->priv->PlaneBuffers[i], originalSize, 0xFF);
}
else if (planeSize < originalSize)
{
if (!nsc_rle_decode(rle, rleSize, context->priv->PlaneBuffers[i],
context->priv->PlaneBuffersLength, originalSize))
return FALSE;
}
else
{
if (context->priv->PlaneBuffersLength < originalSize)
return FALSE;
if (rleSize < originalSize)
return FALSE;
CopyMemory(context->priv->PlaneBuffers[i], rle, originalSize);
}
rle += planeSize;
rleSize -= planeSize;
}
return TRUE;
}
static BOOL nsc_stream_initialize(NSC_CONTEXT* WINPR_RESTRICT context, wStream* WINPR_RESTRICT s)
{
WINPR_ASSERT(context);
WINPR_ASSERT(context->priv);
if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 20))
return FALSE;
size_t total = 0;
for (size_t i = 0; i < 4; i++)
{
Stream_Read_UINT32(s, context->PlaneByteCount[i]);
total += context->PlaneByteCount[i];
}
Stream_Read_UINT8(s, context->ColorLossLevel); /* ColorLossLevel (1 byte) */
if ((context->ColorLossLevel < 1) || (context->ColorLossLevel > 7))
{
WLog_Print(context->priv->log, WLOG_ERROR,
"ColorLossLevel=%" PRIu8 " out of range, must be [1,7] inclusive",
context->ColorLossLevel);
return FALSE;
}
Stream_Read_UINT8(s, context->ChromaSubsamplingLevel); /* ChromaSubsamplingLevel (1 byte) */
Stream_Seek(s, 2); /* Reserved (2 bytes) */
context->Planes = Stream_Pointer(s);
context->PlanesSize = total;
return Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, total);
}
static BOOL nsc_context_initialize(NSC_CONTEXT* WINPR_RESTRICT context, wStream* WINPR_RESTRICT s)
{
if (!nsc_stream_initialize(context, s))
return FALSE;
const size_t blength = 4ull * context->width * context->height;
if (!context->BitmapData || (blength > context->BitmapDataLength))
{
void* tmp = winpr_aligned_recalloc(context->BitmapData, blength + 16, sizeof(BYTE), 32);
if (!tmp)
return FALSE;
context->BitmapData = tmp;
context->BitmapDataLength = blength;
}
const UINT32 tempWidth = ROUND_UP_TO(context->width, 8);
const UINT32 tempHeight = ROUND_UP_TO(context->height, 2);
/* The maximum length a decoded plane can reach in all cases */
const size_t plength = 1ull * tempWidth * tempHeight;
if (plength > UINT32_MAX)
return FALSE;
if (plength > context->priv->PlaneBuffersLength)
{
for (size_t i = 0; i < 4; i++)
{
void* tmp = (BYTE*)winpr_aligned_recalloc(context->priv->PlaneBuffers[i], plength,
sizeof(BYTE), 32);
if (!tmp)
return FALSE;
context->priv->PlaneBuffers[i] = tmp;
}
context->priv->PlaneBuffersLength = (UINT32)plength;
}
for (size_t i = 0; i < 4; i++)
context->OrgByteCount[i] = context->width * context->height;
if (context->ChromaSubsamplingLevel)
{
context->OrgByteCount[0] = tempWidth * context->height;
context->OrgByteCount[1] = (tempWidth >> 1) * (tempHeight >> 1);
context->OrgByteCount[2] = context->OrgByteCount[1];
}
return TRUE;
}
static void nsc_profiler_print(NSC_CONTEXT_PRIV* WINPR_RESTRICT priv)
{
WINPR_UNUSED(priv);
PROFILER_PRINT_HEADER
PROFILER_PRINT(priv->prof_nsc_rle_decompress_data)
PROFILER_PRINT(priv->prof_nsc_decode)
PROFILER_PRINT(priv->prof_nsc_rle_compress_data)
PROFILER_PRINT(priv->prof_nsc_encode)
PROFILER_PRINT_FOOTER
}
BOOL nsc_context_reset(NSC_CONTEXT* WINPR_RESTRICT context, UINT32 width, UINT32 height)
{
if (!context)
return FALSE;
if ((width > UINT16_MAX) || (height > UINT16_MAX))
return FALSE;
context->width = (UINT16)width;
context->height = (UINT16)height;
return TRUE;
}
NSC_CONTEXT* nsc_context_new(void)
{
NSC_CONTEXT* context = (NSC_CONTEXT*)winpr_aligned_calloc(1, sizeof(NSC_CONTEXT), 32);
if (!context)
return nullptr;
context->priv = (NSC_CONTEXT_PRIV*)winpr_aligned_calloc(1, sizeof(NSC_CONTEXT_PRIV), 32);
if (!context->priv)
goto error;
context->priv->log = WLog_Get("com.freerdp.codec.nsc");
WLog_OpenAppender(context->priv->log);
context->BitmapData = nullptr;
context->decode = nsc_decode;
context->encode = nsc_encode;
PROFILER_CREATE(context->priv->prof_nsc_rle_decompress_data, "nsc_rle_decompress_data")
PROFILER_CREATE(context->priv->prof_nsc_decode, "nsc_decode")
PROFILER_CREATE(context->priv->prof_nsc_rle_compress_data, "nsc_rle_compress_data")
PROFILER_CREATE(context->priv->prof_nsc_encode, "nsc_encode")
/* Default encoding parameters */
context->ColorLossLevel = 3;
context->ChromaSubsamplingLevel = 1;
/* init optimized methods */
nsc_init_sse2(context);
nsc_init_neon(context);
return context;
error:
WINPR_PRAGMA_DIAG_PUSH
WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
nsc_context_free(context);
WINPR_PRAGMA_DIAG_POP
return nullptr;
}
void nsc_context_free(NSC_CONTEXT* context)
{
if (!context)
return;
if (context->priv)
{
for (size_t i = 0; i < 5; i++)
winpr_aligned_free(context->priv->PlaneBuffers[i]);
nsc_profiler_print(context->priv);
PROFILER_FREE(context->priv->prof_nsc_rle_decompress_data)
PROFILER_FREE(context->priv->prof_nsc_decode)
PROFILER_FREE(context->priv->prof_nsc_rle_compress_data)
PROFILER_FREE(context->priv->prof_nsc_encode)
winpr_aligned_free(context->priv);
}
winpr_aligned_free(context->BitmapData);
winpr_aligned_free(context);
}
#if defined(WITH_FREERDP_DEPRECATED)
BOOL nsc_context_set_pixel_format(NSC_CONTEXT* context, UINT32 pixel_format)
{
return nsc_context_set_parameters(context, NSC_COLOR_FORMAT, pixel_format);
}
#endif
BOOL nsc_context_set_parameters(NSC_CONTEXT* WINPR_RESTRICT context, NSC_PARAMETER what,
UINT32 value)
{
if (!context)
return FALSE;
switch (what)
{
case NSC_COLOR_LOSS_LEVEL:
context->ColorLossLevel = value;
break;
case NSC_ALLOW_SUBSAMPLING:
context->ChromaSubsamplingLevel = value;
break;
case NSC_DYNAMIC_COLOR_FIDELITY:
context->DynamicColorFidelity = value != 0;
break;
case NSC_COLOR_FORMAT:
context->format = value;
break;
default:
return FALSE;
}
return TRUE;
}
BOOL nsc_process_message(NSC_CONTEXT* WINPR_RESTRICT context, UINT16 bpp, UINT32 width,
UINT32 height, const BYTE* data, UINT32 length,
BYTE* WINPR_RESTRICT pDstData, UINT32 DstFormat, UINT32 nDstStride,
UINT32 nXDst, UINT32 nYDst, UINT32 nWidth, UINT32 nHeight, UINT32 flip)
{
WINPR_ASSERT(context);
WINPR_ASSERT(context->priv);
wStream sbuffer = WINPR_C_ARRAY_INIT;
BOOL ret = 0;
if (!data || !pDstData)
{
WLog_Print(context->priv->log, WLOG_ERROR, "Invalid argument: data=%p, pDstData=%p",
(const void*)data, (void*)pDstData);
return FALSE;
}
if (nXDst > nWidth)
{
WLog_Print(context->priv->log, WLOG_ERROR, "nXDst %" PRIu32 " > nWidth %" PRIu32, nXDst,
nWidth);
return FALSE;
}
if (nYDst > nHeight)
{
WLog_Print(context->priv->log, WLOG_ERROR, "nYDst %" PRIu32 " > nHeight %" PRIu32, nYDst,
nHeight);
return FALSE;
}
wStream* s = Stream_StaticConstInit(&sbuffer, data, length);
if (!s)
return FALSE;
const UINT32 minStride = nWidth * FreeRDPGetBytesPerPixel(DstFormat);
if (nDstStride == 0)
nDstStride = minStride;
if (nDstStride < minStride)
{
WLog_Print(context->priv->log, WLOG_ERROR,
"nDstStride %" PRIu32 " < minimum stride %" PRIu32, nDstStride, minStride);
return FALSE;
}
switch (bpp)
{
case 32:
context->format = PIXEL_FORMAT_BGRA32;
break;
case 24:
context->format = PIXEL_FORMAT_BGR24;
break;
case 16:
context->format = PIXEL_FORMAT_BGR16;
break;
case 8:
context->format = PIXEL_FORMAT_RGB8;
break;
case 4:
context->format = PIXEL_FORMAT_A4;
break;
default:
return FALSE;
}
context->width = WINPR_ASSERTING_INT_CAST(UINT16, width);
context->height = WINPR_ASSERTING_INT_CAST(UINT16, height);
ret = nsc_context_initialize(context, s);
if (!ret)
return FALSE;
/* RLE decode */
{
BOOL rc = 0;
PROFILER_ENTER(context->priv->prof_nsc_rle_decompress_data)
rc = nsc_rle_decompress_data(context);
PROFILER_EXIT(context->priv->prof_nsc_rle_decompress_data)
if (!rc)
return FALSE;
}
/* Colorloss recover, Chroma supersample and AYCoCg to ARGB Conversion in one step */
{
BOOL rc = 0;
PROFILER_ENTER(context->priv->prof_nsc_decode)
rc = context->decode(context);
PROFILER_EXIT(context->priv->prof_nsc_decode)
if (!rc)
return FALSE;
}
return (freerdp_image_copy_no_overlap(pDstData, DstFormat, nDstStride, nXDst, nYDst, width,
height, context->BitmapData, PIXEL_FORMAT_BGRA32, 0, 0, 0,
nullptr, flip));
}
+518
View File
@@ -0,0 +1,518 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* NSCodec Encoder
*
* Copyright 2012 Vic Lee
* Copyright 2016 Armin Novak <armin.novak@thincast.com>
* Copyright 2016 Thincast Technologies GmbH
*
* 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 <freerdp/config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winpr/assert.h>
#include <winpr/cast.h>
#include <winpr/crt.h>
#include <freerdp/codec/nsc.h>
#include <freerdp/codec/color.h>
#include "nsc_types.h"
#include "nsc_encode.h"
typedef struct
{
UINT32 x;
UINT32 y;
UINT32 width;
UINT32 height;
const BYTE* data;
UINT32 scanline;
BYTE* PlaneBuffer;
UINT32 MaxPlaneSize;
BYTE* PlaneBuffers[5];
UINT32 OrgByteCount[4];
UINT32 LumaPlaneByteCount;
UINT32 OrangeChromaPlaneByteCount;
UINT32 GreenChromaPlaneByteCount;
UINT32 AlphaPlaneByteCount;
UINT8 ColorLossLevel;
UINT8 ChromaSubsamplingLevel;
} NSC_MESSAGE;
static BOOL nsc_write_message(NSC_CONTEXT* WINPR_RESTRICT context, wStream* WINPR_RESTRICT s,
const NSC_MESSAGE* WINPR_RESTRICT message);
static BOOL nsc_context_initialize_encode(NSC_CONTEXT* WINPR_RESTRICT context)
{
UINT32 length = 0;
UINT32 tempWidth = 0;
UINT32 tempHeight = 0;
tempWidth = ROUND_UP_TO(context->width, 8);
tempHeight = ROUND_UP_TO(context->height, 2);
/* The maximum length a decoded plane can reach in all cases */
length = tempWidth * tempHeight + 16;
if (length > context->priv->PlaneBuffersLength)
{
for (int i = 0; i < 5; i++)
{
BYTE* tmp = (BYTE*)winpr_aligned_recalloc(context->priv->PlaneBuffers[i], length,
sizeof(BYTE), 32);
if (!tmp)
goto fail;
context->priv->PlaneBuffers[i] = tmp;
}
context->priv->PlaneBuffersLength = length;
}
if (context->ChromaSubsamplingLevel)
{
context->OrgByteCount[0] = tempWidth * context->height;
context->OrgByteCount[1] = tempWidth * tempHeight / 4;
context->OrgByteCount[2] = tempWidth * tempHeight / 4;
context->OrgByteCount[3] = context->width * context->height;
}
else
{
context->OrgByteCount[0] = context->width * context->height;
context->OrgByteCount[1] = context->width * context->height;
context->OrgByteCount[2] = context->width * context->height;
context->OrgByteCount[3] = context->width * context->height;
}
return TRUE;
fail:
if (length > context->priv->PlaneBuffersLength)
{
for (int i = 0; i < 5; i++)
winpr_aligned_free(context->priv->PlaneBuffers[i]);
}
return FALSE;
}
static BOOL nsc_encode_argb_to_aycocg(NSC_CONTEXT* WINPR_RESTRICT context,
const BYTE* WINPR_RESTRICT data, UINT32 scanline)
{
size_t y = 0;
const BYTE* src = nullptr;
BYTE* yplane = nullptr;
BYTE* coplane = nullptr;
BYTE* cgplane = nullptr;
BYTE* aplane = nullptr;
INT16 r_val = 0;
INT16 g_val = 0;
INT16 b_val = 0;
BYTE a_val = 0;
UINT16 tempWidth = ROUND_UP_TO(context->width, 8);
const UINT16 rw = (context->ChromaSubsamplingLevel ? tempWidth : context->width);
const BYTE ccl = WINPR_ASSERTING_INT_CAST(BYTE, context->ColorLossLevel);
for (; y < context->height; y++)
{
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;
aplane = context->priv->PlaneBuffers[3] + y * context->width;
UINT16 x = 0;
for (; x < context->width; x++)
{
switch (context->format)
{
case PIXEL_FORMAT_BGRX32:
b_val = *src++;
g_val = *src++;
r_val = *src++;
src++;
a_val = 0xFF;
break;
case PIXEL_FORMAT_BGRA32:
b_val = *src++;
g_val = *src++;
r_val = *src++;
a_val = *src++;
break;
case PIXEL_FORMAT_RGBX32:
r_val = *src++;
g_val = *src++;
b_val = *src++;
src++;
a_val = 0xFF;
break;
case PIXEL_FORMAT_RGBA32:
r_val = *src++;
g_val = *src++;
b_val = *src++;
a_val = *src++;
break;
case PIXEL_FORMAT_BGR24:
b_val = *src++;
g_val = *src++;
r_val = *src++;
a_val = 0xFF;
break;
case PIXEL_FORMAT_RGB24:
r_val = *src++;
g_val = *src++;
b_val = *src++;
a_val = 0xFF;
break;
case PIXEL_FORMAT_BGR16:
b_val = (INT16)(((*(src + 1)) & 0xF8) | ((*(src + 1)) >> 5));
g_val = (INT16)((((*(src + 1)) & 0x07) << 5) | (((*src) & 0xE0) >> 3));
r_val = (INT16)((((*src) & 0x1F) << 3) | (((*src) >> 2) & 0x07));
a_val = 0xFF;
src += 2;
break;
case PIXEL_FORMAT_RGB16:
r_val = (INT16)(((*(src + 1)) & 0xF8) | ((*(src + 1)) >> 5));
g_val = (INT16)((((*(src + 1)) & 0x07) << 5) | (((*src) & 0xE0) >> 3));
b_val = (INT16)((((*src) & 0x1F) << 3) | (((*src) >> 2) & 0x07));
a_val = 0xFF;
src += 2;
break;
case PIXEL_FORMAT_A4:
{
int shift = 0;
BYTE idx = 0;
shift = (7 - (x % 8));
idx = ((*src) >> shift) & 1;
idx |= (((*(src + 1)) >> shift) & 1) << 1;
idx |= (((*(src + 2)) >> shift) & 1) << 2;
idx |= (((*(src + 3)) >> shift) & 1) << 3;
idx *= 3;
r_val = (INT16)context->palette[idx];
g_val = (INT16)context->palette[idx + 1];
b_val = (INT16)context->palette[idx + 2];
if (shift == 0)
src += 4;
}
a_val = 0xFF;
break;
case PIXEL_FORMAT_RGB8:
{
int idx = (*src) * 3;
r_val = (INT16)context->palette[idx];
g_val = (INT16)context->palette[idx + 1];
b_val = (INT16)context->palette[idx + 2];
src++;
}
a_val = 0xFF;
break;
default:
r_val = g_val = b_val = a_val = 0;
break;
}
*yplane++ = (BYTE)((r_val >> 2) + (g_val >> 1) + (b_val >> 2));
/* Perform color loss reduction here */
*coplane++ = (BYTE)((r_val - b_val) >> ccl);
*cgplane++ = (BYTE)((-(r_val >> 1) + g_val - (b_val >> 1)) >> ccl);
*aplane++ = a_val;
}
if (context->ChromaSubsamplingLevel && (x % 2) == 1)
{
*yplane = *(yplane - 1);
*coplane = *(coplane - 1);
*cgplane = *(cgplane - 1);
}
}
if (context->ChromaSubsamplingLevel && (y % 2) == 1)
{
yplane = context->priv->PlaneBuffers[0] + y * rw;
coplane = context->priv->PlaneBuffers[1] + y * rw;
cgplane = context->priv->PlaneBuffers[2] + y * rw;
CopyMemory(yplane, yplane - rw, rw);
CopyMemory(coplane, coplane - rw, rw);
CopyMemory(cgplane, cgplane - rw, rw);
}
return TRUE;
}
static BOOL nsc_encode_subsampling(NSC_CONTEXT* WINPR_RESTRICT context)
{
UINT32 tempWidth = 0;
UINT32 tempHeight = 0;
if (!context)
return FALSE;
tempWidth = ROUND_UP_TO(context->width, 8);
tempHeight = ROUND_UP_TO(context->height, 2);
if (tempHeight == 0)
return FALSE;
if (tempWidth > context->priv->PlaneBuffersLength / tempHeight)
return FALSE;
for (size_t y = 0; y < tempHeight >> 1; y++)
{
BYTE* co_dst = context->priv->PlaneBuffers[1] + y * (tempWidth >> 1);
BYTE* cg_dst = context->priv->PlaneBuffers[2] + y * (tempWidth >> 1);
const INT8* co_src0 = (INT8*)context->priv->PlaneBuffers[1] + (y << 1) * tempWidth;
const INT8* co_src1 = co_src0 + tempWidth;
const INT8* cg_src0 = (INT8*)context->priv->PlaneBuffers[2] + (y << 1) * tempWidth;
const INT8* cg_src1 = cg_src0 + tempWidth;
for (UINT32 x = 0; x < tempWidth >> 1; x++)
{
*co_dst++ = (BYTE)(((INT16)*co_src0 + (INT16) * (co_src0 + 1) + (INT16)*co_src1 +
(INT16) * (co_src1 + 1)) >>
2);
*cg_dst++ = (BYTE)(((INT16)*cg_src0 + (INT16) * (cg_src0 + 1) + (INT16)*cg_src1 +
(INT16) * (cg_src1 + 1)) >>
2);
co_src0 += 2;
co_src1 += 2;
cg_src0 += 2;
cg_src1 += 2;
}
}
return TRUE;
}
BOOL nsc_encode(NSC_CONTEXT* WINPR_RESTRICT context, const BYTE* WINPR_RESTRICT bmpdata,
UINT32 rowstride)
{
if (!context || !bmpdata || (rowstride == 0))
return FALSE;
if (!nsc_encode_argb_to_aycocg(context, bmpdata, rowstride))
return FALSE;
if (context->ChromaSubsamplingLevel)
{
if (!nsc_encode_subsampling(context))
return FALSE;
}
return TRUE;
}
static UINT32 nsc_rle_encode(const BYTE* WINPR_RESTRICT in, BYTE* WINPR_RESTRICT out,
UINT32 originalSize)
{
UINT32 left = 0;
UINT32 runlength = 1;
UINT32 planeSize = 0;
left = originalSize;
/**
* We quit the loop if the running compressed size is larger than the original.
* In such cases data will be sent uncompressed.
*/
while (left > 4 && planeSize < originalSize - 4)
{
if (left > 5 && *in == *(in + 1))
{
runlength++;
}
else if (runlength == 1)
{
*out++ = *in;
planeSize++;
}
else if (runlength < 256)
{
*out++ = *in;
*out++ = *in;
WINPR_ASSERT(runlength >= 2);
*out++ = WINPR_ASSERTING_INT_CAST(BYTE, runlength - 2);
runlength = 1;
planeSize += 3;
}
else
{
*out++ = *in;
*out++ = *in;
*out++ = 0xFF;
*out++ = (runlength & 0x000000FF);
*out++ = (runlength & 0x0000FF00) >> 8;
*out++ = (runlength & 0x00FF0000) >> 16;
*out++ = (runlength & 0xFF000000) >> 24;
runlength = 1;
planeSize += 7;
}
in++;
left--;
}
if (planeSize < originalSize - 4)
CopyMemory(out, in, 4);
planeSize += 4;
return planeSize;
}
static void nsc_rle_compress_data(NSC_CONTEXT* WINPR_RESTRICT context)
{
UINT32 planeSize = 0;
UINT32 originalSize = 0;
for (UINT16 i = 0; i < 4; i++)
{
originalSize = context->OrgByteCount[i];
if (originalSize == 0)
{
planeSize = 0;
}
else
{
planeSize = nsc_rle_encode(context->priv->PlaneBuffers[i],
context->priv->PlaneBuffers[4], originalSize);
if (planeSize < originalSize)
CopyMemory(context->priv->PlaneBuffers[i], context->priv->PlaneBuffers[4],
planeSize);
else
planeSize = originalSize;
}
context->PlaneByteCount[i] = planeSize;
}
}
BOOL nsc_write_message(WINPR_ATTR_UNUSED NSC_CONTEXT* WINPR_RESTRICT context,
wStream* WINPR_RESTRICT s, const NSC_MESSAGE* WINPR_RESTRICT message)
{
UINT32 totalPlaneByteCount = 0;
totalPlaneByteCount = message->LumaPlaneByteCount + message->OrangeChromaPlaneByteCount +
message->GreenChromaPlaneByteCount + message->AlphaPlaneByteCount;
if (!Stream_EnsureRemainingCapacity(s, 20 + totalPlaneByteCount))
return FALSE;
Stream_Write_UINT32(s, message->LumaPlaneByteCount); /* LumaPlaneByteCount (4 bytes) */
Stream_Write_UINT32(
s, message->OrangeChromaPlaneByteCount); /* OrangeChromaPlaneByteCount (4 bytes) */
Stream_Write_UINT32(
s, message->GreenChromaPlaneByteCount); /* GreenChromaPlaneByteCount (4 bytes) */
Stream_Write_UINT32(s, message->AlphaPlaneByteCount); /* AlphaPlaneByteCount (4 bytes) */
Stream_Write_UINT8(s, message->ColorLossLevel); /* ColorLossLevel (1 byte) */
Stream_Write_UINT8(s, message->ChromaSubsamplingLevel); /* ChromaSubsamplingLevel (1 byte) */
Stream_Write_UINT16(s, 0); /* Reserved (2 bytes) */
if (message->LumaPlaneByteCount)
Stream_Write(s, message->PlaneBuffers[0], message->LumaPlaneByteCount); /* LumaPlane */
if (message->OrangeChromaPlaneByteCount)
Stream_Write(s, message->PlaneBuffers[1],
message->OrangeChromaPlaneByteCount); /* OrangeChromaPlane */
if (message->GreenChromaPlaneByteCount)
Stream_Write(s, message->PlaneBuffers[2],
message->GreenChromaPlaneByteCount); /* GreenChromaPlane */
if (message->AlphaPlaneByteCount)
Stream_Write(s, message->PlaneBuffers[3], message->AlphaPlaneByteCount); /* AlphaPlane */
return TRUE;
}
BOOL nsc_compose_message(NSC_CONTEXT* WINPR_RESTRICT context, wStream* WINPR_RESTRICT s,
const BYTE* WINPR_RESTRICT data, UINT32 width, UINT32 height,
UINT32 scanline)
{
BOOL rc = 0;
NSC_MESSAGE message = WINPR_C_ARRAY_INIT;
if (!context || !s || !data)
return FALSE;
if (scanline == 0)
scanline = width * FreeRDPGetBytesPerPixel(context->format);
context->width = WINPR_ASSERTING_INT_CAST(UINT16, width);
context->height = WINPR_ASSERTING_INT_CAST(UINT16, height);
if (!nsc_context_initialize_encode(context))
return FALSE;
/* ARGB to AYCoCg conversion, chroma subsampling and colorloss reduction */
PROFILER_ENTER(context->priv->prof_nsc_encode)
rc = context->encode(context, data, scanline);
PROFILER_EXIT(context->priv->prof_nsc_encode)
if (!rc)
return FALSE;
/* RLE encode */
PROFILER_ENTER(context->priv->prof_nsc_rle_compress_data)
nsc_rle_compress_data(context);
PROFILER_EXIT(context->priv->prof_nsc_rle_compress_data)
message.PlaneBuffers[0] = context->priv->PlaneBuffers[0];
message.PlaneBuffers[1] = context->priv->PlaneBuffers[1];
message.PlaneBuffers[2] = context->priv->PlaneBuffers[2];
message.PlaneBuffers[3] = context->priv->PlaneBuffers[3];
message.LumaPlaneByteCount = context->PlaneByteCount[0];
message.OrangeChromaPlaneByteCount = context->PlaneByteCount[1];
message.GreenChromaPlaneByteCount = context->PlaneByteCount[2];
message.AlphaPlaneByteCount = context->PlaneByteCount[3];
message.ColorLossLevel = WINPR_ASSERTING_INT_CAST(BYTE, context->ColorLossLevel);
message.ChromaSubsamplingLevel =
WINPR_ASSERTING_INT_CAST(BYTE, context->ChromaSubsamplingLevel);
return nsc_write_message(context, s, &message);
}
#if !defined(WITHOUT_FREERDP_3x_DEPRECATED)
BOOL nsc_decompose_message(NSC_CONTEXT* WINPR_RESTRICT context, wStream* WINPR_RESTRICT s,
BYTE* WINPR_RESTRICT bmpdata, UINT32 x, UINT32 y, UINT32 width,
UINT32 height, UINT32 rowstride, UINT32 format, UINT32 flip)
{
size_t size = Stream_GetRemainingLength(s);
if (size > UINT32_MAX)
return FALSE;
if (!nsc_process_message(context, (UINT16)FreeRDPGetBitsPerPixel(context->format), width,
height, Stream_Pointer(s), (UINT32)size, bmpdata, format, rowstride, x,
y, width, height, flip))
return FALSE;
Stream_Seek(s, size);
return TRUE;
}
#endif
+33
View File
@@ -0,0 +1,33 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* NSCodec Encoder
*
* Copyright 2012 Vic Lee
* Copyright 2016 Armin Novak <armin.novak@thincast.com>
* Copyright 2016 Thincast Technologies GmbH
*
* 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 FREERDP_LIB_CODEC_NSC_ENCODE_H
#define FREERDP_LIB_CODEC_NSC_ENCODE_H
#include <winpr/wtypes.h>
#include <freerdp/api.h>
#include <freerdp/codec/nsc.h>
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL nsc_encode(NSC_CONTEXT* WINPR_RESTRICT context,
const BYTE* WINPR_RESTRICT bmpdata, UINT32 rowstride);
#endif /* FREERDP_LIB_CODEC_NSC_ENCODE_H */
+81
View File
@@ -0,0 +1,81 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* NSCodec Library
*
* Copyright 2011 Samsung, Author Jiten Pathy
* Copyright 2012 Vic Lee
*
* 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 FREERDP_LIB_CODEC_NSC_TYPES_H
#define FREERDP_LIB_CODEC_NSC_TYPES_H
#include <freerdp/config.h>
#include <winpr/assert.h>
#include <winpr/cast.h>
#include <winpr/crt.h>
#include <winpr/wlog.h>
#include <winpr/collections.h>
#include <freerdp/utils/profiler.h>
#include <freerdp/codec/nsc.h>
#define ROUND_UP_TO(_b, _n) (_b + ((~(_b & (_n - 1)) + 0x1) & (_n - 1)))
#define MINMAX(_v, _l, _h) \
((_v) < (_l) ? WINPR_ASSERTING_INT_CAST(BYTE, (_l)) \
: ((_v) > (_h) ? WINPR_ASSERTING_INT_CAST(BYTE, (_h)) \
: WINPR_ASSERTING_INT_CAST(BYTE, (_v))))
typedef struct
{
wLog* log;
BYTE* PlaneBuffers[5]; /* Decompressed Plane Buffers in the respective order */
UINT32 PlaneBuffersLength; /* Lengths of each plane buffer */
/* profilers */
PROFILER_DEFINE(prof_nsc_rle_decompress_data)
PROFILER_DEFINE(prof_nsc_decode)
PROFILER_DEFINE(prof_nsc_rle_compress_data)
PROFILER_DEFINE(prof_nsc_encode)
} NSC_CONTEXT_PRIV;
struct S_NSC_CONTEXT
{
UINT32 OrgByteCount[4];
UINT32 format;
UINT16 width;
UINT16 height;
BYTE* BitmapData;
size_t BitmapDataLength;
BYTE* Planes;
size_t PlanesSize;
UINT32 PlaneByteCount[4];
UINT32 ColorLossLevel;
UINT32 ChromaSubsamplingLevel;
BOOL DynamicColorFidelity;
/* color palette allocated by the application */
const BYTE* palette;
WINPR_ATTR_NODISCARD BOOL (*decode)(NSC_CONTEXT* WINPR_RESTRICT context);
WINPR_ATTR_NODISCARD BOOL (*encode)(NSC_CONTEXT* WINPR_RESTRICT context,
const BYTE* WINPR_RESTRICT BitmapData, UINT32 rowstride);
NSC_CONTEXT_PRIV* priv;
};
#endif /* FREERDP_LIB_CODEC_NSC_TYPES_H */
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+235
View File
@@ -0,0 +1,235 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Progressive Codec Bitmap Compression
*
* Copyright 2017 Armin Novak <anovak@thincast.com>
* Copyright 2017 Thincast Technologies GmbH
*
* 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 INTERNAL_CODEC_PROGRESSIVE_H
#define INTERNAL_CODEC_PROGRESSIVE_H
#include <winpr/wlog.h>
#include <winpr/pool.h>
#include <winpr/collections.h>
#include <freerdp/codec/rfx.h>
#define RFX_SUBBAND_DIFFING 0x01
#define RFX_TILE_DIFFERENCE 0x01
#define RFX_DWT_REDUCE_EXTRAPOLATE 0x01
typedef struct
{
BYTE LL3;
BYTE HL3;
BYTE LH3;
BYTE HH3;
BYTE HL2;
BYTE LH2;
BYTE HH2;
BYTE HL1;
BYTE LH1;
BYTE HH1;
} RFX_COMPONENT_CODEC_QUANT;
typedef struct
{
BYTE quality;
RFX_COMPONENT_CODEC_QUANT yQuantValues;
RFX_COMPONENT_CODEC_QUANT cbQuantValues;
RFX_COMPONENT_CODEC_QUANT crQuantValues;
} RFX_PROGRESSIVE_CODEC_QUANT;
typedef struct
{
UINT16 blockType;
UINT32 blockLen;
} PROGRESSIVE_BLOCK;
typedef struct
{
UINT16 blockType;
UINT32 blockLen;
UINT32 magic;
UINT16 version;
} PROGRESSIVE_BLOCK_SYNC;
typedef struct
{
UINT16 blockType;
UINT32 blockLen;
BYTE ctxId;
UINT16 tileSize;
BYTE flags;
} PROGRESSIVE_BLOCK_CONTEXT;
typedef struct
{
UINT16 blockType;
UINT32 blockLen;
BYTE quantIdxY;
BYTE quantIdxCb;
BYTE quantIdxCr;
UINT16 xIdx;
UINT16 yIdx;
BYTE flags;
BYTE quality;
BOOL dirty;
UINT16 yLen;
UINT16 cbLen;
UINT16 crLen;
UINT16 tailLen;
const BYTE* yData;
const BYTE* cbData;
const BYTE* crData;
const BYTE* tailData;
UINT16 ySrlLen;
UINT16 yRawLen;
UINT16 cbSrlLen;
UINT16 cbRawLen;
UINT16 crSrlLen;
UINT16 crRawLen;
const BYTE* ySrlData;
const BYTE* yRawData;
const BYTE* cbSrlData;
const BYTE* cbRawData;
const BYTE* crSrlData;
const BYTE* crRawData;
UINT32 x;
UINT32 y;
UINT32 width;
UINT32 height;
UINT32 stride;
BYTE* data;
BYTE* current;
UINT16 pass;
BYTE* sign;
RFX_COMPONENT_CODEC_QUANT yBitPos;
RFX_COMPONENT_CODEC_QUANT cbBitPos;
RFX_COMPONENT_CODEC_QUANT crBitPos;
RFX_COMPONENT_CODEC_QUANT yQuant;
RFX_COMPONENT_CODEC_QUANT cbQuant;
RFX_COMPONENT_CODEC_QUANT crQuant;
RFX_COMPONENT_CODEC_QUANT yProgQuant;
RFX_COMPONENT_CODEC_QUANT cbProgQuant;
RFX_COMPONENT_CODEC_QUANT crProgQuant;
} RFX_PROGRESSIVE_TILE;
typedef struct S_PROGRESSIVE_CONTEXT PROGRESSIVE_CONTEXT;
typedef struct S_PROGRESSIVE_BLOCK_REGION PROGRESSIVE_BLOCK_REGION;
typedef struct
{
PROGRESSIVE_CONTEXT* progressive;
PROGRESSIVE_BLOCK_REGION* region;
const PROGRESSIVE_BLOCK_CONTEXT* context;
RFX_PROGRESSIVE_TILE* tile;
} PROGRESSIVE_TILE_PROCESS_WORK_PARAM;
struct S_PROGRESSIVE_BLOCK_REGION
{
UINT16 blockType;
UINT32 blockLen;
BYTE tileSize;
UINT16 numRects;
BYTE numQuant;
BYTE numProgQuant;
BYTE flags;
UINT16 numTiles;
UINT16 usedTiles;
UINT32 tileDataSize;
RFX_RECT rects[0x10000];
RFX_COMPONENT_CODEC_QUANT quantVals[0x100];
RFX_PROGRESSIVE_CODEC_QUANT quantProgVals[0x100];
RFX_PROGRESSIVE_TILE* tiles[0x10000];
};
typedef struct
{
UINT16 blockType;
UINT32 blockLen;
UINT32 frameIndex;
UINT16 regionCount;
PROGRESSIVE_BLOCK_REGION* regions;
} PROGRESSIVE_BLOCK_FRAME_BEGIN;
typedef struct
{
UINT16 blockType;
UINT32 blockLen;
} PROGRESSIVE_BLOCK_FRAME_END;
typedef struct
{
UINT16 id;
UINT32 width;
UINT32 height;
UINT32 gridWidth;
UINT32 gridHeight;
UINT32 gridSize;
RFX_PROGRESSIVE_TILE** tiles;
size_t tilesSize;
UINT32 frameId;
UINT32 numUpdatedTiles;
UINT32* updatedTileIndices;
} PROGRESSIVE_SURFACE_CONTEXT;
typedef enum
{
FLAG_WBT_SYNC = 0x01,
FLAG_WBT_FRAME_BEGIN = 0x02,
FLAG_WBT_FRAME_END = 0x04,
FLAG_WBT_CONTEXT = 0x08,
FLAG_WBT_REGION = 0x10
} WBT_STATE_FLAG;
struct S_PROGRESSIVE_CONTEXT
{
BOOL Compressor;
wBufferPool* bufferPool;
UINT32 format;
UINT32 state;
PROGRESSIVE_BLOCK_CONTEXT context;
PROGRESSIVE_BLOCK_REGION region;
RFX_PROGRESSIVE_CODEC_QUANT quantProgValFull;
wHashTable* SurfaceContexts;
wLog* log;
wStream* buffer;
wStream* rects;
RFX_CONTEXT* rfx_context;
PROGRESSIVE_TILE_PROCESS_WORK_PARAM params[0x10000];
PTP_WORK work_objects[0x10000];
};
#endif /* INTERNAL_CODEC_PROGRESSIVE_H */
+885
View File
@@ -0,0 +1,885 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
*
* Copyright 2014 Thincast Technologies GmbH
* Copyright 2014 Hardening <contact@hardening-consulting.com>
* Copyright 2017 Armin Novak <armin.novak@thincast.com>
* Copyright 2017 Thincast Technologies GmbH
*
* 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 <winpr/assert.h>
#include <winpr/memory.h>
#include <freerdp/log.h>
#include <freerdp/codec/region.h>
#define TAG FREERDP_TAG("codec")
/*
* The functions in this file implement the Region abstraction largely inspired from
* pixman library. The following comment is taken from the pixman code.
*
* A Region is simply a set of disjoint(non-overlapping) rectangles, plus an
* "extent" rectangle which is the smallest single rectangle that contains all
* the non-overlapping rectangles.
*
* A Region is implemented as a "y-x-banded" array of rectangles. This array
* imposes two degrees of order. First, all rectangles are sorted by top side
* y coordinate first (y1), and then by left side x coordinate (x1).
*
* Furthermore, the rectangles are grouped into "bands". Each rectangle in a
* band has the same top y coordinate (y1), and each has the same bottom y
* coordinate (y2). Thus all rectangles in a band differ only in their left
* and right side (x1 and x2). Bands are implicit in the array of rectangles:
* there is no separate list of band start pointers.
*
* The y-x band representation does not minimize rectangles. In particular,
* if a rectangle vertically crosses a band (the rectangle has scanlines in
* the y1 to y2 area spanned by the band), then the rectangle may be broken
* down into two or more smaller rectangles stacked one atop the other.
*
* ----------- -----------
* | | | | band 0
* | | -------- ----------- --------
* | | | | in y-x banded | | | | band 1
* | | | | form is | | | |
* ----------- | | ----------- --------
* | | | | band 2
* -------- --------
*
* An added constraint on the rectangles is that they must cover as much
* horizontal area as possible: no two rectangles within a band are allowed
* to touch.
*
* Whenever possible, bands will be merged together to cover a greater vertical
* distance (and thus reduce the number of rectangles). Two bands can be merged
* only if the bottom of one touches the top of the other and they have
* rectangles in the same places (of the same width, of course).
*/
struct S_REGION16_DATA
{
size_t nbRects;
RECTANGLE_16* rects;
};
void region16_init(REGION16* region)
{
WINPR_ASSERT(region);
const REGION16 empty = WINPR_C_ARRAY_INIT;
*region = empty;
}
int region16_n_rects(const REGION16* region)
{
WINPR_ASSERT(region);
if (!region->data)
return 0;
return WINPR_ASSERTING_INT_CAST(int, region->data->nbRects);
}
const RECTANGLE_16* region16_rects(const REGION16* region, UINT32* nbRects)
{
if (nbRects)
*nbRects = 0;
if (!region)
return nullptr;
REGION16_DATA* data = region->data;
if (!data)
return nullptr;
if (nbRects)
*nbRects = WINPR_ASSERTING_INT_CAST(UINT32, data->nbRects);
return data->rects;
}
static inline RECTANGLE_16* region16_rects_noconst(REGION16* region)
{
WINPR_ASSERT(region);
REGION16_DATA* data = region->data;
if (!data)
return nullptr;
return data->rects;
}
const RECTANGLE_16* region16_extents(const REGION16* region)
{
if (!region)
return nullptr;
return &region->extents;
}
static RECTANGLE_16* region16_extents_noconst(REGION16* region)
{
if (!region)
return nullptr;
return &region->extents;
}
BOOL rectangle_is_empty(const RECTANGLE_16* rect)
{
WINPR_ASSERT(rect);
/* A rectangle with width <= 0 or height <= 0 should be regarded
* as empty.
*/
return ((rect->left >= rect->right) || (rect->top >= rect->bottom));
}
BOOL region16_is_empty(const REGION16* region)
{
WINPR_ASSERT(region);
if (!region->data)
return TRUE;
return (region->data->nbRects == 0);
}
BOOL rectangles_equal(const RECTANGLE_16* r1, const RECTANGLE_16* r2)
{
WINPR_ASSERT(r1);
WINPR_ASSERT(r2);
return ((r1->left == r2->left) && (r1->top == r2->top) && (r1->right == r2->right) &&
(r1->bottom == r2->bottom));
}
BOOL rectangles_intersects(const RECTANGLE_16* r1, const RECTANGLE_16* r2)
{
RECTANGLE_16 tmp = WINPR_C_ARRAY_INIT;
return rectangles_intersection(r1, r2, &tmp);
}
BOOL rectangles_intersection(const RECTANGLE_16* r1, const RECTANGLE_16* r2, RECTANGLE_16* dst)
{
WINPR_ASSERT(r1);
WINPR_ASSERT(r2);
WINPR_ASSERT(dst);
dst->left = MAX(r1->left, r2->left);
dst->right = MIN(r1->right, r2->right);
dst->top = MAX(r1->top, r2->top);
dst->bottom = MIN(r1->bottom, r2->bottom);
return (dst->left < dst->right) && (dst->top < dst->bottom);
}
static void freeRegion(REGION16_DATA* data)
{
if (data)
free(data->rects);
free(data);
}
void region16_clear(REGION16* region)
{
WINPR_ASSERT(region);
freeRegion(region->data);
region->data = nullptr;
const RECTANGLE_16 empty = WINPR_C_ARRAY_INIT;
region->extents = empty;
}
WINPR_ATTR_MALLOC(freeRegion, 1)
WINPR_ATTR_NODISCARD
static REGION16_DATA* allocateRegion(size_t nbItems)
{
REGION16_DATA* data = calloc(1, sizeof(REGION16_DATA));
if (!data)
return nullptr;
if (nbItems > 0)
{
data->rects = calloc(nbItems, sizeof(RECTANGLE_16));
if (!data->rects)
{
free(data);
return nullptr;
}
}
data->nbRects = nbItems;
return data;
}
static inline RECTANGLE_16* nextRect(REGION16_DATA* data, size_t index)
{
WINPR_ASSERT(data);
if (index + 1 > data->nbRects)
{
RECTANGLE_16* rects = realloc(data->rects, (index + 1) * sizeof(RECTANGLE_16));
if (!rects)
{
freeRegion(data);
return nullptr;
}
const RECTANGLE_16 empty = WINPR_C_ARRAY_INIT;
rects[index] = empty;
data->nbRects = index + 1;
data->rects = rects;
}
return &data->rects[index];
}
static BOOL resizeRegion(REGION16* region, size_t nbItems)
{
WINPR_ASSERT(region);
if (nbItems == 0)
{
freeRegion(region->data);
region->data = nullptr;
return TRUE;
}
if (!region->data)
{
region->data = allocateRegion(nbItems);
return region->data != nullptr;
}
RECTANGLE_16* rects = realloc(region->data->rects, nbItems * sizeof(RECTANGLE_16));
if (!rects)
{
free(region->data->rects);
region->data->nbRects = 0;
region->data->rects = nullptr;
return FALSE;
}
for (size_t x = region->data->nbRects; x < nbItems; x++)
{
const RECTANGLE_16 empty = WINPR_C_ARRAY_INIT;
rects[x] = empty;
}
region->data->rects = rects;
region->data->nbRects = nbItems;
return TRUE;
}
static inline BOOL region16_copy_data(REGION16* dst, const REGION16* src)
{
WINPR_ASSERT(dst);
WINPR_ASSERT(src);
freeRegion(dst->data);
dst->data = nullptr;
if (src->data && (src->data->nbRects > 0))
{
dst->data = allocateRegion(src->data->nbRects);
if (!dst->data || !dst->data->rects)
return FALSE;
memcpy(dst->data->rects, src->data->rects, dst->data->nbRects * sizeof(RECTANGLE_16));
}
return TRUE;
}
BOOL region16_copy(REGION16* dst, const REGION16* src)
{
if (dst == src)
return TRUE;
WINPR_ASSERT(dst);
WINPR_ASSERT(src);
dst->extents = src->extents;
return region16_copy_data(dst, src);
}
void region16_print(const REGION16* region)
{
UINT32 nbRects = 0;
int currentBandY = -1;
const RECTANGLE_16* rects = region16_rects(region, &nbRects);
WLog_DBG(TAG, "nrects=%" PRIu32 "", nbRects);
for (UINT32 i = 0; i < nbRects; i++)
{
const RECTANGLE_16* rect = &rects[i];
if (rect->top != currentBandY)
{
currentBandY = rect->top;
WLog_DBG(TAG, "band %d: ", currentBandY);
}
WLog_DBG(TAG, "(%" PRIu16 ",%" PRIu16 "-%" PRIu16 ",%" PRIu16 ")", rect->left, rect->top,
rect->right, rect->bottom);
}
}
static BOOL region16_copy_band_with_union(REGION16_DATA* region, const RECTANGLE_16* src,
const RECTANGLE_16* end, UINT16 newTop, UINT16 newBottom,
const RECTANGLE_16* unionRect, UINT32* dstCounter,
const RECTANGLE_16** srcPtr)
{
WINPR_ASSERT(region);
WINPR_ASSERT(src);
WINPR_ASSERT(end);
WINPR_ASSERT(dstCounter);
UINT16 refY = src->top;
/* merges a band with the given rect
* Input:
* unionRect
* | |
* | |
* ==============+===============+================================
* |Item1| |Item2| |Item3| |Item4| |Item5| Band
* ==============+===============+================================
* before | overlap | after
*
* Resulting band:
* +-----+ +----------------------+ +-----+
* |Item1| | Item2 | |Item3|
* +-----+ +----------------------+ +-----+
*
* We first copy as-is items that are before Item2, the first overlapping
* item.
* Then we find the last one that overlap unionRect to aggregate Item2, Item3
* and Item4 to create Item2.
* Finally Item5 is copied as Item3.
*
* When no unionRect is provided, we skip the two first steps to just copy items
*/
if (unionRect)
{
/* items before unionRect */
while ((src < end) && (src->top == refY) && (src->right < unionRect->left))
{
RECTANGLE_16* dst = nextRect(region, (*dstCounter)++);
if (!dst)
return FALSE;
dst->top = newTop;
dst->bottom = newBottom;
dst->right = src->right;
dst->left = src->left;
src++;
}
/* treat items overlapping with unionRect */
const RECTANGLE_16* startOverlap = unionRect;
const RECTANGLE_16* endOverlap = unionRect;
if ((src < end) && (src->top == refY) && (src->left < unionRect->left))
startOverlap = src;
while ((src < end) && (src->top == refY) && (src->right < unionRect->right))
{
src++;
}
if ((src < end) && (src->top == refY) && (src->left < unionRect->right))
{
endOverlap = src;
src++;
}
{
RECTANGLE_16* dst = nextRect(region, (*dstCounter)++);
if (!dst)
return FALSE;
dst->bottom = newBottom;
dst->top = newTop;
dst->left = startOverlap->left;
dst->right = endOverlap->right;
}
}
/* treat remaining items on the same band */
while ((src < end) && (src->top == refY))
{
RECTANGLE_16* dst = nextRect(region, (*dstCounter)++);
if (!dst)
return FALSE;
dst->top = newTop;
dst->bottom = newBottom;
dst->right = src->right;
dst->left = src->left;
src++;
}
if (srcPtr)
*srcPtr = src;
return TRUE;
}
static RECTANGLE_16* next_band(RECTANGLE_16* band1, RECTANGLE_16* endPtr, int* nbItems)
{
WINPR_ASSERT(band1);
WINPR_ASSERT(endPtr);
WINPR_ASSERT(nbItems);
UINT16 refY = band1->top;
*nbItems = 0;
while ((band1 < endPtr) && (band1->top == refY))
{
band1++;
*nbItems += 1;
}
return band1;
}
static BOOL band_match(const RECTANGLE_16* band1, const RECTANGLE_16* band2,
const RECTANGLE_16* endPtr)
{
int refBand2 = band2->top;
const RECTANGLE_16* band2Start = band2;
while ((band1 < band2Start) && (band2 < endPtr) && (band2->top == refBand2))
{
if ((band1->left != band2->left) || (band1->right != band2->right))
return FALSE;
band1++;
band2++;
}
if (band1 != band2Start)
return FALSE;
return (band2 == endPtr) || (band2->top != refBand2);
}
/** compute if the rectangle is fully included in the band
* @param band a pointer on the beginning of the band
* @param endPtr end of the region
* @param rect the rectangle to test
* @return if rect is fully included in an item of the band
*/
static BOOL rectangle_contained_in_band(const RECTANGLE_16* band, const RECTANGLE_16* endPtr,
const RECTANGLE_16* rect)
{
WINPR_ASSERT(band);
WINPR_ASSERT(endPtr);
WINPR_ASSERT(rect);
UINT16 refY = band->top;
if ((band->top > rect->top) || (rect->bottom > band->bottom))
return FALSE;
/* note: as the band is sorted from left to right, once we've seen an item
* that is after rect->left we're sure that the result is False.
*/
while ((band < endPtr) && (band->top == refY) && (band->left <= rect->left))
{
if (rect->right <= band->right)
return TRUE;
band++;
}
return FALSE;
}
static BOOL region16_simplify_bands(REGION16* region)
{
/** Simplify consecutive bands that touch and have the same items
*
* ==================== ====================
* | 1 | | 2 | | | | |
* ==================== | | | |
* | 1 | | 2 | ====> | 1 | | 2 |
* ==================== | | | |
* | 1 | | 2 | | | | |
* ==================== ====================
*
*/
const int nbRects = region16_n_rects(region);
int finalNbRects = nbRects;
if (nbRects < 2)
return TRUE;
RECTANGLE_16* band1 = region16_rects_noconst(region);
RECTANGLE_16* endPtr = band1 + nbRects;
do
{
int bandItems = 0;
RECTANGLE_16* band2 = next_band(band1, endPtr, &bandItems);
if (band2 == endPtr)
break;
if ((band1->bottom == band2->top) && band_match(band1, band2, endPtr))
{
/* adjust the bottom of band1 items */
RECTANGLE_16* tmp = band1;
while (tmp < band2)
{
tmp->bottom = band2->bottom;
tmp++;
}
/* override band2, we don't move band1 pointer as the band after band2
* may be merged too */
const RECTANGLE_16* endBand = band2 + bandItems;
const size_t toMove =
WINPR_ASSERTING_INT_CAST(size_t, (endPtr - endBand)) * sizeof(RECTANGLE_16);
if (toMove)
MoveMemory(band2, endBand, toMove);
finalNbRects -= bandItems;
endPtr -= bandItems;
}
else
{
band1 = band2;
}
} while (TRUE);
if (finalNbRects != nbRects)
{
if (!resizeRegion(region, WINPR_ASSERTING_INT_CAST(size_t, finalNbRects)))
return FALSE;
}
return TRUE;
}
BOOL region16_union_rect(REGION16* dst, const REGION16* src, const RECTANGLE_16* rect)
{
const RECTANGLE_16* nextBand = nullptr;
UINT32 srcNbRects = 0;
UINT16 topInterBand = 0;
WINPR_ASSERT(src);
WINPR_ASSERT(dst);
const RECTANGLE_16* srcExtents = region16_extents(src);
RECTANGLE_16* dstExtents = region16_extents_noconst(dst);
const int nrSrcRects = region16_n_rects(src);
if (nrSrcRects == 0)
{
/* source is empty, so the union is rect */
dst->extents = *rect;
if (!resizeRegion(dst, 1))
return FALSE;
RECTANGLE_16* dstRect = region16_rects_noconst(dst);
WINPR_ASSERT(dstRect);
dstRect->top = rect->top;
dstRect->left = rect->left;
dstRect->right = rect->right;
dstRect->bottom = rect->bottom;
dst->data->nbRects = 1;
return TRUE;
}
REGION16_DATA* newItems = allocateRegion(WINPR_ASSERTING_INT_CAST(size_t, nrSrcRects + 1));
if (!newItems)
return FALSE;
UINT32 usedRects = 0;
/* adds the piece of rect that is on the top of src */
if (rect->top < srcExtents->top)
{
RECTANGLE_16* dstRect = nextRect(newItems, usedRects++);
if (!dstRect)
return FALSE;
dstRect->top = rect->top;
dstRect->left = rect->left;
dstRect->right = rect->right;
dstRect->bottom = MIN(srcExtents->top, rect->bottom);
}
/* treat possibly overlapping region */
const RECTANGLE_16* currentBand = region16_rects(src, &srcNbRects);
const RECTANGLE_16* endSrcRect = currentBand + srcNbRects;
while (currentBand < endSrcRect)
{
if ((currentBand->bottom <= rect->top) || (rect->bottom <= currentBand->top) ||
rectangle_contained_in_band(currentBand, endSrcRect, rect))
{
/* no overlap between rect and the band, rect is totally below or totally above
* the current band, or rect is already covered by an item of the band.
* let's copy all the rectangles from this band
+----+
| | rect (case 1)
+----+
=================
band of srcRect
=================
+----+
| | rect (case 2)
+----+
*/
if (!region16_copy_band_with_union(newItems, currentBand, endSrcRect, currentBand->top,
currentBand->bottom, nullptr, &usedRects, &nextBand))
return FALSE;
topInterBand = rect->top;
}
else
{
/* rect overlaps the band:
| | | |
====^=================| |==| |=========================== band
| top split | | | |
v | 1 | | 2 |
^ | | | | +----+ +----+
| merge zone | | | | | | | 4 |
v +----+ | | | | +----+
^ | | | 3 |
| bottom split | | | |
====v=========================| |==| |===================
| | | |
possible cases:
1) no top split, merge zone then a bottom split. The band will be split
in two
2) not band split, only the merge zone, band merged with rect but not split
3) a top split, the merge zone and no bottom split. The band will be split
in two
4) a top split, the merge zone and also a bottom split. The band will be
split in 3, but the coalesce algorithm may merge the created bands
*/
UINT16 mergeTop = currentBand->top;
UINT16 mergeBottom = currentBand->bottom;
/* test if we need a top split, case 3 and 4 */
if (rect->top > currentBand->top)
{
if (!region16_copy_band_with_union(newItems, currentBand, endSrcRect,
currentBand->top, rect->top, nullptr, &usedRects,
&nextBand))
return FALSE;
mergeTop = rect->top;
}
/* do the merge zone (all cases) */
if (rect->bottom < currentBand->bottom)
mergeBottom = rect->bottom;
if (!region16_copy_band_with_union(newItems, currentBand, endSrcRect, mergeTop,
mergeBottom, rect, &usedRects, &nextBand))
return FALSE;
/* test if we need a bottom split, case 1 and 4 */
if (rect->bottom < currentBand->bottom)
{
if (!region16_copy_band_with_union(newItems, currentBand, endSrcRect, mergeBottom,
currentBand->bottom, nullptr, &usedRects,
&nextBand))
return FALSE;
}
topInterBand = currentBand->bottom;
}
/* test if a piece of rect should be inserted as a new band between
* the current band and the next one. band n and n+1 shouldn't touch.
*
* ==============================================================
* band n
* +------+ +------+
* ===========| rect |====================| |===============
* | | +------+ | |
* +------+ | rect | | rect |
* +------+ | |
* =======================================| |================
* +------+ band n+1
* ===============================================================
*
*/
if ((nextBand < endSrcRect) && (nextBand->top != currentBand->bottom) &&
(rect->bottom > currentBand->bottom) && (rect->top < nextBand->top))
{
RECTANGLE_16* dstRect = nextRect(newItems, usedRects++);
if (!dstRect)
return FALSE;
dstRect->right = rect->right;
dstRect->left = rect->left;
dstRect->top = topInterBand;
dstRect->bottom = MIN(nextBand->top, rect->bottom);
}
currentBand = nextBand;
}
/* adds the piece of rect that is below src */
if (srcExtents->bottom < rect->bottom)
{
RECTANGLE_16* dstRect = nextRect(newItems, usedRects++);
if (!dstRect)
return FALSE;
dstRect->top = MAX(srcExtents->bottom, rect->top);
dstRect->left = rect->left;
dstRect->right = rect->right;
dstRect->bottom = rect->bottom;
}
dstExtents->top = MIN(rect->top, srcExtents->top);
dstExtents->left = MIN(rect->left, srcExtents->left);
dstExtents->bottom = MAX(rect->bottom, srcExtents->bottom);
dstExtents->right = MAX(rect->right, srcExtents->right);
newItems->nbRects = usedRects;
freeRegion(dst->data);
dst->data = newItems;
return region16_simplify_bands(dst);
}
BOOL region16_intersects_rect(const REGION16* src, const RECTANGLE_16* arg2)
{
const RECTANGLE_16* endPtr = nullptr;
UINT32 nbRects = 0;
if (!src || !src->data || !arg2)
return FALSE;
const RECTANGLE_16* rect = region16_rects(src, &nbRects);
if (!nbRects)
return FALSE;
const RECTANGLE_16* srcExtents = region16_extents(src);
if (nbRects == 1)
return rectangles_intersects(srcExtents, arg2);
if (!rectangles_intersects(srcExtents, arg2))
return FALSE;
for (endPtr = rect + nbRects; (rect < endPtr) && (arg2->bottom > rect->top); rect++)
{
if (rectangles_intersects(rect, arg2))
return TRUE;
}
return FALSE;
}
BOOL region16_intersect_rect(REGION16* dst, const REGION16* src, const RECTANGLE_16* rect)
{
const RECTANGLE_16* endPtr = nullptr;
UINT32 nbRects = 0;
RECTANGLE_16 common = WINPR_C_ARRAY_INIT;
WINPR_ASSERT(dst);
WINPR_ASSERT(src);
const RECTANGLE_16* srcPtr = region16_rects(src, &nbRects);
if (!nbRects)
{
region16_clear(dst);
return TRUE;
}
const RECTANGLE_16* srcExtents = region16_extents(src);
if (nbRects == 1)
{
BOOL intersects = rectangles_intersection(srcExtents, rect, &common);
region16_clear(dst);
if (intersects)
return region16_union_rect(dst, dst, &common);
return TRUE;
}
REGION16_DATA* newItems = allocateRegion(nbRects);
if (!newItems)
return FALSE;
RECTANGLE_16* dstPtr = newItems->rects;
UINT32 usedRects = 0;
RECTANGLE_16 newExtents = WINPR_C_ARRAY_INIT;
/* accumulate intersecting rectangles, the final region16_simplify_bands() will
* do all the bad job to recreate correct rectangles
*/
for (endPtr = srcPtr + nbRects; (srcPtr < endPtr) && (rect->bottom > srcPtr->top); srcPtr++)
{
if (usedRects > nbRects)
{
freeRegion(newItems);
return FALSE;
}
if (rectangles_intersection(srcPtr, rect, &common))
{
*dstPtr = common;
usedRects++;
dstPtr++;
if (rectangle_is_empty(&newExtents))
{
/* Check if the existing newExtents is empty. If it is empty, use
* new common directly. We do not need to check common rectangle
* because the rectangles_intersection() ensures that it is not empty.
*/
newExtents = common;
}
else
{
newExtents.top = MIN(common.top, newExtents.top);
newExtents.left = MIN(common.left, newExtents.left);
newExtents.bottom = MAX(common.bottom, newExtents.bottom);
newExtents.right = MAX(common.right, newExtents.right);
}
}
}
newItems->nbRects = usedRects;
freeRegion(dst->data);
dst->data = newItems;
dst->extents = newExtents;
return region16_simplify_bands(dst);
}
void region16_uninit(REGION16* region)
{
WINPR_ASSERT(region);
freeRegion(region->data);
region->data = nullptr;
}
File diff suppressed because it is too large Load Diff
+138
View File
@@ -0,0 +1,138 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* RemoteFX Codec Library - Bit Stream
*
* Copyright 2011 Vic Lee
*
* 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 FREERDP_LIB_CODEC_RFX_BITSTREAM_H
#define FREERDP_LIB_CODEC_RFX_BITSTREAM_H
#include <winpr/assert.h>
#include <winpr/cast.h>
#include <freerdp/codec/rfx.h>
#ifdef __cplusplus
extern "C"
{
#endif
typedef struct
{
BYTE* buffer;
uint32_t nbytes;
uint32_t byte_pos;
uint32_t bits_left;
} RFX_BITSTREAM;
static inline void rfx_bitstream_attach(RFX_BITSTREAM* bs, BYTE* WINPR_RESTRICT buffer,
size_t nbytes)
{
WINPR_ASSERT(bs);
bs->buffer = (buffer);
WINPR_ASSERT(nbytes <= UINT32_MAX);
bs->nbytes = WINPR_ASSERTING_INT_CAST(uint32_t, nbytes);
bs->byte_pos = 0;
bs->bits_left = 8;
}
WINPR_ATTR_NODISCARD
static inline uint32_t rfx_bitstream_get_bits(RFX_BITSTREAM* bs, uint32_t nbits)
{
UINT16 n = 0;
while (bs->byte_pos < bs->nbytes && nbits > 0)
{
uint32_t b = nbits;
if (b > bs->bits_left)
b = bs->bits_left;
if (n)
n <<= b;
n |= (bs->buffer[bs->byte_pos] >> (bs->bits_left - b)) & ((1 << b) - 1);
bs->bits_left -= b;
nbits -= b;
if (bs->bits_left == 0)
{
bs->bits_left = 8;
bs->byte_pos++;
}
}
return n;
}
static inline void rfx_bitstream_put_bits(RFX_BITSTREAM* bs, uint32_t _bits, uint32_t _nbits)
{
UINT16 bits = WINPR_ASSERTING_INT_CAST(UINT16, _bits);
uint32_t nbits = (_nbits);
while (bs->byte_pos < bs->nbytes && nbits > 0)
{
uint32_t b = nbits;
if (b > bs->bits_left)
b = bs->bits_left;
bs->buffer[bs->byte_pos] |= ((bits >> (nbits - b)) & ((1 << b) - 1))
<< (bs->bits_left - b);
bs->bits_left -= b;
nbits -= b;
if (bs->bits_left == 0)
{
bs->bits_left = 8;
bs->byte_pos++;
}
}
}
static inline void rfx_bitstream_flush(RFX_BITSTREAM* bs)
{
WINPR_ASSERT(bs);
if (bs->bits_left != 8)
{
uint32_t _nbits = 8 - bs->bits_left;
rfx_bitstream_put_bits(bs, 0, _nbits);
}
}
WINPR_ATTR_NODISCARD
static inline BOOL rfx_bitstream_eos(RFX_BITSTREAM* bs)
{
WINPR_ASSERT(bs);
return ((bs)->byte_pos >= (bs)->nbytes);
}
WINPR_ATTR_NODISCARD
static inline uint32_t rfx_bitstream_left(RFX_BITSTREAM* bs)
{
WINPR_ASSERT(bs);
if ((bs)->byte_pos >= (bs)->nbytes)
return 0;
return ((bs)->nbytes - (bs)->byte_pos - 1) * 8 + (bs)->bits_left;
}
WINPR_ATTR_NODISCARD
static inline uint32_t rfx_bitstream_get_processed_bytes(RFX_BITSTREAM* bs)
{
WINPR_ASSERT(bs);
if ((bs)->bits_left < 8)
return (bs)->byte_pos + 1;
return (bs)->byte_pos;
}
#ifdef __cplusplus
}
#endif
#endif /* FREERDP_LIB_CODEC_RFX_BITSTREAM_H */
+82
View File
@@ -0,0 +1,82 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* RemoteFX Codec Library - API Header
*
* Copyright 2011 Vic Lee
*
* 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 FREERDP_LIB_CODEC_RFX_CONSTANTS_H
#define FREERDP_LIB_CODEC_RFX_CONSTANTS_H
#include <freerdp/api.h>
/* sync */
#define WF_MAGIC 0xCACCACCA
#define WF_VERSION_1_0 0x0100
/* blockType */
#define WBT_SYNC 0xCCC0
#define WBT_CODEC_VERSIONS 0xCCC1
#define WBT_CHANNELS 0xCCC2
#define WBT_CONTEXT 0xCCC3
#define WBT_FRAME_BEGIN 0xCCC4
#define WBT_FRAME_END 0xCCC5
#define WBT_REGION 0xCCC6
#define WBT_EXTENSION 0xCCC7
#define CBT_REGION 0xCAC1
#define CBT_TILESET 0xCAC2
#define CBT_TILE 0xCAC3
#define PROGRESSIVE_WBT_SYNC 0xCCC0
#define PROGRESSIVE_WBT_FRAME_BEGIN 0xCCC1
#define PROGRESSIVE_WBT_FRAME_END 0xCCC2
#define PROGRESSIVE_WBT_CONTEXT 0xCCC3
#define PROGRESSIVE_WBT_REGION 0xCCC4
#define PROGRESSIVE_WBT_TILE_SIMPLE 0xCCC5
#define PROGRESSIVE_WBT_TILE_FIRST 0xCCC6
#define PROGRESSIVE_WBT_TILE_UPGRADE 0xCCC7
/* tileSize */
#define CT_TILE_64x64 0x0040
/* properties.flags */
#define CODEC_MODE 0x02
/* properties.cct */
#define COL_CONV_ICT 0x1
/* properties.xft */
#define CLW_XFORM_DWT_53_A 0x1
/* properties.et */
#define CLW_ENTROPY_RLGR1 0x01
#define CLW_ENTROPY_RLGR3 0x04
/* properties.qt */
#define SCALAR_QUANTIZATION 0x1
#ifdef __cplusplus
extern "C"
{
#endif
WINPR_ATTR_NODISCARD
FREERDP_LOCAL const char* rfx_get_progressive_block_type_string(UINT16 blockType);
#ifdef __cplusplus
}
#endif
#endif /* FREERDP_LIB_CODEC_RFX_CONSTANTS_H */
+111
View File
@@ -0,0 +1,111 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* RemoteFX Codec Library - Decode
*
* Copyright 2011 Vic Lee
* Copyright 2011 Norbert Federa <norbert.federa@thincast.com>
*
* 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 <freerdp/config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winpr/stream.h>
#include <freerdp/primitives.h>
#include "rfx_types.h"
#include "rfx_rlgr.h"
#include "rfx_differential.h"
#include "rfx_quantization.h"
#include "rfx_dwt.h"
#include "rfx_decode.h"
static inline void rfx_decode_component(RFX_CONTEXT* WINPR_RESTRICT context,
const UINT32* WINPR_RESTRICT quantization_values,
const BYTE* WINPR_RESTRICT data, size_t size,
INT16* WINPR_RESTRICT buffer)
{
INT16* dwt_buffer = BufferPool_Take(context->priv->BufferPool, -1); /* dwt_buffer */
WINPR_ASSERT(dwt_buffer);
PROFILER_ENTER(context->priv->prof_rfx_decode_component)
PROFILER_ENTER(context->priv->prof_rfx_rlgr_decode)
WINPR_ASSERT(size <= UINT32_MAX);
{
const int rc = context->rlgr_decode(context->mode, data, (UINT32)size, buffer, 4096);
if (rc < 0)
WLog_Print(context->priv->log, WLOG_ERROR, "context->rlgr_decode failed: %d", rc);
}
PROFILER_EXIT(context->priv->prof_rfx_rlgr_decode)
PROFILER_ENTER(context->priv->prof_rfx_differential_decode)
rfx_differential_decode(buffer + 4032, 64);
PROFILER_EXIT(context->priv->prof_rfx_differential_decode)
PROFILER_ENTER(context->priv->prof_rfx_quantization_decode)
context->quantization_decode(buffer, quantization_values);
PROFILER_EXIT(context->priv->prof_rfx_quantization_decode)
PROFILER_ENTER(context->priv->prof_rfx_dwt_2d_decode)
context->dwt_2d_decode(buffer, dwt_buffer);
PROFILER_EXIT(context->priv->prof_rfx_dwt_2d_decode)
PROFILER_EXIT(context->priv->prof_rfx_decode_component)
BufferPool_Return(context->priv->BufferPool, dwt_buffer);
}
/* rfx_decode_ycbcr_to_rgb code now resides in the primitives library. */
/* stride is bytes between rows in the output buffer. */
BOOL rfx_decode_rgb(RFX_CONTEXT* WINPR_RESTRICT context, const RFX_TILE* WINPR_RESTRICT tile,
BYTE* WINPR_RESTRICT rgb_buffer, UINT32 stride)
{
union
{
const INT16** cpv;
INT16** pv;
} cnv;
BOOL rc = TRUE;
BYTE* pBuffer = nullptr;
INT16* pSrcDst[3];
UINT32* y_quants = nullptr;
UINT32* cb_quants = nullptr;
UINT32* cr_quants = nullptr;
static const prim_size_t roi_64x64 = { 64, 64 };
const primitives_t* prims = primitives_get();
PROFILER_ENTER(context->priv->prof_rfx_decode_rgb)
y_quants = context->quants + (10ULL * tile->quantIdxY);
cb_quants = context->quants + (10ULL * tile->quantIdxCb);
cr_quants = context->quants + (10ULL * tile->quantIdxCr);
pBuffer = (BYTE*)BufferPool_Take(context->priv->BufferPool, -1);
pSrcDst[0] = (INT16*)((&pBuffer[((8192ULL + 32ULL) * 0ULL) + 16ULL])); /* y_r_buffer */
pSrcDst[1] = (INT16*)((&pBuffer[((8192ULL + 32ULL) * 1ULL) + 16ULL])); /* cb_g_buffer */
pSrcDst[2] = (INT16*)((&pBuffer[((8192ULL + 32ULL) * 2ULL) + 16ULL])); /* cr_b_buffer */
rfx_decode_component(context, y_quants, tile->YData, tile->YLen, pSrcDst[0]); /* YData */
rfx_decode_component(context, cb_quants, tile->CbData, tile->CbLen, pSrcDst[1]); /* CbData */
rfx_decode_component(context, cr_quants, tile->CrData, tile->CrLen, pSrcDst[2]); /* CrData */
PROFILER_ENTER(context->priv->prof_rfx_ycbcr_to_rgb)
cnv.pv = pSrcDst;
if (prims->yCbCrToRGB_16s8u_P3AC4R(cnv.cpv, 64 * sizeof(INT16), rgb_buffer, stride,
context->pixel_format, &roi_64x64) != PRIMITIVES_SUCCESS)
rc = FALSE;
PROFILER_EXIT(context->priv->prof_rfx_ycbcr_to_rgb)
PROFILER_EXIT(context->priv->prof_rfx_decode_rgb)
BufferPool_Return(context->priv->BufferPool, pBuffer);
return rc;
}
+34
View File
@@ -0,0 +1,34 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* RemoteFX Codec Library - Decode
*
* Copyright 2011 Vic Lee
*
* 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 FREERDP_LIB_CODEC_RFX_DECODE_H
#define FREERDP_LIB_CODEC_RFX_DECODE_H
#include <winpr/wtypes.h>
#include <freerdp/codec/rfx.h>
#include <freerdp/api.h>
/* stride is bytes between rows in the output buffer. */
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rfx_decode_rgb(RFX_CONTEXT* WINPR_RESTRICT context,
const RFX_TILE* WINPR_RESTRICT tile,
BYTE* WINPR_RESTRICT rgb_buffer, UINT32 stride);
#endif /* FREERDP_LIB_CODEC_RFX_DECODE_H */
+52
View File
@@ -0,0 +1,52 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* RemoteFX Codec Library - Differential Encoding
*
* Copyright 2011 Vic Lee
*
* 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 FREERDP_LIB_CODEC_RFX_DIFFERENTIAL_H
#define FREERDP_LIB_CODEC_RFX_DIFFERENTIAL_H
#include <freerdp/codec/rfx.h>
#include <freerdp/api.h>
static inline void rfx_differential_decode(INT16* WINPR_RESTRICT buffer, size_t size)
{
INT16* ptr = buffer;
INT16* end = &buffer[size - 1];
while (ptr != end)
{
const int tmp = ptr[0] + ptr[1];
ptr[1] = WINPR_ASSERTING_INT_CAST(INT16, tmp);
ptr++;
}
}
static inline void rfx_differential_encode(INT16* WINPR_RESTRICT buffer, size_t size)
{
INT16 n1 = buffer[0];
for (size_t x = 0; x < size - 1; x++)
{
INT16* dst = &buffer[x + 1];
const INT16 n2 = *dst;
const int tmp = n2 - n1;
*dst = WINPR_ASSERTING_INT_CAST(INT16, tmp);
n1 = n2;
}
}
#endif /* FREERDP_LIB_CODEC_RFX_DIFFERENTIAL_H */
+230
View File
@@ -0,0 +1,230 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* RemoteFX Codec Library - DWT
*
* Copyright 2011 Vic Lee
*
* 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 <winpr/assert.h>
#include <winpr/cast.h>
#include <freerdp/config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "rfx_dwt.h"
static inline void rfx_dwt_2d_decode_block(INT16* WINPR_RESTRICT buffer, INT16* WINPR_RESTRICT idwt,
size_t subband_width)
{
const size_t total_width = subband_width << 1;
/* Inverse DWT in horizontal direction, results in 2 sub-bands in L, H order in tmp buffer idwt.
*/
/* The 4 sub-bands are stored in HL(0), LH(1), HH(2), LL(3) order. */
/* The lower part L uses LL(3) and HL(0). */
/* The higher part H uses LH(1) and HH(2). */
const INT16* ll = buffer + subband_width * subband_width * 3;
const INT16* hl = buffer;
INT16* l_dst = idwt;
const INT16* lh = buffer + subband_width * subband_width;
const INT16* hh = buffer + subband_width * subband_width * 2;
INT16* h_dst = idwt + subband_width * subband_width * 2;
for (size_t y = 0; y < subband_width; y++)
{
/* Even coefficients */
l_dst[0] = WINPR_ASSERTING_INT_CAST(int16_t, ll[0] - ((hl[0] + hl[0] + 1) >> 1));
h_dst[0] = WINPR_ASSERTING_INT_CAST(int16_t, lh[0] - ((hh[0] + hh[0] + 1) >> 1));
for (size_t n = 1; n < subband_width; n++)
{
const size_t x = n << 1;
l_dst[x] = WINPR_ASSERTING_INT_CAST(int16_t, ll[n] - ((hl[n - 1] + hl[n] + 1) >> 1));
h_dst[x] = WINPR_ASSERTING_INT_CAST(int16_t, lh[n] - ((hh[n - 1] + hh[n] + 1) >> 1));
}
/* Odd coefficients */
size_t n = 0;
for (; n < subband_width - 1; n++)
{
const size_t x = n << 1;
const int ld = (hl[n] << 1) + ((l_dst[x] + l_dst[x + 2]) >> 1);
const int hd = (hh[n] << 1) + ((h_dst[x] + h_dst[x + 2]) >> 1);
l_dst[x + 1] = WINPR_ASSERTING_INT_CAST(INT16, ld);
h_dst[x + 1] = WINPR_ASSERTING_INT_CAST(INT16, hd);
}
const size_t x = n << 1;
const int ld = (hl[n] << 1) + (l_dst[x]);
const int hd = (hh[n] << 1) + (h_dst[x]);
l_dst[x + 1] = WINPR_ASSERTING_INT_CAST(INT16, ld);
h_dst[x + 1] = WINPR_ASSERTING_INT_CAST(INT16, hd);
ll += subband_width;
hl += subband_width;
l_dst += total_width;
lh += subband_width;
hh += subband_width;
h_dst += total_width;
}
/* Inverse DWT in vertical direction, results are stored in original buffer. */
for (size_t x = 0; x < total_width; x++)
{
const INT16* l = idwt + x;
const INT16* h = idwt + x + subband_width * total_width;
INT16* dst = buffer + x;
const int dd = *l - ((*h * 2 + 1) >> 1);
*dst = WINPR_ASSERTING_INT_CAST(INT16, dd);
for (size_t n = 1; n < subband_width; n++)
{
l += total_width;
h += total_width;
/* Even coefficients */
const int d2 = *l - ((*(h - total_width) + *h + 1) >> 1);
dst[2 * total_width] = WINPR_ASSERTING_INT_CAST(INT16, d2);
/* Odd coefficients */
const int d = (*(h - total_width) << 1) + ((*dst + dst[2 * total_width]) >> 1);
dst[total_width] = WINPR_ASSERTING_INT_CAST(INT16, d);
dst += 2 * total_width;
}
const int d = (*h << 1) + ((*dst * 2) >> 1);
dst[total_width] = WINPR_ASSERTING_INT_CAST(INT16, d);
}
}
void rfx_dwt_2d_decode(INT16* WINPR_RESTRICT buffer, INT16* WINPR_RESTRICT dwt_buffer)
{
WINPR_ASSERT(buffer);
WINPR_ASSERT(dwt_buffer);
rfx_dwt_2d_decode_block(&buffer[3840], dwt_buffer, 8);
rfx_dwt_2d_decode_block(&buffer[3072], dwt_buffer, 16);
rfx_dwt_2d_decode_block(&buffer[0], dwt_buffer, 32);
}
static void rfx_dwt_2d_encode_block(INT16* WINPR_RESTRICT buffer, INT16* WINPR_RESTRICT dwt,
UINT32 subband_width)
{
INT16* src = nullptr;
INT16* l = nullptr;
INT16* h = nullptr;
INT16* l_src = nullptr;
INT16* h_src = nullptr;
INT16* hl = nullptr;
INT16* lh = nullptr;
INT16* hh = nullptr;
INT16* ll = nullptr;
const UINT32 total_width = subband_width << 1;
/* DWT in vertical direction, results in 2 sub-bands in L, H order in tmp buffer dwt. */
for (UINT32 x = 0; x < total_width; x++)
{
for (UINT32 n = 0; n < subband_width; n++)
{
UINT32 y = n << 1;
l = dwt + 1ULL * n * total_width + x;
h = l + 1ULL * subband_width * total_width;
src = buffer + 1ULL * y * total_width + x;
/* H */
*h = WINPR_ASSERTING_INT_CAST(
int16_t, (src[total_width] -
((src[0] + src[n < subband_width - 1 ? 2 * total_width : 0]) >> 1)) >>
1);
/* L */
*l = WINPR_ASSERTING_INT_CAST(int16_t,
src[0] + (n == 0 ? *h : (*(h - total_width) + *h) >> 1));
}
}
/* DWT in horizontal direction, results in 4 sub-bands in HL(0), LH(1), HH(2), LL(3) order,
* stored in original buffer. */
/* The lower part L generates LL(3) and HL(0). */
/* The higher part H generates LH(1) and HH(2). */
ll = buffer + 3ULL * subband_width * subband_width;
hl = buffer;
l_src = dwt;
lh = buffer + 1ULL * subband_width * subband_width;
hh = buffer + 2ULL * subband_width * subband_width;
h_src = dwt + 2ULL * subband_width * subband_width;
for (size_t y = 0; y < subband_width; y++)
{
/* L */
for (UINT32 n = 0; n < subband_width; n++)
{
UINT32 x = n << 1;
/* HL */
hl[n] = WINPR_ASSERTING_INT_CAST(
int16_t,
(l_src[x + 1] - ((l_src[x] + l_src[n < subband_width - 1 ? x + 2 : x]) >> 1)) >> 1);
/* LL */
ll[n] = WINPR_ASSERTING_INT_CAST(
int16_t, l_src[x] + (n == 0 ? hl[n] : (hl[n - 1] + hl[n]) >> 1));
}
/* H */
for (UINT32 n = 0; n < subband_width; n++)
{
UINT32 x = n << 1;
/* HH */
hh[n] = WINPR_ASSERTING_INT_CAST(
int16_t,
(h_src[x + 1] - ((h_src[x] + h_src[n < subband_width - 1 ? x + 2 : x]) >> 1)) >> 1);
/* LH */
lh[n] = WINPR_ASSERTING_INT_CAST(
int16_t, h_src[x] + (n == 0 ? hh[n] : (hh[n - 1] + hh[n]) >> 1));
}
ll += subband_width;
hl += subband_width;
l_src += total_width;
lh += subband_width;
hh += subband_width;
h_src += total_width;
}
}
void rfx_dwt_2d_encode(INT16* WINPR_RESTRICT buffer, INT16* WINPR_RESTRICT dwt_buffer)
{
WINPR_ASSERT(buffer);
WINPR_ASSERT(dwt_buffer);
rfx_dwt_2d_encode_block(&buffer[0], dwt_buffer, 32);
rfx_dwt_2d_encode_block(&buffer[3072], dwt_buffer, 16);
rfx_dwt_2d_encode_block(&buffer[3840], dwt_buffer, 8);
}
+34
View File
@@ -0,0 +1,34 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* RemoteFX Codec Library - DWT
*
* Copyright 2011 Vic Lee
*
* 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 FREERDP_LIB_CODEC_RFX_DWT_H
#define FREERDP_LIB_CODEC_RFX_DWT_H
#include <winpr/wtypes.h>
#include <freerdp/codec/rfx.h>
#include <freerdp/api.h>
FREERDP_LOCAL void rfx_dwt_2d_decode(INT16* WINPR_RESTRICT buffer,
INT16* WINPR_RESTRICT dwt_buffer);
FREERDP_LOCAL void rfx_dwt_2d_encode(INT16* WINPR_RESTRICT buffer,
INT16* WINPR_RESTRICT dwt_buffer);
FREERDP_LOCAL void rfx_dwt_2d_extrapolate_decode(INT16* WINPR_RESTRICT buffer,
INT16* WINPR_RESTRICT dwt_buffer);
#endif /* FREERDP_LIB_CODEC_RFX_DWT_H */
+312
View File
@@ -0,0 +1,312 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* RemoteFX Codec Library - Encode
*
* Copyright 2011 Vic Lee
* Copyright 2011 Norbert Federa <norbert.federa@thincast.com>
*
* 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 <freerdp/config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winpr/crt.h>
#include <winpr/collections.h>
#include <freerdp/primitives.h>
#include "rfx_types.h"
#include "rfx_rlgr.h"
#include "rfx_differential.h"
#include "rfx_quantization.h"
#include "rfx_dwt.h"
#include "rfx_encode.h"
static void rfx_encode_format_rgb(const BYTE* WINPR_RESTRICT rgb_data, uint32_t width,
uint32_t height, uint32_t rowstride, UINT32 pixel_format,
const BYTE* WINPR_RESTRICT palette, INT16* WINPR_RESTRICT r_buf,
INT16* WINPR_RESTRICT g_buf, INT16* WINPR_RESTRICT b_buf)
{
const BYTE* src = nullptr;
INT16 r = 0;
INT16 g = 0;
INT16 b = 0;
INT16* r_last = nullptr;
INT16* g_last = nullptr;
INT16* b_last = nullptr;
uint32_t x_exceed = 64 - width;
uint32_t y_exceed = 64 - height;
for (uint32_t y = 0; y < height; y++)
{
src = rgb_data + 1ULL * y * rowstride;
switch (pixel_format)
{
case PIXEL_FORMAT_BGRX32:
case PIXEL_FORMAT_BGRA32:
for (uint32_t x = 0; x < width; x++)
{
*b_buf++ = (INT16)(*src++);
*g_buf++ = (INT16)(*src++);
*r_buf++ = (INT16)(*src++);
src++;
}
break;
case PIXEL_FORMAT_XBGR32:
case PIXEL_FORMAT_ABGR32:
for (size_t x = 0; x < width; x++)
{
src++;
*b_buf++ = (INT16)(*src++);
*g_buf++ = (INT16)(*src++);
*r_buf++ = (INT16)(*src++);
}
break;
case PIXEL_FORMAT_RGBX32:
case PIXEL_FORMAT_RGBA32:
for (size_t x = 0; x < width; x++)
{
*r_buf++ = (INT16)(*src++);
*g_buf++ = (INT16)(*src++);
*b_buf++ = (INT16)(*src++);
src++;
}
break;
case PIXEL_FORMAT_XRGB32:
case PIXEL_FORMAT_ARGB32:
for (size_t x = 0; x < width; x++)
{
src++;
*r_buf++ = (INT16)(*src++);
*g_buf++ = (INT16)(*src++);
*b_buf++ = (INT16)(*src++);
}
break;
case PIXEL_FORMAT_BGR24:
for (size_t x = 0; x < width; x++)
{
*b_buf++ = (INT16)(*src++);
*g_buf++ = (INT16)(*src++);
*r_buf++ = (INT16)(*src++);
}
break;
case PIXEL_FORMAT_RGB24:
for (size_t x = 0; x < width; x++)
{
*r_buf++ = (INT16)(*src++);
*g_buf++ = (INT16)(*src++);
*b_buf++ = (INT16)(*src++);
}
break;
case PIXEL_FORMAT_BGR16:
for (size_t x = 0; x < width; x++)
{
*b_buf++ = (INT16)(((*(src + 1)) & 0xF8) | ((*(src + 1)) >> 5));
*g_buf++ = (INT16)((((*(src + 1)) & 0x07) << 5) | (((*src) & 0xE0) >> 3));
*r_buf++ = (INT16)((((*src) & 0x1F) << 3) | (((*src) >> 2) & 0x07));
src += 2;
}
break;
case PIXEL_FORMAT_RGB16:
for (size_t x = 0; x < width; x++)
{
*r_buf++ = (INT16)(((*(src + 1)) & 0xF8) | ((*(src + 1)) >> 5));
*g_buf++ = (INT16)((((*(src + 1)) & 0x07) << 5) | (((*src) & 0xE0) >> 3));
*b_buf++ = (INT16)((((*src) & 0x1F) << 3) | (((*src) >> 2) & 0x07));
src += 2;
}
break;
case PIXEL_FORMAT_RGB8:
if (!palette)
break;
for (size_t x = 0; x < width; x++)
{
BYTE idx = 0;
const size_t shift = (7 - (x % 8));
idx = ((*src) >> shift) & 1;
idx |= (((*(src + 1)) >> shift) & 1) << 1;
idx |= (((*(src + 2)) >> shift) & 1) << 2;
idx |= (((*(src + 3)) >> shift) & 1) << 3;
idx *= 3;
*r_buf++ = (INT16)palette[idx];
*g_buf++ = (INT16)palette[idx + 1];
*b_buf++ = (INT16)palette[idx + 2];
if (shift == 0)
src += 4;
}
break;
case PIXEL_FORMAT_A4:
if (!palette)
break;
for (size_t x = 0; x < width; x++)
{
int idx = (*src) * 3;
*r_buf++ = (INT16)palette[idx];
*g_buf++ = (INT16)palette[idx + 1];
*b_buf++ = (INT16)palette[idx + 2];
src++;
}
break;
default:
break;
}
/* Fill the horizontal region outside of 64x64 tile size with the right-most pixel for best
* quality */
if (x_exceed > 0)
{
r = *(r_buf - 1);
g = *(g_buf - 1);
b = *(b_buf - 1);
for (size_t x = 0; x < x_exceed; x++)
{
*r_buf++ = r;
*g_buf++ = g;
*b_buf++ = b;
}
}
}
/* Fill the vertical region outside of 64x64 tile size with the last line. */
if (y_exceed > 0)
{
r_last = r_buf - 64;
g_last = g_buf - 64;
b_last = b_buf - 64;
while (y_exceed > 0)
{
CopyMemory(r_buf, r_last, 64 * sizeof(INT16));
CopyMemory(g_buf, g_last, 64 * sizeof(INT16));
CopyMemory(b_buf, b_last, 64 * sizeof(INT16));
r_buf += 64;
g_buf += 64;
b_buf += 64;
y_exceed--;
}
}
}
/* rfx_encode_rgb_to_ycbcr code now resides in the primitives library. */
static void rfx_encode_component(RFX_CONTEXT* WINPR_RESTRICT context,
const UINT32* WINPR_RESTRICT quantization_values,
INT16* WINPR_RESTRICT data, BYTE* WINPR_RESTRICT buffer,
uint32_t buffer_size, uint32_t* WINPR_RESTRICT size)
{
INT16* dwt_buffer = BufferPool_Take(context->priv->BufferPool, -1); /* dwt_buffer */
PROFILER_ENTER(context->priv->prof_rfx_encode_component)
PROFILER_ENTER(context->priv->prof_rfx_dwt_2d_encode)
context->dwt_2d_encode(data, dwt_buffer);
PROFILER_EXIT(context->priv->prof_rfx_dwt_2d_encode)
PROFILER_ENTER(context->priv->prof_rfx_quantization_encode)
context->quantization_encode(data, quantization_values);
PROFILER_EXIT(context->priv->prof_rfx_quantization_encode)
PROFILER_ENTER(context->priv->prof_rfx_differential_encode)
rfx_differential_encode(data + 4032, 64);
PROFILER_EXIT(context->priv->prof_rfx_differential_encode)
PROFILER_ENTER(context->priv->prof_rfx_rlgr_encode)
const int rc = context->rlgr_encode(context->mode, data, 4096, buffer, buffer_size);
PROFILER_EXIT(context->priv->prof_rfx_rlgr_encode)
PROFILER_EXIT(context->priv->prof_rfx_encode_component)
BufferPool_Return(context->priv->BufferPool, dwt_buffer);
*size = WINPR_ASSERTING_INT_CAST(uint32_t, rc);
}
BOOL rfx_encode_rgb(RFX_CONTEXT* WINPR_RESTRICT context, RFX_TILE* WINPR_RESTRICT tile)
{
BOOL rc = TRUE;
union
{
const INT16** cpv;
INT16** pv;
} cnv;
INT16* pSrcDst[3] = WINPR_C_ARRAY_INIT;
uint32_t CbLen = 0;
uint32_t CrLen = 0;
primitives_t* prims = primitives_get();
static const prim_size_t roi_64x64 = { 64, 64 };
BYTE* pBuffer = (BYTE*)BufferPool_Take(context->priv->BufferPool, -1);
if (!pBuffer)
return FALSE;
uint32_t YLen = CbLen = CrLen = 0;
UINT32* YQuant = context->quants + (10ULL * tile->quantIdxY);
UINT32* CbQuant = context->quants + (10ULL * tile->quantIdxCb);
UINT32* CrQuant = context->quants + (10ULL * tile->quantIdxCr);
pSrcDst[0] = (INT16*)((&pBuffer[((8192ULL + 32ULL) * 0ULL) + 16ULL])); /* y_r_buffer */
pSrcDst[1] = (INT16*)((&pBuffer[((8192ULL + 32ULL) * 1ULL) + 16ULL])); /* cb_g_buffer */
pSrcDst[2] = (INT16*)((&pBuffer[((8192ULL + 32ULL) * 2ULL) + 16ULL])); /* cr_b_buffer */
PROFILER_ENTER(context->priv->prof_rfx_encode_rgb)
PROFILER_ENTER(context->priv->prof_rfx_encode_format_rgb)
rfx_encode_format_rgb(tile->data, tile->width, tile->height, tile->scanline,
context->pixel_format, context->palette, pSrcDst[0], pSrcDst[1],
pSrcDst[2]);
PROFILER_EXIT(context->priv->prof_rfx_encode_format_rgb)
PROFILER_ENTER(context->priv->prof_rfx_rgb_to_ycbcr)
cnv.pv = pSrcDst;
if (prims->RGBToYCbCr_16s16s_P3P3(cnv.cpv, 64 * sizeof(INT16), pSrcDst, 64 * sizeof(INT16),
&roi_64x64) != PRIMITIVES_SUCCESS)
rc = FALSE;
PROFILER_EXIT(context->priv->prof_rfx_rgb_to_ycbcr)
/**
* We need to clear the buffers as the RLGR encoder expects it to be initialized to zero.
* This allows simplifying and improving the performance of the encoding process.
*/
ZeroMemory(tile->YData, 4096);
ZeroMemory(tile->CbData, 4096);
ZeroMemory(tile->CrData, 4096);
rfx_encode_component(context, YQuant, pSrcDst[0], tile->YData, 4096, &YLen);
rfx_encode_component(context, CbQuant, pSrcDst[1], tile->CbData, 4096, &CbLen);
rfx_encode_component(context, CrQuant, pSrcDst[2], tile->CrData, 4096, &CrLen);
tile->YLen = WINPR_ASSERTING_INT_CAST(UINT16, YLen);
tile->CbLen = WINPR_ASSERTING_INT_CAST(UINT16, CbLen);
tile->CrLen = WINPR_ASSERTING_INT_CAST(UINT16, CrLen);
PROFILER_EXIT(context->priv->prof_rfx_encode_rgb)
if (!BufferPool_Return(context->priv->BufferPool, pBuffer))
return FALSE;
return rc;
}
+30
View File
@@ -0,0 +1,30 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* RemoteFX Codec Library - Encode
*
* Copyright 2011 Vic Lee
*
* 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 FREERDP_LIB_CODEC_RFX_ENCODE_H
#define FREERDP_LIB_CODEC_RFX_ENCODE_H
#include <freerdp/codec/rfx.h>
#include <freerdp/api.h>
WINPR_ATTR_NODISCARD
FREERDP_LOCAL BOOL rfx_encode_rgb(RFX_CONTEXT* WINPR_RESTRICT context,
RFX_TILE* WINPR_RESTRICT tile);
#endif /* FREERDP_LIB_CODEC_RFX_ENCODE_H */
+109
View File
@@ -0,0 +1,109 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* RemoteFX Codec Library - Quantization
*
* Copyright 2011 Vic Lee
*
* 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 <winpr/assert.h>
#include <winpr/cast.h>
#include <freerdp/config.h>
#include <freerdp/primitives.h>
#include "rfx_quantization.h"
/*
* Band Offset Dimensions Size
*
* HL1 0 32x32 1024
* LH1 1024 32x32 1024
* HH1 2048 32x32 1024
*
* HL2 3072 16x16 256
* LH2 3328 16x16 256
* HH2 3584 16x16 256
*
* HL3 3840 8x8 64
* LH3 3904 8x8 64
* HH3 3968 8x8 64
*
* LL3 4032 8x8 64
*/
static inline BOOL rfx_quantization_decode_block(const primitives_t* WINPR_RESTRICT prims,
INT16* WINPR_RESTRICT buffer, UINT32 buffer_size,
UINT32 factor)
{
if (factor == 0)
return TRUE;
return prims->lShiftC_16s_inplace(buffer, factor, buffer_size) == PRIMITIVES_SUCCESS;
}
void rfx_quantization_decode(INT16* WINPR_RESTRICT buffer,
const UINT32* WINPR_RESTRICT quantization_values)
{
const primitives_t* prims = primitives_get();
WINPR_ASSERT(buffer);
WINPR_ASSERT(quantization_values);
rfx_quantization_decode_block(prims, &buffer[0], 1024, quantization_values[8] - 1); /* HL1 */
rfx_quantization_decode_block(prims, &buffer[1024], 1024, quantization_values[7] - 1); /* LH1 */
rfx_quantization_decode_block(prims, &buffer[2048], 1024, quantization_values[9] - 1); /* HH1 */
rfx_quantization_decode_block(prims, &buffer[3072], 256, quantization_values[5] - 1); /* HL2 */
rfx_quantization_decode_block(prims, &buffer[3328], 256, quantization_values[4] - 1); /* LH2 */
rfx_quantization_decode_block(prims, &buffer[3584], 256, quantization_values[6] - 1); /* HH2 */
rfx_quantization_decode_block(prims, &buffer[3840], 64, quantization_values[2] - 1); /* HL3 */
rfx_quantization_decode_block(prims, &buffer[3904], 64, quantization_values[1] - 1); /* LH3 */
rfx_quantization_decode_block(prims, &buffer[3968], 64, quantization_values[3] - 1); /* HH3 */
rfx_quantization_decode_block(prims, &buffer[4032], 64, quantization_values[0] - 1); /* LL3 */
}
static inline void rfx_quantization_encode_block(INT16* WINPR_RESTRICT buffer, size_t buffer_size,
UINT32 factor)
{
if (factor == 0)
return;
const INT16 half = WINPR_ASSERTING_INT_CAST(INT16, 1 << (factor - 1));
/* Could probably use prims->rShiftC_16s(dst+half, factor, dst, buffer_size); */
for (INT16* dst = buffer; buffer_size > 0; dst++, buffer_size--)
{
*dst = WINPR_ASSERTING_INT_CAST(INT16, (*dst + half) >> factor);
}
}
void rfx_quantization_encode(INT16* WINPR_RESTRICT buffer,
const UINT32* WINPR_RESTRICT quantization_values)
{
WINPR_ASSERT(buffer);
WINPR_ASSERT(quantization_values);
rfx_quantization_encode_block(buffer, 1024, quantization_values[8] - 6); /* HL1 */
rfx_quantization_encode_block(buffer + 1024, 1024, quantization_values[7] - 6); /* LH1 */
rfx_quantization_encode_block(buffer + 2048, 1024, quantization_values[9] - 6); /* HH1 */
rfx_quantization_encode_block(buffer + 3072, 256, quantization_values[5] - 6); /* HL2 */
rfx_quantization_encode_block(buffer + 3328, 256, quantization_values[4] - 6); /* LH2 */
rfx_quantization_encode_block(buffer + 3584, 256, quantization_values[6] - 6); /* HH2 */
rfx_quantization_encode_block(buffer + 3840, 64, quantization_values[2] - 6); /* HL3 */
rfx_quantization_encode_block(buffer + 3904, 64, quantization_values[1] - 6); /* LH3 */
rfx_quantization_encode_block(buffer + 3968, 64, quantization_values[3] - 6); /* HH3 */
rfx_quantization_encode_block(buffer + 4032, 64, quantization_values[0] - 6); /* LL3 */
/* The coefficients are scaled by << 5 at RGB->YCbCr phase, so we round it back here */
rfx_quantization_encode_block(buffer, 4096, 5);
}
+31
View File
@@ -0,0 +1,31 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* RemoteFX Codec Library - Quantization
*
* Copyright 2011 Vic Lee
*
* 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 FREERDP_LIB_CODEC_RFX_QUANTIZATION_H
#define FREERDP_LIB_CODEC_RFX_QUANTIZATION_H
#include <freerdp/codec/rfx.h>
#include <freerdp/api.h>
FREERDP_LOCAL void rfx_quantization_decode(INT16* WINPR_RESTRICT buffer,
const UINT32* WINPR_RESTRICT quantization_values);
FREERDP_LOCAL void rfx_quantization_encode(INT16* WINPR_RESTRICT buffer,
const UINT32* WINPR_RESTRICT quantization_values);
#endif /* FREERDP_LIB_CODEC_RFX_QUANTIZATION_H */
+795
View File
@@ -0,0 +1,795 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* RemoteFX Codec Library - RLGR
*
* Copyright 2011 Vic Lee
*
* 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.
*/
/**
* This implementation of RLGR refers to
* [MS-RDPRFX] 3.1.8.1.7.3 RLGR1/RLGR3 Pseudocode
*/
#include <freerdp/config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winpr/assert.h>
#include <winpr/cast.h>
#include <winpr/crt.h>
#include <winpr/print.h>
#include <winpr/sysinfo.h>
#include <winpr/bitstream.h>
#include <winpr/intrin.h>
#include "rfx_bitstream.h"
#include "rfx_rlgr.h"
/* Constants used in RLGR1/RLGR3 algorithm */
#define KPMAX (80) /* max value for kp or krp */
#define LSGR (3) /* shift count to convert kp to k */
#define UP_GR (4) /* increase in kp after a zero run in RL mode */
#define DN_GR (6) /* decrease in kp after a nonzero symbol in RL mode */
#define UQ_GR (3) /* increase in kp after nonzero symbol in GR mode */
#define DQ_GR (3) /* decrease in kp after zero symbol in GR mode */
/* Returns the least number of bits required to represent a given value */
#define GetMinBits(_val, _nbits) \
do \
{ \
UINT32 _v = (_val); \
(_nbits) = 0; \
while (_v) \
{ \
_v >>= 1; \
(_nbits)++; \
} \
} while (0)
/*
* Update the passed parameter and clamp it to the range [0, KPMAX]
* Return the value of parameter right-shifted by LSGR
*/
static inline uint32_t UpdateParam(uint32_t* param, int32_t deltaP)
{
WINPR_ASSERT(param);
if (deltaP < 0)
{
const uint32_t udeltaP = WINPR_ASSERTING_INT_CAST(uint32_t, -deltaP);
if (udeltaP > *param)
*param = 0;
else
*param -= udeltaP;
}
else
*param += WINPR_ASSERTING_INT_CAST(uint32_t, deltaP);
if ((*param) > KPMAX)
(*param) = KPMAX;
return (*param) >> LSGR;
}
static BOOL g_LZCNT = FALSE;
static INIT_ONCE rfx_rlgr_init_once = INIT_ONCE_STATIC_INIT;
static BOOL CALLBACK rfx_rlgr_init(PINIT_ONCE once, PVOID param, PVOID* context)
{
WINPR_UNUSED(once);
WINPR_UNUSED(param);
WINPR_UNUSED(context);
g_LZCNT = IsProcessorFeaturePresentEx(PF_EX_LZCNT);
return TRUE;
}
static inline UINT32 lzcnt_s(UINT32 x)
{
if (!x)
return 32;
if (!g_LZCNT)
{
UINT32 y = 0;
UINT32 n = 32;
y = x >> 16;
if (y != 0)
{
WINPR_ASSERT(n >= 16);
n = n - 16;
x = y;
}
y = x >> 8;
if (y != 0)
{
WINPR_ASSERT(n >= 8);
n = n - 8;
x = y;
}
y = x >> 4;
if (y != 0)
{
WINPR_ASSERT(n >= 4);
n = n - 4;
x = y;
}
y = x >> 2;
if (y != 0)
{
WINPR_ASSERT(n >= 2);
n = n - 2;
x = y;
}
y = x >> 1;
if (y != 0)
{
WINPR_ASSERT(n >= 2);
return n - 2;
}
WINPR_ASSERT(n >= x);
return n - x;
}
return __lzcnt(x);
}
int rfx_rlgr_decode(RLGR_MODE mode, const BYTE* WINPR_RESTRICT pSrcData, UINT32 SrcSize,
INT16* WINPR_RESTRICT pDstData, UINT32 rDstSize)
{
uint32_t vk = 0;
size_t run = 0;
size_t cnt = 0;
size_t size = 0;
size_t offset = 0;
INT16 mag = 0;
UINT32 k = 0;
UINT32 kp = 0;
UINT32 kr = 0;
UINT32 krp = 0;
UINT16 code = 0;
UINT32 sign = 0;
UINT32 nIdx = 0;
UINT32 val1 = 0;
UINT32 val2 = 0;
INT16* pOutput = nullptr;
wBitStream* bs = nullptr;
wBitStream s_bs = WINPR_C_ARRAY_INIT;
const SSIZE_T DstSize = rDstSize;
if (!InitOnceExecuteOnce(&rfx_rlgr_init_once, rfx_rlgr_init, nullptr, nullptr))
return -1;
k = 1;
kp = k << LSGR;
kr = 1;
krp = kr << LSGR;
if ((mode != RLGR1) && (mode != RLGR3))
mode = RLGR1;
if (!pSrcData || !SrcSize)
return -1;
if (!pDstData || !DstSize)
return -1;
pOutput = pDstData;
bs = &s_bs;
BitStream_Attach(bs, pSrcData, SrcSize);
BitStream_Fetch(bs);
while ((BitStream_GetRemainingLength(bs) > 0) && ((pOutput - pDstData) < DstSize))
{
if (k)
{
/* Run-Length (RL) Mode */
run = 0;
/* count number of leading 0s */
cnt = lzcnt_s(bs->accumulator);
size_t nbits = BitStream_GetRemainingLength(bs);
if (cnt > nbits)
cnt = WINPR_ASSERTING_INT_CAST(uint32_t, nbits);
vk = WINPR_ASSERTING_INT_CAST(uint32_t, cnt);
while ((cnt == 32) && (BitStream_GetRemainingLength(bs) > 0))
{
BitStream_Shift32(bs);
cnt = lzcnt_s(bs->accumulator);
nbits = BitStream_GetRemainingLength(bs);
if (cnt > nbits)
cnt = nbits;
WINPR_ASSERT(cnt + vk <= UINT32_MAX);
vk += WINPR_ASSERTING_INT_CAST(uint32_t, cnt);
}
BitStream_Shift(bs, (vk % 32));
if (BitStream_GetRemainingLength(bs) < 1)
break;
BitStream_Shift(bs, 1);
while (vk--)
{
const UINT32 add = (1 << k); /* add (1 << k) to run length */
run += add;
/* update k, kp params */
kp += UP_GR;
if (kp > KPMAX)
kp = KPMAX;
k = kp >> LSGR;
}
/* next k bits contain run length remainder */
if (BitStream_GetRemainingLength(bs) < k)
break;
bs->mask = ((1 << k) - 1);
run += ((bs->accumulator >> (32 - k)) & bs->mask);
BitStream_Shift(bs, k);
/* read sign bit */
if (BitStream_GetRemainingLength(bs) < 1)
break;
sign = (bs->accumulator & 0x80000000) ? 1 : 0;
BitStream_Shift(bs, 1);
/* count number of leading 1s */
cnt = lzcnt_s(~(bs->accumulator));
nbits = BitStream_GetRemainingLength(bs);
if (cnt > nbits)
cnt = nbits;
vk = WINPR_ASSERTING_INT_CAST(uint32_t, cnt);
while ((cnt == 32) && (BitStream_GetRemainingLength(bs) > 0))
{
BitStream_Shift32(bs);
cnt = lzcnt_s(~(bs->accumulator));
nbits = BitStream_GetRemainingLength(bs);
if (cnt > nbits)
cnt = nbits;
WINPR_ASSERT(cnt + vk <= UINT32_MAX);
vk += WINPR_ASSERTING_INT_CAST(uint32_t, cnt);
}
BitStream_Shift(bs, (vk % 32));
if (BitStream_GetRemainingLength(bs) < 1)
break;
BitStream_Shift(bs, 1);
/* next kr bits contain code remainder */
if (BitStream_GetRemainingLength(bs) < kr)
break;
bs->mask = ((1 << kr) - 1);
if (kr > 0)
code = (UINT16)((bs->accumulator >> (32 - kr)) & bs->mask);
else
code = 0;
BitStream_Shift(bs, kr);
/* add (vk << kr) to code */
code |= (vk << kr);
if (!vk)
{
/* update kr, krp params */
if (krp > 2)
krp -= 2;
else
krp = 0;
kr = krp >> LSGR;
}
else if (vk != 1)
{
/* update kr, krp params */
krp += vk;
if (krp > KPMAX)
krp = KPMAX;
kr = krp >> LSGR;
}
/* update k, kp params */
if (kp > DN_GR)
kp -= DN_GR;
else
kp = 0;
k = kp >> LSGR;
/* compute magnitude from code */
if (sign)
mag = WINPR_ASSERTING_INT_CAST(int16_t, (code + 1)) * -1;
else
mag = WINPR_ASSERTING_INT_CAST(int16_t, code + 1);
/* write to output stream */
offset = WINPR_ASSERTING_INT_CAST(size_t, (pOutput)-pDstData);
size = run;
if ((offset + size) > rDstSize)
size = WINPR_ASSERTING_INT_CAST(size_t, DstSize) - offset;
if (size)
{
ZeroMemory(pOutput, size * sizeof(INT16));
pOutput += size;
}
if ((pOutput - pDstData) < DstSize)
{
*pOutput = mag;
pOutput++;
}
}
else
{
/* Golomb-Rice (GR) Mode */
/* count number of leading 1s */
cnt = lzcnt_s(~(bs->accumulator));
size_t nbits = BitStream_GetRemainingLength(bs);
if (cnt > nbits)
cnt = nbits;
vk = WINPR_ASSERTING_INT_CAST(uint32_t, cnt);
while ((cnt == 32) && (BitStream_GetRemainingLength(bs) > 0))
{
BitStream_Shift32(bs);
cnt = lzcnt_s(~(bs->accumulator));
nbits = BitStream_GetRemainingLength(bs);
if (cnt > nbits)
cnt = nbits;
WINPR_ASSERT(cnt + vk <= UINT32_MAX);
vk += WINPR_ASSERTING_INT_CAST(uint32_t, cnt);
}
BitStream_Shift(bs, (vk % 32));
if (BitStream_GetRemainingLength(bs) < 1)
break;
BitStream_Shift(bs, 1);
/* next kr bits contain code remainder */
if (BitStream_GetRemainingLength(bs) < kr)
break;
bs->mask = ((1 << kr) - 1);
if (kr > 0)
code = (UINT16)((bs->accumulator >> (32 - kr)) & bs->mask);
else
code = 0;
BitStream_Shift(bs, kr);
/* add (vk << kr) to code */
code |= (vk << kr);
if (!vk)
{
/* update kr, krp params */
if (krp > 2)
krp -= 2;
else
krp = 0;
kr = (krp >> LSGR) & UINT32_MAX;
}
else if (vk != 1)
{
/* update kr, krp params */
krp += vk;
if (krp > KPMAX)
krp = KPMAX;
kr = krp >> LSGR;
}
if (mode == RLGR1) /* RLGR1 */
{
if (!code)
{
/* update k, kp params */
kp += UQ_GR;
if (kp > KPMAX)
kp = KPMAX;
k = kp >> LSGR;
mag = 0;
}
else
{
/* update k, kp params */
if (kp > DQ_GR)
kp -= DQ_GR;
else
kp = 0;
k = kp >> LSGR;
/*
* code = 2 * mag - sign
* sign + code = 2 * mag
*/
if (code & 1)
mag = WINPR_ASSERTING_INT_CAST(INT16, (code + 1) >> 1) * -1;
else
mag = WINPR_ASSERTING_INT_CAST(INT16, code >> 1);
}
if ((pOutput - pDstData) < DstSize)
{
*pOutput = mag;
pOutput++;
}
}
else if (mode == RLGR3) /* RLGR3 */
{
nIdx = 0;
if (code)
{
mag = WINPR_ASSERTING_INT_CAST(int16_t, code);
nIdx = 32 - lzcnt_s(WINPR_ASSERTING_INT_CAST(uint32_t, mag));
}
if (BitStream_GetRemainingLength(bs) < nIdx)
break;
bs->mask = ((1 << nIdx) - 1);
if (nIdx > 0)
val1 = ((bs->accumulator >> (32 - nIdx)) & bs->mask);
else
val1 = 0;
BitStream_Shift(bs, nIdx);
val2 = code - val1;
if (val1 && val2)
{
/* update k, kp params */
if (kp > 2 * DQ_GR)
kp -= (2 * DQ_GR);
else
kp = 0;
k = kp >> LSGR;
}
else if (!val1 && !val2)
{
/* update k, kp params */
kp += (2 * UQ_GR);
if (kp > KPMAX)
kp = KPMAX;
k = kp >> LSGR;
}
if (val1 & 1)
mag = WINPR_ASSERTING_INT_CAST(int16_t, (val1 + 1) >> 1) * -1;
else
mag = WINPR_ASSERTING_INT_CAST(int16_t, val1 >> 1);
if ((pOutput - pDstData) < DstSize)
{
*pOutput = mag;
pOutput++;
}
if (val2 & 1)
mag = WINPR_ASSERTING_INT_CAST(int16_t, (val2 + 1) >> 1) * -1;
else
mag = WINPR_ASSERTING_INT_CAST(int16_t, val2 >> 1);
if ((pOutput - pDstData) < DstSize)
{
*pOutput = WINPR_ASSERTING_INT_CAST(int16_t, mag);
pOutput++;
}
}
}
}
offset = WINPR_ASSERTING_INT_CAST(size_t, (pOutput - pDstData));
if (offset < rDstSize)
{
size = WINPR_ASSERTING_INT_CAST(size_t, DstSize) - offset;
ZeroMemory(pOutput, size * 2);
pOutput += size;
}
offset = WINPR_ASSERTING_INT_CAST(size_t, (pOutput - pDstData));
if ((DstSize < 0) || (offset != (size_t)DstSize))
return -1;
return 1;
}
/* Returns the next coefficient (a signed int) to encode, from the input stream */
#define GetNextInput(_n) \
do \
{ \
if (data_size > 0) \
{ \
(_n) = *data++; \
data_size--; \
} \
else \
{ \
(_n) = 0; \
} \
} while (0)
/* Emit bitPattern to the output bitstream */
#define OutputBits(numBits, bitPattern) rfx_bitstream_put_bits(bs, bitPattern, numBits)
/* Emit a bit (0 or 1), count number of times, to the output bitstream */
static inline void OutputBit(RFX_BITSTREAM* bs, uint32_t count, UINT8 bit)
{
UINT16 _b = ((bit) ? 0xFFFF : 0);
const uint32_t rem = count % 16;
for (uint32_t x = 0; x < count - rem; x += 16)
rfx_bitstream_put_bits(bs, _b, 16);
if (rem > 0)
rfx_bitstream_put_bits(bs, _b, rem);
}
/* Converts the input value to (2 * abs(input) - sign(input)), where sign(input) = (input < 0 ? 1 :
* 0) and returns it */
static inline UINT32 Get2MagSign(INT32 input)
{
if (input >= 0)
return WINPR_ASSERTING_INT_CAST(UINT32, 2 * input);
return WINPR_ASSERTING_INT_CAST(UINT32, -2 * input - 1);
}
/* Outputs the Golomb/Rice encoding of a non-negative integer */
#define CodeGR(krp, val) rfx_rlgr_code_gr(bs, krp, val)
static void rfx_rlgr_code_gr(RFX_BITSTREAM* bs, uint32_t* krp, UINT32 val)
{
uint32_t kr = *krp >> LSGR;
/* unary part of GR code */
const uint32_t vk = val >> kr;
OutputBit(bs, vk, 1);
OutputBit(bs, 1, 0);
/* remainder part of GR code, if needed */
if (kr)
{
OutputBits(kr, val & ((1 << kr) - 1));
}
/* update krp, only if it is not equal to 1 */
if (vk == 0)
{
(void)UpdateParam(krp, -2);
}
else if (vk > 1)
{
(void)UpdateParam(krp, WINPR_CXX_COMPAT_CAST(int32_t, vk));
}
}
int rfx_rlgr_encode(RLGR_MODE mode, const INT16* WINPR_RESTRICT data, UINT32 data_size,
BYTE* WINPR_RESTRICT buffer, UINT32 buffer_size)
{
uint32_t k = 0;
uint32_t kp = 0;
uint32_t krp = 0;
RFX_BITSTREAM* bs = nullptr;
if (!(bs = (RFX_BITSTREAM*)winpr_aligned_calloc(1, sizeof(RFX_BITSTREAM), 32)))
return 0;
rfx_bitstream_attach(bs, buffer, buffer_size);
/* initialize the parameters */
k = 1;
kp = 1 << LSGR;
krp = 1 << LSGR;
/* process all the input coefficients */
while (data_size > 0)
{
int input = 0;
if (k)
{
uint32_t numZeros = 0;
uint32_t runmax = 0;
BYTE sign = 0;
/* RUN-LENGTH MODE */
/* collect the run of zeros in the input stream */
numZeros = 0;
GetNextInput(input);
while (input == 0 && data_size > 0)
{
numZeros++;
GetNextInput(input);
}
// emit output zeros
runmax = 1 << k;
while (numZeros >= runmax)
{
OutputBit(bs, 1, 0); /* output a zero bit */
numZeros -= runmax;
k = UpdateParam(&kp, UP_GR); /* update kp, k */
runmax = 1 << k;
}
/* output a 1 to terminate runs */
OutputBit(bs, 1, 1);
/* output the remaining run length using k bits */
OutputBits(k, numZeros);
/* note: when we reach here and the last byte being encoded is 0, we still
need to output the last two bits, otherwise mstsc will crash */
/* encode the nonzero value using GR coding */
const UINT32 mag =
(UINT32)(input < 0 ? -input : input); /* absolute value of input coefficient */
sign = (input < 0 ? 1 : 0); /* sign of input coefficient */
OutputBit(bs, 1, sign); /* output the sign bit */
CodeGR(&krp, mag ? mag - 1 : 0); /* output GR code for (mag - 1) */
k = UpdateParam(&kp, -DN_GR);
}
else
{
/* GOLOMB-RICE MODE */
if (mode == RLGR1)
{
UINT32 twoMs = 0;
/* RLGR1 variant */
/* convert input to (2*magnitude - sign), encode using GR code */
GetNextInput(input);
twoMs = Get2MagSign(input);
CodeGR(&krp, twoMs);
/* update k, kp */
/* NOTE: as of Aug 2011, the algorithm is still wrongly documented
and the update direction is reversed */
if (twoMs)
{
k = UpdateParam(&kp, -DQ_GR);
}
else
{
k = UpdateParam(&kp, UQ_GR);
}
}
else /* mode == RLGR3 */
{
UINT32 twoMs1 = 0;
UINT32 twoMs2 = 0;
UINT32 sum2Ms = 0;
UINT32 nIdx = 0;
/* RLGR3 variant */
/* convert the next two input values to (2*magnitude - sign) and */
/* encode their sum using GR code */
GetNextInput(input);
twoMs1 = Get2MagSign(input);
GetNextInput(input);
twoMs2 = Get2MagSign(input);
sum2Ms = twoMs1 + twoMs2;
CodeGR(&krp, sum2Ms);
/* encode binary representation of the first input (twoMs1). */
GetMinBits(sum2Ms, nIdx);
OutputBits(nIdx, twoMs1);
/* update k,kp for the two input values */
if (twoMs1 && twoMs2)
{
k = UpdateParam(&kp, -2 * DQ_GR);
}
else if (!twoMs1 && !twoMs2)
{
k = UpdateParam(&kp, 2 * UQ_GR);
}
}
}
}
rfx_bitstream_flush(bs);
uint32_t processed_size = rfx_bitstream_get_processed_bytes(bs);
winpr_aligned_free(bs);
return WINPR_ASSERTING_INT_CAST(int, processed_size);
}
+35
View File
@@ -0,0 +1,35 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* RemoteFX Codec Library - RLGR
*
* Copyright 2011 Vic Lee
*
* 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 FREERDP_LIB_CODEC_RFX_RLGR_H
#define FREERDP_LIB_CODEC_RFX_RLGR_H
#include <freerdp/codec/rfx.h>
#include <freerdp/api.h>
WINPR_ATTR_NODISCARD
FREERDP_LOCAL int rfx_rlgr_encode(RLGR_MODE mode, const INT16* WINPR_RESTRICT data,
UINT32 data_size, BYTE* WINPR_RESTRICT buffer,
UINT32 buffer_size);
WINPR_ATTR_NODISCARD
FREERDP_LOCAL int rfx_rlgr_decode(RLGR_MODE mode, const BYTE* WINPR_RESTRICT pSrcData,
UINT32 SrcSize, INT16* WINPR_RESTRICT pDstData, UINT32 rDstSize);
#endif /* FREERDP_LIB_CODEC_RFX_RLGR_H */
+180
View File
@@ -0,0 +1,180 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* RemoteFX Codec Library
*
* Copyright 2011 Vic Lee
*
* 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 FREERDP_LIB_CODEC_RFX_TYPES_H
#define FREERDP_LIB_CODEC_RFX_TYPES_H
#include <freerdp/config.h>
#include <winpr/crt.h>
#include <winpr/pool.h>
#include <winpr/wlog.h>
#include <winpr/collections.h>
#include <freerdp/codec/rfx.h>
#include <freerdp/log.h>
#include <freerdp/utils/profiler.h>
#define RFX_TAG FREERDP_TAG("codec.rfx")
#ifdef WITH_DEBUG_RFX
#define DEBUG_RFX(...) WLog_DBG(RFX_TAG, __VA_ARGS__)
#else
#define DEBUG_RFX(...) \
do \
{ \
} while (0)
#endif
#define RFX_DECODED_SYNC 0x00000001
#define RFX_DECODED_CONTEXT 0x00000002
#define RFX_DECODED_VERSIONS 0x00000004
#define RFX_DECODED_CHANNELS 0x00000008
#define RFX_DECODED_HEADERS 0x0000000F
typedef enum
{
RFX_STATE_INITIAL,
RFX_STATE_SERVER_UNINITIALIZED,
RFX_STATE_SEND_HEADERS,
RFX_STATE_SEND_FRAME_DATA,
RFX_STATE_FRAME_DATA_SENT,
RFX_STATE_FINAL
} RFX_STATE;
typedef struct S_RFX_TILE_COMPOSE_WORK_PARAM RFX_TILE_COMPOSE_WORK_PARAM;
typedef struct S_RFX_CONTEXT_PRIV RFX_CONTEXT_PRIV;
struct S_RFX_CONTEXT_PRIV
{
wLog* log;
wObjectPool* TilePool;
BOOL UseThreads;
PTP_WORK* workObjects;
RFX_TILE_COMPOSE_WORK_PARAM* tileWorkParams;
wBufferPool* BufferPool;
/* profilers */
PROFILER_DEFINE(prof_rfx_decode_rgb)
PROFILER_DEFINE(prof_rfx_decode_component)
PROFILER_DEFINE(prof_rfx_rlgr_decode)
PROFILER_DEFINE(prof_rfx_differential_decode)
PROFILER_DEFINE(prof_rfx_quantization_decode)
PROFILER_DEFINE(prof_rfx_dwt_2d_decode)
PROFILER_DEFINE(prof_rfx_ycbcr_to_rgb)
PROFILER_DEFINE(prof_rfx_encode_rgb)
PROFILER_DEFINE(prof_rfx_encode_component)
PROFILER_DEFINE(prof_rfx_rlgr_encode)
PROFILER_DEFINE(prof_rfx_differential_encode)
PROFILER_DEFINE(prof_rfx_quantization_encode)
PROFILER_DEFINE(prof_rfx_dwt_2d_encode)
PROFILER_DEFINE(prof_rfx_rgb_to_ycbcr)
PROFILER_DEFINE(prof_rfx_encode_format_rgb)
};
struct S_RFX_MESSAGE
{
UINT32 frameIdx;
/**
* The rects array represents the updated region of the frame. The UI
* requires to clip drawing destination base on the union of the rects.
*/
UINT16 numRects;
RFX_RECT* rects;
/**
* The tiles array represents the actual frame data. Each tile is always
* 64x64. Note that only pixels inside the updated region (represented as
* rects described above) are valid. Pixels outside of the region may
* contain arbitrary data.
*/
UINT16 numTiles;
size_t allocatedTiles;
RFX_TILE** tiles;
UINT16 numQuant;
UINT32* quantVals;
UINT32 tilesDataSize;
BOOL freeArray;
};
struct S_RFX_MESSAGE_LIST
{
struct S_RFX_MESSAGE* list;
size_t count;
RFX_CONTEXT* context;
};
struct S_RFX_CONTEXT
{
RFX_STATE state;
BOOL encoder;
UINT16 flags;
UINT16 properties;
UINT16 width;
UINT16 height;
RLGR_MODE mode;
UINT32 version;
UINT32 codec_id;
UINT32 codec_version;
UINT32 pixel_format;
BYTE bits_per_pixel;
/* color palette allocated by the application */
const BYTE* palette;
/* temporary data within a frame */
UINT32 frameIdx;
BYTE numQuant;
UINT32* quants;
BYTE quantIdxY;
BYTE quantIdxCb;
BYTE quantIdxCr;
/* decoded header blocks */
UINT32 decodedHeaderBlocks;
UINT16 expectedDataBlockType;
struct S_RFX_MESSAGE currentMessage;
/* routines */
void (*quantization_decode)(INT16* WINPR_RESTRICT buffer,
const UINT32* WINPR_RESTRICT quantization_values);
void (*quantization_encode)(INT16* WINPR_RESTRICT buffer,
const UINT32* WINPR_RESTRICT quantization_values);
void (*dwt_2d_decode)(INT16* WINPR_RESTRICT buffer, INT16* WINPR_RESTRICT dwt_buffer);
void (*dwt_2d_extrapolate_decode)(INT16* WINPR_RESTRICT src, INT16* WINPR_RESTRICT temp);
void (*dwt_2d_encode)(INT16* WINPR_RESTRICT buffer, INT16* WINPR_RESTRICT dwt_buffer);
WINPR_ATTR_NODISCARD int (*rlgr_decode)(RLGR_MODE mode, const BYTE* WINPR_RESTRICT data,
UINT32 data_size, INT16* WINPR_RESTRICT buffer,
UINT32 buffer_size);
WINPR_ATTR_NODISCARD int (*rlgr_encode)(RLGR_MODE mode, const INT16* WINPR_RESTRICT data,
UINT32 data_size, BYTE* WINPR_RESTRICT buffer,
UINT32 buffer_size);
/* private definitions */
RFX_CONTEXT_PRIV* priv;
};
#endif /* FREERDP_LIB_CODEC_RFX_TYPES_H */
+455
View File
@@ -0,0 +1,455 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* NSCodec Library - SSE2 Optimizations
*
* Copyright 2012 Vic Lee
*
* 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 <winpr/assert.h>
#include <winpr/cast.h>
#include <winpr/platform.h>
#include <freerdp/config.h>
#include "../nsc_types.h"
#include "nsc_sse2.h"
#include "../../core/simd.h"
#include "../../primitives/sse/prim_avxsse.h"
#if defined(SSE_AVX_INTRINSICS_ENABLED)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <xmmintrin.h>
#include <emmintrin.h>
#include <freerdp/codec/color.h>
#include <winpr/crt.h>
#include <winpr/sysinfo.h>
static inline size_t nsc_encode_next_bgrx32(const BYTE* src, __m128i* r_val, __m128i* g_val,
__m128i* b_val, __m128i* a_val)
{
*b_val = _mm_set_epi16(*(src + 28), *(src + 24), *(src + 20), *(src + 16), *(src + 12),
*(src + 8), *(src + 4), *src);
*g_val = _mm_set_epi16(*(src + 29), *(src + 25), *(src + 21), *(src + 17), *(src + 13),
*(src + 9), *(src + 5), *(src + 1));
*r_val = _mm_set_epi16(*(src + 30), *(src + 26), *(src + 22), *(src + 18), *(src + 14),
*(src + 10), *(src + 6), *(src + 2));
*a_val = _mm_set1_epi16(0xFF);
return 32;
}
static inline size_t nsc_encode_next_bgra32(const BYTE* src, __m128i* r_val, __m128i* g_val,
__m128i* b_val, __m128i* a_val)
{
*b_val = _mm_set_epi16(*(src + 28), *(src + 24), *(src + 20), *(src + 16), *(src + 12),
*(src + 8), *(src + 4), *src);
*g_val = _mm_set_epi16(*(src + 29), *(src + 25), *(src + 21), *(src + 17), *(src + 13),
*(src + 9), *(src + 5), *(src + 1));
*r_val = _mm_set_epi16(*(src + 30), *(src + 26), *(src + 22), *(src + 18), *(src + 14),
*(src + 10), *(src + 6), *(src + 2));
*a_val = _mm_set_epi16(*(src + 31), *(src + 27), *(src + 23), *(src + 19), *(src + 15),
*(src + 11), *(src + 7), *(src + 3));
return 32;
}
static inline size_t nsc_encode_next_rgbx32(const BYTE* src, __m128i* r_val, __m128i* g_val,
__m128i* b_val, __m128i* a_val)
{
*r_val = _mm_set_epi16(*(src + 28), *(src + 24), *(src + 20), *(src + 16), *(src + 12),
*(src + 8), *(src + 4), *src);
*g_val = _mm_set_epi16(*(src + 29), *(src + 25), *(src + 21), *(src + 17), *(src + 13),
*(src + 9), *(src + 5), *(src + 1));
*b_val = _mm_set_epi16(*(src + 30), *(src + 26), *(src + 22), *(src + 18), *(src + 14),
*(src + 10), *(src + 6), *(src + 2));
*a_val = _mm_set1_epi16(0xFF);
return 32;
}
static inline size_t nsc_encode_next_rgba32(const BYTE* src, __m128i* r_val, __m128i* g_val,
__m128i* b_val, __m128i* a_val)
{
*r_val = _mm_set_epi16(*(src + 28), *(src + 24), *(src + 20), *(src + 16), *(src + 12),
*(src + 8), *(src + 4), *src);
*g_val = _mm_set_epi16(*(src + 29), *(src + 25), *(src + 21), *(src + 17), *(src + 13),
*(src + 9), *(src + 5), *(src + 1));
*b_val = _mm_set_epi16(*(src + 30), *(src + 26), *(src + 22), *(src + 18), *(src + 14),
*(src + 10), *(src + 6), *(src + 2));
*a_val = _mm_set_epi16(*(src + 31), *(src + 27), *(src + 23), *(src + 19), *(src + 15),
*(src + 11), *(src + 7), *(src + 3));
return 32;
}
static inline size_t nsc_encode_next_bgr24(const BYTE* src, __m128i* r_val, __m128i* g_val,
__m128i* b_val, __m128i* a_val)
{
*b_val = _mm_set_epi16(*(src + 21), *(src + 18), *(src + 15), *(src + 12), *(src + 9),
*(src + 6), *(src + 3), *src);
*g_val = _mm_set_epi16(*(src + 22), *(src + 19), *(src + 16), *(src + 13), *(src + 10),
*(src + 7), *(src + 4), *(src + 1));
*r_val = _mm_set_epi16(*(src + 23), *(src + 20), *(src + 17), *(src + 14), *(src + 11),
*(src + 8), *(src + 5), *(src + 2));
*a_val = _mm_set1_epi16(0xFF);
return 24;
}
static inline size_t nsc_encode_next_rgb24(const BYTE* src, __m128i* r_val, __m128i* g_val,
__m128i* b_val, __m128i* a_val)
{
*r_val = _mm_set_epi16(*(src + 21), *(src + 18), *(src + 15), *(src + 12), *(src + 9),
*(src + 6), *(src + 3), *src);
*g_val = _mm_set_epi16(*(src + 22), *(src + 19), *(src + 16), *(src + 13), *(src + 10),
*(src + 7), *(src + 4), *(src + 1));
*b_val = _mm_set_epi16(*(src + 23), *(src + 20), *(src + 17), *(src + 14), *(src + 11),
*(src + 8), *(src + 5), *(src + 2));
*a_val = _mm_set1_epi16(0xFF);
return 24;
}
static inline size_t nsc_encode_next_bgr16(const BYTE* src, __m128i* r_val, __m128i* g_val,
__m128i* b_val, __m128i* a_val)
{
*b_val = _mm_set_epi16(
WINPR_ASSERTING_INT_CAST(INT16, ((*(src + 15)) & 0xF8) | ((*(src + 15)) >> 5)),
WINPR_ASSERTING_INT_CAST(INT16, ((*(src + 13)) & 0xF8) | ((*(src + 13)) >> 5)),
WINPR_ASSERTING_INT_CAST(INT16, ((*(src + 11)) & 0xF8) | ((*(src + 11)) >> 5)),
WINPR_ASSERTING_INT_CAST(INT16, ((*(src + 9)) & 0xF8) | ((*(src + 9)) >> 5)),
WINPR_ASSERTING_INT_CAST(INT16, ((*(src + 7)) & 0xF8) | ((*(src + 7)) >> 5)),
WINPR_ASSERTING_INT_CAST(INT16, ((*(src + 5)) & 0xF8) | ((*(src + 5)) >> 5)),
WINPR_ASSERTING_INT_CAST(INT16, ((*(src + 3)) & 0xF8) | ((*(src + 3)) >> 5)),
WINPR_ASSERTING_INT_CAST(INT16, ((*(src + 1)) & 0xF8) | ((*(src + 1)) >> 5)));
*g_val = _mm_set_epi16(
WINPR_ASSERTING_INT_CAST(INT16,
(((*(src + 15)) & 0x07) << 5) | (((*(src + 14)) & 0xE0) >> 3)),
WINPR_ASSERTING_INT_CAST(INT16,
(((*(src + 13)) & 0x07) << 5) | (((*(src + 12)) & 0xE0) >> 3)),
WINPR_ASSERTING_INT_CAST(INT16,
(((*(src + 11)) & 0x07) << 5) | (((*(src + 10)) & 0xE0) >> 3)),
WINPR_ASSERTING_INT_CAST(INT16,
(((*(src + 9)) & 0x07) << 5) | (((*(src + 8)) & 0xE0) >> 3)),
WINPR_ASSERTING_INT_CAST(INT16,
(((*(src + 7)) & 0x07) << 5) | (((*(src + 6)) & 0xE0) >> 3)),
WINPR_ASSERTING_INT_CAST(INT16,
(((*(src + 5)) & 0x07) << 5) | (((*(src + 4)) & 0xE0) >> 3)),
WINPR_ASSERTING_INT_CAST(INT16,
(((*(src + 3)) & 0x07) << 5) | (((*(src + 2)) & 0xE0) >> 3)),
WINPR_ASSERTING_INT_CAST(INT16, (((*(src + 1)) & 0x07) << 5) | (((*src) & 0xE0) >> 3)));
*r_val = _mm_set_epi16(
WINPR_ASSERTING_INT_CAST(INT16,
(((*(src + 14)) & 0x1F) << 3) | (((*(src + 14)) >> 2) & 0x07)),
WINPR_ASSERTING_INT_CAST(INT16,
(((*(src + 12)) & 0x1F) << 3) | (((*(src + 12)) >> 2) & 0x07)),
WINPR_ASSERTING_INT_CAST(INT16,
(((*(src + 10)) & 0x1F) << 3) | (((*(src + 10)) >> 2) & 0x07)),
WINPR_ASSERTING_INT_CAST(INT16,
(((*(src + 8)) & 0x1F) << 3) | (((*(src + 8)) >> 2) & 0x07)),
WINPR_ASSERTING_INT_CAST(INT16,
(((*(src + 6)) & 0x1F) << 3) | (((*(src + 6)) >> 2) & 0x07)),
WINPR_ASSERTING_INT_CAST(INT16,
(((*(src + 4)) & 0x1F) << 3) | (((*(src + 4)) >> 2) & 0x07)),
WINPR_ASSERTING_INT_CAST(INT16,
(((*(src + 2)) & 0x1F) << 3) | (((*(src + 2)) >> 2) & 0x07)),
WINPR_ASSERTING_INT_CAST(INT16, (((*src) & 0x1F) << 3) | (((*src) >> 2) & 0x07)));
*a_val = _mm_set1_epi16(0xFF);
return 16;
}
static inline size_t nsc_encode_next_rgb16(const BYTE* src, __m128i* r_val, __m128i* g_val,
__m128i* b_val, __m128i* a_val)
{
*r_val = _mm_set_epi16(WINPR_ASSERTING_INT_CAST(INT16, ((src[15] & 0xF8) | (src[15] >> 5))),
WINPR_ASSERTING_INT_CAST(INT16, ((src[13] & 0xF8) | (src[13] >> 5))),
WINPR_ASSERTING_INT_CAST(INT16, ((src[11] & 0xF8) | (src[11] >> 5))),
WINPR_ASSERTING_INT_CAST(INT16, ((src[9] & 0xF8) | (src[9] >> 5))),
WINPR_ASSERTING_INT_CAST(INT16, ((src[7] & 0xF8) | (src[7] >> 5))),
WINPR_ASSERTING_INT_CAST(INT16, ((src[5] & 0xF8) | (src[5] >> 5))),
WINPR_ASSERTING_INT_CAST(INT16, ((src[3] & 0xF8) | (src[3] >> 5))),
WINPR_ASSERTING_INT_CAST(INT16, ((src[1] & 0xF8) | (src[1] >> 5))));
*g_val = _mm_set_epi16(
WINPR_ASSERTING_INT_CAST(INT16,
(((*(src + 15)) & 0x07) << 5) | (((*(src + 14)) & 0xE0) >> 3)),
WINPR_ASSERTING_INT_CAST(INT16,
(((*(src + 13)) & 0x07) << 5) | (((*(src + 12)) & 0xE0) >> 3)),
WINPR_ASSERTING_INT_CAST(INT16,
(((*(src + 11)) & 0x07) << 5) | (((*(src + 10)) & 0xE0) >> 3)),
WINPR_ASSERTING_INT_CAST(INT16,
(((*(src + 9)) & 0x07) << 5) | (((*(src + 8)) & 0xE0) >> 3)),
WINPR_ASSERTING_INT_CAST(INT16,
(((*(src + 7)) & 0x07) << 5) | (((*(src + 6)) & 0xE0) >> 3)),
WINPR_ASSERTING_INT_CAST(INT16,
(((*(src + 5)) & 0x07) << 5) | (((*(src + 4)) & 0xE0) >> 3)),
WINPR_ASSERTING_INT_CAST(INT16,
(((*(src + 3)) & 0x07) << 5) | (((*(src + 2)) & 0xE0) >> 3)),
WINPR_ASSERTING_INT_CAST(INT16, (((*(src + 1)) & 0x07) << 5) | (((*src) & 0xE0) >> 3)));
*b_val = _mm_set_epi16(
WINPR_ASSERTING_INT_CAST(INT16,
(((*(src + 14)) & 0x1F) << 3) | (((*(src + 14)) >> 2) & 0x07)),
WINPR_ASSERTING_INT_CAST(INT16,
(((*(src + 12)) & 0x1F) << 3) | (((*(src + 12)) >> 2) & 0x07)),
WINPR_ASSERTING_INT_CAST(INT16,
(((*(src + 10)) & 0x1F) << 3) | (((*(src + 10)) >> 2) & 0x07)),
WINPR_ASSERTING_INT_CAST(INT16,
(((*(src + 8)) & 0x1F) << 3) | (((*(src + 8)) >> 2) & 0x07)),
WINPR_ASSERTING_INT_CAST(INT16,
(((*(src + 6)) & 0x1F) << 3) | (((*(src + 6)) >> 2) & 0x07)),
WINPR_ASSERTING_INT_CAST(INT16,
(((*(src + 4)) & 0x1F) << 3) | (((*(src + 4)) >> 2) & 0x07)),
WINPR_ASSERTING_INT_CAST(INT16,
(((*(src + 2)) & 0x1F) << 3) | (((*(src + 2)) >> 2) & 0x07)),
WINPR_ASSERTING_INT_CAST(INT16, (((*src) & 0x1F) << 3) | (((*src) >> 2) & 0x07)));
*a_val = _mm_set1_epi16(0xFF);
return 16;
}
static inline size_t nsc_encode_next_a4(const BYTE* src, const BYTE* palette, __m128i* r_val,
__m128i* g_val, __m128i* b_val, __m128i* a_val)
{
BYTE idx[8] = WINPR_C_ARRAY_INIT;
for (int shift = 7; shift >= 0; shift--)
{
idx[shift] = ((*src) >> shift) & 1;
idx[shift] |= (((*(src + 1)) >> shift) & 1) << 1;
idx[shift] |= (((*(src + 2)) >> shift) & 1) << 2;
idx[shift] |= (((*(src + 3)) >> shift) & 1) << 3;
idx[shift] *= 3;
}
*r_val = _mm_set_epi16(palette[idx[0]], palette[idx[1]], palette[idx[2]], palette[idx[3]],
palette[idx[4]], palette[idx[5]], palette[idx[6]], palette[idx[7]]);
*g_val = _mm_set_epi16(palette[idx[0] + 1], palette[idx[1] + 1], palette[idx[2] + 1],
palette[idx[3] + 1], palette[idx[4] + 1], palette[idx[5] + 1],
palette[idx[6] + 1], palette[idx[7] + 1]);
*b_val = _mm_set_epi16(palette[idx[0] + 2], palette[idx[1] + 2], palette[idx[2] + 2],
palette[idx[3] + 2], palette[idx[4] + 2], palette[idx[5] + 2],
palette[idx[6] + 2], palette[idx[7] + 2]);
*a_val = _mm_set1_epi16(0xFF);
return 4;
}
static inline size_t nsc_encode_next_rgb8(const BYTE* src, const BYTE* palette, __m128i* r_val,
__m128i* g_val, __m128i* b_val, __m128i* a_val)
{
*r_val = _mm_set_epi16(palette[(*(src + 7ULL)) * 3ULL], palette[(*(src + 6ULL)) * 3ULL],
palette[(*(src + 5ULL)) * 3ULL], palette[(*(src + 4ULL)) * 3ULL],
palette[(*(src + 3ULL)) * 3ULL], palette[(*(src + 2ULL)) * 3ULL],
palette[(*(src + 1ULL)) * 3ULL], palette[(*src) * 3ULL]);
*g_val = _mm_set_epi16(
palette[(*(src + 7ULL)) * 3ULL + 1ULL], palette[(*(src + 6ULL)) * 3ULL + 1ULL],
palette[(*(src + 5ULL)) * 3ULL + 1ULL], palette[(*(src + 4ULL)) * 3ULL + 1ULL],
palette[(*(src + 3ULL)) * 3ULL + 1ULL], palette[(*(src + 2ULL)) * 3ULL + 1ULL],
palette[(*(src + 1ULL)) * 3ULL + 1ULL], palette[(*src) * 3ULL + 1ULL]);
*b_val = _mm_set_epi16(
palette[(*(src + 7ULL)) * 3ULL + 2ULL], palette[(*(src + 6ULL)) * 3ULL + 2ULL],
palette[(*(src + 5ULL)) * 3ULL + 2ULL], palette[(*(src + 4ULL)) * 3ULL + 2ULL],
palette[(*(src + 3ULL)) * 3ULL + 2ULL], palette[(*(src + 2ULL)) * 3ULL + 2ULL],
palette[(*(src + 1ULL)) * 3ULL + 2ULL], palette[(*src) * 3ULL + 2ULL]);
*a_val = _mm_set1_epi16(0xFF);
return 8;
}
static inline size_t nsc_encode_next_rgba(UINT32 format, const BYTE* src, const BYTE* palette,
__m128i* r_val, __m128i* g_val, __m128i* b_val,
__m128i* a_val)
{
switch (format)
{
case PIXEL_FORMAT_BGRX32:
return nsc_encode_next_bgrx32(src, r_val, g_val, b_val, a_val);
case PIXEL_FORMAT_BGRA32:
return nsc_encode_next_bgra32(src, r_val, g_val, b_val, a_val);
case PIXEL_FORMAT_RGBX32:
return nsc_encode_next_rgbx32(src, r_val, g_val, b_val, a_val);
case PIXEL_FORMAT_RGBA32:
return nsc_encode_next_rgba32(src, r_val, g_val, b_val, a_val);
case PIXEL_FORMAT_BGR24:
return nsc_encode_next_bgr24(src, r_val, g_val, b_val, a_val);
case PIXEL_FORMAT_RGB24:
return nsc_encode_next_rgb24(src, r_val, g_val, b_val, a_val);
case PIXEL_FORMAT_BGR16:
return nsc_encode_next_bgr16(src, r_val, g_val, b_val, a_val);
case PIXEL_FORMAT_RGB16:
return nsc_encode_next_rgb16(src, r_val, g_val, b_val, a_val);
case PIXEL_FORMAT_A4:
return nsc_encode_next_a4(src, palette, r_val, g_val, b_val, a_val);
case PIXEL_FORMAT_RGB8:
return nsc_encode_next_rgb8(src, palette, r_val, g_val, b_val, a_val);
default:
return 0;
}
}
static BOOL nsc_encode_argb_to_aycocg_sse2(NSC_CONTEXT* context, const BYTE* data, UINT32 scanline)
{
size_t y = 0;
if (!context || !data || (scanline == 0))
return FALSE;
const UINT16 tempWidth = ROUND_UP_TO(context->width, 8);
const UINT16 rw = (context->ChromaSubsamplingLevel > 0 ? tempWidth : context->width);
const BYTE ccl = WINPR_ASSERTING_INT_CAST(BYTE, context->ColorLossLevel);
for (; y < context->height; y++)
{
const BYTE* src = data + (context->height - 1 - y) * scanline;
BYTE* yplane = context->priv->PlaneBuffers[0] + y * rw;
BYTE* coplane = context->priv->PlaneBuffers[1] + y * rw;
BYTE* cgplane = context->priv->PlaneBuffers[2] + y * rw;
BYTE* aplane = context->priv->PlaneBuffers[3] + y * context->width;
for (UINT16 x = 0; x < context->width; x += 8)
{
__m128i r_val = WINPR_C_ARRAY_INIT;
__m128i g_val = WINPR_C_ARRAY_INIT;
__m128i b_val = WINPR_C_ARRAY_INIT;
__m128i a_val = WINPR_C_ARRAY_INIT;
const size_t rc = nsc_encode_next_rgba(context->format, src, context->palette, &r_val,
&g_val, &b_val, &a_val);
src += rc;
__m128i y_val = _mm_srai_epi16(r_val, 2);
y_val = _mm_add_epi16(y_val, _mm_srai_epi16(g_val, 1));
y_val = _mm_add_epi16(y_val, _mm_srai_epi16(b_val, 2));
__m128i co_val = _mm_sub_epi16(r_val, b_val);
co_val = _mm_srai_epi16(co_val, ccl);
__m128i cg_val = _mm_sub_epi16(g_val, _mm_srai_epi16(r_val, 1));
cg_val = _mm_sub_epi16(cg_val, _mm_srai_epi16(b_val, 1));
cg_val = _mm_srai_epi16(cg_val, ccl);
y_val = _mm_packus_epi16(y_val, y_val);
STORE_SI128(yplane, y_val);
co_val = _mm_packs_epi16(co_val, co_val);
STORE_SI128(coplane, co_val);
cg_val = _mm_packs_epi16(cg_val, cg_val);
STORE_SI128(cgplane, cg_val);
a_val = _mm_packus_epi16(a_val, a_val);
STORE_SI128(aplane, a_val);
yplane += 8;
coplane += 8;
cgplane += 8;
aplane += 8;
}
if (context->ChromaSubsamplingLevel > 0 && (context->width % 2) == 1)
{
context->priv->PlaneBuffers[0][y * rw + context->width] =
context->priv->PlaneBuffers[0][y * rw + context->width - 1];
context->priv->PlaneBuffers[1][y * rw + context->width] =
context->priv->PlaneBuffers[1][y * rw + context->width - 1];
context->priv->PlaneBuffers[2][y * rw + context->width] =
context->priv->PlaneBuffers[2][y * rw + context->width - 1];
}
}
if (context->ChromaSubsamplingLevel > 0 && (y % 2) == 1)
{
BYTE* yplane = context->priv->PlaneBuffers[0] + y * rw;
BYTE* coplane = context->priv->PlaneBuffers[1] + y * rw;
BYTE* cgplane = context->priv->PlaneBuffers[2] + y * rw;
CopyMemory(yplane, yplane - rw, rw);
CopyMemory(coplane, coplane - rw, rw);
CopyMemory(cgplane, cgplane - rw, rw);
}
return TRUE;
}
static void nsc_encode_subsampling_sse2(NSC_CONTEXT* context)
{
BYTE* co_dst = nullptr;
BYTE* cg_dst = nullptr;
INT8* co_src0 = nullptr;
INT8* co_src1 = nullptr;
INT8* cg_src0 = nullptr;
INT8* cg_src1 = nullptr;
UINT32 tempWidth = 0;
UINT32 tempHeight = 0;
__m128i t;
__m128i val;
__m128i mask = _mm_set1_epi16(0xFF);
tempWidth = ROUND_UP_TO(context->width, 8);
tempHeight = ROUND_UP_TO(context->height, 2);
for (size_t y = 0; y < tempHeight >> 1; y++)
{
co_dst = context->priv->PlaneBuffers[1] + y * (tempWidth >> 1);
cg_dst = context->priv->PlaneBuffers[2] + y * (tempWidth >> 1);
co_src0 = (INT8*)context->priv->PlaneBuffers[1] + (y << 1) * tempWidth;
co_src1 = co_src0 + tempWidth;
cg_src0 = (INT8*)context->priv->PlaneBuffers[2] + (y << 1) * tempWidth;
cg_src1 = cg_src0 + tempWidth;
for (UINT32 x = 0; x < tempWidth >> 1; x += 8)
{
t = LOAD_SI128(co_src0);
t = _mm_avg_epu8(t, LOAD_SI128(co_src1));
val = _mm_and_si128(_mm_srli_si128(t, 1), mask);
val = _mm_avg_epu16(val, _mm_and_si128(t, mask));
val = _mm_packus_epi16(val, val);
STORE_SI128(co_dst, val);
co_dst += 8;
co_src0 += 16;
co_src1 += 16;
t = LOAD_SI128(cg_src0);
t = _mm_avg_epu8(t, LOAD_SI128(cg_src1));
val = _mm_and_si128(_mm_srli_si128(t, 1), mask);
val = _mm_avg_epu16(val, _mm_and_si128(t, mask));
val = _mm_packus_epi16(val, val);
STORE_SI128(cg_dst, val);
cg_dst += 8;
cg_src0 += 16;
cg_src1 += 16;
}
}
}
static BOOL nsc_encode_sse2(NSC_CONTEXT* WINPR_RESTRICT context, const BYTE* WINPR_RESTRICT data,
UINT32 scanline)
{
if (!nsc_encode_argb_to_aycocg_sse2(context, data, scanline))
return FALSE;
if (context->ChromaSubsamplingLevel > 0)
nsc_encode_subsampling_sse2(context);
return TRUE;
}
#endif
void nsc_init_sse2_int(NSC_CONTEXT* WINPR_RESTRICT context)
{
#if defined(SSE_AVX_INTRINSICS_ENABLED)
WLog_VRB(PRIM_TAG, "SSE2/SSE3 optimizations");
PROFILER_RENAME(context->priv->prof_nsc_encode, "nsc_encode_sse2")
context->encode = nsc_encode_sse2;
#else
WLog_VRB(PRIM_TAG, "undefined WITH_SIMD or SSE2 intrinsics not available");
WINPR_UNUSED(context);
#endif
}
+38
View File
@@ -0,0 +1,38 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* NSCodec Library - SSE2 Optimizations
*
* Copyright 2012 Vic Lee
*
* 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 FREERDP_LIB_CODEC_NSC_SSE2_H
#define FREERDP_LIB_CODEC_NSC_SSE2_H
#include <winpr/sysinfo.h>
#include <freerdp/codec/nsc.h>
#include <freerdp/api.h>
FREERDP_LOCAL void nsc_init_sse2_int(NSC_CONTEXT* WINPR_RESTRICT context);
static inline void nsc_init_sse2(NSC_CONTEXT* WINPR_RESTRICT context)
{
if (!IsProcessorFeaturePresent(PF_SSE2_INSTRUCTIONS_AVAILABLE) ||
!IsProcessorFeaturePresent(PF_SSE3_INSTRUCTIONS_AVAILABLE))
return;
nsc_init_sse2_int(context);
}
#endif /* FREERDP_LIB_CODEC_NSC_SSE2_H */
+470
View File
@@ -0,0 +1,470 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* RemoteFX Codec Library - SSE2 Optimizations
*
* Copyright 2011 Stephen Erisman
* Copyright 2011 Norbert Federa <norbert.federa@thincast.com>
*
* 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 <winpr/assert.h>
#include <winpr/cast.h>
#include <winpr/platform.h>
#include <freerdp/config.h>
#include "../rfx_types.h"
#include "rfx_sse2.h"
#include "../../core/simd.h"
#include "../../primitives/sse/prim_avxsse.h"
#if defined(SSE_AVX_INTRINSICS_ENABLED)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winpr/sysinfo.h>
#include <xmmintrin.h>
#include <emmintrin.h>
#ifdef _MSC_VER
#define __attribute__(...)
#endif
#define CACHE_LINE_BYTES 64
#ifndef __clang__
#define ATTRIBUTES __gnu_inline__, __always_inline__, __artificial__
#else
#define ATTRIBUTES __gnu_inline__, __always_inline__
#endif
static inline void __attribute__((ATTRIBUTES)) mm_prefetch_buffer(char* WINPR_RESTRICT buffer,
size_t num_bytes)
{
__m128i* buf = (__m128i*)buffer;
for (size_t i = 0; i < (num_bytes / sizeof(__m128i)); i += (CACHE_LINE_BYTES / sizeof(__m128i)))
{
_mm_prefetch((char*)(&buf[i]), _MM_HINT_NTA);
}
}
/* rfx_decode_ycbcr_to_rgb_sse2 code now resides in the primitives library. */
/* rfx_encode_rgb_to_ycbcr_sse2 code now resides in the primitives library. */
static inline void __attribute__((ATTRIBUTES))
rfx_quantization_decode_block_sse2(INT16* WINPR_RESTRICT buffer, const size_t buffer_size,
const UINT32 factor)
{
__m128i* ptr = (__m128i*)buffer;
const __m128i* buf_end = (__m128i*)(buffer + buffer_size);
if (factor == 0)
return;
do
{
const __m128i la = LOAD_SI128(ptr);
const __m128i a = _mm_slli_epi16(la, WINPR_ASSERTING_INT_CAST(int, factor));
STORE_SI128(ptr, a);
ptr++;
} while (ptr < buf_end);
}
static void rfx_quantization_decode_sse2(INT16* WINPR_RESTRICT buffer,
const UINT32* WINPR_RESTRICT quantVals)
{
WINPR_ASSERT(buffer);
WINPR_ASSERT(quantVals);
mm_prefetch_buffer((char*)buffer, 4096 * sizeof(INT16));
rfx_quantization_decode_block_sse2(&buffer[0], 1024, quantVals[8] - 1); /* HL1 */
rfx_quantization_decode_block_sse2(&buffer[1024], 1024, quantVals[7] - 1); /* LH1 */
rfx_quantization_decode_block_sse2(&buffer[2048], 1024, quantVals[9] - 1); /* HH1 */
rfx_quantization_decode_block_sse2(&buffer[3072], 256, quantVals[5] - 1); /* HL2 */
rfx_quantization_decode_block_sse2(&buffer[3328], 256, quantVals[4] - 1); /* LH2 */
rfx_quantization_decode_block_sse2(&buffer[3584], 256, quantVals[6] - 1); /* HH2 */
rfx_quantization_decode_block_sse2(&buffer[3840], 64, quantVals[2] - 1); /* HL3 */
rfx_quantization_decode_block_sse2(&buffer[3904], 64, quantVals[1] - 1); /* LH3 */
rfx_quantization_decode_block_sse2(&buffer[3968], 64, quantVals[3] - 1); /* HH3 */
rfx_quantization_decode_block_sse2(&buffer[4032], 64, quantVals[0] - 1); /* LL3 */
}
static inline void __attribute__((ATTRIBUTES))
rfx_quantization_encode_block_sse2(INT16* WINPR_RESTRICT buffer, const unsigned buffer_size,
const INT16 factor)
{
__m128i* ptr = (__m128i*)buffer;
const __m128i* buf_end = (const __m128i*)(buffer + buffer_size);
if (factor == 0)
return;
const __m128i half = _mm_set1_epi16(WINPR_ASSERTING_INT_CAST(INT16, 1 << (factor - 1)));
do
{
const __m128i la = LOAD_SI128(ptr);
__m128i a = _mm_add_epi16(la, half);
a = _mm_srai_epi16(a, factor);
STORE_SI128(ptr, a);
ptr++;
} while (ptr < buf_end);
}
static void rfx_quantization_encode_sse2(INT16* WINPR_RESTRICT buffer,
const UINT32* WINPR_RESTRICT quantization_values)
{
WINPR_ASSERT(buffer);
WINPR_ASSERT(quantization_values);
for (size_t x = 0; x < 10; x++)
{
WINPR_ASSERT(quantization_values[x] >= 6);
WINPR_ASSERT(quantization_values[x] <= INT16_MAX + 6);
}
mm_prefetch_buffer((char*)buffer, 4096 * sizeof(INT16));
rfx_quantization_encode_block_sse2(
buffer, 1024, WINPR_ASSERTING_INT_CAST(INT16, quantization_values[8] - 6)); /* HL1 */
rfx_quantization_encode_block_sse2(
buffer + 1024, 1024, WINPR_ASSERTING_INT_CAST(INT16, quantization_values[7] - 6)); /* LH1 */
rfx_quantization_encode_block_sse2(
buffer + 2048, 1024, WINPR_ASSERTING_INT_CAST(INT16, quantization_values[9] - 6)); /* HH1 */
rfx_quantization_encode_block_sse2(
buffer + 3072, 256, WINPR_ASSERTING_INT_CAST(INT16, quantization_values[5] - 6)); /* HL2 */
rfx_quantization_encode_block_sse2(
buffer + 3328, 256, WINPR_ASSERTING_INT_CAST(INT16, quantization_values[4] - 6)); /* LH2 */
rfx_quantization_encode_block_sse2(
buffer + 3584, 256, WINPR_ASSERTING_INT_CAST(INT16, quantization_values[6] - 6)); /* HH2 */
rfx_quantization_encode_block_sse2(
buffer + 3840, 64, WINPR_ASSERTING_INT_CAST(INT16, quantization_values[2] - 6)); /* HL3 */
rfx_quantization_encode_block_sse2(
buffer + 3904, 64, WINPR_ASSERTING_INT_CAST(INT16, quantization_values[1] - 6)); /* LH3 */
rfx_quantization_encode_block_sse2(
buffer + 3968, 64, WINPR_ASSERTING_INT_CAST(INT16, quantization_values[3] - 6)); /* HH3 */
rfx_quantization_encode_block_sse2(
buffer + 4032, 64, WINPR_ASSERTING_INT_CAST(INT16, quantization_values[0] - 6)); /* LL3 */
rfx_quantization_encode_block_sse2(buffer, 4096, 5);
}
static inline void __attribute__((ATTRIBUTES))
rfx_dwt_2d_decode_block_horiz_sse2(INT16* WINPR_RESTRICT l, INT16* WINPR_RESTRICT h,
INT16* WINPR_RESTRICT dst, size_t subband_width)
{
INT16* l_ptr = l;
INT16* h_ptr = h;
INT16* dst_ptr = dst;
int first = 0;
int last = 0;
__m128i dst1;
__m128i dst2;
for (size_t y = 0; y < subband_width; y++)
{
/* Even coefficients */
for (size_t n = 0; n < subband_width; n += 8)
{
/* dst[2n] = l[n] - ((h[n-1] + h[n] + 1) >> 1); */
__m128i l_n = LOAD_SI128(l_ptr);
__m128i h_n = LOAD_SI128(h_ptr);
__m128i h_n_m = LOAD_SI128(h_ptr - 1);
if (n == 0)
{
first = _mm_extract_epi16(h_n_m, 1);
h_n_m = _mm_insert_epi16(h_n_m, first, 0);
}
__m128i tmp_n = _mm_add_epi16(h_n, h_n_m);
tmp_n = _mm_add_epi16(tmp_n, _mm_set1_epi16(1));
tmp_n = _mm_srai_epi16(tmp_n, 1);
const __m128i dst_n = _mm_sub_epi16(l_n, tmp_n);
STORE_SI128(l_ptr, dst_n);
l_ptr += 8;
h_ptr += 8;
}
l_ptr -= subband_width;
h_ptr -= subband_width;
/* Odd coefficients */
for (size_t n = 0; n < subband_width; n += 8)
{
/* dst[2n + 1] = (h[n] << 1) + ((dst[2n] + dst[2n + 2]) >> 1); */
__m128i h_n = LOAD_SI128(h_ptr);
h_n = _mm_slli_epi16(h_n, 1);
__m128i dst_n = LOAD_SI128(l_ptr);
__m128i dst_n_p = LOAD_SI128(l_ptr + 1);
if (n == subband_width - 8)
{
last = _mm_extract_epi16(dst_n_p, 6);
dst_n_p = _mm_insert_epi16(dst_n_p, last, 7);
}
__m128i tmp_n = _mm_add_epi16(dst_n_p, dst_n);
tmp_n = _mm_srai_epi16(tmp_n, 1);
tmp_n = _mm_add_epi16(tmp_n, h_n);
dst1 = _mm_unpacklo_epi16(dst_n, tmp_n);
dst2 = _mm_unpackhi_epi16(dst_n, tmp_n);
STORE_SI128(dst_ptr, dst1);
STORE_SI128(dst_ptr + 8, dst2);
l_ptr += 8;
h_ptr += 8;
dst_ptr += 16;
}
}
}
static inline void __attribute__((ATTRIBUTES))
rfx_dwt_2d_decode_block_vert_sse2(INT16* WINPR_RESTRICT l, INT16* WINPR_RESTRICT h,
INT16* WINPR_RESTRICT dst, size_t subband_width)
{
INT16* l_ptr = l;
INT16* h_ptr = h;
INT16* dst_ptr = dst;
const size_t total_width = subband_width + subband_width;
/* Even coefficients */
for (size_t n = 0; n < subband_width; n++)
{
for (size_t x = 0; x < total_width; x += 8)
{
/* dst[2n] = l[n] - ((h[n-1] + h[n] + 1) >> 1); */
const __m128i l_n = LOAD_SI128(l_ptr);
const __m128i h_n = LOAD_SI128(h_ptr);
__m128i tmp_n = _mm_add_epi16(h_n, _mm_set1_epi16(1));
if (n == 0)
tmp_n = _mm_add_epi16(tmp_n, h_n);
else
{
const __m128i h_n_m = LOAD_SI128(h_ptr - total_width);
tmp_n = _mm_add_epi16(tmp_n, h_n_m);
}
tmp_n = _mm_srai_epi16(tmp_n, 1);
const __m128i dst_n = _mm_sub_epi16(l_n, tmp_n);
STORE_SI128(dst_ptr, dst_n);
l_ptr += 8;
h_ptr += 8;
dst_ptr += 8;
}
dst_ptr += total_width;
}
h_ptr = h;
dst_ptr = dst + total_width;
/* Odd coefficients */
for (size_t n = 0; n < subband_width; n++)
{
for (size_t x = 0; x < total_width; x += 8)
{
/* dst[2n + 1] = (h[n] << 1) + ((dst[2n] + dst[2n + 2]) >> 1); */
__m128i h_n = LOAD_SI128(h_ptr);
__m128i dst_n_m = LOAD_SI128(dst_ptr - total_width);
h_n = _mm_slli_epi16(h_n, 1);
__m128i tmp_n = dst_n_m;
if (n == subband_width - 1)
tmp_n = _mm_add_epi16(tmp_n, dst_n_m);
else
{
const __m128i dst_n_p = LOAD_SI128(dst_ptr + total_width);
tmp_n = _mm_add_epi16(tmp_n, dst_n_p);
}
tmp_n = _mm_srai_epi16(tmp_n, 1);
const __m128i dst_n = _mm_add_epi16(tmp_n, h_n);
STORE_SI128(dst_ptr, dst_n);
h_ptr += 8;
dst_ptr += 8;
}
dst_ptr += total_width;
}
}
static inline void __attribute__((ATTRIBUTES))
rfx_dwt_2d_decode_block_sse2(INT16* WINPR_RESTRICT buffer, INT16* WINPR_RESTRICT idwt,
size_t subband_width)
{
mm_prefetch_buffer((char*)idwt, 4ULL * subband_width * sizeof(INT16));
/* Inverse DWT in horizontal direction, results in 2 sub-bands in L, H order in tmp buffer idwt.
*/
/* The 4 sub-bands are stored in HL(0), LH(1), HH(2), LL(3) order. */
/* The lower part L uses LL(3) and HL(0). */
/* The higher part H uses LH(1) and HH(2). */
INT16* ll = buffer + 3ULL * subband_width * subband_width;
INT16* hl = buffer;
INT16* l_dst = idwt;
rfx_dwt_2d_decode_block_horiz_sse2(ll, hl, l_dst, subband_width);
INT16* lh = buffer + 1ULL * subband_width * subband_width;
INT16* hh = buffer + 2ULL * subband_width * subband_width;
INT16* h_dst = idwt + 2ULL * subband_width * subband_width;
rfx_dwt_2d_decode_block_horiz_sse2(lh, hh, h_dst, subband_width);
/* Inverse DWT in vertical direction, results are stored in original buffer. */
rfx_dwt_2d_decode_block_vert_sse2(l_dst, h_dst, buffer, subband_width);
}
static void rfx_dwt_2d_decode_sse2(INT16* WINPR_RESTRICT buffer, INT16* WINPR_RESTRICT dwt_buffer)
{
WINPR_ASSERT(buffer);
WINPR_ASSERT(dwt_buffer);
mm_prefetch_buffer((char*)buffer, 4096 * sizeof(INT16));
rfx_dwt_2d_decode_block_sse2(&buffer[3840], dwt_buffer, 8);
rfx_dwt_2d_decode_block_sse2(&buffer[3072], dwt_buffer, 16);
rfx_dwt_2d_decode_block_sse2(&buffer[0], dwt_buffer, 32);
}
static inline void __attribute__((ATTRIBUTES))
rfx_dwt_2d_encode_block_vert_sse2(INT16* WINPR_RESTRICT src, INT16* WINPR_RESTRICT l,
INT16* WINPR_RESTRICT h, size_t subband_width)
{
const size_t total_width = subband_width << 1;
for (size_t n = 0; n < subband_width; n++)
{
for (size_t x = 0; x < total_width; x += 8)
{
__m128i src_2n = LOAD_SI128(src);
__m128i src_2n_1 = LOAD_SI128(src + total_width);
__m128i src_2n_2 = src_2n;
if (n < subband_width - 1)
src_2n_2 = LOAD_SI128(src + 2ULL * total_width);
/* h[n] = (src[2n + 1] - ((src[2n] + src[2n + 2]) >> 1)) >> 1 */
__m128i h_n = _mm_add_epi16(src_2n, src_2n_2);
h_n = _mm_srai_epi16(h_n, 1);
h_n = _mm_sub_epi16(src_2n_1, h_n);
h_n = _mm_srai_epi16(h_n, 1);
STORE_SI128(h, h_n);
__m128i h_n_m = h_n;
if (n != 0)
h_n_m = LOAD_SI128(h - total_width);
/* l[n] = src[2n] + ((h[n - 1] + h[n]) >> 1) */
__m128i l_n = _mm_add_epi16(h_n_m, h_n);
l_n = _mm_srai_epi16(l_n, 1);
l_n = _mm_add_epi16(l_n, src_2n);
STORE_SI128(l, l_n);
src += 8;
l += 8;
h += 8;
}
src += total_width;
}
}
static inline void __attribute__((ATTRIBUTES))
rfx_dwt_2d_encode_block_horiz_sse2(INT16* WINPR_RESTRICT src, INT16* WINPR_RESTRICT l,
INT16* WINPR_RESTRICT h, size_t subband_width)
{
for (size_t y = 0; y < subband_width; y++)
{
for (size_t n = 0; n < subband_width; n += 8)
{
/* The following 3 Set operations consumes more than half of the total DWT processing
* time! */
const INT16 src16 = (INT16)(((n + 8) == subband_width) ? src[14] : src[16]);
__m128i src_2n =
_mm_set_epi16(src[14], src[12], src[10], src[8], src[6], src[4], src[2], src[0]);
__m128i src_2n_1 =
_mm_set_epi16(src[15], src[13], src[11], src[9], src[7], src[5], src[3], src[1]);
__m128i src_2n_2 =
_mm_set_epi16(src16, src[14], src[12], src[10], src[8], src[6], src[4], src[2]);
/* h[n] = (src[2n + 1] - ((src[2n] + src[2n + 2]) >> 1)) >> 1 */
__m128i h_n = _mm_add_epi16(src_2n, src_2n_2);
h_n = _mm_srai_epi16(h_n, 1);
h_n = _mm_sub_epi16(src_2n_1, h_n);
h_n = _mm_srai_epi16(h_n, 1);
STORE_SI128(h, h_n);
__m128i h_n_m = LOAD_SI128(h - 1);
if (n == 0)
{
int first = _mm_extract_epi16(h_n_m, 1);
h_n_m = _mm_insert_epi16(h_n_m, first, 0);
}
/* l[n] = src[2n] + ((h[n - 1] + h[n]) >> 1) */
__m128i l_n = _mm_add_epi16(h_n_m, h_n);
l_n = _mm_srai_epi16(l_n, 1);
l_n = _mm_add_epi16(l_n, src_2n);
STORE_SI128(l, l_n);
src += 16;
l += 8;
h += 8;
}
}
}
static inline void __attribute__((ATTRIBUTES))
rfx_dwt_2d_encode_block_sse2(INT16* WINPR_RESTRICT buffer, INT16* WINPR_RESTRICT dwt,
size_t subband_width)
{
mm_prefetch_buffer((char*)dwt, 4ULL * subband_width * sizeof(INT16));
/* DWT in vertical direction, results in 2 sub-bands in L, H order in tmp buffer dwt. */
INT16* l_src = dwt;
INT16* h_src = dwt + 2ULL * subband_width * subband_width;
rfx_dwt_2d_encode_block_vert_sse2(buffer, l_src, h_src, subband_width);
/* DWT in horizontal direction, results in 4 sub-bands in HL(0), LH(1), HH(2), LL(3) order,
* stored in original buffer. */
/* The lower part L generates LL(3) and HL(0). */
/* The higher part H generates LH(1) and HH(2). */
INT16* ll = buffer + 3ULL * subband_width * subband_width;
INT16* hl = buffer;
INT16* lh = buffer + 1ULL * subband_width * subband_width;
INT16* hh = buffer + 2ULL * subband_width * subband_width;
rfx_dwt_2d_encode_block_horiz_sse2(l_src, ll, hl, subband_width);
rfx_dwt_2d_encode_block_horiz_sse2(h_src, lh, hh, subband_width);
}
static void rfx_dwt_2d_encode_sse2(INT16* WINPR_RESTRICT buffer, INT16* WINPR_RESTRICT dwt_buffer)
{
WINPR_ASSERT(buffer);
WINPR_ASSERT(dwt_buffer);
mm_prefetch_buffer((char*)buffer, 4096 * sizeof(INT16));
rfx_dwt_2d_encode_block_sse2(buffer, dwt_buffer, 32);
rfx_dwt_2d_encode_block_sse2(buffer + 3072, dwt_buffer, 16);
rfx_dwt_2d_encode_block_sse2(buffer + 3840, dwt_buffer, 8);
}
#endif
void rfx_init_sse2_int(RFX_CONTEXT* WINPR_RESTRICT context)
{
#if defined(SSE_AVX_INTRINSICS_ENABLED)
WLog_VRB(PRIM_TAG, "SSE2/SSE3 optimizations");
PROFILER_RENAME(context->priv->prof_rfx_quantization_decode, "rfx_quantization_decode_sse2")
PROFILER_RENAME(context->priv->prof_rfx_quantization_encode, "rfx_quantization_encode_sse2")
PROFILER_RENAME(context->priv->prof_rfx_dwt_2d_decode, "rfx_dwt_2d_decode_sse2")
PROFILER_RENAME(context->priv->prof_rfx_dwt_2d_encode, "rfx_dwt_2d_encode_sse2")
context->quantization_decode = rfx_quantization_decode_sse2;
context->quantization_encode = rfx_quantization_encode_sse2;
context->dwt_2d_decode = rfx_dwt_2d_decode_sse2;
context->dwt_2d_encode = rfx_dwt_2d_encode_sse2;
#else
WINPR_UNUSED(context);
WLog_VRB(PRIM_TAG, "undefined WITH_SIMD or SSE2 intrinsics not available");
#endif
}
+39
View File
@@ -0,0 +1,39 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* RemoteFX Codec Library - SSE2 Optimizations
*
* Copyright 2011 Stephen Erisman
*
* 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 FREERDP_LIB_CODEC_RFX_SSE2_H
#define FREERDP_LIB_CODEC_RFX_SSE2_H
#include <winpr/sysinfo.h>
#include <freerdp/codec/rfx.h>
#include <freerdp/api.h>
FREERDP_LOCAL void rfx_init_sse2_int(RFX_CONTEXT* WINPR_RESTRICT context);
static inline void rfx_init_sse2(RFX_CONTEXT* WINPR_RESTRICT context)
{
if (!IsProcessorFeaturePresent(PF_SSE2_INSTRUCTIONS_AVAILABLE) ||
!IsProcessorFeaturePresent(PF_SSE3_INSTRUCTIONS_AVAILABLE))
return;
rfx_init_sse2_int(context);
}
#endif /* FREERDP_LIB_CODEC_RFX_SSE2_H */
@@ -0,0 +1,88 @@
set(MODULE_NAME "TestFreeRDPCodec")
set(MODULE_PREFIX "TEST_FREERDP_CODEC")
disable_warnings_for_directory(${CMAKE_CURRENT_BINARY_DIR})
set(DRIVER ${MODULE_NAME}.c)
set(TEST_COMMON TestFreeRDPHelpers.c TestFreeRDPHelpers.h)
set(TESTS
TestFreeRDPRegion.c
TestFreeRDPCodecColor.c
TestFreeRDPCodecZGfx.c
TestFreeRDPCodecPlanar.c
TestFreeRDPCodecCopy.c
TestFreeRDPCodecCursor.c
TestFreeRDPCodecClear.c
TestFreeRDPCodecInterleaved.c
TestFreeRDPCodecProgressive.c
TestFreeRDPCodecRemoteFX.c
)
if(NOT BUILD_TESTING_NO_H264)
list(APPEND TESTS TestFreeRDPCodecH264.c)
endif()
if(BUILD_TESTING_INTERNAL)
list(APPEND TESTS TestFreeRDPCodecMppc.c TestFreeRDPCodecNCrush.c TestFreeRDPCodecXCrush.c)
endif()
file(GLOB CURSOR_TESTCASES_C LIST_DIRECTORIES false RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "cursor/*.c")
file(GLOB CURSOR_TESTCASES_H LIST_DIRECTORIES false RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "cursor/*.h")
# Create a combined header for all testcases
set(TESTCASE_HEADER "${CMAKE_CURRENT_BINARY_DIR}/testcases.h")
write_file(${TESTCASE_HEADER} "#pragma once\n")
foreach(header ${CURSOR_TESTCASES_H})
write_file(${TESTCASE_HEADER} "#include <${header}>" APPEND)
endforeach()
write_file(${TESTCASE_HEADER} "\nstatic const gdiPalette* testcase_palette[] = {" APPEND)
foreach(header ${CURSOR_TESTCASES_H})
get_filename_component(NAME ${header} NAME_WE)
write_file(${TESTCASE_HEADER} "&${NAME}_palette," APPEND)
endforeach()
write_file(${TESTCASE_HEADER} "};\n" APPEND)
write_file(${TESTCASE_HEADER} "static const rdpPointer* testcase_pointer[] = {" APPEND)
foreach(header ${CURSOR_TESTCASES_H})
get_filename_component(NAME ${header} NAME_WE)
write_file(${TESTCASE_HEADER} "&${NAME}_pointer," APPEND)
endforeach()
write_file(${TESTCASE_HEADER} "};\n" APPEND)
write_file(${TESTCASE_HEADER} "static const uint8_t* testcase_image_bgra32[] = {" APPEND)
foreach(header ${CURSOR_TESTCASES_H})
get_filename_component(NAME ${header} NAME_WE)
write_file(${TESTCASE_HEADER} "${NAME}_image_bgra32," APPEND)
endforeach()
write_file(${TESTCASE_HEADER} "};" APPEND)
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
include_directories(${CMAKE_CURRENT_BINARY_DIR})
create_test_sourcelist(SRCS ${DRIVER} ${TESTS})
add_compile_definitions(CMAKE_CURRENT_SOURCE_DIR="${CMAKE_CURRENT_SOURCE_DIR}")
add_compile_definitions(CMAKE_CURRENT_BINARY_DIR="${CMAKE_CURRENT_BINARY_DIR}")
add_executable(${MODULE_NAME} ${SRCS} ${CURSOR_TESTCASES_H} ${CURSOR_TESTCASES_C} ${TESTCASE_HEADER} ${TEST_COMMON})
target_link_libraries(${MODULE_NAME} freerdp winpr)
set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}")
foreach(test ${TESTS})
get_filename_component(TestName ${test} NAME_WE)
add_test(${TestName} ${TESTING_OUTPUT_DIRECTORY}/${MODULE_NAME} ${TestName})
endforeach()
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "FreeRDP/Test")
add_executable(img2bgra img2bgra.c)
target_link_libraries(img2bgra winpr)
set(FUZZERS TestFuzzCodecs.c)
include(AddFuzzerTest)
add_fuzzer_test("${FUZZERS}" "freerdp winpr")
@@ -0,0 +1,91 @@
#include <winpr/crt.h>
#include <winpr/print.h>
#include <winpr/platform.h>
#include <freerdp/codec/clear.h>
WINPR_PRAGMA_DIAG_PUSH
WINPR_PRAGMA_DIAG_IGNORED_UNUSED_CONST_VAR
/* [MS-RDPEGFX] 4.1.1.1 Example 1 */
static const BYTE PREPARE_CLEAR_EXAMPLE_1[] = "\x03\xc3\x11\x00";
static const BYTE TEST_CLEAR_EXAMPLE_1[] = "\x03\xc3\x11\x00";
WINPR_PRAGMA_DIAG_POP
/* [MS-RDPEGFX] 4.1.1.1 Example 2 */
static const BYTE TEST_CLEAR_EXAMPLE_2[] =
"\x00\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x82\x00\x00\x00\x00\x00"
"\x00\x00\x4e\x00\x11\x00\x75\x00\x00\x00\x02\x0e\xff\xff\xff\x00"
"\x00\x00\xdb\xff\xff\x00\x3a\x90\xff\xb6\x66\x66\xb6\xff\xb6\x66"
"\x00\x90\xdb\xff\x00\x00\x3a\xdb\x90\x3a\x3a\x90\xdb\x66\x00\x00"
"\xff\xff\xb6\x64\x64\x64\x11\x04\x11\x4c\x11\x4c\x11\x4c\x11\x4c"
"\x11\x4c\x00\x47\x13\x00\x01\x01\x04\x00\x01\x00\x00\x47\x16\x00"
"\x11\x02\x00\x47\x29\x00\x11\x01\x00\x49\x0a\x00\x01\x00\x04\x00"
"\x01\x00\x00\x4a\x0a\x00\x09\x00\x01\x00\x00\x47\x05\x00\x01\x01"
"\x1c\x00\x01\x00\x11\x4c\x11\x4c\x11\x4c\x00\x47\x0d\x4d\x00\x4d";
/* [MS-RDPEGFX] 4.1.1.1 Example 3 */
static const BYTE TEST_CLEAR_EXAMPLE_3[] =
"\x00\xdf\x0e\x00\x00\x00\x8b\x00\x00\x00\x00\x00\x00\x00\xfe\xfe"
"\xfe\xff\x80\x05\xff\xff\xff\x40\xfe\xfe\xfe\x40\x00\x00\x3f\x00"
"\x03\x00\x0b\x00\xfe\xfe\xfe\xc5\xd0\xc6\xd0\xc7\xd0\x68\xd4\x69"
"\xd4\x6a\xd4\x6b\xd4\x6c\xd4\x6d\xd4\x1a\xd4\x1a\xd4\xa6\xd0\x6e"
"\xd4\x6f\xd4\x70\xd4\x71\xd4\x72\xd4\x73\xd4\x74\xd4\x21\xd4\x22"
"\xd4\x23\xd4\x24\xd4\x25\xd4\xd9\xd0\xda\xd0\xdb\xd0\xc5\xd0\xc5"
"\xd0\xdc\xd0\xc2\xd0\x21\xd4\x22\xd4\x23\xd4\x24\xd4\x25\xd4\xc9"
"\xd0\xca\xd0\x5a\xd4\x2b\xd1\x28\xd1\x2c\xd1\x75\xd4\x27\xd4\x28"
"\xd4\x29\xd4\x2a\xd4\x1a\xd4\x1a\xd4\x1a\xd4\xb7\xd0\xb8\xd0\xb9"
"\xd0\xba\xd0\xbb\xd0\xbc\xd0\xbd\xd0\xbe\xd0\xbf\xd0\xc0\xd0\xc1"
"\xd0\xc2\xd0\xc3\xd0\xc4\xd0";
/* [MS-RDPEGFX] 4.1.1.1 Example 4 */
static const BYTE TEST_CLEAR_EXAMPLE_4[] =
"\x01\x0b\x78\x00\x00\x00\x00\x00\x46\x00\x00\x00\x00\x00\x00\x00"
"\x00\x00\x06\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x0f\xff\xff\xff"
"\xff\xff\xff\xff\xff\xff\xb6\xff\xff\xff\xff\xff\xff\xff\xff\xff"
"\xb6\x66\xff\xff\xff\xff\xff\xff\xff\xb6\x66\xdb\x90\x3a\xff\xff"
"\xb6\xff\xff\xff\xff\xff\xff\xff\xff\xff\x46\x91\x47\x91\x48\x91"
"\x49\x91\x4a\x91\x1b\x91";
static BOOL test_ClearDecompressExample(UINT32 nr, UINT32 width, UINT32 height,
const BYTE* pSrcData, const UINT32 SrcSize)
{
BOOL rc = FALSE;
int status = 0;
BYTE* pDstData = calloc(4ULL * width, height);
CLEAR_CONTEXT* clear = clear_context_new(FALSE);
if (!clear || !pDstData)
goto fail;
status = clear_decompress(clear, pSrcData, SrcSize, width, height, pDstData,
PIXEL_FORMAT_XRGB32, 0, 0, 0, width, height, nullptr);
(void)printf("clear_decompress example %" PRIu32 " status: %d\n", nr, status);
(void)fflush(stdout);
rc = (status == 0);
fail:
clear_context_free(clear);
free(pDstData);
return rc;
}
int TestFreeRDPCodecClear(int argc, char* argv[])
{
WINPR_UNUSED(argc);
WINPR_UNUSED(argv);
/* Example 1 needs a filled glyph cache
if (!test_ClearDecompressExample(1, 8, 9, TEST_CLEAR_EXAMPLE_1,
sizeof(TEST_CLEAR_EXAMPLE_1)))
return -1;
*/
if (!test_ClearDecompressExample(2, 78, 17, TEST_CLEAR_EXAMPLE_2, sizeof(TEST_CLEAR_EXAMPLE_2)))
return -1;
if (!test_ClearDecompressExample(3, 64, 24, TEST_CLEAR_EXAMPLE_3, sizeof(TEST_CLEAR_EXAMPLE_3)))
return -1;
if (!test_ClearDecompressExample(4, 7, 15, TEST_CLEAR_EXAMPLE_4, sizeof(TEST_CLEAR_EXAMPLE_4)))
return -1;
return 0;
}
@@ -0,0 +1,74 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
*
* Copyright 2025 Thincast Technologies GmbH
* Copyright 2025 Armin Novak <anovak@thincast.com>
*
* 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 <winpr/wtypes.h>
#include <freerdp/codec/color.h>
typedef struct
{
uint32_t val;
const char* str;
} test_t;
#define XSTR(s) STR(s)
#define STR(x) #x
#define ENTRY(x) { x, #x }
static const test_t testcases[] = { ENTRY(PIXEL_FORMAT_ARGB32),
ENTRY(PIXEL_FORMAT_XRGB32),
ENTRY(PIXEL_FORMAT_ABGR32),
ENTRY(PIXEL_FORMAT_XBGR32),
ENTRY(PIXEL_FORMAT_BGRA32),
ENTRY(PIXEL_FORMAT_BGRX32),
ENTRY(PIXEL_FORMAT_RGBA32),
ENTRY(PIXEL_FORMAT_RGBX32),
ENTRY(PIXEL_FORMAT_BGRX32_DEPTH30),
ENTRY(PIXEL_FORMAT_RGBX32_DEPTH30),
ENTRY(PIXEL_FORMAT_RGB24),
ENTRY(PIXEL_FORMAT_BGR24),
ENTRY(PIXEL_FORMAT_RGB16),
ENTRY(PIXEL_FORMAT_BGR16),
ENTRY(PIXEL_FORMAT_ARGB15),
ENTRY(PIXEL_FORMAT_RGB15),
ENTRY(PIXEL_FORMAT_ABGR15),
ENTRY(PIXEL_FORMAT_BGR15),
ENTRY(PIXEL_FORMAT_RGB8),
ENTRY(PIXEL_FORMAT_A4),
ENTRY(PIXEL_FORMAT_MONO) };
#undef ENTRY
#undef STR
int TestFreeRDPCodecColor(WINPR_ATTR_UNUSED int argc, WINPR_ATTR_UNUSED char* argv[])
{
const size_t count = ARRAYSIZE(testcases);
for (size_t x = 0; x < count; x++)
{
const test_t* cur = &testcases[x];
const char* cmp = cur->str;
const uint32_t val = FreeRDPGetColorFromatFromName(cmp);
if (val != cur->val)
return -1;
const char* str = FreeRDPGetColorFormatName(cur->val);
if (!str || (strcmp(str, cmp) != 0))
return -2;
}
return 0;
}
@@ -0,0 +1,132 @@
#include <math.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <winpr/sysinfo.h>
#include <freerdp/freerdp.h>
#include <freerdp/codec/color.h>
#define TEST_RUNS 2
static BOOL TestFreeRDPImageCopy(UINT32 w, UINT32 h, UINT32 srcFormat, UINT32 dstFormat,
size_t runs)
{
BOOL rc = FALSE;
const size_t sbpp = FreeRDPGetBytesPerPixel(srcFormat);
const size_t dbpp = FreeRDPGetBytesPerPixel(dstFormat);
const size_t srcStep = w * sbpp;
const size_t dstStep = w * dbpp;
char* src = calloc(h, srcStep);
char* dst = calloc(h, dstStep);
if (!src || !dst)
goto fail;
for (size_t x = 0; x < runs; x++)
{
if (winpr_RAND_pseudo(src, h * srcStep) < 0)
goto fail;
const UINT64 start = winpr_GetUnixTimeNS();
rc = freerdp_image_copy(dst, dstFormat, dstStep, 0, 0, w, h, src, srcFormat, srcStep, 0, 0,
nullptr, 0);
const UINT64 end = winpr_GetUnixTimeNS();
double ms = (double)(end - start);
ms /= 1000000.0;
(void)fprintf(stdout,
"[%s] copied %" PRIu32 "x%" PRIu32 " [%-20s] -> [%-20s] in %lf ms [%s]\n",
__func__, w, h, FreeRDPGetColorFormatName(srcFormat),
FreeRDPGetColorFormatName(dstFormat), ms, rc ? "success" : "failure");
if (!rc)
break;
}
fail:
free(src);
free(dst);
return rc;
}
static BOOL TestFreeRDPImageCopy_no_overlap(UINT32 w, UINT32 h, UINT32 srcFormat, UINT32 dstFormat,
size_t runs)
{
BOOL rc = FALSE;
const size_t sbpp = FreeRDPGetBytesPerPixel(srcFormat);
const size_t dbpp = FreeRDPGetBytesPerPixel(dstFormat);
const size_t srcStep = w * sbpp;
const size_t dstStep = w * dbpp;
char* src = calloc(h, srcStep);
char* dst = calloc(h, dstStep);
if (!src || !dst)
goto fail;
for (size_t x = 0; x < runs; x++)
{
if (winpr_RAND_pseudo(src, h * srcStep) < 0)
goto fail;
const UINT64 start = winpr_GetUnixTimeNS();
rc = freerdp_image_copy_no_overlap(dst, dstFormat, dstStep, 0, 0, w, h, src, srcFormat,
srcStep, 0, 0, nullptr, 0);
const UINT64 end = winpr_GetUnixTimeNS();
double ms = (double)(end - start);
ms /= 1000000.0;
(void)fprintf(stdout,
"[%s] copied %" PRIu32 "x%" PRIu32 " [%-20s] -> [%-20s] in %lf ms [%s]\n",
__func__, w, h, FreeRDPGetColorFormatName(srcFormat),
FreeRDPGetColorFormatName(dstFormat), ms, rc ? "success" : "failure");
if (!rc)
break;
}
fail:
free(src);
free(dst);
return rc;
}
int TestFreeRDPCodecCopy(int argc, char* argv[])
{
WINPR_UNUSED(argc);
WINPR_UNUSED(argv);
UINT32 width = 192;
UINT32 height = 108;
const UINT32 formats[] = {
PIXEL_FORMAT_ABGR15, PIXEL_FORMAT_ARGB15, PIXEL_FORMAT_BGR15, PIXEL_FORMAT_BGR16,
PIXEL_FORMAT_BGR24, PIXEL_FORMAT_RGB15, PIXEL_FORMAT_RGB16, PIXEL_FORMAT_RGB24,
PIXEL_FORMAT_ABGR32, PIXEL_FORMAT_ARGB32, PIXEL_FORMAT_XBGR32, PIXEL_FORMAT_XRGB32,
PIXEL_FORMAT_BGRA32, PIXEL_FORMAT_RGBA32, PIXEL_FORMAT_BGRX32, PIXEL_FORMAT_RGBX32,
};
if (argc == 3)
{
errno = 0;
width = strtoul(argv[1], nullptr, 0);
height = strtoul(argv[2], nullptr, 0);
if ((errno != 0) || (width == 0) || (height == 0))
{
char buffer[128] = WINPR_C_ARRAY_INIT;
(void)fprintf(stderr, "%s failed: width=%" PRIu32 ", height=%" PRIu32 ", errno=%s\n",
__func__, width, height, winpr_strerror(errno, buffer, sizeof(buffer)));
return -1;
}
}
for (size_t x = 0; x < ARRAYSIZE(formats); x++)
{
const UINT32 SrcFormat = formats[x];
for (size_t y = 0; y < ARRAYSIZE(formats); y++)
{
const UINT32 DstFormat = formats[y];
if (!TestFreeRDPImageCopy(width, height, SrcFormat, DstFormat, TEST_RUNS))
return -1;
if (!TestFreeRDPImageCopy_no_overlap(width, height, SrcFormat, DstFormat, TEST_RUNS))
return -1;
}
}
return 0;
}
@@ -0,0 +1,79 @@
#include <stdint.h>
#include <winpr/path.h>
#include <winpr/image.h>
#include <freerdp/codec/color.h>
#include "testcases.h"
static BOOL run_testcase(size_t x, const gdiPalette* palette, const rdpPointer* pointer,
const uint8_t* ref)
{
WINPR_ASSERT(palette);
WINPR_ASSERT(pointer);
WINPR_ASSERT(ref);
WLog_INFO("test", "running cursor test case %" PRIuz, x);
BOOL rc = FALSE;
const uint32_t format = PIXEL_FORMAT_BGRA32;
const size_t width = pointer->width;
const size_t height = pointer->height;
const size_t xorBpp = pointer->xorBpp;
const size_t bpp = FreeRDPGetBytesPerPixel(format);
const size_t stride = width * bpp;
uint8_t* bmp = calloc(stride, height);
if (!bmp)
goto fail;
const BOOL result = freerdp_image_copy_from_pointer_data(
bmp, format, 0, 0, 0, width, height, pointer->xorMaskData, pointer->lengthXorMask,
pointer->andMaskData, pointer->lengthAndMask, xorBpp, palette);
if (!result)
goto fail;
rc = TRUE;
for (size_t y = 0; y < height; y++)
{
const uint8_t* linea = &bmp[y * stride];
const uint8_t* lineb = &ref[y * stride];
for (size_t x = 0; x < stride; x++)
{
const uint8_t a = linea[x];
const uint8_t b = lineb[x];
if (a != b)
{
printf("xxx: %" PRIuz "x%" PRIuz ": color %" PRIuz " diff 0x%02" PRIx8
"<-->0x%02" PRIx8 "\n",
x / 4, y, x % 4, a, b);
rc = FALSE;
}
}
}
fail:
free(bmp);
WLog_INFO("test", "cursor test case %" PRIuz ": %s", x, rc ? "success" : "failure");
return rc;
}
int TestFreeRDPCodecCursor(WINPR_ATTR_UNUSED int argc, WINPR_ATTR_UNUSED char* argv[])
{
const size_t palette_len = ARRAYSIZE(testcase_palette);
const size_t pointer_len = ARRAYSIZE(testcase_pointer);
const size_t bmp_len = ARRAYSIZE(testcase_image_bgra32);
WINPR_ASSERT(palette_len == pointer_len);
WINPR_ASSERT(palette_len == bmp_len);
int rc = 0;
for (size_t x = 0; x < palette_len; x++)
{
const gdiPalette* palette = testcase_palette[x];
const rdpPointer* pointer = testcase_pointer[x];
const uint8_t* bmp = testcase_image_bgra32[x];
if (!run_testcase(x, palette, pointer, bmp))
rc = -1;
}
return rc;
}
@@ -0,0 +1,196 @@
#include <math.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <winpr/sysinfo.h>
#include <freerdp/freerdp.h>
#include <freerdp/codec/color.h>
static const char* print_ns(UINT64 start, UINT64 end, char* buffer, size_t len)
{
const UINT64 diff = end - start;
const unsigned ns = diff % 1000;
const unsigned us = (diff / 1000) % 1000;
const unsigned ms = (diff / 1000000) % 1000;
const unsigned s = (diff / 1000000000ULL) % 1000;
(void)_snprintf(buffer, len, "%03u %03u %03u %03uns", s, ms, us, ns);
return buffer;
}
static BOOL testContextOptions(BOOL compressor, uint32_t width, uint32_t height)
{
BOOL rc = FALSE;
const UINT64 start = winpr_GetUnixTimeNS();
H264_CONTEXT* h264 = h264_context_new(FALSE);
if (!h264)
return FALSE;
struct optpair_s
{
H264_CONTEXT_OPTION opt;
uint32_t val;
};
const struct optpair_s optpair[] = { { H264_CONTEXT_OPTION_RATECONTROL, H264_RATECONTROL_VBR },
{ H264_CONTEXT_OPTION_BITRATE, 2323 },
{ H264_CONTEXT_OPTION_FRAMERATE, 23 },
{ H264_CONTEXT_OPTION_QP, 21 },
{ H264_CONTEXT_OPTION_USAGETYPE, 23 } };
for (size_t x = 0; x < ARRAYSIZE(optpair); x++)
{
const struct optpair_s* cur = &optpair[x];
if (!h264_context_set_option(h264, cur->opt, cur->val))
goto fail;
}
if (!h264_context_reset(h264, width, height))
goto fail;
rc = TRUE;
fail:
h264_context_free(h264);
const UINT64 end = winpr_GetUnixTimeNS();
char buffer[64] = WINPR_C_ARRAY_INIT;
printf("[%s] %" PRIu32 "x%" PRIu32 " took %s\n", __func__, width, height,
print_ns(start, end, buffer, sizeof(buffer)));
return rc;
}
static void* allocRGB(uint32_t format, uint32_t width, uint32_t height, uint32_t* pstride)
{
const size_t bpp = FreeRDPGetBytesPerPixel(format);
const size_t stride = bpp * width + 32;
WINPR_ASSERT(pstride);
*pstride = WINPR_ASSERTING_INT_CAST(uint32_t, stride);
uint8_t* rgb = calloc(stride, height);
if (!rgb)
return nullptr;
for (size_t x = 0; x < height; x++)
{
if (winpr_RAND(&rgb[x * stride], width * bpp) < 0)
{
free(rgb);
return nullptr;
}
}
return rgb;
}
static BOOL compareRGB(const uint8_t* src, const uint8_t* dst, uint32_t format, size_t width,
size_t stride, size_t height)
{
const size_t bpp = FreeRDPGetBytesPerPixel(format);
for (size_t y = 0; y < height; y++)
{
const uint8_t* csrc = &src[y * stride];
const uint8_t* cdst = &dst[y * stride];
const int rc = memcmp(csrc, cdst, width * bpp);
// TODO: Both, AVC420 encoding and decoding are lossy.
// TODO: Find a proper error margin to check for
#if 0
if (rc != 0)
return FALSE;
#endif
}
return TRUE;
}
static BOOL testEncode(uint32_t format, uint32_t width, uint32_t height)
{
BOOL rc = FALSE;
void* src = nullptr;
void* out = nullptr;
RDPGFX_H264_METABLOCK meta = WINPR_C_ARRAY_INIT;
H264_CONTEXT* h264 = h264_context_new(TRUE);
H264_CONTEXT* h264dec = h264_context_new(FALSE);
if (!h264 || !h264dec)
goto fail;
if (!h264_context_reset(h264, width, height))
goto fail;
if (!h264_context_reset(h264dec, width, height))
goto fail;
uint32_t stride = 0;
uint32_t ostride = 0;
src = allocRGB(format, width, height, &stride);
out = allocRGB(format, width, height, &ostride);
if (!src || !out || (stride < width) || (stride != ostride))
goto fail;
const RECTANGLE_16 rect = { .left = 0, .top = 0, .right = width, .bottom = height };
uint32_t dstsize = 0;
uint8_t* dst = nullptr;
if (avc420_compress(h264, src, format, stride, width, height, &rect, &dst, &dstsize, &meta) < 0)
goto fail;
if ((dstsize == 0) || !dst)
goto fail;
if (avc420_decompress(h264dec, dst, dstsize, out, format, stride, width, height, &rect, 1) < 0)
goto fail;
rc = compareRGB(src, out, format, width, stride, height);
fail:
h264_context_free(h264);
h264_context_free(h264dec);
free_h264_metablock(&meta);
free(src);
free(out);
return rc;
}
int TestFreeRDPCodecH264(int argc, char* argv[])
{
WINPR_UNUSED(argc);
WINPR_UNUSED(argv);
UINT32 width = 124;
UINT32 height = 54;
const UINT32 formats[] = {
PIXEL_FORMAT_ABGR15, PIXEL_FORMAT_ARGB15, PIXEL_FORMAT_BGR15, PIXEL_FORMAT_BGR16,
PIXEL_FORMAT_BGR24, PIXEL_FORMAT_RGB15, PIXEL_FORMAT_RGB16, PIXEL_FORMAT_RGB24,
PIXEL_FORMAT_ABGR32, PIXEL_FORMAT_ARGB32, PIXEL_FORMAT_XBGR32, PIXEL_FORMAT_XRGB32,
PIXEL_FORMAT_BGRA32, PIXEL_FORMAT_RGBA32, PIXEL_FORMAT_BGRX32, PIXEL_FORMAT_RGBX32,
};
if (argc == 3)
{
errno = 0;
width = strtoul(argv[1], nullptr, 0);
height = strtoul(argv[2], nullptr, 0);
if ((errno != 0) || (width == 0) || (height == 0))
{
char buffer[128] = WINPR_C_ARRAY_INIT;
(void)fprintf(stderr, "%s failed: width=%" PRIu32 ", height=%" PRIu32 ", errno=%s\n",
__func__, width, height, winpr_strerror(errno, buffer, sizeof(buffer)));
return -1;
}
}
#if !defined(WITH_MEDIACODEC) && !defined(WITH_MEDIA_FOUNDATION) && !defined(WITH_OPENH264) && \
!defined(WITH_VIDEO_FFMPEG)
(void)fprintf(stderr, "[%s] skipping, no H264 encoder/decoder support compiled in\n", __func__);
return 0;
#endif
if (!testContextOptions(FALSE, width, height))
return -1;
if (!testContextOptions(TRUE, width, height))
return -1;
for (size_t x = 0; x < ARRAYSIZE(formats); x++)
{
const UINT32 SrcFormat = formats[x];
for (size_t y = 0; y < ARRAYSIZE(formats); y++)
{
if (!testEncode(SrcFormat, width, height))
return -1;
}
}
return 0;
}
@@ -0,0 +1,454 @@
#include <freerdp/config.h>
#include <math.h>
#include <winpr/crt.h>
#include <winpr/print.h>
#include <winpr/json.h>
#include <winpr/path.h>
#include <freerdp/freerdp.h>
#include <freerdp/codec/color.h>
#include <freerdp/codec/bitmap.h>
#include <freerdp/codec/interleaved.h>
#include <winpr/crypto.h>
#include <freerdp/utils/profiler.h>
#include "TestFreeRDPHelpers.h"
// #define CREATE_TEST_OUTPUT
static bool run_encode_decode_single(UINT16 bpp, BITMAP_INTERLEAVED_CONTEXT* encoder,
BITMAP_INTERLEAVED_CONTEXT* decoder
#if defined(WITH_PROFILER)
,
PROFILER* profiler_comp, PROFILER* profiler_decomp
#endif
)
{
bool rc2 = false;
bool rc = 0;
const UINT32 w = 64;
const UINT32 h = 64;
const UINT32 x = 0;
const UINT32 y = 0;
const UINT32 format = PIXEL_FORMAT_RGBX32;
const UINT32 bstep = FreeRDPGetBytesPerPixel(format);
const size_t step = (13ULL + w) * 4ULL;
const size_t SrcSize = step * h;
const int maxDiff = 4 * ((bpp < 24) ? 2 : 1);
UINT32 DstSize = SrcSize;
BYTE* pSrcData = calloc(1, SrcSize);
BYTE* pDstData = calloc(1, SrcSize);
BYTE* tmp = calloc(1, SrcSize);
if (!pSrcData || !pDstData || !tmp)
goto fail;
if (winpr_RAND(pSrcData, SrcSize) < 0)
goto fail;
if (!bitmap_interleaved_context_reset(encoder) || !bitmap_interleaved_context_reset(decoder))
goto fail;
PROFILER_ENTER(profiler_comp)
rc = interleaved_compress(encoder, tmp, &DstSize, w, h, pSrcData, format, step, x, y, nullptr,
bpp);
PROFILER_EXIT(profiler_comp)
if (!rc)
goto fail;
PROFILER_ENTER(profiler_decomp)
rc = interleaved_decompress(decoder, tmp, DstSize, w, h, bpp, pDstData, format, step, x, y, w,
h, nullptr);
PROFILER_EXIT(profiler_decomp)
if (!rc)
goto fail;
for (UINT32 i = 0; i < h; i++)
{
const BYTE* srcLine = &pSrcData[i * step];
const BYTE* dstLine = &pDstData[i * step];
for (UINT32 j = 0; j < w; j++)
{
BYTE r = 0;
BYTE g = 0;
BYTE b = 0;
BYTE dr = 0;
BYTE dg = 0;
BYTE db = 0;
const UINT32 srcColor = FreeRDPReadColor(&srcLine[1ULL * j * bstep], format);
const UINT32 dstColor = FreeRDPReadColor(&dstLine[1ULL * j * bstep], format);
FreeRDPSplitColor(srcColor, format, &r, &g, &b, nullptr, nullptr);
FreeRDPSplitColor(dstColor, format, &dr, &dg, &db, nullptr, nullptr);
if (abs(r - dr) > maxDiff)
goto fail;
if (abs(g - dg) > maxDiff)
goto fail;
if (abs(b - db) > maxDiff)
goto fail;
}
}
rc2 = true;
fail:
free(pSrcData);
free(pDstData);
free(tmp);
return rc2;
}
static const char* get_profiler_name(bool encode, UINT16 bpp)
{
switch (bpp)
{
case 24:
if (encode)
return "interleaved_compress 24bpp";
else
return "interleaved_decompress 24bpp";
case 16:
if (encode)
return "interleaved_compress 16bpp";
else
return "interleaved_decompress 16bpp";
case 15:
if (encode)
return "interleaved_compress 15bpp";
else
return "interleaved_decompress 15bpp";
default:
return "configuration error!";
}
}
static bool run_encode_decode(UINT16 bpp, BITMAP_INTERLEAVED_CONTEXT* encoder,
BITMAP_INTERLEAVED_CONTEXT* decoder)
{
bool rc = false;
PROFILER_DEFINE(profiler_comp)
PROFILER_DEFINE(profiler_decomp)
PROFILER_CREATE(profiler_comp, get_profiler_name(true, bpp))
PROFILER_CREATE(profiler_decomp, get_profiler_name(false, bpp))
for (UINT32 x = 0; x < 50; x++)
{
if (!run_encode_decode_single(bpp, encoder, decoder
#if defined(WITH_PROFILER)
,
profiler_comp, profiler_decomp
#endif
))
goto fail;
}
rc = true;
fail:
PROFILER_PRINT_HEADER
PROFILER_PRINT(profiler_comp)
PROFILER_PRINT(profiler_decomp)
PROFILER_PRINT_FOOTER
PROFILER_FREE(profiler_comp)
PROFILER_FREE(profiler_decomp)
return rc;
}
static bool TestColorConversion(void)
{
const UINT32 formats[] = { PIXEL_FORMAT_RGB15, PIXEL_FORMAT_BGR15, PIXEL_FORMAT_ABGR15,
PIXEL_FORMAT_ARGB15, PIXEL_FORMAT_BGR16, PIXEL_FORMAT_RGB16 };
/* Check color conversion 15/16 -> 32bit maps to proper values */
for (UINT32 x = 0; x < ARRAYSIZE(formats); x++)
{
const UINT32 dstFormat = PIXEL_FORMAT_RGBA32;
const UINT32 format = formats[x];
const UINT32 colorLow = FreeRDPGetColor(format, 0, 0, 0, 255);
const UINT32 colorHigh = FreeRDPGetColor(format, 255, 255, 255, 255);
const UINT32 colorLow32 = FreeRDPConvertColor(colorLow, format, dstFormat, nullptr);
const UINT32 colorHigh32 = FreeRDPConvertColor(colorHigh, format, dstFormat, nullptr);
BYTE r = 0;
BYTE g = 0;
BYTE b = 0;
BYTE a = 0;
FreeRDPSplitColor(colorLow32, dstFormat, &r, &g, &b, &a, nullptr);
if ((r != 0) || (g != 0) || (b != 0))
return false;
FreeRDPSplitColor(colorHigh32, dstFormat, &r, &g, &b, &a, nullptr);
if ((r != 255) || (g != 255) || (b != 255))
return false;
}
return true;
}
static bool RunEncoderTest(const char* name, uint32_t format, uint32_t width, uint32_t height,
uint32_t step, uint32_t bpp)
{
bool rc = false;
void* data = nullptr;
void* encdata = nullptr;
BITMAP_INTERLEAVED_CONTEXT* encoder = bitmap_interleaved_context_new(true);
if (!encoder)
goto fail;
size_t srclen = 0;
data = test_codec_helper_read_data("interleaved", "bmp", name, &srclen);
if (!data)
goto fail;
encdata = calloc(srclen, 1);
if (!encdata)
goto fail;
for (size_t x = 0; x < 42; x++)
{
uint32_t enclen = WINPR_ASSERTING_INT_CAST(uint32_t, srclen);
if (!interleaved_compress(encoder, encdata, &enclen, width, height, data, format, step, 0,
0, nullptr, bpp))
goto fail;
char encname[128] = WINPR_C_ARRAY_INIT;
(void)_snprintf(encname, sizeof(encname), "enc-%" PRIu32, bpp);
#if defined(CREATE_TEST_OUTPUT)
test_codec_helper_write_data("interleaved", encname, name, encdata, enclen);
#else
if (!test_codec_helper_compare("interleaved", encname, name, encdata, enclen))
goto fail;
#endif
}
rc = true;
fail:
free(data);
free(encdata);
bitmap_interleaved_context_free(encoder);
return rc;
}
static bool RunDecoderTest(const char* name, uint32_t format, uint32_t width, uint32_t height,
uint32_t step, uint32_t bpp)
{
bool rc = false;
void* data = nullptr;
void* decdata = nullptr;
BITMAP_INTERLEAVED_CONTEXT* decoder = bitmap_interleaved_context_new(false);
if (!decoder)
goto fail;
char encname[128] = WINPR_C_ARRAY_INIT;
(void)_snprintf(encname, sizeof(encname), "enc-%" PRIu32, bpp);
size_t srclen = 0;
data = test_codec_helper_read_data("interleaved", encname, name, &srclen);
if (!data)
goto fail;
const size_t declen = 1ULL * step * height;
decdata = calloc(step, height);
if (!decdata)
goto fail;
for (size_t x = 0; x < 42; x++)
{
if (!interleaved_decompress(decoder, data, WINPR_ASSERTING_INT_CAST(uint32_t, srclen),
width, height, bpp, decdata, format, step, 0, 0, width, height,
nullptr))
goto fail;
char decname[128] = WINPR_C_ARRAY_INIT;
(void)_snprintf(decname, sizeof(decname), "dec-%s", encname);
#if defined(CREATE_TEST_OUTPUT)
test_codec_helper_write_data("interleaved", decname, name, decdata, declen);
#else
if (!test_codec_helper_compare("interleaved", decname, name, decdata, declen))
goto fail;
#endif
}
rc = true;
fail:
free(data);
free(decdata);
bitmap_interleaved_context_free(decoder);
return rc;
}
/* The encoder expects a JSON that describes a test cast:
*
* [
* {
* "name": "somestring",
* "format": "somestring",
* "width": <someint>,
* "height": <someint>,
* "step": <someint>,
* "bpp": <someint>
* },
* {...},
* ...
* ]
*/
static bool isObjectValid(const WINPR_JSON* obj)
{
if (!obj || !WINPR_JSON_IsObject(obj))
return false;
const char* strvalues[] = { "name", "format" };
for (size_t x = 0; x < ARRAYSIZE(strvalues); x++)
{
const char* val = strvalues[x];
if (!WINPR_JSON_HasObjectItem(obj, val))
return false;
WINPR_JSON* jval = WINPR_JSON_GetObjectItem(obj, val);
if (!jval)
return false;
if (!WINPR_JSON_IsString(jval))
return false;
}
const char* values[] = { "width", "height", "step" };
for (size_t x = 0; x < ARRAYSIZE(values); x++)
{
const char* val = values[x];
if (!WINPR_JSON_HasObjectItem(obj, val))
return false;
WINPR_JSON* jval = WINPR_JSON_GetObjectItem(obj, val);
if (!jval)
return false;
if (!WINPR_JSON_IsNumber(jval))
return false;
const double dval = WINPR_JSON_GetNumberValue(jval);
if (dval <= 0.0)
return false;
}
{
const char* val = "bpp";
if (!WINPR_JSON_HasObjectItem(obj, val))
return false;
WINPR_JSON* jval = WINPR_JSON_GetObjectItem(obj, val);
if (!jval)
return false;
if (!WINPR_JSON_IsArray(jval))
return false;
for (size_t x = 0; x < WINPR_JSON_GetArraySize(jval); x++)
{
WINPR_JSON* aval = WINPR_JSON_GetArrayItem(jval, x);
if (!jval || !WINPR_JSON_IsNumber(aval))
return false;
}
}
return true;
}
static bool TestEncoder(void)
{
bool rc = false;
WINPR_JSON* json = nullptr;
char* file = nullptr;
char* path = GetCombinedPath(CMAKE_CURRENT_SOURCE_DIR, "interleaved");
if (!path)
goto fail;
file = GetCombinedPath(path, "encoder.json");
if (!file)
goto fail;
json = WINPR_JSON_ParseFromFile(file);
if (!json)
goto fail;
if (!WINPR_JSON_IsArray(json))
goto fail;
for (size_t x = 0; x < WINPR_JSON_GetArraySize(json); x++)
{
WINPR_JSON* obj = WINPR_JSON_GetArrayItem(json, x);
if (!isObjectValid(obj))
goto fail;
const char* name = WINPR_JSON_GetStringValue(WINPR_JSON_GetObjectItem(obj, "name"));
const uint32_t format = WINPR_ASSERTING_INT_CAST(
uint32_t, FreeRDPGetColorFromatFromName(
WINPR_JSON_GetStringValue(WINPR_JSON_GetObjectItem(obj, "format"))));
const uint32_t width = WINPR_ASSERTING_INT_CAST(
uint32_t, WINPR_JSON_GetNumberValue(WINPR_JSON_GetObjectItem(obj, "width")));
const uint32_t height = WINPR_ASSERTING_INT_CAST(
uint32_t, WINPR_JSON_GetNumberValue(WINPR_JSON_GetObjectItem(obj, "height")));
const uint32_t step = WINPR_ASSERTING_INT_CAST(
uint32_t, WINPR_JSON_GetNumberValue(WINPR_JSON_GetObjectItem(obj, "step")));
WINPR_JSON* jbpp = WINPR_JSON_GetObjectItem(obj, "bpp");
for (size_t x = 0; x < WINPR_JSON_GetArraySize(jbpp); x++)
{
const uint32_t bpp = WINPR_ASSERTING_INT_CAST(
uint32_t, WINPR_JSON_GetNumberValue(WINPR_JSON_GetArrayItem(jbpp, x)));
if (!RunEncoderTest(name, format, width, height, step, bpp))
goto fail;
if (!RunDecoderTest(name, format, width, height, step, bpp))
goto fail;
}
}
rc = true;
fail:
WINPR_JSON_Delete(json);
free(path);
free(file);
return rc;
}
int TestFreeRDPCodecInterleaved(int argc, char* argv[])
{
BITMAP_INTERLEAVED_CONTEXT* encoder = nullptr;
BITMAP_INTERLEAVED_CONTEXT* decoder = nullptr;
int rc = -1;
WINPR_UNUSED(argc);
WINPR_UNUSED(argv);
encoder = bitmap_interleaved_context_new(true);
decoder = bitmap_interleaved_context_new(false);
if (!encoder || !decoder)
goto fail;
if (!run_encode_decode(24, encoder, decoder))
goto fail;
if (!run_encode_decode(16, encoder, decoder))
goto fail;
if (!run_encode_decode(15, encoder, decoder))
goto fail;
if (!TestColorConversion())
goto fail;
if (!TestEncoder())
goto fail;
rc = 0;
fail:
bitmap_interleaved_context_free(encoder);
bitmap_interleaved_context_free(decoder);
return rc;
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,122 @@
#include <winpr/crt.h>
#include <winpr/print.h>
#include "../ncrush.h"
static const BYTE TEST_BELLS_DATA[] = "for.whom.the.bell.tolls,.the.bell.tolls.for.thee!";
static const BYTE TEST_BELLS_NCRUSH[] =
"\xfb\x1d\x7e\xe4\xda\xc7\x1d\x70\xf8\xa1\x6b\x1f\x7d\xc0\xbe\x6b"
"\xef\xb5\xef\x21\x87\xd0\xc5\xe1\x85\x71\xd4\x10\x16\xe7\xda\xfb"
"\x1d\x7e\xe4\xda\x47\x1f\xb0\xef\xbe\xbd\xff\x2f";
static BOOL test_NCrushCompressBells(void)
{
BOOL rc = FALSE;
int status = 0;
UINT32 Flags = 0;
const BYTE* pDstData = nullptr;
BYTE OutputBuffer[65536] = WINPR_C_ARRAY_INIT;
const UINT32 SrcSize = sizeof(TEST_BELLS_DATA) - 1;
const BYTE* pSrcData = TEST_BELLS_DATA;
const UINT32 expectedSize = sizeof(TEST_BELLS_NCRUSH) - 1;
UINT32 DstSize = sizeof(OutputBuffer);
NCRUSH_CONTEXT* ncrush = ncrush_context_new(TRUE);
if (!ncrush)
return rc;
status = ncrush_compress(ncrush, pSrcData, SrcSize, OutputBuffer, &pDstData, &DstSize, &Flags);
if (status < 0)
goto fail;
printf("status: %d Flags: 0x%08" PRIX32 " DstSize: %" PRIu32 "\n", status, Flags, DstSize);
if (DstSize != expectedSize)
{
printf("NCrushCompressBells: output size mismatch: Actual: %" PRIu32 ", Expected: %" PRIu32
"\n",
DstSize, expectedSize);
printf("Actual\n");
BitDump(__func__, WLOG_INFO, pDstData, DstSize * 8, 0);
printf("Expected\n");
BitDump(__func__, WLOG_INFO, TEST_BELLS_NCRUSH, expectedSize * 8, 0);
goto fail;
}
if (memcmp(pDstData, TEST_BELLS_NCRUSH, DstSize) != 0)
{
printf("NCrushCompressBells: output mismatch\n");
printf("Actual\n");
BitDump(__func__, WLOG_INFO, pDstData, DstSize * 8, 0);
printf("Expected\n");
BitDump(__func__, WLOG_INFO, TEST_BELLS_NCRUSH, expectedSize * 8, 0);
goto fail;
}
rc = TRUE;
fail:
ncrush_context_free(ncrush);
return rc;
}
static BOOL test_NCrushDecompressBells(void)
{
BOOL rc = FALSE;
int status = 0;
UINT32 Flags = 0;
const BYTE* pSrcData = nullptr;
UINT32 SrcSize = 0;
UINT32 DstSize = 0;
UINT32 expectedSize = 0;
const BYTE* pDstData = nullptr;
NCRUSH_CONTEXT* ncrush = ncrush_context_new(FALSE);
if (!ncrush)
return rc;
SrcSize = sizeof(TEST_BELLS_NCRUSH) - 1;
pSrcData = (const BYTE*)TEST_BELLS_NCRUSH;
Flags = PACKET_COMPRESSED | 2;
expectedSize = sizeof(TEST_BELLS_DATA) - 1;
status = ncrush_decompress(ncrush, pSrcData, SrcSize, &pDstData, &DstSize, Flags);
if (status < 0)
goto fail;
printf("Flags: 0x%08" PRIX32 " DstSize: %" PRIu32 "\n", Flags, DstSize);
if (DstSize != expectedSize)
{
printf("NCrushDecompressBells: output size mismatch: Actual: %" PRIu32
", Expected: %" PRIu32 "\n",
DstSize, expectedSize);
goto fail;
}
if (memcmp(pDstData, TEST_BELLS_DATA, DstSize) != 0)
{
printf("NCrushDecompressBells: output mismatch\n");
goto fail;
}
rc = TRUE;
fail:
ncrush_context_free(ncrush);
return rc;
}
int TestFreeRDPCodecNCrush(int argc, char* argv[])
{
WINPR_UNUSED(argc);
WINPR_UNUSED(argv);
if (!test_NCrushCompressBells())
return -1;
if (!test_NCrushDecompressBells())
return -1;
return 0;
}
@@ -0,0 +1,428 @@
#include <math.h>
#include <errno.h>
#include <winpr/crt.h>
#include <winpr/print.h>
#include <winpr/crypto.h>
#include <winpr/path.h>
#include <freerdp/freerdp.h>
#include <freerdp/codec/color.h>
#include <freerdp/codec/bitmap.h>
#include <freerdp/codec/planar.h>
#include "TestFreeRDPHelpers.h"
static const UINT32 colorFormatList[] = {
PIXEL_FORMAT_RGB15, PIXEL_FORMAT_BGR15, PIXEL_FORMAT_RGB16, PIXEL_FORMAT_BGR16,
PIXEL_FORMAT_RGB24, PIXEL_FORMAT_BGR24, PIXEL_FORMAT_ARGB32, PIXEL_FORMAT_ABGR32,
PIXEL_FORMAT_XRGB32, PIXEL_FORMAT_XBGR32, PIXEL_FORMAT_RGBX32, PIXEL_FORMAT_BGRX32
};
static const UINT32 colorFormatCount = sizeof(colorFormatList) / sizeof(colorFormatList[0]);
static BOOL CompareBitmap(const BYTE* srcA, UINT32 srcAFormat, const BYTE* srcB, UINT32 srcBFormat,
UINT32 width, UINT32 height)
{
double maxDiff = NAN;
const UINT32 srcABits = FreeRDPGetBitsPerPixel(srcAFormat);
const UINT32 srcBBits = FreeRDPGetBitsPerPixel(srcBFormat);
UINT32 diff = WINPR_ASSERTING_INT_CAST(uint32_t, fabs((double)srcABits - srcBBits));
/* No support for 8bpp */
if ((srcABits < 15) || (srcBBits < 15))
return FALSE;
/* Compare with following granularity:
* 32 --> 24 bpp: Each color channel has 8bpp, no difference expected
* 24/32 --> 15/16 bpp: 8bit per channel against 5/6bit per channel, +/- 3bit
* 16 --> 15bpp: 5/6bit per channel against 5 bit per channel, +/- 1bit
*/
switch (diff)
{
case 1:
maxDiff = 2 * 2.0;
break;
case 8:
case 9:
case 16:
case 17:
maxDiff = 2 * 8.0;
break;
default:
maxDiff = 0.0;
break;
}
if ((srcABits == 32) || (srcBBits == 32))
{
if (diff == 8)
maxDiff = 0.0;
}
for (size_t y = 0; y < height; y++)
{
const BYTE* lineA = &srcA[y * width * FreeRDPGetBytesPerPixel(srcAFormat)];
const BYTE* lineB = &srcB[y * width * FreeRDPGetBytesPerPixel(srcBFormat)];
for (size_t x = 0; x < width; x++)
{
BYTE sR = 0;
BYTE sG = 0;
BYTE sB = 0;
BYTE sA = 0;
BYTE dR = 0;
BYTE dG = 0;
BYTE dB = 0;
BYTE dA = 0;
const BYTE* a = &lineA[x * FreeRDPGetBytesPerPixel(srcAFormat)];
const BYTE* b = &lineB[x * FreeRDPGetBytesPerPixel(srcBFormat)];
UINT32 colorA = FreeRDPReadColor(a, srcAFormat);
UINT32 colorB = FreeRDPReadColor(b, srcBFormat);
FreeRDPSplitColor(colorA, srcAFormat, &sR, &sG, &sB, &sA, nullptr);
FreeRDPSplitColor(colorB, srcBFormat, &dR, &dG, &dB, &dA, nullptr);
if (fabs((double)sR - dR) > maxDiff)
return FALSE;
if (fabs((double)sG - dG) > maxDiff)
return FALSE;
if (fabs((double)sB - dB) > maxDiff)
return FALSE;
if (fabs((double)sA - dA) > maxDiff)
return FALSE;
}
}
return TRUE;
}
static BOOL RunTestPlanar(BITMAP_PLANAR_CONTEXT* encplanar, BITMAP_PLANAR_CONTEXT* decplanar,
const char* name, const UINT32 srcFormat, const UINT32 dstFormat,
const UINT32 width, const UINT32 height)
{
WINPR_ASSERT(encplanar);
WINPR_ASSERT(decplanar);
BOOL rc = FALSE;
UINT32 dstSize = 0;
size_t srclen = 0;
(void)printf("---------------------- start %s [%s] ----------------------\n", __func__, name);
BYTE* srcBitmap = test_codec_helper_read_data("planar", "bmp", name, &srclen);
if (!srcBitmap)
return FALSE;
BYTE* compressedBitmap = freerdp_bitmap_compress_planar(encplanar, srcBitmap, srcFormat, width,
height, 0, nullptr, &dstSize);
BYTE* decompressedBitmap =
(BYTE*)calloc(height, 1ULL * width * FreeRDPGetBytesPerPixel(dstFormat));
if (!test_codec_helper_compare("planar", "enc", name, compressedBitmap, dstSize))
goto fail;
(void)printf("%s [%s] --> [%s]: ", __func__, FreeRDPGetColorFormatName(srcFormat),
FreeRDPGetColorFormatName(dstFormat));
if (!compressedBitmap || !decompressedBitmap)
goto fail;
if (!freerdp_bitmap_decompress_planar(decplanar, compressedBitmap, dstSize, width, height,
decompressedBitmap, dstFormat, 0, 0, 0, width, height,
FALSE))
{
(void)printf("failed to decompress experimental bitmap 01: width: %" PRIu32
" height: %" PRIu32 "\n",
width, height);
goto fail;
}
#if 0
if (!compare("dec", name, decompressedBitmap,
1ull * width * height * FreeRDPGetBytesPerPixel(dstFormat)))
goto fail;
if (!CompareBitmap(decompressedBitmap, dstFormat, srcBitmap, srcFormat, width, height))
{
printf("FAIL");
goto fail;
}
#endif
rc = TRUE;
fail:
free(srcBitmap);
free(compressedBitmap);
free(decompressedBitmap);
(void)printf("\n");
(void)printf("%s [%s]: %s\n", __func__, name, rc ? "SUCCESS" : "FAILED");
(void)printf("---------------------- end %s [%s] ----------------------\n", __func__, name);
(void)fflush(stdout);
(void)fflush(stderr);
return rc;
}
static BOOL RunTestPlanarSingleColor(BITMAP_PLANAR_CONTEXT* planar, const UINT32 srcFormat,
const UINT32 dstFormat)
{
BOOL rc = FALSE;
(void)printf("%s: [%s] --> [%s]: ", __func__, FreeRDPGetColorFormatName(srcFormat),
FreeRDPGetColorFormatName(dstFormat));
(void)fflush(stdout);
(void)fflush(stderr);
for (UINT32 j = 0; j < 32; j += 8)
{
for (UINT32 i = 4; i < 32; i += 8)
{
UINT32 compressedSize = 0;
const UINT32 fill = j;
const UINT32 color = FreeRDPGetColor(srcFormat, (fill >> 8) & 0xF, (fill >> 4) & 0xF,
(fill) & 0xF, 0xFF);
const UINT32 width = i;
const UINT32 height = i;
BOOL failed = TRUE;
const UINT32 srcSize = width * height * FreeRDPGetBytesPerPixel(srcFormat);
const UINT32 dstSize = width * height * FreeRDPGetBytesPerPixel(dstFormat);
BYTE* compressedBitmap = nullptr;
BYTE* bmp = malloc(srcSize);
BYTE* decompressedBitmap = (BYTE*)malloc(dstSize);
if (!bmp || !decompressedBitmap)
goto fail_loop;
for (size_t y = 0; y < height; y++)
{
BYTE* line = &bmp[y * width * FreeRDPGetBytesPerPixel(srcFormat)];
for (size_t x = 0; x < width; x++)
{
FreeRDPWriteColor(line, srcFormat, color);
line += FreeRDPGetBytesPerPixel(srcFormat);
}
}
compressedBitmap = freerdp_bitmap_compress_planar(planar, bmp, srcFormat, width, height,
0, nullptr, &compressedSize);
if (!compressedBitmap)
goto fail_loop;
if (!freerdp_bitmap_decompress_planar(planar, compressedBitmap, compressedSize, width,
height, decompressedBitmap, dstFormat, 0, 0, 0,
width, height, FALSE))
goto fail_loop;
if (!CompareBitmap(decompressedBitmap, dstFormat, bmp, srcFormat, width, height))
goto fail_loop;
failed = FALSE;
fail_loop:
free(bmp);
free(compressedBitmap);
free(decompressedBitmap);
if (failed)
{
printf("FAIL");
goto fail;
}
}
}
rc = TRUE;
fail:
(void)printf("\n");
(void)printf("%s [%s->%s]: %s\n", __func__, FreeRDPGetColorFormatName(srcFormat),
FreeRDPGetColorFormatName(dstFormat), rc ? "SUCCESS" : "FAILED");
(void)fflush(stdout);
(void)fflush(stderr);
return rc;
}
static BOOL TestPlanar(const UINT32 format)
{
BOOL rc = FALSE;
const DWORD planarFlags = PLANAR_FORMAT_HEADER_NA | PLANAR_FORMAT_HEADER_RLE;
BITMAP_PLANAR_CONTEXT* encplanar = freerdp_bitmap_planar_context_new(planarFlags, 64, 64);
BITMAP_PLANAR_CONTEXT* decplanar = freerdp_bitmap_planar_context_new(planarFlags, 64, 64);
if (!encplanar || !decplanar)
goto fail;
if (!RunTestPlanar(encplanar, decplanar, "TEST_RLE_BITMAP_EXPERIMENTAL_01", PIXEL_FORMAT_RGBX32,
format, 64, 64))
goto fail;
if (!RunTestPlanar(encplanar, decplanar, "TEST_RLE_BITMAP_EXPERIMENTAL_02", PIXEL_FORMAT_RGBX32,
format, 64, 64))
goto fail;
if (!RunTestPlanar(encplanar, decplanar, "TEST_RLE_BITMAP_EXPERIMENTAL_03", PIXEL_FORMAT_RGBX32,
format, 64, 64))
goto fail;
if (!RunTestPlanar(encplanar, decplanar, "TEST_RLE_UNCOMPRESSED_BITMAP_16BPP",
PIXEL_FORMAT_RGB16, format, 32, 32))
goto fail;
for (UINT32 x = 0; x < colorFormatCount; x++)
{
if (!RunTestPlanarSingleColor(encplanar, format, colorFormatList[x]))
goto fail;
}
rc = TRUE;
fail:
freerdp_bitmap_planar_context_free(encplanar);
freerdp_bitmap_planar_context_free(decplanar);
return rc;
}
static UINT32 prand(UINT32 max)
{
UINT32 tmp = 0;
if (max <= 1)
return 1;
if (winpr_RAND(&tmp, sizeof(tmp)) < 0)
{
(void)fprintf(stderr, "winpr_RAND failed, retry...\n");
// NOLINTNEXTLINE(concurrency-mt-unsafe)
exit(-1);
}
return tmp % (max - 1) + 1;
}
static BOOL FuzzPlanar(void)
{
(void)printf("---------------------- start %s ----------------------\n", __func__);
BOOL rc = FALSE;
const DWORD planarFlags = PLANAR_FORMAT_HEADER_NA | PLANAR_FORMAT_HEADER_RLE;
BITMAP_PLANAR_CONTEXT* planar = freerdp_bitmap_planar_context_new(planarFlags, 64, 64);
if (!planar)
goto fail;
for (UINT32 x = 0; x < 100; x++)
{
BYTE data[0x10000] = WINPR_C_ARRAY_INIT;
size_t dataSize = 0x10000;
BYTE dstData[0x10000] = WINPR_C_ARRAY_INIT;
UINT32 DstFormat = 0;
UINT32 nDstStep = 0;
UINT32 nXDst = 0;
UINT32 nYDst = 0;
UINT32 nDstWidth = 0;
UINT32 nDstHeight = 0;
BOOL invalid = TRUE;
do
{
switch (prand(17) - 1)
{
case 0:
DstFormat = PIXEL_FORMAT_RGB8;
break;
case 1:
DstFormat = PIXEL_FORMAT_BGR15;
break;
case 2:
DstFormat = PIXEL_FORMAT_RGB15;
break;
case 3:
DstFormat = PIXEL_FORMAT_ABGR15;
break;
case 4:
DstFormat = PIXEL_FORMAT_ABGR15;
break;
case 5:
DstFormat = PIXEL_FORMAT_BGR16;
break;
case 6:
DstFormat = PIXEL_FORMAT_RGB16;
break;
case 7:
DstFormat = PIXEL_FORMAT_BGR24;
break;
case 8:
DstFormat = PIXEL_FORMAT_RGB24;
break;
case 9:
DstFormat = PIXEL_FORMAT_BGRA32;
break;
case 10:
DstFormat = PIXEL_FORMAT_BGRX32;
break;
case 11:
DstFormat = PIXEL_FORMAT_RGBA32;
break;
case 12:
DstFormat = PIXEL_FORMAT_RGBX32;
break;
case 13:
DstFormat = PIXEL_FORMAT_ABGR32;
break;
case 14:
DstFormat = PIXEL_FORMAT_XBGR32;
break;
case 15:
DstFormat = PIXEL_FORMAT_ARGB32;
break;
case 16:
DstFormat = PIXEL_FORMAT_XRGB32;
break;
default:
break;
}
nDstStep = prand(sizeof(dstData));
nXDst = prand(nDstStep);
nYDst = prand(sizeof(dstData) / nDstStep);
nDstWidth = prand(nDstStep / FreeRDPGetBytesPerPixel(DstFormat));
nDstHeight = prand(sizeof(dstData) / nDstStep);
invalid = nXDst * FreeRDPGetBytesPerPixel(DstFormat) + (nYDst + nDstHeight) * nDstStep >
sizeof(dstData);
} while (invalid);
printf("DstFormat=%s, nXDst=%" PRIu32 ", nYDst=%" PRIu32 ", nDstWidth=%" PRIu32
", nDstHeight=%" PRIu32 ", nDstStep=%" PRIu32 ", total size=%" PRIuz "\n",
FreeRDPGetColorFormatName(DstFormat), nXDst, nYDst, nDstWidth, nDstHeight, nDstStep,
sizeof(dstData));
freerdp_planar_switch_bgr(planar, ((prand(2) % 2) != 0));
freerdp_bitmap_decompress_planar(planar, data, dataSize, prand(4096), prand(4096), dstData,
DstFormat, nDstStep, nXDst, nYDst, nDstWidth, nDstHeight,
((prand(2) % 2) != 0));
}
rc = TRUE;
fail:
freerdp_bitmap_planar_context_free(planar);
(void)printf("\n");
(void)printf("%s: %s\n", __func__, rc ? "SUCCESS" : "FAILED");
(void)printf("---------------------- end %s ----------------------\n", __func__);
(void)fflush(stdout);
(void)fflush(stderr);
return rc;
}
int TestFreeRDPCodecPlanar(int argc, char* argv[])
{
int rc = -1;
WINPR_UNUSED(argc);
WINPR_UNUSED(argv);
if (!FuzzPlanar())
goto fail;
for (UINT32 x = 0; x < colorFormatCount; x++)
{
if (!TestPlanar(colorFormatList[x]))
goto fail;
}
rc = 0;
fail:
printf("test returned %d\n", rc);
return rc;
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,886 @@
#include <winpr/crt.h>
#include <winpr/print.h>
#include <freerdp/freerdp.h>
#include <freerdp/codec/rfx.h>
static BYTE encodeHeaderSample[] = {
/* as in 4.2.2 */
0xc0, 0xcc, 0x0c, 0x00, 0x00, 0x00, 0xca, 0xac, 0xcc, 0xca, 0x00, 0x01, 0xc3, 0xcc, 0x0d, 0x00,
0x00, 0x00, 0x01, 0xff, 0x00, 0x40, 0x00, 0x28, 0xa8, 0xc1, 0xcc, 0x0a, 0x00, 0x00, 0x00, 0x01,
0x01, 0x00, 0x01, 0xc2, 0xcc, 0x0c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x40, 0x00, 0x40, 0x00
};
static BYTE encodeDataSample[] = {
/* FRAME_BEGIN as in 4.2.3 */
0xc4, 0xcc, 0x0e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
/* REGION as in 4.2.3 */
0xc6, 0xcc, 0x17, 0x00, 0x00, 0x00, 0x01, 0x00, 0xcd, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40,
0x00, 0x40, 0x00, 0xc1, 0xca, 0x01, 0x00,
/* TILESET as in 4.2.4.1 */
0xc7, 0xcc, 0x3e, 0x0b, 0x00, 0x00, 0x01, 0x00, 0xc2, 0xca, 0x00, 0x00, 0x51, 0x50, 0x01, 0x40,
0x01, 0x00, 0x23, 0x0b, 0x00, 0x00, 0x66, 0x66, 0x77, 0x88, 0x98, 0xc3, 0xca, 0x23, 0x0b, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xae, 0x03, 0xcf, 0x03, 0x93, 0x03, 0xc0, 0x01,
0x01, 0x15, 0x48, 0x99, 0xc7, 0x41, 0xa1, 0x12, 0x68, 0x11, 0xdc, 0x22, 0x29, 0x74, 0xef, 0xfd,
0x20, 0x92, 0xe0, 0x4e, 0xa8, 0x69, 0x3b, 0xfd, 0x41, 0x83, 0xbf, 0x28, 0x53, 0x0c, 0x1f, 0xe2,
0x54, 0x0c, 0x77, 0x7c, 0xa3, 0x05, 0x7c, 0x30, 0xd0, 0x9c, 0xe8, 0x09, 0x39, 0x1a, 0x5d, 0xff,
0xe2, 0x01, 0x22, 0x13, 0x80, 0x90, 0x87, 0xd2, 0x9f, 0xfd, 0xfd, 0x50, 0x09, 0x0d, 0x24, 0xa0,
0x8f, 0xab, 0xfe, 0x3c, 0x04, 0x84, 0xc6, 0x9c, 0xde, 0xf8, 0x80, 0xc3, 0x22, 0x50, 0xaf, 0x4c,
0x2a, 0x7f, 0xfe, 0xe0, 0x5c, 0xa9, 0x52, 0x8a, 0x06, 0x7d, 0x3d, 0x09, 0x03, 0x65, 0xa3, 0xaf,
0xd2, 0x61, 0x1f, 0x72, 0x04, 0x50, 0x8d, 0x3e, 0x16, 0x4a, 0x3f, 0xff, 0xfd, 0x41, 0x42, 0x87,
0x24, 0x37, 0x06, 0x17, 0x2e, 0x56, 0x05, 0x9c, 0x1c, 0xb3, 0x84, 0x6a, 0xff, 0xfb, 0x43, 0x8b,
0xa3, 0x7a, 0x32, 0x43, 0x28, 0xe1, 0x1f, 0x50, 0x54, 0xfc, 0xca, 0xa5, 0xdf, 0xff, 0x08, 0x04,
0x48, 0x15, 0x61, 0xd9, 0x76, 0x43, 0xf8, 0x2a, 0x07, 0xe9, 0x65, 0xf7, 0xc6, 0x89, 0x2d, 0x40,
0xa1, 0xc3, 0x35, 0x8d, 0xf5, 0xed, 0xf5, 0x91, 0xae, 0x2f, 0xcc, 0x01, 0xce, 0x03, 0x48, 0xc0,
0x8d, 0x63, 0xf4, 0xfd, 0x50, 0x20, 0x2d, 0x0c, 0x9b, 0xb0, 0x8d, 0x13, 0xc0, 0x8a, 0x09, 0x52,
0x1b, 0x02, 0x6e, 0x42, 0x3b, 0xd0, 0x13, 0x4e, 0x84, 0x01, 0x26, 0x88, 0x6a, 0x04, 0x84, 0x34,
0x2a, 0xa5, 0x00, 0xba, 0x54, 0x48, 0x58, 0xea, 0x54, 0x02, 0xb4, 0x1d, 0xa7, 0xfa, 0x47, 0x82,
0xec, 0x7a, 0x77, 0xfd, 0x00, 0x92, 0x66, 0x62, 0x04, 0xa6, 0x9b, 0xff, 0xf6, 0x80, 0xc0, 0x69,
0x01, 0xc2, 0x3e, 0x90, 0x14, 0x20, 0x2f, 0xfc, 0x40, 0x96, 0x59, 0x58, 0x0c, 0xb1, 0x13, 0x68,
0x20, 0x2e, 0xb5, 0xf5, 0xdf, 0xff, 0xf8, 0xfc, 0x56, 0x88, 0x60, 0x24, 0x53, 0xb5, 0x41, 0x46,
0x5f, 0xf8, 0xf1, 0x7e, 0xde, 0x4a, 0x08, 0x97, 0xe0, 0x55, 0x03, 0x8f, 0xe5, 0x75, 0x61, 0x03,
0xf2, 0xe1, 0x90, 0x01, 0xa2, 0x8e, 0x88, 0x04, 0x98, 0x05, 0x93, 0x6b, 0xff, 0xea, 0xc0, 0x60,
0xa1, 0x88, 0x04, 0x49, 0xbf, 0xf7, 0xff, 0x8c, 0xb4, 0x59, 0x90, 0x80, 0x30, 0x64, 0x53, 0xff,
0xf5, 0xc4, 0x48, 0xda, 0xda, 0xcb, 0x80, 0x38, 0x61, 0x57, 0xb2, 0xaf, 0x00, 0xe8, 0x7b, 0x46,
0xe6, 0xd8, 0x02, 0x03, 0x8a, 0x06, 0x18, 0x14, 0x32, 0x83, 0xd0, 0x8a, 0xee, 0xbc, 0x81, 0xb4,
0x28, 0xc4, 0x7f, 0xf9, 0xa1, 0x69, 0x00, 0x91, 0xc5, 0x51, 0xff, 0xfe, 0x3f, 0xe9, 0xf1, 0x70,
0x30, 0x24, 0x10, 0xa7, 0xcb, 0x1f, 0x8a, 0x24, 0x93, 0xed, 0x83, 0x00, 0x36, 0x20, 0xd1, 0x50,
0xe7, 0xd8, 0xad, 0x58, 0x20, 0x09, 0x22, 0x80, 0xd0, 0xca, 0x5d, 0x1a, 0xd7, 0xf1, 0x60, 0x75,
0x2a, 0xf2, 0xd7, 0xf8, 0xc0, 0x32, 0x45, 0x86, 0x00, 0x43, 0x01, 0xfe, 0x80, 0xf7, 0x42, 0x81,
0x74, 0x84, 0x4c, 0xa1, 0x60, 0x4c, 0xcb, 0x14, 0x58, 0x01, 0x4d, 0x18, 0xa1, 0xaa, 0x47, 0x0e,
0x11, 0x1a, 0x40, 0x7d, 0x41, 0x02, 0xe3, 0x30, 0xcd, 0x33, 0x81, 0x34, 0x06, 0x46, 0x83, 0xa2,
0x47, 0x1c, 0x04, 0xaa, 0x20, 0x12, 0xa2, 0x8b, 0x81, 0xc4, 0x9c, 0xa0, 0x2e, 0x06, 0x32, 0xf8,
0x86, 0x85, 0x01, 0xe8, 0x70, 0xf9, 0x46, 0x09, 0x6a, 0xbf, 0xe0, 0xf5, 0xa4, 0xc8, 0x78, 0xe7,
0xd2, 0x97, 0x0b, 0xbc, 0x3c, 0x97, 0xff, 0xd5, 0x40, 0x94, 0xb2, 0xc1, 0x18, 0x18, 0x11, 0x1f,
0x43, 0xc1, 0x18, 0xc3, 0x83, 0x7f, 0x9a, 0x31, 0xc4, 0x8e, 0x70, 0x56, 0xda, 0xf6, 0x17, 0xde,
0xd1, 0x02, 0x0d, 0x42, 0x21, 0x13, 0xdc, 0x3a, 0x3c, 0x40, 0x9e, 0xf4, 0x01, 0x43, 0xea, 0x0c,
0x46, 0x73, 0xa2, 0x7b, 0x0c, 0x80, 0xff, 0xe4, 0xad, 0x2e, 0x09, 0xb4, 0x63, 0xb0, 0x8c, 0x54,
0x59, 0xfa, 0xac, 0x76, 0x36, 0x10, 0x05, 0xf0, 0x98, 0x88, 0x83, 0x42, 0x00, 0x20, 0x71, 0xcc,
0xc1, 0xa9, 0x97, 0x3e, 0x5a, 0x0d, 0x04, 0x50, 0x92, 0x23, 0x20, 0x0d, 0x0a, 0x1c, 0x57, 0xd7,
0xff, 0x10, 0xf2, 0x03, 0x0f, 0x58, 0x1b, 0xa5, 0x11, 0xf8, 0xf1, 0xb4, 0x12, 0xdb, 0x1a, 0x48,
0x56, 0x1f, 0xe3, 0xc7, 0x50, 0xe9, 0x16, 0xb4, 0xbc, 0xb0, 0x40, 0x93, 0xea, 0xb5, 0x5b, 0x2f,
0xfc, 0x50, 0x0a, 0x6f, 0xcc, 0x25, 0xe0, 0x06, 0xab, 0x5f, 0x24, 0xfe, 0x8b, 0xcb, 0x42, 0x43,
0x7e, 0x69, 0x02, 0x25, 0xc7, 0x38, 0x00, 0x6e, 0xe5, 0x80, 0xa8, 0xa4, 0x30, 0x44, 0x15, 0x8f,
0xe9, 0x0c, 0xd3, 0xa6, 0xc2, 0x14, 0x34, 0x4a, 0xfe, 0x03, 0x7f, 0x06, 0xa5, 0x91, 0x02, 0x54,
0xf1, 0xa1, 0xa1, 0x53, 0xbf, 0x11, 0xf2, 0x8f, 0x83, 0x67, 0x80, 0x09, 0x08, 0x12, 0x3f, 0xfd,
0x44, 0x91, 0xc2, 0x83, 0x30, 0x50, 0x07, 0x02, 0x82, 0x4d, 0x31, 0x34, 0x06, 0x41, 0x79, 0x6f,
0xf0, 0xcc, 0x03, 0x79, 0x00, 0x2c, 0x05, 0x24, 0xec, 0x8d, 0x29, 0x15, 0xaf, 0x44, 0xc8, 0xeb,
0x4f, 0xe1, 0xfd, 0xf1, 0x41, 0x48, 0x81, 0x08, 0xaf, 0xfe, 0x51, 0x48, 0xce, 0xe7, 0xf9, 0xb6,
0x0a, 0x30, 0x83, 0x11, 0xf0, 0x0c, 0x3b, 0xd2, 0xa6, 0x24, 0x24, 0xef, 0x25, 0xfa, 0x5a, 0x3e,
0x92, 0x3e, 0x79, 0x0e, 0x35, 0x61, 0xc8, 0xaa, 0x1c, 0x2e, 0x9a, 0x27, 0x7f, 0xff, 0xf0, 0x7d,
0x30, 0x5b, 0xbc, 0x91, 0xff, 0xfe, 0x43, 0x24, 0x28, 0x66, 0xa7, 0x70, 0x99, 0x28, 0x6e, 0x2b,
0x18, 0x2b, 0xd4, 0xa1, 0x77, 0x3b, 0x96, 0x9f, 0xf7, 0xeb, 0xbe, 0x1f, 0x04, 0x34, 0x75, 0x84,
0x31, 0x42, 0x4c, 0x65, 0xaa, 0x09, 0x50, 0xa0, 0xc4, 0x51, 0x31, 0xd3, 0x26, 0x3a, 0x1b, 0xf4,
0x6e, 0x4a, 0x4e, 0x17, 0x25, 0x84, 0x78, 0x7d, 0x2c, 0x3f, 0x46, 0x18, 0xca, 0x5f, 0xf9, 0xe5,
0x38, 0x2f, 0xd8, 0x71, 0x94, 0x94, 0xe2, 0xcc, 0xa3, 0x15, 0xb0, 0xda, 0xa9, 0xcb, 0x58, 0xe4,
0x18, 0x77, 0x93, 0x8a, 0x51, 0xc6, 0x23, 0xc4, 0x4e, 0x6d, 0xd9, 0x14, 0x1e, 0x9b, 0x8d, 0xbc,
0xcb, 0x9d, 0xc4, 0x18, 0x05, 0xf5, 0xa9, 0x29, 0xf8, 0x6d, 0x29, 0x38, 0xc7, 0x44, 0xe5, 0x3a,
0xcd, 0xba, 0x61, 0x98, 0x4a, 0x57, 0x02, 0x96, 0x42, 0x02, 0xd9, 0x37, 0x11, 0xde, 0x2d, 0xd4,
0x3f, 0xfe, 0x61, 0xe7, 0x33, 0xd7, 0x89, 0x4a, 0xdd, 0xb0, 0x34, 0x47, 0xf4, 0xdc, 0xad, 0xaa,
0xc9, 0x9d, 0x7e, 0x6d, 0x4b, 0xcc, 0xdc, 0x17, 0x89, 0x57, 0xfd, 0xbb, 0x37, 0x75, 0x47, 0x5a,
0xec, 0x2c, 0x6e, 0x3c, 0x15, 0x92, 0x54, 0x64, 0x2c, 0xab, 0x9e, 0xab, 0x2b, 0xdd, 0x3c, 0x66,
0xa0, 0x8f, 0x47, 0x5e, 0x93, 0x1a, 0x37, 0x16, 0xf4, 0x89, 0x23, 0x00, 0x00, 0xb0, 0x33, 0x56,
0xfa, 0x14, 0x1e, 0xff, 0x48, 0x7a, 0x7e, 0x0f, 0x10, 0x1f, 0xf4, 0x91, 0xc8, 0x10, 0x56, 0x84,
0xff, 0x08, 0xec, 0xb4, 0xac, 0x0e, 0x0f, 0xff, 0xad, 0xc5, 0xe0, 0x1a, 0x2f, 0x82, 0x04, 0x9f,
0x91, 0xc2, 0x0e, 0xfe, 0x48, 0x36, 0x79, 0x01, 0x42, 0x14, 0xff, 0xfe, 0x30, 0xf0, 0x08, 0x18,
0xf1, 0x81, 0x45, 0x9a, 0x60, 0xc1, 0x79, 0xf0, 0x14, 0x12, 0x10, 0xce, 0xea, 0x31, 0x5a, 0xff,
0xfc, 0x20, 0x13, 0x82, 0x2f, 0xc9, 0x02, 0x1f, 0x81, 0xcb, 0x00, 0xe1, 0x10, 0xd2, 0xb4, 0xbe,
0x87, 0xff, 0xb0, 0x1e, 0x27, 0x81, 0xb7, 0x04, 0x06, 0x3c, 0xc2, 0x04, 0xf6, 0x06, 0x0e, 0x28,
0xbc, 0x40, 0xbf, 0x12, 0x1e, 0x86, 0xd4, 0x6a, 0x7f, 0x18, 0x1b, 0x96, 0x85, 0x4c, 0x16, 0x80,
0xdf, 0x2c, 0xa5, 0x8d, 0x86, 0xa3, 0x4a, 0x8a, 0xb4, 0x1b, 0xa1, 0x38, 0xa9, 0xd5, 0xff, 0xff,
0xea, 0x06, 0x20, 0xd2, 0x95, 0x1e, 0xf4, 0x2f, 0xb2, 0x12, 0x0e, 0x61, 0x78, 0x4a, 0x17, 0x52,
0x5d, 0xe4, 0x25, 0x1f, 0xfe, 0xc0, 0xb3, 0x1f, 0xff, 0xff, 0xec, 0x02, 0x82, 0x80, 0x90, 0x41,
0x88, 0xde, 0x48, 0x2c, 0x42, 0x52, 0x0b, 0x2f, 0x43, 0x7e, 0x50, 0x78, 0xf2, 0x67, 0x78, 0x41,
0x34, 0x3d, 0xc8, 0x0f, 0x67, 0xa1, 0xeb, 0x21, 0xfe, 0xc0, 0x1f, 0x22, 0x60, 0x41, 0x6c, 0x00,
0x92, 0x4b, 0x60, 0x10, 0xd0, 0x0d, 0x01, 0x35, 0x05, 0x0e, 0x87, 0xa2, 0xa0, 0x5d, 0x1f, 0xa3,
0xaf, 0x7f, 0xf1, 0xbe, 0x8f, 0xcd, 0xa5, 0x00, 0x1c, 0x10, 0x40, 0x15, 0x76, 0x81, 0x05, 0xef,
0xee, 0x00, 0x60, 0x84, 0x00, 0x99, 0x40, 0x4a, 0x82, 0x17, 0xe9, 0xfc, 0xc4, 0x7f, 0xff, 0xfd,
0x04, 0x80, 0x06, 0x06, 0xdc, 0xaf, 0xa7, 0x7e, 0x94, 0x75, 0x74, 0x01, 0x00, 0xe0, 0x91, 0x00,
0x85, 0x7f, 0x8e, 0xd6, 0x0b, 0x20, 0x21, 0x30, 0xca, 0x62, 0x8e, 0x07, 0x04, 0xe9, 0x45, 0x40,
0x5f, 0x47, 0x4a, 0x30, 0x15, 0x41, 0xcb, 0xdf, 0xff, 0xfc, 0xbf, 0xc3, 0xb4, 0x46, 0x6a, 0x01,
0x40, 0xd0, 0xa7, 0x34, 0x18, 0x24, 0x1c, 0x2a, 0x45, 0xfe, 0xa8, 0x05, 0x08, 0x61, 0xfd, 0xa8,
0x80, 0x71, 0x01, 0x25, 0x9c, 0xc1, 0x47, 0x17, 0x37, 0x02, 0x7a, 0x15, 0xff, 0xf3, 0x01, 0x45,
0x7f, 0xd6, 0x80, 0x60, 0x83, 0x67, 0xf8, 0x9d, 0x2f, 0xf4, 0xdd, 0x8c, 0x30, 0x01, 0x51, 0x42,
0xbc, 0x43, 0x7a, 0x6b, 0x9f, 0x84, 0x1e, 0x00, 0x48, 0xc1, 0xe0, 0xb7, 0xe0, 0x7e, 0x99, 0xf2,
0x4a, 0xe9, 0x40, 0x02, 0x81, 0xc3, 0x00, 0x24, 0x3a, 0xc5, 0x52, 0x0f, 0x91, 0xc8, 0x68, 0x25,
0x40, 0x99, 0xa4, 0x25, 0x1a, 0x04, 0xd0, 0xa2, 0x91, 0xdd, 0xeb, 0x93, 0x00, 0x21, 0x49, 0x24,
0x8b, 0x40, 0x75, 0x38, 0x14, 0xa1, 0xfd, 0x3f, 0x88, 0x25, 0xbf, 0x32, 0x00, 0xe3, 0x19, 0xfc,
0xb9, 0xf8, 0x6f, 0x81, 0xc0, 0x01, 0xb3, 0x93, 0x20, 0x09, 0x08, 0x25, 0x84, 0xe1, 0x34, 0xd4,
0x1b, 0x48, 0x88, 0x11, 0xa0, 0x15, 0x59, 0xd7, 0x07, 0x81, 0x81, 0x3b, 0xa1, 0x40, 0x2e, 0x2f,
0x48, 0x70, 0x09, 0xc4, 0x76, 0x49, 0x0f, 0x2e, 0x50, 0x2e, 0x46, 0x19, 0xa4, 0x16, 0xa2, 0x1b,
0x84, 0xa2, 0x89, 0x58, 0xfc, 0x4f, 0x3f, 0x40, 0x90, 0x4c, 0xa3, 0x01, 0x32, 0x09, 0x02, 0x80,
0x9c, 0x91, 0x13, 0x2c, 0xba, 0xde, 0x5d, 0x99, 0xf2, 0xff, 0xff, 0x3d, 0x5a, 0x1f, 0xa9, 0x02,
0x90, 0x8f, 0xf3, 0x08, 0xbd, 0x01, 0xf8, 0xd0, 0x2a, 0x95, 0x41, 0x0c, 0x40, 0x0a, 0x20, 0xc4,
0xd4, 0xcc, 0x6b, 0x0f, 0xf0, 0x80, 0xb1, 0x5d, 0x28, 0x3d, 0x08, 0xc2, 0xf8, 0x31, 0x02, 0x49,
0x88, 0x14, 0x28, 0xed, 0xe8, 0x86, 0x3b, 0x00, 0x9f, 0x95, 0x06, 0x37, 0x15, 0xa4, 0x59, 0xc8,
0x80, 0xb6, 0x10, 0xf0, 0xe5, 0xb8, 0x18, 0x00, 0x56, 0x1c, 0xff, 0x95, 0x21, 0x0e, 0x7f, 0x2b,
0xc5, 0x08, 0x59, 0x10, 0xe1, 0x46, 0x31, 0x8d, 0xec, 0xe0, 0xa1, 0x99, 0xbb, 0x21, 0xff, 0xfe,
0x30, 0x10, 0xd0, 0x05, 0xe3, 0x08, 0x50, 0xfc, 0xf3, 0x0e, 0x00, 0x8d, 0x68, 0x8e, 0x07, 0xa6,
0x80, 0x34, 0x42, 0xed, 0x1f, 0x88, 0x00, 0xf0, 0x8a, 0x21, 0xae, 0xf7, 0xfb, 0x80, 0x28, 0x86,
0x0f, 0xff, 0xff, 0x82, 0xea, 0x47, 0x95, 0x91, 0xe0, 0x04, 0x01, 0x44, 0x0c, 0x29, 0xff, 0x0e,
0x33, 0xe8, 0xc0, 0x54, 0x04, 0x23, 0xfc, 0x81, 0x5b, 0xf0, 0x3c, 0x07, 0x10, 0x70, 0x30, 0xd8,
0x21, 0x6f, 0xef, 0xde, 0x46, 0x09, 0x43, 0xfa, 0x5f, 0xff, 0x0d, 0x72, 0x30, 0xdd, 0x00, 0xdb,
0xe4, 0x48, 0x24, 0x97, 0x08, 0x46, 0xb1, 0x49, 0xc4, 0x4d, 0x80, 0x12, 0x60, 0xff, 0xa4, 0xa6,
0xff, 0xf6, 0x8c, 0x00, 0x40, 0x05, 0x02, 0xb4, 0x0f, 0xf0, 0x3e, 0xfc, 0x84, 0x38, 0x81, 0x94,
0x8b, 0xfe, 0x49, 0xef, 0xc0, 0x10, 0x49, 0x88, 0x28, 0xa2, 0x1c, 0x2a, 0x8b, 0x64, 0xd4, 0x86,
0xd7, 0xff, 0xff, 0xff, 0xeb, 0x91, 0x6b, 0x11, 0x10, 0x00, 0x69, 0x4c, 0xbf, 0xb4, 0x1c, 0xd8,
0x00, 0x07, 0x16, 0x80, 0x60, 0x0a, 0x1c, 0x82, 0x42, 0x27, 0x82, 0x43, 0xc9, 0x0a, 0x64, 0x20,
0x5a, 0x5f, 0x4e, 0xbf, 0x8c, 0x38, 0x82, 0x36, 0x02, 0x07, 0x72, 0x79, 0x07, 0x23, 0xb4, 0xbb,
0x57, 0x5f, 0xe8, 0x04, 0xdd, 0x39, 0xe9, 0x07, 0x95, 0xbe, 0x04, 0x2b, 0xdd, 0x8e, 0x22, 0xdc,
0x14, 0x2c, 0x61, 0xa3, 0xa9, 0xcd, 0x4f, 0x82, 0x5d, 0xa0, 0x44, 0xdf, 0xf4, 0x96, 0xff, 0xf5,
0x2b, 0xff, 0xfe, 0x01, 0x19, 0xd2, 0xa2, 0x9e, 0x43, 0xa5, 0x7f, 0xf0, 0x4c, 0x4c, 0x2b, 0x3c,
0x33, 0xe2, 0x55, 0xff, 0x04, 0x06, 0x29, 0x2c, 0x0d, 0x22, 0x5d, 0x7c, 0x93, 0xba, 0x18, 0xaf,
0xf9, 0x32, 0xa6, 0xc3, 0x99, 0x46, 0x79, 0xe3, 0x06, 0xa6, 0x38, 0x8b, 0x92, 0x22, 0x4b, 0xdb,
0x1b, 0x36, 0x20, 0xb0, 0x6c, 0x20, 0xce, 0x37, 0x42, 0xe1, 0x66, 0xd4, 0x49, 0x34, 0x42, 0x8b,
0xfa, 0x9c, 0x12, 0x99, 0xdc, 0x06, 0x87, 0xfa, 0x46, 0xf8, 0x2f, 0x04, 0xa9, 0xd8, 0x82, 0x07,
0xa6, 0x30, 0x0f, 0xc0, 0xdf, 0x35, 0xe8, 0x90, 0xf0, 0xff, 0xff, 0xa8, 0xe0, 0xd7, 0x02, 0x60,
0x1a, 0xc3, 0x20, 0x28, 0xa2, 0x31, 0x29, 0x3c, 0xeb, 0x04, 0xa5, 0xdd, 0x48, 0x0e, 0x82, 0xa4,
0xb6, 0x56, 0x22, 0x06, 0x57, 0xe0, 0xda, 0x10, 0x27, 0x31, 0x0e, 0x11, 0x77, 0xfe, 0x02, 0x60,
0x16, 0x48, 0x81, 0x8c, 0x0d, 0x05, 0x17, 0x7f, 0xcb, 0xbb, 0x7e, 0x25, 0x2a, 0x41, 0xfd, 0x8a,
0x7f, 0xc9, 0x36, 0x7c, 0xe0, 0x98, 0x7e, 0x92, 0xef, 0x7e, 0x06, 0x03, 0x13, 0x3e, 0x20, 0x3a,
0xbf, 0x4c, 0xc3, 0x0f, 0x2e, 0x80, 0x74, 0xbf, 0x39, 0x3c, 0xf0, 0xa6, 0xb2, 0xe9, 0x3f, 0x41,
0x55, 0x1f, 0x2c, 0xf5, 0xd2, 0x7e, 0x8c, 0xae, 0x4e, 0xaa, 0x61, 0x3c, 0xbc, 0x3f, 0xc4, 0xc7,
0x36, 0xdc, 0x23, 0xc8, 0xb8, 0x52, 0xe2, 0x8a, 0x80, 0x18, 0x00, 0x00, 0xb2, 0x46, 0xa2, 0x56,
0x0d, 0x12, 0x94, 0xaa, 0xbd, 0x01, 0x07, 0xff, 0xfa, 0x34, 0x0c, 0x5f, 0xf8, 0x0c, 0x12, 0x50,
0xaf, 0xd6, 0xd1, 0x89, 0x40, 0xa4, 0xff, 0xe0, 0xce, 0xc4, 0x49, 0x25, 0x9d, 0xc1, 0xff, 0x7e,
0x60, 0x24, 0x5d, 0xcc, 0x10, 0xc0, 0xbe, 0x5a, 0x12, 0xd3, 0xc3, 0xfe, 0x2d, 0x40, 0x7c, 0x28,
0x9e, 0x71, 0x01, 0xd2, 0x6e, 0x86, 0x0b, 0xc8, 0xf2, 0x9b, 0x45, 0x08, 0x4c, 0x04, 0x52, 0x7e,
0xf2, 0x7e, 0xd9, 0xcc, 0x0b, 0x1c, 0x20, 0x80, 0xae, 0xaf, 0xfe, 0xb0, 0x6d, 0x23, 0xf2, 0x41,
0xe3, 0x2e, 0x20, 0x11, 0x4b, 0x74, 0x89, 0xdd, 0xff, 0xa8, 0x38, 0xa3, 0x95, 0x82, 0x15, 0xf0,
0xd0, 0xd5, 0xf1, 0x92, 0x8e, 0xee, 0xc0, 0x26, 0x81, 0xe9, 0x47, 0xff, 0xee, 0x0d, 0x20, 0x34,
0x31, 0x3a, 0xef, 0x40, 0xb2, 0x29, 0x47, 0x19, 0x7f, 0x04, 0x27, 0xf1, 0x90, 0x85, 0x09, 0x86,
0x7d, 0x42, 0xe2, 0x54, 0x5d, 0x5f, 0xe8, 0x0e, 0xd0, 0x2c, 0xaa, 0x16, 0xbf, 0x04, 0xa7, 0xf8,
0xa2, 0x46, 0x0b, 0x08, 0x7a, 0x79, 0xe9, 0x28, 0x62, 0x7c, 0x33, 0xf4, 0x0b, 0x14, 0x82, 0xfa,
0x61, 0xeb, 0xc1, 0xff, 0x4c, 0xa4, 0x11, 0x7f, 0x03, 0x68, 0x44, 0xc1, 0x1f, 0x81, 0x3a, 0x6c,
0x77, 0x95, 0x02, 0x2b, 0x53, 0x80, 0xe5, 0x10, 0x1e, 0x90, 0xe8, 0xfd, 0x1f, 0xa6, 0x40, 0x0b,
0x13, 0xff, 0x4e, 0x4d, 0x7f, 0x52, 0xe8, 0xaf, 0x9a, 0xc1, 0x80, 0x0f, 0x0a, 0x14, 0x02, 0x3c,
0xc0, 0x09, 0x13, 0xe7, 0xdc, 0xc0, 0x1a, 0x28, 0xa0, 0xe4, 0x83, 0x8e, 0x03, 0x88, 0xd5, 0xaf,
0x1a, 0xbd, 0x91, 0x00, 0xb7, 0x4e, 0xba, 0xdf, 0xf8, 0xdb, 0xcc, 0x02, 0x43, 0xc4, 0x14, 0x2a,
0x3f, 0xc8, 0x0d, 0x09, 0x1c, 0x44, 0xf4, 0x01, 0x3c, 0xca, 0x28, 0x56, 0x80, 0xa6, 0x85, 0x00,
0xea, 0x3e, 0x8f, 0xeb, 0x9f, 0xfc, 0x6e, 0x07, 0xc4, 0xe0, 0x30, 0x78, 0xa0, 0x1e, 0x6f, 0x54,
0x78, 0x51, 0xff, 0x56, 0x4a, 0x01, 0x47, 0x02, 0x4c, 0x21, 0x3b, 0xfb, 0x90, 0x0a, 0xcc, 0x1d,
0xd2, 0x47, 0xff, 0xfc, 0x70, 0x18, 0x22, 0xc0, 0xb9, 0x2f, 0xe9, 0x7f, 0x91, 0xd3, 0x66, 0x2f,
0x80, 0x2c, 0x24, 0xa7, 0xfa, 0x84, 0x51, 0xab, 0x6b, 0x72, 0x00, 0xab, 0x33, 0x04, 0xcf, 0x43,
0xff, 0x17, 0x51, 0x84, 0x0c, 0x01, 0x50, 0x10, 0x8f, 0x90, 0x34, 0x41, 0x44, 0x84, 0x8e, 0x08,
0x19, 0x04, 0x48, 0x50, 0x84, 0x38, 0x3d, 0x02, 0x52, 0xf9, 0x7c, 0xd2, 0xd0, 0x1f, 0x13, 0x42,
0xa0, 0x21, 0x41, 0xc4, 0x02, 0x02, 0x3d, 0x09, 0xc8, 0xfd, 0x60, 0x7d, 0x35, 0x4f, 0x7f, 0xff,
0xf9, 0x97, 0x6a, 0xd8, 0x00, 0xc3, 0x83, 0x00, 0x09, 0x50, 0x4b, 0x90, 0x8a, 0xc7, 0x94, 0x4d,
0x47, 0xc1, 0x62, 0x32, 0x28, 0x24, 0x09, 0x52, 0x2e, 0x2e, 0x1c, 0x96, 0x44, 0xa0, 0x09, 0xc8,
0xce, 0x64, 0xa9, 0x1c, 0x19, 0x0e, 0x52, 0x3e, 0x3e, 0x19, 0x93, 0xa0, 0x36, 0x26, 0x22, 0x08,
0x9a, 0x00, 0xdd, 0x66, 0x3a, 0x93, 0xd5, 0x89, 0xd1, 0x40, 0x06, 0xd4, 0xa8, 0x22, 0x73, 0x7b,
0x3d, 0x3f, 0xe3, 0x04, 0x94, 0xff, 0xff, 0xff, 0xff, 0x0c, 0x56, 0x77, 0xac, 0xe0, 0xc4, 0x06,
0x1f, 0xb8, 0xa5, 0x80, 0xfd, 0x68, 0x1c, 0x32, 0x16, 0x03, 0xde, 0x71, 0x2a, 0x3d, 0x14, 0x19,
0xbe, 0xc2, 0x88, 0xd9, 0x24, 0x92, 0x5f, 0xc5, 0x90, 0x0a, 0x85, 0xc2, 0x3f, 0x87, 0x03, 0xa8,
0x26, 0x17, 0xc4, 0x06, 0x86, 0x12, 0x87, 0x76, 0x0a, 0x48, 0x16, 0xed, 0x96, 0x93, 0xec, 0x1b,
0x30, 0x73, 0xe8, 0x1a, 0x3f, 0xff, 0x4d, 0xce, 0x40, 0xf3, 0x0c, 0x51, 0x4b, 0x84, 0x9e, 0x67,
0x2b, 0x15, 0x40, 0x1a, 0xa0, 0xfc, 0x10, 0x0f, 0xd8, 0x81, 0x35, 0x87, 0xff, 0x98, 0x0f, 0x40,
0x00, 0xba, 0xc0, 0x71, 0xe2, 0x00, 0x18, 0x28, 0xb3, 0x82, 0xcc, 0x80, 0x6a, 0xa0, 0x43, 0xff,
0x2d, 0xd6, 0x04, 0x8a, 0x68, 0xff, 0xff, 0xff, 0xfc, 0x1a, 0xf3, 0x1a, 0x2a, 0x06, 0xc0, 0x01,
0x40, 0x0c, 0x30, 0xc1, 0xd0, 0xd7, 0x4f, 0xcb, 0x74, 0x1f, 0x07, 0xd3, 0xb4, 0x0d, 0x88, 0x98,
0xea, 0xda, 0x9f, 0xce, 0x2b, 0x3c, 0x55, 0xb3, 0x40, 0x14, 0xff, 0xff, 0xff, 0xea, 0xdb, 0x9b,
0x92, 0xd8, 0x68, 0x08, 0x0b, 0x41, 0x09, 0x26, 0x40, 0x8c, 0xf1, 0xb0, 0x9a, 0x98, 0xc0, 0x80,
0x8b, 0xf0, 0x3d, 0xe7, 0xec, 0x19, 0x68, 0x21, 0x03, 0x29, 0x7f, 0xe1, 0x6d, 0x4c, 0x0f, 0x01,
0xd1, 0x51, 0x01, 0x1a, 0x50, 0x2a, 0x59, 0x27, 0x80, 0xc1, 0x6e, 0x33, 0xf1, 0x80, 0xe1, 0x49,
0x08, 0xe9, 0x17, 0xff, 0xff, 0xff, 0x80, 0x5a, 0x10, 0x10, 0x36, 0x5e, 0xca, 0xf8, 0x3a, 0x00,
0x1e, 0xb0, 0x06, 0x84, 0x01, 0xf3, 0x07, 0x1b, 0x4a, 0xc0, 0x1e, 0x21, 0x43, 0x8e, 0xa5, 0x55,
0x77, 0xc7, 0x65, 0x7c, 0xc2, 0xdf, 0x5e, 0x0c, 0x42, 0x20, 0xd2, 0x48, 0x61, 0xc8, 0x1c, 0x65,
0xf8, 0xfe, 0x4c, 0x88, 0x71, 0x1f, 0x82, 0x50, 0x81, 0xa3, 0x54, 0x09, 0x13, 0x28, 0x52, 0xf5,
0xe0, 0x82, 0xc3, 0x06, 0x7f, 0xfa, 0x2c, 0xcf, 0xf8, 0xf4, 0x7f, 0xff, 0xfd, 0x01, 0x49, 0xa4,
0xb8, 0xde, 0x62, 0x84, 0xfe, 0xed, 0x65, 0x1f, 0x3c, 0x3c, 0xb2, 0x50, 0x76, 0x30, 0x5b, 0x03,
0xc0, 0x08, 0xa6, 0x64, 0x90, 0xc8, 0xcd, 0x14, 0x6e, 0x69, 0x46, 0x7a, 0xc6, 0x1c, 0x87, 0xd7,
0x48, 0x7b, 0x49, 0x05, 0x2d, 0x5e, 0x7f, 0xcb, 0x67, 0xf0, 0xd9, 0x0d, 0x1e, 0x9e, 0x53, 0xb7,
0x64, 0xa5, 0xa5, 0x10, 0x39, 0x06, 0x11, 0x3f, 0xb1, 0xa9, 0xa6, 0xe8, 0x4d, 0x47, 0x77, 0xda,
0x43, 0x76, 0x89, 0x45, 0x09, 0x70, 0xc2, 0x38, 0x0f, 0x09, 0x6f, 0xe7, 0x2d, 0x82, 0x35, 0x07,
0xfe, 0x64, 0x18, 0x2e, 0xb8, 0x04, 0x42, 0x54, 0x80, 0x43, 0x12, 0x6c, 0x9a, 0x55, 0xc9, 0x0a,
0xa0, 0x79, 0x47, 0x52, 0x65, 0x2a, 0xff, 0x50, 0x11, 0xc9, 0x4e, 0xfe, 0x5b, 0x30, 0xa4, 0xe8,
0x30, 0x63, 0xff, 0x21, 0x12, 0x1b, 0xdc, 0x1c, 0x01, 0x41, 0x51, 0x1f, 0xff, 0xfa, 0xc3, 0xe3,
0x55, 0xf1, 0x66, 0xe2, 0xd5, 0x78, 0x5e, 0xfa, 0x4d, 0xf2, 0x61, 0x01, 0x26, 0x15, 0xa9, 0xf9,
0xd9, 0x32, 0x41, 0x90, 0x36, 0x4e, 0xae, 0xe3, 0x0b, 0x16, 0x56, 0x8c, 0x6e, 0x42, 0x5d, 0xd8,
0x1e, 0xfe, 0x1d, 0x40, 0x3a, 0x50, 0x9f, 0x09, 0x14, 0xeb, 0x6e, 0x48, 0x7a, 0x91, 0x88, 0x7b,
0x7d, 0x8f, 0x72, 0x42, 0x39, 0xb0, 0x1c, 0x65, 0x18, 0x23, 0x8b, 0x60, 0x30, 0x00,
/* FRAME_END as in 4.2.3 */
0xc5, 0xcc, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00
};
static UINT32 srefImage
[] = { /* 4.2.4.4 Inverse Color Conversion */
0x00229cdf, 0x00249de0, 0x00259fe2, 0x002ca5e8, 0x00229cdf, 0x00229ce0, 0x00239de0,
0x00229ce0, 0x00229cdf, 0x00229cdf, 0x00239ce0, 0x00249ce0, 0x00249ce0, 0x00219ce3,
0x001e9ce6, 0x00209ae2, 0x002299dd, 0x002199de, 0x00209adf, 0x00209ae0, 0x001f9be0,
0x001e9ae0, 0x001d99e0, 0x001c98e0, 0x001b97df, 0x001e96dc, 0x002194d9, 0x001f93dd,
0x001d93e0, 0x001b94dc, 0x001895d8, 0x001c92db, 0x00208fde, 0x001b91de, 0x001693df,
0x001793df, 0x001992df, 0x001891df, 0x00178fdf, 0x00178edf, 0x00168dde, 0x00158cdd,
0x00148cdc, 0x00128cda, 0x00118cd9, 0x00118bd9, 0x00128ada, 0x001289da, 0x001288db,
0x001187da, 0x001186da, 0x001085da, 0x000f85d9, 0x000f84d9, 0x000e83d9, 0x000d82d8,
0x000d82d8, 0x000d81d8, 0x000d80d7, 0x000d7fd7, 0x000d7ed6, 0x000d7ed6, 0x000d7ed6,
0x000d7ed6, 0x00259fe1, 0x0027a1e2, 0x0029a2e3, 0x002ba4e6, 0x00249fe1, 0x00249fe1,
0x00249fe1, 0x00249ee1, 0x00239ee1, 0x00249ee1, 0x00249ee1, 0x00259de1, 0x00259de2,
0x00249de2, 0x00229de2, 0x00229ce1, 0x00229bdf, 0x00219ce0, 0x00209ce1, 0x00209ce2,
0x00209ce2, 0x00209ae0, 0x002199de, 0x001f99df, 0x001d98e0, 0x001e97e0, 0x001f97e0,
0x001d96df, 0x001c95de, 0x001c94e0, 0x001c94e1, 0x001d93e1, 0x001d92e0, 0x001b93de,
0x001a94dc, 0x001a93de, 0x001a93e0, 0x001992e0, 0x001891df, 0x00188fdf, 0x00178edf,
0x00168ede, 0x00158edd, 0x00148ddc, 0x00138ddb, 0x00138cdb, 0x00138bdb, 0x00128adb,
0x001289db, 0x001288db, 0x001187db, 0x001186db, 0x001085db, 0x000f84da, 0x000e83d9,
0x000e83d9, 0x000e83d9, 0x000e82d9, 0x000e81d8, 0x000e80d8, 0x000d7fd7, 0x000d7fd7,
0x000d7fd7, 0x000d7fd7, 0x0027a3e3, 0x002aa4e3, 0x002ea6e3, 0x002aa4e3, 0x0026a2e3,
0x0026a1e3, 0x0025a1e3, 0x0025a0e3, 0x0025a0e3, 0x0025a0e3, 0x00259fe3, 0x00269fe3,
0x00269ee4, 0x00279ee1, 0x00279edf, 0x00259ee0, 0x00239ee1, 0x00219ee2, 0x00209ee4,
0x00209de4, 0x00219de3, 0x00229be0, 0x002499dc, 0x002299de, 0x001f98e0, 0x001d99e4,
0x001b9ae7, 0x001c98e2, 0x001c96dc, 0x001e94e3, 0x002092ea, 0x001d94e6, 0x001a96e2,
0x001c96de, 0x001d95da, 0x001c94de, 0x001b94e1, 0x001a93e0, 0x001a92e0, 0x001991e0,
0x001890e0, 0x001790df, 0x00178fde, 0x00168fde, 0x00158edd, 0x00148ddd, 0x00138cdc,
0x00138bdc, 0x00128adc, 0x001289dc, 0x001188dc, 0x001187dd, 0x001086dd, 0x000f85db,
0x000e83d9, 0x000e84da, 0x000f84da, 0x000e83da, 0x000e82d9, 0x000e81d9, 0x000e80d8,
0x000e80d8, 0x000e80d8, 0x000e80d8, 0x002aa7e5, 0x002da7e4, 0x0031a8e3, 0x002ca6e3,
0x0027a4e4, 0x0027a3e4, 0x0027a3e4, 0x0027a3e4, 0x0026a2e4, 0x0026a2e4, 0x0027a1e5,
0x0027a0e5, 0x0027a0e6, 0x0026a0e5, 0x0025a0e4, 0x00259fe4, 0x00259ee3, 0x00239ee5,
0x00229fe6, 0x00229fe5, 0x00229fe4, 0x0013a5e6, 0x001b9fe8, 0x0016a0e8, 0x0011a0e7,
0x00129fef, 0x00139ef7, 0x001b99ec, 0x00179ae2, 0x00149ce4, 0x001d98e5, 0x001c97e6,
0x001b96e7, 0x001c98dc, 0x001d97df, 0x001c96e1, 0x001c94e2, 0x001b94e1, 0x001b93e1,
0x001a93e0, 0x001a92e0, 0x001991e0, 0x001890e0, 0x001790df, 0x00168fdf, 0x00158ede,
0x00158dde, 0x00148cdd, 0x00138bdc, 0x00128add, 0x001289dd, 0x001188de, 0x001187de,
0x000f85dc, 0x000d83da, 0x000f85db, 0x001086db, 0x000f84db, 0x000f83da, 0x000e82da,
0x000e81da, 0x000e81da, 0x000e81da, 0x000e81da, 0x002caae7, 0x0030aae5, 0x0034abe3,
0x002ea8e4, 0x0029a6e5, 0x0028a6e5, 0x0028a5e5, 0x0028a5e5, 0x0028a5e6, 0x0028a4e6,
0x0028a3e7, 0x0028a2e7, 0x0028a1e8, 0x0025a2e9, 0x0023a3ea, 0x0025a0e8, 0x00279ee6,
0x00259fe7, 0x0023a0e9, 0x0018a4f5, 0x000ea7ff, 0x001ba6de, 0x00558ebb, 0x006f839c,
0x0089797e, 0x008d797c, 0x00917979, 0x007f7b94, 0x005687af, 0x00229bd6, 0x0004a4fd,
0x00109df4, 0x001c97eb, 0x001c9ada, 0x001c98e4, 0x001c97e3, 0x001d95e2, 0x001c95e2,
0x001c94e2, 0x001c94e1, 0x001b94e1, 0x001a93e1, 0x001a92e1, 0x001991e1, 0x001890e1,
0x00178fe0, 0x00158edf, 0x00148dde, 0x00138cdd, 0x00128bde, 0x00128adf, 0x001289df,
0x001188e0, 0x000f85dd, 0x000d83da, 0x000f85db, 0x001187dd, 0x001086dc, 0x000f84dc,
0x000e83db, 0x000e81db, 0x000e81db, 0x000e81db, 0x000e81db, 0x0030abe5, 0x0036afe8,
0x0034abe4, 0x002faae5, 0x002ba8e6, 0x0036aee8, 0x0026a6e8, 0x0029a7e7, 0x002ca8e7,
0x002da7e6, 0x002fa5e5, 0x002ca5e7, 0x0029a4e9, 0x002ba5e5, 0x002ca5e2, 0x0010aaef,
0x0013adf6, 0x0023a3f8, 0x006091a5, 0x00a6755d, 0x00ec5915, 0x00ff490c, 0x00fa5504,
0x00ff590f, 0x00ff5d1b, 0x00ff6116, 0x00fa6412, 0x00ff550f, 0x00ff4b0d, 0x00fb4918,
0x00f54823, 0x008e737e, 0x00269eda, 0x0006a2ff, 0x001d97e2, 0x001799ea, 0x001c97e4,
0x001a98e4, 0x001898e4, 0x001a96e3, 0x001b95e3, 0x001a94e2, 0x001a93e0, 0x001992e1,
0x001891e2, 0x001790e1, 0x00168fe0, 0x00158fdf, 0x00138ede, 0x00138ddf, 0x00138ce0,
0x00128be0, 0x001189e0, 0x001087de, 0x000f85db, 0x00138ae0, 0x000f87dc, 0x000f86dc,
0x000f85dc, 0x000f84dc, 0x000e83db, 0x000e83db, 0x000e83db, 0x000e83db, 0x0034abe2,
0x003cb4ec, 0x0034ace5, 0x0031abe6, 0x002daae8, 0x0044b6eb, 0x0024a7ea, 0x0029aaea,
0x002face9, 0x0032a9e6, 0x0035a7e3, 0x0030a7e6, 0x002ba8ea, 0x0025aaf0, 0x0020adf6,
0x004d8ba7, 0x00b8674c, 0x00ff5510, 0x00f7650c, 0x00f86313, 0x00fa611b, 0x00f0671f,
0x00fc6222, 0x00fb6926, 0x00f96f29, 0x00f67122, 0x00f3721b, 0x00f26b20, 0x00f16424,
0x00ff5622, 0x00ff531f, 0x00ff4b17, 0x00ff440e, 0x00b1615b, 0x001f95e0, 0x00129bf0,
0x001c9ae5, 0x00189ae6, 0x00159be7, 0x001898e6, 0x001b95e5, 0x001b95e2, 0x001995e0,
0x001994e1, 0x001892e2, 0x001792e1, 0x001691e0, 0x001590df, 0x00148fdf, 0x00148fe0,
0x00148fe1, 0x00128de1, 0x00108be0, 0x001189de, 0x001186dd, 0x00178fe4, 0x000e87db,
0x000e87dc, 0x000f87dd, 0x000f85dc, 0x000e84dc, 0x000e84dc, 0x000e84dc, 0x000e84dc,
0x0036b1eb, 0x0036b4f0, 0x002eafed, 0x002caeec, 0x002aadec, 0x0041b4ef, 0x0029abe9,
0x002cabe8, 0x002fabe7, 0x0031abe6, 0x0032aae6, 0x002faae7, 0x002ca9e8, 0x0025a7eb,
0x00946a5f, 0x00ff3e06, 0x00f95618, 0x00e27312, 0x00f87329, 0x00f77427, 0x00f77626,
0x00f27628, 0x00f8712b, 0x00f9772e, 0x00f97e30, 0x00f77f2e, 0x00f5812b, 0x00f57b2c,
0x00f5752d, 0x00fd6a2b, 0x00fb652a, 0x00f65e2c, 0x00f1572e, 0x00ff4810, 0x00ff460f,
0x00817680, 0x0002a7f1, 0x002496ea, 0x00199be4, 0x001b98e4, 0x001d96e5, 0x001b96e2,
0x001a96e0, 0x001995e1, 0x001794e3, 0x001793e2, 0x001692e1, 0x001691e0, 0x001590df,
0x001591e1, 0x001591e3, 0x00138fe1, 0x00108ce0, 0x00128be0, 0x00158ae0, 0x00168de2,
0x000f89dd, 0x000f88dd, 0x000f88dd, 0x000f86dd, 0x000f85dc, 0x000f85dc, 0x000f85dc,
0x000f85dc, 0x005fc1e7, 0x0057bee8, 0x004fbbe9, 0x004ebae6, 0x004ebae3, 0x0051b6ee,
0x002eaee8, 0x002eade6, 0x002fabe5, 0x002face7, 0x002eade9, 0x002eace7, 0x002daae5,
0x0015b2ff, 0x00ec4310, 0x00f15016, 0x00f75d1c, 0x00f87123, 0x00f9862a, 0x00f6882d,
0x00f48b31, 0x00f48532, 0x00f47f33, 0x00f78535, 0x00fa8c37, 0x00f88e39, 0x00f7903a,
0x00f88b38, 0x00f98635, 0x00f87e35, 0x00f77635, 0x00f76d34, 0x00f76532, 0x00f85e31,
0x00f95730, 0x00ff5125, 0x00f65237, 0x0003a5fd, 0x001e9be1, 0x001e98e3, 0x001f96e5,
0x001c97e2, 0x001a97df, 0x001896e1, 0x001795e4, 0x001794e3, 0x001793e2, 0x001692e1,
0x001692e0, 0x001693e2, 0x001794e4, 0x001391e2, 0x000f8ee0, 0x00148ee1, 0x00198ee3,
0x00148ce1, 0x000f8bde, 0x000f8ade, 0x000f89de, 0x000f88dd, 0x000f86dd, 0x000f86dd,
0x000f86dd, 0x000f86dd, 0x003cb6ee, 0x0036b4ef, 0x0030b2f0, 0x0030b1ee, 0x002fb1ec,
0x0038b0ef, 0x002eaee9, 0x002faee8, 0x0031ade6, 0x002fafe8, 0x002eb1ea, 0x0031adec,
0x0029afee, 0x0030aac8, 0x00ff3d05, 0x00fa501a, 0x00f96021, 0x00f87428, 0x00f7882f,
0x00fa9638, 0x00f59b38, 0x00f5973b, 0x00f6923e, 0x00f89440, 0x00fa9742, 0x00fa9a44,
0x00fa9d46, 0x00f99845, 0x00f89444, 0x00f98d43, 0x00fa8641, 0x00f97d3f, 0x00f9743d,
0x00f77039, 0x00f56d35, 0x00ff6122, 0x00bf6c63, 0x00129eef, 0x00229ae8, 0x001c99ed,
0x00179ce4, 0x001498f0, 0x001b94e1, 0x001a96e2, 0x001998e3, 0x001897e4, 0x001896e5,
0x001895e4, 0x001993e2, 0x001792e1, 0x001590df, 0x001692e2, 0x001793e5, 0x001490e4,
0x00128ee2, 0x00118de3, 0x00108de3, 0x00118bde, 0x001289d9, 0x000f88e2, 0x000c89dd,
0x001085e0, 0x000987e4, 0x000987e4, 0x0040b5e9, 0x003bb4e9, 0x0037b2ea, 0x0037b2e9,
0x0038b1e8, 0x0033b0ea, 0x002eaeeb, 0x0030afe9, 0x0033afe8, 0x0030b2ea, 0x002eb5ec,
0x0034aff2, 0x0025b4f7, 0x008d7f86, 0x00f64f00, 0x00ed5c1e, 0x00fa6326, 0x00f7762d,
0x00f58a35, 0x00fea242, 0x00f7ab3f, 0x00f7a843, 0x00f7a548, 0x00f9a34a, 0x00faa24c,
0x00fba64f, 0x00fcaa52, 0x00f9a652, 0x00f7a252, 0x00fa9c50, 0x00fd974e, 0x00fc8d4b,
0x00fb8348, 0x00f68341, 0x00f1823a, 0x00f5732c, 0x00718cac, 0x00179af0, 0x002599ef,
0x002697e9, 0x00269bc6, 0x001696f1, 0x001d91e3, 0x001c96e3, 0x001b9be3, 0x001a99e6,
0x001998e9, 0x001b97e7, 0x001c95e5, 0x001891df, 0x00138dda, 0x001992e2, 0x001e98ea,
0x001592e6, 0x000b8de2, 0x000e8ee5, 0x00108fe9, 0x00128cdf, 0x001489d4, 0x000e88e6,
0x00088cdc, 0x001184e4, 0x000488ec, 0x000488ec, 0x003eb6ea, 0x003bb5eb, 0x0038b4eb,
0x0038b4eb, 0x0038b3eb, 0x0035b2eb, 0x0033b1ec, 0x0034b1eb, 0x0035b1ea, 0x0032b3e9,
0x0030b5e9, 0x0034b0f0, 0x0023b6f8, 0x00c56044, 0x00f9540c, 0x00f26322, 0x00f77029,
0x00f77d2f, 0x00f78b35, 0x00fba142, 0x00f6b046, 0x00fbb44f, 0x00f7b051, 0x00f9af54,
0x00fbad56, 0x00fcb25a, 0x00feb75d, 0x00fab35f, 0x00f6b061, 0x00faac5d, 0x00fda95a,
0x00fb9f55, 0x00f99551, 0x00f7914b, 0x00f68d45, 0x00ff7e23, 0x001ba5f0, 0x00129ef4,
0x002896f1, 0x00239fb1, 0x006c9600, 0x003c9c82, 0x00179ef8, 0x00169cf4, 0x00149de3,
0x00169ae5, 0x001897e7, 0x001995e6, 0x001a93e5, 0x001993e3, 0x001793e0, 0x001c98e6,
0x001a95e5, 0x001692e5, 0x00138fe5, 0x00138ceb, 0x00138be3, 0x000087e4, 0x00007cf5,
0x001a86d3, 0x000d8cf1, 0x00008fe2, 0x000d85ea, 0x000886f1, 0x003cb7ec, 0x003bb7ed,
0x003ab6ed, 0x0039b6ed, 0x0038b5ed, 0x0037b5ed, 0x0037b4ed, 0x0037b3ed, 0x0036b3ec,
0x0034b4e9, 0x0031b5e5, 0x0035b1ef, 0x0021b8fa, 0x00fd4203, 0x00fc581e, 0x00f86a26,
0x00f47c2d, 0x00f78431, 0x00f98c36, 0x00f8a041, 0x00f6b54d, 0x00fec05b, 0x00f6bc5a,
0x00f8ba5d, 0x00fbb861, 0x00fdbe65, 0x00ffc469, 0x00fbc16c, 0x00f5bd70, 0x00fabc6b,
0x00febb66, 0x00fab160, 0x00f6a75a, 0x00f89f55, 0x00fa984f, 0x00df956f, 0x0008a6fc,
0x00259ddb, 0x00159ff3, 0x004aa172, 0x0069a90d, 0x0062a406, 0x005a981b, 0x0034969b,
0x000e99ff, 0x001297f2, 0x001695e4, 0x001793e5, 0x001892e5, 0x001995e6, 0x001a98e7,
0x00209deb, 0x001593df, 0x001892e4, 0x001a91e9, 0x002095eb, 0x00259dd1, 0x00d0f772,
0x00c1f396, 0x000083f1, 0x001782a0, 0x003c7e2f, 0x001787cc, 0x000b8ada, 0x003db9ed,
0x003cb8ed, 0x003bb8ed, 0x003ab7ed, 0x0039b7ed, 0x0039b7ed, 0x0039b6ed, 0x003ab6ed,
0x003ab6ed, 0x0037b4ed, 0x0034b2ec, 0x0035abf3, 0x006e96b3, 0x00ff4601, 0x00f86520,
0x00f67329, 0x00f58131, 0x00f78b37, 0x00f9953e, 0x00f8a649, 0x00f8b854, 0x00fcc260,
0x00f8c465, 0x00f9c36a, 0x00fac26e, 0x00fac773, 0x00facb77, 0x00fbcb7b, 0x00fccb7e,
0x00fac87b, 0x00f8c578, 0x00f9bc72, 0x00fbb46d, 0x00f6b069, 0x00feaa57, 0x0094a0a5,
0x0013a1f3, 0x00219df0, 0x00199eff, 0x0071c124, 0x0079b826, 0x0072b21e, 0x006aaa24,
0x0067a125, 0x00649a19, 0x00419d72, 0x001f9fcb, 0x001994ff, 0x001399f1, 0x00199cf4,
0x001ea0f8, 0x001b9cff, 0x001193f6, 0x001293f1, 0x001393ec, 0x000083ff, 0x0072cca0,
0x00cbf982, 0x00d0ffac, 0x0079a046, 0x00337700, 0x003a7c03, 0x000d8de2, 0x000d8edb,
0x003fbbee, 0x003ebaed, 0x003db9ed, 0x003cb9ed, 0x003bb8ed, 0x003bb8ed, 0x003cb9ee,
0x003cb9ee, 0x003db9ef, 0x003ab4f1, 0x0037aff3, 0x0032b3fe, 0x00b48f7d, 0x00ff5907,
0x00f37122, 0x00f57c2b, 0x00f68735, 0x00f7923d, 0x00f89d45, 0x00f9ac50, 0x00f9bb5a,
0x00f9c465, 0x00facd71, 0x00facd76, 0x00facd7b, 0x00f7cf80, 0x00f4d286, 0x00fcd689,
0x00ffd98c, 0x00fbd48b, 0x00f3cf8a, 0x00f9c885, 0x00ffc17f, 0x00f5c27d, 0x00ffbc5e,
0x0048abdc, 0x001e9deb, 0x001ea2e8, 0x001da8e5, 0x0099d31c, 0x008acb22, 0x0082c427,
0x007abc2c, 0x0075b429, 0x0070ad25, 0x006dab17, 0x006ba908, 0x005ea912, 0x00519f54,
0x00489b6d, 0x003e9887, 0x003b9592, 0x00389880, 0x00449663, 0x00509446, 0x0083b43c,
0x004f851b, 0x00afe187, 0x009fcc83, 0x00368011, 0x0043821c, 0x0032853c, 0x000492f9,
0x001092dd, 0x0040bcee, 0x003fbcee, 0x003ebbee, 0x003dbaed, 0x003cbaed, 0x003cb9ed,
0x003cb9ec, 0x003cb9ec, 0x003cb8ec, 0x003fb4f0, 0x0043aff5, 0x000ebbe9, 0x00ffb897,
0x00f7814d, 0x00f57623, 0x00f6812e, 0x00f88c39, 0x00f89943, 0x00f8a64d, 0x00f8b257,
0x00f9bd60, 0x00fac96d, 0x00fbd47b, 0x00fad681, 0x00fad788, 0x00fbd98e, 0x00fbda93,
0x00fae5a1, 0x00fed692, 0x00fadea0, 0x00f9db98, 0x00fad694, 0x00fbd090, 0x00ffd285,
0x00ffc778, 0x00009afd, 0x0026a8f2, 0x0020a4f8, 0x0053bea5, 0x00a4da31, 0x009dd638,
0x0097d03a, 0x0091ca3d, 0x008bc539, 0x0085c035, 0x007dbe31, 0x0074bc2d, 0x0076b81c,
0x0077b027, 0x0072ab25, 0x006da724, 0x006ba328, 0x0068a31f, 0x0058951a, 0x0078b745,
0x00bbf181, 0x0073ad4c, 0x00417c15, 0x00508b1e, 0x0043861c, 0x00498614, 0x0017868b,
0x000b90f6, 0x00168ee8, 0x0042beef, 0x0041bdee, 0x0040bcee, 0x003fbced, 0x003ebbed,
0x003dbaec, 0x003db9eb, 0x003cb8ea, 0x003bb7e9, 0x0039b9f0, 0x0037bbf7, 0x0050b5dc,
0x00ff9744, 0x00fec49d, 0x00f87a24, 0x00f88530, 0x00f9913d, 0x00f8a049, 0x00f7af55,
0x00f8b85d, 0x00f9c065, 0x00face75, 0x00fcdb85, 0x00fbde8d, 0x00fae195, 0x00fee29b,
0x00ffe2a0, 0x00fbe9a4, 0x00ffbe6b, 0x00fdde9f, 0x00ffe8a6, 0x00fbe3a3, 0x00f8dea0,
0x00fdd899, 0x00b6bdab, 0x00119ff1, 0x001ea4e9, 0x001a9fff, 0x0089d465, 0x00b0e245,
0x00b0e04e, 0x00acdc4e, 0x00a7d94e, 0x00a1d649, 0x009ad345, 0x0097ce3d, 0x0094c935,
0x008dc534, 0x0086c133, 0x007bbc32, 0x006fb731, 0x006db330, 0x006cae2e, 0x007eba3f,
0x0070a531, 0x007bb54f, 0x00579a20, 0x005c9f2b, 0x00519425, 0x0080b965, 0x00609a1d,
0x000390e3, 0x00118ef2, 0x001c89f2, 0x0044c0ef, 0x0043bfef, 0x0042beee, 0x0040bdee,
0x003fbcee, 0x003fbbed, 0x0040baeb, 0x003eb9ed, 0x003cb9ee, 0x0037b9eb, 0x0027bcf7,
0x00949c8f, 0x00fb9637, 0x00f9bc7c, 0x00f9b585, 0x00f7994a, 0x00f69b43, 0x00f6a64e,
0x00f7b259, 0x00f8bc66, 0x00fac672, 0x00fad380, 0x00fae08d, 0x00f9e698, 0x00f9eba2,
0x00feeaa6, 0x00ffeaab, 0x00fcefa9, 0x00faba62, 0x00fbdc99, 0x00fff4b9, 0x00fbecb2,
0x00f7e6ab, 0x00ffe5a3, 0x0064b1d1, 0x00199ff0, 0x00269fe9, 0x000499f2, 0x00e3f051,
0x00d5ef58, 0x00c0e364, 0x00bde165, 0x00bae065, 0x00b5de5d, 0x00b0dc56, 0x00aad74e,
0x00a3d346, 0x009bd043, 0x0093cd3f, 0x008cc93e, 0x0084c63c, 0x0081c139, 0x007dbc36,
0x008bc746, 0x0089c245, 0x0063a02c, 0x0065aa2c, 0x005ea42d, 0x00509626, 0x00a4cf98,
0x00d9eadd, 0x00b9ddff, 0x00389ef4, 0x00008fd4, 0x0046c1ef, 0x0044c0ef, 0x0043bfef,
0x0042beef, 0x0040bdef, 0x0042bced, 0x0043baec, 0x0040baf0, 0x003dbaf4, 0x0035b8e7,
0x0017bdf7, 0x00d97f50, 0x00f79147, 0x00f7a554, 0x00ffdbba, 0x00f8a24d, 0x00f3a549,
0x00f5ad53, 0x00f7b55e, 0x00f9c16f, 0x00fbcc7f, 0x00f9d88a, 0x00f8e595, 0x00f8eda2,
0x00f8f5ae, 0x00fff3b2, 0x00fff2b6, 0x00fef5ae, 0x00f4b659, 0x00f9db93, 0x00feffcd,
0x00fbf6c1, 0x00f7edb6, 0x00fff2ac, 0x0013a4f7, 0x0016a5f0, 0x0018a5e8, 0x0056b4cd,
0x00f1f271, 0x00d5ef84, 0x00cfe67b, 0x00cde77c, 0x00cbe77c, 0x00c9e672, 0x00c7e567,
0x00bce15f, 0x00b1dd57, 0x00a9dc51, 0x00a0da4b, 0x009dd749, 0x009ad447, 0x0094cf43,
0x008fcb3f, 0x0088c43c, 0x0082be39, 0x0072b430, 0x0063a928, 0x0059a028, 0x004e9827,
0x00a0c479, 0x00fffbf7, 0x007fd3f5, 0x00038fe2, 0x000e89e2, 0x0048c3ef, 0x0046c2ef,
0x0045c1f0, 0x0043c0f0, 0x0042bff0, 0x0042beee, 0x0043bdec, 0x0041bcef, 0x003fbcf2,
0x002fc0fe, 0x0036bdfc, 0x00f54c00, 0x00ff8a52, 0x00faa65e, 0x00fdc48e, 0x00fbc185,
0x00f5ae50, 0x00f7b65e, 0x00f9be6c, 0x00fac978, 0x00fbd485, 0x00fede98, 0x00ffe8aa,
0x00fdeeae, 0x00f9f5b2, 0x00fcf6ba, 0x00fff7c2, 0x00fcf0b2, 0x00f7cc6e, 0x00fbde91,
0x00fdfcca, 0x00fffbd1, 0x00fffdc8, 0x00cae4c8, 0x0016a1f2, 0x001da4ef, 0x0012a1f1,
0x009fd5b9, 0x00eaf28c, 0x00dcf095, 0x00d9eb90, 0x00d9ec93, 0x00d9ec95, 0x00d6eb8c,
0x00d4ea83, 0x00c9e779, 0x00bfe36f, 0x00b8e368, 0x00b1e262, 0x00afe05e, 0x00addf5a,
0x00a3d952, 0x0099d449, 0x008ecb41, 0x0084c33a, 0x0075b833, 0x0066ac2c, 0x005da329,
0x00559927, 0x004b9421, 0x002499b9, 0x001593fe, 0x000993d8, 0x000f90d8, 0x004ac5ef,
0x0048c4f0, 0x0046c2f0, 0x0045c1f1, 0x0043c0f1, 0x0043bfef, 0x0043bfed, 0x0042beee,
0x0041bdf0, 0x0038bbf0, 0x0072a1b8, 0x00ff5d1e, 0x00f97931, 0x00f5a151, 0x00f9ad61,
0x00fee0bd, 0x00f8b758, 0x00fabf69, 0x00fcc87a, 0x00fcd282, 0x00fcdc8b, 0x00fbde8f,
0x00fbe193, 0x00fbeba4, 0x00fbf5b5, 0x00faf8c2, 0x00f9fcce, 0x00f9ecb7, 0x00fae183,
0x00fee290, 0x00fbfac8, 0x00fdf8d8, 0x00fffccb, 0x008bcedc, 0x00189fee, 0x0025a3ee,
0x000b9dfb, 0x00e8f6a5, 0x00e4f1a6, 0x00e4f0a6, 0x00e4efa6, 0x00e5f1aa, 0x00e6f2ad,
0x00e3f1a6, 0x00e0ef9e, 0x00d7ec93, 0x00cde987, 0x00c8ea80, 0x00c2eb78, 0x00c1ea73,
0x00c0e96e, 0x00b1e360, 0x00a3dd53, 0x0094d247, 0x0086c83b, 0x0078bc35, 0x0069b030,
0x0062a52b, 0x005b9b27, 0x0057920a, 0x000995fc, 0x000d96e5, 0x001091eb, 0x001091eb,
0x004ac5f0, 0x0049c4f0, 0x0047c3f1, 0x0045c2f1, 0x0044c1f2, 0x0041c1f2, 0x003fc1f2,
0x003fbff1, 0x003fbcf0, 0x0032c3fe, 0x00be7f6e, 0x00fe6526, 0x00f67b35, 0x00f59a4d,
0x00f8ab5c, 0x00fbd0a0, 0x00f7c783, 0x00fec16b, 0x00fdd17f, 0x00fbdb87, 0x00f9e590,
0x00f8ed9a, 0x00f7f4a5, 0x00fbea9a, 0x00ffdf8e, 0x00fce3a0, 0x00f7e6b1, 0x00fceecc,
0x00fffbcb, 0x00fff3c7, 0x00fcf1c3, 0x00fef5d2, 0x00fffcd3, 0x004bb5e7, 0x0021a5ed,
0x001ca2ee, 0x003daae2, 0x00eef6ac, 0x00e6f2b1, 0x00e8f2b5, 0x00e9f3b8, 0x00eaf4ba,
0x00ebf5bc, 0x00e8f3b6, 0x00e6f2af, 0x00e0f0a8, 0x00dbeea2, 0x00d6ef9a, 0x00d1f092,
0x00c9ed82, 0x00c1eb73, 0x00b0e362, 0x00a1dc51, 0x0094d347, 0x0088ca3e, 0x007bbf38,
0x006eb433, 0x0066a92e, 0x005da01b, 0x003d9448, 0x000a93f6, 0x000e94ec, 0x001193f0,
0x001193f0, 0x004bc5f1, 0x004ac5f1, 0x0048c4f1, 0x0047c3f2, 0x0045c3f2, 0x0040c3f4,
0x003bc4f6, 0x003cbff3, 0x003ebbf0, 0x002dcaff, 0x00ff5d25, 0x00fe6d2f, 0x00f37d39,
0x00f59348, 0x00f8a958, 0x00f7c083, 0x00f7d7ae, 0x00ffc36d, 0x00ffda84, 0x00fbe48c,
0x00f7ee94, 0x00f8ed9e, 0x00faeca7, 0x00f9f1b4, 0x00f8f6c1, 0x00fcf6c8, 0x00fff6d0,
0x00fef2d3, 0x00fcf4ba, 0x00fffee8, 0x00f7fdea, 0x00fdfde3, 0x00fffcdc, 0x000b9df1,
0x002aaaed, 0x001baaf6, 0x0080c8da, 0x00fdffbb, 0x00e8f2bd, 0x00ebf4c4, 0x00eff7cb,
0x00eff7cb, 0x00eff7cb, 0x00edf6c5, 0x00ebf5c0, 0x00eaf4be, 0x00e8f3bd, 0x00e4f4b4,
0x00e0f6ab, 0x00d0f191, 0x00c1ec77, 0x00b0e463, 0x009edb4e, 0x0095d448, 0x008bcc42,
0x007fc23b, 0x0073b935, 0x006aac31, 0x0060a510, 0x00229687, 0x000b91f1, 0x000e93f3,
0x001294f5, 0x001294f5, 0x004cc6f1, 0x004bc5f2, 0x0049c5f2, 0x0047c4f2, 0x0046c4f2,
0x0043c4f1, 0x0040c4f0, 0x0042c0f3, 0x0039c1f6, 0x005eacca, 0x00fb591e, 0x00f36e31,
0x00f88135, 0x00fb923f, 0x00fbaf5e, 0x00ffc373, 0x00fde2ba, 0x00ffcd75, 0x00ffd372,
0x00ffe584, 0x00fff796, 0x00fef4a2, 0x00fdf1ae, 0x00fff8c2, 0x00fcf8cd, 0x00fef8d2,
0x00fff9d6, 0x00fef6e1, 0x00fcf5dd, 0x00fffbee, 0x00fbfce8, 0x00fffce0, 0x00b2e0e8,
0x0019a4f0, 0x0026abec, 0x0016a8f6, 0x00c2e4d8, 0x00f9fac5, 0x00eff6cb, 0x00f0f7ce,
0x00f1f8d2, 0x00f1f8d1, 0x00f2f9d1, 0x00f1f9cd, 0x00f1f9ca, 0x00f2fbca, 0x00f4fdca,
0x00e7f8b6, 0x00daf3a2, 0x00cbef8a, 0x00bcec71, 0x00b0e661, 0x00a5e151, 0x009ad949,
0x008fd240, 0x0083c73b, 0x0077bc35, 0x006ab31d, 0x005ea905, 0x00138dea, 0x001193ef,
0x001093f0, 0x000f93f0, 0x000f93f0, 0x004dc6f2, 0x004cc6f2, 0x004ac5f3, 0x0048c5f3,
0x0047c5f3, 0x0046c4ef, 0x0046c4eb, 0x0048c0f3, 0x0034c7fb, 0x00989591, 0x00fc6428,
0x00f1773b, 0x00fc8432, 0x00ff9135, 0x00ffb564, 0x00ffbe5a, 0x00f3ddb6, 0x00ccd097,
0x00b4cea5, 0x00b0d3b1, 0x00abd7bd, 0x00c3e1bf, 0x00daebc1, 0x00f5fdc7, 0x00ffffbd,
0x00fffecd, 0x00fffcdc, 0x00fffce0, 0x00fbfce5, 0x00fdfbe6, 0x00fffae7, 0x00fffbdd,
0x0061c4f4, 0x0026aaee, 0x0022abec, 0x0010a7f6, 0x00ffffd7, 0x00f5f5d0, 0x00f6fad9,
0x00f4f9d9, 0x00f2f9da, 0x00f3fad8, 0x00f4fbd7, 0x00f5fcd5, 0x00f7fdd4, 0x00f3face,
0x00f0f7c8, 0x00e2f4b0, 0x00d4f199, 0x00c5ee82, 0x00b7eb6b, 0x00b1e95f, 0x00abe754,
0x009fdf49, 0x0094d83f, 0x0087cc3a, 0x007bc034, 0x006bb425, 0x005ba332, 0x000495f9,
0x001795ee, 0x001293ed, 0x000c91eb, 0x000c91eb, 0x004fc8f3, 0x004dc8f3, 0x004cc8f4,
0x004bc8f4, 0x0049c8f4, 0x0047c5f2, 0x0045c2ef, 0x0042c2f8, 0x0034c8ff, 0x00df6746,
0x00ff632a, 0x00ff701b, 0x00e18b53, 0x00a4a185, 0x0063c1cd, 0x0026c0ff, 0x002ab8ff,
0x0025b5f1, 0x0027b7f9, 0x0026b5f6, 0x0023b3f2, 0x0024b5fa, 0x0025b7ff, 0x00189ddf,
0x0043bbf4, 0x009edae8, 0x00f9f9dc, 0x00f3fbe6, 0x00ffffea, 0x00fdffe6, 0x00fafce2,
0x00ffffff, 0x001ea8ef, 0x001ca8f1, 0x001ba8f2, 0x005bc4f1, 0x00ffffe7, 0x00fbf9e1,
0x00fbfce3, 0x00f8fbe0, 0x00f5fadd, 0x00f5fbdb, 0x00f5fbda, 0x00f6fcd7, 0x00f6fdd3,
0x00f0f8c9, 0x00ebf4be, 0x00dff2a9, 0x00d4f094, 0x00c7f47b, 0x00baf862, 0x00b0ef58,
0x00a6e64e, 0x00a3e248, 0x0098d73a, 0x008acd38, 0x007bc435, 0x0070b821, 0x003b9c84,
0x000d93f4, 0x001394ed, 0x001193e9, 0x000f92e6, 0x000f92e6, 0x0050c9f4, 0x004fcaf4,
0x004ecaf5, 0x004dcaf5, 0x004ccaf6, 0x0048c5f4, 0x0045c0f3, 0x0047c2ef, 0x004ac4eb,
0x00ff521f, 0x00a79a92, 0x0051b7e6, 0x0028c7ff, 0x002cc4f9, 0x0031c1f1, 0x003fbbf0,
0x0037c0ef, 0x0039b9f0, 0x003bb3f1, 0x0038b5f4, 0x0036b7f7, 0x0032b9f0, 0x002fbbe8,
0x002fb8eb, 0x002fb5ed, 0x0020acf3, 0x0010a3fa, 0x0070c9f3, 0x00f5f9df, 0x00f6fbde,
0x00f6fdde, 0x00d8ebe4, 0x0011a5ee, 0x002db2f5, 0x0014a5f8, 0x00a5e2ec, 0x00fffff8,
0x00fffef3, 0x00fffded, 0x00fcfde6, 0x00f8fce0, 0x00f7fcde, 0x00f6fcdd, 0x00f6fcd8,
0x00f5fdd3, 0x00edf7c4, 0x00e5f1b4, 0x00e5f5b8, 0x00e4f9bb, 0x00ecfed2, 0x00f3ffe9,
0x00edfedb, 0x00e8f9cd, 0x00caef89, 0x009cd636, 0x0084c72e, 0x006bb826, 0x006cb315,
0x001a95d6, 0x001591ef, 0x001093eb, 0x001193e6, 0x001294e1, 0x001294e1, 0x0052cbf4,
0x0050caf4, 0x004ecaf4, 0x004ccaf3, 0x004ac9f3, 0x0048c8f5, 0x0046c7f6, 0x0040bfed,
0x0041bfeb, 0x0041d4f9, 0x0033c9fc, 0x002fc9ff, 0x0042c3ec, 0x0040c3f4, 0x003ec3fc,
0x0035bbf4, 0x0033bbf3, 0x0049bdf7, 0x0039b7f9, 0x0037b7f6, 0x0035b7f2, 0x002eb5f4,
0x0028b3f5, 0x002fbbf8, 0x002fbaf2, 0x0030b5f2, 0x0031b0f1, 0x001facf6, 0x000dabed,
0x007fd2ed, 0x00ffffe6, 0x0080d9d2, 0x002faaf8, 0x001dafec, 0x0003aae6, 0x00fff8ff,
0x00fffffe, 0x00fffff9, 0x00fffdf4, 0x00fdfeeb, 0x00fbfee3, 0x00f9fde1, 0x00f7fce0,
0x00f5fdd8, 0x00f4fdcf, 0x00f5fce2, 0x00f6fde8, 0x00f3fde8, 0x00f1fde9, 0x00ebfdd3,
0x00e6fdbe, 0x00e0f8ba, 0x00daf2b7, 0x00eafcd2, 0x00f2fde6, 0x00b7de8d, 0x0084c73d,
0x009ab848, 0x0014a1f9, 0x000494f3, 0x001094ef, 0x001095ec, 0x001095e9, 0x001095e9,
0x0054ccf5, 0x0051cbf4, 0x004ecaf3, 0x004cc9f2, 0x0049c8f1, 0x0048cbf5, 0x0048cef9,
0x0040c4f3, 0x0049cafc, 0x0040c2f1, 0x0047caf5, 0x0046c7f4, 0x0046c4f3, 0x0039b5ee,
0x002ca5e8, 0x002eb1e1, 0x0056c1ea, 0x006dc9e9, 0x0037c2e5, 0x0051caeb, 0x006bd2f1,
0x0074d1f5, 0x007dcff9, 0x0056c7f8, 0x001fafe8, 0x0025b1ee, 0x002cb3f4, 0x003eb5f9,
0x002bb3ee, 0x001baff5, 0x0032b5f0, 0x003fb2f9, 0x0026a9f2, 0x001faeeb, 0x003fb8f4,
0x00fcfff3, 0x00ffffff, 0x00ffffff, 0x00fffefb, 0x00fefff1, 0x00feffe6, 0x00fbffe5,
0x00f8fde3, 0x00f5fdd7, 0x00f3fecb, 0x00f5fbeb, 0x00f7feee, 0x00f2fdde, 0x00edfccf,
0x00e3f9b0, 0x00d9f692, 0x00d2f48b, 0x00ccf184, 0x00ceee97, 0x00d0eaa9, 0x00daebc1,
0x00f4fbe9, 0x007fc679, 0x005ac1ff, 0x001aa1eb, 0x001195f2, 0x000f96f2, 0x000e97f2,
0x000e97f2, 0x0054cdf5, 0x0052ccf4, 0x004fcbf3, 0x004dc9f3, 0x004ac8f2, 0x0049c6f2,
0x0047c4f2, 0x0049d2f3, 0x0046c8f3, 0x004dc5fc, 0x002c9add, 0x001883cd, 0x00046cbe,
0x000080c5, 0x000f96d4, 0x002eaddb, 0x0060c6eb, 0x0076cdef, 0x0051caea, 0x0069d2f0,
0x0081daf5, 0x009ae4f7, 0x00b3eff9, 0x00cffaff, 0x00e3feff, 0x009ae1ff, 0x0048bcf7,
0x0011b5dd, 0x0032aef0, 0x0028acfc, 0x0031b2f3, 0x0034b1f6, 0x0025adf0, 0x0026acf6,
0x0098d1fc, 0x00fffdf8, 0x00ffffff, 0x00fffffb, 0x00fefff4, 0x00fdffee, 0x00fcfde7,
0x00fbfee4, 0x00faffe0, 0x00f8fde7, 0x00f7fcef, 0x00f3fbeb, 0x00effdd9, 0x00e9fbc2,
0x00e3f9ac, 0x00d9f49b, 0x00ceef8b, 0x00c1ea76, 0x00b4e562, 0x00abdd5a, 0x00a2d261,
0x00c1e98e, 0x00dbe8b9, 0x0096d4ff, 0x008ed0fa, 0x0042aeee, 0x001095f1, 0x001096f1,
0x000f96f1, 0x000f96f1, 0x0055cef5, 0x0053ccf4, 0x0050cbf4, 0x004ecaf4, 0x004cc8f4,
0x0051caf7, 0x0057cbfa, 0x0045c0ea, 0x001a75c7, 0x000058ad, 0x00015bb4, 0x00066fc0,
0x000b84cd, 0x000093ce, 0x0011a7e0, 0x003eb9e6, 0x006bcbeb, 0x007ed1f6, 0x006cd3f0,
0x0082dbf4, 0x0098e3f9, 0x00a5ecf7, 0x00b2f4f5, 0x00c7f7f9, 0x00ddfafd, 0x00f2ffff,
0x00f8fff6, 0x00bcebfe, 0x0022b4f2, 0x0029afff, 0x002fb0f7, 0x0029b1f2, 0x0023b1ee,
0x001aa7fa, 0x00cae6f4, 0x00f7f8f4, 0x00feffff, 0x00fefff7, 0x00feffed, 0x00fcffeb,
0x00fbfae9, 0x00fbfee3, 0x00fbffdc, 0x00fbffe9, 0x00fbfff7, 0x00f1fedd, 0x00e7fbc3,
0x00e0f6b4, 0x00d8f0a5, 0x00ceec94, 0x00c4e884, 0x00b8e678, 0x00ace36c, 0x00a0df53,
0x0094d455, 0x0080bd41, 0x00d2e599, 0x002ca1f4, 0x0030a2f6, 0x00209cf3, 0x001096f1,
0x001096f1, 0x001096f1, 0x001096f1, 0x0055cef4, 0x0053cdf4, 0x0051cbf5, 0x0050cbf5,
0x004ecaf6, 0x004dc9f4, 0x0054d0fa, 0x002b86ce, 0x000752b1, 0x00045fb9, 0x000a74c9,
0x000882ce, 0x000691d4, 0x0002a0d5, 0x0024b5e7, 0x004cc4ea, 0x0074d3ee, 0x0083d9f5,
0x007fddf4, 0x0093e4f6, 0x00a8ecf9, 0x00b6f2f9, 0x00c3f9f9, 0x00d3fafb, 0x00e3fcfc,
0x00edfefb, 0x00f0f9f3, 0x00ffffff, 0x00fffdff, 0x007edcef, 0x0026adfd, 0x002aaff7,
0x002db2f2, 0x0034b1e0, 0x0009a7f7, 0x008dd3f5, 0x00fdfbf9, 0x00fffff6, 0x00fdffeb,
0x00fcffe6, 0x00fcfce0, 0x00f9fcde, 0x00f7fcdd, 0x00fcffef, 0x00f9fdec, 0x00e8f5d0,
0x00dff5bd, 0x00d9f1ad, 0x00d2ed9d, 0x00c5e97e, 0x00b8e26d, 0x00abdd5e, 0x009fd74f,
0x0098c95f, 0x0092c735, 0x008bc942, 0x0080b34d, 0x00009bf2, 0x001894f8, 0x001595f5,
0x001397f2, 0x001296f1, 0x001195f0, 0x001195f0, 0x0056cff4, 0x0054cdf5, 0x0052ccf5,
0x0051cbf7, 0x0051cbf9, 0x0049c8f1, 0x0051d5fa, 0x001662c1, 0x00005cbb, 0x000874cd,
0x00037cce, 0x00028dd4, 0x00019edb, 0x0009aedc, 0x0037c2ee, 0x005acfef, 0x007edcf0,
0x0088e1f4, 0x0092e6f8, 0x00a5eef8, 0x00b9f5f9, 0x00c7f9fb, 0x00d5fdfe, 0x00dffdfc,
0x00e9fdfa, 0x00f0fefe, 0x00f8ffff, 0x00fafffe, 0x00fdfffc, 0x00fdfbff, 0x001db0e8,
0x002ab1ee, 0x0037b2f5, 0x0025b9f7, 0x0029b4f8, 0x0022aff5, 0x001baaf2, 0x009fd7f6,
0x00fdffea, 0x00fcfee0, 0x00fcfdd7, 0x00f8fada, 0x00f4f7dd, 0x00fdfef5, 0x00f6fae1,
0x00dfecc3, 0x00d8efb6, 0x00d2eca6, 0x00ccea95, 0x00bce567, 0x00abdb56, 0x009fd344,
0x0092cb33, 0x0085c824, 0x0079b46a, 0x003a9eaf, 0x000c97ff, 0x001994f9, 0x000f9bee,
0x00139af0, 0x001699f3, 0x001497f1, 0x001295ef, 0x001295ef, 0x0058d0f5, 0x0056cef5,
0x0053cdf4, 0x0053ccf6, 0x0052cbf8, 0x0053d6fb, 0x004fc8fc, 0x00004cad, 0x00096fca,
0x000b80d4, 0x000588d5, 0x000598db, 0x0005a8e1, 0x0018b6e6, 0x003fc8f2, 0x0063d3f3,
0x0086dff5, 0x0091e4f7, 0x009ce9fa, 0x00aef0f9, 0x00c0f7f9, 0x00cbfafb, 0x00d7fdfd,
0x00defdfc, 0x00e6fefb, 0x00f0fffe, 0x00faffff, 0x00f2fefb, 0x00fefffd, 0x00c6e9fb,
0x001eb0ec, 0x0030b4f6, 0x0030b7f8, 0x0019a8f7, 0x0026b0f0, 0x0022aef3, 0x001eabf5,
0x0027aafa, 0x001ca6f6, 0x007dcdea, 0x00dff4dd, 0x00eaffb0, 0x00fdfeed, 0x00ffffef,
0x00fcf9d3, 0x00edeeb4, 0x00e6e9ac, 0x00d9e68a, 0x00cbe367, 0x00b9e153, 0x00a6dd4d,
0x0075c57f, 0x0043adb0, 0x00229bf3, 0x000a9cff, 0x000998f6, 0x00109cef, 0x00189aee,
0x00149ded, 0x00159bf0, 0x001599f2, 0x001397f0, 0x001195ee, 0x001195ee, 0x005ad1f6,
0x0057cff5, 0x0054cef4, 0x0054cdf6, 0x0053cbf8, 0x004dd3f4, 0x002c9add, 0x00045ec1,
0x000572c9, 0x000683d2, 0x000794dc, 0x0008a2e2, 0x0008b1e8, 0x0028bfef, 0x0048cef6,
0x006bd8f8, 0x008fe3fa, 0x009be8fa, 0x00a6edfb, 0x00b7f3fb, 0x00c7f9fa, 0x00d0fbfc,
0x00d9fdfd, 0x00defefd, 0x00e2fffc, 0x00effffe, 0x00fcffff, 0x00ebfef7, 0x00fffffe,
0x008fd7f8, 0x001eb0f1, 0x002eb0f6, 0x0018abec, 0x00e0f7fd, 0x0024ade9, 0x0023acf1,
0x0021acf8, 0x0026aef7, 0x002cb0f6, 0x001aa9f5, 0x0008a3f4, 0x0022a7f9, 0x004cc2f2,
0x006dcdef, 0x007ec9db, 0x007fcac2, 0x0081c6c6, 0x0061bccb, 0x0041b3d0, 0x0024a7e9,
0x00089bff, 0x00119dff, 0x001a9fff, 0x000f99e9, 0x00149cf9, 0x00159cf7, 0x00159cf5,
0x00179df1, 0x00199eed, 0x00179cef, 0x001599f1, 0x001397ef, 0x001195ed, 0x001195ed,
0x005cd2f6, 0x0059d0f5, 0x0055cff3, 0x0054cdf5, 0x0053ccf8, 0x0051d5f6, 0x00167bcf,
0x000467c6, 0x00067bcf, 0x00068bd7, 0x00059cdf, 0x0008a9e5, 0x000ab6eb, 0x002bc4f1,
0x004cd2f7, 0x006ddbf9, 0x008ee5fa, 0x009deafb, 0x00aceffb, 0x00bdf5fb, 0x00cefbfa,
0x00d5fbfc, 0x00dcfcfd, 0x00dcfefd, 0x00ddfffd, 0x00e4fffd, 0x00eafffd, 0x00fffffe,
0x00ffffff, 0x0027c0de, 0x0026b5f6, 0x001fb0f9, 0x004dc6ff, 0x00fff9ef, 0x00fefffa,
0x008bd8f7, 0x0018a7f3, 0x001daaf4, 0x0023acf6, 0x0022acf3, 0x0022abf0, 0x001aa3f2,
0x001aa6ee, 0x0018a8f5, 0x000ea2f3, 0x0011a4f2, 0x0014a4ff, 0x0015a3fc, 0x0016a3fa,
0x0017a2f3, 0x0019a2ec, 0x000e99fe, 0x00169bed, 0x0000a1ff, 0x002b9de8, 0x0061b5b0,
0x00109af7, 0x00149cf2, 0x00189eed, 0x00169cef, 0x00149af0, 0x001298ee, 0x001096ec,
0x001096ec, 0x005fd3f7, 0x005bd2f5, 0x0056d0f3, 0x0055cef5, 0x0053cdf7, 0x0056d8f8,
0x00005cc0, 0x000370cb, 0x000785d6, 0x000594dc, 0x0004a3e2, 0x0008afe8, 0x000cbcee,
0x002ec8f3, 0x0050d5f9, 0x006fdefa, 0x008de7fb, 0x009fecfb, 0x00b1f2fb, 0x00c3f7fb,
0x00d4fcfa, 0x00d9fcfc, 0x00defcfd, 0x00dbfdfd, 0x00d9fffd, 0x00d9fdfb, 0x00d9fcfa,
0x00e5fafa, 0x00a4eaf7, 0x002badfb, 0x002fb9fa, 0x001aaeed, 0x0099dbf8, 0x00ffffff,
0x00fefdfc, 0x00fffefd, 0x00fffffd, 0x008cd4fa, 0x0019a9f6, 0x0018a9f7, 0x0016aaf9,
0x001aa7f3, 0x001ea5ee, 0x001fa7f2, 0x0021a9f6, 0x001ea7f7, 0x001ba5f7, 0x0017a4f9,
0x0012a2fb, 0x000b9dfd, 0x000399fe, 0x0026a2fa, 0x006fc0b0, 0x00cfca5e, 0x00ffe528,
0x0074b4b3, 0x000b98fa, 0x00119af4, 0x00179dee, 0x00159cee, 0x00139aef, 0x001198ed,
0x000f96eb, 0x000f96eb, 0x005dd1f6, 0x005bd2f5, 0x0058d2f4, 0x0053cef4, 0x0056d2fb,
0x0040b2e6, 0x000164c6, 0x000376cf, 0x000487d7, 0x000296dd, 0x0001a4e4, 0x0004b1ea,
0x0007bdf1, 0x001bc8f2, 0x0043d5fc, 0x0064ddfb, 0x0085e6fb, 0x0098ebfc, 0x00acf1fd,
0x00bef9ff, 0x00cfffff, 0x00cffdff, 0x00cff9fb, 0x00d2fefe, 0x00d5ffff, 0x00c6f9ff,
0x00b8efff, 0x005ad7d9, 0x0040b9e9, 0x002fb9ff, 0x002bb2f0, 0x0028afeb, 0x00def0f2,
0x00ffffff, 0x00feffff, 0x00fffefe, 0x00fffefa, 0x00fffffa, 0x00fffff9, 0x00c2e8f0,
0x0084cde7, 0x0053bbe9, 0x0022a9eb, 0x0014a1ff, 0x00069ff8, 0x000fa0f8, 0x0019a3eb,
0x0043b1e1, 0x006ec2c9, 0x00b0d79a, 0x00f2eb6b, 0x00ebee32, 0x00f8e647, 0x00ffe23a,
0x00fde142, 0x000098f4, 0x0019a1fc, 0x00169ef7, 0x00129bf1, 0x00139af1, 0x00149af0,
0x001298ee, 0x001096ec, 0x001096ec, 0x005ccff6, 0x005bd2f6, 0x005ad4f6, 0x0052cdf2,
0x005ad6fe, 0x00298cd5, 0x00026ccc, 0x00027bd2, 0x000189d8, 0x000097df, 0x0000a6e6,
0x0000b2ed, 0x0002bef4, 0x0009c7f1, 0x0035d5ff, 0x0059ddfd, 0x007ce5fb, 0x0091eafd,
0x00a6f0ff, 0x00b1f2ff, 0x00bbf5ff, 0x00bef5fc, 0x00c1f6f9, 0x00c1f7f7, 0x00c1f9f4,
0x00c7fdfc, 0x00cdffff, 0x00c2f9f8, 0x005acdf4, 0x0039b1f3, 0x0038baf5, 0x002ab4f7,
0x00fcfbf8, 0x00fdfeff, 0x00feffff, 0x00fffeff, 0x00fffcf6, 0x00fdfef2, 0x00f7ffee,
0x00fcffea, 0x00ffffe5, 0x00ffffd8, 0x00ffffcb, 0x00fffbf1, 0x00ffffdf, 0x00fdfdc2,
0x00f7ff88, 0x00fbfe92, 0x00ffff7f, 0x00fdfc6c, 0x00faf759, 0x00f8f059, 0x00f7e958,
0x00f7e359, 0x00d0d368, 0x000998ff, 0x00189aef, 0x00129af2, 0x000c99f5, 0x001199f3,
0x001599f2, 0x001397f0, 0x001195ee, 0x001195ee, 0x005fd2f9, 0x005cd3f8, 0x0059d4f6,
0x0058d3f8, 0x005edaff, 0x001971cd, 0x00026ecd, 0x00037bd3, 0x000488d9, 0x000497e0,
0x0005a6e6, 0x0001ade7, 0x0000b5e8, 0x0007beea, 0x0023cbf5, 0x004cd7f8, 0x0074e4fc,
0x0089e8fd, 0x009fecfe, 0x00a5edfe, 0x00abeffe, 0x00aeeffc, 0x00b0eff9, 0x00b3f3f9,
0x00b6f6f8, 0x00b6f9fc, 0x00b5fcff, 0x00daf3ff, 0x001ab9f1, 0x0028b3f4, 0x002bb3f6,
0x0073cef4, 0x00fdfdf5, 0x00fdfefa, 0x00fdfffe, 0x00fffef9, 0x00fffdf3, 0x00fdfeee,
0x00faffe9, 0x00fdffe4, 0x00ffffde, 0x00ffffd0, 0x00ffffc2, 0x00fdfad7, 0x00fffcf3,
0x00ffffc0, 0x00fcfbc5, 0x00fcff84, 0x00fcfb8b, 0x00fbf67a, 0x00f9f269, 0x00f7ed5e,
0x00f4e954, 0x00f7e948, 0x0087bda9, 0x00109afc, 0x00179cf2, 0x00149bf1, 0x00119af1,
0x001399f2, 0x001698f3, 0x001496f1, 0x001294ef, 0x001294ef, 0x0062d4fc, 0x005dd4f9,
0x0059d4f6, 0x0056d1f6, 0x0053cef5, 0x00014ebe, 0x00026fcd, 0x00057bd4, 0x000787da,
0x000996e0, 0x000ca5e7, 0x000bb0e9, 0x0009bbeb, 0x0015c5f3, 0x0021d0fc, 0x0046dafc,
0x006ce3fc, 0x0082e6fd, 0x0097e9fe, 0x0099e9fe, 0x009ce8fe, 0x009ee9fb, 0x00a0e9f9,
0x00a6eefa, 0x00acf3fc, 0x00b0effc, 0x00b5ecfb, 0x0089ddf9, 0x0028b4f3, 0x003ebef7,
0x001eadf7, 0x00bde8f0, 0x00fefff2, 0x00fefff3, 0x00fdfff4, 0x00fefef2, 0x00fefef0,
0x00fefeea, 0x00fefee4, 0x00fefede, 0x00fefed8, 0x00fcffc9, 0x00fbffba, 0x00f6fea0,
0x00ffffce, 0x00fff9f6, 0x00ffffc9, 0x00fdf7be, 0x00f8f87a, 0x00f9f66b, 0x00f9f35c,
0x00f5ee56, 0x00f1e84f, 0x00f8ee37, 0x003fa7ea, 0x00189df5, 0x00179df4, 0x00169cf1,
0x00159bee, 0x00169af2, 0x001798f5, 0x001596f3, 0x001394f1, 0x001394f1, 0x0066d7fc,
0x005fd1f5, 0x0060d4f6, 0x0059d8f9, 0x00399ddb, 0x000858be, 0x00096ccd, 0x000c7ad2,
0x001087d7, 0x001296df, 0x0013a6e8, 0x0013b0eb, 0x001bc3f5, 0x000fc8f3, 0x0017d0f9,
0x0027d3f4, 0x004bd7f7, 0x0061dbf8, 0x0077def9, 0x007fe0fa, 0x0088e1fa, 0x008de4fb,
0x0091e7fb, 0x0096eafc, 0x009aedfd, 0x009feafb, 0x00a3e7fa, 0x005eccfb, 0x002db7f5,
0x0024b8f9, 0x0014b1f5, 0x00fffbff, 0x00feffec, 0x00ffffed, 0x00ffffee, 0x00ffffec,
0x00fefdeb, 0x00fefde4, 0x00fefddd, 0x00fefed6, 0x00fefece, 0x00fcfdc1, 0x00fcfcb5,
0x00f6fb8d, 0x00f8fc8a, 0x00f8facc, 0x00f8fef2, 0x00f9ffbe, 0x00fbf9c2, 0x00fbf8ac,
0x00fcf796, 0x00faf491, 0x00f7f18d, 0x00ffe5a9, 0x000096f7, 0x00089af7, 0x00159ef7,
0x00169df4, 0x00169cf0, 0x00169bf2, 0x001699f4, 0x001497f3, 0x001396f1, 0x001396f1,
0x006bd9fb, 0x0061cef1, 0x0067d3f7, 0x005cdefd, 0x001f6cc0, 0x000f63bf, 0x000f6acd,
0x001478d1, 0x001887d4, 0x001997df, 0x001aa6e9, 0x0014a9e4, 0x001dbbef, 0x000dbeeb,
0x0023c5f6, 0x0013c6ed, 0x002acbf3, 0x0040cff4, 0x0056d4f4, 0x0065d7f6, 0x0074daf7,
0x007bdffb, 0x0083e5fe, 0x0086e6fe, 0x0089e8fd, 0x008ee5fb, 0x0092e2fa, 0x0033bcfc,
0x0032b9f7, 0x0031bafd, 0x0057c5f7, 0x00f4ffde, 0x00fdffe7, 0x00ffffe7, 0x00ffffe7,
0x00ffffe6, 0x00fdfce6, 0x00fdfddd, 0x00fdfdd5, 0x00fdfdcd, 0x00fefdc5, 0x00fdfaba,
0x00fcf8af, 0x00fef99f, 0x00fffb8e, 0x00fafe77, 0x00f4fb7d, 0x00f9f8d2, 0x00fdffee,
0x00fefedf, 0x00fffcd0, 0x00fefacd, 0x00fdf9ca, 0x00a6d3ce, 0x000399eb, 0x001ea1ec,
0x00149ffa, 0x00159ef6, 0x00179ef2, 0x00169cf3, 0x00159af3, 0x001499f2, 0x001398f1,
0x001398f1, 0x0055d4f4, 0x005bd1f1, 0x0069d6f6, 0x006ee2ff, 0x000c50a8, 0x001161be,
0x000f6acd, 0x001f83d6, 0x001f89dc, 0x000f8cdd, 0x001a9be0, 0x0022b1f4, 0x001dabe1,
0x0014aedf, 0x0026bdee, 0x0015bae7, 0x001fc1ef, 0x0025c7ef, 0x002bcdef, 0x003dcdf1,
0x004ecef3, 0x005bd6f9, 0x0068defe, 0x006eddfc, 0x0073ddfb, 0x0076ddf5, 0x0070d3f7,
0x0031bafb, 0x0033b9f6, 0x0024b6ff, 0x00a4dee5, 0x00f9ffdc, 0x00fdfedc, 0x00ffffdc,
0x00ffffdc, 0x00fefedb, 0x00fcfdda, 0x00fdfdd2, 0x00fdfdcb, 0x00fdfdc3, 0x00fefdbc,
0x00fdfbaf, 0x00fcfaa2, 0x00fdfb93, 0x00fefb83, 0x00fcfd6b, 0x00f9fc60, 0x00fbf85d,
0x00fdf74c, 0x00fef576, 0x00fff2a1, 0x00f6ec87, 0x00f8e360, 0x0051bbb4, 0x000d9afe,
0x001a9ef7, 0x00159ef6, 0x00159df4, 0x00159df2, 0x00149bf2, 0x001299f2, 0x001299f2,
0x001299f2, 0x001299f2, 0x0067d4fd, 0x0069d6f9, 0x006cd9f5, 0x004fb7dc, 0x001953af,
0x001c67c6, 0x00005abd, 0x001a7eca, 0x00157bd4, 0x000581dc, 0x002aa1e7, 0x000189d3,
0x002dabe3, 0x0023a7dc, 0x0029b4e6, 0x0017ade1, 0x0014b7ec, 0x0015b9ea, 0x0016bbe9,
0x001fbfec, 0x0028c2ef, 0x003bcdf7, 0x004ed8ff, 0x0056d5fb, 0x005dd2f8, 0x005ed6f0,
0x004ec5f4, 0x002fb9fa, 0x0035b8f4, 0x0017b1ff, 0x00f0f7d2, 0x00feffda, 0x00fdfcd2,
0x00fdfdd1, 0x00fdfed1, 0x00fdfecf, 0x00fcfecd, 0x00fcfdc7, 0x00fdfdc0, 0x00fdfdb9,
0x00fdfdb2, 0x00fdfca4, 0x00fdfc95, 0x00fdfc87, 0x00fdfc79, 0x00fdfa6c, 0x00fef85f,
0x00f9f645, 0x00f6ef47, 0x00f2e938, 0x00efe428, 0x00eee425, 0x00ffdd05, 0x000399ff,
0x0017a1f5, 0x00179ef4, 0x00169cf3, 0x00159cf3, 0x00149cf3, 0x00129bf1, 0x001099f0,
0x00119af1, 0x00129bf2, 0x00129bf2, 0x0066d5fb, 0x0070d5fc, 0x0078e2ff, 0x003b86c7,
0x00235fba, 0x001e6aba, 0x00227ad1, 0x002787d8, 0x00248cd7, 0x001d8dd4, 0x002189d1,
0x002ca1ea, 0x002296d5, 0x0031aaef, 0x0020a1db, 0x0017a1dd, 0x000ea1e0, 0x001aace3,
0x0013b1eb, 0x0010b8ed, 0x000dc0ef, 0x001cc1ef, 0x002cc3f0, 0x0036c4f2, 0x0040c5f4,
0x0047c9f2, 0x0045c3f6, 0x0031bafa, 0x0031b7f7, 0x004cc2f4, 0x00f5fac0, 0x00fdffc6,
0x00fdfcc5, 0x00fdfdc4, 0x00fdfdc4, 0x00fcfdc2, 0x00fbfdc1, 0x00f8f9b6, 0x00fdfdb3,
0x00fdfdab, 0x00fdfca3, 0x00fcfc95, 0x00fcfb88, 0x00fcfb7b, 0x00fbfb6d, 0x00fcf962,
0x00fcf757, 0x00f8f245, 0x00f4eb41, 0x00f0e532, 0x00ebe023, 0x00fbe01c, 0x00c5d244,
0x000aa2fe, 0x00169ff9, 0x00179ff6, 0x00189ff3, 0x00179ef2, 0x00159df2, 0x00179ff5,
0x0018a1f8, 0x00159ef5, 0x00129bf2, 0x00129bf2, 0x0065d7fa, 0x0064d1f7, 0x005de7ff,
0x0004439b, 0x000e4ca5, 0x00317bcd, 0x000455c1, 0x000053c9, 0x000368c6, 0x002687ca,
0x002881ca, 0x002789d1, 0x002791d7, 0x000774c9, 0x00178dcf, 0x001f9ce1, 0x00179be4,
0x001e9eda, 0x000097de, 0x0003a5e6, 0x0008b1ee, 0x0009b0e8, 0x000aafe2, 0x0017b4e9,
0x0024b9ef, 0x0030bdf4, 0x003cc1f9, 0x0034bcf9, 0x002cb6f9, 0x0080d2e8, 0x00fafdaf,
0x00fcfdb3, 0x00fdfcb7, 0x00fdfcb7, 0x00fdfdb7, 0x00fcfcb6, 0x00fbfcb5, 0x00f4f4a5,
0x00fdfda5, 0x00fcfc9d, 0x00fcfc94, 0x00fbfb87, 0x00fbfb7b, 0x00fafa6e, 0x00fafa61,
0x00faf758, 0x00faf54e, 0x00f7ee44, 0x00f3e73a, 0x00ede12c, 0x00e7db1e, 0x00ffd21a,
0x0078b090, 0x0009a0fd, 0x00159dfd, 0x0018a0f8, 0x001aa2f2, 0x0018a0f2, 0x00169ef2,
0x00139bf2, 0x001099f1, 0x00119af2, 0x00129bf3, 0x00129bf3, 0x0060d4f7, 0x0067dcfd,
0x004fc2f0, 0x00002c8a, 0x002e6bc0, 0x000547ad, 0x000044ba, 0x003685c4, 0x00064ebc,
0x001462c3, 0x002d70cb, 0x000f5ab4, 0x002274cd, 0x001169c2, 0x001979c2, 0x001d80d0,
0x001980d7, 0x001a86d3, 0x001090de, 0x00038dda, 0x000599e6, 0x00059ce1, 0x00049edd,
0x0005a6e1, 0x0000a7de, 0x001fb6ee, 0x0039bdf7, 0x0038bcf6, 0x0024b5fc, 0x00bfe8b9,
0x00fafea2, 0x00fbfca5, 0x00fcfaa8, 0x00fcfca7, 0x00fdfda6, 0x00fbfca3, 0x00f9fb9f,
0x00f6f795, 0x00fafb92, 0x00fbfb8b, 0x00fbfb85, 0x00fafa79, 0x00fafa6d, 0x00f9f961,
0x00f8f956, 0x00f9f64c, 0x00f9f442, 0x00f5ec39, 0x00f2e531, 0x00efde28, 0x00ecd620,
0x00eed900, 0x0032a6e5, 0x0019a4ff, 0x0029a4f4, 0x0020a2f4, 0x0018a0f5, 0x00179ef4,
0x00159df4, 0x00139bf3, 0x001199f2, 0x00129af2, 0x00129af3, 0x00129af3, 0x005bd1f5,
0x0063dffa, 0x00318dcc, 0x00062d91, 0x000e499a, 0x0000369f, 0x00003897, 0x00155fb6,
0x0053aad9, 0x0031a6e2, 0x0045bcef, 0x006dddff, 0x0076defa, 0x006dd9f9, 0x0064d5f9,
0x0054c5f3, 0x0045b5ed, 0x00238ed6, 0x001277ce, 0x00006cc6, 0x000282de, 0x000187db,
0x00008dd7, 0x00079be1, 0x000099dc, 0x0022b1f0, 0x0036baf4, 0x003cbcf4, 0x001cb5ff,
0x00fffe89, 0x00fbff96, 0x00fbfc98, 0x00fbf99a, 0x00fcfb98, 0x00fdfd96, 0x00fafb90,
0x00f6f98a, 0x00f7f984, 0x00f8fa7f, 0x00fafa7a, 0x00fbfb75, 0x00fafa6a, 0x00f9f960,
0x00f8f855, 0x00f7f84a, 0x00f7f540, 0x00f8f336, 0x00f4eb2f, 0x00f0e328, 0x00f0da24,
0x00f0d121, 0x00e9ca24, 0x00049bff, 0x0020a3f6, 0x0016a1f7, 0x0016a0f7, 0x00169ef7,
0x00159df6, 0x00149cf5, 0x00139bf4, 0x00129af3, 0x00129af3, 0x00129af3, 0x00129af3,
0x005ae3ff, 0x0064d8ff, 0x000d4798, 0x00002682, 0x001d6bb7, 0x003aa2de, 0x005fe5ff,
0x0052d8fd, 0x004dd6f6, 0x0048ccf5, 0x005fd0f6, 0x0068d9ff, 0x0061d3f8, 0x005bd2f8,
0x0042cbff, 0x0053cefe, 0x0051cff5, 0x0049caf6, 0x004acdff, 0x0040baff, 0x000e7edb,
0x000069c2, 0x000584da, 0x000184d5, 0x00068cd8, 0x0038bef8, 0x003abef7, 0x0035beff,
0x0062c7e2, 0x00fbf379, 0x00f8fa83, 0x00f9f983, 0x00faf884, 0x00f9f77f, 0x00f7f77b,
0x00f8f979, 0x00f9fa77, 0x00f8f972, 0x00f7f86c, 0x00fcfc6c, 0x00f9f864, 0x00f8f85b,
0x00f8f752, 0x00f7f649, 0x00f6f53f, 0x00f5f237, 0x00f4ef2f, 0x00f1e628, 0x00eede20,
0x00ead61f, 0x00f2cc11, 0x009db96c, 0x000c9ffe, 0x001ba3f9, 0x0017a2f9, 0x0017a0f9,
0x00169ef8, 0x00169df7, 0x00159cf6, 0x00149bf5, 0x00139af5, 0x00139af5, 0x00139af5,
0x00139af5, 0x0060d8f9, 0x005bd9f8, 0x004cadd7, 0x0069ddff, 0x0056ddf8, 0x0055d6fc,
0x0055d0ff, 0x005cd5ff, 0x0053cbf2, 0x004bcaf6, 0x0043cafa, 0x0047c9f8, 0x004cc8f6,
0x005ccff1, 0x0046ccf8, 0x0055caff, 0x003ec4fa, 0x0043c3fb, 0x0048c2fd, 0x003ebff4,
0x0044ccfb, 0x0037b3fc, 0x000b7bdd, 0x00006dc9, 0x000d80d4, 0x004eccff, 0x003ec3fa,
0x002ec2ff, 0x00a7dea8, 0x00f8ec5b, 0x00f5f570, 0x00f7f66f, 0x00faf76e, 0x00f5f467,
0x00f1f060, 0x00f6f663, 0x00fbfc65, 0x00f8f95f, 0x00f6f659, 0x00fefe5d, 0x00f7f652,
0x00f7f54c, 0x00f7f545, 0x00f6f33d, 0x00f6f235, 0x00f3ef2f, 0x00f1eb29, 0x00efe221,
0x00ecd818, 0x00e5d21a, 0x00f3c700, 0x0052a9b4, 0x0014a4fb, 0x0015a3fb, 0x0017a3fc,
0x0017a1fa, 0x00179ff8, 0x00169df8, 0x00159cf7, 0x00159bf7, 0x001499f6, 0x001499f6,
0x001499f6, 0x001499f6, 0x0058cff2, 0x0059ddfd, 0x0055d5f9, 0x005ddeff, 0x004dcef3,
0x004dcbf3, 0x004cc8f3, 0x0056d2fc, 0x0059d3fd, 0x0050cefb, 0x0047cafa, 0x0048c9f9,
0x0049c7f9, 0x0051cbf6, 0x0045c9f9, 0x004bc8fd, 0x003fc5f9, 0x0041c4fa, 0x0043c2fb,
0x003bbdf3, 0x003ac0f4, 0x003ec7fc, 0x003ac6fc, 0x0025a1e3, 0x001f8dd9, 0x0037b9f7,
0x0026bbfa, 0x002abbf4, 0x00ced857, 0x00f9fa5b, 0x00d9db49, 0x00edec58, 0x00faf560,
0x00f2ef4d, 0x00e9ea3b, 0x00eeef46, 0x00f2f451, 0x00f9f34f, 0x00edf145, 0x00fef84b,
0x00f4f542, 0x00f5f43d, 0x00f6f337, 0x00f5f131, 0x00f5ef2b, 0x00f2eb27, 0x00f0e622,
0x00eedb1d, 0x00ecd117, 0x00f1cc09, 0x00f5c509, 0x000fadff, 0x0017a1f9, 0x0018a1f9,
0x0018a1f8, 0x0018a0f9, 0x00179ff9, 0x00169df9, 0x00169cf8, 0x00159bf8, 0x001599f8,
0x001599f8, 0x001599f8, 0x001599f8, 0x0060d5fb, 0x005bd3fb, 0x0056d2fb, 0x0055d1fc,
0x0055d0fe, 0x0054d0fa, 0x0053d1f6, 0x0051cef7, 0x004ecbf8, 0x004dcbf9, 0x004ccafb,
0x0049c8fb, 0x0047c6fc, 0x0045c6fb, 0x0043c6fa, 0x0041c6fa, 0x0040c7f9, 0x003fc5f9,
0x003ec3f9, 0x003fc3fb, 0x0041c4fd, 0x0038baf2, 0x0040c1f8, 0x003dc3fb, 0x003bc5fe,
0x0037c1f6, 0x0034beef, 0x002ebcf0, 0x00ded722, 0x00bfdc38, 0x00dee142, 0x00ecea4a,
0x00eae442, 0x00eee942, 0x00f2ee42, 0x00eeed3f, 0x00eaec3d, 0x00fbee3f, 0x00e5ec31,
0x00fff239, 0x00f2f531, 0x00f4f32e, 0x00f5f12a, 0x00f5ee25, 0x00f4ec21, 0x00f2e71e,
0x00f0e11c, 0x00eed519, 0x00ecc917, 0x00dec40c, 0x00bbbe39, 0x000798f8, 0x001a9ff8,
0x001a9ff7, 0x001a9ff5, 0x00189ff7, 0x00179ff9, 0x00179ef9, 0x00169cf9, 0x00169bf9,
0x001699f9, 0x001699f9, 0x001699f9, 0x001699f9, 0x005cd4f9, 0x0058d4f9, 0x0055d3f9,
0x0056d2fa, 0x0058d0fb, 0x0056d0f8, 0x0054d0f6, 0x0051cef7, 0x004dccf9, 0x004ccbfa,
0x004bcafb, 0x0049c8fb, 0x0047c7fb, 0x0045c7fb, 0x0043c6fa, 0x0041c6fa, 0x0040c6f9,
0x003fc4f9, 0x003ec3f9, 0x003ec2fa, 0x003ec2fb, 0x003abef5, 0x003ec2f8, 0x003bc1f9,
0x0037c0f9, 0x0036beff, 0x0035bbff, 0x0067bb84, 0x00b0d219, 0x00b4d31a, 0x00d3da39,
0x00e2dd3d, 0x00d6d532, 0x00e1df38, 0x00ece93e, 0x00e1e636, 0x00e9e536, 0x00f1e634,
0x00e5e42b, 0x00f6e62e, 0x00e9eb29, 0x00f0ee2a, 0x00f0e824, 0x00ece420, 0x00e9e01d,
0x00ebdb1c, 0x00edd71c, 0x00e9ce19, 0x00e5c516, 0x00e7c004, 0x006cb292, 0x00109dfc,
0x0018a1f7, 0x001aa0f5, 0x001ca0f3, 0x0019a0f6, 0x00179ff9, 0x00169ef9, 0x00169cf9,
0x00159bf8, 0x00159af8, 0x001499f8, 0x001499f7, 0x001499f7, 0x0058d4f6, 0x0056d4f6,
0x0054d5f7, 0x0057d3f7, 0x005bd1f8, 0x0058d0f6, 0x0054cff5, 0x0050cef8, 0x004dcdfa,
0x004bcbfb, 0x004acafb, 0x0048c9fb, 0x0046c7fb, 0x0045c7fa, 0x0043c7fa, 0x0042c6fa,
0x0040c6f9, 0x003fc4f9, 0x003ec3f9, 0x003dc1f9, 0x003cc0f9, 0x003cc1f8, 0x003cc2f7,
0x0038bff6, 0x0034bbf5, 0x0035bdfd, 0x0037beff, 0x0046bcfc, 0x0082c92c, 0x00a0be02,
0x00b8c420, 0x00d8cf31, 0x00d2d632, 0x00d4d52e, 0x00d7d42a, 0x00cdd725, 0x00e9df2f,
0x00e6dd2a, 0x00e4dc25, 0x00edd922, 0x00e0e220, 0x00ede927, 0x00eae01e, 0x00e4da1c,
0x00ded319, 0x00e5d01a, 0x00ebcd1b, 0x00e5c818, 0x00dec214, 0x00f0bc00, 0x001da5eb,
0x0019a1ff, 0x0016a2f7, 0x0019a2f4, 0x001ea2f1, 0x001aa0f5, 0x00169ff9, 0x00169ef8,
0x00159df8, 0x00159cf8, 0x00149bf8, 0x00139af7, 0x001299f6, 0x001299f6, 0x005ed5f9,
0x0063d6fc, 0x0068d6ff, 0x005fd3fc, 0x0056d0f8, 0x0053cff8, 0x0051cef8, 0x004ecdf9,
0x004bccfb, 0x004acbfb, 0x0048cafb, 0x0047c9fa, 0x0046c8fb, 0x0044c7fa, 0x0043c7fa,
0x0042c6fa, 0x0040c5f9, 0x003fc4f9, 0x003ec3f9, 0x003dc1f9, 0x003cc0f9, 0x003bc1f9,
0x003bc1f8, 0x0038bff7, 0x0036bdf7, 0x0035bdfa, 0x0034bdfe, 0x0022c3f6, 0x0027bbfc,
0x0053b0b2, 0x009bc606, 0x00c1d322, 0x00d3dd36, 0x00b4ba12, 0x00c4c71f, 0x00c5cf22,
0x00d9d82d, 0x00dfdb30, 0x00dcd52b, 0x00e8d520, 0x00d5d51c, 0x00e8e428, 0x00ece324,
0x00d1ce1f, 0x00d3c51d, 0x00dcc302, 0x00cfc312, 0x00e3c209, 0x00e3be00, 0x0084bf6e,
0x000ca0f6, 0x00129ffd, 0x0018a2f6, 0x0019a1f5, 0x001ba1f4, 0x0018a0f6, 0x00169ff8,
0x00159ef8, 0x00159df8, 0x00149cf7, 0x00139bf7, 0x00129af6, 0x001098f4, 0x001098f4,
0x0065d7fb, 0x005dd4fa, 0x0056d2f8, 0x0053d0f9, 0x0050cff9, 0x004fcef9, 0x004dcdfa,
0x004bcdfa, 0x004accfb, 0x0048cbfb, 0x0047cafb, 0x0046c9fa, 0x0045c8fa, 0x0044c7fa,
0x0043c7fa, 0x0042c6fa, 0x0040c5fa, 0x003fc4f9, 0x003ec3f9, 0x003dc1f9, 0x003bc0f9,
0x003ac0f9, 0x0039c0f9, 0x0038bff9, 0x0037bff9, 0x0034bef8, 0x0031bcf7, 0x0033bbf8,
0x0035bbfa, 0x002cbcff, 0x0061c2df, 0x0093cb85, 0x00c5d52b, 0x00cbd82f, 0x00b0bb13,
0x00b5be17, 0x00b9c21b, 0x00c7c826, 0x00c5bf21, 0x00dbc817, 0x00cac819, 0x00dbd722,
0x00ddd61a, 0x00b7bd0d, 0x00c8bd04, 0x00d0c000, 0x00adc951, 0x006cb8b1, 0x0004a3ff,
0x0013a4fb, 0x0021a4f5, 0x001ea3f5, 0x001aa1f6, 0x0019a1f6, 0x0018a0f7, 0x0017a0f7,
0x00169ff8, 0x00159ef7, 0x00149ef7, 0x00139df7, 0x00139cf6, 0x00119af4, 0x000f98f2,
0x000f98f2, 0x005cd5f9, 0x0058d3f8, 0x0053d1f8, 0x0052d0f9, 0x0050cff9, 0x004ecefa,
0x004ccdfa, 0x004accfa, 0x0048ccfa, 0x0047cbfa, 0x0046cafa, 0x0045c9fa, 0x0044c8fa,
0x0043c7fa, 0x0042c7fa, 0x0041c6fa, 0x0040c5fa, 0x003fc4f9, 0x003ec2f9, 0x003cc1f9,
0x003bc0f9, 0x003ac0f9, 0x0038bff9, 0x0037bff9, 0x0036bff9, 0x0035bdf6, 0x0034bbf3,
0x0035b9f7, 0x0035b8fb, 0x0022b5ff, 0x002fb5ff, 0x004dbae6, 0x006bbfce, 0x0027b1c5,
0x006cbc7c, 0x008abd49, 0x00a7be15, 0x00b9bf09, 0x00ccc000, 0x00dac43d, 0x00bbca20,
0x00aec73e, 0x0099bc54, 0x005aad8b, 0x0036abc4, 0x0004b3ff, 0x0015a7ff, 0x0021a4ff,
0x0019a0fb, 0x001ba2fa, 0x001da4f9, 0x001ba3f8, 0x001aa1f7, 0x0019a1f7, 0x0018a0f7,
0x0017a0f7, 0x00169ff8, 0x00159ef7, 0x00149ef7, 0x00139df7, 0x00129cf6, 0x00119af5,
0x000f99f3, 0x000f99f3, 0x0053d2f6, 0x0052d1f7, 0x0051d1f8, 0x0050d0f9, 0x004fcffa,
0x004dcefa, 0x004bcdfa, 0x0049ccfa, 0x0047cbfa, 0x0046caf9, 0x0045caf9, 0x0044c9f9,
0x0044c8fa, 0x0043c7fa, 0x0042c6f9, 0x0041c6f9, 0x0040c5fa, 0x003fc4f9, 0x003dc2f9,
0x003cc1f9, 0x003ac0f9, 0x0039c0f9, 0x0038bff9, 0x0036bff9, 0x0035bef8, 0x0036bcf4,
0x0038baf0, 0x0036b8f6, 0x0034b5fc, 0x002cb6f9, 0x0023b7f6, 0x0025b5fa, 0x0028b4ff,
0x0028b6ff, 0x0029b7ff, 0x001fb5ff, 0x0015b2ff, 0x0020aef7, 0x003cb9ff, 0x005acbf0,
0x0042befa, 0x002ab6fc, 0x0012adff, 0x0018acfc, 0x001eacfa, 0x001ea9fd, 0x001ea7ff,
0x001ba8fa, 0x0018a8f4, 0x0018a6f8, 0x0018a4fd, 0x0019a3fa, 0x001aa1f7, 0x0019a1f7,
0x0018a0f8, 0x0017a0f8, 0x00169ff8, 0x00159ef7, 0x00149df7, 0x00139cf6, 0x00129bf6,
0x00119af5, 0x001099f4, 0x001099f4, 0x0054d1f8, 0x0052d1f8, 0x0051d0f9, 0x004fcff9,
0x004ecffa, 0x004ccefa, 0x004acdf9, 0x0048ccf9, 0x0045cbf9, 0x0045caf9, 0x0044c9f9,
0x0043c8f9, 0x0043c8f9, 0x0042c7f9, 0x0042c6f9, 0x0041c5f9, 0x0040c5fa, 0x003fc4f9,
0x003dc2f9, 0x003bc1f9, 0x003ac0fa, 0x0038bff9, 0x0037bff9, 0x0036bef9, 0x0034bef8,
0x0035bcf6, 0x0035baf5, 0x0034b8f8, 0x0033b6fc, 0x002eb6f9, 0x0029b6f7, 0x0029b5f8,
0x002ab4fa, 0x002ab5fb, 0x002ab5fc, 0x002ab2f6, 0x002aafef, 0x001ba9f6, 0x009bcfd9,
0x006dcfe9, 0x0074c7e4, 0x0080c9dd, 0x0019adfb, 0x001cacf9, 0x001fabf8, 0x001fa9f9,
0x001ea7fb, 0x001ca7f9, 0x001aa7f6, 0x001aa5f8, 0x001aa4fb, 0x001aa3fa, 0x001aa2f8,
0x0019a1f8, 0x0018a0f8, 0x0017a0f8, 0x00169ff8, 0x00159ef7, 0x00149df7, 0x00139cf6,
0x00129bf6, 0x00119bf5, 0x00119af5, 0x00119af5, 0x0055d0f9, 0x0053d0fa, 0x0051d0fa,
0x004fcffa, 0x004dcffa, 0x004bcefa, 0x0049cdf9, 0x0046ccf9, 0x0044caf8, 0x0043caf8,
0x0043c9f8, 0x0043c8f9, 0x0042c8f9, 0x0042c7f9, 0x0041c6f9, 0x0041c6f9, 0x0040c5fa,
0x003ec3f9, 0x003dc2fa, 0x003bc1fa, 0x0039c0fa, 0x0038bff9, 0x0036bff9, 0x0035bef9,
0x0034bdf8, 0x0033bcf9, 0x0033bafa, 0x0032b9fb, 0x0032b8fc, 0x0030b7fa, 0x002eb6f8,
0x002db5f7, 0x002bb4f5, 0x002bb4f6, 0x002bb3f7, 0x0029b2f9, 0x0028b2fc, 0x0030b2f7,
0x0012a8fe, 0x007fd4e1, 0x0058bbe6, 0x0015aafb, 0x001fadf8, 0x0020acf7, 0x0020aaf5,
0x001fa9f6, 0x001ea8f7, 0x001da6f7, 0x001ca5f8, 0x001ca4f8, 0x001ba3f9, 0x001ba3f9,
0x001ba2f9, 0x0019a1f9, 0x0018a0f8, 0x0017a0f8, 0x00169ff8, 0x00159ef7, 0x00149df7,
0x00139cf6, 0x00129bf5, 0x00129bf5, 0x00129bf5, 0x00129bf5, 0x0055d0f9, 0x0053d0fa,
0x0051d0fa, 0x004fcffa, 0x004dcffa, 0x004bcefa, 0x0049cdf9, 0x0046ccf9, 0x0044caf8,
0x0043caf8, 0x0043c9f8, 0x0043c8f9, 0x0042c8f9, 0x0042c7f9, 0x0041c6f9, 0x0041c6f9,
0x0040c5fa, 0x003ec3f9, 0x003dc2fa, 0x003bc1fa, 0x0039c0fa, 0x0038bff9, 0x0036bff9,
0x0035bef9, 0x0034bdf8, 0x0033bcf9, 0x0033bafa, 0x0032b9fb, 0x0032b8fc, 0x0030b7fa,
0x002eb6f8, 0x002db5f7, 0x002bb4f5, 0x002bb4f6, 0x002bb3f7, 0x002ab2f8, 0x0029b2fa,
0x002db6f5, 0x001db5f6, 0x00239bff, 0x0020b6f3, 0x000cacfb, 0x001eacf7, 0x001fabf6,
0x0020aaf5, 0x001fa9f6, 0x001ea8f7, 0x001da6f7, 0x001ca5f8, 0x001ca4f8, 0x001ba3f9,
0x001ba3f9, 0x001ba2f9, 0x0019a1f9, 0x0018a0f8, 0x0017a0f8, 0x00169ff8, 0x00159ef7,
0x00149df7, 0x00139cf6, 0x00129bf5, 0x00129bf5, 0x00129bf5, 0x00129bf5, 0x0055d0f9,
0x0053d0fa, 0x0051d0fa, 0x004fcffa, 0x004dcffa, 0x004bcefa, 0x0049cdf9, 0x0046ccf9,
0x0044caf8, 0x0043caf8, 0x0043c9f8, 0x0043c8f9, 0x0042c8f9, 0x0042c7f9, 0x0041c6f9,
0x0041c6f9, 0x0040c5fa, 0x003ec3f9, 0x003dc2fa, 0x003bc1fa, 0x0039c0fa, 0x0038bff9,
0x0036bff9, 0x0035bef9, 0x0034bdf8, 0x0033bcf9, 0x0033bafa, 0x0032b9fb, 0x0032b8fc,
0x0030b7fa, 0x002eb6f8, 0x002db5f7, 0x002bb4f5, 0x002bb4f6, 0x002bb3f7, 0x002bb2f8,
0x002bb1f8, 0x0022aff9, 0x0019acfa, 0x001eadf7, 0x0024aef3, 0x0020adf5, 0x001dabf6,
0x001fabf6, 0x0020aaf5, 0x001fa9f6, 0x001ea8f7, 0x001da6f7, 0x001ca5f8, 0x001ca4f8,
0x001ba3f9, 0x001ba3f9, 0x001ba2f9, 0x0019a1f9, 0x0018a0f8, 0x0017a0f8, 0x00169ff8,
0x00159ef7, 0x00149df7, 0x00139cf6, 0x00129bf5, 0x00129bf5, 0x00129bf5, 0x00129bf5,
0x0055d0f9, 0x0053d0fa, 0x0051d0fa, 0x004fcffa, 0x004dcffa, 0x004bcefa, 0x0049cdf9,
0x0046ccf9, 0x0044caf8, 0x0043caf8, 0x0043c9f8, 0x0043c8f9, 0x0042c8f9, 0x0042c7f9,
0x0041c6f9, 0x0041c6f9, 0x0040c5fa, 0x003ec3f9, 0x003dc2fa, 0x003bc1fa, 0x0039c0fa,
0x0038bff9, 0x0036bff9, 0x0035bef9, 0x0034bdf8, 0x0033bcf9, 0x0033bafa, 0x0032b9fb,
0x0032b8fc, 0x0030b7fa, 0x002eb6f8, 0x002db5f7, 0x002bb4f5, 0x002bb4f6, 0x002bb3f7,
0x002bb2f8, 0x002bb1f8, 0x0022aff9, 0x0019acfa, 0x001eadf7, 0x0024aef3, 0x0020adf5,
0x001dabf6, 0x001fabf6, 0x0020aaf5, 0x001fa9f6, 0x001ea8f7, 0x001da6f7, 0x001ca5f8,
0x001ca4f8, 0x001ba3f9, 0x001ba3f9, 0x001ba2f9, 0x0019a1f9, 0x0018a0f8, 0x0017a0f8,
0x00169ff8, 0x00159ef7, 0x00149df7, 0x00139cf6, 0x00129bf5, 0x00129bf5, 0x00129bf5,
0x00129bf5
};
#define IMG_WIDTH 64ULL
#define IMG_HEIGHT 64ULL
#define FORMAT_SIZE 4ULL
#define FORMAT PIXEL_FORMAT_XRGB32
static inline size_t fuzzyCompare(BYTE b1, BYTE b2)
{
if (b1 > b2)
return b1 - b2;
return b2 - b1;
}
static BOOL fuzzyCompareImage(const UINT32* crefImage, const BYTE* img, size_t npixels)
{
size_t totalDelta = 0;
for (size_t i = 0; i < npixels; i++, crefImage++)
{
BYTE A = *img++;
BYTE R = *img++;
BYTE G = *img++;
BYTE B = *img++;
size_t delta = 0;
if (A != 0x00)
return FALSE;
delta = fuzzyCompare(R, (*crefImage & 0x00ff0000) >> 16);
if (delta > 1)
return FALSE;
totalDelta += delta;
delta = fuzzyCompare(G, (*crefImage & 0x0000ff00) >> 8);
if (delta > 1)
return FALSE;
totalDelta += delta;
delta = fuzzyCompare(B, (*crefImage & 0x0000ff));
if (delta > 1)
return FALSE;
totalDelta += delta;
}
WLog_DBG("test", "totalDelta=%d (npixels=%d)", totalDelta, npixels);
return TRUE;
}
int TestFreeRDPCodecRemoteFX(int argc, char* argv[])
{
int rc = -1;
REGION16 region = WINPR_C_ARRAY_INIT;
RFX_CONTEXT* context = nullptr;
BYTE* dest = nullptr;
size_t stride = FORMAT_SIZE * IMG_WIDTH;
WINPR_UNUSED(argc);
WINPR_UNUSED(argv);
/* use default threading options here, pass zero as
* ThreadingFlags */
context = rfx_context_new(FALSE);
if (!context)
goto fail;
dest = calloc(IMG_WIDTH * IMG_HEIGHT, FORMAT_SIZE);
if (!dest)
goto fail;
region16_init(&region);
if (!rfx_process_message(context, encodeHeaderSample, sizeof(encodeHeaderSample), 0, 0, dest,
FORMAT, stride, IMG_HEIGHT, &region))
goto fail;
region16_clear(&region);
if (!rfx_process_message(context, encodeDataSample, sizeof(encodeDataSample), 0, 0, dest,
FORMAT, stride, IMG_HEIGHT, &region))
goto fail;
region16_print(&region);
if (!fuzzyCompareImage(srefImage, dest, IMG_WIDTH * IMG_HEIGHT))
goto fail;
rc = 0;
fail:
region16_uninit(&region);
rfx_context_free(context);
free(dest);
return rc;
}
@@ -0,0 +1,128 @@
#include <winpr/crt.h>
#include <winpr/print.h>
#include "../xcrush.h"
static const BYTE TEST_BELLS_DATA[] = "for.whom.the.bell.tolls,.the.bell.tolls.for.thee!";
static const BYTE TEST_BELLS_DATA_XCRUSH[] =
"\x66\x6f\x72\x2e\x77\x68\x6f\x6d\x2e\x74\x68\x65\x2e\x62"
"\x65\x6c\x6c\x2e\x74\x6f\x6c\x6c\x73\x2c\x2e\x74\x68\x65\x2e\x62"
"\x65\x6c\x6c\x2e\x74\x6f\x6c\x6c\x73\x2e\x66\x6f\x72\x2e\x74\x68"
"\x65\x65\x21";
static const BYTE TEST_ISLAND_DATA[] = "No man is an island entire of itself; every man "
"is a piece of the continent, a part of the main; "
"if a clod be washed away by the sea, Europe "
"is the less, as well as if a promontory were, as"
"well as any manner of thy friends or of thine "
"own were; any man's death diminishes me, "
"because I am involved in mankind. "
"And therefore never send to know for whom "
"the bell tolls; it tolls for thee.";
static const BYTE TEST_ISLAND_DATA_XCRUSH[] =
"\x12\x61\x4e\x6f\x20\x6d\x61\x6e\x20\x69\x73\x20\xf8\xd2\xd8\xc2"
"\xdc\xc8\x40\xca\xdc\xe8\xd2\xe4\xca\x40\xde\xcc\x40\xd2\xe8\xe6"
"\xca\xd8\xcc\x76\x40\xca\xec\xca\xe4\xf3\xfa\x71\x20\x70\x69\x65"
"\x63\xfc\x12\xe8\xd0\xca\x40\xc6\xdf\xfb\xcd\xdf\xd0\x58\x40\xc2"
"\x40\xe0\xc2\xe4\xe9\xfe\x63\xec\xc3\x6b\x0b\x4b\x71\xd9\x03\x4b"
"\x37\xd7\x31\xb6\x37\xb2\x10\x31\x32\x90\x3b\xb0\xb9\xb4\x32\xb2"
"\x10\x30\xbb\xb0\xbc\x90\x31\x3c\x90\x7e\x68\x73\x65\x61\x2c\x20"
"\x45\x75\x72\x6f\x70\x65\xf2\x34\x7d\x38\x6c\x65\x73\x73\xf0\x69"
"\xcc\x81\xdd\x95\xb1\xb0\x81\x85\xcf\xc0\x94\xe0\xe4\xde\xdb\xe2"
"\xb3\x7f\x92\x4e\xec\xae\x4c\xbf\x86\x3f\x06\x0c\x2d\xde\x5d\x96"
"\xe6\x57\x2f\x1e\x53\xc9\x03\x33\x93\x4b\x2b\x73\x23\x99\x03\x7f"
"\xd2\xb6\x96\xef\x38\x1d\xdb\xbc\x24\x72\x65\x3b\xf5\x5b\xf8\x49"
"\x3b\x99\x03\x23\x2b\x0b\xa3\x41\x03\x23\x4b\x6b\x4b\x73\x4f\x96"
"\xce\x64\x0d\xbe\x19\x31\x32\xb1\xb0\xba\xb9\xb2\x90\x24\x90\x30"
"\xb6\x90\x34\xb7\x3b\x37\xb6\x3b\x79\xd4\xd2\xdd\xec\x18\x6b\x69"
"\x6e\x64\x2e\x20\x41\xf7\x33\xcd\x47\x26\x56\x66\xff\x74\x9b\xbd"
"\xbf\x04\x0e\x7e\x31\x10\x3a\x37\x90\x35\xb7\x37\xbb\x90\x7d\x81"
"\x03\xbb\x43\x7b\x6f\xa8\xe5\x8b\xd0\xf0\xe8\xde\xd8\xd8\xe7\xec"
"\xf3\xa7\xe4\x7c\xa7\xe2\x9f\x01\x99\x4b\x80";
static void test_dump(const char* fkt, const void* generated, size_t generated_size,
const void* expected, size_t expected_size)
{
printf("[%s] output size mismatch: Actual: %" PRIuz ", Expected: %" PRIuz "\n", fkt,
generated_size, expected_size);
printf("[%s] Actual\n", fkt);
winpr_HexDump(fkt, WLOG_INFO, generated, generated_size);
printf("[%s] Expected\n", fkt);
winpr_HexDump(fkt, WLOG_INFO, expected, expected_size);
}
static BOOL test_compare(const char* fkt, const void* generated, size_t generated_size,
const void* expected, size_t expected_size)
{
if (generated_size != expected_size)
{
test_dump(fkt, generated, generated_size, expected, expected_size);
return FALSE;
}
if (memcmp(generated, expected, generated_size) != 0)
{
test_dump(fkt, generated, generated_size, expected, expected_size);
return FALSE;
}
return TRUE;
}
static BOOL test_run(const char* fkt, const void* src, UINT32 src_size, const void* expected,
size_t expected_size)
{
BOOL rc = FALSE;
int status = -1;
UINT32 Flags = 0;
const BYTE* pDstData = nullptr;
BYTE OutputBuffer[65536] = WINPR_C_ARRAY_INIT;
UINT32 DstSize = sizeof(OutputBuffer);
XCRUSH_CONTEXT* xcrush = xcrush_context_new(TRUE);
if (!xcrush)
return -1;
status = xcrush_compress(xcrush, src, src_size, OutputBuffer, &pDstData, &DstSize, &Flags);
printf("[%s] status: %d Flags: 0x%08" PRIX32 " DstSize: %" PRIu32 "\n", fkt, status, Flags,
DstSize);
rc = test_compare(fkt, pDstData, DstSize, expected, expected_size);
xcrush_context_free(xcrush);
return rc;
}
struct test_argument
{
const char* name;
const void* src;
UINT32 src_size;
const void* expected;
size_t expected_size;
};
static const struct test_argument tests[] = {
{ "XCrushCompressIsland", TEST_ISLAND_DATA, sizeof(TEST_ISLAND_DATA) - 1,
TEST_ISLAND_DATA_XCRUSH, sizeof(TEST_ISLAND_DATA_XCRUSH) - 1 },
{ "XCrushCompressBells", TEST_BELLS_DATA, sizeof(TEST_BELLS_DATA) - 1, TEST_BELLS_DATA_XCRUSH,
sizeof(TEST_BELLS_DATA_XCRUSH) - 1 }
};
int TestFreeRDPCodecXCrush(int argc, char* argv[])
{
int rc = 0;
WINPR_UNUSED(argc);
WINPR_UNUSED(argv);
for (size_t x = 0; x < ARRAYSIZE(tests); x++)
{
const struct test_argument* arg = &tests[x];
if (!test_run(arg->name, arg->src, arg->src_size, arg->expected, arg->expected_size))
rc = -1;
}
return rc;
}
@@ -0,0 +1,274 @@
#include <winpr/crt.h>
#include <winpr/print.h>
#include <winpr/bitstream.h>
#include <freerdp/freerdp.h>
#include <freerdp/codec/zgfx.h>
#include <freerdp/log.h>
/* Sample from [MS-RDPEGFX] */
static const BYTE TEST_FOX_DATA[] = "The quick brown "
"fox jumps over t"
"he lazy dog";
static const BYTE TEST_FOX_DATA_SINGLE[] =
"\xE0\x04\x54\x68\x65\x20\x71\x75\x69\x63\x6B\x20\x62\x72\x6F\x77"
"\x6E\x20\x66\x6F\x78\x20\x6A\x75\x6D\x70\x73\x20\x6F\x76\x65\x72"
"\x20\x74\x68\x65\x20\x6C\x61\x7A\x79\x20\x64\x6F\x67";
static const BYTE TEST_FOX_DATA_MULTIPART[] =
"\xE1\x03\x00\x2B\x00\x00\x00\x11\x00\x00\x00\x04\x54\x68\x65\x20"
"\x71\x75\x69\x63\x6B\x20\x62\x72\x6F\x77\x6E\x20\x0E\x00\x00\x00"
"\x04\x66\x6F\x78\x20\x6A\x75\x6D\x70\x73\x20\x6F\x76\x65\x10\x00"
"\x00\x00\x24\x39\x08\x0E\x91\xF8\xD8\x61\x3D\x1E\x44\x06\x43\x79"
"\x9C\x02";
static int test_ZGfxCompressFox(void)
{
int rc = -1;
int status = 0;
UINT32 Flags = 0;
const BYTE* pSrcData = nullptr;
UINT32 SrcSize = 0;
UINT32 DstSize = 0;
BYTE* pDstData = nullptr;
ZGFX_CONTEXT* zgfx = nullptr;
UINT32 expectedSize = 0;
zgfx = zgfx_context_new(TRUE);
if (!zgfx)
return -1;
SrcSize = sizeof(TEST_FOX_DATA) - 1;
pSrcData = (const BYTE*)TEST_FOX_DATA;
Flags = 0;
expectedSize = sizeof(TEST_FOX_DATA_SINGLE) - 1;
status = zgfx_compress(zgfx, pSrcData, SrcSize, &pDstData, &DstSize, &Flags);
if (status < 0)
goto fail;
printf("flags: 0x%08" PRIX32 " size: %" PRIu32 "\n", Flags, DstSize);
if (DstSize != expectedSize)
{
printf("test_ZGfxCompressFox: output size mismatch: Actual: %" PRIu32 ", Expected: %" PRIu32
"\n",
DstSize, expectedSize);
goto fail;
}
if (memcmp(pDstData, TEST_FOX_DATA_SINGLE, DstSize) != 0)
{
printf("test_ZGfxCompressFox: output mismatch\n");
printf("Actual\n");
BitDump(__func__, WLOG_INFO, pDstData, DstSize * 8, 0);
printf("Expected\n");
BitDump(__func__, WLOG_INFO, TEST_FOX_DATA_SINGLE, DstSize * 8, 0);
goto fail;
}
rc = 0;
fail:
free(pDstData);
zgfx_context_free(zgfx);
return rc;
}
static int test_ZGfxDecompressFoxSingle(void)
{
int rc = -1;
int status = 0;
UINT32 Flags = 0;
const BYTE* pSrcData = nullptr;
UINT32 SrcSize = 0;
UINT32 DstSize = 0;
BYTE* pDstData = nullptr;
ZGFX_CONTEXT* zgfx = nullptr;
UINT32 expectedSize = 0;
zgfx = zgfx_context_new(TRUE);
if (!zgfx)
return -1;
SrcSize = sizeof(TEST_FOX_DATA_SINGLE) - 1;
pSrcData = (const BYTE*)TEST_FOX_DATA_SINGLE;
Flags = 0;
expectedSize = sizeof(TEST_FOX_DATA) - 1;
status = zgfx_decompress(zgfx, pSrcData, SrcSize, &pDstData, &DstSize, Flags);
if (status < 0)
goto fail;
printf("flags: 0x%08" PRIX32 " size: %" PRIu32 "\n", Flags, DstSize);
if (DstSize != expectedSize)
{
printf("test_ZGfxDecompressFoxSingle: output size mismatch: Actual: %" PRIu32
", Expected: %" PRIu32 "\n",
DstSize, expectedSize);
goto fail;
}
if (memcmp(pDstData, TEST_FOX_DATA, DstSize) != 0)
{
printf("test_ZGfxDecompressFoxSingle: output mismatch\n");
printf("Actual\n");
BitDump(__func__, WLOG_INFO, pDstData, DstSize * 8, 0);
printf("Expected\n");
BitDump(__func__, WLOG_INFO, TEST_FOX_DATA, DstSize * 8, 0);
goto fail;
}
rc = 0;
fail:
free(pDstData);
zgfx_context_free(zgfx);
return rc;
}
static int test_ZGfxDecompressFoxMultipart(void)
{
int rc = -1;
int status = 0;
UINT32 Flags = 0;
const BYTE* pSrcData = nullptr;
UINT32 SrcSize = 0;
UINT32 DstSize = 0;
BYTE* pDstData = nullptr;
ZGFX_CONTEXT* zgfx = nullptr;
UINT32 expectedSize = 0;
zgfx = zgfx_context_new(TRUE);
if (!zgfx)
return -1;
SrcSize = sizeof(TEST_FOX_DATA_MULTIPART) - 1;
pSrcData = (const BYTE*)TEST_FOX_DATA_MULTIPART;
Flags = 0;
expectedSize = sizeof(TEST_FOX_DATA) - 1;
status = zgfx_decompress(zgfx, pSrcData, SrcSize, &pDstData, &DstSize, Flags);
if (status < 0)
goto fail;
printf("flags: 0x%08" PRIX32 " size: %" PRIu32 "\n", Flags, DstSize);
if (DstSize != expectedSize)
{
printf("test_ZGfxDecompressFoxSingle: output size mismatch: Actual: %" PRIu32
", Expected: %" PRIu32 "\n",
DstSize, expectedSize);
goto fail;
}
if (memcmp(pDstData, TEST_FOX_DATA, DstSize) != 0)
{
printf("test_ZGfxDecompressFoxSingle: output mismatch\n");
printf("Actual\n");
BitDump(__func__, WLOG_INFO, pDstData, DstSize * 8, 0);
printf("Expected\n");
BitDump(__func__, WLOG_INFO, TEST_FOX_DATA, DstSize * 8, 0);
goto fail;
}
rc = 0;
fail:
free(pDstData);
zgfx_context_free(zgfx);
return rc;
}
static int test_ZGfxCompressConsistent(void)
{
int rc = -1;
int status = 0;
UINT32 Flags = 0;
const BYTE* pSrcData = nullptr;
UINT32 SrcSize = 0;
UINT32 DstSize = 0;
BYTE* pDstData = nullptr;
UINT32 DstSize2 = 0;
BYTE* pDstData2 = nullptr;
ZGFX_CONTEXT* zgfx = nullptr;
UINT32 expectedSize = 0;
BYTE BigBuffer[65536];
memset(BigBuffer, 0xaa, sizeof(BigBuffer));
memcpy(BigBuffer, TEST_FOX_DATA, sizeof(TEST_FOX_DATA) - 1);
zgfx = zgfx_context_new(TRUE);
if (!zgfx)
return -1;
/* Compress */
expectedSize = SrcSize = sizeof(BigBuffer);
pSrcData = (const BYTE*)BigBuffer;
Flags = 0;
status = zgfx_compress(zgfx, pSrcData, SrcSize, &pDstData2, &DstSize2, &Flags);
if (status < 0)
goto fail;
printf("Compress: flags: 0x%08" PRIX32 " size: %" PRIu32 "\n", Flags, DstSize2);
/* Decompress */
status = zgfx_decompress(zgfx, pDstData2, DstSize2, &pDstData, &DstSize, Flags);
if (status < 0)
goto fail;
printf("Decompress: flags: 0x%08" PRIX32 " size: %" PRIu32 "\n", Flags, DstSize);
if (DstSize != expectedSize)
{
printf("test_ZGfxDecompressFoxSingle: output size mismatch: Actual: %" PRIu32
", Expected: %" PRIu32 "\n",
DstSize, expectedSize);
goto fail;
}
if (memcmp(pDstData, BigBuffer, DstSize) != 0)
{
printf("test_ZGfxDecompressFoxSingle: output mismatch\n");
printf("Actual\n");
BitDump(__func__, WLOG_INFO, pDstData, 64 * 8, 0);
printf("...\n");
BitDump(__func__, WLOG_INFO, pDstData + DstSize - 64, 64 * 8, 0);
printf("Expected\n");
BitDump(__func__, WLOG_INFO, BigBuffer, 64 * 8, 0);
printf("...\n");
BitDump(__func__, WLOG_INFO, BigBuffer + DstSize - 64, 64 * 8, 0);
printf("Middle Result\n");
BitDump(__func__, WLOG_INFO, pDstData2, 64 * 8, 0);
printf("...\n");
BitDump(__func__, WLOG_INFO, pDstData2 + DstSize2 - 64, 64 * 8, 0);
goto fail;
}
rc = 0;
fail:
free(pDstData);
free(pDstData2);
zgfx_context_free(zgfx);
return rc;
}
int TestFreeRDPCodecZGfx(int argc, char* argv[])
{
WINPR_UNUSED(argc);
WINPR_UNUSED(argv);
if (test_ZGfxCompressFox() < 0)
return -1;
if (test_ZGfxDecompressFoxSingle() < 0)
return -1;
if (test_ZGfxDecompressFoxMultipart() < 0)
return -1;
if (test_ZGfxCompressConsistent() < 0)
return -1;
return 0;
}
@@ -0,0 +1,149 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
*
* Copyright 2025 Thincast Technologies GmbH
* Copyright 2025 Armin Novak <anovak@thincast.com>
*
* 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 <errno.h>
#include <stdio.h>
#include <winpr/path.h>
#include <winpr/file.h>
#include <winpr/debug.h>
#include <winpr/print.h>
#include "TestFreeRDPHelpers.h"
static char* get_path(const char* codec, const char* type, const char* name)
{
char path[500] = WINPR_C_ARRAY_INIT;
(void)snprintf(path, sizeof(path), "%s-%s-%s.bin", codec, type, name);
char* s1 = GetCombinedPath(CMAKE_CURRENT_SOURCE_DIR, codec);
if (!s1)
return nullptr;
char* s2 = GetCombinedPath(s1, path);
free(s1);
return s2;
}
static FILE* open_path(const char* codec, const char* type, const char* name, const char* mode)
{
WINPR_ASSERT(type);
WINPR_ASSERT(name);
WINPR_ASSERT(mode);
char* path = get_path(codec, type, name);
if (!path)
{
(void)printf("%s: get_path %s %s failed\n", __func__, type, name);
return nullptr;
}
FILE* fp = winpr_fopen(path, mode);
if (!fp)
{
char buffer[128] = WINPR_C_ARRAY_INIT;
(void)printf("%s: %s %s: fopen(%s, %s) failed: %s\n", __func__, type, name, path, mode,
winpr_strerror(errno, buffer, sizeof(buffer)));
}
free(path);
return fp;
}
void* test_codec_helper_read_data(const char* codec, const char* type, const char* name,
size_t* plength)
{
WINPR_ASSERT(type);
WINPR_ASSERT(name);
WINPR_ASSERT(plength);
void* rc = nullptr;
void* cmp = nullptr;
*plength = 0;
FILE* fp = open_path(codec, type, name, "rb");
if (!fp)
goto fail;
if (_fseeki64(fp, 0, SEEK_END) != 0)
goto fail;
const size_t pos = _ftelli64(fp);
if (_fseeki64(fp, 0, SEEK_SET) != 0)
goto fail;
cmp = calloc(pos, 1);
if (!cmp)
goto fail;
if (fread(cmp, 1, pos, fp) != pos)
goto fail;
*plength = pos;
rc = cmp;
cmp = nullptr;
fail:
(void)printf("%s: [%s] %s %s -> %p\n", __func__, codec, type, name, rc);
free(cmp);
if (fp)
(void)fclose(fp);
return rc;
}
void test_codec_helper_write_data(const char* codec, const char* type, const char* name,
const void* data, size_t length)
{
FILE* fp = open_path(codec, type, name, "wb");
if (!fp)
return;
if (fwrite(data, 1, length, fp) != length)
goto fail;
fail:
fclose(fp);
}
bool test_codec_helper_compare(const char* codec, const char* type, const char* name,
const void* data, size_t length)
{
bool rc = false;
size_t cmplen = 0;
void* cmp = test_codec_helper_read_data(codec, type, name, &cmplen);
if (!cmp)
goto fail;
if (cmplen != length)
{
(void)printf("%s: [%s] %s %s: length mismatch: %" PRIuz " vs %" PRIuz "\n", __func__, codec,
type, name, cmplen, length);
goto fail;
}
if (memcmp(data, cmp, length) != 0)
{
(void)printf("%s: [%s] %s %s: data mismatch\n", __func__, codec, type, name);
winpr_HexDump(__func__, WLOG_WARN, data, length);
winpr_HexDump(__func__, WLOG_WARN, cmp, cmplen);
goto fail;
}
rc = true;
fail:
(void)printf("%s: [%s] %s %s -> %s\n", __func__, codec, type, name, rc ? "SUCCESS" : "FAILED");
free(cmp);
return rc;
}
@@ -0,0 +1,30 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
*
* Copyright 2025 Thincast Technologies GmbH
* Copyright 2025 Armin Novak <anovak@thincast.com>
*
* 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.
*/
#pragma once
#include <stdlib.h>
#include <stdbool.h>
void* test_codec_helper_read_data(const char* codec, const char* type, const char* name,
size_t* plength);
void test_codec_helper_write_data(const char* codec, const char* type, const char* name,
const void* data, size_t length);
bool test_codec_helper_compare(const char* codec, const char* type, const char* name,
const void* data, size_t length);
@@ -0,0 +1,876 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
*
* Copyright 2014 Thincast Technologies GmbH
* Copyright 2014 Hardening <contact@hardening-consulting.com>
*
* 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 <winpr/crt.h>
#include <winpr/print.h>
#include <freerdp/codec/region.h>
static BOOL compareRectangles(const RECTANGLE_16* src1, const RECTANGLE_16* src2, int nb)
{
for (int i = 0; i < nb; i++, src1++, src2++)
{
if (memcmp(src1, src2, sizeof(RECTANGLE_16)) != 0)
{
(void)fprintf(stderr,
"expecting rect %d (%" PRIu16 ",%" PRIu16 "-%" PRIu16 ",%" PRIu16
") and have (%" PRIu16 ",%" PRIu16 "-%" PRIu16 ",%" PRIu16 ")\n",
i, src2->left, src2->top, src2->right, src2->bottom, src1->left,
src1->top, src1->right, src1->bottom);
return FALSE;
}
}
return TRUE;
}
static int test_basic(void)
{
REGION16 region = WINPR_C_ARRAY_INIT;
int retCode = -1;
const RECTANGLE_16* rects = nullptr;
UINT32 nbRects = 0;
/* R1 + R2 ==> disjointed rects */
RECTANGLE_16 r1 = { 0, 101, 200, 201 };
RECTANGLE_16 r2 = { 150, 301, 250, 401 };
RECTANGLE_16 r1_r2[] = { { 0, 101, 200, 201 }, { 150, 301, 250, 401 } };
/* r1 */
region16_init(&region);
if (!region16_union_rect(&region, &region, &r1))
goto out;
rects = region16_rects(&region, &nbRects);
if (!rects || nbRects != 1 || memcmp(rects, &r1, sizeof(RECTANGLE_16)) != 0)
goto out;
/* r1 + r2 */
if (!region16_union_rect(&region, &region, &r2))
goto out;
rects = region16_rects(&region, &nbRects);
if (!rects || nbRects != 2 ||
!compareRectangles(rects, r1_r2, WINPR_ASSERTING_INT_CAST(int, nbRects)))
goto out;
/* clear region */
region16_clear(&region);
region16_rects(&region, &nbRects);
if (nbRects)
goto out;
retCode = 0;
out:
region16_uninit(&region);
return retCode;
}
static int test_r1_r3(void)
{
REGION16 region;
int retCode = -1;
const RECTANGLE_16* rects = nullptr;
UINT32 nbRects = 0;
RECTANGLE_16 r1 = { 0, 101, 200, 201 };
RECTANGLE_16 r3 = { 150, 151, 250, 251 };
RECTANGLE_16 r1_r3[] = { { 0, 101, 200, 151 }, { 0, 151, 250, 201 }, { 150, 201, 250, 251 } };
region16_init(&region);
/*
* +===============================================================
* |
* |+-----+ +-----+
* || r1 | | |
* || +-+------+ +-----+--------+
* || | r3 | | |
* |+---+ | ====> +-----+--------+
* | | | | |
* | +--------+ +--------+
*/
/* R1 + R3 */
if (!region16_union_rect(&region, &region, &r1))
goto out;
if (!region16_union_rect(&region, &region, &r3))
goto out;
rects = region16_rects(&region, &nbRects);
if (!rects || nbRects != 3 ||
!compareRectangles(rects, r1_r3, WINPR_ASSERTING_INT_CAST(int, nbRects)))
goto out;
/* R3 + R1 */
region16_clear(&region);
if (!region16_union_rect(&region, &region, &r3))
goto out;
if (!region16_union_rect(&region, &region, &r1))
goto out;
rects = region16_rects(&region, &nbRects);
if (!rects || nbRects != 3 ||
!compareRectangles(rects, r1_r3, WINPR_ASSERTING_INT_CAST(int, nbRects)))
goto out;
retCode = 0;
out:
region16_uninit(&region);
return retCode;
}
static int test_r9_r10(void)
{
REGION16 region;
int retCode = -1;
const RECTANGLE_16* rects = nullptr;
UINT32 nbRects = 0;
/*
* +===============================================================
* |
* | +---+ +---+
* |+--|r10|-+ +--+---+-+
* ||r9| | | | |
* || | | | | |
* || | | | =====> | |
* || | | | | |
* || | | | | |
* |+--| |-+ +--+---+-+
* | +---+ +---+
*/
RECTANGLE_16 r9 = { 0, 100, 400, 200 };
RECTANGLE_16 r10 = { 200, 0, 300, 300 };
RECTANGLE_16 r9_r10[] = {
{ 200, 0, 300, 100 },
{ 0, 100, 400, 200 },
{ 200, 200, 300, 300 },
};
region16_init(&region);
if (!region16_union_rect(&region, &region, &r9))
goto out;
if (!region16_union_rect(&region, &region, &r10))
goto out;
rects = region16_rects(&region, &nbRects);
if (!rects || nbRects != 3 ||
!compareRectangles(rects, r9_r10, WINPR_ASSERTING_INT_CAST(int, nbRects)))
goto out;
retCode = 0;
out:
region16_uninit(&region);
return retCode;
}
static int test_r1_r5(void)
{
REGION16 region;
int retCode = -1;
const RECTANGLE_16* rects = nullptr;
UINT32 nbRects = 0;
RECTANGLE_16 r1 = { 0, 101, 200, 201 };
RECTANGLE_16 r5 = { 150, 121, 300, 131 };
RECTANGLE_16 r1_r5[] = { { 0, 101, 200, 121 }, { 0, 121, 300, 131 }, { 0, 131, 200, 201 } };
region16_init(&region);
/*
* +===============================================================
* |
* |+--------+ +--------+
* || r1 | | |
* || +--+----+ +--------+----+
* || | r5 | =====> | |
* || +-------+ +--------+----+
* || | | |
* |+--------+ +--------+
* |
*
*/
if (!region16_union_rect(&region, &region, &r1))
goto out;
if (!region16_union_rect(&region, &region, &r5))
goto out;
rects = region16_rects(&region, &nbRects);
if (!rects || nbRects != 3 ||
!compareRectangles(rects, r1_r5, WINPR_ASSERTING_INT_CAST(int, nbRects)))
goto out;
retCode = 0;
out:
region16_uninit(&region);
return retCode;
}
static int test_r1_r6(void)
{
REGION16 region = WINPR_C_ARRAY_INIT;
int retCode = -1;
const RECTANGLE_16* rects = nullptr;
UINT32 nbRects = 0;
RECTANGLE_16 r1 = { 0, 101, 200, 201 };
RECTANGLE_16 r6 = { 150, 121, 170, 131 };
region16_init(&region);
/*
* +===============================================================
* |
* |+--------+ +--------+
* || r1 | | |
* || +--+ | | |
* || |r6| | =====> | |
* || +--+ | | |
* || | | |
* |+--------+ +--------+
* |
*/
region16_clear(&region);
if (!region16_union_rect(&region, &region, &r1))
goto out;
if (!region16_union_rect(&region, &region, &r6))
goto out;
rects = region16_rects(&region, &nbRects);
if (!rects || nbRects != 1 ||
!compareRectangles(rects, &r1, WINPR_ASSERTING_INT_CAST(int, nbRects)))
goto out;
retCode = 0;
out:
region16_uninit(&region);
return retCode;
}
static int test_r1_r2_r4(void)
{
REGION16 region;
int retCode = -1;
const RECTANGLE_16* rects = nullptr;
UINT32 nbRects = 0;
RECTANGLE_16 r1 = { 0, 101, 200, 201 };
RECTANGLE_16 r2 = { 150, 301, 250, 401 };
RECTANGLE_16 r4 = { 150, 251, 250, 301 };
RECTANGLE_16 r1_r2_r4[] = { { 0, 101, 200, 201 }, { 150, 251, 250, 401 } };
/*
* +===============================================================
* |
* |+-----+ +-----+
* || r1 | | |
* || | | |
* || | | |
* |+-----+ ====> +-----+
* |
* | +--------+ +--------+
* | | r4 | | |
* | +--------+ | |
* | | r2 | | |
* | | | | |
* | +--------+ +--------+
*
*/
region16_init(&region);
if (!region16_union_rect(&region, &region, &r1))
goto out;
if (!region16_union_rect(&region, &region, &r2))
goto out;
if (!region16_union_rect(&region, &region, &r4))
goto out;
rects = region16_rects(&region, &nbRects);
if (!rects || nbRects != 2 ||
!compareRectangles(rects, r1_r2_r4, WINPR_ASSERTING_INT_CAST(int, nbRects)))
goto out;
retCode = 0;
out:
region16_uninit(&region);
return retCode;
}
static int test_r1_r7_r8(void)
{
REGION16 region;
int retCode = -1;
const RECTANGLE_16* rects = nullptr;
UINT32 nbRects = 0;
RECTANGLE_16 r1 = { 0, 101, 200, 201 };
RECTANGLE_16 r7 = { 300, 101, 500, 201 };
RECTANGLE_16 r8 = { 150, 121, 400, 131 };
RECTANGLE_16 r1_r7_r8[] = {
{ 0, 101, 200, 121 }, { 300, 101, 500, 121 }, { 0, 121, 500, 131 },
{ 0, 131, 200, 201 }, { 300, 131, 500, 201 },
};
/*
* +===============================================================
* |
* |+--------+ +--------+ +--------+ +--------+
* || r1 | | r7 | | | | |
* || +------------+ | +--------+---+--------+
* || | r8 | | =====> | |
* || +------------+ | +--------+---+--------+
* || | | | | | | |
* |+--------+ +--------+ +--------+ +--------+
* |
*/
region16_init(&region);
if (!region16_union_rect(&region, &region, &r1))
goto out;
if (!region16_union_rect(&region, &region, &r7))
goto out;
if (!region16_union_rect(&region, &region, &r8))
goto out;
rects = region16_rects(&region, &nbRects);
if (!rects || nbRects != 5 ||
!compareRectangles(rects, r1_r7_r8, WINPR_ASSERTING_INT_CAST(int, nbRects)))
goto out;
region16_clear(&region);
if (!region16_union_rect(&region, &region, &r1))
goto out;
if (!region16_union_rect(&region, &region, &r8))
goto out;
if (!region16_union_rect(&region, &region, &r7))
goto out;
rects = region16_rects(&region, &nbRects);
if (!rects || nbRects != 5 ||
!compareRectangles(rects, r1_r7_r8, WINPR_ASSERTING_INT_CAST(int, nbRects)))
goto out;
region16_clear(&region);
if (!region16_union_rect(&region, &region, &r8))
goto out;
if (!region16_union_rect(&region, &region, &r7))
goto out;
if (!region16_union_rect(&region, &region, &r1))
goto out;
rects = region16_rects(&region, &nbRects);
if (!rects || nbRects != 5 ||
!compareRectangles(rects, r1_r7_r8, WINPR_ASSERTING_INT_CAST(int, nbRects)))
goto out;
retCode = 0;
out:
region16_uninit(&region);
return retCode;
}
static int test_r1_r2_r3_r4(void)
{
REGION16 region;
int retCode = -1;
const RECTANGLE_16* rects = nullptr;
UINT32 nbRects = 0;
RECTANGLE_16 r1 = { 0, 101, 200, 201 };
RECTANGLE_16 r2 = { 150, 301, 250, 401 };
RECTANGLE_16 r3 = { 150, 151, 250, 251 };
RECTANGLE_16 r4 = { 150, 251, 250, 301 };
RECTANGLE_16 r1_r2_r3[] = {
{ 0, 101, 200, 151 }, { 0, 151, 250, 201 }, { 150, 201, 250, 251 }, { 150, 301, 250, 401 }
};
RECTANGLE_16 r1_r2_r3_r4[] = { { 0, 101, 200, 151 },
{ 0, 151, 250, 201 },
{ 150, 201, 250, 401 } };
region16_init(&region);
/*
* +===============================================================
* |
* |+-----+ +-----+
* || r1 | | |
* || +-+------+ +-----+--------+
* || | r3 | | |
* |+---+ | ====> +-----+--------+
* | | | | |
* | +--------+ +--------+
* | +--------+ +--------+
* | | r2 | | |
* | | | | |
* | +--------+ +--------+
*/
if (!region16_union_rect(&region, &region, &r1))
goto out;
if (!region16_union_rect(&region, &region, &r2))
goto out;
if (!region16_union_rect(&region, &region, &r3))
goto out;
rects = region16_rects(&region, &nbRects);
if (!rects || nbRects != 4 || !compareRectangles(rects, r1_r2_r3, 4))
goto out;
/*
* +===============================================================
* |
* |+-----+ +-----+
* || | | |
* |+-----+--------+ +-----+--------+
* || | ==> | |
* |+-----+--------+ +-----+--------+
* | | | | |
* | +--------+ | |
* | | + r4 | | |
* | +--------+ | |
* | | | | |
* | | | | |
* | +--------+ +--------+
*/
if (!region16_union_rect(&region, &region, &r4))
goto out;
rects = region16_rects(&region, &nbRects);
if (!rects || nbRects != 3 || !compareRectangles(rects, r1_r2_r3_r4, 3))
goto out;
retCode = 0;
out:
region16_uninit(&region);
return retCode;
}
static int test_from_weston(void)
{
/*
* 0: 0,0 -> 640,32 (w=640 h=32)
* 1: 236,169 -> 268,201 (w=32 h=32)
* 2: 246,258 -> 278,290 (w=32 h=32)
*/
REGION16 region;
int retCode = -1;
const RECTANGLE_16* rects = nullptr;
UINT32 nbRects = 0;
RECTANGLE_16 r1 = { 0, 0, 640, 32 };
RECTANGLE_16 r2 = { 236, 169, 268, 201 };
RECTANGLE_16 r3 = { 246, 258, 278, 290 };
RECTANGLE_16 r1_r2_r3[] = { { 0, 0, 640, 32 }, { 236, 169, 268, 201 }, { 246, 258, 278, 290 } };
region16_init(&region);
/*
* +===============================================================
* |+-------------------------------------------------------------+
* || r1 |
* |+-------------------------------------------------------------+
* |
* | +---------------+
* | | r2 |
* | +---------------+
* |
* | +---------------+
* | | r3 |
* | +---------------+
* |
*/
if (!region16_union_rect(&region, &region, &r1))
goto out;
if (!region16_union_rect(&region, &region, &r2))
goto out;
if (!region16_union_rect(&region, &region, &r3))
goto out;
rects = region16_rects(&region, &nbRects);
if (!rects || nbRects != 3 || !compareRectangles(rects, r1_r2_r3, 3))
goto out;
retCode = 0;
out:
region16_uninit(&region);
return retCode;
}
static int test_r1_inter_r3(void)
{
REGION16 region;
REGION16 intersection;
int retCode = -1;
const RECTANGLE_16* rects = nullptr;
UINT32 nbRects = 0;
RECTANGLE_16 r1 = { 0, 101, 200, 201 };
RECTANGLE_16 r3 = { 150, 151, 250, 251 };
RECTANGLE_16 r1_inter_r3[] = {
{ 150, 151, 200, 201 },
};
region16_init(&region);
region16_init(&intersection);
/*
* +===============================================================
* |
* |+-----+
* || r1 |
* || +-+------+ +-+
* || | r3 | r1&r3 | |
* |+---+ | ====> +-+
* | | |
* | +--------+
*/
if (!region16_union_rect(&region, &region, &r1))
goto out;
if (!region16_intersects_rect(&region, &r3))
goto out;
if (!region16_intersect_rect(&intersection, &region, &r3))
goto out;
rects = region16_rects(&intersection, &nbRects);
if (!rects || nbRects != 1 ||
!compareRectangles(rects, r1_inter_r3, WINPR_ASSERTING_INT_CAST(int, nbRects)))
goto out;
retCode = 0;
out:
region16_uninit(&region);
region16_uninit(&intersection);
return retCode;
}
static int test_r1_r3_inter_r11(void)
{
REGION16 region;
REGION16 intersection;
int retCode = -1;
const RECTANGLE_16* rects = nullptr;
UINT32 nbRects = 0;
RECTANGLE_16 r1 = { 0, 101, 200, 201 };
RECTANGLE_16 r3 = { 150, 151, 250, 251 };
RECTANGLE_16 r11 = { 170, 151, 600, 301 };
RECTANGLE_16 r1_r3_inter_r11[] = {
{ 170, 151, 250, 251 },
};
region16_init(&region);
region16_init(&intersection);
/*
* +===============================================================
* |
* |+-----+
* || |
* || +------+
* || r1+r3 | (r1+r3) & r11
* || +----------------+ +--------+
* |+---+ | | | ====> | |
* | | | | | | |
* | | | | | | |
* | +-|------+ | +--------+
* | | r11 |
* | +----------------+
*
*
* R1+R3 is made of 3 bands, R11 overlap the second and the third band. The
* intersection is made of two band that must be reassembled to give only
* one
*/
if (!region16_union_rect(&region, &region, &r1))
goto out;
if (!region16_union_rect(&region, &region, &r3))
goto out;
if (!region16_intersects_rect(&region, &r11))
goto out;
if (!region16_intersect_rect(&intersection, &region, &r11))
goto out;
rects = region16_rects(&intersection, &nbRects);
if (!rects || nbRects != 1 ||
!compareRectangles(rects, r1_r3_inter_r11, WINPR_ASSERTING_INT_CAST(int, nbRects)))
goto out;
retCode = 0;
out:
region16_uninit(&intersection);
region16_uninit(&region);
return retCode;
}
static int test_norbert_case(void)
{
REGION16 region;
REGION16 intersection;
int retCode = -1;
const RECTANGLE_16* rects = nullptr;
UINT32 nbRects = 0;
RECTANGLE_16 inRectangles[5] = { { 1680, 0, 1920, 242 },
{ 294, 242, 971, 776 },
{ 1680, 242, 1920, 776 },
{ 1680, 776, 1920, 1036 },
{ 2, 1040, 53, 1078 } };
RECTANGLE_16 screenRect = { 0, 0, 1920, 1080 };
RECTANGLE_16 expected_inter_extents = { 2, 0, 1920, 1078 };
region16_init(&region);
region16_init(&intersection);
/*
* Consider following as a screen with resolution 1920*1080
* | | | | | | |
* | |2 |53 |294 |971 |1680 |
* | | | | | | |
* 0 +=+======================================+======+
* | | | |
* | | R[0]|
* 242 | +-----------+ +------+
* | | | | | |
* | | | | |
* | | R[1]| | R[2]|
* 776 | | +-----------+ +------+
* | | |
* | | R[3]|
* 1036 | | +------+
* 1040 | +----+
* | |R[4]| Union of R[0-4]|
* 1078 | +----+ - - - - - - - -+
* 1080 |
*
*
* The result is union of R[0] - R[4].
* After intersected with the full screen rect, the
* result should keep the same.
*/
for (int i = 0; i < 5; i++)
{
if (!region16_union_rect(&region, &region, &inRectangles[i]))
goto out;
}
if (!compareRectangles(region16_extents(&region), &expected_inter_extents, 1))
goto out;
if (!region16_intersect_rect(&intersection, &region, &screenRect))
goto out;
rects = region16_rects(&intersection, &nbRects);
if (!rects || nbRects != 5 ||
!compareRectangles(rects, inRectangles, WINPR_ASSERTING_INT_CAST(int, nbRects)))
goto out;
if (!compareRectangles(region16_extents(&intersection), &expected_inter_extents, 1))
goto out;
retCode = 0;
out:
region16_uninit(&intersection);
region16_uninit(&region);
return retCode;
}
static int test_norbert2_case(void)
{
REGION16 region;
int retCode = -1;
const RECTANGLE_16* rects = nullptr;
UINT32 nbRects = 0;
RECTANGLE_16 rect1 = { 464, 696, 476, 709 };
RECTANGLE_16 rect2 = { 0, 0, 1024, 32 };
region16_init(&region);
if (!region16_union_rect(&region, &region, &rect1))
{
(void)fprintf(stderr, "%s: Error 1 - region16_union_rect failed\n", __func__);
goto out;
}
if (!(rects = region16_rects(&region, &nbRects)))
{
(void)fprintf(stderr, "%s: Error 2 - region16_rects failed\n", __func__);
goto out;
}
if (nbRects != 1)
{
(void)fprintf(stderr, "%s: Error 3 - expected nbRects == 1 but got %" PRIu32 "\n", __func__,
nbRects);
goto out;
}
if (!compareRectangles(&rects[0], &rect1, 1))
{
(void)fprintf(stderr, "%s: Error 4 - compare failed\n", __func__);
goto out;
}
if (!region16_union_rect(&region, &region, &rect2))
{
(void)fprintf(stderr, "%s: Error 5 - region16_union_rect failed\n", __func__);
goto out;
}
if (!(rects = region16_rects(&region, &nbRects)))
{
(void)fprintf(stderr, "%s: Error 6 - region16_rects failed\n", __func__);
goto out;
}
if (nbRects != 2)
{
(void)fprintf(stderr, "%s: Error 7 - expected nbRects == 2 but got %" PRIu32 "\n", __func__,
nbRects);
goto out;
}
if (!compareRectangles(&rects[0], &rect2, 1))
{
(void)fprintf(stderr, "%s: Error 8 - compare failed\n", __func__);
goto out;
}
if (!compareRectangles(&rects[1], &rect1, 1))
{
(void)fprintf(stderr, "%s: Error 9 - compare failed\n", __func__);
goto out;
}
retCode = 0;
out:
region16_uninit(&region);
return retCode;
}
static int test_empty_rectangle(void)
{
REGION16 region;
REGION16 intersection;
int retCode = -1;
RECTANGLE_16 emptyRectangles[3] = { { 0, 0, 0, 0 }, { 10, 10, 10, 11 }, { 10, 10, 11, 10 } };
RECTANGLE_16 firstRect = { 0, 0, 100, 100 };
RECTANGLE_16 anotherRect = { 100, 100, 200, 200 };
RECTANGLE_16 expected_inter_extents = { 0, 0, 0, 0 };
region16_init(&region);
region16_init(&intersection);
/* Check for empty rectangles */
for (int i = 0; i < 3; i++)
{
if (!rectangle_is_empty(&emptyRectangles[i]))
goto out;
}
/* Check for non-empty rectangles */
if (rectangle_is_empty(&firstRect))
goto out;
/* Intersect 2 non-intersect rectangle, result should be empty */
if (!region16_union_rect(&region, &region, &firstRect))
goto out;
if (!region16_intersect_rect(&region, &region, &anotherRect))
goto out;
if (!compareRectangles(region16_extents(&region), &expected_inter_extents, 1))
goto out;
if (!region16_is_empty(&region))
goto out;
if (!rectangle_is_empty(region16_extents(&intersection)))
goto out;
retCode = 0;
out:
region16_uninit(&intersection);
region16_uninit(&region);
return retCode;
}
typedef int (*TestFunction)(void);
struct UnitaryTest
{
const char* name;
WINPR_ATTR_NODISCARD TestFunction func;
};
static struct UnitaryTest tests[] = { { "Basic trivial tests", test_basic },
{ "R1+R3 and R3+R1", test_r1_r3 },
{ "R1+R5", test_r1_r5 },
{ "R1+R6", test_r1_r6 },
{ "R9+R10", test_r9_r10 },
{ "R1+R2+R4", test_r1_r2_r4 },
{ "R1+R7+R8 in many orders", test_r1_r7_r8 },
{ "R1+R2+R3+R4", test_r1_r2_r3_r4 },
{ "data from weston", test_from_weston },
{ "R1 & R3", test_r1_inter_r3 },
{ "(R1+R3)&R11 (band merge)", test_r1_r3_inter_r11 },
{ "norbert's case", test_norbert_case },
{ "norbert's case 2", test_norbert2_case },
{ "empty rectangle case", test_empty_rectangle },
{ nullptr, nullptr } };
int TestFreeRDPRegion(int argc, char* argv[])
{
int testNb = 0;
int retCode = -1;
WINPR_UNUSED(argc);
WINPR_UNUSED(argv);
for (int i = 0; tests[i].func; i++)
{
testNb++;
(void)fprintf(stderr, "%d: %s\n", testNb, tests[i].name);
retCode = tests[i].func();
if (retCode < 0)
break;
}
if (retCode < 0)
(void)fprintf(stderr, "failed for test %d\n", testNb);
return retCode;
}
@@ -0,0 +1,467 @@
/* https://github.com/ergnoorr/fuzzrdp
*
* MIT License
*
* Copyright (c) 2024 ergnoorr
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <freerdp/assistance.h>
#include <winpr/crt.h>
#include <winpr/print.h>
#include <winpr/platform.h>
#include <freerdp/codec/interleaved.h>
#include <freerdp/codec/planar.h>
#include <freerdp/codec/bulk.h>
#include <freerdp/codec/clear.h>
#include <freerdp/codec/zgfx.h>
#include <freerdp/log.h>
#include <winpr/bitstream.h>
#include <freerdp/codec/rfx.h>
#include <freerdp/codec/progressive.h>
#include <freerdp/freerdp.h>
#include <freerdp/gdi/gdi.h>
#include "../progressive.h"
#include "../mppc.h"
#include "../xcrush.h"
#include "../ncrush.h"
static BOOL test_ClearDecompressExample(UINT32 nr, UINT32 width, UINT32 height,
const BYTE* pSrcData, const UINT32 SrcSize)
{
BOOL rc = FALSE;
int status = 0;
BYTE* pDstData = calloc(1ull * width * height, 4);
CLEAR_CONTEXT* clear = clear_context_new(FALSE);
WINPR_UNUSED(nr);
if (!clear || !pDstData)
goto fail;
status = clear_decompress(clear, pSrcData, SrcSize, width, height, pDstData,
PIXEL_FORMAT_XRGB32, 0, 0, 0, width, height, nullptr);
// printf("clear_decompress example %" PRIu32 " status: %d\n", nr, status);
// fflush(stdout);
rc = (status == 0);
fail:
clear_context_free(clear);
free(pDstData);
return rc;
}
static int TestFreeRDPCodecClear(const uint8_t* Data, size_t Size)
{
if (Size > UINT32_MAX)
return -1;
test_ClearDecompressExample(2, 78, 17, Data, (UINT32)Size);
test_ClearDecompressExample(3, 64, 24, Data, (UINT32)Size);
test_ClearDecompressExample(4, 7, 15, Data, (UINT32)Size);
return 0;
}
static int TestFreeRDPCodecXCrush(const uint8_t* Data, size_t Size)
{
if (Size > UINT32_MAX)
return -1;
const BYTE* OutputBuffer = nullptr;
UINT32 DstSize = 0;
XCRUSH_CONTEXT* xcrush = xcrush_context_new(TRUE);
if (!xcrush)
return 0;
xcrush_decompress(xcrush, Data, (UINT32)Size, &OutputBuffer, &DstSize, 0);
xcrush_context_free(xcrush);
return 0;
}
static int test_ZGfxDecompressFoxSingle(const uint8_t* Data, size_t Size)
{
if (Size > UINT32_MAX)
return -1;
int rc = -1;
int status = 0;
UINT32 Flags = 0;
const BYTE* pSrcData = (const BYTE*)Data;
UINT32 SrcSize = (UINT32)Size;
UINT32 DstSize = 0;
BYTE* pDstData = nullptr;
ZGFX_CONTEXT* zgfx = zgfx_context_new(TRUE);
if (!zgfx)
return -1;
status = zgfx_decompress(zgfx, pSrcData, SrcSize, &pDstData, &DstSize, Flags);
if (status < 0)
goto fail;
rc = 0;
fail:
free(pDstData);
zgfx_context_free(zgfx);
return rc;
}
static int TestFreeRDPCodecZGfx(const uint8_t* Data, size_t Size)
{
test_ZGfxDecompressFoxSingle(Data, Size);
return 0;
}
static BOOL test_NCrushDecompressBells(const uint8_t* Data, size_t Size)
{
if (Size > UINT32_MAX)
return FALSE;
BOOL rc = FALSE;
int status = 0;
UINT32 Flags = PACKET_COMPRESSED | 2;
const BYTE* pSrcData = (const BYTE*)Data;
UINT32 SrcSize = (UINT32)Size;
UINT32 DstSize = 0;
const BYTE* pDstData = nullptr;
NCRUSH_CONTEXT* ncrush = ncrush_context_new(FALSE);
if (!ncrush)
return rc;
status = ncrush_decompress(ncrush, pSrcData, SrcSize, &pDstData, &DstSize, Flags);
if (status < 0)
goto fail;
rc = TRUE;
fail:
ncrush_context_free(ncrush);
return rc;
}
static int TestFreeRDPCodecNCrush(const uint8_t* Data, size_t Size)
{
test_NCrushDecompressBells(Data, Size);
return 0;
}
static const size_t IMG_WIDTH = 64;
static const size_t IMG_HEIGHT = 64;
static const size_t FORMAT_SIZE = 4;
static const UINT32 FORMAT = PIXEL_FORMAT_XRGB32;
static int TestFreeRDPCodecRemoteFX(const uint8_t* Data, size_t Size)
{
int rc = -1;
REGION16 region = WINPR_C_ARRAY_INIT;
RFX_CONTEXT* context = rfx_context_new(FALSE);
BYTE* dest = calloc(IMG_WIDTH * IMG_HEIGHT, FORMAT_SIZE);
size_t stride = FORMAT_SIZE * IMG_WIDTH;
if (!context)
goto fail;
if (Size > UINT32_MAX)
goto fail;
if (stride > UINT32_MAX)
goto fail;
if (!dest)
goto fail;
region16_init(&region);
if (!rfx_process_message(context, Data, (UINT32)Size, 0, 0, dest, FORMAT, (UINT32)stride,
IMG_HEIGHT, &region))
goto fail;
region16_clear(&region);
if (!rfx_process_message(context, Data, (UINT32)Size, 0, 0, dest, FORMAT, (UINT32)stride,
IMG_HEIGHT, &region))
goto fail;
region16_print(&region);
rc = 0;
fail:
region16_uninit(&region);
rfx_context_free(context);
free(dest);
return rc;
}
static int test_MppcDecompressBellsRdp5(const uint8_t* Data, size_t Size)
{
int rc = -1;
int status = 0;
UINT32 Flags = PACKET_AT_FRONT | PACKET_COMPRESSED | 1;
const BYTE* pSrcData = Data;
UINT32 SrcSize = (UINT32)Size;
UINT32 DstSize = 0;
const BYTE* pDstData = nullptr;
MPPC_CONTEXT* mppc = mppc_context_new(1, FALSE);
if (!mppc)
return -1;
status = mppc_decompress(mppc, pSrcData, SrcSize, &pDstData, &DstSize, Flags);
if (status < 0)
goto fail;
rc = 0;
fail:
mppc_context_free(mppc);
return rc;
}
static int test_MppcDecompressBellsRdp4(const uint8_t* Data, size_t Size)
{
if (Size > UINT32_MAX)
return -1;
int rc = -1;
int status = 0;
UINT32 Flags = PACKET_AT_FRONT | PACKET_COMPRESSED | 0;
const BYTE* pSrcData = (const BYTE*)Data;
UINT32 SrcSize = (UINT32)Size;
UINT32 DstSize = 0;
const BYTE* pDstData = nullptr;
MPPC_CONTEXT* mppc = mppc_context_new(0, FALSE);
if (!mppc)
return -1;
status = mppc_decompress(mppc, pSrcData, SrcSize, &pDstData, &DstSize, Flags);
if (status < 0)
goto fail;
rc = 0;
fail:
mppc_context_free(mppc);
return rc;
}
static int test_MppcDecompressBufferRdp5(const uint8_t* Data, size_t Size)
{
if (Size > UINT32_MAX)
return -1;
int rc = -1;
int status = 0;
UINT32 Flags = PACKET_AT_FRONT | PACKET_COMPRESSED | 1;
const BYTE* pSrcData = (const BYTE*)Data;
UINT32 SrcSize = (UINT32)Size;
UINT32 DstSize = 0;
const BYTE* pDstData = nullptr;
MPPC_CONTEXT* mppc = mppc_context_new(1, FALSE);
if (!mppc)
return -1;
status = mppc_decompress(mppc, pSrcData, SrcSize, &pDstData, &DstSize, Flags);
if (status < 0)
goto fail;
rc = 0;
fail:
mppc_context_free(mppc);
return rc;
}
static int TestFreeRDPCodecMppc(const uint8_t* Data, size_t Size)
{
test_MppcDecompressBellsRdp5(Data, Size);
test_MppcDecompressBellsRdp4(Data, Size);
test_MppcDecompressBufferRdp5(Data, Size);
return 0;
}
static BOOL progressive_decode(const uint8_t* Data, size_t Size)
{
BOOL res = FALSE;
int rc = 0;
BYTE* resultData = nullptr;
UINT32 ColorFormat = PIXEL_FORMAT_BGRX32;
REGION16 invalidRegion = WINPR_C_ARRAY_INIT;
UINT32 scanline = 4240;
UINT32 width = 1060;
UINT32 height = 827;
if (Size > UINT32_MAX)
return FALSE;
PROGRESSIVE_CONTEXT* progressiveDec = progressive_context_new(FALSE);
region16_init(&invalidRegion);
if (!progressiveDec)
goto fail;
resultData = calloc(scanline, height);
if (!resultData)
goto fail;
rc = progressive_create_surface_context(progressiveDec, 0, width, height);
if (rc <= 0)
goto fail;
rc = progressive_decompress(progressiveDec, Data, (UINT32)Size, resultData, ColorFormat,
scanline, 0, 0, &invalidRegion, 0, 0);
if (rc < 0)
goto fail;
res = TRUE;
fail:
region16_uninit(&invalidRegion);
progressive_context_free(progressiveDec);
free(resultData);
return res;
}
static int TestFreeRDPCodecProgressive(const uint8_t* Data, size_t Size)
{
progressive_decode(Data, Size);
return 0;
}
static BOOL i_run_encode_decode(UINT16 bpp, BITMAP_INTERLEAVED_CONTEXT* encoder,
BITMAP_INTERLEAVED_CONTEXT* decoder, const uint8_t* Data,
size_t Size)
{
BOOL rc2 = FALSE;
BOOL rc = 0;
const UINT32 w = 64;
const UINT32 h = 64;
const UINT32 x = 0;
const UINT32 y = 0;
const UINT32 format = PIXEL_FORMAT_RGBX32;
const size_t step = (w + 13ull) * 4ull;
const size_t SrcSize = step * h;
BYTE* pSrcData = calloc(1, SrcSize);
BYTE* pDstData = calloc(1, SrcSize);
BYTE* tmp = calloc(1, SrcSize);
WINPR_UNUSED(encoder);
if (!pSrcData || !pDstData || !tmp)
goto fail;
if (Size > UINT32_MAX)
goto fail;
winpr_RAND(pSrcData, SrcSize);
if (!bitmap_interleaved_context_reset(decoder))
goto fail;
rc = interleaved_decompress(decoder, Data, (UINT32)Size, w, h, bpp, pDstData, format, step, x,
y, w, h, nullptr);
if (!rc)
goto fail;
rc2 = TRUE;
fail:
free(pSrcData);
free(pDstData);
free(tmp);
return rc2;
}
static int TestFreeRDPCodecInterleaved(const uint8_t* Data, size_t Size)
{
int rc = -1;
BITMAP_INTERLEAVED_CONTEXT* decoder = bitmap_interleaved_context_new(FALSE);
if (!decoder)
goto fail;
i_run_encode_decode(24, nullptr, decoder, Data, Size);
i_run_encode_decode(16, nullptr, decoder, Data, Size);
i_run_encode_decode(15, nullptr, decoder, Data, Size);
rc = 0;
fail:
bitmap_interleaved_context_free(decoder);
return rc;
}
static BOOL RunTestPlanar(BITMAP_PLANAR_CONTEXT* planar, const BYTE* srcBitmap,
const UINT32 srcFormat, const UINT32 dstFormat, const UINT32 width,
const UINT32 height, const uint8_t* Data, size_t Size)
{
BOOL rc = FALSE;
WINPR_UNUSED(srcBitmap);
WINPR_UNUSED(srcFormat);
if (Size > UINT32_MAX)
return FALSE;
UINT32 dstSize = (UINT32)Size;
const BYTE* compressedBitmap = Data;
BYTE* decompressedBitmap =
(BYTE*)calloc(height, 1ull * width * FreeRDPGetBytesPerPixel(dstFormat));
rc = TRUE;
if (!decompressedBitmap)
goto fail;
if (!planar_decompress(planar, compressedBitmap, dstSize, width, height, decompressedBitmap,
dstFormat, 0, 0, 0, width, height, FALSE))
{
goto fail;
}
rc = TRUE;
fail:
free(decompressedBitmap);
return rc;
}
static BOOL TestPlanar(const UINT32 format, const uint8_t* Data, size_t Size)
{
BOOL rc = FALSE;
const DWORD planarFlags = PLANAR_FORMAT_HEADER_NA | PLANAR_FORMAT_HEADER_RLE;
BITMAP_PLANAR_CONTEXT* planar = freerdp_bitmap_planar_context_new(planarFlags, 64, 64);
if (!planar)
goto fail;
RunTestPlanar(planar, nullptr, PIXEL_FORMAT_RGBX32, format, 64, 64, Data, Size);
RunTestPlanar(planar, nullptr, PIXEL_FORMAT_RGB16, format, 32, 32, Data, Size);
rc = TRUE;
fail:
freerdp_bitmap_planar_context_free(planar);
return rc;
}
static int TestFreeRDPCodecPlanar(const uint8_t* Data, size_t Size)
{
TestPlanar(0, Data, Size);
return 0;
}
int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size)
{
if (Size < 4)
return 0;
TestFreeRDPCodecClear(Data, Size);
TestFreeRDPCodecXCrush(Data, Size);
TestFreeRDPCodecZGfx(Data, Size);
TestFreeRDPCodecNCrush(Data, Size);
TestFreeRDPCodecRemoteFX(Data, Size);
TestFreeRDPCodecMppc(Data, Size);
TestFreeRDPCodecProgressive(Data, Size);
TestFreeRDPCodecInterleaved(Data, Size);
TestFreeRDPCodecPlanar(Data, Size);
return 0;
}
@@ -0,0 +1,5 @@
cursor dumps created from a connection to FreeRDP shadow server.
target machine was a debian 12 with openbox.
So licensing of image, ... according to the license of the default cursor theme
@@ -0,0 +1,140 @@
/* FreeRDP cursor dump to use for unit tests
* this file was auto generated by dump_write_c_file
* do not modify manually
*/
#include "cursor_dump_00000000.h"
static uint8_t andmask[] = { 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc1, 0x80, 0xe3, 0x80, 0xe3,
0x80, 0xe3, 0x80, 0xe3, 0x80, 0xe3, 0x80, 0xe3, 0x80, 0xe3, 0x80,
0xe3, 0x80, 0xc1, 0x80, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00 };
static uint8_t xormask[] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff,
0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff,
0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00
};
const gdiPalette cursor_dump_00000000_palette = {
.format = 0,
.palette = { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000 }
};
const rdpPointer cursor_dump_00000000_pointer = { .size = 0,
.New = nullptr,
.Free = nullptr,
.Set = nullptr,
.SetNull = nullptr,
.SetDefault = nullptr,
.SetPosition = nullptr,
.paddingA = { 0 },
.xPos = 0,
.yPos = 0,
.width = 9,
.height = 16,
.xorBpp = 24,
.lengthAndMask = ARRAYSIZE(andmask),
.lengthXorMask = ARRAYSIZE(xormask),
.xorMaskData = xormask,
.andMaskData = andmask,
.paddingB = { 0 } };
const uint8_t cursor_dump_00000000_image_bgra32[] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff,
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff,
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff,
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff,
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
};
@@ -0,0 +1,13 @@
/* FreeRDP cursor dump to use for unit tests
* this file was auto generated by dump_write_header
* do not modify manually
*/
#pragma once
#include <freerdp/codec/color.h>
#include <freerdp/graphics.h>
extern const gdiPalette cursor_dump_00000000_palette;
extern const rdpPointer cursor_dump_00000000_pointer;
extern const uint8_t cursor_dump_00000000_image_bgra32[];
Binary file not shown.

After

Width:  |  Height:  |  Size: 136 B

@@ -0,0 +1,333 @@
/* FreeRDP cursor dump to use for unit tests
* this file was auto generated by dump_write_c_file
* do not modify manually
*/
#include "cursor_dump_00000001.h"
static uint8_t andmask[] = {
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xe1, 0xff, 0x00, 0xff, 0xc0, 0xff, 0x00,
0xff, 0xc0, 0xff, 0x00, 0xff, 0xc0, 0xff, 0x00, 0xff, 0xc0, 0xff, 0x00, 0xff, 0xc0, 0xff, 0x00,
0xff, 0xc0, 0xff, 0x00, 0xff, 0xc0, 0xff, 0x00, 0xfc, 0x00, 0x07, 0x00, 0xf8, 0x00, 0x07, 0x00,
0xfc, 0x00, 0x0f, 0x00, 0xfe, 0x00, 0x1f, 0x00, 0xff, 0x00, 0x3f, 0x00, 0xff, 0x00, 0x7f, 0x00,
0xf8, 0x00, 0x07, 0x00, 0xf0, 0x00, 0x03, 0x00, 0xf0, 0x00, 0x03, 0x00, 0xf0, 0x00, 0x07, 0x00,
0xf0, 0x00, 0x07, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00
};
static uint8_t xormask[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc9, 0xc9, 0xc9, 0xf1, 0xf1, 0xf1, 0xff, 0xff, 0xff, 0xf6,
0xf6, 0xf6, 0xa0, 0xa0, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf9, 0xf9,
0xf9, 0x16, 0x16, 0x16, 0x00, 0x00, 0x00, 0x15, 0x15, 0x15, 0xf6, 0xf6, 0xf6, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xfc, 0xfc, 0x03, 0x03, 0x03, 0x00, 0x00, 0x00, 0x03,
0x03, 0x03, 0xfc, 0xfc, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xfc,
0xfc, 0x03, 0x03, 0x03, 0x00, 0x00, 0x00, 0x03, 0x03, 0x03, 0xfc, 0xfc, 0xfc, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xfc, 0xfc, 0x03, 0x03, 0x03, 0x00, 0x00, 0x00, 0x03,
0x03, 0x03, 0xfc, 0xfc, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xfc,
0xfc, 0x03, 0x03, 0x03, 0x00, 0x00, 0x00, 0x03, 0x03, 0x03, 0xfc, 0xfc, 0xfc, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xfc, 0xfc, 0x03, 0x03, 0x03, 0x00, 0x00, 0x00, 0x03,
0x03, 0x03, 0xfc, 0xfc, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x2a, 0x2a, 0x2a, 0x22, 0x22, 0x22, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0xfc, 0xfc,
0xfc, 0x03, 0x03, 0x03, 0x00, 0x00, 0x00, 0x03, 0x03, 0x03, 0xfc, 0xfc, 0xfc, 0x1d, 0x1d, 0x1d,
0x20, 0x20, 0x20, 0x21, 0x21, 0x21, 0x22, 0x22, 0x22, 0x24, 0x24, 0x24, 0x29, 0x29, 0x29, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, 0xf1, 0xf1, 0xf1,
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xef, 0xef, 0xef, 0x03, 0x03, 0x03, 0x00, 0x00, 0x00, 0x03,
0x03, 0x03, 0xef, 0xef, 0xef, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf9, 0xf9,
0xf9, 0xf9, 0xf9, 0xf9, 0xab, 0xab, 0xab, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xf3, 0xf3, 0xf3, 0x4d, 0x4d, 0x4d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x3b, 0x3b, 0x3b, 0xee, 0xee, 0xee, 0xab, 0xab, 0xab, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf2, 0xf2, 0xf2,
0x4d, 0x4d, 0x4d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x3b, 0x3b, 0xee, 0xee, 0xee, 0xab, 0xab,
0xab, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf2, 0xf2, 0xf2, 0x4e, 0x4e, 0x4e, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x3b, 0x3b,
0xee, 0xee, 0xee, 0xa6, 0xa6, 0xa6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x99, 0x99, 0x99, 0xf0, 0xf0, 0xf0, 0x4f, 0x4f, 0x4f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x3b, 0x3b, 0x3b, 0xed, 0xed, 0xed, 0x88, 0x88, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c,
0x1c, 0x1c, 0x22, 0x22, 0x22, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x6e, 0x6e, 0x6e, 0xf2, 0xf2,
0xf2, 0x4e, 0x4e, 0x4e, 0x00, 0x00, 0x00, 0x3e, 0x3e, 0x3e, 0xf0, 0xf0, 0xf0, 0x76, 0x76, 0x76,
0x1f, 0x1f, 0x1f, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x16, 0x16, 0x16, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xd5, 0xd5, 0xd5, 0xf5, 0xf5, 0xf5, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xe8, 0xe8, 0xe8, 0x6d, 0x6d, 0x6d, 0xe3,
0xe3, 0xe3, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
0xf0, 0xf5, 0xf5, 0xf5, 0xb4, 0xb4, 0xb4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf1, 0xf1, 0xf1, 0x19,
0x19, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x06, 0xf9, 0xf9, 0xf9, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xf1, 0xf1, 0xf1, 0x1f, 0x1f, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x08, 0x08, 0x08, 0xfc, 0xfc, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe7, 0xe7, 0xe7, 0xf9,
0xf9, 0xf9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfa, 0xfa, 0xfa, 0xdf, 0xdf, 0xdf, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
const gdiPalette cursor_dump_00000001_palette = {
.format = 0,
.palette = { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000 }
};
const rdpPointer cursor_dump_00000001_pointer = { .size = 0,
.New = nullptr,
.Free = nullptr,
.Set = nullptr,
.SetNull = nullptr,
.SetDefault = nullptr,
.SetPosition = nullptr,
.paddingA = { 0 },
.xPos = 0,
.yPos = 0,
.width = 24,
.height = 24,
.xorBpp = 24,
.lengthAndMask = ARRAYSIZE(andmask),
.lengthXorMask = ARRAYSIZE(xormask),
.xorMaskData = xormask,
.andMaskData = andmask,
.paddingB = { 0 } };
const uint8_t cursor_dump_00000001_image_bgra32[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xe7, 0xe7, 0xe7, 0xff, 0xf9, 0xf9, 0xf9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfa, 0xfa, 0xfa, 0xff,
0xdf, 0xdf, 0xdf, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xf1, 0xf1, 0xf1, 0xff, 0x1f, 0x1f, 0x1f, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x08, 0x08, 0x08, 0xff,
0xfc, 0xfc, 0xfc, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xf1, 0xf1, 0xf1, 0xff, 0x19, 0x19, 0x19, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x06, 0x06, 0x06, 0xff,
0xf9, 0xf9, 0xf9, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xd5, 0xd5, 0xd5, 0xff, 0xf5, 0xf5, 0xf5, 0xff, 0xf0, 0xf0, 0xf0, 0xff, 0xf0, 0xf0, 0xf0, 0xff,
0xf0, 0xf0, 0xf0, 0xff, 0xf0, 0xf0, 0xf0, 0xff, 0xf0, 0xf0, 0xf0, 0xff, 0xe8, 0xe8, 0xe8, 0xff,
0x6d, 0x6d, 0x6d, 0xff, 0xe3, 0xe3, 0xe3, 0xff, 0xf0, 0xf0, 0xf0, 0xff, 0xf0, 0xf0, 0xf0, 0xff,
0xf0, 0xf0, 0xf0, 0xff, 0xf0, 0xf0, 0xf0, 0xff, 0xf0, 0xf0, 0xf0, 0xff, 0xf5, 0xf5, 0xf5, 0xff,
0xb4, 0xb4, 0xb4, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x1c, 0x1c, 0x1c, 0xff, 0x22, 0x22, 0x22, 0xff, 0x21, 0x21, 0x21, 0xff,
0x21, 0x21, 0x21, 0xff, 0x6e, 0x6e, 0x6e, 0xff, 0xf2, 0xf2, 0xf2, 0xff, 0x4e, 0x4e, 0x4e, 0xff,
0x00, 0x00, 0x00, 0xff, 0x3e, 0x3e, 0x3e, 0xff, 0xf0, 0xf0, 0xf0, 0xff, 0x76, 0x76, 0x76, 0xff,
0x1f, 0x1f, 0x1f, 0xff, 0x21, 0x21, 0x21, 0xff, 0x21, 0x21, 0x21, 0xff, 0x16, 0x16, 0x16, 0xff,
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x99, 0x99, 0x99, 0xff, 0xf0, 0xf0, 0xf0, 0xff, 0x4f, 0x4f, 0x4f, 0xff, 0x00, 0x00, 0x00, 0xff,
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x3b, 0x3b, 0x3b, 0xff, 0xed, 0xed, 0xed, 0xff,
0x88, 0x88, 0x88, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xf2, 0xf2, 0xf2, 0xff, 0x4e, 0x4e, 0x4e, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x3b, 0x3b, 0x3b, 0xff,
0xee, 0xee, 0xee, 0xff, 0xa6, 0xa6, 0xa6, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf2, 0xf2, 0xf2, 0xff,
0x4d, 0x4d, 0x4d, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
0x3b, 0x3b, 0x3b, 0xff, 0xee, 0xee, 0xee, 0xff, 0xab, 0xab, 0xab, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf3, 0xf3, 0xf3, 0xff, 0x4d, 0x4d, 0x4d, 0xff,
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
0x00, 0x00, 0x00, 0xff, 0x3b, 0x3b, 0x3b, 0xff, 0xee, 0xee, 0xee, 0xff, 0xab, 0xab, 0xab, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xfb, 0xfb, 0xfb, 0xff, 0xfb, 0xfb, 0xfb, 0xff, 0xf1, 0xf1, 0xf1, 0xff,
0xf0, 0xf0, 0xf0, 0xff, 0xf0, 0xf0, 0xf0, 0xff, 0xef, 0xef, 0xef, 0xff, 0x03, 0x03, 0x03, 0xff,
0x00, 0x00, 0x00, 0xff, 0x03, 0x03, 0x03, 0xff, 0xef, 0xef, 0xef, 0xff, 0xf0, 0xf0, 0xf0, 0xff,
0xf0, 0xf0, 0xf0, 0xff, 0xf0, 0xf0, 0xf0, 0xff, 0xf9, 0xf9, 0xf9, 0xff, 0xf9, 0xf9, 0xf9, 0xff,
0xab, 0xab, 0xab, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x2a, 0x2a, 0xff, 0x22, 0x22, 0x22, 0xff,
0x21, 0x21, 0x21, 0xff, 0x21, 0x21, 0x21, 0xff, 0xfc, 0xfc, 0xfc, 0xff, 0x03, 0x03, 0x03, 0xff,
0x00, 0x00, 0x00, 0xff, 0x03, 0x03, 0x03, 0xff, 0xfc, 0xfc, 0xfc, 0xff, 0x1d, 0x1d, 0x1d, 0xff,
0x20, 0x20, 0x20, 0xff, 0x21, 0x21, 0x21, 0xff, 0x22, 0x22, 0x22, 0xff, 0x24, 0x24, 0x24, 0xff,
0x29, 0x29, 0x29, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xfc, 0xfc, 0xff, 0x03, 0x03, 0x03, 0xff,
0x00, 0x00, 0x00, 0xff, 0x03, 0x03, 0x03, 0xff, 0xfc, 0xfc, 0xfc, 0xff, 0x00, 0x00, 0x00, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xfc, 0xfc, 0xff, 0x03, 0x03, 0x03, 0xff,
0x00, 0x00, 0x00, 0xff, 0x03, 0x03, 0x03, 0xff, 0xfc, 0xfc, 0xfc, 0xff, 0x00, 0x00, 0x00, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xfc, 0xfc, 0xff, 0x03, 0x03, 0x03, 0xff,
0x00, 0x00, 0x00, 0xff, 0x03, 0x03, 0x03, 0xff, 0xfc, 0xfc, 0xfc, 0xff, 0x00, 0x00, 0x00, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xfc, 0xfc, 0xff, 0x03, 0x03, 0x03, 0xff,
0x00, 0x00, 0x00, 0xff, 0x03, 0x03, 0x03, 0xff, 0xfc, 0xfc, 0xfc, 0xff, 0x00, 0x00, 0x00, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xfc, 0xfc, 0xff, 0x03, 0x03, 0x03, 0xff,
0x00, 0x00, 0x00, 0xff, 0x03, 0x03, 0x03, 0xff, 0xfc, 0xfc, 0xfc, 0xff, 0x00, 0x00, 0x00, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf9, 0xf9, 0xf9, 0xff, 0x16, 0x16, 0x16, 0xff,
0x00, 0x00, 0x00, 0xff, 0x15, 0x15, 0x15, 0xff, 0xf6, 0xf6, 0xf6, 0xff, 0x00, 0x00, 0x00, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc9, 0xc9, 0xc9, 0xff, 0xf1, 0xf1, 0xf1, 0xff,
0xff, 0xff, 0xff, 0xff, 0xf6, 0xf6, 0xf6, 0xff, 0xa0, 0xa0, 0xa0, 0xff, 0x00, 0x00, 0x00, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
@@ -0,0 +1,13 @@
/* FreeRDP cursor dump to use for unit tests
* this file was auto generated by dump_write_header
* do not modify manually
*/
#pragma once
#include <freerdp/codec/color.h>
#include <freerdp/graphics.h>
extern const gdiPalette cursor_dump_00000001_palette;
extern const rdpPointer cursor_dump_00000001_pointer;
extern const uint8_t cursor_dump_00000001_image_bgra32[];
Binary file not shown.

After

Width:  |  Height:  |  Size: 456 B

@@ -0,0 +1,333 @@
/* FreeRDP cursor dump to use for unit tests
* this file was auto generated by dump_write_c_file
* do not modify manually
*/
#include "cursor_dump_00000002.h"
static uint8_t andmask[] = {
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x8f, 0xff, 0x00, 0xef, 0x87, 0xff, 0x00,
0xe3, 0x07, 0xff, 0x00, 0xe0, 0x07, 0xff, 0x00, 0xe0, 0x0f, 0xff, 0x00, 0xe0, 0x0f, 0xff, 0x00,
0xe0, 0x01, 0xff, 0x00, 0xe0, 0x00, 0xff, 0x00, 0xe0, 0x01, 0xff, 0x00, 0xe0, 0x03, 0xff, 0x00,
0xe0, 0x07, 0xff, 0x00, 0xe0, 0x0f, 0xff, 0x00, 0xe0, 0x1f, 0xff, 0x00, 0xe0, 0x3f, 0xff, 0x00,
0xe0, 0x7f, 0xff, 0x00, 0xe0, 0xff, 0xff, 0x00, 0xe1, 0xff, 0xff, 0x00, 0xe3, 0xff, 0xff, 0x00,
0xe7, 0xff, 0xff, 0x00, 0xef, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00
};
static uint8_t xormask[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x77, 0x77, 0x76, 0x76,
0x76, 0x23, 0x23, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xb6, 0xb6, 0xb6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xee, 0xee, 0xee, 0xc0, 0xc0, 0xc0, 0xeb, 0xeb, 0xeb, 0x3b, 0x3b, 0x3b, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfd, 0xfd, 0xfd, 0x8d, 0x8d, 0x8d, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd5, 0xd5, 0xd5, 0x80, 0x80, 0x80, 0x14, 0x14,
0x14, 0xb6, 0xb6, 0xb6, 0x92, 0x92, 0x92, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xff, 0xff, 0xff, 0xe7, 0xe7, 0xe7, 0x8c, 0x8c, 0x8c, 0x00, 0x00, 0x00, 0x75, 0x75, 0x75,
0xee, 0xee, 0xee, 0x1a, 0x1a, 0x1a, 0x27, 0x27, 0x27, 0xf0, 0xf0, 0xf0, 0x55, 0x55, 0x55, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x26, 0x26, 0x26, 0xe5,
0xe5, 0xe5, 0x94, 0x94, 0x94, 0xc3, 0xc3, 0xc3, 0x83, 0x83, 0x83, 0x12, 0x12, 0x12, 0x87, 0x87,
0x87, 0xc8, 0xc8, 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0xe2, 0xe2, 0xe2, 0xef, 0xef, 0xef,
0x1b, 0x1b, 0x1b, 0x1e, 0x1e, 0x1e, 0xea, 0xea, 0xea, 0x63, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x1f, 0x1f, 0x1f, 0x6a, 0x6a, 0x6a, 0x10, 0x10, 0x10, 0x77, 0x77, 0x77, 0xcc, 0xcc,
0xcc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x09, 0x09,
0x19, 0x19, 0x19, 0xde, 0xde, 0xde, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xf5, 0xf5, 0xf5, 0x8d, 0x8d, 0x8d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x02, 0x02, 0x02, 0x0e, 0x0e, 0x0e, 0x1b, 0x1b, 0x1b, 0x27, 0x27, 0x27, 0x34, 0x34,
0x34, 0x40, 0x40, 0x40, 0x7c, 0x7c, 0x7c, 0xf1, 0xf1, 0xf1, 0x87, 0x87, 0x87, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x14, 0x14, 0x14,
0x20, 0x20, 0x20, 0x2d, 0x2d, 0x2d, 0x39, 0x39, 0x39, 0x77, 0x77, 0x77, 0xf1, 0xf1, 0xf1, 0x8b,
0x8b, 0x8b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x0c, 0x0c, 0x0c, 0x19, 0x19, 0x19, 0x26, 0x26, 0x26, 0x32, 0x32, 0x32, 0x6b, 0x6b,
0x6b, 0xf1, 0xf1, 0xf1, 0x98, 0x98, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x05, 0x05, 0x05, 0x12, 0x12, 0x12, 0x1e, 0x1e, 0x1e,
0x2b, 0x2b, 0x2b, 0x62, 0x62, 0x62, 0xf0, 0xf0, 0xf0, 0x98, 0x98, 0x98, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x0b,
0x0b, 0x0b, 0x17, 0x17, 0x17, 0x24, 0x24, 0x24, 0x56, 0x56, 0x56, 0xee, 0xee, 0xee, 0xa2, 0xa2,
0xa2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xff, 0xff, 0xff, 0x03, 0x03, 0x03, 0x10, 0x10, 0x10, 0x1c, 0x1c, 0x1c, 0x4a, 0x4a, 0x4a,
0xec, 0xec, 0xec, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x09, 0x09, 0x09, 0x15,
0x15, 0x15, 0x41, 0x41, 0x41, 0xea, 0xea, 0xea, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xff, 0xff, 0xff, 0x0e, 0x0e, 0x0e, 0x34, 0x34, 0x34, 0xe5, 0xe5, 0xe5, 0xb5, 0xb5, 0xb5,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x2c, 0x2c, 0x2c, 0xe3,
0xe3, 0xe3, 0xb3, 0xb3, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xff, 0xff, 0xff, 0xdf, 0xdf, 0xdf, 0xb9, 0xb9, 0xb9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xc7, 0xc7, 0xc7, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xee, 0xee, 0xee, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
const gdiPalette cursor_dump_00000002_palette = {
.format = 0,
.palette = { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000 }
};
const rdpPointer cursor_dump_00000002_pointer = { .size = 0,
.New = nullptr,
.Free = nullptr,
.Set = nullptr,
.SetNull = nullptr,
.SetDefault = nullptr,
.SetPosition = nullptr,
.paddingA = { 0 },
.xPos = 0,
.yPos = 0,
.width = 24,
.height = 24,
.xorBpp = 24,
.lengthAndMask = ARRAYSIZE(andmask),
.lengthXorMask = ARRAYSIZE(xormask),
.xorMaskData = xormask,
.andMaskData = andmask,
.paddingB = { 0 } };
const uint8_t cursor_dump_00000002_image_bgra32[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xee, 0xee, 0xee, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0xc7, 0xc7, 0xc7, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0xdf, 0xdf, 0xdf, 0xff, 0xb9, 0xb9, 0xb9, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0x2c, 0x2c, 0x2c, 0xff, 0xe3, 0xe3, 0xe3, 0xff, 0xb3, 0xb3, 0xb3, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0x0e, 0x0e, 0x0e, 0xff, 0x34, 0x34, 0x34, 0xff, 0xe5, 0xe5, 0xe5, 0xff, 0xb5, 0xb5, 0xb5, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0x09, 0x09, 0x09, 0xff, 0x15, 0x15, 0x15, 0xff, 0x41, 0x41, 0x41, 0xff, 0xea, 0xea, 0xea, 0xff,
0xaa, 0xaa, 0xaa, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0x03, 0x03, 0x03, 0xff, 0x10, 0x10, 0x10, 0xff, 0x1c, 0x1c, 0x1c, 0xff, 0x4a, 0x4a, 0x4a, 0xff,
0xec, 0xec, 0xec, 0xff, 0xaa, 0xaa, 0xaa, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0xff, 0x0b, 0x0b, 0x0b, 0xff, 0x17, 0x17, 0x17, 0xff, 0x24, 0x24, 0x24, 0xff,
0x56, 0x56, 0x56, 0xff, 0xee, 0xee, 0xee, 0xff, 0xa2, 0xa2, 0xa2, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0xff, 0x05, 0x05, 0x05, 0xff, 0x12, 0x12, 0x12, 0xff, 0x1e, 0x1e, 0x1e, 0xff,
0x2b, 0x2b, 0x2b, 0xff, 0x62, 0x62, 0x62, 0xff, 0xf0, 0xf0, 0xf0, 0xff, 0x98, 0x98, 0x98, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x0c, 0x0c, 0x0c, 0xff, 0x19, 0x19, 0x19, 0xff,
0x26, 0x26, 0x26, 0xff, 0x32, 0x32, 0x32, 0xff, 0x6b, 0x6b, 0x6b, 0xff, 0xf1, 0xf1, 0xf1, 0xff,
0x98, 0x98, 0x98, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x07, 0x07, 0x07, 0xff, 0x14, 0x14, 0x14, 0xff,
0x20, 0x20, 0x20, 0xff, 0x2d, 0x2d, 0x2d, 0xff, 0x39, 0x39, 0x39, 0xff, 0x77, 0x77, 0x77, 0xff,
0xf1, 0xf1, 0xf1, 0xff, 0x8b, 0x8b, 0x8b, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x02, 0x02, 0x02, 0xff, 0x0e, 0x0e, 0x0e, 0xff,
0x1b, 0x1b, 0x1b, 0xff, 0x27, 0x27, 0x27, 0xff, 0x34, 0x34, 0x34, 0xff, 0x40, 0x40, 0x40, 0xff,
0x7c, 0x7c, 0x7c, 0xff, 0xf1, 0xf1, 0xf1, 0xff, 0x87, 0x87, 0x87, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x09, 0x09, 0x09, 0xff,
0x19, 0x19, 0x19, 0xff, 0xde, 0xde, 0xde, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf5, 0xf5, 0xf5, 0xff, 0x8d, 0x8d, 0x8d, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x1f, 0x1f, 0x1f, 0xff, 0x6a, 0x6a, 0x6a, 0xff,
0x10, 0x10, 0x10, 0xff, 0x77, 0x77, 0x77, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0x00, 0x00, 0x00, 0xff,
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0xff, 0x22, 0x22, 0x22, 0xff, 0xe2, 0xe2, 0xe2, 0xff, 0xef, 0xef, 0xef, 0xff,
0x1b, 0x1b, 0x1b, 0xff, 0x1e, 0x1e, 0x1e, 0xff, 0xea, 0xea, 0xea, 0xff, 0x63, 0x63, 0x63, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0x26, 0x26, 0x26, 0xff, 0xe5, 0xe5, 0xe5, 0xff, 0x94, 0x94, 0x94, 0xff, 0xc3, 0xc3, 0xc3, 0xff,
0x83, 0x83, 0x83, 0xff, 0x12, 0x12, 0x12, 0xff, 0x87, 0x87, 0x87, 0xff, 0xc8, 0xc8, 0xc8, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0xe7, 0xe7, 0xe7, 0xff, 0x8c, 0x8c, 0x8c, 0xff, 0x00, 0x00, 0x00, 0xff, 0x75, 0x75, 0x75, 0xff,
0xee, 0xee, 0xee, 0xff, 0x1a, 0x1a, 0x1a, 0xff, 0x27, 0x27, 0x27, 0xff, 0xf0, 0xf0, 0xf0, 0xff,
0x55, 0x55, 0x55, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfd, 0xfd, 0xfd, 0xff,
0x8d, 0x8d, 0x8d, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xd5, 0xd5, 0xd5, 0xff, 0x80, 0x80, 0x80, 0xff, 0x14, 0x14, 0x14, 0xff, 0xb6, 0xb6, 0xb6, 0xff,
0x92, 0x92, 0x92, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb6, 0xb6, 0xb6, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xee, 0xee, 0xee, 0xff, 0xc0, 0xc0, 0xc0, 0xff, 0xeb, 0xeb, 0xeb, 0xff,
0x3b, 0x3b, 0x3b, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x77, 0x77, 0x77, 0xff, 0x76, 0x76, 0x76, 0xff, 0x23, 0x23, 0x23, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
@@ -0,0 +1,13 @@
/* FreeRDP cursor dump to use for unit tests
* this file was auto generated by dump_write_header
* do not modify manually
*/
#pragma once
#include <freerdp/codec/color.h>
#include <freerdp/graphics.h>
extern const gdiPalette cursor_dump_00000002_palette;
extern const rdpPointer cursor_dump_00000002_pointer;
extern const uint8_t cursor_dump_00000002_image_bgra32[];
Binary file not shown.

After

Width:  |  Height:  |  Size: 537 B

@@ -0,0 +1,333 @@
/* FreeRDP cursor dump to use for unit tests
* this file was auto generated by dump_write_c_file
* do not modify manually
*/
#include "cursor_dump_00000003.h"
static uint8_t andmask[] = {
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xc7, 0xff, 0x00,
0xff, 0x83, 0xff, 0x00, 0xff, 0x01, 0xff, 0x00, 0xfe, 0x00, 0xff, 0x00, 0xfc, 0x00, 0x7f, 0x00,
0xf8, 0x00, 0x3f, 0x00, 0xf0, 0xc2, 0x1f, 0x00, 0xe0, 0x82, 0x0f, 0x00, 0xc0, 0x00, 0x07, 0x00,
0x80, 0x00, 0x07, 0x00, 0x80, 0x02, 0x07, 0x00, 0xc0, 0x02, 0x0f, 0x00, 0xe0, 0x86, 0x1f, 0x00,
0xf0, 0x00, 0x3f, 0x00, 0xf8, 0x00, 0x7f, 0x00, 0xfc, 0x00, 0xff, 0x00, 0xfe, 0x01, 0xff, 0x00,
0xff, 0x03, 0xff, 0x00, 0xff, 0x87, 0xff, 0x00, 0xff, 0xcf, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00
};
static uint8_t xormask[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb5, 0xb5, 0xb5, 0xac, 0xac, 0xac, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb4, 0xb4, 0xb4, 0xdd, 0xdd,
0xdd, 0xd6, 0xd6, 0xd6, 0xa4, 0xa4, 0xa4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xb1, 0xb1, 0xb1, 0xde, 0xde, 0xde, 0x1b, 0x1b, 0x1b, 0x15, 0x15, 0x15, 0xd6, 0xd6, 0xd6, 0xa3,
0xa3, 0xa3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xb1, 0xb1, 0xb1, 0xdf, 0xdf, 0xdf, 0x1b, 0x1b, 0x1b, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x16, 0x16, 0x16, 0xd6, 0xd6, 0xd6, 0xa3, 0xa3, 0xa3, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0xb0, 0xb0, 0xe3, 0xe3, 0xe3,
0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16,
0x16, 0x16, 0xd7, 0xd7, 0xd7, 0xa6, 0xa6, 0xa6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaf,
0xaf, 0xaf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xa6, 0xa6, 0xa6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xaf, 0xaf, 0xaf, 0xe1, 0xe1, 0xe1, 0xfd, 0xfd, 0xfd, 0x08, 0x08, 0x08,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0xfe, 0xda, 0xda, 0xda, 0xa1, 0xa1, 0xa1, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xad, 0xad, 0xad, 0xe2, 0xe2, 0xe2, 0x1f,
0x1f, 0x1f, 0xfc, 0xfc, 0xfc, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0xba, 0xba, 0xba, 0xee, 0xee,
0xee, 0xed, 0xed, 0xed, 0xac, 0xac, 0xac, 0x0f, 0x0f, 0x0f, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0xfe,
0x19, 0x19, 0x19, 0xda, 0xda, 0xda, 0xa1, 0xa1, 0xa1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaf, 0xaf,
0xaf, 0xe3, 0xe3, 0xe3, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc, 0xfc, 0xfc, 0x08, 0x08, 0x08,
0xc9, 0xc9, 0xc9, 0xb4, 0xb4, 0xb4, 0x18, 0x18, 0x18, 0x19, 0x19, 0x19, 0xb5, 0xb5, 0xb5, 0xb0,
0xb0, 0xb0, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0xfe, 0x01, 0x01, 0x01, 0x18, 0x18, 0x18, 0xda, 0xda,
0xda, 0xa0, 0xa0, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xd5, 0xd5, 0xd5, 0xe5, 0xe5, 0xe5, 0x21, 0x21, 0x21, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xfc, 0xfc, 0xfc, 0x07, 0x07, 0x07, 0xf1, 0xf1, 0xf1, 0x17, 0x17, 0x17, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x19, 0x19, 0x19, 0xee, 0xee, 0xee, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0xfe,
0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0xdb, 0xdb, 0xdb, 0xa9, 0xa9, 0xa9, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe9, 0xe9, 0xe9, 0xe5, 0xe5,
0xe5, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xfc, 0xfc, 0x08, 0x08, 0x08,
0xf2, 0xf2, 0xf2, 0x17, 0x17, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x19, 0x19, 0xef,
0xef, 0xef, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0xfe, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x13, 0x13,
0x13, 0xd2, 0xd2, 0xd2, 0xcb, 0xcb, 0xcb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe7, 0xe7, 0xe7, 0xe6, 0xe6, 0xe6, 0x20, 0x20, 0x20, 0x00,
0x00, 0x00, 0xfc, 0xfc, 0xfc, 0x08, 0x08, 0x08, 0xdd, 0xdd, 0xdd, 0xb4, 0xb4, 0xb4, 0x17, 0x17,
0x17, 0x18, 0x18, 0x18, 0xb4, 0xb4, 0xb4, 0xc8, 0xc8, 0xc8, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0xfe,
0x01, 0x01, 0x01, 0x15, 0x15, 0x15, 0xd5, 0xd5, 0xd5, 0xca, 0xca, 0xca, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0x1f, 0x1f, 0x1f, 0xfc, 0xfc, 0xfc, 0x08, 0x08, 0x08,
0x00, 0x00, 0x00, 0xd9, 0xd9, 0xd9, 0xf3, 0xf3, 0xf3, 0xf2, 0xf2, 0xf2, 0xce, 0xce, 0xce, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0xfe, 0x17, 0x17, 0x17, 0xd8, 0xd8, 0xd8, 0xc8, 0xc8,
0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe7, 0xe7, 0xe7, 0xe5,
0xe5, 0xe5, 0xfd, 0xfd, 0xfd, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0xfe,
0xd9, 0xd9, 0xd9, 0xc5, 0xc5, 0xc5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe5, 0xe5, 0xe5, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc4, 0xc4, 0xc4, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xe4, 0xe4, 0xe4, 0xe6, 0xe6, 0xe6, 0x21, 0x21, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0xda, 0xda, 0xda, 0xc5, 0xc5, 0xc5,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe4, 0xe4, 0xe4,
0xe6, 0xe6, 0xe6, 0x21, 0x21, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x1c, 0x1c, 0xdf,
0xdf, 0xdf, 0xc5, 0xc5, 0xc5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe4, 0xe4, 0xe4, 0xe6, 0xe6, 0xe6, 0x21, 0x21,
0x21, 0x1d, 0x1d, 0x1d, 0xe0, 0xe0, 0xe0, 0xc5, 0xc5, 0xc5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xe7, 0xe7, 0xe7, 0xe3, 0xe3, 0xe3, 0xe3, 0xe3, 0xe3, 0xbf, 0xbf, 0xbf, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xeb, 0xeb,
0xeb, 0xdd, 0xdd, 0xdd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
const gdiPalette cursor_dump_00000003_palette = {
.format = 0,
.palette = { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000 }
};
const rdpPointer cursor_dump_00000003_pointer = { .size = 0,
.New = nullptr,
.Free = nullptr,
.Set = nullptr,
.SetNull = nullptr,
.SetDefault = nullptr,
.SetPosition = nullptr,
.paddingA = { 0 },
.xPos = 0,
.yPos = 0,
.width = 24,
.height = 24,
.xorBpp = 24,
.lengthAndMask = ARRAYSIZE(andmask),
.lengthXorMask = ARRAYSIZE(xormask),
.xorMaskData = xormask,
.andMaskData = andmask,
.paddingB = { 0 } };
const uint8_t cursor_dump_00000003_image_bgra32[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xeb, 0xeb, 0xeb, 0xff, 0xdd, 0xdd, 0xdd, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xe7, 0xe7, 0xe7, 0xff, 0xe3, 0xe3, 0xe3, 0xff, 0xe3, 0xe3, 0xe3, 0xff,
0xbf, 0xbf, 0xbf, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xe4, 0xe4, 0xe4, 0xff, 0xe6, 0xe6, 0xe6, 0xff, 0x21, 0x21, 0x21, 0xff, 0x1d, 0x1d, 0x1d, 0xff,
0xe0, 0xe0, 0xe0, 0xff, 0xc5, 0xc5, 0xc5, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe4, 0xe4, 0xe4, 0xff,
0xe6, 0xe6, 0xe6, 0xff, 0x21, 0x21, 0x21, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
0x1c, 0x1c, 0x1c, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xc5, 0xc5, 0xc5, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe4, 0xe4, 0xe4, 0xff, 0xe6, 0xe6, 0xe6, 0xff,
0x21, 0x21, 0x21, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0xff, 0xda, 0xda, 0xda, 0xff, 0xc5, 0xc5, 0xc5, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xe5, 0xe5, 0xe5, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xc4, 0xc4, 0xc4, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xe7, 0xe7, 0xe7, 0xff, 0xe5, 0xe5, 0xe5, 0xff, 0xfd, 0xfd, 0xfd, 0xff, 0x06, 0x06, 0x06, 0xff,
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0xfe, 0xfe, 0xfe, 0xff,
0xd9, 0xd9, 0xd9, 0xff, 0xc5, 0xc5, 0xc5, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe5, 0xe5, 0xe5, 0xff,
0xe5, 0xe5, 0xe5, 0xff, 0x1f, 0x1f, 0x1f, 0xff, 0xfc, 0xfc, 0xfc, 0xff, 0x08, 0x08, 0x08, 0xff,
0x00, 0x00, 0x00, 0x00, 0xd9, 0xd9, 0xd9, 0xff, 0xf3, 0xf3, 0xf3, 0xff, 0xf2, 0xf2, 0xf2, 0xff,
0xce, 0xce, 0xce, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0xfe, 0xff,
0x17, 0x17, 0x17, 0xff, 0xd8, 0xd8, 0xd8, 0xff, 0xc8, 0xc8, 0xc8, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe7, 0xe7, 0xe7, 0xff, 0xe6, 0xe6, 0xe6, 0xff,
0x20, 0x20, 0x20, 0xff, 0x00, 0x00, 0x00, 0xff, 0xfc, 0xfc, 0xfc, 0xff, 0x08, 0x08, 0x08, 0xff,
0xdd, 0xdd, 0xdd, 0xff, 0xb4, 0xb4, 0xb4, 0xff, 0x17, 0x17, 0x17, 0xff, 0x18, 0x18, 0x18, 0xff,
0xb4, 0xb4, 0xb4, 0xff, 0xc8, 0xc8, 0xc8, 0xff, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0xfe, 0xff,
0x01, 0x01, 0x01, 0xff, 0x15, 0x15, 0x15, 0xff, 0xd5, 0xd5, 0xd5, 0xff, 0xca, 0xca, 0xca, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xe9, 0xe9, 0xe9, 0xff, 0xe5, 0xe5, 0xe5, 0xff, 0x20, 0x20, 0x20, 0xff,
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0xfc, 0xfc, 0xfc, 0xff, 0x08, 0x08, 0x08, 0xff,
0xf2, 0xf2, 0xf2, 0xff, 0x17, 0x17, 0x17, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
0x19, 0x19, 0x19, 0xff, 0xef, 0xef, 0xef, 0xff, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0xfe, 0xff,
0x01, 0x01, 0x01, 0xff, 0x00, 0x00, 0x00, 0xff, 0x13, 0x13, 0x13, 0xff, 0xd2, 0xd2, 0xd2, 0xff,
0xcb, 0xcb, 0xcb, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xd5, 0xd5, 0xd5, 0xff, 0xe5, 0xe5, 0xe5, 0xff, 0x21, 0x21, 0x21, 0xff,
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0xfc, 0xfc, 0xfc, 0xff, 0x07, 0x07, 0x07, 0xff,
0xf1, 0xf1, 0xf1, 0xff, 0x17, 0x17, 0x17, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
0x19, 0x19, 0x19, 0xff, 0xee, 0xee, 0xee, 0xff, 0x00, 0x00, 0x00, 0xff, 0xfe, 0xfe, 0xfe, 0xff,
0x01, 0x01, 0x01, 0xff, 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0xff, 0xdb, 0xdb, 0xdb, 0xff,
0xa9, 0xa9, 0xa9, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaf, 0xaf, 0xaf, 0xff, 0xe3, 0xe3, 0xe3, 0xff,
0x20, 0x20, 0x20, 0xff, 0x00, 0x00, 0x00, 0xff, 0xfc, 0xfc, 0xfc, 0xff, 0x08, 0x08, 0x08, 0xff,
0xc9, 0xc9, 0xc9, 0xff, 0xb4, 0xb4, 0xb4, 0xff, 0x18, 0x18, 0x18, 0xff, 0x19, 0x19, 0x19, 0xff,
0xb5, 0xb5, 0xb5, 0xff, 0xb0, 0xb0, 0xb0, 0xff, 0x00, 0x00, 0x00, 0xff, 0xfe, 0xfe, 0xfe, 0xff,
0x01, 0x01, 0x01, 0xff, 0x18, 0x18, 0x18, 0xff, 0xda, 0xda, 0xda, 0xff, 0xa0, 0xa0, 0xa0, 0xff,
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xad, 0xad, 0xad, 0xff,
0xe2, 0xe2, 0xe2, 0xff, 0x1f, 0x1f, 0x1f, 0xff, 0xfc, 0xfc, 0xfc, 0xff, 0x08, 0x08, 0x08, 0xff,
0x00, 0x00, 0x00, 0x00, 0xba, 0xba, 0xba, 0xff, 0xee, 0xee, 0xee, 0xff, 0xed, 0xed, 0xed, 0xff,
0xac, 0xac, 0xac, 0xff, 0x0f, 0x0f, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0xfe, 0xff,
0x19, 0x19, 0x19, 0xff, 0xda, 0xda, 0xda, 0xff, 0xa1, 0xa1, 0xa1, 0xff, 0x00, 0x00, 0x00, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xaf, 0xaf, 0xaf, 0xff, 0xe1, 0xe1, 0xe1, 0xff, 0xfd, 0xfd, 0xfd, 0xff, 0x08, 0x08, 0x08, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0xfe, 0xff,
0xda, 0xda, 0xda, 0xff, 0xa1, 0xa1, 0xa1, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xaf, 0xaf, 0xaf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xa6, 0xa6, 0xa6, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0xb0, 0xb0, 0xff, 0xe3, 0xe3, 0xe3, 0xff,
0x20, 0x20, 0x20, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
0x00, 0x00, 0x00, 0xff, 0x16, 0x16, 0x16, 0xff, 0xd7, 0xd7, 0xd7, 0xff, 0xa6, 0xa6, 0xa6, 0xff,
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb1, 0xb1, 0xb1, 0xff,
0xdf, 0xdf, 0xdf, 0xff, 0x1b, 0x1b, 0x1b, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
0x16, 0x16, 0x16, 0xff, 0xd6, 0xd6, 0xd6, 0xff, 0xa3, 0xa3, 0xa3, 0xff, 0x00, 0x00, 0x00, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xb1, 0xb1, 0xb1, 0xff, 0xde, 0xde, 0xde, 0xff, 0x1b, 0x1b, 0x1b, 0xff, 0x15, 0x15, 0x15, 0xff,
0xd6, 0xd6, 0xd6, 0xff, 0xa3, 0xa3, 0xa3, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xb4, 0xb4, 0xb4, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xd6, 0xd6, 0xd6, 0xff,
0xa4, 0xa4, 0xa4, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb5, 0xb5, 0xb5, 0xff, 0xac, 0xac, 0xac, 0xff,
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
@@ -0,0 +1,13 @@
/* FreeRDP cursor dump to use for unit tests
* this file was auto generated by dump_write_header
* do not modify manually
*/
#pragma once
#include <freerdp/codec/color.h>
#include <freerdp/graphics.h>
extern const gdiPalette cursor_dump_00000003_palette;
extern const rdpPointer cursor_dump_00000003_pointer;
extern const uint8_t cursor_dump_00000003_image_bgra32[];
Binary file not shown.

After

Width:  |  Height:  |  Size: 573 B

@@ -0,0 +1,333 @@
/* FreeRDP cursor dump to use for unit tests
* this file was auto generated by dump_write_c_file
* do not modify manually
*/
#include "cursor_dump_00000004.h"
static uint8_t andmask[] = {
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xc7, 0xff, 0x00,
0xff, 0x83, 0xff, 0x00, 0xff, 0x01, 0xff, 0x00, 0xfe, 0x00, 0xff, 0x00, 0xfc, 0x00, 0x7f, 0x00,
0xf8, 0x00, 0x3f, 0x00, 0xf0, 0xc2, 0x1f, 0x00, 0xe0, 0x82, 0x0f, 0x00, 0xc0, 0x00, 0x07, 0x00,
0x80, 0x00, 0x07, 0x00, 0x80, 0x02, 0x07, 0x00, 0xc0, 0x02, 0x0f, 0x00, 0xe0, 0x86, 0x1f, 0x00,
0xf0, 0x00, 0x3f, 0x00, 0xf8, 0x00, 0x7f, 0x00, 0xfc, 0x00, 0xff, 0x00, 0xfe, 0x01, 0xff, 0x00,
0xff, 0x03, 0xff, 0x00, 0xff, 0x87, 0xff, 0x00, 0xff, 0xcf, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00
};
static uint8_t xormask[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb5, 0xb5, 0xb5, 0xac, 0xac, 0xac, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb4, 0xb4, 0xb4, 0xdd, 0xdd,
0xdd, 0xd6, 0xd6, 0xd6, 0xa4, 0xa4, 0xa4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xb1, 0xb1, 0xb1, 0xde, 0xde, 0xde, 0x1b, 0x1b, 0x1b, 0x15, 0x15, 0x15, 0xd6, 0xd6, 0xd6, 0xa3,
0xa3, 0xa3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xb1, 0xb1, 0xb1, 0xdf, 0xdf, 0xdf, 0x1b, 0x1b, 0x1b, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x16, 0x16, 0x16, 0xd6, 0xd6, 0xd6, 0xa3, 0xa3, 0xa3, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0xb0, 0xb0, 0xe3, 0xe3, 0xe3,
0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16,
0x16, 0x16, 0xd7, 0xd7, 0xd7, 0xa6, 0xa6, 0xa6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaf,
0xaf, 0xaf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xa6, 0xa6, 0xa6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xaf, 0xaf, 0xaf, 0xe1, 0xe1, 0xe1, 0xfd, 0xfd, 0xfd, 0x08, 0x08, 0x08,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0xfe, 0xda, 0xda, 0xda, 0xa1, 0xa1, 0xa1, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xad, 0xad, 0xad, 0xe2, 0xe2, 0xe2, 0x1f,
0x1f, 0x1f, 0xfc, 0xfc, 0xfc, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0xba, 0xba, 0xba, 0xee, 0xee,
0xee, 0xed, 0xed, 0xed, 0xac, 0xac, 0xac, 0x0f, 0x0f, 0x0f, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0xfe,
0x19, 0x19, 0x19, 0xda, 0xda, 0xda, 0xa1, 0xa1, 0xa1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaf, 0xaf,
0xaf, 0xe3, 0xe3, 0xe3, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc, 0xfc, 0xfc, 0x08, 0x08, 0x08,
0xc9, 0xc9, 0xc9, 0xb4, 0xb4, 0xb4, 0x18, 0x18, 0x18, 0x19, 0x19, 0x19, 0xb5, 0xb5, 0xb5, 0xb0,
0xb0, 0xb0, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0xfe, 0x01, 0x01, 0x01, 0x18, 0x18, 0x18, 0xda, 0xda,
0xda, 0xa0, 0xa0, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xd5, 0xd5, 0xd5, 0xe5, 0xe5, 0xe5, 0x21, 0x21, 0x21, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xfc, 0xfc, 0xfc, 0x07, 0x07, 0x07, 0xf1, 0xf1, 0xf1, 0x17, 0x17, 0x17, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x19, 0x19, 0x19, 0xee, 0xee, 0xee, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0xfe,
0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0xdb, 0xdb, 0xdb, 0xa9, 0xa9, 0xa9, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe9, 0xe9, 0xe9, 0xe5, 0xe5,
0xe5, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xfc, 0xfc, 0x08, 0x08, 0x08,
0xf2, 0xf2, 0xf2, 0x17, 0x17, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x19, 0x19, 0xef,
0xef, 0xef, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0xfe, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x13, 0x13,
0x13, 0xd2, 0xd2, 0xd2, 0xcb, 0xcb, 0xcb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe7, 0xe7, 0xe7, 0xe6, 0xe6, 0xe6, 0x20, 0x20, 0x20, 0x00,
0x00, 0x00, 0xfc, 0xfc, 0xfc, 0x08, 0x08, 0x08, 0xdd, 0xdd, 0xdd, 0xb4, 0xb4, 0xb4, 0x17, 0x17,
0x17, 0x18, 0x18, 0x18, 0xb4, 0xb4, 0xb4, 0xc8, 0xc8, 0xc8, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0xfe,
0x01, 0x01, 0x01, 0x15, 0x15, 0x15, 0xd5, 0xd5, 0xd5, 0xca, 0xca, 0xca, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0x1f, 0x1f, 0x1f, 0xfc, 0xfc, 0xfc, 0x08, 0x08, 0x08,
0x00, 0x00, 0x00, 0xd9, 0xd9, 0xd9, 0xf3, 0xf3, 0xf3, 0xf2, 0xf2, 0xf2, 0xce, 0xce, 0xce, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0xfe, 0x17, 0x17, 0x17, 0xd8, 0xd8, 0xd8, 0xc8, 0xc8,
0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe7, 0xe7, 0xe7, 0xe5,
0xe5, 0xe5, 0xfd, 0xfd, 0xfd, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0xfe,
0xd9, 0xd9, 0xd9, 0xc5, 0xc5, 0xc5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe5, 0xe5, 0xe5, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc4, 0xc4, 0xc4, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xe4, 0xe4, 0xe4, 0xe6, 0xe6, 0xe6, 0x21, 0x21, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0xda, 0xda, 0xda, 0xc5, 0xc5, 0xc5,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe4, 0xe4, 0xe4,
0xe6, 0xe6, 0xe6, 0x21, 0x21, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x1c, 0x1c, 0xdf,
0xdf, 0xdf, 0xc5, 0xc5, 0xc5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe4, 0xe4, 0xe4, 0xe6, 0xe6, 0xe6, 0x21, 0x21,
0x21, 0x1d, 0x1d, 0x1d, 0xe0, 0xe0, 0xe0, 0xc5, 0xc5, 0xc5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xe7, 0xe7, 0xe7, 0xe3, 0xe3, 0xe3, 0xe3, 0xe3, 0xe3, 0xbf, 0xbf, 0xbf, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xeb, 0xeb,
0xeb, 0xdd, 0xdd, 0xdd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
const gdiPalette cursor_dump_00000004_palette = {
.format = 0,
.palette = { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000 }
};
const rdpPointer cursor_dump_00000004_pointer = { .size = 0,
.New = nullptr,
.Free = nullptr,
.Set = nullptr,
.SetNull = nullptr,
.SetDefault = nullptr,
.SetPosition = nullptr,
.paddingA = { 0 },
.xPos = 0,
.yPos = 0,
.width = 24,
.height = 24,
.xorBpp = 24,
.lengthAndMask = ARRAYSIZE(andmask),
.lengthXorMask = ARRAYSIZE(xormask),
.xorMaskData = xormask,
.andMaskData = andmask,
.paddingB = { 0 } };
const uint8_t cursor_dump_00000004_image_bgra32[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xeb, 0xeb, 0xeb, 0xff, 0xdd, 0xdd, 0xdd, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xe7, 0xe7, 0xe7, 0xff, 0xe3, 0xe3, 0xe3, 0xff, 0xe3, 0xe3, 0xe3, 0xff,
0xbf, 0xbf, 0xbf, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xe4, 0xe4, 0xe4, 0xff, 0xe6, 0xe6, 0xe6, 0xff, 0x21, 0x21, 0x21, 0xff, 0x1d, 0x1d, 0x1d, 0xff,
0xe0, 0xe0, 0xe0, 0xff, 0xc5, 0xc5, 0xc5, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe4, 0xe4, 0xe4, 0xff,
0xe6, 0xe6, 0xe6, 0xff, 0x21, 0x21, 0x21, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
0x1c, 0x1c, 0x1c, 0xff, 0xdf, 0xdf, 0xdf, 0xff, 0xc5, 0xc5, 0xc5, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe4, 0xe4, 0xe4, 0xff, 0xe6, 0xe6, 0xe6, 0xff,
0x21, 0x21, 0x21, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0xff, 0xda, 0xda, 0xda, 0xff, 0xc5, 0xc5, 0xc5, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xe5, 0xe5, 0xe5, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xc4, 0xc4, 0xc4, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xe7, 0xe7, 0xe7, 0xff, 0xe5, 0xe5, 0xe5, 0xff, 0xfd, 0xfd, 0xfd, 0xff, 0x06, 0x06, 0x06, 0xff,
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0xfe, 0xfe, 0xfe, 0xff,
0xd9, 0xd9, 0xd9, 0xff, 0xc5, 0xc5, 0xc5, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe5, 0xe5, 0xe5, 0xff,
0xe5, 0xe5, 0xe5, 0xff, 0x1f, 0x1f, 0x1f, 0xff, 0xfc, 0xfc, 0xfc, 0xff, 0x08, 0x08, 0x08, 0xff,
0x00, 0x00, 0x00, 0x00, 0xd9, 0xd9, 0xd9, 0xff, 0xf3, 0xf3, 0xf3, 0xff, 0xf2, 0xf2, 0xf2, 0xff,
0xce, 0xce, 0xce, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0xfe, 0xff,
0x17, 0x17, 0x17, 0xff, 0xd8, 0xd8, 0xd8, 0xff, 0xc8, 0xc8, 0xc8, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe7, 0xe7, 0xe7, 0xff, 0xe6, 0xe6, 0xe6, 0xff,
0x20, 0x20, 0x20, 0xff, 0x00, 0x00, 0x00, 0xff, 0xfc, 0xfc, 0xfc, 0xff, 0x08, 0x08, 0x08, 0xff,
0xdd, 0xdd, 0xdd, 0xff, 0xb4, 0xb4, 0xb4, 0xff, 0x17, 0x17, 0x17, 0xff, 0x18, 0x18, 0x18, 0xff,
0xb4, 0xb4, 0xb4, 0xff, 0xc8, 0xc8, 0xc8, 0xff, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0xfe, 0xff,
0x01, 0x01, 0x01, 0xff, 0x15, 0x15, 0x15, 0xff, 0xd5, 0xd5, 0xd5, 0xff, 0xca, 0xca, 0xca, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xe9, 0xe9, 0xe9, 0xff, 0xe5, 0xe5, 0xe5, 0xff, 0x20, 0x20, 0x20, 0xff,
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0xfc, 0xfc, 0xfc, 0xff, 0x08, 0x08, 0x08, 0xff,
0xf2, 0xf2, 0xf2, 0xff, 0x17, 0x17, 0x17, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
0x19, 0x19, 0x19, 0xff, 0xef, 0xef, 0xef, 0xff, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0xfe, 0xff,
0x01, 0x01, 0x01, 0xff, 0x00, 0x00, 0x00, 0xff, 0x13, 0x13, 0x13, 0xff, 0xd2, 0xd2, 0xd2, 0xff,
0xcb, 0xcb, 0xcb, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xd5, 0xd5, 0xd5, 0xff, 0xe5, 0xe5, 0xe5, 0xff, 0x21, 0x21, 0x21, 0xff,
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0xfc, 0xfc, 0xfc, 0xff, 0x07, 0x07, 0x07, 0xff,
0xf1, 0xf1, 0xf1, 0xff, 0x17, 0x17, 0x17, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
0x19, 0x19, 0x19, 0xff, 0xee, 0xee, 0xee, 0xff, 0x00, 0x00, 0x00, 0xff, 0xfe, 0xfe, 0xfe, 0xff,
0x01, 0x01, 0x01, 0xff, 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0xff, 0xdb, 0xdb, 0xdb, 0xff,
0xa9, 0xa9, 0xa9, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaf, 0xaf, 0xaf, 0xff, 0xe3, 0xe3, 0xe3, 0xff,
0x20, 0x20, 0x20, 0xff, 0x00, 0x00, 0x00, 0xff, 0xfc, 0xfc, 0xfc, 0xff, 0x08, 0x08, 0x08, 0xff,
0xc9, 0xc9, 0xc9, 0xff, 0xb4, 0xb4, 0xb4, 0xff, 0x18, 0x18, 0x18, 0xff, 0x19, 0x19, 0x19, 0xff,
0xb5, 0xb5, 0xb5, 0xff, 0xb0, 0xb0, 0xb0, 0xff, 0x00, 0x00, 0x00, 0xff, 0xfe, 0xfe, 0xfe, 0xff,
0x01, 0x01, 0x01, 0xff, 0x18, 0x18, 0x18, 0xff, 0xda, 0xda, 0xda, 0xff, 0xa0, 0xa0, 0xa0, 0xff,
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xad, 0xad, 0xad, 0xff,
0xe2, 0xe2, 0xe2, 0xff, 0x1f, 0x1f, 0x1f, 0xff, 0xfc, 0xfc, 0xfc, 0xff, 0x08, 0x08, 0x08, 0xff,
0x00, 0x00, 0x00, 0x00, 0xba, 0xba, 0xba, 0xff, 0xee, 0xee, 0xee, 0xff, 0xed, 0xed, 0xed, 0xff,
0xac, 0xac, 0xac, 0xff, 0x0f, 0x0f, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0xfe, 0xff,
0x19, 0x19, 0x19, 0xff, 0xda, 0xda, 0xda, 0xff, 0xa1, 0xa1, 0xa1, 0xff, 0x00, 0x00, 0x00, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xaf, 0xaf, 0xaf, 0xff, 0xe1, 0xe1, 0xe1, 0xff, 0xfd, 0xfd, 0xfd, 0xff, 0x08, 0x08, 0x08, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0xfe, 0xff,
0xda, 0xda, 0xda, 0xff, 0xa1, 0xa1, 0xa1, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xaf, 0xaf, 0xaf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xa6, 0xa6, 0xa6, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0xb0, 0xb0, 0xff, 0xe3, 0xe3, 0xe3, 0xff,
0x20, 0x20, 0x20, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
0x00, 0x00, 0x00, 0xff, 0x16, 0x16, 0x16, 0xff, 0xd7, 0xd7, 0xd7, 0xff, 0xa6, 0xa6, 0xa6, 0xff,
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb1, 0xb1, 0xb1, 0xff,
0xdf, 0xdf, 0xdf, 0xff, 0x1b, 0x1b, 0x1b, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
0x16, 0x16, 0x16, 0xff, 0xd6, 0xd6, 0xd6, 0xff, 0xa3, 0xa3, 0xa3, 0xff, 0x00, 0x00, 0x00, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xb1, 0xb1, 0xb1, 0xff, 0xde, 0xde, 0xde, 0xff, 0x1b, 0x1b, 0x1b, 0xff, 0x15, 0x15, 0x15, 0xff,
0xd6, 0xd6, 0xd6, 0xff, 0xa3, 0xa3, 0xa3, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xb4, 0xb4, 0xb4, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xd6, 0xd6, 0xd6, 0xff,
0xa4, 0xa4, 0xa4, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb5, 0xb5, 0xb5, 0xff, 0xac, 0xac, 0xac, 0xff,
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
@@ -0,0 +1,13 @@
/* FreeRDP cursor dump to use for unit tests
* this file was auto generated by dump_write_header
* do not modify manually
*/
#pragma once
#include <freerdp/codec/color.h>
#include <freerdp/graphics.h>
extern const gdiPalette cursor_dump_00000004_palette;
extern const rdpPointer cursor_dump_00000004_pointer;
extern const uint8_t cursor_dump_00000004_image_bgra32[];
Binary file not shown.

After

Width:  |  Height:  |  Size: 573 B

@@ -0,0 +1,333 @@
/* FreeRDP cursor dump to use for unit tests
* this file was auto generated by dump_write_c_file
* do not modify manually
*/
#include "cursor_dump_00000005.h"
static uint8_t andmask[] = {
0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x8f, 0xff, 0x00, 0xef, 0x87, 0xff, 0x00,
0xe3, 0x07, 0xff, 0x00, 0xe0, 0x07, 0xff, 0x00, 0xe0, 0x0f, 0xff, 0x00, 0xe0, 0x0f, 0xff, 0x00,
0xe0, 0x01, 0xff, 0x00, 0xe0, 0x00, 0xff, 0x00, 0xe0, 0x01, 0xff, 0x00, 0xe0, 0x03, 0xff, 0x00,
0xe0, 0x07, 0xff, 0x00, 0xe0, 0x0f, 0xff, 0x00, 0xe0, 0x1f, 0xff, 0x00, 0xe0, 0x3f, 0xff, 0x00,
0xe0, 0x7f, 0xff, 0x00, 0xe0, 0xff, 0xff, 0x00, 0xe1, 0xff, 0xff, 0x00, 0xe3, 0xff, 0xff, 0x00,
0xe7, 0xff, 0xff, 0x00, 0xef, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00
};
static uint8_t xormask[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x77, 0x77, 0x76, 0x76,
0x76, 0x23, 0x23, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xb6, 0xb6, 0xb6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xee, 0xee, 0xee, 0xc0, 0xc0, 0xc0, 0xeb, 0xeb, 0xeb, 0x3b, 0x3b, 0x3b, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfd, 0xfd, 0xfd, 0x8d, 0x8d, 0x8d, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd5, 0xd5, 0xd5, 0x80, 0x80, 0x80, 0x14, 0x14,
0x14, 0xb6, 0xb6, 0xb6, 0x92, 0x92, 0x92, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xff, 0xff, 0xff, 0xe7, 0xe7, 0xe7, 0x8c, 0x8c, 0x8c, 0x00, 0x00, 0x00, 0x75, 0x75, 0x75,
0xee, 0xee, 0xee, 0x1a, 0x1a, 0x1a, 0x27, 0x27, 0x27, 0xf0, 0xf0, 0xf0, 0x55, 0x55, 0x55, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x26, 0x26, 0x26, 0xe5,
0xe5, 0xe5, 0x94, 0x94, 0x94, 0xc3, 0xc3, 0xc3, 0x83, 0x83, 0x83, 0x12, 0x12, 0x12, 0x87, 0x87,
0x87, 0xc8, 0xc8, 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0xe2, 0xe2, 0xe2, 0xef, 0xef, 0xef,
0x1b, 0x1b, 0x1b, 0x1e, 0x1e, 0x1e, 0xea, 0xea, 0xea, 0x63, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x1f, 0x1f, 0x1f, 0x6a, 0x6a, 0x6a, 0x10, 0x10, 0x10, 0x77, 0x77, 0x77, 0xcc, 0xcc,
0xcc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x09, 0x09,
0x19, 0x19, 0x19, 0xde, 0xde, 0xde, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xf5, 0xf5, 0xf5, 0x8d, 0x8d, 0x8d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x02, 0x02, 0x02, 0x0e, 0x0e, 0x0e, 0x1b, 0x1b, 0x1b, 0x27, 0x27, 0x27, 0x34, 0x34,
0x34, 0x40, 0x40, 0x40, 0x7c, 0x7c, 0x7c, 0xf1, 0xf1, 0xf1, 0x87, 0x87, 0x87, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x14, 0x14, 0x14,
0x20, 0x20, 0x20, 0x2d, 0x2d, 0x2d, 0x39, 0x39, 0x39, 0x77, 0x77, 0x77, 0xf1, 0xf1, 0xf1, 0x8b,
0x8b, 0x8b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x0c, 0x0c, 0x0c, 0x19, 0x19, 0x19, 0x26, 0x26, 0x26, 0x32, 0x32, 0x32, 0x6b, 0x6b,
0x6b, 0xf1, 0xf1, 0xf1, 0x98, 0x98, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x05, 0x05, 0x05, 0x12, 0x12, 0x12, 0x1e, 0x1e, 0x1e,
0x2b, 0x2b, 0x2b, 0x62, 0x62, 0x62, 0xf0, 0xf0, 0xf0, 0x98, 0x98, 0x98, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x0b,
0x0b, 0x0b, 0x17, 0x17, 0x17, 0x24, 0x24, 0x24, 0x56, 0x56, 0x56, 0xee, 0xee, 0xee, 0xa2, 0xa2,
0xa2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xff, 0xff, 0xff, 0x03, 0x03, 0x03, 0x10, 0x10, 0x10, 0x1c, 0x1c, 0x1c, 0x4a, 0x4a, 0x4a,
0xec, 0xec, 0xec, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x09, 0x09, 0x09, 0x15,
0x15, 0x15, 0x41, 0x41, 0x41, 0xea, 0xea, 0xea, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xff, 0xff, 0xff, 0x0e, 0x0e, 0x0e, 0x34, 0x34, 0x34, 0xe5, 0xe5, 0xe5, 0xb5, 0xb5, 0xb5,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x2c, 0x2c, 0x2c, 0xe3,
0xe3, 0xe3, 0xb3, 0xb3, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xff, 0xff, 0xff, 0xdf, 0xdf, 0xdf, 0xb9, 0xb9, 0xb9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xc7, 0xc7, 0xc7, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xee, 0xee, 0xee, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
const gdiPalette cursor_dump_00000005_palette = {
.format = 0,
.palette = { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000 }
};
const rdpPointer cursor_dump_00000005_pointer = { .size = 0,
.New = nullptr,
.Free = nullptr,
.Set = nullptr,
.SetNull = nullptr,
.SetDefault = nullptr,
.SetPosition = nullptr,
.paddingA = { 0 },
.xPos = 0,
.yPos = 0,
.width = 24,
.height = 24,
.xorBpp = 24,
.lengthAndMask = ARRAYSIZE(andmask),
.lengthXorMask = ARRAYSIZE(xormask),
.xorMaskData = xormask,
.andMaskData = andmask,
.paddingB = { 0 } };
const uint8_t cursor_dump_00000005_image_bgra32[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xee, 0xee, 0xee, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0xc7, 0xc7, 0xc7, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0xdf, 0xdf, 0xdf, 0xff, 0xb9, 0xb9, 0xb9, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0x2c, 0x2c, 0x2c, 0xff, 0xe3, 0xe3, 0xe3, 0xff, 0xb3, 0xb3, 0xb3, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0x0e, 0x0e, 0x0e, 0xff, 0x34, 0x34, 0x34, 0xff, 0xe5, 0xe5, 0xe5, 0xff, 0xb5, 0xb5, 0xb5, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0x09, 0x09, 0x09, 0xff, 0x15, 0x15, 0x15, 0xff, 0x41, 0x41, 0x41, 0xff, 0xea, 0xea, 0xea, 0xff,
0xaa, 0xaa, 0xaa, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0x03, 0x03, 0x03, 0xff, 0x10, 0x10, 0x10, 0xff, 0x1c, 0x1c, 0x1c, 0xff, 0x4a, 0x4a, 0x4a, 0xff,
0xec, 0xec, 0xec, 0xff, 0xaa, 0xaa, 0xaa, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0xff, 0x0b, 0x0b, 0x0b, 0xff, 0x17, 0x17, 0x17, 0xff, 0x24, 0x24, 0x24, 0xff,
0x56, 0x56, 0x56, 0xff, 0xee, 0xee, 0xee, 0xff, 0xa2, 0xa2, 0xa2, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0xff, 0x05, 0x05, 0x05, 0xff, 0x12, 0x12, 0x12, 0xff, 0x1e, 0x1e, 0x1e, 0xff,
0x2b, 0x2b, 0x2b, 0xff, 0x62, 0x62, 0x62, 0xff, 0xf0, 0xf0, 0xf0, 0xff, 0x98, 0x98, 0x98, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x0c, 0x0c, 0x0c, 0xff, 0x19, 0x19, 0x19, 0xff,
0x26, 0x26, 0x26, 0xff, 0x32, 0x32, 0x32, 0xff, 0x6b, 0x6b, 0x6b, 0xff, 0xf1, 0xf1, 0xf1, 0xff,
0x98, 0x98, 0x98, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x07, 0x07, 0x07, 0xff, 0x14, 0x14, 0x14, 0xff,
0x20, 0x20, 0x20, 0xff, 0x2d, 0x2d, 0x2d, 0xff, 0x39, 0x39, 0x39, 0xff, 0x77, 0x77, 0x77, 0xff,
0xf1, 0xf1, 0xf1, 0xff, 0x8b, 0x8b, 0x8b, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x02, 0x02, 0x02, 0xff, 0x0e, 0x0e, 0x0e, 0xff,
0x1b, 0x1b, 0x1b, 0xff, 0x27, 0x27, 0x27, 0xff, 0x34, 0x34, 0x34, 0xff, 0x40, 0x40, 0x40, 0xff,
0x7c, 0x7c, 0x7c, 0xff, 0xf1, 0xf1, 0xf1, 0xff, 0x87, 0x87, 0x87, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x09, 0x09, 0x09, 0xff,
0x19, 0x19, 0x19, 0xff, 0xde, 0xde, 0xde, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf5, 0xf5, 0xf5, 0xff, 0x8d, 0x8d, 0x8d, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x1f, 0x1f, 0x1f, 0xff, 0x6a, 0x6a, 0x6a, 0xff,
0x10, 0x10, 0x10, 0xff, 0x77, 0x77, 0x77, 0xff, 0xcc, 0xcc, 0xcc, 0xff, 0x00, 0x00, 0x00, 0xff,
0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0xff, 0x22, 0x22, 0x22, 0xff, 0xe2, 0xe2, 0xe2, 0xff, 0xef, 0xef, 0xef, 0xff,
0x1b, 0x1b, 0x1b, 0xff, 0x1e, 0x1e, 0x1e, 0xff, 0xea, 0xea, 0xea, 0xff, 0x63, 0x63, 0x63, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0x26, 0x26, 0x26, 0xff, 0xe5, 0xe5, 0xe5, 0xff, 0x94, 0x94, 0x94, 0xff, 0xc3, 0xc3, 0xc3, 0xff,
0x83, 0x83, 0x83, 0xff, 0x12, 0x12, 0x12, 0xff, 0x87, 0x87, 0x87, 0xff, 0xc8, 0xc8, 0xc8, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
0xe7, 0xe7, 0xe7, 0xff, 0x8c, 0x8c, 0x8c, 0xff, 0x00, 0x00, 0x00, 0xff, 0x75, 0x75, 0x75, 0xff,
0xee, 0xee, 0xee, 0xff, 0x1a, 0x1a, 0x1a, 0xff, 0x27, 0x27, 0x27, 0xff, 0xf0, 0xf0, 0xf0, 0xff,
0x55, 0x55, 0x55, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfd, 0xfd, 0xfd, 0xff,
0x8d, 0x8d, 0x8d, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xd5, 0xd5, 0xd5, 0xff, 0x80, 0x80, 0x80, 0xff, 0x14, 0x14, 0x14, 0xff, 0xb6, 0xb6, 0xb6, 0xff,
0x92, 0x92, 0x92, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb6, 0xb6, 0xb6, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xee, 0xee, 0xee, 0xff, 0xc0, 0xc0, 0xc0, 0xff, 0xeb, 0xeb, 0xeb, 0xff,
0x3b, 0x3b, 0x3b, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x77, 0x77, 0x77, 0xff, 0x76, 0x76, 0x76, 0xff, 0x23, 0x23, 0x23, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
@@ -0,0 +1,13 @@
/* FreeRDP cursor dump to use for unit tests
* this file was auto generated by dump_write_header
* do not modify manually
*/
#pragma once
#include <freerdp/codec/color.h>
#include <freerdp/graphics.h>
extern const gdiPalette cursor_dump_00000005_palette;
extern const rdpPointer cursor_dump_00000005_pointer;
extern const uint8_t cursor_dump_00000005_image_bgra32[];
Binary file not shown.

After

Width:  |  Height:  |  Size: 537 B

+130
View File
@@ -0,0 +1,130 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* helper utility, convert image to RAW RGBA32 header ready to be included
*
* Copyright 2025 Armin Novak <armin.novak@thincast.com>
* Copyright 2025 Thincast Technologies GmbH
*
* 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 <winpr/image.h>
#include <stdio.h>
static void usage(const char* name)
{
(void)printf("%s <source file> <destination file>\n\n", name);
(void)printf("\tRead any image format supported by WinPR::wImage\n");
(void)printf("\tand convert it to raw BGRA data.\n\n");
(void)printf("\toutput format is a C header with an array ready to be included\n");
}
static int dump_data_hex(FILE* fp, const uint8_t* data, size_t size)
{
if (size > 0)
{
const int rc = fprintf(fp, "0x%02" PRIx8, data[0]);
if (rc != 4)
return -1;
}
for (size_t x = 1; x < size; x++)
{
if (x % 16 == 0)
{
const int rc = fprintf(fp, ",\n");
if (rc != 2)
return -2;
}
else
{
const int rc = fprintf(fp, ",");
if (rc != 1)
return -2;
}
const int rc = fprintf(fp, "0x%02" PRIx8, data[x]);
if (rc != 4)
return -2;
}
return 0;
}
static int dump_data(const wImage* img, const char* file)
{
FILE* fp = fopen(file, "w");
if (!fp)
{
(void)fprintf(stderr, "Failed to open file '%s'\n", file);
return -1;
}
int rc = -2;
int count = fprintf(fp, "#pragma once\n");
if (count < 0)
goto fail;
count = fprintf(fp, "\n");
if (count < 0)
goto fail;
count = fprintf(fp, "#include <stdint.h>\n");
if (count < 0)
goto fail;
count = fprintf(fp, "\n");
if (count < 0)
goto fail;
count = fprintf(fp, "static const uint8_t img_data[] ={\n");
if (count < 0)
goto fail;
count = dump_data_hex(fp, img->data, 1ULL * img->height * img->scanline);
if (count < 0)
goto fail;
count = fprintf(fp, "};\n");
if (count < 0)
goto fail;
rc = 0;
fail:
fclose(fp);
return rc;
}
int main(int argc, char* argv[])
{
if (argc != 3)
{
usage(argv[0]);
return -1;
}
int rc = -1;
const char* src = argv[1];
const char* dst = argv[2];
wImage* img = winpr_image_new();
if (!img)
goto fail;
const int res = winpr_image_read(img, src);
if (res <= 0)
{
(void)fprintf(stderr, "Failed to read image file '%s'\n", src);
goto fail;
}
rc = dump_data(img, dst);
if (rc >= 0)
(void)printf("Converted '%s' to header '%s'\n", src, dst);
fail:
if (rc != 0)
usage(argv[0]);
winpr_image_free(img, TRUE);
return rc;
}
@@ -0,0 +1,122 @@
[
{
"name": "encoder_test_01",
"format": "PIXEL_FORMAT_BGRA32",
"width": 64,
"height": 64,
"step": 256,
"bpp": [
24,
16,
15
]
},
{
"name": "encoder_test_02",
"format": "PIXEL_FORMAT_BGRX32",
"width": 64,
"height": 64,
"step": 256,
"bpp": [
24,
16,
15
]
},
{
"name": "encoder_test_03",
"format": "PIXEL_FORMAT_RGBA32",
"width": 64,
"height": 64,
"step": 256,
"bpp": [
24,
16,
15
]
},
{
"name": "encoder_test_04",
"format": "PIXEL_FORMAT_RGBX32",
"width": 64,
"height": 64,
"step": 256,
"bpp": [
24,
16,
15
]
},
{
"name": "encoder_test_05",
"format": "PIXEL_FORMAT_ABGR32",
"width": 64,
"height": 64,
"step": 256,
"bpp": [
24,
16,
15
]
},
{
"name": "encoder_test_06",
"format": "PIXEL_FORMAT_XBGR32",
"width": 64,
"height": 64,
"step": 256,
"bpp": [
24,
16,
15
]
},
{
"name": "encoder_test_07",
"format": "PIXEL_FORMAT_ARGB32",
"width": 64,
"height": 64,
"step": 256,
"bpp": [
24,
16,
15
]
},
{
"name": "encoder_test_08",
"format": "PIXEL_FORMAT_XRGB32",
"width": 64,
"height": 64,
"step": 256,
"bpp": [
24,
16,
15
]
},
{
"name": "encoder_test_09",
"format": "PIXEL_FORMAT_RGB24",
"width": 64,
"height": 64,
"step": 256,
"bpp": [
24,
16,
15
]
},
{
"name": "encoder_test_10",
"format": "PIXEL_FORMAT_BGR24",
"width": 64,
"height": 64,
"step": 256,
"bpp": [
24,
16,
15
]
}
]

Some files were not shown because too many files have changed in this diff Show More