From e414a7d9ccaa1f1532cb5998a3b437687788a340 Mon Sep 17 00:00:00 2001 From: Vic Lee Date: Wed, 10 Aug 2011 15:13:39 +0800 Subject: [PATCH] libfreerdp-rfx: initial migration. --- CMakeLists.txt | 1 + cmake/ConfigOptions.cmake | 2 + config.h.in | 2 + cunit/CMakeLists.txt | 4 + cunit/test_freerdp.c | 5 + cunit/test_librfx.c | 416 +++++++++++++++ cunit/test_librfx.h | 34 ++ include/freerdp/rfx.h | 134 +++++ include/freerdp/utils/stream.h | 7 + libfreerdp-rfx/CMakeLists.txt | 46 ++ libfreerdp-rfx/librfx.c | 819 ++++++++++++++++++++++++++++++ libfreerdp-rfx/rfx_bitstream.c | 85 ++++ libfreerdp-rfx/rfx_bitstream.h | 42 ++ libfreerdp-rfx/rfx_constants.h | 59 +++ libfreerdp-rfx/rfx_decode.c | 152 ++++++ libfreerdp-rfx/rfx_decode.h | 32 ++ libfreerdp-rfx/rfx_differential.c | 47 ++ libfreerdp-rfx/rfx_differential.h | 28 + libfreerdp-rfx/rfx_dwt.c | 194 +++++++ libfreerdp-rfx/rfx_dwt.h | 28 + libfreerdp-rfx/rfx_encode.c | 187 +++++++ libfreerdp-rfx/rfx_encode.h | 32 ++ libfreerdp-rfx/rfx_pool.c | 112 ++++ libfreerdp-rfx/rfx_pool.h | 40 ++ libfreerdp-rfx/rfx_quantization.c | 76 +++ libfreerdp-rfx/rfx_quantization.h | 28 + libfreerdp-rfx/rfx_rlgr.c | 428 ++++++++++++++++ libfreerdp-rfx/rfx_rlgr.h | 28 + libfreerdp-rfx/rfx_types.h | 73 +++ 29 files changed, 3141 insertions(+) create mode 100644 cunit/test_librfx.c create mode 100644 cunit/test_librfx.h create mode 100644 include/freerdp/rfx.h create mode 100644 libfreerdp-rfx/CMakeLists.txt create mode 100644 libfreerdp-rfx/librfx.c create mode 100644 libfreerdp-rfx/rfx_bitstream.c create mode 100644 libfreerdp-rfx/rfx_bitstream.h create mode 100644 libfreerdp-rfx/rfx_constants.h create mode 100644 libfreerdp-rfx/rfx_decode.c create mode 100644 libfreerdp-rfx/rfx_decode.h create mode 100644 libfreerdp-rfx/rfx_differential.c create mode 100644 libfreerdp-rfx/rfx_differential.h create mode 100644 libfreerdp-rfx/rfx_dwt.c create mode 100644 libfreerdp-rfx/rfx_dwt.h create mode 100644 libfreerdp-rfx/rfx_encode.c create mode 100644 libfreerdp-rfx/rfx_encode.h create mode 100644 libfreerdp-rfx/rfx_pool.c create mode 100644 libfreerdp-rfx/rfx_pool.h create mode 100644 libfreerdp-rfx/rfx_quantization.c create mode 100644 libfreerdp-rfx/rfx_quantization.h create mode 100644 libfreerdp-rfx/rfx_rlgr.c create mode 100644 libfreerdp-rfx/rfx_rlgr.h create mode 100644 libfreerdp-rfx/rfx_types.h diff --git a/CMakeLists.txt b/CMakeLists.txt index bd34a14f4..f798bcd75 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -92,6 +92,7 @@ add_subdirectory(libfreerdp-gdi) add_subdirectory(libfreerdp-cache) add_subdirectory(libfreerdp-chanman) add_subdirectory(libfreerdp-core) +add_subdirectory(libfreerdp-rfx) add_subdirectory(channels) add_subdirectory(client) diff --git a/cmake/ConfigOptions.cmake b/cmake/ConfigOptions.cmake index 35ce59554..0b9fc1f71 100644 --- a/cmake/ConfigOptions.cmake +++ b/cmake/ConfigOptions.cmake @@ -8,3 +8,5 @@ option(WITH_DEBUG_NEGO "Print negotiation related debug messages." OFF) option(WITH_DEBUG_CERTIFICATE "Print certificate related debug messages." OFF) option(WITH_DEBUG_LICENSE "Print license debug messages." OFF) option(WITH_DEBUG_GDI "Print graphics debug messages." OFF) +option(WITH_DEBUG_RFX "Print RemoteFX debug messages." OFF) +option(WITH_PROFILER "Compile profiler." OFF) diff --git a/config.h.in b/config.h.in index 164a42a03..5a2915cfe 100644 --- a/config.h.in +++ b/config.h.in @@ -25,5 +25,7 @@ #cmakedefine WITH_DEBUG_LICENSE #cmakedefine WITH_DEBUG_GDI #cmakedefine WITH_DEBUG_ASSERT +#cmakedefine WITH_DEBUG_RFX +#cmakedefine WITH_PROFILER #endif diff --git a/cunit/CMakeLists.txt b/cunit/CMakeLists.txt index f82818026..4bc5369c2 100644 --- a/cunit/CMakeLists.txt +++ b/cunit/CMakeLists.txt @@ -23,6 +23,7 @@ include_directories(${CMAKE_SOURCE_DIR}) # for some internal tests include_directories(../libfreerdp-core) include_directories(../libfreerdp-gdi) include_directories(../libfreerdp-cache) +include_directories(../libfreerdp-rfx) add_executable(test_freerdp test_per.c @@ -55,6 +56,8 @@ add_executable(test_freerdp test_cliprdr.h test_drdynvc.c test_drdynvc.h + test_librfx.c + test_librfx.h test_freerdp.c test_freerdp.h) @@ -64,5 +67,6 @@ target_link_libraries(test_freerdp freerdp-core) target_link_libraries(test_freerdp freerdp-gdi) target_link_libraries(test_freerdp freerdp-utils) target_link_libraries(test_freerdp freerdp-chanman) +target_link_libraries(test_freerdp freerdp-rfx) add_test(CUnitTests ${EXECUTABLE_OUTPUT_PATH}/test_freerdp) diff --git a/cunit/test_freerdp.c b/cunit/test_freerdp.c index 85db80ffe..3a094f767 100644 --- a/cunit/test_freerdp.c +++ b/cunit/test_freerdp.c @@ -34,6 +34,7 @@ #include "test_chanman.h" #include "test_cliprdr.h" #include "test_drdynvc.h" +#include "test_librfx.h" #include "test_freerdp.h" void dump_data(unsigned char * p, int len, int width, char* name) @@ -174,6 +175,10 @@ int main(int argc, char* argv[]) { add_drdynvc_suite(); } + else if (strcmp("librfx", argv[*pindex]) == 0) + { + add_librfx_suite(); + } else if (strcmp("per", argv[*pindex]) == 0) { add_per_suite(); diff --git a/cunit/test_librfx.c b/cunit/test_librfx.c new file mode 100644 index 000000000..d485def85 --- /dev/null +++ b/cunit/test_librfx.c @@ -0,0 +1,416 @@ +/** + * FreeRDP: A Remote Desktop Protocol Client + * RemoteFX Codec Library Unit Tests + * + * 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. + */ + +/** + * The sample data comes from [MS-RDPRFX] 4.2.3, which is decoded into three + * vertical bands in red (21x64), green (23x64) and blue(20x64) color. + */ + +#include +#include +#include +#include +#include +#include +#include +#include "rfx_types.h" +#include "rfx_bitstream.h" +#include "rfx_rlgr.h" +#include "rfx_differential.h" +#include "rfx_quantization.h" +#include "rfx_dwt.h" +#include "rfx_decode.h" +#include "rfx_encode.h" + +#include "test_librfx.h" + +static const uint8 y_data[] = +{ + 0x19, 0x82, 0x1d, 0x10, 0x62, 0x9d, 0x28, 0x85, 0x2c, 0xa2, 0x14, 0xb2, 0x88, + 0x52, 0xca, 0x21, 0x4b, 0x28, 0x85, 0x2c, 0xa2, 0x14, 0xb2, 0x88, 0x52, 0xca, 0x21, 0x4b, 0x28, + 0x85, 0x2c, 0xa2, 0x14, 0xb2, 0x88, 0x52, 0xca, 0x21, 0x4b, 0x28, 0x85, 0x2c, 0xa2, 0x14, 0xb2, + 0x88, 0x52, 0xca, 0x21, 0x4b, 0x28, 0x85, 0x2c, 0xa2, 0x14, 0xb2, 0x88, 0x52, 0xca, 0x21, 0x4b, + 0x28, 0x85, 0x2c, 0xa2, 0x14, 0xb2, 0x88, 0x52, 0xca, 0x21, 0x4b, 0x28, 0x85, 0x2c, 0xa2, 0x14, + 0xb2, 0x88, 0x52, 0xca, 0x21, 0x4b, 0x28, 0x85, 0x2c, 0xa2, 0x14, 0xb0, 0x00, 0x20, 0xf4, 0x40, + 0x0c, 0xc1, 0x1e, 0x20, 0x26, 0x22, 0x20, 0x33, 0x23, 0xc4, 0x23, 0x88, 0x86, 0x50, 0xf1, 0x22, + 0x68, 0x4c, 0x91, 0x85, 0x10, 0x34, 0x4c, 0x84, 0x78, 0xa2, 0x0d, 0x13, 0x21, 0x1e, 0x29, 0x06, + 0x89, 0x90, 0x8f, 0x14, 0x83, 0x44, 0xf4, 0x23, 0xc5, 0x20, 0xd1, 0x3d, 0x08, 0xf1, 0x48, 0x34, + 0x4f, 0x42, 0x3c, 0x52, 0x0d, 0x13, 0xd0, 0x8f, 0x14, 0x83, 0x44, 0xf4, 0x23, 0xc5, 0x20, 0xd1, + 0x3d, 0x08, 0xf1, 0x48, 0x34, 0x4f, 0x42, 0x3c, 0x52, 0x0d, 0x13, 0xd0, 0x8f, 0x14, 0x83, 0x44, + 0xf4, 0x23, 0xc5, 0x20, 0x00, 0x08, 0x47, 0x70, 0x15, 0x02, 0xe0, 0x7f, 0xe4, 0x9d, 0xc2, 0x51, + 0x71, 0xf4, 0x99, 0xc9, 0x57, 0xff, 0x32, 0x87, 0x9d, 0x17, 0xd6, 0x50, 0x6e, 0x06, 0x2f, 0xac, + 0xa0, 0x9c, 0x0c, 0x5f, 0x59, 0x41, 0x38, 0x18, 0xbe, 0xb2, 0x82, 0x70, 0x31, 0x7d, 0x65, 0x00, + 0x00, 0x10, 0xff, 0x9c, 0x33, 0x41, 0xf1, 0xc4, 0xb0, 0x3c, 0xff, 0xa2, 0x15, 0xbd, 0x7b, 0xea, + 0x86, 0x9b, 0x5f, 0xfc, 0x78, 0x8c, 0xf5, 0xed, 0xa8, 0x68, 0xda, 0xfd, 0x3c, 0x45, 0x7a, 0xf4, + 0xd4, 0x34, 0x6d, 0x7e, 0x9e, 0x22, 0xbd, 0x7a, 0x6a, 0x1a, 0x36, 0xbf, 0x4f, 0x11, 0x5e, 0xbd, + 0x35, 0x0d, 0x1b, 0x5f, 0xa7, 0x88, 0xaf, 0x5e, 0x9a, 0x86, 0x8d, 0xaf, 0xd3, 0xc4, 0x57, 0xaf, + 0x4d, 0x43, 0x46, 0xd7, 0xe9, 0xe2, 0x20, 0x30, 0x00 +}; + +static const uint8 cb_data[] = +{ + 0x1b, 0x04, 0x7f, 0x04, 0x31, 0x5f, 0xc2, + 0x94, 0xaf, 0x05, 0x29, 0x5e, 0x0a, 0x52, 0xbc, 0x14, 0xa5, 0x78, 0x29, 0x25, 0x78, 0x29, 0x25, + 0x78, 0x29, 0x25, 0x68, 0x52, 0x4a, 0xf0, 0x52, 0x4a, 0xf0, 0x52, 0x4a, 0xd0, 0xa4, 0x95, 0xe0, + 0xa4, 0x95, 0xe0, 0xa4, 0x95, 0xa1, 0x49, 0x2b, 0xc1, 0x49, 0x2b, 0xc1, 0x49, 0x2b, 0x42, 0x92, + 0x57, 0x82, 0x92, 0x57, 0x82, 0x92, 0x56, 0x85, 0x24, 0xaf, 0x05, 0x24, 0xaf, 0x05, 0x24, 0xad, + 0x0a, 0x49, 0x5e, 0x0a, 0x49, 0x5e, 0x0a, 0x49, 0x5a, 0x14, 0x92, 0xbc, 0x14, 0x92, 0xbc, 0x14, + 0x92, 0xb4, 0x29, 0x25, 0x78, 0x29, 0x25, 0x78, 0x00, 0x02, 0x0f, 0x02, 0x00, 0xac, 0x13, 0xfc, + 0xc0, 0x0a, 0x20, 0x10, 0x2b, 0x27, 0xf9, 0x80, 0xb0, 0x08, 0xaa, 0x3d, 0x60, 0x8c, 0x0b, 0x24, + 0xff, 0x30, 0x80, 0xc0, 0xaa, 0x13, 0xfc, 0xc2, 0x03, 0x05, 0x90, 0x9f, 0xe6, 0x10, 0x18, 0x2c, + 0x84, 0xff, 0x30, 0x81, 0x82, 0xc8, 0x4f, 0xf3, 0x08, 0x18, 0x2c, 0x84, 0xff, 0x31, 0x03, 0x05, + 0x90, 0x9f, 0xff, 0xd8, 0x40, 0x60, 0x59, 0x09, 0xfe, 0x61, 0x01, 0x81, 0x64, 0x27, 0xf9, 0x84, + 0x06, 0x0b, 0x21, 0x3f, 0xcc, 0x20, 0x30, 0x59, 0x09, 0xfe, 0x61, 0x03, 0x05, 0x90, 0x9f, 0xe6, + 0x10, 0x30, 0x59, 0x09, 0xfe, 0x62, 0x00, 0x00, 0x42, 0x15, 0x00, 0x10, 0x15, 0x01, 0xfe, 0x20, + 0x84, 0xd5, 0x01, 0x0a, 0x8f, 0xf1, 0x40, 0x33, 0x78, 0x17, 0xf9, 0xc2, 0x03, 0x83, 0x01, 0x78, + 0xe1, 0x01, 0xc1, 0x00, 0xbc, 0x70, 0x80, 0xe0, 0x80, 0x5e, 0x38, 0x40, 0x70, 0x40, 0x2f, 0x1c, + 0x20, 0x38, 0x20, 0x17, 0x8e, 0x10, 0x00, 0x00, 0x87, 0xd5, 0x08, 0x70, 0xef, 0x81, 0xa2, 0xd8, + 0xff, 0xff, 0xff, 0xfb, 0xd1, 0x2d, 0x4e, 0xa6, 0xce, 0x20, 0xa4, 0xef, 0x05, 0x78, 0x35, 0x3a, + 0x9b, 0x38, 0x82, 0x93, 0xbc, 0x15, 0xe0, 0xd4, 0xea, 0x66, 0x71, 0x05, 0x27, 0x78, 0x2b, 0xc1, + 0x29, 0xd4, 0xcc, 0xe2, 0x0a, 0x4e, 0xf0, 0x57, 0x82, 0x53, 0xa9, 0x99, 0xc4, 0x14, 0x9d, 0xe0, + 0xaf, 0x04, 0xa7, 0x53, 0x33, 0x88, 0x29, 0x3b, 0xc1, 0x5e, 0x09, 0x4e, 0xa6, 0x67, 0x10, 0x52, + 0x77, 0x82, 0xbc, 0x00, 0x18, 0x00 +}; + +static const uint8 cr_data[] = +{ + 0x1b, 0xfc, 0x11, 0xc1, 0x0f, 0x4a, 0xc1, 0x4f, 0x4a, 0xc1, + 0x4f, 0x4a, 0xa1, 0x4d, 0x95, 0x42, 0x9e, 0x95, 0x42, 0x9e, 0x95, 0x42, 0x9b, 0x2a, 0x85, 0x3d, + 0x2a, 0x85, 0x3d, 0x2a, 0x85, 0x36, 0x55, 0x0a, 0x7a, 0x55, 0x0a, 0x7a, 0x55, 0x0a, 0x6c, 0xaa, + 0x14, 0xf4, 0xaa, 0x14, 0xf4, 0xaa, 0x14, 0xd9, 0x54, 0x29, 0xe9, 0x54, 0x29, 0xe9, 0x54, 0x29, + 0xb2, 0xa8, 0x53, 0xd2, 0xa8, 0x53, 0xd2, 0xa8, 0x53, 0x65, 0x50, 0xa7, 0xa5, 0x50, 0xa7, 0xa5, + 0x50, 0xa6, 0xca, 0xa1, 0x4f, 0x4a, 0xa1, 0x4f, 0x4a, 0xa1, 0x4d, 0x95, 0x42, 0x9e, 0x95, 0x42, + 0x9e, 0x95, 0x42, 0x9b, 0x2a, 0x80, 0x00, 0x41, 0xe3, 0x80, 0x3f, 0xe2, 0x09, 0x9c, 0x00, 0x22, + 0x07, 0x03, 0xe1, 0x26, 0x70, 0x06, 0x07, 0x1f, 0x04, 0x67, 0x00, 0x61, 0xdf, 0x02, 0x67, 0x00, + 0x0c, 0x3b, 0xfe, 0x01, 0x33, 0x80, 0x06, 0x1d, 0xff, 0x00, 0x99, 0xc0, 0x03, 0x0e, 0xff, 0x80, + 0x4c, 0xe0, 0x01, 0x87, 0x7f, 0xc0, 0x26, 0x70, 0x00, 0xc3, 0xbf, 0xe0, 0x13, 0x38, 0x00, 0x61, + 0xdf, 0xf0, 0x09, 0x9c, 0x00, 0x30, 0xef, 0xf8, 0x04, 0xce, 0x00, 0x18, 0x77, 0xfc, 0x02, 0x67, + 0x00, 0x0c, 0x3b, 0xfe, 0x01, 0x33, 0x80, 0x06, 0x1d, 0xff, 0x00, 0x99, 0xc0, 0x03, 0x0e, 0xff, + 0x80, 0x4c, 0xe0, 0x01, 0x87, 0x7f, 0xc0, 0x26, 0x70, 0x00, 0x00, 0x08, 0x3c, 0x20, 0x1f, 0xf1, + 0x00, 0xf0, 0x05, 0x02, 0x93, 0x84, 0x3d, 0x20, 0xf0, 0x52, 0x81, 0xc7, 0xff, 0xff, 0xea, 0x54, + 0x01, 0x80, 0x05, 0xf5, 0x4a, 0x80, 0x30, 0x00, 0xb6, 0xa5, 0x40, 0x18, 0x00, 0x5f, 0x54, 0xa8, + 0x03, 0x00, 0x0b, 0xea, 0x95, 0x00, 0x60, 0x01, 0x6d, 0x4a, 0x80, 0x30, 0x00, 0x00, 0x22, 0x3f, + 0xba, 0x08, 0x10, 0x2b, 0x1f, 0xf2, 0x20, 0x3e, 0x49, 0x9c, 0x1f, 0x6e, 0x0f, 0x5a, 0x0f, 0xfb, + 0x18, 0x46, 0xae, 0x27, 0x9b, 0x83, 0xcb, 0x41, 0xf3, 0x18, 0x46, 0xae, 0x27, 0x9b, 0x83, 0xc5, + 0xa0, 0xf9, 0x8c, 0x22, 0xd7, 0x13, 0x8d, 0xc1, 0xe2, 0xd0, 0x7c, 0xc6, 0x11, 0x6b, 0x89, 0xc6, + 0xe0, 0xf1, 0x68, 0x3e, 0x63, 0x08, 0xb5, 0xc4, 0xe3, 0x70, 0x78, 0xb4, 0x1f, 0x31, 0x84, 0x5a, + 0xe2, 0x71, 0xb8, 0x3c, 0x5a, 0x0f, 0x98, 0xc2, 0x2d, 0x71, 0x30, 0x83, 0xc0, 0x00 +}; + +/* HL1, LH1, HH1, HL2, LH2, HH2, HL3, LH3, HH3, LL3 */ +static const unsigned int test_quantization_values[] = +{ + 6, 6, 6, 6, 7, 7, 8, 8, 8, 9 +}; + +static const uint8 rgb_scanline_data[] = +{ + 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, + 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, + 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, + 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, + 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, + 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, + 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, + 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, + 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, + 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, + 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, + 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, + 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, + 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, + 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, + 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, + + 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, + 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, + 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, + 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, + 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, + 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, + 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, + 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, + 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, + 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, + 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, + 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, + 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, + 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, + 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, + 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xFF +}; + +static uint8* rgb_data; + +int init_librfx_suite(void) +{ + return 0; +} + +int clean_librfx_suite(void) +{ + return 0; +} + +int add_librfx_suite(void) +{ + add_test_suite(librfx); + + add_test_function(bitstream); + add_test_function(bitstream_enc); + add_test_function(rlgr); + add_test_function(differential); + add_test_function(quantization); + add_test_function(dwt); + add_test_function(decode); + add_test_function(encode); + add_test_function(message); + + return 0; +} + +void test_bitstream(void) +{ + uint16 b; + RFX_BITSTREAM* bs; + + bs = xnew(RFX_BITSTREAM); + rfx_bitstream_attach(bs, (uint8*) y_data, sizeof(y_data)); + while (!rfx_bitstream_eos(bs)) + { + b = rfx_bitstream_get_bits(bs, 3); + //printf("%u ", b); + } + xfree(bs); + + //printf("\n"); +} + +void test_bitstream_enc(void) +{ + uint8 buffer[10]; + RFX_BITSTREAM* bs; + int i; + + bs = xnew(RFX_BITSTREAM); + memset(buffer, 0, sizeof(buffer)); + rfx_bitstream_attach(bs, buffer, sizeof(buffer)); + for (i = 0; i < 16; i++) + { + rfx_bitstream_put_bits(bs, i, 5); + } + /*for (i = 0; i < sizeof(buffer); i++) + { + printf("%X ", buffer[i]); + }*/ + xfree(bs); + + //printf("\n"); +} + +static sint16 buffer[4096]; + +void dump_buffer(sint16* buf, int n) +{ + int i; + + for (i = 0; i < n; i++) + { + if (i % 16 == 0) + printf("\n%04d ", i); + printf("% 4d ", buf[i]); + } + printf("\n"); +} + +void test_rlgr(void) +{ + int n; + + n = rfx_rlgr_decode(RLGR3, y_data, sizeof(y_data), buffer, sizeof(buffer) / sizeof(unsigned int)); + + //printf("RLGR decode %d bytes to %d values.", sizeof(y_data), n); + //dump_buffer(buffer, n); +} + +void test_differential(void) +{ + rfx_differential_decode(buffer + 4032, 64); + //dump_buffer(buffer + 4032, 64); +} + +void test_quantization(void) +{ + rfx_quantization_decode(buffer, test_quantization_values); + //dump_buffer(buffer, 4096); +} + +void test_dwt(void) +{ + RFX_CONTEXT* context; + + context = rfx_context_new(); + rfx_dwt_2d_decode(buffer, context->priv->dwt_buffer); + //dump_buffer(buffer, 4096); + rfx_context_free(context); +} + +/* Dump a .ppm image. */ +static void dump_ppm_image(uint8* image_buf) +{ + static int frame_id = 0; + char buf[100]; + FILE* fp; + + snprintf(buf, sizeof(buf), "/tmp/FreeRDP_Frame_%d.ppm", frame_id); + fp = fopen(buf, "wb"); + fwrite("P6\n", 1, 3, fp); + fwrite("64 64\n", 1, 6, fp); + fwrite("255\n", 1, 4, fp); + fwrite(image_buf, 1, 4096 * 3, fp); + fflush(fp); + fclose(fp); + frame_id++; +} + +void test_decode(void) +{ + RFX_CONTEXT* context; + uint8 decode_buffer[4096 * 3]; + STREAM* s; + + s = stream_new(sizeof(y_data) + sizeof(cb_data) + sizeof(cr_data)); + stream_write(s, y_data, sizeof(y_data)); + stream_write(s, cb_data, sizeof(cb_data)); + stream_write(s, cr_data, sizeof(cr_data)); + stream_set_pos(s, 0); + + context = rfx_context_new(); + context->mode = RLGR3; + rfx_context_set_pixel_format(context, RFX_PIXEL_FORMAT_RGB); + rfx_decode_rgb(context, s, + sizeof(y_data), test_quantization_values, + sizeof(cb_data), test_quantization_values, + sizeof(cr_data), test_quantization_values, + decode_buffer); + rfx_context_free(context); + stream_free(s); + + dump_ppm_image(decode_buffer); +} + +void test_encode(void) +{ + RFX_CONTEXT* context; + STREAM* enc_stream; + int y_size, cb_size, cr_size; + int i; + uint8 decode_buffer[4096 * 3]; + + rgb_data = (uint8 *) malloc(64 * 64 * 3); + for (i = 0; i < 64; i++) + memcpy(rgb_data + i * 64 * 3, rgb_scanline_data, 64 * 3); + //freerdp_hexdump(rgb_data, 64 * 64 * 3); + + enc_stream = stream_new(65536); + stream_clear(enc_stream); + + context = rfx_context_new(); + context->mode = RLGR3; + rfx_context_set_pixel_format(context, RFX_PIXEL_FORMAT_RGB); + + rfx_encode_rgb(context, rgb_data, 64, 64, 64 * 3, + test_quantization_values, test_quantization_values, test_quantization_values, + enc_stream, &y_size, &cb_size, &cr_size); + //dump_buffer(context->priv->cb_g_buffer, 4096); + + /*printf("*** Y ***\n"); + freerdp_hexdump(stream_get_head(enc_stream), y_size); + printf("*** Cb ***\n"); + freerdp_hexdump(stream_get_head(enc_stream) + y_size, cb_size); + printf("*** Cr ***\n"); + freerdp_hexdump(stream_get_head(enc_stream) + y_size + cb_size, cr_size);*/ + + stream_set_pos(enc_stream, 0); + rfx_decode_rgb(context, enc_stream, + y_size, test_quantization_values, + cb_size, test_quantization_values, + cr_size, test_quantization_values, + decode_buffer); + dump_ppm_image(decode_buffer); + + rfx_context_free(context); + stream_free(enc_stream); + free(rgb_data); +} + +void test_message(void) +{ + RFX_CONTEXT* context; + STREAM* s; + int size; + int i, j; + RFX_RECT rect = {0, 0, 100, 80}; + RFX_MESSAGE * message; + + rgb_data = (uint8 *) malloc(100 * 80 * 3); + for (i = 0; i < 80; i++) + memcpy(rgb_data + i * 100 * 3, rgb_scanline_data, 100 * 3); + + s = stream_new(65536); + stream_clear(s); + + context = rfx_context_new(); + context->mode = RLGR3; + context->width = 800; + context->height = 600; + rfx_context_set_pixel_format(context, RFX_PIXEL_FORMAT_RGB); + + rfx_compose_message_header(context, s); + /*hexdump(buffer, size);*/ + stream_seal(s); + stream_set_pos(s, 0); + message = rfx_process_message(context, s); + rfx_message_free(context, message); + stream_free(s); + + for (i = 0; i < 1; i++) + { + s = stream_new(65536); + stream_clear(s); + rfx_compose_message_data(context, s, + &rect, 1, rgb_data, 100, 80, 100 * 3); + stream_seal(s); + /*hexdump(buffer, size);*/ + stream_set_pos(s, 0); + message = rfx_process_message(context, s); + if (i == 0) + { + for (j = 0; j < message->num_tiles; j++) + { + dump_ppm_image(message->tiles[j]->data); + } + } + rfx_message_free(context, message); + stream_free(s); + } + + rfx_context_free(context); + free(rgb_data); +} diff --git a/cunit/test_librfx.h b/cunit/test_librfx.h new file mode 100644 index 000000000..f007816b0 --- /dev/null +++ b/cunit/test_librfx.h @@ -0,0 +1,34 @@ +/** + * FreeRDP: A Remote Desktop Protocol Client + * RemoteFX Codec Library Unit Tests + * + * 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 "test_freerdp.h" + +int init_librfx_suite(void); +int clean_librfx_suite(void); +int add_librfx_suite(void); + +void test_bitstream(void); +void test_bitstream_enc(void); +void test_rlgr(void); +void test_differential(void); +void test_quantization(void); +void test_dwt(void); +void test_decode(void); +void test_encode(void); +void test_message(void); diff --git a/include/freerdp/rfx.h b/include/freerdp/rfx.h new file mode 100644 index 000000000..d69a477a9 --- /dev/null +++ b/include/freerdp/rfx.h @@ -0,0 +1,134 @@ +/** + * FreeRDP: A Remote Desktop Protocol client. + * 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 __RFX_H +#define __RFX_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +enum _RLGR_MODE +{ + RLGR1, + RLGR3 +}; +typedef enum _RLGR_MODE RLGR_MODE; + +enum _RFX_PIXEL_FORMAT +{ + RFX_PIXEL_FORMAT_BGRA, + RFX_PIXEL_FORMAT_RGBA, + RFX_PIXEL_FORMAT_BGR, + RFX_PIXEL_FORMAT_RGB +}; +typedef enum _RFX_PIXEL_FORMAT RFX_PIXEL_FORMAT; + +struct _RFX_RECT +{ + uint16 x; + uint16 y; + uint16 width; + uint16 height; +}; +typedef struct _RFX_RECT RFX_RECT; + +struct _RFX_TILE +{ + uint16 x; + uint16 y; + uint8* data; +}; +typedef struct _RFX_TILE RFX_TILE; + +struct _RFX_MESSAGE +{ + /** + * 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 num_rects; + 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 num_tiles; + RFX_TILE** tiles; +}; +typedef struct _RFX_MESSAGE RFX_MESSAGE; + +typedef struct _RFX_CONTEXT_PRIV RFX_CONTEXT_PRIV; + +struct _RFX_CONTEXT +{ + uint16 flags; + uint16 properties; + uint16 width; + uint16 height; + RLGR_MODE mode; + uint32 version; + uint32 codec_id; + uint32 codec_version; + RFX_PIXEL_FORMAT pixel_format; + uint8 bytes_per_pixel; + + /* temporary data within a frame */ + uint32 frame_idx; + uint8 num_quants; + uint32* quants; + uint8 quant_idx_y; + uint8 quant_idx_cb; + uint8 quant_idx_cr; + + /* routines */ + void (*decode_ycbcr_to_rgb)(sint16* y_r_buf, sint16* cb_g_buf, sint16* cr_b_buf); + void (*encode_rgb_to_ycbcr)(sint16* y_r_buf, sint16* cb_g_buf, sint16* cr_b_buf); + void (*quantization_decode)(sint16* buffer, const uint32* quantization_values); + void (*quantization_encode)(sint16* buffer, const uint32* quantization_values); + void (*dwt_2d_decode)(sint16* buffer, sint16* dwt_buffer); + void (*dwt_2d_encode)(sint16* buffer, sint16* dwt_buffer); + + /* private definitions */ + RFX_CONTEXT_PRIV* priv; +}; +typedef struct _RFX_CONTEXT RFX_CONTEXT; + +RFX_CONTEXT* rfx_context_new(void); +void rfx_context_free(RFX_CONTEXT* context); +void rfx_context_set_pixel_format(RFX_CONTEXT* context, RFX_PIXEL_FORMAT pixel_format); + +RFX_MESSAGE* rfx_process_message(RFX_CONTEXT* context, STREAM* data_in); +void rfx_message_free(RFX_CONTEXT* context, RFX_MESSAGE* message); + +void rfx_compose_message_header(RFX_CONTEXT* context, STREAM* data_out); +void rfx_compose_message_data(RFX_CONTEXT* context, STREAM* data_out, + const RFX_RECT* rects, int num_rects, uint8* image_data, int width, int height, int rowstride); + +#ifdef __cplusplus +} +#endif + +#endif /* __RFX_H */ diff --git a/include/freerdp/utils/stream.h b/include/freerdp/utils/stream.h index 1e9e38b62..4c7d0a1ea 100644 --- a/include/freerdp/utils/stream.h +++ b/include/freerdp/utils/stream.h @@ -35,6 +35,13 @@ typedef struct _STREAM STREAM; STREAM* stream_new(int size); void stream_free(STREAM* stream); +#define stream_attach(_s, _buf, _size) do { \ + _s->size = _size; \ + _s->data = _buf; \ + _s->p = _buf; } while (0) +#define stream_detach(_s) memset(_s, 0, sizeof(STREAM)) +#define stream_clear(_s) memset(_s->data, 0, _s->size) + void stream_extend(STREAM* stream); #define stream_check_size(_s,_n) \ while (_s->p - _s->data + (_n) > _s->size) \ diff --git a/libfreerdp-rfx/CMakeLists.txt b/libfreerdp-rfx/CMakeLists.txt new file mode 100644 index 000000000..7b489ac59 --- /dev/null +++ b/libfreerdp-rfx/CMakeLists.txt @@ -0,0 +1,46 @@ +# FreeRDP: A Remote Desktop Protocol Client +# libfreerdp-core cmake build script +# +# Copyright 2011 O.S. Systems Software Ltda. +# Copyright 2011 Otavio Salvador +# Copyright 2011 Marc-Andre Moreau +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set(LIBFREERDP_RFX_SRCS + rfx_bitstream.c + rfx_bitstream.h + rfx_constants.h + rfx_decode.c + rfx_decode.h + rfx_differential.c + rfx_differential.h + rfx_dwt.c + rfx_dwt.h + rfx_encode.c + rfx_encode.h + rfx_pool.c + rfx_pool.h + rfx_quantization.c + rfx_quantization.h + rfx_rlgr.c + rfx_rlgr.h + rfx_types.h + librfx.c +) + +add_library(freerdp-rfx SHARED ${LIBFREERDP_RFX_SRCS}) + +target_link_libraries(freerdp-rfx freerdp-utils) + +install(TARGETS freerdp-rfx DESTINATION lib) diff --git a/libfreerdp-rfx/librfx.c b/libfreerdp-rfx/librfx.c new file mode 100644 index 000000000..304f2a9aa --- /dev/null +++ b/libfreerdp-rfx/librfx.c @@ -0,0 +1,819 @@ +/** + * FreeRDP: A Remote Desktop Protocol client. + * 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. + */ + +#include +#include +#include +#include +#include +#include + +#include "rfx_constants.h" +#include "rfx_types.h" +#include "rfx_pool.h" +#include "rfx_decode.h" +#include "rfx_encode.h" +#include "rfx_quantization.h" +#include "rfx_dwt.h" + +#ifdef WITH_SSE +#include "rfx_sse.h" +#endif + +#ifdef WITH_NEON +#include "rfx_neon.h" +#endif + +#ifndef RFX_INIT_SIMD +#define RFX_INIT_SIMD(_rfx_context) do { } while (0) +#endif + +/** + * The quantization values control the compression rate and quality. The value + * range is between 6 and 15. The higher value, the higher compression rate + * and lower quality. + * + * This is the default values being use by the MS RDP server, and we will also + * use it as our default values for the encoder. It can be overrided by setting + * the context->num_quants and context->quants member. + * + * The order of the values are: + * LL3, LH3, HL3, HH3, LH2, HL2, HH2, LH1, HL1, HH1 + */ +static const uint32 rfx_default_quantization_values[] = +{ + 6, 6, 6, 6, 7, 7, 8, 8, 8, 9 +}; + +static void rfx_profiler_create(RFX_CONTEXT* context) +{ + PROFILER_CREATE(context->priv->prof_rfx_decode_rgb, "rfx_decode_rgb"); + PROFILER_CREATE(context->priv->prof_rfx_decode_component, "rfx_decode_component"); + PROFILER_CREATE(context->priv->prof_rfx_rlgr_decode, "rfx_rlgr_decode"); + PROFILER_CREATE(context->priv->prof_rfx_differential_decode, "rfx_differential_decode"); + PROFILER_CREATE(context->priv->prof_rfx_quantization_decode, "rfx_quantization_decode"); + PROFILER_CREATE(context->priv->prof_rfx_dwt_2d_decode, "rfx_dwt_2d_decode"); + PROFILER_CREATE(context->priv->prof_rfx_decode_ycbcr_to_rgb, "rfx_decode_ycbcr_to_rgb"); + PROFILER_CREATE(context->priv->prof_rfx_decode_format_rgb, "rfx_decode_format_rgb"); + + PROFILER_CREATE(context->priv->prof_rfx_encode_rgb, "rfx_encode_rgb"); + PROFILER_CREATE(context->priv->prof_rfx_encode_component, "rfx_encode_component"); + PROFILER_CREATE(context->priv->prof_rfx_rlgr_encode, "rfx_rlgr_encode"); + PROFILER_CREATE(context->priv->prof_rfx_differential_encode, "rfx_differential_encode"); + PROFILER_CREATE(context->priv->prof_rfx_quantization_encode, "rfx_quantization_encode"); + PROFILER_CREATE(context->priv->prof_rfx_dwt_2d_encode, "rfx_dwt_2d_encode"); + PROFILER_CREATE(context->priv->prof_rfx_encode_rgb_to_ycbcr, "rfx_encode_rgb_to_ycbcr"); + PROFILER_CREATE(context->priv->prof_rfx_encode_format_rgb, "rfx_encode_format_rgb"); +} + +static void rfx_profiler_free(RFX_CONTEXT* context) +{ + PROFILER_FREE(context->priv->prof_rfx_decode_rgb); + PROFILER_FREE(context->priv->prof_rfx_decode_component); + PROFILER_FREE(context->priv->prof_rfx_rlgr_decode); + PROFILER_FREE(context->priv->prof_rfx_differential_decode); + PROFILER_FREE(context->priv->prof_rfx_quantization_decode); + PROFILER_FREE(context->priv->prof_rfx_dwt_2d_decode); + PROFILER_FREE(context->priv->prof_rfx_decode_ycbcr_to_rgb); + PROFILER_FREE(context->priv->prof_rfx_decode_format_rgb); + + PROFILER_FREE(context->priv->prof_rfx_encode_rgb); + PROFILER_FREE(context->priv->prof_rfx_encode_component); + PROFILER_FREE(context->priv->prof_rfx_rlgr_encode); + PROFILER_FREE(context->priv->prof_rfx_differential_encode); + PROFILER_FREE(context->priv->prof_rfx_quantization_encode); + PROFILER_FREE(context->priv->prof_rfx_dwt_2d_encode); + PROFILER_FREE(context->priv->prof_rfx_encode_rgb_to_ycbcr); + PROFILER_FREE(context->priv->prof_rfx_encode_format_rgb); +} + +static void rfx_profiler_print(RFX_CONTEXT* context) +{ + PROFILER_PRINT_HEADER; + + PROFILER_PRINT(context->priv->prof_rfx_decode_rgb); + PROFILER_PRINT(context->priv->prof_rfx_decode_component); + PROFILER_PRINT(context->priv->prof_rfx_rlgr_decode); + PROFILER_PRINT(context->priv->prof_rfx_differential_decode); + PROFILER_PRINT(context->priv->prof_rfx_quantization_decode); + PROFILER_PRINT(context->priv->prof_rfx_dwt_2d_decode); + PROFILER_PRINT(context->priv->prof_rfx_decode_ycbcr_to_rgb); + PROFILER_PRINT(context->priv->prof_rfx_decode_format_rgb); + + PROFILER_PRINT(context->priv->prof_rfx_encode_rgb); + PROFILER_PRINT(context->priv->prof_rfx_encode_component); + PROFILER_PRINT(context->priv->prof_rfx_rlgr_encode); + PROFILER_PRINT(context->priv->prof_rfx_differential_encode); + PROFILER_PRINT(context->priv->prof_rfx_quantization_encode); + PROFILER_PRINT(context->priv->prof_rfx_dwt_2d_encode); + PROFILER_PRINT(context->priv->prof_rfx_encode_rgb_to_ycbcr); + PROFILER_PRINT(context->priv->prof_rfx_encode_format_rgb); + + PROFILER_PRINT_FOOTER; +} + +RFX_CONTEXT* rfx_context_new(void) +{ + RFX_CONTEXT* context; + + context = xnew(RFX_CONTEXT); + context->priv = xnew(RFX_CONTEXT_PRIV); + context->priv->pool = rfx_pool_new(); + + /* initialize the default pixel format */ + rfx_context_set_pixel_format(context, RFX_PIXEL_FORMAT_BGRA); + + /* align buffers to 16 byte boundary (needed for SSE/SSE2 instructions) */ + context->priv->y_r_buffer = (sint16*)(((uintptr_t)context->priv->y_r_mem + 16) & ~ 0x0F); + context->priv->cb_g_buffer = (sint16*)(((uintptr_t)context->priv->cb_g_mem + 16) & ~ 0x0F); + context->priv->cr_b_buffer = (sint16*)(((uintptr_t)context->priv->cr_b_mem + 16) & ~ 0x0F); + + context->priv->dwt_buffer = (sint16*)(((uintptr_t)context->priv->dwt_mem + 16) & ~ 0x0F); + + /* create profilers for default decoding routines */ + rfx_profiler_create(context); + + /* set up default routines */ + context->decode_ycbcr_to_rgb = rfx_decode_ycbcr_to_rgb; + context->encode_rgb_to_ycbcr = rfx_encode_rgb_to_ycbcr; + context->quantization_decode = rfx_quantization_decode; + context->quantization_encode = rfx_quantization_encode; + context->dwt_2d_decode = rfx_dwt_2d_decode; + context->dwt_2d_encode = rfx_dwt_2d_encode; + + /* detect and enable SIMD CPU acceleration */ + RFX_INIT_SIMD(context); + + return context; +} + +void rfx_context_free(RFX_CONTEXT* context) +{ + xfree(context->quants); + + rfx_pool_free(context->priv->pool); + + rfx_profiler_print(context); + rfx_profiler_free(context); + + xfree(context->priv); + xfree(context); +} + +void rfx_context_set_pixel_format(RFX_CONTEXT* context, RFX_PIXEL_FORMAT pixel_format) +{ + context->pixel_format = pixel_format; + switch (pixel_format) + { + case RFX_PIXEL_FORMAT_BGRA: + case RFX_PIXEL_FORMAT_RGBA: + context->bytes_per_pixel = 4; + break; + case RFX_PIXEL_FORMAT_BGR: + case RFX_PIXEL_FORMAT_RGB: + context->bytes_per_pixel = 3; + break; + default: + context->bytes_per_pixel = 0; + break; + } +} + +static void rfx_process_message_sync(RFX_CONTEXT* context, STREAM* data_in) +{ + uint32 magic; + + /* RFX_SYNC */ + stream_read_uint32(data_in, magic); /* magic (4 bytes), 0xCACCACCA */ + + if (magic != WF_MAGIC) + { + DEBUG_WARN("invalid magic number 0x%X", magic); + return; + } + + stream_read_uint16(data_in, context->version); /* version (2 bytes), WF_VERSION_1_0 (0x0100) */ + + if (context->version != WF_VERSION_1_0) + { + DEBUG_WARN("unknown version number 0x%X", context->version); + return; + } + + DEBUG_RFX("version 0x%X", context->version); +} + +static void rfx_process_message_codec_versions(RFX_CONTEXT* context, STREAM* data_in) +{ + uint8 numCodecs; + + stream_read_uint8(data_in, numCodecs); /* numCodecs (1 byte), must be set to 0x01 */ + + if (numCodecs != 1) + { + DEBUG_WARN("numCodecs: %d, expected:1", numCodecs); + return; + } + + /* RFX_CODEC_VERSIONT */ + stream_read_uint8(data_in, context->codec_id); /* codecId (1 byte) */ + stream_read_uint8(data_in, context->codec_version); /* version (2 bytes) */ + + DEBUG_RFX("id %d version 0x%X.", context->codec_id, context->codec_version); +} + +static void rfx_process_message_channels(RFX_CONTEXT* context, STREAM* data_in) +{ + uint8 channelId; + uint8 numChannels; + + stream_read_uint8(data_in, numChannels); /* numChannels (1 byte), must bet set to 0x01 */ + + if (numChannels != 1) + { + DEBUG_WARN("numChannels:%d, expected:1", numChannels); + return; + } + + /* RFX_CHANNELT */ + stream_read_uint8(data_in, channelId); /* channelId (1 byte) */ + stream_read_uint16(data_in, context->width); /* width (2 bytes) */ + stream_read_uint16(data_in, context->height); /* height (2 bytes) */ + + DEBUG_RFX("numChannels %d id %d, %dx%d.", + numChannels, channelId, context->width, context->height); +} + +static void rfx_process_message_context(RFX_CONTEXT* context, STREAM* data_in) +{ + uint8 ctxId; + uint16 tileSize; + uint16 properties; + + stream_read_uint8(data_in, ctxId); /* ctxId (1 byte), must be set to 0x00 */ + stream_read_uint16(data_in, tileSize); /* tileSize (2 bytes), must be set to CT_TILE_64x64 (0x0040) */ + stream_read_uint16(data_in, properties); /* properties (2 bytes) */ + + DEBUG_RFX("ctxId %d tileSize %d properties 0x%X.", ctxId, tileSize, properties); + + context->properties = properties; + context->flags = (properties & 0x0007); + + if (context->flags == CODEC_MODE) + DEBUG_RFX("codec is in image mode."); + else + DEBUG_RFX("codec is in video mode."); + + switch ((properties & 0x1E00) >> 9) + { + case CLW_ENTROPY_RLGR1: + context->mode = RLGR1; + DEBUG_RFX("RLGR1."); + break; + + case CLW_ENTROPY_RLGR3: + context->mode = RLGR3; + DEBUG_RFX("RLGR3."); + break; + + default: + DEBUG_WARN("unknown RLGR algorithm."); + break; + } +} + +static void rfx_process_message_frame_begin(RFX_CONTEXT* context, RFX_MESSAGE* message, STREAM* data_in) +{ + uint32 frameIdx; + uint16 numRegions; + + stream_read_uint32(data_in, frameIdx); /* frameIdx (4 bytes), if codec is in video mode, must be ignored */ + stream_read_uint16(data_in, numRegions); /* numRegions (2 bytes) */ + + DEBUG_RFX("RFX_FRAME_BEGIN: frameIdx:%d numRegions:%d", frameIdx, numRegions); +} + +static void rfx_process_message_frame_end(RFX_CONTEXT* context, RFX_MESSAGE* message, STREAM* data_in) +{ + DEBUG_RFX("RFX_FRAME_END"); +} + +static void rfx_process_message_region(RFX_CONTEXT* context, RFX_MESSAGE* message, STREAM* data_in) +{ + int i; + + stream_seek_uint8(data_in); /* regionFlags (1 byte) */ + stream_read_uint16(data_in, message->num_rects); /* numRects (2 bytes) */ + + if (message->num_rects < 1) + { + DEBUG_WARN("no rects."); + return; + } + + if (message->rects != NULL) + message->rects = (RFX_RECT*) xrealloc(message->rects, message->num_rects * sizeof(RFX_RECT)); + else + message->rects = (RFX_RECT*) xmalloc(message->num_rects * sizeof(RFX_RECT)); + + /* rects */ + for (i = 0; i < message->num_rects; i++) + { + /* RFX_RECT */ + stream_read_uint16(data_in, message->rects[i].x); /* x (2 bytes) */ + stream_read_uint16(data_in, message->rects[i].y); /* y (2 bytes) */ + stream_read_uint16(data_in, message->rects[i].width); /* width (2 bytes) */ + stream_read_uint16(data_in, message->rects[i].height); /* height (2 bytes) */ + + DEBUG_RFX("rect %d (%d %d %d %d).", + i, message->rects[i].x, message->rects[i].y, message->rects[i].width, message->rects[i].height); + } +} + +static void rfx_process_message_tile(RFX_CONTEXT* context, RFX_TILE* tile, STREAM* data_in) +{ + uint8 quantIdxY; + uint8 quantIdxCb; + uint8 quantIdxCr; + uint16 xIdx, yIdx; + uint16 YLen, CbLen, CrLen; + + /* RFX_TILE */ + stream_read_uint8(data_in, quantIdxY); /* quantIdxY (1 byte) */ + stream_read_uint8(data_in, quantIdxCb); /* quantIdxCb (1 byte) */ + stream_read_uint8(data_in, quantIdxCr); /* quantIdxCr (1 byte) */ + stream_read_uint16(data_in, xIdx); /* xIdx (2 bytes) */ + stream_read_uint16(data_in, yIdx); /* yIdx (2 bytes) */ + stream_read_uint16(data_in, YLen); /* YLen (2 bytes) */ + stream_read_uint16(data_in, CbLen); /* CbLen (2 bytes) */ + stream_read_uint16(data_in, CrLen); /* CrLen (2 bytes) */ + + DEBUG_RFX("quantIdxY:%d quantIdxCb:%d quantIdxCr:%d xIdx:%d yIdx:%d YLen:%d CbLen:%d CrLen:%d", + quantIdxY, quantIdxCb, quantIdxCr, xIdx, yIdx, YLen, CbLen, CrLen); + + tile->x = xIdx * 64; + tile->y = yIdx * 64; + + rfx_decode_rgb(context, data_in, + YLen, context->quants + (quantIdxY * 10), + CbLen, context->quants + (quantIdxCb * 10), + CrLen, context->quants + (quantIdxCr * 10), + tile->data); +} + +static void rfx_process_message_tileset(RFX_CONTEXT* context, RFX_MESSAGE* message, STREAM* data_in) +{ + int i; + uint16 subtype; + uint32 blockLen; + uint32 blockType; + uint32 tilesDataSize; + uint32* quants; + uint8 quant; + int pos; + + stream_read_uint16(data_in, subtype); /* subtype (2 bytes) must be set to CBT_TILESET (0xCAC2) */ + + if (subtype != CBT_TILESET) + { + DEBUG_WARN("invalid subtype, expected CBT_TILESET."); + return; + } + + stream_seek_uint16(data_in); /* idx (2 bytes), must be set to 0x0000 */ + stream_seek_uint16(data_in); /* properties (2 bytes) */ + + stream_read_uint8(data_in, context->num_quants); /* numQuant (1 byte) */ + stream_seek_uint8(data_in); /* tileSize (1 byte), must be set to 0x40 */ + + if (context->num_quants < 1) + { + DEBUG_WARN("no quantization value."); + return; + } + + stream_read_uint16(data_in, message->num_tiles); /* numTiles (2 bytes) */ + + if (message->num_tiles < 1) + { + DEBUG_WARN("no tiles."); + return; + } + + stream_read_uint32(data_in, tilesDataSize); /* tilesDataSize (4 bytes) */ + + if (context->quants != NULL) + context->quants = (uint32*) xrealloc((void*) context->quants, context->num_quants * 10 * sizeof(uint32)); + else + context->quants = (uint32*) xmalloc(context->num_quants * 10 * sizeof(uint32)); + quants = context->quants; + + /* quantVals */ + for (i = 0; i < context->num_quants; i++) + { + /* RFX_CODEC_QUANT */ + stream_read_uint8(data_in, quant); + *quants++ = (quant & 0x0F); + *quants++ = (quant >> 4); + stream_read_uint8(data_in, quant); + *quants++ = (quant & 0x0F); + *quants++ = (quant >> 4); + stream_read_uint8(data_in, quant); + *quants++ = (quant & 0x0F); + *quants++ = (quant >> 4); + stream_read_uint8(data_in, quant); + *quants++ = (quant & 0x0F); + *quants++ = (quant >> 4); + stream_read_uint8(data_in, quant); + *quants++ = (quant & 0x0F); + *quants++ = (quant >> 4); + + DEBUG_RFX("quant %d (%d %d %d %d %d %d %d %d %d %d).", + i, context->quants[i * 10], context->quants[i * 10 + 1], + context->quants[i * 10 + 2], context->quants[i * 10 + 3], + context->quants[i * 10 + 4], context->quants[i * 10 + 5], + context->quants[i * 10 + 6], context->quants[i * 10 + 7], + context->quants[i * 10 + 8], context->quants[i * 10 + 9]); + } + + message->tiles = rfx_pool_get_tiles(context->priv->pool, message->num_tiles); + + /* tiles */ + for (i = 0; i < message->num_tiles; i++) + { + /* RFX_TILE */ + stream_read_uint16(data_in, blockType); /* blockType (2 bytes), must be set to CBT_TILE (0xCAC3) */ + stream_read_uint32(data_in, blockLen); /* blockLen (4 bytes) */ + + pos = stream_get_pos(data_in) - 6 + blockLen; + + if (blockType != CBT_TILE) + { + DEBUG_WARN("unknown block type 0x%X, expected CBT_TILE (0xCAC3).", blockType); + break; + } + + rfx_process_message_tile(context, message->tiles[i], data_in); + + stream_set_pos(data_in, pos); + } +} + +RFX_MESSAGE* rfx_process_message(RFX_CONTEXT* context, STREAM* data_in) +{ + uint32 offset; + uint32 blockLen; + uint32 blockType; + RFX_MESSAGE* message; + int pos; + + message = xnew(RFX_MESSAGE); + + while (stream_get_left(data_in) > 6) + { + /* RFX_BLOCKT */ + stream_read_uint16(data_in, blockType); /* blockType (2 bytes) */ + stream_read_uint32(data_in, blockLen); /* blockLen (4 bytes) */ + + DEBUG_RFX("blockType 0x%X blockLen %d", blockType, blockLen); + + if (blockLen == 0) + { + DEBUG_WARN("zero blockLen"); + break; + } + + pos = stream_get_pos(data_in) - 6 + blockLen; + + if (blockType >= WBT_CONTEXT && blockType <= WBT_EXTENSION) + { + /* RFX_CODEC_CHANNELT */ + /* codecId (1 byte) must be set to 0x01 */ + /* channelId (1 byte) must be set to 0x00 */ + stream_seek(data_in, 2); + } + + switch (blockType) + { + case WBT_SYNC: + rfx_process_message_sync(context, data_in); + break; + + case WBT_CODEC_VERSIONS: + rfx_process_message_codec_versions(context, data_in); + break; + + case WBT_CHANNELS: + rfx_process_message_channels(context, data_in); + break; + + case WBT_CONTEXT: + rfx_process_message_context(context, data_in); + break; + + case WBT_FRAME_BEGIN: + rfx_process_message_frame_begin(context, message, data_in); + break; + + case WBT_FRAME_END: + rfx_process_message_frame_end(context, message, data_in); + break; + + case WBT_REGION: + rfx_process_message_region(context, message, data_in); + break; + + case WBT_EXTENSION: + rfx_process_message_tileset(context, message, data_in); + break; + + default: + DEBUG_WARN("unknown blockType 0x%X", blockType); + break; + } + + stream_set_pos(data_in, pos); + } + + return message; +} + +void rfx_message_free(RFX_CONTEXT* context, RFX_MESSAGE* message) +{ + if (message != NULL) + { + xfree(message->rects); + + if (message->tiles != NULL) + { + rfx_pool_put_tiles(context->priv->pool, message->tiles, message->num_tiles); + xfree(message->tiles); + } + + xfree(message); + } +} + +static void rfx_compose_message_sync(RFX_CONTEXT* context, STREAM* data_out) +{ + stream_write_uint16(data_out, WBT_SYNC); /* BlockT.blockType */ + stream_write_uint32(data_out, 12); /* BlockT.blockLen */ + stream_write_uint32(data_out, WF_MAGIC); /* magic */ + stream_write_uint16(data_out, WF_VERSION_1_0); /* version */ +} + +static void rfx_compose_message_codec_versions(RFX_CONTEXT* context, STREAM* data_out) +{ + stream_write_uint16(data_out, WBT_CODEC_VERSIONS); /* BlockT.blockType */ + stream_write_uint32(data_out, 10); /* BlockT.blockLen */ + stream_write_uint8(data_out, 1); /* numCodecs */ + stream_write_uint8(data_out, 1); /* codecs.codecId */ + stream_write_uint16(data_out, WF_VERSION_1_0); /* codecs.version */ +} + +static void rfx_compose_message_channels(RFX_CONTEXT* context, STREAM* data_out) +{ + stream_write_uint16(data_out, WBT_CHANNELS); /* BlockT.blockType */ + stream_write_uint32(data_out, 12); /* BlockT.blockLen */ + stream_write_uint8(data_out, 1); /* numChannels */ + stream_write_uint8(data_out, 0); /* Channel.channelId */ + stream_write_uint16(data_out, context->width); /* Channel.width */ + stream_write_uint16(data_out, context->height); /* Channel.height */ +} + +static void rfx_compose_message_context(RFX_CONTEXT* context, STREAM* data_out) +{ + uint16 properties; + + stream_write_uint16(data_out, WBT_CONTEXT); /* CodecChannelT.blockType */ + stream_write_uint32(data_out, 13); /* CodecChannelT.blockLen */ + stream_write_uint8(data_out, 1); /* CodecChannelT.codecId */ + stream_write_uint8(data_out, 0); /* CodecChannelT.channelId */ + stream_write_uint8(data_out, 0); /* ctxId */ + stream_write_uint16(data_out, CT_TILE_64x64); /* tileSize */ + + /* properties */ + properties = context->flags; /* flags */ + properties |= (COL_CONV_ICT << 3); /* cct */ + properties |= (CLW_XFORM_DWT_53_A << 5); /* xft */ + properties |= ((context->mode == RLGR1 ? CLW_ENTROPY_RLGR1 : CLW_ENTROPY_RLGR3) << 9); /* et */ + properties |= (SCALAR_QUANTIZATION << 13); /* qt */ + stream_write_uint16(data_out, properties); + context->properties = properties; +} + +void rfx_compose_message_header(RFX_CONTEXT* context, STREAM* data_out) +{ + stream_check_size(data_out, 12 + 10 + 12 + 13); + + rfx_compose_message_sync(context, data_out); + rfx_compose_message_codec_versions(context, data_out); + rfx_compose_message_channels(context, data_out); + rfx_compose_message_context(context, data_out); +} + +static void rfx_compose_message_frame_begin(RFX_CONTEXT* context, STREAM* data_out) +{ + stream_check_size(data_out, 14); + + stream_write_uint16(data_out, WBT_FRAME_BEGIN); /* CodecChannelT.blockType */ + stream_write_uint32(data_out, 14); /* CodecChannelT.blockLen */ + stream_write_uint8(data_out, 1); /* CodecChannelT.codecId */ + stream_write_uint8(data_out, 0); /* CodecChannelT.channelId */ + stream_write_uint32(data_out, context->frame_idx); /* frameIdx */ + stream_write_uint16(data_out, 1); /* numRegions */ +} + +static void rfx_compose_message_region(RFX_CONTEXT* context, STREAM* data_out, + const RFX_RECT* rects, int num_rects) +{ + int size; + int i; + + size = 15 + num_rects * 8; + stream_check_size(data_out, size); + + stream_write_uint16(data_out, WBT_REGION); /* CodecChannelT.blockType */ + stream_write_uint32(data_out, size); /* set CodecChannelT.blockLen later */ + stream_write_uint8(data_out, 1); /* CodecChannelT.codecId */ + stream_write_uint8(data_out, 0); /* CodecChannelT.channelId */ + stream_write_uint8(data_out, 1); /* regionFlags */ + stream_write_uint16(data_out, num_rects); /* numRects */ + + for (i = 0; i < num_rects; i++) + { + stream_write_uint16(data_out, rects[i].x); + stream_write_uint16(data_out, rects[i].y); + stream_write_uint16(data_out, rects[i].width); + stream_write_uint16(data_out, rects[i].height); + } + + stream_write_uint16(data_out, CBT_REGION); /* regionType */ + stream_write_uint16(data_out, 1); /* numTilesets */ +} + +static void rfx_compose_message_tile(RFX_CONTEXT* context, STREAM* data_out, + uint8* tile_data, int tile_width, int tile_height, int rowstride, + const uint32* quantVals, int quantIdxY, int quantIdxCb, int quantIdxCr, + int xIdx, int yIdx) +{ + int YLen = 0; + int CbLen = 0; + int CrLen = 0; + int start_pos, end_pos; + + stream_check_size(data_out, 19); + start_pos = stream_get_pos(data_out); + + stream_write_uint16(data_out, CBT_TILE); /* BlockT.blockType */ + stream_seek_uint32(data_out); /* set BlockT.blockLen later */ + stream_write_uint8(data_out, quantIdxY); + stream_write_uint8(data_out, quantIdxCb); + stream_write_uint8(data_out, quantIdxCr); + stream_write_uint16(data_out, xIdx); + stream_write_uint16(data_out, yIdx); + + stream_seek(data_out, 6); /* YLen, CbLen, CrLen */ + + rfx_encode_rgb(context, tile_data, tile_width, tile_height, rowstride, + quantVals + quantIdxY * 10, quantVals + quantIdxCb * 10, quantVals + quantIdxCr * 10, + data_out, &YLen, &CbLen, &CrLen); + + DEBUG_RFX("xIdx=%d yIdx=%d width=%d height=%d YLen=%d CbLen=%d CrLen=%d", + xIdx, yIdx, tile_width, tile_height, YLen, CbLen, CrLen); + + end_pos = stream_get_pos(data_out); + + stream_set_pos(data_out, start_pos + 2); + stream_write_uint32(data_out, 19 + YLen + CbLen + CrLen); /* BlockT.blockLen */ + stream_set_pos(data_out, start_pos + 13); + stream_write_uint16(data_out, YLen); + stream_write_uint16(data_out, CbLen); + stream_write_uint16(data_out, CrLen); + + stream_set_pos(data_out, end_pos); +} + +static void rfx_compose_message_tileset(RFX_CONTEXT* context, STREAM* data_out, + uint8* image_data, int width, int height, int rowstride) +{ + int size; + int start_pos, end_pos; + int i; + int numQuants; + const uint32* quantVals; + const uint32* quantValsPtr; + int quantIdxY; + int quantIdxCb; + int quantIdxCr; + int numTiles; + int numTilesX; + int numTilesY; + int xIdx; + int yIdx; + int tilesDataSize; + + if (context->num_quants == 0) + { + numQuants = 1; + quantVals = rfx_default_quantization_values; + quantIdxY = 0; + quantIdxCb = 0; + quantIdxCr = 0; + } + else + { + numQuants = context->num_quants; + quantVals = context->quants; + quantIdxY = context->quant_idx_y; + quantIdxCb = context->quant_idx_cb; + quantIdxCr = context->quant_idx_cr; + } + + numTilesX = (width + 63) / 64; + numTilesY = (height + 63) / 64; + numTiles = numTilesX * numTilesY; + + size = 22 + numQuants * 5; + stream_check_size(data_out, size); + start_pos = stream_get_pos(data_out); + + stream_write_uint16(data_out, WBT_EXTENSION); /* CodecChannelT.blockType */ + stream_seek_uint32(data_out); /* set CodecChannelT.blockLen later */ + stream_write_uint8(data_out, 1); /* CodecChannelT.codecId */ + stream_write_uint8(data_out, 0); /* CodecChannelT.channelId */ + stream_write_uint16(data_out, CBT_TILESET); /* subtype */ + stream_write_uint16(data_out, 0); /* idx */ + stream_write_uint16(data_out, context->properties); /* properties */ + stream_write_uint8(data_out, numQuants); /* numQuants */ + stream_write_uint8(data_out, 0x40); /* tileSize */ + stream_write_uint16(data_out, numTiles); /* numTiles */ + stream_seek_uint32(data_out); /* set tilesDataSize later */ + + quantValsPtr = quantVals; + for (i = 0; i < numQuants * 5; i++) + { + stream_write_uint8(data_out, quantValsPtr[0] + (quantValsPtr[1] << 4)); + quantValsPtr += 2; + } + + DEBUG_RFX("width:%d height:%d rowstride:%d", width, height, rowstride); + + end_pos = stream_get_pos(data_out); + for (yIdx = 0; yIdx < numTilesY; yIdx++) + { + for (xIdx = 0; xIdx < numTilesX; xIdx++) + { + rfx_compose_message_tile(context, data_out, + image_data + yIdx * 64 * rowstride + xIdx * 64 * context->bytes_per_pixel, + xIdx < numTilesX - 1 ? 64 : width - xIdx * 64, + yIdx < numTilesY - 1 ? 64 : height - yIdx * 64, + rowstride, quantVals, quantIdxY, quantIdxCb, quantIdxCr, xIdx, yIdx); + } + } + tilesDataSize = stream_get_pos(data_out) - end_pos; + size += tilesDataSize; + end_pos = stream_get_pos(data_out); + + stream_set_pos(data_out, start_pos + 2); + stream_write_uint32(data_out, size); /* CodecChannelT.blockLen */ + stream_set_pos(data_out, start_pos + 18); + stream_write_uint32(data_out, tilesDataSize); + + stream_set_pos(data_out, end_pos); +} + +static void rfx_compose_message_frame_end(RFX_CONTEXT* context, STREAM* data_out) +{ + stream_check_size(data_out, 8); + + stream_write_uint16(data_out, WBT_FRAME_END); /* CodecChannelT.blockType */ + stream_write_uint32(data_out, 8); /* CodecChannelT.blockLen */ + stream_write_uint8(data_out, 1); /* CodecChannelT.codecId */ + stream_write_uint8(data_out, 0); /* CodecChannelT.channelId */ +} + +void rfx_compose_message_data(RFX_CONTEXT* context, STREAM* data_out, + const RFX_RECT* rects, int num_rects, uint8* image_data, int width, int height, int rowstride) +{ + rfx_compose_message_frame_begin(context, data_out); + rfx_compose_message_region(context, data_out, rects, num_rects); + rfx_compose_message_tileset(context, data_out, image_data, width, height, rowstride); + rfx_compose_message_frame_end(context, data_out); +} diff --git a/libfreerdp-rfx/rfx_bitstream.c b/libfreerdp-rfx/rfx_bitstream.c new file mode 100644 index 000000000..de32a8471 --- /dev/null +++ b/libfreerdp-rfx/rfx_bitstream.c @@ -0,0 +1,85 @@ +/** + * FreeRDP: A Remote Desktop Protocol client. + * 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. + */ + +#include +#include +#include +#include + +#include "rfx_bitstream.h" + +void rfx_bitstream_attach(RFX_BITSTREAM* bs, uint8* buffer, int nbytes) +{ + bs->buffer = buffer; + bs->nbytes = nbytes; + bs->byte_pos = 0; + bs->bits_left = 8; +} + +uint16 rfx_bitstream_get_bits(RFX_BITSTREAM* bs, int nbits) +{ + int b; + uint16 n = 0; + + while (bs->byte_pos < bs->nbytes && nbits > 0) + { + 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; +} + +void rfx_bitstream_put_bits(RFX_BITSTREAM* bs, uint16 bits, int nbits) +{ + int b; + + while (bs->byte_pos < bs->nbytes && nbits > 0) + { + 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++; + } + } +} diff --git a/libfreerdp-rfx/rfx_bitstream.h b/libfreerdp-rfx/rfx_bitstream.h new file mode 100644 index 000000000..23dd54f2a --- /dev/null +++ b/libfreerdp-rfx/rfx_bitstream.h @@ -0,0 +1,42 @@ +/** + * FreeRDP: A Remote Desktop Protocol client. + * 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 __RFX_BITSTREAM_H +#define __RFX_BITSTREAM_H + +#include + +struct _RFX_BITSTREAM +{ + uint8* buffer; + int nbytes; + int byte_pos; + int bits_left; +}; +typedef struct _RFX_BITSTREAM RFX_BITSTREAM; + +void rfx_bitstream_attach(RFX_BITSTREAM* bs, uint8* buffer, int nbytes); +uint16 rfx_bitstream_get_bits(RFX_BITSTREAM* bs, int nbits); +void rfx_bitstream_put_bits(RFX_BITSTREAM* bs, uint16 bits, int nbits); + +#define rfx_bitstream_eos(_bs) ((_bs)->byte_pos >= (_bs)->nbytes) +#define rfx_bitstream_left(_bs) ((_bs)->byte_pos >= (_bs)->nbytes ? 0 : ((_bs)->nbytes - (_bs)->byte_pos - 1) * 8 + (_bs)->bits_left) +#define rfx_bitstream_get_processed_bytes(_bs) ((_bs)->bits_left < 8 ? (_bs)->byte_pos + 1 : (_bs)->byte_pos) + +#endif /* __RFX_BITSTREAM_H */ diff --git a/libfreerdp-rfx/rfx_constants.h b/libfreerdp-rfx/rfx_constants.h new file mode 100644 index 000000000..08d516cd1 --- /dev/null +++ b/libfreerdp-rfx/rfx_constants.h @@ -0,0 +1,59 @@ +/** + * FreeRDP: A Remote Desktop Protocol client. + * 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 __RFX_CONSTANTS_H +#define __RFX_CONSTANTS_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 + +/* 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 + +#endif /* __RFX_CONSTANTS_H */ diff --git a/libfreerdp-rfx/rfx_decode.c b/libfreerdp-rfx/rfx_decode.c new file mode 100644 index 000000000..c9eeefa89 --- /dev/null +++ b/libfreerdp-rfx/rfx_decode.c @@ -0,0 +1,152 @@ +/** + * FreeRDP: A Remote Desktop Protocol client. + * 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. + */ + +#include +#include +#include +#include +#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 void rfx_decode_format_rgb(sint16* r_buf, sint16* g_buf, sint16* b_buf, + RFX_PIXEL_FORMAT pixel_format, uint8* dst_buf) +{ + sint16* r = r_buf; + sint16* g = g_buf; + sint16* b = b_buf; + uint8* dst = dst_buf; + int i; + + switch (pixel_format) + { + case RFX_PIXEL_FORMAT_BGRA: + for (i = 0; i < 4096; i++) + { + *dst++ = (uint8) (*b++); + *dst++ = (uint8) (*g++); + *dst++ = (uint8) (*r++); + *dst++ = 0xFF; + } + break; + case RFX_PIXEL_FORMAT_RGBA: + for (i = 0; i < 4096; i++) + { + *dst++ = (uint8) (*r++); + *dst++ = (uint8) (*g++); + *dst++ = (uint8) (*b++); + *dst++ = 0xFF; + } + break; + case RFX_PIXEL_FORMAT_BGR: + for (i = 0; i < 4096; i++) + { + *dst++ = (uint8) (*b++); + *dst++ = (uint8) (*g++); + *dst++ = (uint8) (*r++); + } + break; + case RFX_PIXEL_FORMAT_RGB: + for (i = 0; i < 4096; i++) + { + *dst++ = (uint8) (*r++); + *dst++ = (uint8) (*g++); + *dst++ = (uint8) (*b++); + } + break; + default: + break; + } +} + +#define MINMAX(_v,_l,_h) ((_v) < (_l) ? (_l) : ((_v) > (_h) ? (_h) : (_v))) + +void rfx_decode_ycbcr_to_rgb(sint16* y_r_buf, sint16* cb_g_buf, sint16* cr_b_buf) +{ + sint16 y, cb, cr; + sint16 r, g, b; + + int i; + for (i = 0; i < 4096; i++) + { + y = y_r_buf[i] + 128; + cb = cb_g_buf[i]; + cr = cr_b_buf[i]; + r = (y + cr + (cr >> 2) + (cr >> 3) + (cr >> 5)); + y_r_buf[i] = MINMAX(r, 0, 255); + g = (y - ((cb >> 2) + (cb >> 4) + (cb >> 5)) - ((cr >> 1) + (cr >> 3) + (cr >> 4) + (cr >> 5))); + cb_g_buf[i] = MINMAX(g, 0, 255); + b = (y + cb + (cb >> 1) + (cb >> 2) + (cb >> 6)); + cr_b_buf[i] = MINMAX(b, 0, 255); + } +} + +static void rfx_decode_component(RFX_CONTEXT* context, const uint32* quantization_values, + const uint8* data, int size, sint16* buffer) +{ + PROFILER_ENTER(context->priv->prof_rfx_decode_component); + + PROFILER_ENTER(context->priv->prof_rfx_rlgr_decode); + rfx_rlgr_decode(context->mode, data, size, buffer, 4096); + 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, context->priv->dwt_buffer); + PROFILER_EXIT(context->priv->prof_rfx_dwt_2d_decode); + + PROFILER_EXIT(context->priv->prof_rfx_decode_component); +} + +void rfx_decode_rgb(RFX_CONTEXT* context, STREAM* data_in, + int y_size, const uint32 * y_quants, + int cb_size, const uint32 * cb_quants, + int cr_size, const uint32 * cr_quants, uint8* rgb_buffer) +{ + PROFILER_ENTER(context->priv->prof_rfx_decode_rgb); + + rfx_decode_component(context, y_quants, stream_get_tail(data_in), y_size, context->priv->y_r_buffer); /* YData */ + stream_seek(data_in, y_size); + rfx_decode_component(context, cb_quants, stream_get_tail(data_in), cb_size, context->priv->cb_g_buffer); /* CbData */ + stream_seek(data_in, cb_size); + rfx_decode_component(context, cr_quants, stream_get_tail(data_in), cr_size, context->priv->cr_b_buffer); /* CrData */ + stream_seek(data_in, cr_size); + + PROFILER_ENTER(context->priv->prof_rfx_decode_ycbcr_to_rgb); + context->decode_ycbcr_to_rgb(context->priv->y_r_buffer, context->priv->cb_g_buffer, context->priv->cr_b_buffer); + PROFILER_EXIT(context->priv->prof_rfx_decode_ycbcr_to_rgb); + + PROFILER_ENTER(context->priv->prof_rfx_decode_format_rgb); + rfx_decode_format_rgb(context->priv->y_r_buffer, context->priv->cb_g_buffer, context->priv->cr_b_buffer, + context->pixel_format, rgb_buffer); + PROFILER_EXIT(context->priv->prof_rfx_decode_format_rgb); + + PROFILER_EXIT(context->priv->prof_rfx_decode_rgb); +} diff --git a/libfreerdp-rfx/rfx_decode.h b/libfreerdp-rfx/rfx_decode.h new file mode 100644 index 000000000..617acdb13 --- /dev/null +++ b/libfreerdp-rfx/rfx_decode.h @@ -0,0 +1,32 @@ +/** + * FreeRDP: A Remote Desktop Protocol client. + * 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 __RFX_DECODE_H +#define __RFX_DECODE_H + +#include + +void rfx_decode_ycbcr_to_rgb(sint16* y_r_buf, sint16* cb_g_buf, sint16* cr_b_buf); + +void rfx_decode_rgb(RFX_CONTEXT* context, STREAM* data_in, + int y_size, const uint32 * y_quants, + int cb_size, const uint32 * cb_quants, + int cr_size, const uint32 * cr_quants, uint8* rgb_buffer); + +#endif /* __RFX_DECODE_H */ diff --git a/libfreerdp-rfx/rfx_differential.c b/libfreerdp-rfx/rfx_differential.c new file mode 100644 index 000000000..7a1d49e25 --- /dev/null +++ b/libfreerdp-rfx/rfx_differential.c @@ -0,0 +1,47 @@ +/** + * FreeRDP: A Remote Desktop Protocol client. + * 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. + */ + +#include +#include +#include +#include "rfx_differential.h" + +void rfx_differential_decode(sint16* buffer, int buffer_size) +{ + sint16* src; + sint16* dst; + + for (src = buffer, dst = buffer + 1; buffer_size > 1; src++, dst++, buffer_size--) + { + *dst += *src; + } +} + +void rfx_differential_encode(sint16* buffer, int buffer_size) +{ + sint16 n1, n2; + sint16* dst; + + for (n1 = *buffer, dst = buffer + 1; buffer_size > 1; dst++, buffer_size--) + { + n2 = *dst; + *dst -= n1; + n1 = n2; + } +} diff --git a/libfreerdp-rfx/rfx_differential.h b/libfreerdp-rfx/rfx_differential.h new file mode 100644 index 000000000..9591858b4 --- /dev/null +++ b/libfreerdp-rfx/rfx_differential.h @@ -0,0 +1,28 @@ +/** + * FreeRDP: A Remote Desktop Protocol client. + * 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 __RFX_DIFFERENTIAL_H +#define __RFX_DIFFERENTIAL_H + +#include + +void rfx_differential_decode(sint16* buffer, int buffer_size); +void rfx_differential_encode(sint16* buffer, int buffer_size); + +#endif /* __RFX_DIFFERENTIAL_H */ diff --git a/libfreerdp-rfx/rfx_dwt.c b/libfreerdp-rfx/rfx_dwt.c new file mode 100644 index 000000000..448980494 --- /dev/null +++ b/libfreerdp-rfx/rfx_dwt.c @@ -0,0 +1,194 @@ +/** + * FreeRDP: A Remote Desktop Protocol client. + * 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 +#include +#include + +#include "rfx_dwt.h" + +static void rfx_dwt_2d_decode_block(sint16* buffer, sint16* idwt, int subband_width) +{ + sint16 *dst, *l, *h; + sint16 *l_dst, *h_dst; + sint16 *hl, *lh, *hh, *ll; + int total_width; + int x, y; + int n; + + 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). */ + + ll = buffer + subband_width * subband_width * 3; + hl = buffer; + l_dst = idwt; + + lh = buffer + subband_width * subband_width; + hh = buffer + subband_width * subband_width * 2; + h_dst = idwt + subband_width * subband_width * 2; + + for (y = 0; y < subband_width; y++) + { + /* Even coefficients */ + l_dst[0] = ll[0] - ((hl[0] + hl[0] + 1) >> 1); + h_dst[0] = lh[0] - ((hh[0] + hh[0] + 1) >> 1); + for (n = 1; n < subband_width; n++) + { + x = n << 1; + l_dst[x] = ll[n] - ((hl[n-1] + hl[n] + 1) >> 1); + h_dst[x] = lh[n] - ((hh[n-1] + hh[n] + 1) >> 1); + } + + /* Odd coefficients */ + for (n = 0; n < subband_width-1; n++) + { + x = n << 1; + l_dst[x + 1] = (hl[n] << 1) + ((l_dst[x] + l_dst[x + 2]) >> 1); + h_dst[x + 1] = (hh[n] << 1) + ((h_dst[x] + h_dst[x + 2]) >> 1); + } + x = n << 1; + l_dst[x + 1] = (hl[n] << 1) + (l_dst[x]); + h_dst[x + 1] = (hh[n] << 1) + (h_dst[x]); + + 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 (x = 0; x < total_width; x++) + { + /* Even coefficients */ + for (n = 0; n < subband_width; n++) + { + y = n << 1; + dst = buffer + y * total_width + x; + l = idwt + n * total_width + x; + h = l + subband_width * total_width; + dst[0] = *l - (((n > 0 ? *(h - total_width) : *h) + (*h) + 1) >> 1); + } + + /* Odd coefficients */ + for (n = 0; n < subband_width; n++) + { + y = n << 1; + dst = buffer + y * total_width + x; + l = idwt + n * total_width + x; + h = l + subband_width * total_width; + dst[total_width] = (*h << 1) + ((dst[0] + dst[n < subband_width - 1 ? 2 * total_width : 0]) >> 1); + } + } +} + +void rfx_dwt_2d_decode(sint16* buffer, sint16* 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, dwt_buffer, 32); +} + +static void rfx_dwt_2d_encode_block(sint16* buffer, sint16* dwt, int subband_width) +{ + sint16 *src, *l, *h; + sint16 *l_src, *h_src; + sint16 *hl, *lh, *hh, *ll; + int total_width; + int x, y; + int n; + + total_width = subband_width << 1; + + /* DWT in vertical direction, results in 2 sub-bands in L, H order in tmp buffer dwt. */ + for (x = 0; x < total_width; x++) + { + for (n = 0; n < subband_width; n++) + { + y = n << 1; + l = dwt + n * total_width + x; + h = l + subband_width * total_width; + src = buffer + y * total_width + x; + + /* H */ + *h = (src[total_width] - ((src[0] + src[n < subband_width - 1 ? 2 * total_width : total_width]) >> 1)) >> 1; + + /* L */ + *l = 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 + subband_width * subband_width * 3; + hl = buffer; + l_src = dwt; + + lh = buffer + subband_width * subband_width; + hh = buffer + subband_width * subband_width * 2; + h_src = dwt + subband_width * subband_width * 2; + + for (y = 0; y < subband_width; y++) + { + /* L */ + for (n = 0; n < subband_width; n++) + { + x = n << 1; + + /* HL */ + hl[n] = (l_src[x + 1] - ((l_src[x] + l_src[n < subband_width - 1 ? x + 2 : x]) >> 1)) >> 1; + /* LL */ + ll[n] = l_src[x] + (n == 0 ? hl[n] : (hl[n - 1] + hl[n]) >> 1); + } + + /* H */ + for (n = 0; n < subband_width; n++) + { + x = n << 1; + + /* HH */ + hh[n] = (h_src[x + 1] - ((h_src[x] + h_src[n < subband_width - 1 ? x + 2 : x]) >> 1)) >> 1; + /* LH */ + lh[n] = 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(sint16* buffer, sint16* dwt_buffer) +{ + rfx_dwt_2d_encode_block(buffer, dwt_buffer, 32); + rfx_dwt_2d_encode_block(buffer + 3072, dwt_buffer, 16); + rfx_dwt_2d_encode_block(buffer + 3840, dwt_buffer, 8); +} diff --git a/libfreerdp-rfx/rfx_dwt.h b/libfreerdp-rfx/rfx_dwt.h new file mode 100644 index 000000000..902ad0a2c --- /dev/null +++ b/libfreerdp-rfx/rfx_dwt.h @@ -0,0 +1,28 @@ +/** + * FreeRDP: A Remote Desktop Protocol client. + * 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 __RFX_DWT_H +#define __RFX_DWT_H + +#include + +void rfx_dwt_2d_decode(sint16* buffer, sint16* dwt_buffer); +void rfx_dwt_2d_encode(sint16* buffer, sint16* dwt_buffer); + +#endif /* __RFX_DWT_H */ diff --git a/libfreerdp-rfx/rfx_encode.c b/libfreerdp-rfx/rfx_encode.c new file mode 100644 index 000000000..793931583 --- /dev/null +++ b/libfreerdp-rfx/rfx_encode.c @@ -0,0 +1,187 @@ +/** + * FreeRDP: A Remote Desktop Protocol client. + * 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. + */ + +#include +#include +#include +#include "rfx_types.h" +#include "rfx_rlgr.h" +#include "rfx_differential.h" +#include "rfx_quantization.h" +#include "rfx_dwt.h" + +#include "rfx_encode.h" + +#define MINMAX(_v,_l,_h) ((_v) < (_l) ? (_l) : ((_v) > (_h) ? (_h) : (_v))) + +static void rfx_encode_format_rgb(const uint8* rgb_data, int width, int height, int rowstride, + RFX_PIXEL_FORMAT pixel_format, sint16* r_buf, sint16* g_buf, sint16* b_buf) +{ + int x, y; + int x_exceed; + int y_exceed; + const uint8* src; + + x_exceed = 64 - width; + y_exceed = 64 - height; + for (y = 0; y < height; y++) + { + src = rgb_data + y * rowstride; + + switch (pixel_format) + { + case RFX_PIXEL_FORMAT_BGRA: + for (x = 0; x < width; x++) + { + *b_buf++ = (sint16) (*src++); + *g_buf++ = (sint16) (*src++); + *r_buf++ = (sint16) (*src++); + src++; + } + break; + case RFX_PIXEL_FORMAT_RGBA: + for (x = 0; x < width; x++) + { + *r_buf++ = (sint16) (*src++); + *g_buf++ = (sint16) (*src++); + *b_buf++ = (sint16) (*src++); + src++; + } + break; + case RFX_PIXEL_FORMAT_BGR: + for (x = 0; x < width; x++) + { + *b_buf++ = (sint16) (*src++); + *g_buf++ = (sint16) (*src++); + *r_buf++ = (sint16) (*src++); + } + break; + case RFX_PIXEL_FORMAT_RGB: + for (x = 0; x < width; x++) + { + *r_buf++ = (sint16) (*src++); + *g_buf++ = (sint16) (*src++); + *b_buf++ = (sint16) (*src++); + } + break; + default: + break; + } + /* Fill the horizontal region outside of 64x64 tile size to 0 in order to be better compressed. */ + if (x_exceed > 0) + { + memset(r_buf, 0, x_exceed * sizeof(sint16)); + memset(g_buf, 0, x_exceed * sizeof(sint16)); + memset(b_buf, 0, x_exceed * sizeof(sint16)); + r_buf += x_exceed; + g_buf += x_exceed; + b_buf += x_exceed; + } + } + + /* Fill the vertical region outside of 64x64 tile size to 0 in order to be better compressed. */ + if (y_exceed > 0) + { + memset(r_buf, 0, y_exceed * 64 * sizeof(sint16)); + memset(g_buf, 0, y_exceed * 64 * sizeof(sint16)); + memset(b_buf, 0, y_exceed * 64 * sizeof(sint16)); + } +} + +void rfx_encode_rgb_to_ycbcr(sint16* y_r_buf, sint16* cb_g_buf, sint16* cr_b_buf) +{ + sint16 y, cb, cr; + sint16 r, g, b; + + int i; + for (i = 0; i < 4096; i++) + { + r = y_r_buf[i]; + g = cb_g_buf[i]; + b = cr_b_buf[i]; + y = ((r >> 2) + (r >> 5) + (r >> 6)) + ((g >> 1) + (g >> 4) + (g >> 6) + (g >> 7)) + ((b >> 4) + (b >> 5) + (b >> 6)); + y_r_buf[i] = MINMAX(y, 0, 255) - 128; + cb = 0 - ((r >> 3) + (r >> 5) + (r >> 7)) - ((g >> 2) + (g >> 4) + (g >> 6)) + (b >> 1); + cb_g_buf[i] = MINMAX(cb, -128, 127); + cr = (r >> 1) - ((g >> 2) + (g >> 3) + (g >> 5) + (g >> 7)) - ((b >> 4) + (b >> 6)); + cr_b_buf[i] = MINMAX(cr, -128, 127); + } +} + +static void rfx_encode_component(RFX_CONTEXT* context, const uint32* quantization_values, + sint16* data, uint8* buffer, int buffer_size, int* size) +{ + PROFILER_ENTER(context->priv->prof_rfx_encode_component); + + PROFILER_ENTER(context->priv->prof_rfx_dwt_2d_encode); + context->dwt_2d_encode(data, context->priv->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); + *size = rfx_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); +} + +void rfx_encode_rgb(RFX_CONTEXT* context, const uint8* rgb_data, int width, int height, int rowstride, + const uint32* y_quants, const uint32* cb_quants, const uint32* cr_quants, + STREAM* data_out, int* y_size, int* cb_size, int* cr_size) +{ + sint16* y_r_buffer = context->priv->y_r_buffer; + sint16* cb_g_buffer = context->priv->cb_g_buffer; + sint16* cr_b_buffer = context->priv->cr_b_buffer; + + PROFILER_ENTER(context->priv->prof_rfx_encode_rgb); + + PROFILER_ENTER(context->priv->prof_rfx_encode_format_rgb); + rfx_encode_format_rgb(rgb_data, width, height, rowstride, + context->pixel_format, y_r_buffer, cb_g_buffer, cr_b_buffer); + PROFILER_EXIT(context->priv->prof_rfx_encode_format_rgb); + + PROFILER_ENTER(context->priv->prof_rfx_encode_rgb_to_ycbcr); + context->encode_rgb_to_ycbcr(context->priv->y_r_buffer, context->priv->cb_g_buffer, context->priv->cr_b_buffer); + PROFILER_EXIT(context->priv->prof_rfx_encode_rgb_to_ycbcr); + + /* Ensure the buffer is reasonably large enough */ + stream_check_size(data_out, 4096); + rfx_encode_component(context, y_quants, context->priv->y_r_buffer, + stream_get_tail(data_out), stream_get_left(data_out), y_size); + stream_seek(data_out, *y_size); + + stream_check_size(data_out, 4096); + rfx_encode_component(context, cb_quants, context->priv->cb_g_buffer, + stream_get_tail(data_out), stream_get_left(data_out), cb_size); + stream_seek(data_out, *cb_size); + + stream_check_size(data_out, 4096); + rfx_encode_component(context, cr_quants, context->priv->cr_b_buffer, + stream_get_tail(data_out), stream_get_left(data_out), cr_size); + stream_seek(data_out, *cr_size); + + PROFILER_EXIT(context->priv->prof_rfx_encode_rgb); +} diff --git a/libfreerdp-rfx/rfx_encode.h b/libfreerdp-rfx/rfx_encode.h new file mode 100644 index 000000000..ef7e24ea9 --- /dev/null +++ b/libfreerdp-rfx/rfx_encode.h @@ -0,0 +1,32 @@ +/** + * FreeRDP: A Remote Desktop Protocol client. + * 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 __RFX_ENCODE_H +#define __RFX_ENCODE_H + +#include + +void rfx_encode_rgb_to_ycbcr(sint16* y_r_buf, sint16* cb_g_buf, sint16* cr_b_buf); + +void rfx_encode_rgb(RFX_CONTEXT* context, const uint8* rgb_data, int width, int height, int rowstride, + const uint32* y_quants, const uint32* cb_quants, const uint32* cr_quants, + STREAM* data_out, int* y_size, int* cb_size, int* cr_size); + +#endif + diff --git a/libfreerdp-rfx/rfx_pool.c b/libfreerdp-rfx/rfx_pool.c new file mode 100644 index 000000000..12e703c01 --- /dev/null +++ b/libfreerdp-rfx/rfx_pool.c @@ -0,0 +1,112 @@ +/** + * FreeRDP: A Remote Desktop Protocol client. + * RemoteFX Codec Library - Memory Pool + * + * Copyright 2011 Marc-Andre Moreau + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include + +#include "rfx_pool.h" + +RFX_POOL* rfx_pool_new() +{ + RFX_POOL* pool; + + pool = xnew(RFX_POOL); + + pool->size = 64; + pool->tiles = (RFX_TILE**) xzalloc(sizeof(RFX_TILE*) * pool->size); + + return pool; +} + +void rfx_pool_free(RFX_POOL* pool) +{ + int i; + RFX_TILE* tile; + + for (i = 0; i < pool->count; i++) + { + tile = pool->tiles[i]; + + if (tile != NULL) + { + if (tile->data != NULL) + xfree(tile->data); + + xfree(tile); + } + } + + xfree(pool->tiles); + xfree(pool); +} + +void rfx_pool_put_tile(RFX_POOL* pool, RFX_TILE* tile) +{ + if (pool->count >= pool->size) + { + pool->size *= 2; + pool->tiles = (RFX_TILE**) xrealloc((void*) pool->tiles, sizeof(RFX_TILE*) * pool->size); + } + + pool->tiles[(pool->count)++] = tile; +} + +RFX_TILE* rfx_pool_get_tile(RFX_POOL* pool) +{ + RFX_TILE* tile; + + if (pool->count < 1) + { + tile = xnew(RFX_TILE); + tile->data = (uint8*) xmalloc(4096 * 4); /* 64x64 * 4 */ + } + else + { + tile = pool->tiles[--(pool->count)]; + } + + return tile; +} + +void rfx_pool_put_tiles(RFX_POOL* pool, RFX_TILE** tiles, int count) +{ + int i; + + for (i = 0; i < count; i++) + { + rfx_pool_put_tile(pool, tiles[i]); + } +} + +RFX_TILE** rfx_pool_get_tiles(RFX_POOL* pool, int count) +{ + int i; + RFX_TILE** tiles; + + tiles = (RFX_TILE**) xmalloc(sizeof(RFX_TILE*) * count); + + for (i = 0; i < count; i++) + { + tiles[i] = rfx_pool_get_tile(pool); + } + + return tiles; +} diff --git a/libfreerdp-rfx/rfx_pool.h b/libfreerdp-rfx/rfx_pool.h new file mode 100644 index 000000000..68132656a --- /dev/null +++ b/libfreerdp-rfx/rfx_pool.h @@ -0,0 +1,40 @@ +/** + * FreeRDP: A Remote Desktop Protocol client. + * RemoteFX Codec Library - Memory Pool + * + * Copyright 2011 Marc-Andre Moreau + * + * 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 __RFX_POOL_H +#define __RFX_POOL_H + +#include + +struct _RFX_POOL +{ + int size; + int count; + RFX_TILE** tiles; +}; +typedef struct _RFX_POOL RFX_POOL; + +RFX_POOL* rfx_pool_new(); +void rfx_pool_free(RFX_POOL* pool); +void rfx_pool_put_tile(RFX_POOL* pool, RFX_TILE* tile); +RFX_TILE* rfx_pool_get_tile(RFX_POOL* pool); +void rfx_pool_put_tiles(RFX_POOL* pool, RFX_TILE** tiles, int count); +RFX_TILE** rfx_pool_get_tiles(RFX_POOL* pool, int count); + +#endif /* __RFX_POOL_H */ diff --git a/libfreerdp-rfx/rfx_quantization.c b/libfreerdp-rfx/rfx_quantization.c new file mode 100644 index 000000000..6a92b686d --- /dev/null +++ b/libfreerdp-rfx/rfx_quantization.c @@ -0,0 +1,76 @@ +/** + * FreeRDP: A Remote Desktop Protocol client. + * 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 "rfx_quantization.h" + +static void rfx_quantization_decode_block(sint16* buffer, int buffer_size, uint32 factor) +{ + sint16* dst; + + if (factor <= 6) + return; + + factor -= 6; + for (dst = buffer; buffer_size > 0; dst++, buffer_size--) + { + *dst <<= factor; + } +} + +void rfx_quantization_decode(sint16* buffer, const uint32* quantization_values) +{ + rfx_quantization_decode_block(buffer, 1024, quantization_values[8]); /* HL1 */ + rfx_quantization_decode_block(buffer + 1024, 1024, quantization_values[7]); /* LH1 */ + rfx_quantization_decode_block(buffer + 2048, 1024, quantization_values[9]); /* HH1 */ + rfx_quantization_decode_block(buffer + 3072, 256, quantization_values[5]); /* HL2 */ + rfx_quantization_decode_block(buffer + 3328, 256, quantization_values[4]); /* LH2 */ + rfx_quantization_decode_block(buffer + 3584, 256, quantization_values[6]); /* HH2 */ + rfx_quantization_decode_block(buffer + 3840, 64, quantization_values[2]); /* HL3 */ + rfx_quantization_decode_block(buffer + 3904, 64, quantization_values[1]); /* LH3 */ + rfx_quantization_decode_block(buffer + 3868, 64, quantization_values[3]); /* HH3 */ + rfx_quantization_decode_block(buffer + 4032, 64, quantization_values[0]); /* LL3 */ +} + +static void rfx_quantization_encode_block(sint16* buffer, int buffer_size, uint32 factor) +{ + sint16* dst; + + if (factor <= 6) + return; + + factor -= 6; + for (dst = buffer; buffer_size > 0; dst++, buffer_size--) + { + *dst >>= factor; + } +} + +void rfx_quantization_encode(sint16* buffer, const uint32* quantization_values) +{ + rfx_quantization_encode_block(buffer, 1024, quantization_values[8]); /* HL1 */ + rfx_quantization_encode_block(buffer + 1024, 1024, quantization_values[7]); /* LH1 */ + rfx_quantization_encode_block(buffer + 2048, 1024, quantization_values[9]); /* HH1 */ + rfx_quantization_encode_block(buffer + 3072, 256, quantization_values[5]); /* HL2 */ + rfx_quantization_encode_block(buffer + 3328, 256, quantization_values[4]); /* LH2 */ + rfx_quantization_encode_block(buffer + 3584, 256, quantization_values[6]); /* HH2 */ + rfx_quantization_encode_block(buffer + 3840, 64, quantization_values[2]); /* HL3 */ + rfx_quantization_encode_block(buffer + 3904, 64, quantization_values[1]); /* LH3 */ + rfx_quantization_encode_block(buffer + 3868, 64, quantization_values[3]); /* HH3 */ + rfx_quantization_encode_block(buffer + 4032, 64, quantization_values[0]); /* LL3 */ +} diff --git a/libfreerdp-rfx/rfx_quantization.h b/libfreerdp-rfx/rfx_quantization.h new file mode 100644 index 000000000..9b1f289d7 --- /dev/null +++ b/libfreerdp-rfx/rfx_quantization.h @@ -0,0 +1,28 @@ +/** + * FreeRDP: A Remote Desktop Protocol client. + * 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 __RFX_QUANTIZATION_H +#define __RFX_QUANTIZATION_H + +#include + +void rfx_quantization_decode(sint16* buffer, const uint32* quantization_values); +void rfx_quantization_encode(sint16* buffer, const uint32* quantization_values); + +#endif /* __RFX_QUANTIZATION_H */ diff --git a/libfreerdp-rfx/rfx_rlgr.c b/libfreerdp-rfx/rfx_rlgr.c new file mode 100644 index 000000000..f2f0b3ad4 --- /dev/null +++ b/libfreerdp-rfx/rfx_rlgr.c @@ -0,0 +1,428 @@ +/** + * FreeRDP: A Remote Desktop Protocol client. + * 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 +#include +#include +#include +#include "rfx_bitstream.h" + +#include "rfx_rlgr.h" + +/* Constants used within the 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 */ + +/* Gets (returns) the next nBits from the bitstream */ +#define GetBits(nBits) rfx_bitstream_get_bits(bs, nBits) + +/* From current output pointer, write "value", check and update buffer_size */ +#define WriteValue(value) \ +{ \ + if (buffer_size > 0) \ + *dst++ = (value); \ + buffer_size--; \ +} + +/* From current output pointer, write next nZeroes terms with value 0, check and update buffer_size */ +#define WriteZeroes(nZeroes) \ +{ \ + int nZeroesWritten = (nZeroes); \ + if (nZeroesWritten > buffer_size) \ + nZeroesWritten = buffer_size; \ + if (nZeroesWritten > 0) \ + { \ + memset(dst, 0, nZeroesWritten * sizeof(sint16)); \ + dst += nZeroesWritten; \ + } \ + buffer_size -= (nZeroes); \ +} + +/* Returns the least number of bits required to represent a given value */ +#define GetMinBits(_val, _nbits) \ +{ \ + uint32 _v = _val; \ + _nbits = 0; \ + while (_v) \ + { \ + _v >>= 1; \ + _nbits++; \ + } \ +} + +/* Converts from (2 * magnitude - sign) to integer */ +#define GetIntFrom2MagSign(twoMs) (((twoMs) & 1) ? -1 * (sint16)(((twoMs) + 1) >> 1) : (sint16)((twoMs) >> 1)) + +/* + * Update the passed parameter and clamp it to the range [0, KPMAX] + * Return the value of parameter right-shifted by LSGR + */ +#define UpdateParam(_param, _deltaP, _k) \ +{ \ + _param += _deltaP; \ + if (_param > KPMAX) \ + _param = KPMAX; \ + if (_param < 0) \ + _param = 0; \ + _k = (_param >> LSGR); \ +} + +/* Outputs the Golomb/Rice encoding of a non-negative integer */ +#define GetGRCode(krp, kr) rfx_rlgr_get_gr_code(bs, krp, kr) + +static uint16 rfx_rlgr_get_gr_code(RFX_BITSTREAM* bs, int* krp, int* kr) +{ + int vk; + uint16 mag; + + /* chew up/count leading 1s and escape 0 */ + for (vk = 0; GetBits(1) == 1;) + vk++; + + /* get next *kr bits, and combine with leading 1s */ + mag = (vk << *kr) | GetBits(*kr); + + /* adjust krp and kr based on vk */ + if (!vk) + { + UpdateParam(*krp, -2, *kr); + } + else if (vk != 1) + { + /* at 1, no change! */ + UpdateParam(*krp, vk, *kr); + } + + return mag; +} + +int rfx_rlgr_decode(RLGR_MODE mode, const uint8* data, int data_size, sint16* buffer, int buffer_size) +{ + int k; + int kp; + int kr; + int krp; + sint16* dst; + RFX_BITSTREAM* bs; + + bs = xnew(RFX_BITSTREAM); + rfx_bitstream_attach(bs, (uint8*) data, data_size); + dst = buffer; + + /* initialize the parameters */ + k = 1; + kp = k << LSGR; + kr = 1; + krp = kr << LSGR; + + while (!rfx_bitstream_eos(bs) && buffer_size > 0) + { + int run; + if (k) + { + int mag; + uint32 sign; + + /* RL MODE */ + while (!rfx_bitstream_eos(bs) && GetBits(1) == 0) + { + /* we have an RL escape "0", which translates to a run (1< 0) \ + { \ + _n = *data++; \ + data_size--; \ + } \ + else \ + { \ + _n = 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 */ +#define OutputBit(count, bit) \ +{ \ + uint16 _b = (bit ? 0xFFFF : 0); \ + int _c = (count); \ + for (; _c > 0; _c -= 16) \ + rfx_bitstream_put_bits(bs, _b, (_c > 16 ? 16 : _c)); \ +} + +/* Converts the input value to (2 * abs(input) - sign(input)), where sign(input) = (input < 0 ? 1 : 0) and returns it */ +#define Get2MagSign(input) ((input) >= 0 ? 2 * (input) : -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, int* krp, uint16 val) +{ + int kr = *krp >> LSGR; + + /* unary part of GR code */ + + uint16 vk = (val) >> kr; + OutputBit(vk, 1); + OutputBit(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) + { + UpdateParam(*krp, -2, kr); + } + else if (vk > 1) + { + UpdateParam(*krp, vk, kr); + } +} + +int rfx_rlgr_encode(RLGR_MODE mode, const sint16* data, int data_size, uint8* buffer, int buffer_size) +{ + int k; + int kp; + int kr; + int krp; + RFX_BITSTREAM* bs; + int processed_size; + + bs = xnew(RFX_BITSTREAM); + rfx_bitstream_attach(bs, buffer, buffer_size); + + /* initialize the parameters */ + k = 1; + kp = 1 << LSGR; + kr = 1; + krp = 1 << LSGR; + + /* process all the input coefficients */ + while (data_size > 0) + { + int input; + + if (k) + { + int numZeros; + int runmax; + int mag; + int sign; + + /* 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(1, 0); /* output a zero bit */ + numZeros -= runmax; + UpdateParam(kp, UP_GR, k); /* update kp, k */ + runmax = 1 << k; + } + + /* output a 1 to terminate runs */ + OutputBit(1, 1); + + /* output the remaining run length using k bits */ + OutputBits(k, numZeros); + + if (input != 0) + { + /* encode the nonzero value using GR coding */ + mag = (input < 0 ? -input : input); /* absolute value of input coefficient */ + sign = (input < 0 ? 1 : 0); /* sign of input coefficient */ + + OutputBit(1, sign); /* output the sign bit */ + CodeGR(&krp, mag - 1); /* output GR code for (mag - 1) */ + + UpdateParam(kp, -DN_GR, k); + } + } + else + { + /* GOLOMB-RICE MODE */ + + if (mode == RLGR1) + { + uint32 twoMs; + + /* RLGR1 variant */ + + /* convert input to (2*magnitude - sign), encode using GR code */ + GetNextInput(input); + twoMs = Get2MagSign(input); + CodeGR(&krp, twoMs); + + /* update k, kp */ + if (twoMs) + { + UpdateParam(kp, UQ_GR, k); + } + else + { + UpdateParam(kp, -DQ_GR, k); + } + } + else /* mode == RLGR3 */ + { + uint32 twoMs1; + uint32 twoMs2; + uint32 sum2Ms; + uint32 nIdx; + + /* 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) + { + UpdateParam(kp, -2 * DQ_GR, k); + } + else if (!twoMs1 && !twoMs2) + { + UpdateParam(kp, 2 * UQ_GR, k); + } + } + } + } + + processed_size = rfx_bitstream_get_processed_bytes(bs); + xfree(bs); + + return processed_size; +} diff --git a/libfreerdp-rfx/rfx_rlgr.h b/libfreerdp-rfx/rfx_rlgr.h new file mode 100644 index 000000000..05604766e --- /dev/null +++ b/libfreerdp-rfx/rfx_rlgr.h @@ -0,0 +1,28 @@ +/** + * FreeRDP: A Remote Desktop Protocol client. + * 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 __RFX_RLGR_H +#define __RFX_RLGR_H + +#include + +int rfx_rlgr_decode(RLGR_MODE mode, const uint8* data, int data_size, sint16* buffer, int buffer_size); +int rfx_rlgr_encode(RLGR_MODE mode, const sint16* data, int data_size, uint8* buffer, int buffer_size); + +#endif /* __RFX_RLGR_H */ diff --git a/libfreerdp-rfx/rfx_types.h b/libfreerdp-rfx/rfx_types.h new file mode 100644 index 000000000..a18034ed0 --- /dev/null +++ b/libfreerdp-rfx/rfx_types.h @@ -0,0 +1,73 @@ +/** + * FreeRDP: A Remote Desktop Protocol client. + * 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 __RFX_TYPES_H +#define __RFX_TYPES_H + +#include "config.h" +#include +#include + +#ifdef WITH_DEBUG_RFX +#define DEBUG_RFX(fmt, ...) DEBUG_CLASS(RFX, fmt, ## __VA_ARGS__) +#else +#define DEBUG_RFX(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__) +#endif + +#include "rfx_pool.h" + +struct _RFX_CONTEXT_PRIV +{ + /* pre-allocated buffers */ + + RFX_POOL* pool; /* memory pool */ + + sint16 y_r_mem[4096 + 8]; /* 4096 = 64x64 (+ 8x2 = 16 for mem align) */ + sint16 cb_g_mem[4096 + 8]; /* 4096 = 64x64 (+ 8x2 = 16 for mem align) */ + sint16 cr_b_mem[4096 + 8]; /* 4096 = 64x64 (+ 8x2 = 16 for mem align) */ + + sint16* y_r_buffer; + sint16* cb_g_buffer; + sint16* cr_b_buffer; + + sint16 dwt_mem[32 * 32 * 2 * 2 + 8]; /* maximum sub-band width is 32 */ + + sint16* dwt_buffer; + + /* 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_decode_ycbcr_to_rgb); + PROFILER_DEFINE(prof_rfx_decode_format_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_encode_rgb_to_ycbcr); + PROFILER_DEFINE(prof_rfx_encode_format_rgb); +}; + +#endif /* __RFX_TYPES_H */