diff --git a/.travis.yml b/.travis.yml index 615a6d4..b5dc259 100644 --- a/.travis.yml +++ b/.travis.yml @@ -41,7 +41,6 @@ addons: - libgsm1-dev - libavcodec-dev - libavutil-dev - - libx264-dev - libxext-dev - ninja-build - libsystemd-dev diff --git a/CMakeLists.txt b/CMakeLists.txt index 22c0347..967304e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -85,7 +85,7 @@ if ($ENV{BUILD_NUMBER}) endif() set(WITH_LIBRARY_VERSIONING "ON") -set(RAW_VERSION_STRING "2.5.0") +set(RAW_VERSION_STRING "2.6.0") if(EXISTS "${CMAKE_SOURCE_DIR}/.source_tag") file(READ ${CMAKE_SOURCE_DIR}/.source_tag RAW_VERSION_STRING) elseif(USE_VERSION_FROM_GIT_TAG) @@ -652,6 +652,7 @@ if(UNIX OR CYGWIN) include(CheckFunctionExists) check_function_exists(getlogin_r HAVE_GETLOGIN_R) + check_function_exists(getpwuid_r HAVE_GETPWUID_R) else() set(X11_FEATURE_TYPE "DISABLED") set(WAYLAND_FEATURE_TYPE "DISABLED") @@ -719,10 +720,6 @@ set(JPEG_FEATURE_TYPE "OPTIONAL") set(JPEG_FEATURE_PURPOSE "codec") set(JPEG_FEATURE_DESCRIPTION "use JPEG library") -set(X264_FEATURE_TYPE "OPTIONAL") -set(X264_FEATURE_PURPOSE "codec") -set(X264_FEATURE_DESCRIPTION "use x264 library") - set(OPENH264_FEATURE_TYPE "OPTIONAL") set(OPENH264_FEATURE_PURPOSE "codec") set(OPENH264_FEATURE_DESCRIPTION "use OpenH264 library") @@ -808,7 +805,6 @@ if(ANDROID) set(PULSE_FEATURE_TYPE "DISABLED") set(CUPS_FEATURE_TYPE "DISABLED") set(PCSC_FEATURE_TYPE "DISABLED") - set(FFMPEG_FEATURE_TYPE "DISABLED") set(VAAPI_FEATURE_TYPE "DISABLED") set(OPENSLES_FEATURE_TYPE "REQUIRED") endif() @@ -831,7 +827,6 @@ find_feature(PCSC ${PCSC_FEATURE_TYPE} ${PCSC_FEATURE_PURPOSE} ${PCSC_FEATURE_DE find_feature(FFmpeg ${FFMPEG_FEATURE_TYPE} ${FFMPEG_FEATURE_PURPOSE} ${FFMPEG_FEATURE_DESCRIPTION}) find_feature(JPEG ${JPEG_FEATURE_TYPE} ${JPEG_FEATURE_PURPOSE} ${JPEG_FEATURE_DESCRIPTION}) -find_feature(x264 ${X264_FEATURE_TYPE} ${X264_FEATURE_PURPOSE} ${X264_FEATURE_DESCRIPTION}) find_feature(OpenH264 ${OPENH264_FEATURE_TYPE} ${OPENH264_FEATURE_PURPOSE} ${OPENH264_FEATURE_DESCRIPTION}) find_feature(OpenCL ${OPENCL_FEATURE_TYPE} ${OPENCL_FEATURE_PURPOSE} ${OPENCL_FEATURE_DESCRIPTION}) find_feature(GSM ${GSM_FEATURE_TYPE} ${GSM_FEATURE_PURPOSE} ${GSM_FEATURE_DESCRIPTION}) @@ -917,7 +912,7 @@ if(MBEDTLS_FOUND) add_definitions("-DWITH_MBEDTLS") endif() -if (WITH_X264 OR WITH_OPENH264 OR WITH_MEDIA_FOUNDATION OR WITH_FFMPEG) +if (WITH_OPENH264 OR WITH_MEDIA_FOUNDATION OR WITH_FFMPEG OR WITH_MEDIACODEC) set(WITH_GFX_H264 ON) else() set(WITH_GFX_H264 OFF) diff --git a/ChangeLog b/ChangeLog index bf4e500..b7c7c4f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,26 @@ +# 2022-02-22 Version 2.6.0 + +Noteworthy changes: +* Backported android FFMPEG build scripts +* Updated android build dependencies + +Fixed issues: +* Backported #7303: Fix PDU length for RDPINPUT_PROTOCOL_V300 +* Backported #7658: Sanitize optional physical monitor size values +* Backported #7426: Wayland memory corruption +* Backported #7293: Remove unused codec x264 +* Backported #7541: Allow resolutions larger 2048x2048 +* Backported #7574: FFMPEG 5.0 support +* Backported #7578: FFMPEG 5.0 support +* Backported #7580: Fixed device hotplugging +* Backported #7583: GetUserNameExA: Prefer getpwuid_r over getlogin_r over getlogin +* Backported #7585: Android Mediacodec support + +Important notes: + +For a complete and detailed change log since the last release run: +git log 2.5.0..2.6.0 + # 2022-01-12 Version 2.5.0 Noteworthy changes: diff --git a/cmake/ConfigOptionsAndroid.cmake b/channels/ainput/CMakeLists.txt similarity index 58% rename from cmake/ConfigOptionsAndroid.cmake rename to channels/ainput/CMakeLists.txt index 07dd604..b1d1a6a 100644 --- a/cmake/ConfigOptionsAndroid.cmake +++ b/channels/ainput/CMakeLists.txt @@ -1,7 +1,8 @@ -# FreeRDP cmake android options +# FreeRDP: A Remote Desktop Protocol Implementation +# FreeRDP cmake build script # -# Copyright 2013 Thincast Technologies GmbH -# Copyright 2013 Bernhard Miklautz +# Copyright 2022 Armin Novak +# Copyright 2022 Thincast Technologies GmbH # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -15,8 +16,12 @@ # See the License for the specific language governing permissions and # limitations under the License. -option(WITH_OPENSLES "Enable sound and microphone redirection using OpenSLES" ON) +define_channel("ainput") -set(ANDROID_APP_TARGET_SDK 21 CACHE STRING "Application target android SDK") -set(ANDROID_APP_MIN_SDK 14 CACHE STRING "Application minimum android SDK requirement") +if(WITH_CLIENT_CHANNELS) + add_channel_client(${MODULE_PREFIX} ${CHANNEL_NAME}) +endif() +if(WITH_SERVER_CHANNELS) + add_channel_server(${MODULE_PREFIX} ${CHANNEL_NAME}) +endif() diff --git a/channels/ainput/ChannelOptions.cmake b/channels/ainput/ChannelOptions.cmake new file mode 100644 index 0000000..eafc6c0 --- /dev/null +++ b/channels/ainput/ChannelOptions.cmake @@ -0,0 +1,13 @@ + +set(OPTION_DEFAULT OFF) +set(OPTION_CLIENT_DEFAULT ON) +set(OPTION_SERVER_DEFAULT ON) + +define_channel_options(NAME "ainput" TYPE "dynamic" + DESCRIPTION "Advanced Input Virtual Channel Extension" + SPECIFICATIONS "[XXXXX]" + DEFAULT ${OPTION_DEFAULT}) + +define_channel_client_options(${OPTION_CLIENT_DEFAULT}) +define_channel_server_options(${OPTION_SERVER_DEFAULT}) + diff --git a/channels/ainput/client/CMakeLists.txt b/channels/ainput/client/CMakeLists.txt new file mode 100644 index 0000000..4cf2d22 --- /dev/null +++ b/channels/ainput/client/CMakeLists.txt @@ -0,0 +1,34 @@ +# FreeRDP: A Remote Desktop Protocol Implementation +# FreeRDP cmake build script +# +# Copyright 2022 Armin Novak +# Copyright 2022 Thincast Technologies GmbH +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +define_channel_client("ainput") + +set(${MODULE_PREFIX}_SRCS + ainput_main.c + ainput_main.h) + +include_directories(..) + +add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} TRUE "DVCPluginEntry") + +if (WITH_DEBUG_SYMBOLS AND MSVC AND NOT BUILTIN_CHANNELS AND BUILD_SHARED_LIBS) + install(FILES ${PROJECT_BINARY_DIR}/${MODULE_NAME}.pdb DESTINATION ${FREERDP_ADDIN_PATH} COMPONENT symbols) +endif() + +target_link_libraries(${MODULE_NAME} winpr) +set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Client") diff --git a/channels/ainput/client/ainput_main.c b/channels/ainput/client/ainput_main.c new file mode 100644 index 0000000..bf4ce26 --- /dev/null +++ b/channels/ainput/client/ainput_main.c @@ -0,0 +1,317 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Advanced Input Virtual Channel Extension + * + * Copyright 2022 Armin Novak + * Copyright 2022 Thincast Technologies GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include +#include +#include +#include + +#include "ainput_main.h" +#include +#include +#include + +#include "../common/ainput_common.h" + +#define WINPR_ASSERT(x) assert(x) + +#define TAG CHANNELS_TAG("ainput.client") + +typedef struct AINPUT_CHANNEL_CALLBACK_ AINPUT_CHANNEL_CALLBACK; +struct AINPUT_CHANNEL_CALLBACK_ +{ + IWTSVirtualChannelCallback iface; + + IWTSPlugin* plugin; + IWTSVirtualChannelManager* channel_mgr; + IWTSVirtualChannel* channel; +}; + +typedef struct AINPUT_LISTENER_CALLBACK_ AINPUT_LISTENER_CALLBACK; +struct AINPUT_LISTENER_CALLBACK_ +{ + IWTSListenerCallback iface; + + IWTSPlugin* plugin; + IWTSVirtualChannelManager* channel_mgr; + AINPUT_CHANNEL_CALLBACK* channel_callback; +}; + +typedef struct AINPUT_PLUGIN_ AINPUT_PLUGIN; +struct AINPUT_PLUGIN_ +{ + IWTSPlugin iface; + + AINPUT_LISTENER_CALLBACK* listener_callback; + IWTSListener* listener; + UINT32 MajorVersion; + UINT32 MinorVersion; + BOOL initialized; +}; + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT ainput_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, wStream* data) +{ + UINT16 type; + AINPUT_PLUGIN* ainput; + AINPUT_CHANNEL_CALLBACK* callback = (AINPUT_CHANNEL_CALLBACK*)pChannelCallback; + + WINPR_ASSERT(callback); + WINPR_ASSERT(data); + + ainput = (AINPUT_PLUGIN*)callback->plugin; + WINPR_ASSERT(ainput); + + if (Stream_GetRemainingLength(data) < 2) + return ERROR_NO_DATA; + Stream_Read_UINT16(data, type); + switch (type) + { + case MSG_AINPUT_VERSION: + if (Stream_GetRemainingLength(data) < 8) + return ERROR_NO_DATA; + Stream_Read_UINT32(data, ainput->MajorVersion); + Stream_Read_UINT32(data, ainput->MinorVersion); + break; + default: + WLog_WARN(TAG, "Received unsupported message type 0x%04" PRIx16, type); + break; + } + + return CHANNEL_RC_OK; +} + +static UINT ainput_send_input_event(AInputClientContext* context, UINT64 flags, INT32 x, INT32 y) +{ + AINPUT_PLUGIN* ainput; + AINPUT_CHANNEL_CALLBACK* callback; + BYTE buffer[32] = { 0 }; + UINT64 time; + wStream sbuffer = { 0 }; + wStream* s = &sbuffer; + + Stream_StaticInit(&sbuffer, buffer, sizeof(buffer)); + + WINPR_ASSERT(s); + WINPR_ASSERT(context); + + time = GetTickCount64(); + ainput = (AINPUT_PLUGIN*)context->handle; + WINPR_ASSERT(ainput); + WINPR_ASSERT(ainput->listener_callback); + + if (ainput->MajorVersion != AINPUT_VERSION_MAJOR) + { + WLog_WARN(TAG, "Unsupported channel version %" PRIu32 ".%" PRIu32 ", aborting.", + ainput->MajorVersion, ainput->MinorVersion); + return CHANNEL_RC_UNSUPPORTED_VERSION; + } + callback = ainput->listener_callback->channel_callback; + WINPR_ASSERT(callback); + + { + char buffer[128] = { 0 }; + WLog_VRB(TAG, "[%s] sending timestamp=0x%08" PRIx64 ", flags=%s, %" PRId32 "x%" PRId32, + __FUNCTION__, time, ainput_flags_to_string(flags, buffer, sizeof(buffer)), x, y); + } + + /* Message type */ + Stream_Write_UINT16(s, MSG_AINPUT_MOUSE); + + /* Event data */ + Stream_Write_UINT64(s, time); + Stream_Write_UINT64(s, flags); + Stream_Write_INT32(s, x); + Stream_Write_INT32(s, y); + Stream_SealLength(s); + + /* ainput back what we have received. AINPUT does not have any message IDs. */ + WINPR_ASSERT(callback->channel); + WINPR_ASSERT(callback->channel->Write); + return callback->channel->Write(callback->channel, (ULONG)Stream_Length(s), Stream_Buffer(s), + NULL); +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT ainput_on_close(IWTSVirtualChannelCallback* pChannelCallback) +{ + AINPUT_CHANNEL_CALLBACK* callback = (AINPUT_CHANNEL_CALLBACK*)pChannelCallback; + + free(callback); + + return CHANNEL_RC_OK; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT ainput_on_new_channel_connection(IWTSListenerCallback* pListenerCallback, + IWTSVirtualChannel* pChannel, BYTE* Data, + BOOL* pbAccept, + IWTSVirtualChannelCallback** ppCallback) +{ + AINPUT_CHANNEL_CALLBACK* callback; + AINPUT_LISTENER_CALLBACK* listener_callback = (AINPUT_LISTENER_CALLBACK*)pListenerCallback; + + WINPR_ASSERT(listener_callback); + WINPR_UNUSED(Data); + WINPR_UNUSED(pbAccept); + + callback = (AINPUT_CHANNEL_CALLBACK*)calloc(1, sizeof(AINPUT_CHANNEL_CALLBACK)); + + if (!callback) + { + WLog_ERR(TAG, "calloc failed!"); + return CHANNEL_RC_NO_MEMORY; + } + + callback->iface.OnDataReceived = ainput_on_data_received; + callback->iface.OnClose = ainput_on_close; + callback->plugin = listener_callback->plugin; + callback->channel_mgr = listener_callback->channel_mgr; + callback->channel = pChannel; + listener_callback->channel_callback = callback; + + *ppCallback = &callback->iface; + + return CHANNEL_RC_OK; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT ainput_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManager* pChannelMgr) +{ + UINT status; + AINPUT_PLUGIN* ainput = (AINPUT_PLUGIN*)pPlugin; + + WINPR_ASSERT(ainput); + + if (ainput->initialized) + { + WLog_ERR(TAG, "[%s] channel initialized twice, aborting", AINPUT_DVC_CHANNEL_NAME); + return ERROR_INVALID_DATA; + } + ainput->listener_callback = + (AINPUT_LISTENER_CALLBACK*)calloc(1, sizeof(AINPUT_LISTENER_CALLBACK)); + + if (!ainput->listener_callback) + { + WLog_ERR(TAG, "calloc failed!"); + return CHANNEL_RC_NO_MEMORY; + } + + ainput->listener_callback->iface.OnNewChannelConnection = ainput_on_new_channel_connection; + ainput->listener_callback->plugin = pPlugin; + ainput->listener_callback->channel_mgr = pChannelMgr; + + status = pChannelMgr->CreateListener(pChannelMgr, AINPUT_DVC_CHANNEL_NAME, 0, + &ainput->listener_callback->iface, &ainput->listener); + + ainput->listener->pInterface = ainput->iface.pInterface; + ainput->initialized = status == CHANNEL_RC_OK; + return status; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT ainput_plugin_terminated(IWTSPlugin* pPlugin) +{ + AINPUT_PLUGIN* ainput = (AINPUT_PLUGIN*)pPlugin; + if (ainput && ainput->listener_callback) + { + IWTSVirtualChannelManager* mgr = ainput->listener_callback->channel_mgr; + if (mgr) + IFCALL(mgr->DestroyListener, mgr, ainput->listener); + } + if (ainput) + { + free(ainput->listener_callback); + free(ainput->iface.pInterface); + } + free(ainput); + + return CHANNEL_RC_OK; +} + +#ifdef BUILTIN_CHANNELS +#define DVCPluginEntry ainput_DVCPluginEntry +#else +#define DVCPluginEntry FREERDP_API DVCPluginEntry +#endif + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) +{ + UINT status = CHANNEL_RC_OK; + AINPUT_PLUGIN* ainput = (AINPUT_PLUGIN*)pEntryPoints->GetPlugin(pEntryPoints, "ainput"); + + if (!ainput) + { + AInputClientContext* context = (AInputClientContext*)calloc(1, sizeof(AInputClientContext)); + ainput = (AINPUT_PLUGIN*)calloc(1, sizeof(AINPUT_PLUGIN)); + + if (!ainput || !context) + { + free(context); + free(ainput); + + WLog_ERR(TAG, "calloc failed!"); + return CHANNEL_RC_NO_MEMORY; + } + + ainput->iface.Initialize = ainput_plugin_initialize; + ainput->iface.Terminated = ainput_plugin_terminated; + + context->handle = (void*)ainput; + context->AInputSendInputEvent = ainput_send_input_event; + ainput->iface.pInterface = (void*)context; + + status = pEntryPoints->RegisterPlugin(pEntryPoints, AINPUT_CHANNEL_NAME, &ainput->iface); + } + + return status; +} diff --git a/channels/ainput/client/ainput_main.h b/channels/ainput/client/ainput_main.h new file mode 100644 index 0000000..8a19ad9 --- /dev/null +++ b/channels/ainput/client/ainput_main.h @@ -0,0 +1,43 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Advanced Input Virtual Channel Extension + * + * Copyright 2022 Armin Novak + * Copyright 2022 Thincast Technologies GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FREERDP_CHANNEL_AINPUT_CLIENT_MAIN_H +#define FREERDP_CHANNEL_AINPUT_CLIENT_MAIN_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include + +#define DVC_TAG CHANNELS_TAG("ainput.client") +#ifdef WITH_DEBUG_DVC +#define DEBUG_DVC(...) WLog_DBG(DVC_TAG, __VA_ARGS__) +#else +#define DEBUG_DVC(...) \ + do \ + { \ + } while (0) +#endif + +#endif /* FREERDP_CHANNEL_AINPUT_CLIENT_MAIN_H */ diff --git a/channels/ainput/common/ainput_common.h b/channels/ainput/common/ainput_common.h new file mode 100644 index 0000000..bc1be04 --- /dev/null +++ b/channels/ainput/common/ainput_common.h @@ -0,0 +1,81 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Audio Input Redirection Virtual Channel + * + * Copyright 2022 Armin Novak + * Copyright 2022 Thincast Technologies GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FREERDP_INT_AINPUT_COMMON_H +#define FREERDP_INT_AINPUT_COMMON_H + +#include +#include + +#include + +static INLINE void ainput_append(char* buffer, size_t size, const char* what, BOOL separator) +{ + size_t have; + size_t toadd; + + assert(buffer || (size == 0)); + assert(what); + + have = strnlen(buffer, size); + toadd = strlen(what); + if (have > 0) + toadd += 1; + + if (size - have < toadd + 1) + return; + + if (have > 0) + strcat(buffer, separator ? "|" : " "); + strcat(buffer, what); +} + +static INLINE const char* ainput_flags_to_string(UINT64 flags, char* buffer, size_t size) +{ + char number[32] = { 0 }; + + if (flags & AINPUT_FLAGS_HAVE_REL) + ainput_append(buffer, size, "AINPUT_FLAGS_HAVE_REL", TRUE); + if (flags & AINPUT_FLAGS_WHEEL) + ainput_append(buffer, size, "AINPUT_FLAGS_WHEEL", TRUE); + if (flags & AINPUT_FLAGS_MOVE) + ainput_append(buffer, size, "AINPUT_FLAGS_MOVE", TRUE); + if (flags & AINPUT_FLAGS_DOWN) + ainput_append(buffer, size, "AINPUT_FLAGS_DOWN", TRUE); + if (flags & AINPUT_FLAGS_REL) + ainput_append(buffer, size, "AINPUT_FLAGS_REL", TRUE); + if (flags & AINPUT_FLAGS_BUTTON1) + ainput_append(buffer, size, "AINPUT_FLAGS_BUTTON1", TRUE); + if (flags & AINPUT_FLAGS_BUTTON2) + ainput_append(buffer, size, "AINPUT_FLAGS_BUTTON2", TRUE); + if (flags & AINPUT_FLAGS_BUTTON3) + ainput_append(buffer, size, "AINPUT_FLAGS_BUTTON3", TRUE); + if (flags & AINPUT_XFLAGS_BUTTON1) + ainput_append(buffer, size, "AINPUT_XFLAGS_BUTTON1", TRUE); + if (flags & AINPUT_XFLAGS_BUTTON2) + ainput_append(buffer, size, "AINPUT_XFLAGS_BUTTON2", TRUE); + + _snprintf(number, sizeof(number), "[0x%08" PRIx64 "]", flags); + ainput_append(buffer, size, number, FALSE); + + return buffer; +} + +#endif /* FREERDP_INT_AINPUT_COMMON_H */ diff --git a/channels/ainput/server/CMakeLists.txt b/channels/ainput/server/CMakeLists.txt new file mode 100644 index 0000000..59be263 --- /dev/null +++ b/channels/ainput/server/CMakeLists.txt @@ -0,0 +1,27 @@ +# FreeRDP: A Remote Desktop Protocol Implementation +# FreeRDP cmake build script +# +# Copyright 2022 Armin Novak +# Copyright 2022 Thincast Technologies GmbH +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +define_channel_server("ainput") + +set(${MODULE_PREFIX}_SRCS + ainput_main.c) + +add_channel_server_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "DVCPluginEntry") + +target_link_libraries(${MODULE_NAME} freerdp) +set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Server") diff --git a/channels/ainput/server/ainput_main.c b/channels/ainput/server/ainput_main.c new file mode 100644 index 0000000..670b668 --- /dev/null +++ b/channels/ainput/server/ainput_main.c @@ -0,0 +1,546 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Advanced Input Virtual Channel Extension + * + * Copyright 2022 Armin Novak + * Copyright 2022 Thincast Technologies GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "../common/ainput_common.h" + +#define WINPR_ASSERT(x) assert(x) + +#define TAG CHANNELS_TAG("ainput.server") + +typedef enum +{ + AINPUT_INITIAL, + AINPUT_OPENED, + AINPUT_VERSION_SENT, +} eAInputChannelState; + +typedef struct +{ + ainput_server_context context; + + BOOL opened; + + HANDLE stopEvent; + + HANDLE thread; + void* ainput_channel; + + DWORD SessionId; + + BOOL isOpened; + BOOL externalThread; + + /* Channel state */ + eAInputChannelState state; + + wStream* buffer; +} ainput_server; + +static UINT ainput_server_context_poll(ainput_server_context* context); +static BOOL ainput_server_context_handle(ainput_server_context* context, HANDLE* handle); +static UINT ainput_server_context_poll_int(ainput_server_context* context); + +static BOOL ainput_server_is_open(ainput_server_context* context) +{ + ainput_server* ainput = (ainput_server*)context; + + WINPR_ASSERT(ainput); + return ainput->isOpened; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT ainput_server_open_channel(ainput_server* ainput) +{ + DWORD Error; + HANDLE hEvent; + DWORD StartTick; + DWORD BytesReturned = 0; + PULONG pSessionId = NULL; + + WINPR_ASSERT(ainput); + + if (WTSQuerySessionInformationA(ainput->context.vcm, WTS_CURRENT_SESSION, WTSSessionId, + (LPSTR*)&pSessionId, &BytesReturned) == FALSE) + { + WLog_ERR(TAG, "WTSQuerySessionInformationA failed!"); + return ERROR_INTERNAL_ERROR; + } + + ainput->SessionId = (DWORD)*pSessionId; + WTSFreeMemory(pSessionId); + hEvent = WTSVirtualChannelManagerGetEventHandle(ainput->context.vcm); + StartTick = GetTickCount(); + + while (ainput->ainput_channel == NULL) + { + if (WaitForSingleObject(hEvent, 1000) == WAIT_FAILED) + { + Error = GetLastError(); + WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", Error); + return Error; + } + + ainput->ainput_channel = WTSVirtualChannelOpenEx(ainput->SessionId, AINPUT_DVC_CHANNEL_NAME, + WTS_CHANNEL_OPTION_DYNAMIC); + + if (ainput->ainput_channel) + break; + + Error = GetLastError(); + + if (Error == ERROR_NOT_FOUND) + break; + + if (GetTickCount() - StartTick > 5000) + break; + } + + return ainput->ainput_channel ? CHANNEL_RC_OK : ERROR_INTERNAL_ERROR; +} + +static UINT ainput_server_send_version(ainput_server* ainput) +{ + ULONG written; + wStream* s; + + WINPR_ASSERT(ainput); + + s = ainput->buffer; + WINPR_ASSERT(s); + + Stream_SetPosition(s, 0); + if (!Stream_EnsureCapacity(s, 10)) + return ERROR_OUTOFMEMORY; + + Stream_Write_UINT16(s, MSG_AINPUT_VERSION); + Stream_Write_UINT32(s, AINPUT_VERSION_MAJOR); /* Version (4 bytes) */ + Stream_Write_UINT32(s, AINPUT_VERSION_MINOR); /* Version (4 bytes) */ + + WINPR_ASSERT(Stream_GetPosition(s) <= ULONG_MAX); + if (!WTSVirtualChannelWrite(ainput->ainput_channel, (PCHAR)Stream_Buffer(s), + (ULONG)Stream_GetPosition(s), &written)) + { + WLog_ERR(TAG, "WTSVirtualChannelWrite failed!"); + return ERROR_INTERNAL_ERROR; + } + + return CHANNEL_RC_OK; +} + +static UINT ainput_server_recv_mouse_event(ainput_server* ainput, wStream* s) +{ + UINT error = CHANNEL_RC_OK; + UINT64 flags, time; + INT32 x, y; + char buffer[128] = { 0 }; + + WINPR_ASSERT(ainput); + WINPR_ASSERT(s); + + if (Stream_GetRemainingLength(s) < 24) + return ERROR_NO_DATA; + + Stream_Read_UINT64(s, time); + Stream_Read_UINT64(s, flags); + Stream_Read_INT32(s, x); + Stream_Read_INT32(s, y); + + WLog_VRB(TAG, "[%s] received: time=0x%08" PRIx64 ", flags=%s, %" PRId32 "x%" PRId32, + __FUNCTION__, time, ainput_flags_to_string(flags, buffer, sizeof(buffer)), x, y); + IFCALLRET(ainput->context.MouseEvent, error, &ainput->context, time, flags, x, y); + + return error; +} + +static HANDLE ainput_server_get_channel_handle(ainput_server* ainput) +{ + BYTE* buffer = NULL; + DWORD BytesReturned = 0; + HANDLE ChannelEvent = NULL; + + WINPR_ASSERT(ainput); + + if (WTSVirtualChannelQuery(ainput->ainput_channel, WTSVirtualEventHandle, &buffer, + &BytesReturned) == TRUE) + { + if (BytesReturned == sizeof(HANDLE)) + CopyMemory(&ChannelEvent, buffer, sizeof(HANDLE)); + + WTSFreeMemory(buffer); + } + + return ChannelEvent; +} + +static DWORD WINAPI ainput_server_thread_func(LPVOID arg) +{ + DWORD nCount; + HANDLE events[2] = { 0 }; + ainput_server* ainput = (ainput_server*)arg; + UINT error = CHANNEL_RC_OK; + DWORD status; + + WINPR_ASSERT(ainput); + + nCount = 0; + events[nCount++] = ainput->stopEvent; + + while ((error == CHANNEL_RC_OK) && (WaitForSingleObject(events[0], 0) != WAIT_OBJECT_0)) + { + switch (ainput->state) + { + case AINPUT_OPENED: + events[1] = ainput_server_get_channel_handle(ainput); + nCount = 2; + status = WaitForMultipleObjects(nCount, events, FALSE, 100); + switch (status) + { + case WAIT_TIMEOUT: + case WAIT_OBJECT_0 + 1: + case WAIT_OBJECT_0: + error = ainput_server_context_poll_int(&ainput->context); + + case WAIT_FAILED: + default: + error = ERROR_INTERNAL_ERROR; + break; + } + break; + case AINPUT_VERSION_SENT: + status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE); + switch (status) + { + case WAIT_TIMEOUT: + case WAIT_OBJECT_0 + 1: + case WAIT_OBJECT_0: + error = ainput_server_context_poll_int(&ainput->context); + + case WAIT_FAILED: + default: + error = ERROR_INTERNAL_ERROR; + break; + } + break; + default: + error = ainput_server_context_poll_int(&ainput->context); + break; + } + } + + WTSVirtualChannelClose(ainput->ainput_channel); + ainput->ainput_channel = NULL; + + if (error && ainput->context.rdpcontext) + setChannelError(ainput->context.rdpcontext, error, + "ainput_server_thread_func reported an error"); + + ExitThread(error); + return error; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT ainput_server_open(ainput_server_context* context) +{ + ainput_server* ainput = (ainput_server*)context; + + WINPR_ASSERT(ainput); + + if (!ainput->externalThread && (ainput->thread == NULL)) + { + ainput->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + if (!ainput->stopEvent) + { + WLog_ERR(TAG, "CreateEvent failed!"); + return ERROR_INTERNAL_ERROR; + } + + ainput->thread = CreateThread(NULL, 0, ainput_server_thread_func, ainput, 0, NULL); + if (!ainput->thread) + { + WLog_ERR(TAG, "CreateEvent failed!"); + CloseHandle(ainput->stopEvent); + ainput->stopEvent = NULL; + return ERROR_INTERNAL_ERROR; + } + } + ainput->isOpened = TRUE; + + return CHANNEL_RC_OK; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT ainput_server_close(ainput_server_context* context) +{ + UINT error = CHANNEL_RC_OK; + ainput_server* ainput = (ainput_server*)context; + + WINPR_ASSERT(ainput); + + if (!ainput->externalThread && ainput->thread) + { + SetEvent(ainput->stopEvent); + + if (WaitForSingleObject(ainput->thread, INFINITE) == WAIT_FAILED) + { + error = GetLastError(); + WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", error); + return error; + } + + CloseHandle(ainput->thread); + CloseHandle(ainput->stopEvent); + ainput->thread = NULL; + ainput->stopEvent = NULL; + } + if (ainput->externalThread) + { + if (ainput->state != AINPUT_INITIAL) + { + WTSVirtualChannelClose(ainput->ainput_channel); + ainput->ainput_channel = NULL; + ainput->state = AINPUT_INITIAL; + } + } + ainput->isOpened = FALSE; + + return error; +} + +static UINT ainput_server_initialize(ainput_server_context* context, BOOL externalThread) +{ + UINT error = CHANNEL_RC_OK; + ainput_server* ainput = (ainput_server*)context; + + WINPR_ASSERT(ainput); + + if (ainput->isOpened) + { + WLog_WARN(TAG, "Application error: AINPUT channel already initialized, calling in this " + "state is not possible!"); + return ERROR_INVALID_STATE; + } + ainput->externalThread = externalThread; + return error; +} + +ainput_server_context* ainput_server_context_new(HANDLE vcm) +{ + ainput_server* ainput = (ainput_server*)calloc(1, sizeof(ainput_server)); + + if (!ainput) + return NULL; + + ainput->context.vcm = vcm; + ainput->context.Open = ainput_server_open; + ainput->context.IsOpen = ainput_server_is_open; + ainput->context.Close = ainput_server_close; + ainput->context.Initialize = ainput_server_initialize; + ainput->context.Poll = ainput_server_context_poll; + ainput->context.ChannelHandle = ainput_server_context_handle; + + ainput->buffer = Stream_New(NULL, 4096); + if (!ainput->buffer) + goto fail; + return &ainput->context; +fail: + ainput_server_context_free(ainput); + return NULL; +} + +void ainput_server_context_free(ainput_server_context* context) +{ + ainput_server* ainput = (ainput_server*)context; + if (ainput) + { + ainput_server_close(context); + Stream_Free(ainput->buffer, TRUE); + } + free(ainput); +} + +static UINT ainput_process_message(ainput_server* ainput) +{ + BOOL rc; + UINT error = ERROR_INTERNAL_ERROR; + ULONG BytesReturned; + UINT16 MessageId; + wStream* s; + + WINPR_ASSERT(ainput); + WINPR_ASSERT(ainput->ainput_channel); + + s = ainput->buffer; + WINPR_ASSERT(s); + + Stream_SetPosition(s, 0); + rc = WTSVirtualChannelRead(ainput->ainput_channel, 0, NULL, 0, &BytesReturned); + if (!rc) + goto out; + + if (BytesReturned < 2) + { + error = CHANNEL_RC_OK; + goto out; + } + + if (!Stream_EnsureRemainingCapacity(s, BytesReturned)) + { + WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!"); + error = CHANNEL_RC_NO_MEMORY; + goto out; + } + + if (WTSVirtualChannelRead(ainput->ainput_channel, 0, (PCHAR)Stream_Buffer(s), + (ULONG)Stream_Capacity(s), &BytesReturned) == FALSE) + { + WLog_ERR(TAG, "WTSVirtualChannelRead failed!"); + goto out; + } + + Stream_SetLength(s, BytesReturned); + Stream_Read_UINT16(s, MessageId); + + switch (MessageId) + { + case MSG_AINPUT_MOUSE: + error = ainput_server_recv_mouse_event(ainput, s); + break; + + default: + WLog_ERR(TAG, "audin_server_thread_func: unknown MessageId %" PRIu8 "", MessageId); + break; + } + +out: + if (error) + WLog_ERR(TAG, "Response failed with error %" PRIu32 "!", error); + + return error; +} + +BOOL ainput_server_context_handle(ainput_server_context* context, HANDLE* handle) +{ + ainput_server* ainput = (ainput_server*)context; + WINPR_ASSERT(ainput); + WINPR_ASSERT(handle); + + if (!ainput->externalThread) + return FALSE; + if (ainput->state == AINPUT_INITIAL) + return FALSE; + *handle = ainput_server_get_channel_handle(ainput); + return TRUE; +} + +UINT ainput_server_context_poll_int(ainput_server_context* context) +{ + ainput_server* ainput = (ainput_server*)context; + UINT error = ERROR_INTERNAL_ERROR; + + WINPR_ASSERT(ainput); + + switch (ainput->state) + { + case AINPUT_INITIAL: + error = ainput_server_open_channel(ainput); + if (error) + WLog_ERR(TAG, "ainput_server_open_channel failed with error %" PRIu32 "!", error); + else + ainput->state = AINPUT_OPENED; + break; + case AINPUT_OPENED: + { + BYTE* buffer = NULL; + DWORD BytesReturned = 0; + + if (WTSVirtualChannelQuery(ainput->ainput_channel, WTSVirtualChannelReady, &buffer, + &BytesReturned) != TRUE) + { + WLog_ERR(TAG, "WTSVirtualChannelReady failed,"); + } + else + { + if (*buffer != 0) + { + error = ainput_server_send_version(ainput); + if (error) + WLog_ERR(TAG, "audin_server_send_version failed with error %" PRIu32 "!", + error); + else + ainput->state = AINPUT_VERSION_SENT; + } + else + error = CHANNEL_RC_OK; + } + WTSFreeMemory(buffer); + } + break; + case AINPUT_VERSION_SENT: + error = ainput_process_message(ainput); + break; + + default: + WLog_ERR(TAG, "AINPUT chanel is in invalid state %d", ainput->state); + break; + } + + return error; +} + +UINT ainput_server_context_poll(ainput_server_context* context) +{ + ainput_server* ainput = (ainput_server*)context; + + WINPR_ASSERT(ainput); + if (!ainput->externalThread) + return ERROR_INTERNAL_ERROR; + return ainput_server_context_poll_int(context); +} diff --git a/channels/audin/client/audin_main.c b/channels/audin/client/audin_main.c index a5b9416..81a6e8f 100644 --- a/channels/audin/client/audin_main.c +++ b/channels/audin/client/audin_main.c @@ -444,11 +444,8 @@ static BOOL audin_open_device(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALLBACK* callb return FALSE; } - if (!supported) - { - if (!freerdp_dsp_context_reset(audin->dsp_context, audin->format)) - return FALSE; - } + if (!freerdp_dsp_context_reset(audin->dsp_context, audin->format)) + return FALSE; IFCALLRET(audin->device->Open, error, audin->device, audin_receive_wave_data, callback); diff --git a/channels/audin/client/winmm/audin_winmm.c b/channels/audin/client/winmm/audin_winmm.c index 92a7785..7538672 100644 --- a/channels/audin/client/winmm/audin_winmm.c +++ b/channels/audin/client/winmm/audin_winmm.c @@ -345,7 +345,9 @@ static UINT audin_winmm_set_format(IAudinDevice* device, const AUDIO_FORMAT* for if (ppwfx->nBlockAlign != 2) { ppwfx->nBlockAlign = 2; + ppwfx->nAvgBytesPerSec = ppwfx->nSamplesPerSec * ppwfx->nBlockAlign; } + if (!test_format_supported(ppwfx)) return ERROR_INVALID_PARAMETER; winmm->pwfx_cur = ppwfx; diff --git a/channels/disp/server/disp_main.c b/channels/disp/server/disp_main.c index a764acd..64e96c3 100644 --- a/channels/disp/server/disp_main.c +++ b/channels/disp/server/disp_main.c @@ -72,6 +72,24 @@ error: return NULL; } +static void disp_server_sanitize_monitor_layout(DISPLAY_CONTROL_MONITOR_LAYOUT* monitor) +{ + if (monitor->PhysicalWidth < DISPLAY_CONTROL_MIN_PHYSICAL_MONITOR_WIDTH || + monitor->PhysicalWidth > DISPLAY_CONTROL_MAX_PHYSICAL_MONITOR_WIDTH || + monitor->PhysicalHeight < DISPLAY_CONTROL_MIN_PHYSICAL_MONITOR_HEIGHT || + monitor->PhysicalHeight > DISPLAY_CONTROL_MAX_PHYSICAL_MONITOR_HEIGHT) + { + if (monitor->PhysicalWidth != 0 || monitor->PhysicalHeight != 0) + WLog_DBG( + TAG, + "Sanitizing invalid physical monitor size. Old physical monitor size: [%" PRIu32 + ", %" PRIu32 "]", + monitor->PhysicalWidth, monitor->PhysicalHeight); + + monitor->PhysicalWidth = monitor->PhysicalHeight = 0; + } +} + static BOOL disp_server_is_monitor_layout_valid(DISPLAY_CONTROL_MONITOR_LAYOUT* monitor) { if (monitor->Width < DISPLAY_CONTROL_MIN_MONITOR_WIDTH || @@ -88,22 +106,6 @@ static BOOL disp_server_is_monitor_layout_valid(DISPLAY_CONTROL_MONITOR_LAYOUT* return FALSE; } - if (monitor->PhysicalWidth < DISPLAY_CONTROL_MIN_PHYSICAL_MONITOR_WIDTH || - monitor->PhysicalWidth > DISPLAY_CONTROL_MAX_PHYSICAL_MONITOR_WIDTH) - { - WLog_WARN(TAG, "Received invalid value for monitor->PhysicalWidth: %" PRIu32 "", - monitor->PhysicalWidth); - return FALSE; - } - - if (monitor->PhysicalHeight < DISPLAY_CONTROL_MIN_PHYSICAL_MONITOR_HEIGHT || - monitor->PhysicalHeight > DISPLAY_CONTROL_MAX_PHYSICAL_MONITOR_HEIGHT) - { - WLog_WARN(TAG, "Received invalid value for monitor->Height: %" PRIu32 "", - monitor->PhysicalHeight); - return FALSE; - } - switch (monitor->Orientation) { case ORIENTATION_LANDSCAPE: @@ -183,6 +185,8 @@ static UINT disp_recv_display_control_monitor_layout_pdu(wStream* s, DispServerC Stream_Read_UINT32(s, monitor->Orientation); /* Orientation (4 bytes) */ Stream_Read_UINT32(s, monitor->DesktopScaleFactor); /* DesktopScaleFactor (4 bytes) */ Stream_Read_UINT32(s, monitor->DeviceScaleFactor); /* DeviceScaleFactor (4 bytes) */ + + disp_server_sanitize_monitor_layout(monitor); WLog_DBG(TAG, "\t%d : Flags: 0x%08" PRIX32 " Left/Top: (%" PRId32 ",%" PRId32 ") W/H=%" PRIu32 "x%" PRIu32 ")", diff --git a/channels/rdpdr/client/rdpdr_main.c b/channels/rdpdr/client/rdpdr_main.c index 617ea42..309d24c 100644 --- a/channels/rdpdr/client/rdpdr_main.c +++ b/channels/rdpdr/client/rdpdr_main.c @@ -33,6 +33,8 @@ #include #include +#include + #include #include #include @@ -204,7 +206,6 @@ LRESULT CALLBACK hotplug_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) drive.Type = RDPDR_DTYP_FILESYSTEM; drive.Path = drive_path; - drive_path[1] = '\0'; drive.automount = TRUE; drive.Name = drive_name; devman_load_device_service(rdpdr->devman, @@ -583,7 +584,6 @@ static DWORD WINAPI drive_hotplug_thread_func(LPVOID arg) #else - static const char* automountLocations[] = { "/run/user/%lu/gvfs", "/run/media/%s", "/media/%s", "/media", "/mnt" }; @@ -591,16 +591,13 @@ static BOOL isAutomountLocation(const char* path) { const size_t nrLocations = sizeof(automountLocations) / sizeof(automountLocations[0]); size_t x; - char buffer[MAX_PATH]; + char buffer[MAX_PATH] = { 0 }; uid_t uid = getuid(); char uname[MAX_PATH] = { 0 }; + ULONG size = sizeof(uname) - 1; -#ifndef HAVE_GETLOGIN_R - strncpy(uname, getlogin(), sizeof(uname)); -#else - if (getlogin_r(uname, sizeof(uname)) != 0) + if (!GetUserNameExA(NameSamCompatible, uname, &size)) return FALSE; -#endif if (!path) return FALSE; @@ -656,7 +653,7 @@ static void handle_mountpoint(hotplug_dev* dev_array, size_t* size, const char* if (isAutomountLocation(mountpoint) && (*size < MAX_USB_DEVICES)) { dev_array[*size].path = _strdup(mountpoint); - dev_array[*size + 1].to_add = TRUE; + dev_array[*size].to_add = TRUE; (*size)++; } } diff --git a/channels/rdpei/server/rdpei_main.c b/channels/rdpei/server/rdpei_main.c index 80ab4b6..1e2dfe2 100644 --- a/channels/rdpei/server/rdpei_main.c +++ b/channels/rdpei/server/rdpei_main.c @@ -612,6 +612,7 @@ UINT rdpei_server_send_sc_ready_ex(RdpeiServerContext* context, UINT32 version, { ULONG written; RdpeiServerPrivate* priv = context->priv; + UINT32 pduLen = 4; if (priv->automataState != STATE_INITIAL) { @@ -621,14 +622,17 @@ UINT rdpei_server_send_sc_ready_ex(RdpeiServerContext* context, UINT32 version, Stream_SetPosition(priv->outputStream, 0); - if (!Stream_EnsureCapacity(priv->outputStream, RDPINPUT_HEADER_LENGTH + 4)) + if (version >= RDPINPUT_PROTOCOL_V300) + pduLen += 4; + + if (!Stream_EnsureCapacity(priv->outputStream, RDPINPUT_HEADER_LENGTH + pduLen)) { WLog_ERR(TAG, "Stream_EnsureCapacity failed!"); return CHANNEL_RC_NO_MEMORY; } Stream_Write_UINT16(priv->outputStream, EVENTID_SC_READY); - Stream_Write_UINT32(priv->outputStream, RDPINPUT_HEADER_LENGTH + 4); + Stream_Write_UINT32(priv->outputStream, RDPINPUT_HEADER_LENGTH + pduLen); Stream_Write_UINT32(priv->outputStream, version); if (version >= RDPINPUT_PROTOCOL_V300) Stream_Write_UINT32(priv->outputStream, features); diff --git a/channels/rdpgfx/rdpgfx_common.c b/channels/rdpgfx/rdpgfx_common.c index 79bbc9e..c0bc0b0 100644 --- a/channels/rdpgfx/rdpgfx_common.c +++ b/channels/rdpgfx/rdpgfx_common.c @@ -1,4 +1,4 @@ -/** +/** * FreeRDP: A Remote Desktop Protocol Implementation * Graphics Pipeline Extension * @@ -24,9 +24,12 @@ #endif #include +#include #include #include +#define WINPR_ASSERT(x) assert(x) + #define TAG CHANNELS_TAG("rdpgfx.common") #include "rdpgfx_common.h" @@ -110,6 +113,9 @@ const char* rdpgfx_get_codec_id_string(UINT16 codecId) */ UINT rdpgfx_read_header(wStream* s, RDPGFX_HEADER* header) { + WINPR_ASSERT(s); + WINPR_ASSERT(header); + if (Stream_GetRemainingLength(s) < 8) { WLog_ERR(TAG, "calloc failed!"); @@ -119,6 +125,13 @@ UINT rdpgfx_read_header(wStream* s, RDPGFX_HEADER* header) Stream_Read_UINT16(s, header->cmdId); /* cmdId (2 bytes) */ Stream_Read_UINT16(s, header->flags); /* flags (2 bytes) */ Stream_Read_UINT32(s, header->pduLength); /* pduLength (4 bytes) */ + + if ((header->pduLength < 8) || (Stream_GetRemainingLength(s) < (header->pduLength - 8))) + { + WLog_ERR(TAG, "header->pduLength %u less than 8!", header->pduLength); + return ERROR_INVALID_DATA; + } + return CHANNEL_RC_OK; } diff --git a/channels/server/channels.c b/channels/server/channels.c index 40c55ee..3714c5e 100644 --- a/channels/server/channels.c +++ b/channels/server/channels.c @@ -53,6 +53,12 @@ #include #include +#if defined(CHANNEL_AINPUT_SERVER) +#include +#endif + +extern void freerdp_channels_dummy(void); + void freerdp_channels_dummy(void) { audin_server_context* audin; @@ -91,6 +97,12 @@ void freerdp_channels_dummy(void) rdpgfx_server_context_free(rdpgfx); disp = disp_server_context_new(NULL); disp_server_context_free(disp); +#if defined(CHANNEL_AINPUT_SERVER) + { + ainput_server_context* ainput = ainput_server_context_new(NULL); + ainput_server_context_free(ainput); + } +#endif } /** diff --git a/channels/tsmf/client/ffmpeg/tsmf_ffmpeg.c b/channels/tsmf/client/ffmpeg/tsmf_ffmpeg.c index 0444ad0..cf0aa9b 100644 --- a/channels/tsmf/client/ffmpeg/tsmf_ffmpeg.c +++ b/channels/tsmf/client/ffmpeg/tsmf_ffmpeg.c @@ -615,7 +615,9 @@ static void tsmf_ffmpeg_free(ITSMFDecoder* decoder) static INIT_ONCE g_Initialized = INIT_ONCE_STATIC_INIT; static BOOL CALLBACK InitializeAvCodecs(PINIT_ONCE once, PVOID param, PVOID* context) { +#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 10, 100) avcodec_register_all(); +#endif return TRUE; } diff --git a/ci/cmake-preloads/config-android.txt b/ci/cmake-preloads/config-android.txt deleted file mode 100644 index bcb3446..0000000 --- a/ci/cmake-preloads/config-android.txt +++ /dev/null @@ -1,7 +0,0 @@ -message("PRELOADING android cache") -set(CMAKE_TOOLCHAIN_FILE "$ANDROID_NDK/build/cmake/android.toolchain.cmake" CACHE PATH "ToolChain file") -set(WITH_SANITIZE_ADDRESS ON) -set(FREERDP_EXTERNAL_SSL_PATH $ENV{ANDROID_SSL_PATH} CACHE PATH "android ssl") -# ANDROID_NDK and ANDROID_SDK must be set as environment variable -#set(ANDROID_NDK $ENV{ANDROID_SDK} CACHE PATH "Android NDK") -#set(ANDROID_SDK "${ANDROID_NDK}" CACHE PATH "android SDK") diff --git a/ci/cmake-preloads/config-debian-squeeze.txt b/ci/cmake-preloads/config-debian-squeeze.txt deleted file mode 100644 index c7319cf..0000000 --- a/ci/cmake-preloads/config-debian-squeeze.txt +++ /dev/null @@ -1,11 +0,0 @@ -message("PRELOADING cache") -set (WITH_MANPAGES OFF CACHE BOOL "man pages") -set (CMAKE_BUILD_TYPE "Debug" CACHE STRING "build type") -set (WITH_CUPS OFF CACHE BOOL "CUPS printing") -set (WITH_GSSAPI ON CACHE BOOL "Kerberos support") -set (WITH_ALSA OFF CACHE BOOL "alsa audio") -set (WITH_FFMPEG OFF CACHE BOOL "ffmepg support") -set (WITH_XV OFF CACHE BOOL "xvideo support") -set (BUILD_TESTING ON CACHE BOOL "build testing") -set (WITH_XSHM OFF CACHE BOOL "build with xshm support") -set (WITH_SANITIZE_ADDRESS ON) diff --git a/ci/cmake-preloads/config-ios.txt b/ci/cmake-preloads/config-ios.txt deleted file mode 100644 index 886c36a..0000000 --- a/ci/cmake-preloads/config-ios.txt +++ /dev/null @@ -1,7 +0,0 @@ -message("PRELOADING iOS cache") -set (CMAKE_TOOLCHAIN_FILE "cmake/iOSToolchain.cmake" CACHE PATH "ToolChain file") -set (FREERDP_IOS_EXTERNAL_SSL_PATH $ENV{FREERDP_IOS_EXTERNAL_SSL_PATH} CACHE PATH "android ssl") -set (CMAKE_BUILD_TYPE "Debug" CACHE STRING "build type") -set (IOS_PLATFORM "SIMULATOR" CACHE STRING "iso platfrorm to build") -set (WITH_SANITIZE_ADDRESS ON CACHE BOOL "build with address sanitizer") -set (WITH_CLIENT OFF CACHE BOOL "disable iOS client") diff --git a/ci/cmake-preloads/config-linux-all.txt b/ci/cmake-preloads/config-linux-all.txt deleted file mode 100644 index 4ba743e..0000000 --- a/ci/cmake-preloads/config-linux-all.txt +++ /dev/null @@ -1,53 +0,0 @@ -message("PRELOADING cache") -set (BUILD_TESTING ON CACHE BOOL "testing") -set (WITH_MANPAGES OFF CACHE BOOL "man pages") -set (CMAKE_BUILD_TYPE "Debug" CACHE STRING "build type") -set (BUILD_TESTING ON CACHE BOOL "build testing") -set (WITH_PULSE ON CACHE BOOL "pulse") -set (WITH_CHANNELS ON CACHE BOOL "channels") -set (BUILTIN_CHANNELS ON CACHE BOOL "static channels") -set (WITH_CUPS ON CACHE BOOL "cups") -set (WITH_WAYLAND ON CACHE BOOL "wayland") -set (WITH_GSSAPI ON CACHE BOOL "Kerberos support") -set (WITH_PCSC ON CACHE BOOL "PCSC") -set (WITH_JPEG ON CACHE BOOL "jpeg") -set (WITH_GSTREAMER_0_10 ON CACHE BOOL "gstreamer") -set (WITH_GSM ON CACHE BOOL "gsm") -set (CHANNEL_URBDRC ON CACHE BOOL "urbdrc") -set (CHANNEL_URBDRC_CLIENT ON CACHE BOOL "urbdrc client") -set (WITH_SERVER ON CACHE BOOL "server side") -set (WITH_DEBUG_ALL OFF CACHE BOOL "enable debug") -set (WITH_DEBUG_CAPABILITIES OFF CACHE BOOL "enable debug") -set (WITH_DEBUG_CERTIFICATE OFF CACHE BOOL "enable debug") -set (WITH_DEBUG_CHANNELS OFF CACHE BOOL "enable debug") -set (WITH_DEBUG_CLIPRDR OFF CACHE BOOL "enable debug") -set (WITH_DEBUG_RDPGFX OFF CACHE BOOL "enable debug") -set (WITH_DEBUG_DVC OFF CACHE BOOL "enable debug") -set (WITH_DEBUG_KBD OFF CACHE BOOL "enable debug") -set (WITH_DEBUG_LICENSE OFF CACHE BOOL "enable debug") -set (WITH_DEBUG_NEGO OFF CACHE BOOL "enable debug") -set (WITH_DEBUG_NLA OFF CACHE BOOL "enable debug") -set (WITH_DEBUG_NTLM OFF CACHE BOOL "enable debug") -set (WITH_DEBUG_RAIL OFF CACHE BOOL "enable debug") -set (WITH_DEBUG_RDP OFF CACHE BOOL "enable debug") -set (WITH_DEBUG_RDPEI OFF CACHE BOOL "enable debug") -set (WITH_DEBUG_REDIR OFF CACHE BOOL "enable debug") -set (WITH_DEBUG_RDPDR OFF CACHE BOOL "enable debug") -set (WITH_DEBUG_RFX OFF CACHE BOOL "enable debug") -set (WITH_DEBUG_SCARD OFF CACHE BOOL "enable debug") -set (WITH_DEBUG_SND OFF CACHE BOOL "enable debug") -set (WITH_DEBUG_SVC OFF CACHE BOOL "enable debug") -set (WITH_DEBUG_THREADS OFF CACHE BOOL "enable debug") -set (WITH_DEBUG_TIMEZONE OFF CACHE BOOL "enable debug") -set (WITH_DEBUG_TRANSPORT OFF CACHE BOOL "enable debug") -set (WITH_DEBUG_TSG OFF CACHE BOOL "enable debug") -set (WITH_DEBUG_TSMF OFF CACHE BOOL "enable debug") -set (WITH_DEBUG_WND OFF CACHE BOOL "enable debug") -set (WITH_DEBUG_X11 OFF CACHE BOOL "enable debug") -set (WITH_DEBUG_X11_CLIPRDR OFF CACHE BOOL "enable debug") -set (WITH_DEBUG_X11_LOCAL_MOVESIZE OFF CACHE BOOL "enable debug") -set (WITH_DEBUG_XV OFF CACHE BOOL "enable debug") -set (WITH_SAMPLE ON CACHE BOOL "samples") -set (WITH_NO_UNDEFINED ON CACHE BOOL "don't link with undefined symbols") -set (WITH_SANITIZE_ADDRESS ON) -set (WITH_PROXY_MODULES OFF CACHE BOOL "compile proxy modules") diff --git a/ci/cmake-preloads/config-macosx.txt b/ci/cmake-preloads/config-macosx.txt deleted file mode 100644 index a004dd9..0000000 --- a/ci/cmake-preloads/config-macosx.txt +++ /dev/null @@ -1,8 +0,0 @@ -message("PRELOADING mac cache") -set (WITH_MANPAGES OFF CACHE BOOL "man pages") -set (CMAKE_BUILD_TYPE "Debug" CACHE STRING "build type") -set (WITH_CUPS ON CACHE BOOL "CUPS printing") -set (CHANNEL_URBDRC OFF CACHE BOOL "USB redirection") -set (WITH_X11 ON CACHE BOOL "Enable X11") -set (BUILD_TESTING ON CACHE BOOL "build testing") -set (WITH_SANITIZE_ADDRESS ON) diff --git a/ci/cmake-preloads/config-ubuntu-1204.txt b/ci/cmake-preloads/config-ubuntu-1204.txt deleted file mode 100644 index c7319cf..0000000 --- a/ci/cmake-preloads/config-ubuntu-1204.txt +++ /dev/null @@ -1,11 +0,0 @@ -message("PRELOADING cache") -set (WITH_MANPAGES OFF CACHE BOOL "man pages") -set (CMAKE_BUILD_TYPE "Debug" CACHE STRING "build type") -set (WITH_CUPS OFF CACHE BOOL "CUPS printing") -set (WITH_GSSAPI ON CACHE BOOL "Kerberos support") -set (WITH_ALSA OFF CACHE BOOL "alsa audio") -set (WITH_FFMPEG OFF CACHE BOOL "ffmepg support") -set (WITH_XV OFF CACHE BOOL "xvideo support") -set (BUILD_TESTING ON CACHE BOOL "build testing") -set (WITH_XSHM OFF CACHE BOOL "build with xshm support") -set (WITH_SANITIZE_ADDRESS ON) diff --git a/ci/cmake-preloads/config-windows.txt b/ci/cmake-preloads/config-windows.txt deleted file mode 100644 index fcc78ae..0000000 --- a/ci/cmake-preloads/config-windows.txt +++ /dev/null @@ -1,6 +0,0 @@ -message("PRELOADING windows cache") -set (CMAKE_BUILD_TYPE "Debug" CACHE STRING "build type") -set (WITH_SERVER "ON" CACHE BOOL "Build server binaries") -set (CHANNEL_URBDRC OFF CACHE BOOL "USB redirection") -set (BUILD_TESTING ON CACHE BOOL "build testing") -set (WITH_SANITIZE_ADDRESS ON) diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index 7cba44e..af7606b 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -43,7 +43,10 @@ if(FREERDP_VENDOR AND WITH_CLIENT) add_subdirectory(iOS) endif() else() - add_subdirectory(Mac) + option(WITH_CLIENT_MAC "Build native mac client" ON) + if (WITH_CLIENT_MAC) + add_subdirectory(Mac) + endif() endif() endif() diff --git a/client/X11/xf_client.c b/client/X11/xf_client.c index 78852a7..4bdad53 100644 --- a/client/X11/xf_client.c +++ b/client/X11/xf_client.c @@ -27,6 +27,7 @@ #endif #include +#include #include #include @@ -1183,20 +1184,12 @@ static BOOL xf_pre_connect(freerdp* instance) if (!settings->Username && !settings->CredentialsFromStdin && !settings->SmartcardLogon) { - int rc; char login_name[MAX_PATH] = { 0 }; + ULONG size = sizeof(login_name) - 1; -#ifdef HAVE_GETLOGIN_R - rc = getlogin_r(login_name, sizeof(login_name)); -#else - strncpy(login_name, getlogin(), sizeof(login_name)); - rc = 0; -#endif - if (rc == 0) + if (GetUserNameExA(NameSamCompatible, login_name, &size)) { - settings->Username = _strdup(login_name); - - if (!settings->Username) + if (!freerdp_settings_set_string(settings, FreeRDP_Username, login_name)) return FALSE; WLog_INFO(TAG, "No user name set. - Using login name: %s", settings->Username); diff --git a/cmake/Findx264.cmake b/cmake/Findx264.cmake deleted file mode 100644 index f8df475..0000000 --- a/cmake/Findx264.cmake +++ /dev/null @@ -1,33 +0,0 @@ - -if (X264_INCLUDE_DIR AND X264_LIBRARY) - set(X264_FIND_QUIETLY TRUE) -endif (X264_INCLUDE_DIR AND X264_LIBRARY) - -find_path(X264_INCLUDE_DIR NAMES x264.h - PATH_SUFFIXES include - HINTS ${X264_ROOT}) -find_library(X264_LIBRARY - NAMES x264 - PATH_SUFFIXES lib - HINTS ${X264_ROOT}) - -include(FindPackageHandleStandardArgs) -FIND_PACKAGE_HANDLE_STANDARD_ARGS(x264 DEFAULT_MSG X264_LIBRARY X264_INCLUDE_DIR) - -if (X264_INCLUDE_DIR AND X264_LIBRARY) - set(X264_FOUND TRUE) - set(X264_LIBRARIES ${X264_LIBRARY}) -endif (X264_INCLUDE_DIR AND X264_LIBRARY) - -if (X264_FOUND) - if (NOT X264_FIND_QUIETLY) - message(STATUS "Found x264: ${X264_LIBRARIES}") - endif (NOT X264_FIND_QUIETLY) -else (X264_FOUND) - if (X264_FIND_REQUIRED) - message(FATAL_ERROR "x264 was not found") - endif(X264_FIND_REQUIRED) -endif (X264_FOUND) - -mark_as_advanced(X264_INCLUDE_DIR X264_LIBRARY) - diff --git a/cmake/iOSToolchain.cmake b/cmake/iOSToolchain.cmake deleted file mode 100644 index 1824ecb..0000000 --- a/cmake/iOSToolchain.cmake +++ /dev/null @@ -1,196 +0,0 @@ -# This file is based off of the Platform/Darwin.cmake and Platform/UnixPaths.cmake -# files which are included with CMake 2.8.4 -# It has been altered for iOS development - -# Options: -# -# IOS_PLATFORM = OS (default) or SIMULATOR -# This decides if SDKS will be selected from the iPhoneOS.platform or iPhoneSimulator.platform folders -# OS - the default, used to build for iPhone and iPad physical devices, which have an arm arch. -# SIMULATOR - used to build for the Simulator platforms, which have an x86 arch. -# -# CMAKE_IOS_DEVELOPER_ROOT = automatic(default) or /path/to/platform/Developer folder -# By default this location is automatcially chosen based on the IOS_PLATFORM value above. -# If set manually, it will override the default location and force the user of a particular Developer Platform -# -# CMAKE_IOS_SDK_ROOT = automatic(default) or /path/to/platform/Developer/SDKs/SDK folder -# By default this location is automatcially chosen based on the CMAKE_IOS_DEVELOPER_ROOT value. -# In this case it will always be the most up-to-date SDK found in the CMAKE_IOS_DEVELOPER_ROOT path. -# If set manually, this will force the use of a specific SDK version - -# Macros: -# -# set_xcode_property (TARGET XCODE_PROPERTY XCODE_VALUE) -# A convenience macro for setting xcode specific properties on targets -# example: set_xcode_property (myioslib IPHONEOS_DEPLOYMENT_TARGET "3.1") -# -# find_host_package (PROGRAM ARGS) -# A macro used to find executable programs on the host system, not within the iOS environment. -# Thanks to the android-cmake project for providing the command - - -# Standard settings -set (CMAKE_SYSTEM_NAME Darwin) -set (CMAKE_SYSTEM_VERSION 1) -set (UNIX True) -set (APPLE True) -set (IOS True) - -# Required as of cmake 2.8.10 -#set (CMAKE_OSX_DEPLOYMENT_TARGET "" CACHE STRING "Force unset of the deployment target for iOS" FORCE) - -# Determine the cmake host system version so we know where to find the iOS SDKs -find_program (CMAKE_UNAME uname /bin /usr/bin /usr/local/bin) -if (CMAKE_UNAME) - exec_program(uname ARGS -r OUTPUT_VARIABLE CMAKE_HOST_SYSTEM_VERSION) - string (REGEX REPLACE "^([0-9]+)\\.([0-9]+).*$" "\\1" DARWIN_MAJOR_VERSION "${CMAKE_HOST_SYSTEM_VERSION}") -endif (CMAKE_UNAME) - -# Force the compilers to gcc for iOS -include (CMakeForceCompiler) -CMAKE_FORCE_C_COMPILER (/usr/bin/clang Apple) -CMAKE_FORCE_CXX_COMPILER (/usr/bin/clang++ Apple) -set(CMAKE_AR ar CACHE FILEPATH "" FORCE) - -# Skip the platform compiler checks for cross compiling -#set (CMAKE_CXX_COMPILER_WORKS TRUE) -#set (CMAKE_C_COMPILER_WORKS TRUE) - -# All iOS/Darwin specific settings - some may be redundant -set (CMAKE_SHARED_LIBRARY_PREFIX "lib") -set (CMAKE_SHARED_LIBRARY_SUFFIX ".dylib") -set (CMAKE_SHARED_MODULE_PREFIX "lib") -set (CMAKE_SHARED_MODULE_SUFFIX ".so") -set (CMAKE_MODULE_EXISTS 1) -set (CMAKE_DL_LIBS "") - -set (CMAKE_C_OSX_COMPATIBILITY_VERSION_FLAG "-compatibility_version ") -set (CMAKE_C_OSX_CURRENT_VERSION_FLAG "-current_version ") -set (CMAKE_CXX_OSX_COMPATIBILITY_VERSION_FLAG "${CMAKE_C_OSX_COMPATIBILITY_VERSION_FLAG}") -set (CMAKE_CXX_OSX_CURRENT_VERSION_FLAG "${CMAKE_C_OSX_CURRENT_VERSION_FLAG}") - -# Hidden visibilty is required for cxx on iOS -set (CMAKE_C_FLAGS_INIT "") -set (CMAKE_CXX_FLAGS_INIT "-fvisibility=hidden -fvisibility-inlines-hidden -isysroot ${CMAKE_OSX_SYSROOT}") - -set (CMAKE_C_LINK_FLAGS "-Wl,-search_paths_first ${CMAKE_C_LINK_FLAGS}") -set (CMAKE_CXX_LINK_FLAGS "-Wl,-search_paths_first ${CMAKE_CXX_LINK_FLAGS}") - -set (CMAKE_PLATFORM_HAS_INSTALLNAME 1) -set (CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS "-dynamiclib -headerpad_max_install_names") -set (CMAKE_SHARED_MODULE_CREATE_C_FLAGS "-bundle -headerpad_max_install_names") -set (CMAKE_SHARED_MODULE_LOADER_C_FLAG "-Wl,-bundle_loader,") -set (CMAKE_SHARED_MODULE_LOADER_CXX_FLAG "-Wl,-bundle_loader,") -set (CMAKE_FIND_LIBRARY_SUFFIXES ".dylib" ".so" ".a") - -# hack: if a new cmake (which uses CMAKE_INSTALL_NAME_TOOL) runs on an old build tree -# (where install_name_tool was hardcoded) and where CMAKE_INSTALL_NAME_TOOL isn't in the cache -# and still cmake didn't fail in CMakeFindBinUtils.cmake (because it isn't rerun) -# hardcode CMAKE_INSTALL_NAME_TOOL here to install_name_tool, so it behaves as it did before, Alex -if (NOT DEFINED CMAKE_INSTALL_NAME_TOOL) - find_program(CMAKE_INSTALL_NAME_TOOL install_name_tool) -endif (NOT DEFINED CMAKE_INSTALL_NAME_TOOL) - -# Setup iOS platform unless specified manually with IOS_PLATFORM -if (NOT DEFINED IOS_PLATFORM) - set (IOS_PLATFORM "OS") -endif (NOT DEFINED IOS_PLATFORM) -set (IOS_PLATFORM ${IOS_PLATFORM} CACHE STRING "Type of iOS Platform") - -# Check the platform selection and setup for developer root -if (${IOS_PLATFORM} STREQUAL "OS") - set (IOS_PLATFORM_LOCATION "iPhoneOS.platform") - - # This causes the installers to properly locate the output libraries - set (CMAKE_XCODE_EFFECTIVE_PLATFORMS "-iphoneos") -elseif (${IOS_PLATFORM} STREQUAL "SIMULATOR") - set (IOS_PLATFORM_LOCATION "iPhoneSimulator.platform") - - # This causes the installers to properly locate the output libraries - set (CMAKE_XCODE_EFFECTIVE_PLATFORMS "-iphonesimulator") -else (${IOS_PLATFORM} STREQUAL "OS") - message (FATAL_ERROR "Unsupported IOS_PLATFORM value selected. Please choose OS or SIMULATOR") -endif (${IOS_PLATFORM} STREQUAL "OS") - -# Setup iOS developer location unless specified manually with CMAKE_IOS_DEVELOPER_ROOT -# Note Xcode 4.3 changed the installation location, choose the most recent one available -set (XCODE_POST_43_ROOT "/Applications/Xcode.app/Contents/Developer/Platforms/${IOS_PLATFORM_LOCATION}/Developer") -set (XCODE_PRE_43_ROOT "/Developer/Platforms/${IOS_PLATFORM_LOCATION}/Developer") -if (NOT DEFINED CMAKE_IOS_DEVELOPER_ROOT) - if (EXISTS ${XCODE_POST_43_ROOT}) - set (CMAKE_IOS_DEVELOPER_ROOT ${XCODE_POST_43_ROOT}) - elseif(EXISTS ${XCODE_PRE_43_ROOT}) - set (CMAKE_IOS_DEVELOPER_ROOT ${XCODE_PRE_43_ROOT}) - endif (EXISTS ${XCODE_POST_43_ROOT}) -endif (NOT DEFINED CMAKE_IOS_DEVELOPER_ROOT) -set (CMAKE_IOS_DEVELOPER_ROOT ${CMAKE_IOS_DEVELOPER_ROOT} CACHE PATH "Location of iOS Platform") - -# Find and use the most recent iOS sdk unless specified manually with CMAKE_IOS_SDK_ROOT -if (NOT DEFINED CMAKE_IOS_SDK_ROOT) - file (GLOB _CMAKE_IOS_SDKS "${CMAKE_IOS_DEVELOPER_ROOT}/SDKs/*") - if (_CMAKE_IOS_SDKS) - list (SORT _CMAKE_IOS_SDKS) - list (REVERSE _CMAKE_IOS_SDKS) - list (GET _CMAKE_IOS_SDKS 0 CMAKE_IOS_SDK_ROOT) - else (_CMAKE_IOS_SDKS) - message (FATAL_ERROR "No iOS SDK's found in default search path ${CMAKE_IOS_DEVELOPER_ROOT}. Manually set CMAKE_IOS_SDK_ROOT or install the iOS SDK.") - endif (_CMAKE_IOS_SDKS) - message (STATUS "Toolchain using default iOS SDK: ${CMAKE_IOS_SDK_ROOT}") -endif (NOT DEFINED CMAKE_IOS_SDK_ROOT) -set (CMAKE_IOS_SDK_ROOT ${CMAKE_IOS_SDK_ROOT} CACHE PATH "Location of the selected iOS SDK") - -# Set the sysroot default to the most recent SDK -set (CMAKE_OSX_SYSROOT ${CMAKE_IOS_SDK_ROOT} CACHE PATH "Sysroot used for iOS support") - -# set the architecture for iOS -# NOTE: Currently both ARCHS_STANDARD_32_BIT and ARCHS_UNIVERSAL_IPHONE_OS set armv7 only, so set both manually -if (${IOS_PLATFORM} STREQUAL "OS") - set (IOS_ARCH armv7 armv7s) - set (CMAKE_SYSTEM_PROCESSOR armv7) -else (${IOS_PLATFORM} STREQUAL "OS") - set (IOS_ARCH i386) - set (CMAKE_SYSTEM_PROCESSOR i386) -endif (${IOS_PLATFORM} STREQUAL "OS") - -set (CMAKE_OSX_ARCHITECTURES ${IOS_ARCH} CACHE string "Build architecture for iOS") - -# Set the find root to the iOS developer roots and to user defined paths -set (CMAKE_FIND_ROOT_PATH ${CMAKE_IOS_DEVELOPER_ROOT} ${CMAKE_IOS_SDK_ROOT} ${CMAKE_PREFIX_PATH} CACHE string "iOS find search path root") - -# default to searching for frameworks first -set (CMAKE_FIND_FRAMEWORK FIRST) - -# set up the default search directories for frameworks -set (CMAKE_SYSTEM_FRAMEWORK_PATH - ${CMAKE_IOS_SDK_ROOT}/System/Library/Frameworks - ${CMAKE_IOS_SDK_ROOT}/System/Library/PrivateFrameworks - ${CMAKE_IOS_SDK_ROOT}/Developer/Library/Frameworks -) - -# only search the iOS sdks, not the remainder of the host filesystem -set (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY) -set (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) -set (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) - - -# This little macro lets you set any XCode specific property -macro (set_xcode_property TARGET XCODE_PROPERTY XCODE_VALUE) - set_property (TARGET ${TARGET} PROPERTY XCODE_ATTRIBUTE_${XCODE_PROPERTY} ${XCODE_VALUE}) -endmacro (set_xcode_property) - - -# This macro lets you find executable programs on the host system -macro (find_host_package) - set (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) - set (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY NEVER) - set (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE NEVER) - set (IOS FALSE) - - find_package(${ARGN}) - - set (IOS TRUE) - set (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY) - set (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) - set (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) -endmacro (find_host_package) - diff --git a/config.h.in b/config.h.in index 2264e59..1f35d68 100644 --- a/config.h.in +++ b/config.h.in @@ -25,6 +25,7 @@ #cmakedefine HAVE_VALGRIND_MEMCHECK_H #cmakedefine HAVE_EXECINFO_H #cmakedefine HAVE_GETLOGIN_R +#cmakedefine HAVE_GETPWUID_R /* Features */ #cmakedefine SWRESAMPLE_FOUND @@ -63,9 +64,9 @@ #cmakedefine WITH_FFMPEG #cmakedefine WITH_DSP_EXPERIMENTAL #cmakedefine WITH_DSP_FFMPEG -#cmakedefine WITH_X264 #cmakedefine WITH_OPENCL #cmakedefine WITH_MEDIA_FOUNDATION +#cmakedefine WITH_MEDIACODEC #cmakedefine WITH_VAAPI @@ -74,6 +75,9 @@ #cmakedefine WITH_RDPDR /* Channels */ +#cmakedefine CHANNEL_AINPUT +#cmakedefine CHANNEL_AINPUT_CLIENT +#cmakedefine CHANNEL_AINPUT_SERVER #cmakedefine CHANNEL_AUDIN #cmakedefine CHANNEL_AUDIN_CLIENT #cmakedefine CHANNEL_AUDIN_SERVER diff --git a/docs/README.android b/docs/README.android deleted file mode 100644 index f2da658..0000000 --- a/docs/README.android +++ /dev/null @@ -1,86 +0,0 @@ -Overview -======== - -The FreeRDP Android port consists of three parts: -* Android Java GUI (client/Android/Studio) -* FreeRDP library and its dependencies -* JNI bindings (client/Android/android_freerdp.c - and client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/services/LibFreeRDP.java) - -Build requirements -================= - -For the Android port some additional dependencies need to be fulfilled: - -* for JNI -- CMake >= 3.0 -- Android NDK (>= r9) - -* for the Java GUI -- Android SDK - -FreeRDP requires openssl libraries for building but they are not part of the -Android NDK and therefore they need to be prebuild manually. - -For jpeg support https://github.com/akallabeth/jpeg8d has been tested and used. -However, any other static builds should work as well. - -Build native libraries: -====================== -From the project root run the build script -./scripts/android-build-freerdp.sh --ndk --sdk -Set ANDROID_NDK and ANDROID_SDK to the absolute paths on your machine. -This will fetch sources from git and build OpenSSL, OpenH264, libJPEG. -The native FreeRDP libraries will also be build. - -Currently the default script builds for: -* armeabi -* armeabi-v7a -* x86 -* mips -* arm64-v8a -* x86_64 -* mips64 - -When the script is finished the libraries are ready for android studio to -be picked up in client/Android/Studio/freeRDPCore/src/main/jniLibs - -The default configuration build configuration can be found in -./scripts/android-build.conf and is configured to provide debug builds. -They are limited to API level 21 and above. - -If release binaries (and old android API support) are required, build 32 bit architectures with -./scripts/android-build-freerdp.sh --ndk --sdk --conf ./scripts/android-build-32.conf -and 64 bit architectures with -./scripts/android-build-freerdp.sh --ndk --sdk --conf ./scripts/android-build-64.conf - -Building the APK (Android Studio) -================ - -* Import the folder client/Android/Studio in Android Studio -* You are ready to go - -Building the APK (gradle) -================ - -* change to directory client/Android/Studio -* run ./gradlew build to build -* run ./gradlew tasks for other gradle options - -Development -=========== - -Updating JNI ------------- - -Whenever the FreeRDP API changes or you need some extra functionality in your Java -GUI the JNI needs to be updated. - -The JNI functions are defined in client/Android/android_freerdp.c -Add the new functions to the methods struct. - -* edit client/Android/src/com/freerdp/afreerdp/services/LibFreeRDP.Java to - reflect your changes -* edit client/Android/android_freerdp.c and adjust the methods struct to reflect - the changes made. - diff --git a/docs/README.ios b/docs/README.ios deleted file mode 100644 index c4f767e..0000000 --- a/docs/README.ios +++ /dev/null @@ -1,100 +0,0 @@ -Overview -======== - -The FreeRDP iOS port allows users to enjoy FreeRDP features on Apple iOS devices. -The application was written to be compatible with devices running iOS 4.3 or higher. - -Build requirements -================== - -The following prerequisites are required in order to build the iOS port: - -- cmake version >= 2.8.9 -- latest Xcode installed (>= 4.6) -- installed Provisioning Profile and iOS Developer Certificate for code signing - (not required for simulator builds) -- pre-build static OpenSSL libraries (see below) - -FreeRDP requires OpenSSL libraries for building but they are not part of the iOS SDK and therefore they need to be pre-build manually. -There are various versions and builds of static OpenSSL libraries floating around like iOSPorts. -At the time of writing we have tested and used a small script (OpenSSL-DownloadAndBuild.command) that downloads and builds armv7, armv7s and i386 versions of the OpenSSL 1.0.0e libraries. - -If you don't care about modifying the OpenSSL build you can run the following command in the FreeRDP root directory: - -./scripts/OpenSSL-DownloadAndBuild.command - -The output of the script will be found in external/openssl/. In case you want a -different install/build directory you specify it as first parameter: - -./scripts/OpenSSL-DownloadAndBuild.command /tmp/ - -In the example above the output can then be found in /tmp/openssl. - -The script uses oldest iOS/iPhoneSimulator SDK found on the build machine per default. If it is required to build against a specific SDK version -the variable SDK_VERSION can be used to specify it. The minimum SDK version that should be used can be set with MIN_SDK_VERSION within the script. - -When the script is finished you will find libcrypto.a and libssl.at, both universal libraries containing all openssl/lib -subfolder in the specified -install directory (external per default) - -When the script finishes you will find libcrypto.a and libssl.a, both universal -binary libraries containing arm and i386 targets in order to compile FreeRDP for -iOS devices and the simulator, in the lib subfolder of your installation -directory. - -If you build OpenSSL youself or with an install directory specified you need to set FREERDP_IOS_EXTERNAL_SSL_PATH when running cmake. - - -Building -======== - -Run the following commands in the top level FreeRDP directory: - -cmake -DCMAKE_TOOLCHAIN_FILE=cmake/iOSToolchain.cmake -GXcode - -This command will create a XCode project in the FreeRDP root folder called FreeRDP.xcodeproj. -Open the project in XCode and modify, build or run the app. - -Alternatively you can also build the project from the command line using xcodebuild: - -xcodebuild -project FreeRDP.xcodeproj -configuration Debug -sdk iphoneos6.1 - -or with cmake --build . in your build directory. - -Notes: - -* XCode, by default will build the application into its derived data location (usually in ~/Library/Developer/...). -If you want to specify an output directory add CONFIGURATION_BUILD_DIR= to the end of above command line. - -* If using XCode choose "Open Other" from the welcome screen, browse to the FreeRDP root directory and select FreeRDP.xcodeproj. Alternatively you can - also start it with "open FreeRDP.xcodeproj". - -* If you switch between platforms (OS and SIMULATOR) please remove CMakeCache.txt and CMakeFiles/ before calling cmake again. - Otherwise build errors might occur (this seems to be a bug with cmake or the cmake scripts). To switch between platforms do: - - rm CMakeCache.txt - rm -rf CMakeFiles/ - - before you run a new cmake command with the desired platform. - - -cmake variables -=============== - -CMAKE_TOOLCHAIN_FILE -* the toolchain file to use must be cmake/iOSToolchain.cmake - -IOS_PLATFORM (OS (default), SIMULATOR) -* the platform for which to build iFreeRDP. OS compiles for iOS devices (using armv7 and armv7s ABIs) and SIMULATOR compiles for the iOS Simulator (i386) - -CMAKE_IOS_DEVELOPER_ROOT (used by toolchain file) -* absolute path to the iOS developer platform (i.e. /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer) the toolchain file will usually auto-detect the correct Developer platform depending on IOS_PLATFORM - -CMAKE_IOS_SDK_ROOT (used by toolchain file) -* absolute path to the iOS SDK (i.e. /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS6.1.sdk) the toolchain file will usually auto-detect the correct SDK, depending on IOS_PLATFORM - -FREERDP_IOS_EXTERNAL_SSL_PATH (used by FindOpenSSL) -* absolut root path to the pre-built static OpenSSL libraries - -CODE_SIGN_IDENTITY -* specify the identity to sign the code with diff --git a/docs/README.macOS b/docs/README.macOS deleted file mode 100644 index d9fbb6b..0000000 --- a/docs/README.macOS +++ /dev/null @@ -1,7 +0,0 @@ -Starting with "El Capitan" Apple removed the openssl headers. Therefore it's -required to build openssl manually upfront. For example by using MacPorts or Homebrew. -To build FreeRDP against this library it's required to set the PKG_CONFIG_PATH -pointing to the openssl root directory befor building. -For example with brew it would look like this: - -export PKG_CONFIG_PATH=$(brew --prefix)/opt/openssl/lib/pkgconfig diff --git a/include/freerdp/channels/ainput.h b/include/freerdp/channels/ainput.h new file mode 100644 index 0000000..fe9faef --- /dev/null +++ b/include/freerdp/channels/ainput.h @@ -0,0 +1,61 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Audio Input Redirection Virtual Channel + * + * Copyright 2022 Armin Novak + * Copyright 2022 Thincast Technologies GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FREERDP_CHANNEL_AINPUT_H +#define FREERDP_CHANNEL_AINPUT_H + +#include +#include +#include + +#define AINPUT_CHANNEL_NAME "ainput" +#define AINPUT_DVC_CHANNEL_NAME "FreeRDP::Advanced::Input" + +typedef enum +{ + MSG_AINPUT_VERSION = 0x01, + MSG_AINPUT_MOUSE = 0x02 +} eAInputMsgType; + +typedef enum +{ + AINPUT_FLAGS_WHEEL = 0x0001, + AINPUT_FLAGS_MOVE = 0x0004, + AINPUT_FLAGS_DOWN = 0x0008, + + AINPUT_FLAGS_REL = 0x0010, + AINPUT_FLAGS_HAVE_REL = 0x0020, + + /* Pointer Flags */ + AINPUT_FLAGS_BUTTON1 = 0x1000, /* left */ + AINPUT_FLAGS_BUTTON2 = 0x2000, /* right */ + AINPUT_FLAGS_BUTTON3 = 0x4000, /* middle */ + + /* Extended Pointer Flags */ + AINPUT_XFLAGS_BUTTON1 = 0x0100, + AINPUT_XFLAGS_BUTTON2 = 0x0200 +} AInputEventFlags; + +typedef struct ainput_client_context AInputClientContext; + +#define AINPUT_VERSION_MAJOR 1 +#define AINPUT_VERSION_MINOR 0 + +#endif /* FREERDP_CHANNEL_AINPUT_H */ diff --git a/include/freerdp/client/ainput.h b/include/freerdp/client/ainput.h new file mode 100644 index 0000000..1447483 --- /dev/null +++ b/include/freerdp/client/ainput.h @@ -0,0 +1,38 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Display Update Virtual Channel Extension + * + * Copyright 2013 Marc-Andre Moreau + * Copyright 2015 Thincast Technologies GmbH + * Copyright 2015 DI (FH) Martin Haimberger + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FREERDP_CHANNEL_AINPUT_CLIENT_AINPUT_H +#define FREERDP_CHANNEL_AINPUT_CLIENT_AINPUT_H + +#include + +typedef UINT (*pcAInputSendInputEvent)(AInputClientContext* context, UINT64 flags, INT32 x, + INT32 y); + +struct ainput_client_context +{ + void* handle; + void* custom; + + pcAInputSendInputEvent AInputSendInputEvent; +}; + +#endif /* FREERDP_CHANNEL_AINPUT_CLIENT_AINPUT_H */ diff --git a/include/freerdp/server/ainput.h b/include/freerdp/server/ainput.h new file mode 100644 index 0000000..39acad1 --- /dev/null +++ b/include/freerdp/server/ainput.h @@ -0,0 +1,114 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * AInput Virtual Channel Extension + * + * Copyright 2022 Armin Novak + * Copyright 2022 Thincast Technologies GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FREERDP_CHANNEL_AINPUT_SERVER_H +#define FREERDP_CHANNEL_AINPUT_SERVER_H + +#include + +typedef enum AINPUT_SERVER_OPEN_RESULT +{ + AINPUT_SERVER_OPEN_RESULT_OK = 0, + AINPUT_SERVER_OPEN_RESULT_CLOSED = 1, + AINPUT_SERVER_OPEN_RESULT_NOTSUPPORTED = 2, + AINPUT_SERVER_OPEN_RESULT_ERROR = 3 +} AINPUT_SERVER_OPEN_RESULT; + +typedef struct _ainput_server_context ainput_server_context; + +typedef UINT (*psAInputServerInitialize)(ainput_server_context* context, BOOL externalThread); +typedef UINT (*psAInputServerPoll)(ainput_server_context* context); +typedef BOOL (*psAInputServerChannelHandle)(ainput_server_context* context, HANDLE* handle); + +typedef UINT (*psAInputServerOpen)(ainput_server_context* context); +typedef UINT (*psAInputServerClose)(ainput_server_context* context); +typedef BOOL (*psAInputServerIsOpen)(ainput_server_context* context); + +typedef UINT (*psAInputServerOpenResult)(ainput_server_context* context, + AINPUT_SERVER_OPEN_RESULT result); +typedef UINT (*psAInputServerMouseEvent)(ainput_server_context* context, UINT64 timestamp, + UINT64 flags, INT32 x, INT32 y); + +struct _ainput_server_context +{ + HANDLE vcm; + + /* Server self-defined pointer. */ + void* data; + + /*** APIs called by the server. ***/ + /** + * Open the ainput channel. + */ + psAInputServerOpen Open; + + /** + * Optional: Set thread handling. + * When externalThread=TRUE the application is responsible to call + * ainput_server_context_poll periodically to process input events. + * + * Defaults to externalThread=FALSE + */ + psAInputServerInitialize Initialize; + + /** + * @brief Poll When externalThread=TRUE call periodically from your main loop. + * if externalThread=FALSE do not call. + */ + psAInputServerPoll Poll; + + /** + * @brief Poll When externalThread=TRUE call to get a handle to wait for events. + * Will return FALSE until the handle is available. + */ + psAInputServerChannelHandle ChannelHandle; + + /** + * Close the ainput channel. + */ + psAInputServerClose Close; + /** + * Status of the ainput channel. + */ + psAInputServerIsOpen IsOpen; + + /*** Callbacks registered by the server. ***/ + + /** + * Receive ainput mouse event PDU. + */ + psAInputServerMouseEvent MouseEvent; + + rdpContext* rdpcontext; +}; + +#ifdef __cplusplus +extern "C" +{ +#endif + + FREERDP_API ainput_server_context* ainput_server_context_new(HANDLE vcm); + FREERDP_API void ainput_server_context_free(ainput_server_context* context); + +#ifdef __cplusplus +} +#endif + +#endif /* FREERDP_CHANNEL_AINPUT_SERVER_H */ diff --git a/libfreerdp/CMakeLists.txt b/libfreerdp/CMakeLists.txt index e3a4103..5b74614 100644 --- a/libfreerdp/CMakeLists.txt +++ b/libfreerdp/CMakeLists.txt @@ -220,12 +220,6 @@ if(WITH_JPEG) freerdp_library_add(${JPEG_LIBRARIES}) endif() -if(WITH_X264) - set(CODEC_SRCS ${CODEC_SRCS} codec/h264_x264.c) - freerdp_include_directory_add(${X264_INCLUDE_DIR}) - freerdp_library_add(${X264_LIBRARIES}) -endif() - if(WITH_OPENH264) set(CODEC_SRCS ${CODEC_SRCS} codec/h264_openh264.c) freerdp_include_directory_add(${OPENH264_INCLUDE_DIR}) @@ -244,6 +238,10 @@ if(WIN32 AND WITH_MEDIA_FOUNDATION) set(CODEC_SRCS ${CODEC_SRCS} codec/h264_mf.c) endif() +if(ANDROID AND WITH_MEDIACODEC) + list(APPEND CODEC_SRCS codec/h264_mediacodec.c) +endif() + freerdp_module_add(${CODEC_SRCS}) if(BUILD_TESTING) diff --git a/libfreerdp/codec/dsp_ffmpeg.c b/libfreerdp/codec/dsp_ffmpeg.c index 0af3cf4..086c797 100644 --- a/libfreerdp/codec/dsp_ffmpeg.c +++ b/libfreerdp/codec/dsp_ffmpeg.c @@ -571,7 +571,9 @@ BOOL freerdp_dsp_ffmpeg_supports_format(const AUDIO_FORMAT* format, BOOL encode) FREERDP_DSP_CONTEXT* freerdp_dsp_ffmpeg_context_new(BOOL encode) { FREERDP_DSP_CONTEXT* context; +#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 10, 100) avcodec_register_all(); +#endif context = calloc(1, sizeof(FREERDP_DSP_CONTEXT)); if (!context) @@ -667,7 +669,9 @@ BOOL freerdp_dsp_ffmpeg_decode(FREERDP_DSP_CONTEXT* context, const AUDIO_FORMAT* if (!context || !srcFormat || !data || !out || context->encoder) return FALSE; +#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 133, 100) av_init_packet(context->packet); +#endif context->packet->data = (uint8_t*)data; context->packet->size = length; return ffmpeg_decode(context->context, context->packet, context->frame, context->rcontext, diff --git a/libfreerdp/codec/h264.c b/libfreerdp/codec/h264.c index 00b812b..36b5a7c 100644 --- a/libfreerdp/codec/h264.c +++ b/libfreerdp/codec/h264.c @@ -484,7 +484,7 @@ INT32 avc444_decompress(H264_CONTEXT* h264, BYTE op, RECTANGLE_16* regionRects, #define MAX_SUBSYSTEMS 10 static INIT_ONCE subsystems_once = INIT_ONCE_STATIC_INIT; -static H264_CONTEXT_SUBSYSTEM* subSystems[MAX_SUBSYSTEMS]; +static H264_CONTEXT_SUBSYSTEM* subSystems[MAX_SUBSYSTEMS] = { 0 }; #if defined(_WIN32) && defined(WITH_MEDIA_FOUNDATION) extern H264_CONTEXT_SUBSYSTEM g_Subsystem_MF; @@ -493,7 +493,14 @@ extern H264_CONTEXT_SUBSYSTEM g_Subsystem_MF; static BOOL CALLBACK h264_register_subsystems(PINIT_ONCE once, PVOID param, PVOID* context) { int i = 0; - ZeroMemory(subSystems, sizeof(subSystems)); + +#ifdef WITH_MEDIACODEC + { + extern H264_CONTEXT_SUBSYSTEM g_Subsystem_mediacodec; + subSystems[i] = &g_Subsystem_mediacodec; + i++; + } +#endif #if defined(_WIN32) && defined(WITH_MEDIA_FOUNDATION) { subSystems[i] = &g_Subsystem_MF; @@ -513,13 +520,6 @@ static BOOL CALLBACK h264_register_subsystems(PINIT_ONCE once, PVOID param, PVOI subSystems[i] = &g_Subsystem_libavcodec; i++; } -#endif -#ifdef WITH_X264 - { - extern H264_CONTEXT_SUBSYSTEM g_Subsystem_x264; - subSystems[i] = &g_Subsystem_x264; - i++; - } #endif return i > 0; } diff --git a/libfreerdp/codec/h264_mediacodec.c b/libfreerdp/codec/h264_mediacodec.c new file mode 100644 index 0000000..ba207e5 --- /dev/null +++ b/libfreerdp/codec/h264_mediacodec.c @@ -0,0 +1,649 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * H.264 Bitmap Compression + * + * Copyright 2022 Ely Ronnen + * + * 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 + +#include "h264.h" + +#define WINPR_ASSERT(x) assert(x) + +#define RESOLVE_MEDIANDK_FUNC(sys, name) \ + ({ \ + BOOL rc = TRUE; \ + sys->fn##name = GetProcAddress(sys->mediandkLibrary, #name); \ + if (sys->fn##name == NULL) \ + { \ + WLog_Print(h264->log, WLOG_ERROR, \ + "Error resolving function " #name " from libmediandk.so"); \ + rc = FALSE; \ + } \ + rc; \ + }) + +#define RESOLVE_MEDIANDK_VARIABLE(sys, member, exported) \ + ({ \ + BOOL rc = FALSE; \ + const char** temp = GetProcAddress(sys->mediandkLibrary, exported); \ + if (temp == NULL) \ + { \ + WLog_Print(h264->log, WLOG_ERROR, \ + "Error resolving variable " exported " from libmediandk.so"); \ + } \ + else \ + { \ + sys->member = *temp; \ + rc = TRUE; \ + } \ + rc; \ + }) + +typedef AMediaFormat* (*AMediaFormat_new_t)(void); +typedef media_status_t (*AMediaFormat_delete_t)(AMediaFormat*); +typedef const char* (*AMediaFormat_toString_t)(AMediaFormat*); +typedef void (*AMediaFormat_setInt32_t)(AMediaFormat*, const char*, int32_t); +typedef void (*AMediaFormat_setString_t)(AMediaFormat*, const char*, const char*); +typedef AMediaCodec* (*AMediaCodec_createDecoderByType_t)(const char*); +typedef media_status_t (*AMediaCodec_delete_t)(AMediaCodec*); +typedef media_status_t (*AMediaCodec_configure_t)(AMediaCodec*, const AMediaFormat*, ANativeWindow*, + AMediaCrypto*, uint32_t); +typedef media_status_t (*AMediaCodec_start_t)(AMediaCodec*); +typedef media_status_t (*AMediaCodec_stop_t)(AMediaCodec*); +typedef uint8_t* (*AMediaCodec_getInputBuffer_t)(AMediaCodec*, size_t, size_t*); +typedef uint8_t* (*AMediaCodec_getOutputBuffer_t)(AMediaCodec*, size_t, size_t*); +typedef ssize_t (*AMediaCodec_dequeueInputBuffer_t)(AMediaCodec*, int64_t); +typedef media_status_t (*AMediaCodec_queueInputBuffer_t)(AMediaCodec*, size_t, ssize_t, size_t, + uint64_t, uint32_t); +typedef ssize_t (*AMediaCodec_dequeueOutputBuffer_t)(AMediaCodec*, AMediaCodecBufferInfo*, int64_t); +typedef AMediaFormat* (*AMediaCodec_getOutputFormat_t)(AMediaCodec*); +typedef media_status_t (*AMediaCodec_releaseOutputBuffer_t)(AMediaCodec*, size_t, bool); +typedef media_status_t (*AMediaCodec_setParameters_t)(AMediaCodec*, const AMediaFormat*); // 26 +typedef media_status_t (*AMediaCodec_getName_t)(AMediaCodec*, char**); // 28 +typedef void (*AMediaCodec_releaseName_t)(AMediaCodec*, char*); // 28 +typedef AMediaFormat* (*AMediaCodec_getInputFormat_t)(AMediaCodec*); // 28 + +const int COLOR_FormatYUV420Planar = 19; +const int COLOR_FormatYUV420Flexible = 0x7f420888; + +struct _H264_CONTEXT_MEDIACODEC +{ + AMediaCodec* decoder; + AMediaFormat* inputFormat; + AMediaFormat* outputFormat; + int32_t width; + int32_t height; + ssize_t currentOutputBufferIndex; + + // libmediandk.so imports + HMODULE mediandkLibrary; + + AMediaFormat_new_t fnAMediaFormat_new; + AMediaFormat_delete_t fnAMediaFormat_delete; + AMediaFormat_toString_t fnAMediaFormat_toString; + AMediaFormat_setInt32_t fnAMediaFormat_setInt32; + AMediaFormat_setString_t fnAMediaFormat_setString; + AMediaCodec_createDecoderByType_t fnAMediaCodec_createDecoderByType; + AMediaCodec_delete_t fnAMediaCodec_delete; + AMediaCodec_configure_t fnAMediaCodec_configure; + AMediaCodec_start_t fnAMediaCodec_start; + AMediaCodec_stop_t fnAMediaCodec_stop; + AMediaCodec_getInputBuffer_t fnAMediaCodec_getInputBuffer; + AMediaCodec_getOutputBuffer_t fnAMediaCodec_getOutputBuffer; + AMediaCodec_dequeueInputBuffer_t fnAMediaCodec_dequeueInputBuffer; + AMediaCodec_queueInputBuffer_t fnAMediaCodec_queueInputBuffer; + AMediaCodec_dequeueOutputBuffer_t fnAMediaCodec_dequeueOutputBuffer; + AMediaCodec_getOutputFormat_t fnAMediaCodec_getOutputFormat; + AMediaCodec_releaseOutputBuffer_t fnAMediaCodec_releaseOutputBuffer; + AMediaCodec_setParameters_t fnAMediaCodec_setParameters; + AMediaCodec_getName_t fnAMediaCodec_getName; + AMediaCodec_releaseName_t fnAMediaCodec_releaseName; + AMediaCodec_getInputFormat_t fnAMediaCodec_getInputFormat; + + const char* gAMediaFormatKeyMime; + const char* gAMediaFormatKeyWidth; + const char* gAMediaFormatKeyHeight; + const char* gAMediaFormatKeyColorFormat; +}; + +typedef struct _H264_CONTEXT_MEDIACODEC H264_CONTEXT_MEDIACODEC; + +static int load_libmediandk(H264_CONTEXT* h264) +{ + BOOL rc; + H264_CONTEXT_MEDIACODEC* sys; + + WINPR_ASSERT(h264); + + sys = (H264_CONTEXT_MEDIACODEC*)h264->pSystemData; + WINPR_ASSERT(sys); + + WLog_Print(h264->log, WLOG_DEBUG, "MediaCodec Loading libmediandk.so"); + + sys->mediandkLibrary = LoadLibraryA("libmediandk.so"); + if (sys->mediandkLibrary == NULL) + { + WLog_Print(h264->log, WLOG_WARN, "Error loading libmediandk.so"); + return -1; + } + + rc = RESOLVE_MEDIANDK_FUNC(sys, AMediaFormat_new); + if (!rc) + return -1; + rc = RESOLVE_MEDIANDK_FUNC(sys, AMediaFormat_delete); + if (!rc) + return -1; + rc = RESOLVE_MEDIANDK_FUNC(sys, AMediaFormat_toString); + if (!rc) + return -1; + rc = RESOLVE_MEDIANDK_FUNC(sys, AMediaFormat_setInt32); + if (!rc) + return -1; + rc = RESOLVE_MEDIANDK_FUNC(sys, AMediaFormat_setString); + if (!rc) + return -1; + rc = RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_createDecoderByType); + if (!rc) + return -1; + rc = RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_delete); + if (!rc) + return -1; + rc = RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_configure); + if (!rc) + return -1; + rc = RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_start); + if (!rc) + return -1; + rc = RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_stop); + if (!rc) + return -1; + rc = RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_getInputBuffer); + if (!rc) + return -1; + rc = RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_getOutputBuffer); + if (!rc) + return -1; + rc = RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_dequeueInputBuffer); + if (!rc) + return -1; + rc = RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_queueInputBuffer); + if (!rc) + return -1; + rc = RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_dequeueOutputBuffer); + if (!rc) + return -1; + rc = RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_getOutputFormat); + if (!rc) + return -1; + rc = RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_releaseOutputBuffer); + if (!rc) + return -1; + rc = RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_setParameters); + if (!rc) + return -1; + rc = RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_getName); + if (!rc) + return -1; + rc = RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_releaseName); + if (!rc) + return -1; + rc = RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_getInputFormat); + if (!rc) + return -1; + + rc = RESOLVE_MEDIANDK_VARIABLE(sys, gAMediaFormatKeyMime, "AMEDIAFORMAT_KEY_MIME"); + if (!rc) + return -1; + rc = RESOLVE_MEDIANDK_VARIABLE(sys, gAMediaFormatKeyWidth, "AMEDIAFORMAT_KEY_WIDTH"); + if (!rc) + return -1; + rc = RESOLVE_MEDIANDK_VARIABLE(sys, gAMediaFormatKeyHeight, "AMEDIAFORMAT_KEY_HEIGHT"); + if (!rc) + return -1; + rc = RESOLVE_MEDIANDK_VARIABLE(sys, gAMediaFormatKeyColorFormat, + "AMEDIAFORMAT_KEY_COLOR_FORMAT"); + if (!rc) + return -1; + + return 0; +} + +static void unload_libmediandk(H264_CONTEXT* h264) +{ + H264_CONTEXT_MEDIACODEC* sys; + + WINPR_ASSERT(h264); + + sys = (H264_CONTEXT_MEDIACODEC*)h264->pSystemData; + WINPR_ASSERT(sys); + + if (NULL == sys->mediandkLibrary) + { + return; + } + + FreeLibrary(sys->mediandkLibrary); +} + +static void set_mediacodec_format(H264_CONTEXT* h264, AMediaFormat** formatVariable, + AMediaFormat* newFormat) +{ + media_status_t status = AMEDIA_OK; + H264_CONTEXT_MEDIACODEC* sys; + + WINPR_ASSERT(h264); + WINPR_ASSERT(formatVariable); + + sys = (H264_CONTEXT_MEDIACODEC*)h264->pSystemData; + WINPR_ASSERT(sys); + + if (*formatVariable != NULL) + { + status = sys->fnAMediaFormat_delete(*formatVariable); + if (status != AMEDIA_OK) + { + WLog_Print(h264->log, WLOG_ERROR, "Error AMediaFormat_delete %d", status); + } + } + + *formatVariable = newFormat; +} + +static void release_current_outputbuffer(H264_CONTEXT* h264) +{ + media_status_t status = AMEDIA_OK; + H264_CONTEXT_MEDIACODEC* sys; + + WINPR_ASSERT(h264); + sys = (H264_CONTEXT_MEDIACODEC*)h264->pSystemData; + WINPR_ASSERT(sys); + + if (sys->currentOutputBufferIndex < 0) + { + return; + } + + status = + sys->fnAMediaCodec_releaseOutputBuffer(sys->decoder, sys->currentOutputBufferIndex, FALSE); + if (status != AMEDIA_OK) + { + WLog_Print(h264->log, WLOG_ERROR, "Error AMediaCodec_releaseOutputBuffer %d", status); + } + + sys->currentOutputBufferIndex = -1; +} + +static int mediacodec_compress(H264_CONTEXT* h264, const BYTE** pSrcYuv, const UINT32* pStride, + BYTE** ppDstData, UINT32* pDstSize) +{ + WINPR_ASSERT(h264); + WINPR_ASSERT(pSrcYuv); + WINPR_ASSERT(pStride); + WINPR_ASSERT(ppDstData); + WINPR_ASSERT(pDstSize); + + WLog_Print(h264->log, WLOG_ERROR, "MediaCodec is not supported as an encoder"); + return -1; +} + +static int mediacodec_decompress(H264_CONTEXT* h264, const BYTE* pSrcData, UINT32 SrcSize) +{ + ssize_t inputBufferId = -1; + size_t inputBufferSize, outputBufferSize; + uint8_t* inputBuffer; + media_status_t status; + const char* media_format; + BYTE** pYUVData; + UINT32* iStride; + H264_CONTEXT_MEDIACODEC* sys; + + WINPR_ASSERT(h264); + WINPR_ASSERT(pSrcData); + + sys = (H264_CONTEXT_MEDIACODEC*)h264->pSystemData; + WINPR_ASSERT(sys); + + pYUVData = h264->pYUVData; + WINPR_ASSERT(pYUVData); + + iStride = h264->iStride; + WINPR_ASSERT(iStride); + + release_current_outputbuffer(h264); + + if (sys->width == 0) + { + int32_t width = h264->width; + int32_t height = h264->height; + if (width % 16 != 0) + width += 16 - width % 16; + if (height % 16 != 0) + height += 16 - height % 16; + + WLog_Print(h264->log, WLOG_DEBUG, "MediaCodec setting width and height [%d,%d]", width, + height); + sys->fnAMediaFormat_setInt32(sys->inputFormat, sys->gAMediaFormatKeyWidth, width); + sys->fnAMediaFormat_setInt32(sys->inputFormat, sys->gAMediaFormatKeyHeight, height); + + status = sys->fnAMediaCodec_setParameters(sys->decoder, sys->inputFormat); + if (status != AMEDIA_OK) + { + WLog_Print(h264->log, WLOG_ERROR, "AMediaCodec_setParameters failed: %d", status); + return -1; + } + + sys->width = width; + sys->height = height; + } + + while (true) + { + UINT32 inputBufferCurrnetOffset = 0; + while (inputBufferCurrnetOffset < SrcSize) + { + UINT32 numberOfBytesToCopy = SrcSize - inputBufferCurrnetOffset; + inputBufferId = sys->fnAMediaCodec_dequeueInputBuffer(sys->decoder, -1); + if (inputBufferId < 0) + { + WLog_Print(h264->log, WLOG_ERROR, "AMediaCodec_dequeueInputBuffer failed [%d]", + inputBufferId); + // TODO: sleep? + continue; + } + + inputBuffer = + sys->fnAMediaCodec_getInputBuffer(sys->decoder, inputBufferId, &inputBufferSize); + if (inputBuffer == NULL) + { + WLog_Print(h264->log, WLOG_ERROR, "AMediaCodec_getInputBuffer failed"); + return -1; + } + + if (numberOfBytesToCopy > inputBufferSize) + { + WLog_Print(h264->log, WLOG_WARN, + "MediaCodec inputBufferSize: got [%d] but wanted [%d]", inputBufferSize, + numberOfBytesToCopy); + numberOfBytesToCopy = inputBufferSize; + } + + memcpy(inputBuffer, pSrcData + inputBufferCurrnetOffset, numberOfBytesToCopy); + inputBufferCurrnetOffset += numberOfBytesToCopy; + + status = sys->fnAMediaCodec_queueInputBuffer(sys->decoder, inputBufferId, 0, + numberOfBytesToCopy, 0, 0); + if (status != AMEDIA_OK) + { + WLog_Print(h264->log, WLOG_ERROR, "Error AMediaCodec_queueInputBuffer %d", status); + return -1; + } + } + + while (true) + { + AMediaCodecBufferInfo bufferInfo; + ssize_t outputBufferId = + sys->fnAMediaCodec_dequeueOutputBuffer(sys->decoder, &bufferInfo, -1); + if (outputBufferId >= 0) + { + sys->currentOutputBufferIndex = outputBufferId; + + uint8_t* outputBuffer; + outputBuffer = sys->fnAMediaCodec_getOutputBuffer(sys->decoder, outputBufferId, + &outputBufferSize); + sys->currentOutputBufferIndex = outputBufferId; + + if (outputBufferSize != (sys->width * sys->height + + ((sys->width + 1) / 2) * ((sys->height + 1) / 2) * 2)) + { + WLog_Print(h264->log, WLOG_ERROR, "Error unexpected output buffer size %d", + outputBufferSize); + return -1; + } + + // TODO: work with AImageReader and get AImage object instead of + // COLOR_FormatYUV420Planar buffer. + iStride[0] = sys->width; + iStride[1] = (sys->width + 1) / 2; + iStride[2] = (sys->width + 1) / 2; + pYUVData[0] = outputBuffer; + pYUVData[1] = outputBuffer + iStride[0] * sys->height; + pYUVData[2] = + outputBuffer + iStride[0] * sys->height + iStride[1] * ((sys->height + 1) / 2); + break; + } + else if (outputBufferId == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED) + { + AMediaFormat* outputFormat; + outputFormat = sys->fnAMediaCodec_getOutputFormat(sys->decoder); + if (outputFormat == NULL) + { + WLog_Print(h264->log, WLOG_ERROR, "AMediaCodec_getOutputFormat failed"); + return -1; + } + set_mediacodec_format(h264, &sys->outputFormat, outputFormat); + + media_format = sys->fnAMediaFormat_toString(sys->outputFormat); + if (media_format == NULL) + { + WLog_Print(h264->log, WLOG_ERROR, "AMediaFormat_toString failed"); + return -1; + } + } + else if (outputBufferId == AMEDIACODEC_INFO_TRY_AGAIN_LATER) + { + WLog_Print(h264->log, WLOG_WARN, + "AMediaCodec_dequeueOutputBuffer need to try again later"); + // TODO: sleep? + } + else if (outputBufferId == AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED) + { + WLog_Print(h264->log, WLOG_WARN, + "AMediaCodec_dequeueOutputBuffer returned deprecated value " + "AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED, ignoring"); + } + else + { + WLog_Print(h264->log, WLOG_ERROR, + "AMediaCodec_dequeueOutputBuffer returned unknown value [%d]", + outputBufferId); + return -1; + } + } + + break; + } + + return 1; +} + +static void mediacodec_uninit(H264_CONTEXT* h264) +{ + media_status_t status = AMEDIA_OK; + H264_CONTEXT_MEDIACODEC* sys; + + WINPR_ASSERT(h264); + + sys = (H264_CONTEXT_MEDIACODEC*)h264->pSystemData; + + WLog_Print(h264->log, WLOG_DEBUG, "Uninitializing MediaCodec"); + + if (!sys) + return; + + if (sys->decoder != NULL) + { + release_current_outputbuffer(h264); + status = sys->fnAMediaCodec_stop(sys->decoder); + if (status != AMEDIA_OK) + { + WLog_Print(h264->log, WLOG_ERROR, "Error AMediaCodec_stop %d", status); + } + + status = sys->fnAMediaCodec_delete(sys->decoder); + if (status != AMEDIA_OK) + { + WLog_Print(h264->log, WLOG_ERROR, "Error AMediaCodec_delete %d", status); + } + + sys->decoder = NULL; + } + + set_mediacodec_format(h264, &sys->inputFormat, NULL); + set_mediacodec_format(h264, &sys->outputFormat, NULL); + + unload_libmediandk(h264); + + free(sys); + h264->pSystemData = NULL; +} + +static BOOL mediacodec_init(H264_CONTEXT* h264) +{ + H264_CONTEXT_MEDIACODEC* sys; + media_status_t status; + const char* media_format; + char* codec_name; + AMediaFormat *inputFormat, *outputFormat; + + WINPR_ASSERT(h264); + + if (h264->Compressor) + { + WLog_Print(h264->log, WLOG_ERROR, "MediaCodec is not supported as an encoder"); + goto EXCEPTION; + } + + WLog_Print(h264->log, WLOG_DEBUG, "Initializing MediaCodec"); + + sys = (H264_CONTEXT_MEDIACODEC*)calloc(1, sizeof(H264_CONTEXT_MEDIACODEC)); + + if (!sys) + { + goto EXCEPTION; + } + + h264->pSystemData = (void*)sys; + + if (load_libmediandk(h264) < 0) + { + goto EXCEPTION; + } + + sys->currentOutputBufferIndex = -1; + sys->width = sys->height = 0; // update when we're given the height and width + sys->decoder = sys->fnAMediaCodec_createDecoderByType("video/avc"); + if (sys->decoder == NULL) + { + WLog_Print(h264->log, WLOG_ERROR, "AMediaCodec_createCodecByName failed"); + goto EXCEPTION; + } + + status = sys->fnAMediaCodec_getName(sys->decoder, &codec_name); + if (status != AMEDIA_OK) + { + WLog_Print(h264->log, WLOG_ERROR, "AMediaCodec_getName failed: %d", status); + goto EXCEPTION; + } + + WLog_Print(h264->log, WLOG_DEBUG, "MediaCodec using video/avc codec [%s]", codec_name); + sys->fnAMediaCodec_releaseName(sys->decoder, codec_name); + + sys->inputFormat = sys->fnAMediaFormat_new(); + if (sys->inputFormat == NULL) + { + WLog_Print(h264->log, WLOG_ERROR, "AMediaFormat_new failed"); + goto EXCEPTION; + } + + sys->fnAMediaFormat_setString(sys->inputFormat, sys->gAMediaFormatKeyMime, "video/avc"); + sys->fnAMediaFormat_setInt32(sys->inputFormat, sys->gAMediaFormatKeyWidth, sys->width); + sys->fnAMediaFormat_setInt32(sys->inputFormat, sys->gAMediaFormatKeyHeight, sys->height); + sys->fnAMediaFormat_setInt32(sys->inputFormat, sys->gAMediaFormatKeyColorFormat, + COLOR_FormatYUV420Planar); + + media_format = sys->fnAMediaFormat_toString(sys->inputFormat); + if (media_format == NULL) + { + WLog_Print(h264->log, WLOG_ERROR, "AMediaFormat_toString failed"); + goto EXCEPTION; + } + + status = sys->fnAMediaCodec_configure(sys->decoder, sys->inputFormat, NULL, NULL, 0); + if (status != AMEDIA_OK) + { + WLog_Print(h264->log, WLOG_ERROR, "AMediaCodec_configure failed: %d", status); + goto EXCEPTION; + } + + inputFormat = sys->fnAMediaCodec_getInputFormat(sys->decoder); + if (inputFormat == NULL) + { + WLog_Print(h264->log, WLOG_ERROR, "AMediaCodec_getInputFormat failed"); + goto EXCEPTION; + } + set_mediacodec_format(h264, &sys->inputFormat, inputFormat); + + media_format = sys->fnAMediaFormat_toString(sys->inputFormat); + if (media_format == NULL) + { + WLog_Print(h264->log, WLOG_ERROR, "AMediaFormat_toString failed"); + goto EXCEPTION; + } + WLog_Print(h264->log, WLOG_DEBUG, "Using MediaCodec with input MediaFormat [%s]", media_format); + + outputFormat = sys->fnAMediaCodec_getOutputFormat(sys->decoder); + if (outputFormat == NULL) + { + WLog_Print(h264->log, WLOG_ERROR, "AMediaCodec_getOutputFormat failed"); + goto EXCEPTION; + } + set_mediacodec_format(h264, &sys->outputFormat, outputFormat); + + media_format = sys->fnAMediaFormat_toString(sys->outputFormat); + if (media_format == NULL) + { + WLog_Print(h264->log, WLOG_ERROR, "AMediaFormat_toString failed"); + goto EXCEPTION; + } + WLog_Print(h264->log, WLOG_DEBUG, "Using MediaCodec with output MediaFormat [%s]", + media_format); + + WLog_Print(h264->log, WLOG_DEBUG, "Starting MediaCodec"); + status = sys->fnAMediaCodec_start(sys->decoder); + if (status != AMEDIA_OK) + { + WLog_Print(h264->log, WLOG_ERROR, "AMediaCodec_start failed %d", status); + goto EXCEPTION; + } + + return TRUE; +EXCEPTION: + mediacodec_uninit(h264); + return FALSE; +} + +H264_CONTEXT_SUBSYSTEM g_Subsystem_mediacodec = { "MediaCodec", mediacodec_init, mediacodec_uninit, + mediacodec_decompress, mediacodec_compress }; diff --git a/libfreerdp/codec/h264_x264.c b/libfreerdp/codec/h264_x264.c deleted file mode 100644 index c360094..0000000 --- a/libfreerdp/codec/h264_x264.c +++ /dev/null @@ -1,117 +0,0 @@ -/** - * FreeRDP: A Remote Desktop Protocol Implementation - * H.264 Bitmap Compression - * - * Copyright 2015 Marc-André 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. - */ - -#define NAL_UNKNOWN X264_NAL_UNKNOWN -#define NAL_SLICE X264_NAL_SLICE -#define NAL_SLICE_DPA X264_NAL_SLICE_DPA -#define NAL_SLICE_DPB X264_NAL_SLICE_DPB -#define NAL_SLICE_DPC X264_NAL_SLICE_DPC -#define NAL_SLICE_IDR X264_NAL_SLICE_IDR -#define NAL_SEI X264_NAL_SEI -#define NAL_SPS X264_NAL_SPS -#define NAL_PPS X264_NAL_PPS -#define NAL_AUD X264_NAL_AUD -#define NAL_FILLER X264_NAL_FILLER - -#define NAL_PRIORITY_DISPOSABLE X264_NAL_PRIORITY_DISPOSABLE -#define NAL_PRIORITY_LOW X264_NAL_PRIORITY_LOW -#define NAL_PRIORITY_HIGH X264_NAL_PRIORITY_HIGH -#define NAL_PRIORITY_HIGHEST X264_NAL_PRIORITY_HIGHEST - -#include -#include -#include - -#error "X264 backend not implemented, please review your configuration!" - -struct _H264_CONTEXT_X264 -{ - void* dummy; -}; -typedef struct _H264_CONTEXT_X264 H264_CONTEXT_X264; - -static int x264_decompress(H264_CONTEXT* h264, BYTE* pSrcData, UINT32 SrcSize) -{ - // H264_CONTEXT_X264* sys = (H264_CONTEXT_X264*) h264->pSystemData; - return -1; -} - -static int x264_compress(H264_CONTEXT* h264, const BYTE** ppSrcYuv, const UINT32* pStride, - BYTE** ppDstData, UINT32* pDstSize) -{ - // H264_CONTEXT_X264* sys = (H264_CONTEXT_X264*) h264->pSystemData; - return -1; -} - -static void x264_uninit(H264_CONTEXT* h264) -{ - H264_CONTEXT_X264* sys = (H264_CONTEXT_X264*)h264->pSystemData; - - if (sys) - { - free(sys); - h264->pSystemData = NULL; - } -} - -static BOOL x264_init(H264_CONTEXT* h264) -{ - H264_CONTEXT_X264* sys; - h264->numSystemData = 1; - sys = (H264_CONTEXT_X264*)calloc(h264->numSystemData, sizeof(H264_CONTEXT_X264)); - - if (!sys) - { - goto EXCEPTION; - } - - h264->pSystemData = (void*)sys; - - if (h264->Compressor) - { - } - else - { - } - - return TRUE; -EXCEPTION: - x264_uninit(h264); - return FALSE; -} - -H264_CONTEXT_SUBSYSTEM g_Subsystem_x264 = { "x264", x264_init, x264_uninit, x264_decompress, - x264_compress }; - -#undef NAL_UNKNOWN -#undef NAL_SLICE -#undef NAL_SLICE_DPA -#undef NAL_SLICE_DPB -#undef NAL_SLICE_DPC -#undef NAL_SLICE_IDR -#undef NAL_SEI -#undef NAL_SPS -#undef NAL_PPS -#undef NAL_AUD -#undef NAL_FILLER - -#undef NAL_PRIORITY_DISPOSABLE -#undef NAL_PRIORITY_LOW -#undef NAL_PRIORITY_HIGH -#undef NAL_PRIORITY_HIGHEST diff --git a/libfreerdp/codec/progressive.c b/libfreerdp/codec/progressive.c index 08b8199..60343b8 100644 --- a/libfreerdp/codec/progressive.c +++ b/libfreerdp/codec/progressive.c @@ -23,6 +23,7 @@ #include "config.h" #endif +#include #include #include #include @@ -40,6 +41,8 @@ #include "rfx_types.h" #include "progressive.h" +#define WINPR_ASSERT(x) assert(x) + #define TAG FREERDP_TAG("codec.progressive") struct _RFX_PROGRESSIVE_UPGRADE_STATE @@ -434,6 +437,36 @@ static INLINE BOOL progressive_tile_allocate(RFX_PROGRESSIVE_TILE* tile) return rc; } +static BOOL progressive_allocate_tile_cache(PROGRESSIVE_SURFACE_CONTEXT* surface) +{ + size_t oldIndex; + + WINPR_ASSERT(surface); + WINPR_ASSERT(surface->gridSize > 0); + + oldIndex = surface->gridSize; + if (surface->tiles) + surface->gridSize *= 2; + + { + void* tmp = realloc(surface->tiles, surface->gridSize * sizeof(RFX_PROGRESSIVE_TILE)); + if (!tmp) + return FALSE; + surface->tiles = tmp; + memset(&surface->tiles[oldIndex], 0, + (surface->gridSize - oldIndex) * sizeof(RFX_PROGRESSIVE_TILE)); + } + { + void* tmp = realloc(surface->updatedTileIndices, surface->gridSize * sizeof(UINT32)); + if (!tmp) + return FALSE; + surface->updatedTileIndices = tmp; + memset(&surface->updatedTileIndices[oldIndex], 0, + (surface->gridSize - oldIndex) * sizeof(UINT32)); + } + return TRUE; +} + static PROGRESSIVE_SURFACE_CONTEXT* progressive_surface_context_new(UINT16 surfaceId, UINT32 width, UINT32 height) { @@ -450,14 +483,10 @@ static PROGRESSIVE_SURFACE_CONTEXT* progressive_surface_context_new(UINT16 surfa surface->gridWidth = (width + (64 - width % 64)) / 64; surface->gridHeight = (height + (64 - height % 64)) / 64; surface->gridSize = surface->gridWidth * surface->gridHeight; - surface->tiles = (RFX_PROGRESSIVE_TILE*)calloc(surface->gridSize, sizeof(RFX_PROGRESSIVE_TILE)); - surface->updatedTileIndices = (UINT32*)calloc(surface->gridSize, sizeof(UINT32)); - if (!surface->tiles || !surface->updatedTileIndices) + if (!progressive_allocate_tile_cache(surface)) { - free(surface->updatedTileIndices); - free(surface->tiles); - free(surface); + progressive_surface_context_free(surface); return NULL; } for (x = 0; x < surface->gridSize; x++) @@ -549,8 +578,8 @@ static BOOL progressive_surface_tile_replace(PROGRESSIVE_SURFACE_CONTEXT* surfac } if (surface->numUpdatedTiles >= surface->gridSize) { - WLog_ERR(TAG, "Invalid total tile count, maximum %" PRIu32, surface->gridSize); - return FALSE; + if (!progressive_allocate_tile_cache(surface)) + return FALSE; } region->tiles[region->usedTiles++] = t; diff --git a/libfreerdp/core/freerdp.c b/libfreerdp/core/freerdp.c index 2ce9cf7..a070d0c 100644 --- a/libfreerdp/core/freerdp.c +++ b/libfreerdp/core/freerdp.c @@ -181,7 +181,8 @@ BOOL freerdp_connect(freerdp* instance) if (status) status2 = freerdp_channels_pre_connect(instance->context->channels, instance); - if (settings->KeyboardLayout == KBD_JAPANESE_INPUT_SYSTEM_MS_IME2002) + if (settings->KeyboardLayout == KBD_JAPANESE || + settings->KeyboardLayout == KBD_JAPANESE_INPUT_SYSTEM_MS_IME2002) { settings->KeyboardType = 7; settings->KeyboardSubType = 2; diff --git a/scripts/android-build-32.conf b/scripts/android-build-32.conf deleted file mode 100644 index 4bafb23..0000000 --- a/scripts/android-build-32.conf +++ /dev/null @@ -1,29 +0,0 @@ -#!/bin/bash -# -# Android build confguration -# -# Note: This is a simple configuration to build all -# architectures in one rush. -# Since android 64 bit support was introduced with NDK API 21 -# this is the minimal common denominator. -# If you require support for older NDK API levels, -# create seperate configurations for each NDK API level -# and architecture you want to support. -WITH_JPEG=0 -WITH_OPENH264=1 -WITH_OPENSSL=1 -BUILD_DEPS=1 -DEPS_ONLY=0 -NDK_TARGET=21 - -JPEG_TAG=master -OPENH264_TAG=v1.8.0 # NOTE: NDK r15c or earlier needed in --openh624-ndk for v1.8.0 -OPENSSL_TAG=OpenSSL_1_1_1j - -SRC_DIR=$SCRIPT_PATH/.. -BUILD_DST=$SCRIPT_PATH/../client/Android/Studio/freeRDPCore/src/main/jniLibs -BUILD_SRC=$SRC_DIR/build - -CMAKE_BUILD_TYPE=Release - -BUILD_ARCH="armeabi-v7a x86" diff --git a/scripts/android-build-64.conf b/scripts/android-build-64.conf deleted file mode 100644 index a3dcf71..0000000 --- a/scripts/android-build-64.conf +++ /dev/null @@ -1,29 +0,0 @@ -#!/bin/bash -# -# Android build confguration -# -# Note: This is a simple configuration to build all -# architectures in one rush. -# Since android 64 bit support was introduced with NDK API 21 -# this is the minimal common denominator. -# If you require support for older NDK API levels, -# create seperate configurations for each NDK API level -# and architecture you want to support. -WITH_JPEG=0 -WITH_OPENH264=1 -WITH_OPENSSL=1 -BUILD_DEPS=1 -DEPS_ONLY=0 -NDK_TARGET=21 - -JPEG_TAG=master -OPENH264_TAG=v1.8.0 # NOTE: NDK r15c or earlier needed in --openh624-ndk for v1.8.0 -OPENSSL_TAG=OpenSSL_1_1_1j - -SRC_DIR=$SCRIPT_PATH/.. -BUILD_DST=$SCRIPT_PATH/../client/Android/Studio/freeRDPCore/src/main/jniLibs -BUILD_SRC=$SRC_DIR/build - -CMAKE_BUILD_TYPE=Release - -BUILD_ARCH="arm64-v8a x86_64" diff --git a/scripts/android-build-common.sh b/scripts/android-build-common.sh deleted file mode 100644 index 11fda67..0000000 --- a/scripts/android-build-common.sh +++ /dev/null @@ -1,292 +0,0 @@ -#!/bin/bash - -SCRIPT_PATH=$(dirname "${BASH_SOURCE[0]}") -SCRIPT_PATH=$(realpath "$SCRIPT_PATH") - -if [ -z $BUILD_ARCH ]; then - BUILD_ARCH="armeabi-v7a x86 x86_64 arm64-v8a" -fi - -if [ -z $NDK_TARGET ]; then - NDK_TARGET=21 -fi - -if [ -z $CMAKE_PROGRAM ]; then - CMAKE_PROGRAM=$(find $ANDROID_SDK/cmake -name cmake -type f -executable -print -quit) -fi - -if [ -z $CCACHE ]; then - CCACHE=$(which ccache) -fi - -if [ -z $ANDROID_NDK ]; then - ANDROID_NDK="missing" -fi - -if [ -z $ANDROID_SDK ]; then - ANDROID_SDK="missing" -fi - -if [ -z $BUILD_DST ]; then - BUILD_DST=$(pwd)/libs -fi - -if [ -z $BUILD_SRC ]; then - BUILD_SRC=$(pwd)/src -fi - -if [ -z $SCM_URL ]; then - SCM_URL="missing" -fi - -if [ -z $SCM_TAG ]; then - SCM_TAG=master -fi - -CLEAN_BUILD_DIR=0 - -function common_help { - echo "$(BASHSOURCE[0]) supports the following arguments:" - echo " --ndk The base directory of your android NDK defa" - echo " ANDROID_NDK=$ANDROID_NDK" - echo " --sdk The base directory of your android SDK defa" - echo " ANDROID_SDK=$ANDROID_SDK" - echo " --arch A list of architectures to build" - echo " BUILD_ARCH=$BUILD_ARCH" - echo " --dst The destination directory for include and library files" - echo " BUILD_DST=$BUILD_DST" - echo " --src The source directory for SCM checkout" - echo " BUILD_SRC=$BUILD_SRC" - echo " --url The SCM source url" - echo " SCM_URL=$SCM_URL" - echo " --tag The SCM branch or tag to check out" - echo " SCM_TAG=$SCM_TAG" - echo " --clean Clean the destination before build" - echo " --help Display this help" - exit 0 -} - -function common_run { - echo "[RUN] $@" - "$@" - RES=$? - if [[ $RES -ne 0 ]]; - then - echo "[ERROR] $@ retured $RES" - exit 1 - fi -} - -function common_parse_arguments { - while [[ $# > 0 ]] - do - key="$1" - case $key in - --conf) - source "$2" - shift - ;; - - --target) - NDK_TARGET="$2" - shift - ;; - - --ndk) - ANDROID_NDK="$2" - shift - ;; - - --sdk) - ANDROID_SDK="$2" - CMAKE_PROGRAM=$(find $ANDROID_SDK/cmake -name cmake -type f -executable -print -quit) - shift - ;; - - --arch) - BUILD_ARCH="$2" - shift - ;; - - --dst) - BUILD_DST="$2" - shift - ;; - - --src) - BUILD_SRC="$2" - shift - ;; - - --url) - SCM_URL="$2" - shift - ;; - - --tag) - SCM_TAG="$2" - shift - ;; - - --clean) - CLEAN_BUILD_DIR=1 - shift - ;; - - --help) - common_help - shift - ;; - - *) # Unknown - ;; - esac - shift - done -} - -function common_check_requirements { - if [[ ! -d $ANDROID_NDK ]]; - then - echo "export ANDROID_NDK to point to your NDK location." - exit 1 - fi - - if [[ ! -d $ANDROID_SDK ]]; - then - echo "export ANDROID_SDK to point to your SDK location." - exit 1 - fi - if [[ -z $BUILD_DST ]]; - then - echo "Destination directory not valid" - exit 1 - fi - - if [[ -z $BUILD_SRC ]]; - then - echo "Source directory not valid" - exit 1 - fi - - if [[ -z $SCM_URL ]]; - then - echo "Source URL not defined! Define SCM_URL" - exit 1 - fi - - if [[ -z $SCM_TAG ]]; - then - echo "SCM TAG / BRANCH not defined! Define SCM_TAG" - exit 1 - fi - - if [[ -z $NDK_TARGET ]]; - then - echo "Android platform NDK_TARGET not defined" - exit 1 - fi - - if [ -x $ANDROID_NDK/ndk-build ]; then - NDK_BUILD=$ANDROID_NDK/ndk-build - else - echo "ndk-build not found in NDK directory $ANDROID_NDK" - echo "assuming ndk-build is in path..." - NDK_BUILD=ndk-build - fi - - if [ -z $CMAKE_PROGRAM ]; then - CMAKE_PROGRAM=$(find $ANDROID_SDK/cmake -name cmake -type f -executable -print -quit) - fi - - for CMD in make git $CMAKE_PROGRAM $NDK_BUILD - do - if ! type $CMD >/dev/null; then - echo "Command $CMD not found. Install and add it to the PATH." - exit 1 - fi - done - - if [ "${BUILD_SRC:0:1}" != "/" ]; - then - BUILD_SRC=$(pwd)/$BUILD_SRC - fi - if [ "${BUILD_DST:0:1}" != "/" ]; - then - BUILD_DST=$(pwd)/$BUILD_DST - fi -} - -function common_update { - if [ $# -ne 3 ]; - then - echo "Invalid arguments to update function $@" - exit 1 - fi - SCM_URL=$1 - SCM_TAG=$2 - BUILD_SRC=$3 - - echo "Preparing checkout..." - BASE=$(pwd) - CACHE=$SCRIPT_PATH/../cache - common_run mkdir -p $CACHE - TARFILE="$CACHE/$SCM_TAG.tar.gz" - - - if [[ ! -f "$TARFILE" ]]; - then - common_run wget -O "$TARFILE" "$SCM_URL/archive/$SCM_TAG.tar.gz" - fi - - if [[ -d $BUILD_SRC ]]; - then - common_run rm -rf $BUILD_SRC - fi - common_run mkdir -p $BUILD_SRC - common_run cd $BUILD_SRC - common_run tar zxf "$TARFILE" --strip 1 - common_run cd $BASE - -} - -function common_clean { - if [ $CLEAN_BUILD_DIR -ne 1 ]; - then - return - fi - - if [ $# -ne 1 ]; - then - echo "Invalid arguments to clean function $@" - exit 1 - fi - - echo "Cleaning up $1..." - common_run rm -rf $1 -} - -function common_copy { - if [ $# -ne 2 ]; - then - echo "Invalid arguments to copy function $@" - exit 1 - fi - if [ ! -d $1 ] || [ ! -d $1/include ] || [ ! -d $1/libs ]; - then - echo "Invalid source $1" - exit 1 - fi - if [ -z $2 ]; - then - echo "Invalid destination $2" - exit 1 - fi - - if [ ! -d $2 ]; - then - common_run mkdir -p $2 - fi - common_run cp -L -r $1/include $2 - common_run cp -L -r $1/libs/* $2 -} diff --git a/scripts/android-build-freerdp.sh b/scripts/android-build-freerdp.sh deleted file mode 100755 index 40f26f2..0000000 --- a/scripts/android-build-freerdp.sh +++ /dev/null @@ -1,168 +0,0 @@ -#!/bin/bash - -JPEG_TAG=master -OPENH264_TAG=master -OPENSSL_TAG=master - -WITH_JPEG=0 -WITH_OPENH264=0 -WITH_OPENSSL=0 - -SRC_DIR=$(dirname "${BASH_SOURCE[0]}") -SRC_DIR=$(realpath "$SRC_DIR") -BUILD_SRC=$(pwd) -BUILD_DST=$(pwd) - -CMAKE_BUILD_TYPE=Debug -BUILD_DEPS=0 - -SCRIPT_PATH=$(dirname "${BASH_SOURCE[0]}") -source $SCRIPT_PATH/android-build-common.sh -source $SCRIPT_PATH/android-build.conf - -# Parse arguments. -REMAINING="" -while [[ $# > 0 ]] -do - key="$1" - case $key in - --freerdp-src) - SRC_DIR="$2" - shift - ;; - --jpeg) - WITH_JPEG=1 - shift - ;; - --openh264) - WITH_OPENH264=1 - shift - ;; - --openh264-ndk) - shift - ANDROID_NDK_OPENH264=$1 - shift - ;; - --openssl) - WITH_OPENSSL=1 - shift - ;; - --debug) - CMAKE_BUILD_TYPE=Debug - shift - ;; - --release) - CMAKE_BUILD_TYPE=Release - shift - ;; - --relWithDebug) - CMAKE_BUILD_TYPE=RelWithDebug - shift - ;; - --build-deps) - BUILD_DEPS=1 - shift - ;; - *) - REMAINING="$REMAINING $key" - shift - ;; - esac -done -common_parse_arguments $REMAINING - -# clean up top -if [ -d $BUILD_SRC ]; -then - common_clean $BUILD_SRC -fi - -if [ -d $BUILD_DST ]; -then - common_run mkdir -p $BUILD_DST -fi - -# Prepare the environment -common_run mkdir -p $BUILD_SRC - -CMAKE_CMD_ARGS="-DANDROID_NDK=$ANDROID_NDK \ - -DANDROID_NATIVE_API_LEVEL=android-${NDK_TARGET} \ - -DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK/build/cmake/android.toolchain.cmake \ - -DCMAKE_BUILD_TYPE=$CMAKE_BUILD_TYPE \ - -DFREERDP_EXTERNAL_PATH=$BUILD_DST \ - -DCMAKE_MAKE_PROGRAM=make" - -BASE=$(pwd) -for ARCH in $BUILD_ARCH -do - # build dependencies. - if [ $WITH_JPEG -ne 0 ]; - then - if [ $BUILD_DEPS -ne 0 ]; - then - common_run bash $SCRIPT_PATH/android-build-jpeg.sh \ - --src $BUILD_SRC/jpeg --dst $BUILD_DST \ - --ndk $ANDROID_NDK \ - --arch $ARCH \ - --target $NDK_TARGET \ - --tag $JPEG_TAG - fi - CMAKE_CMD_ARGS="$CMAKE_CMD_ARGS -DWITH_JPEG=ON" - else - CMAKE_CMD_ARGS="$CMAKE_CMD_ARGS -DWITH_JPEG=OFF" - fi - if [ $WITH_OPENH264 -ne 0 ]; - then - if [ -z "$ANDROID_NDK_OPENH264" ] - then - echo - echo "Warning: Missing openh264-ndk, using $ANDROID_NDK" >&2 - echo - ANDROID_NDK_OPENH264=$ANDROID_NDK - fi - if [ $BUILD_DEPS -ne 0 ]; - then - common_run bash $SCRIPT_PATH/android-build-openh264.sh \ - --src $BUILD_SRC/openh264 --dst $BUILD_DST \ - --sdk "$ANDROID_SDK" \ - --ndk "$ANDROID_NDK_OPENH264" \ - --arch $ARCH \ - --target $NDK_TARGET \ - --tag $OPENH264_TAG - fi - CMAKE_CMD_ARGS="$CMAKE_CMD_ARGS -DWITH_OPENH264=ON" - else - CMAKE_CMD_ARGS="$CMAKE_CMD_ARGS -DWITH_OPENH264=OFF" - fi - if [ $WITH_OPENSSL -ne 0 ]; - then - if [ $BUILD_DEPS -ne 0 ]; - then - common_run bash $SCRIPT_PATH/android-build-openssl.sh \ - --src $BUILD_SRC/openssl --dst $BUILD_DST \ - --sdk "$ANDROID_SDK" \ - --ndk $ANDROID_NDK \ - --arch $ARCH \ - --target $NDK_TARGET \ - --tag $OPENSSL_TAG - fi - fi - - # Build and install the library. - if [ $DEPS_ONLY -eq 0 ]; - then - common_run cd $BASE - common_run mkdir -p $BUILD_SRC/freerdp-build/$ARCH - common_run cd $BUILD_SRC/freerdp-build/$ARCH - common_run export ANDROID_NDK=$ANDROID_NDK - common_run $CMAKE_PROGRAM $CMAKE_CMD_ARGS \ - -DANDROID_ABI=$ARCH \ - -DCMAKE_INSTALL_PREFIX=$BUILD_DST/$ARCH \ - -DCMAKE_INSTALL_LIBDIR=. \ - $SRC_DIR - echo $(pwd) - common_run cmake --build . --target install - fi -done - -echo "Successfully build library for architectures $BUILD_ARCH" diff --git a/scripts/android-build-jpeg.sh b/scripts/android-build-jpeg.sh deleted file mode 100755 index dafcf89..0000000 --- a/scripts/android-build-jpeg.sh +++ /dev/null @@ -1,40 +0,0 @@ -#!/bin/bash -SCM_URL=https://github.com/akallabeth/jpeg8d -SCM_TAG=master - -source $(dirname "${BASH_SOURCE[0]}")/android-build-common.sh - -function usage { - echo $0 [arguments] - echo "\tThe script checks out the OpenH264 git repository" - echo "\tto a local source directory, builds and installs" - echo "\tthe library for all architectures defined to" - echo "\tthe destination directory." - echo "" - echo "\t[-s|--source-dir ]" - echo "\t[-d|--destination-dir ]" - echo "\t[-a|--arch ]" - echo "\t[-t|--tag ]" - echo "\t[--scm-url ]" - echo "\t[--ndk ]" - echo "\t[--sdk ]" - exit 1 -} - -function build { - echo "Building architectures $BUILD_ARCH..." - BASE=$(pwd) - common_run cd $BUILD_SRC - common_run $NDK_BUILD V=1 APP_ABI="${BUILD_ARCH}" NDK_TOOLCHAIN_VERSION=4.9 -j clean - common_run $NDK_BUILD V=1 APP_ABI="${BUILD_ARCH}" NDK_TOOLCHAIN_VERSION=4.9 -j - common_run cd $BASE -} - -# Run the main program. -common_parse_arguments $@ -common_check_requirements -common_update $SCM_URL $SCM_TAG $BUILD_SRC - -build - -common_copy $BUILD_SRC $BUILD_DST diff --git a/scripts/android-build-openh264.sh b/scripts/android-build-openh264.sh deleted file mode 100755 index 5e9abed..0000000 --- a/scripts/android-build-openh264.sh +++ /dev/null @@ -1,64 +0,0 @@ -#!/bin/bash -SCM_URL=https://github.com/cisco/openh264 -SCM_TAG=master - -source $(dirname "${BASH_SOURCE[0]}")/android-build-common.sh - -function build { - echo "Building architecture $1..." - BASE=$(pwd) - common_run cd $BUILD_SRC - PATH=$ANDROID_NDK:$PATH - MAKE="make PATH=$PATH ENABLEPIC=Yes OS=android NDKROOT=$ANDROID_NDK TARGET=android-$2 NDKLEVEL=$2 ARCH=$1 -j libraries" - - common_run export QUIET_AR="$CCACHE " - common_run export QUIET_ASM="$CCACHE " - common_run export QUIET_CC="$CCACHE " - common_run export QUIET_CCAR="$CCACHE " - common_run export QUIET_CXX="$CCACHE " - - common_run $MAKE -j - # Install creates a non optimal directory layout, fix that - common_run $MAKE PREFIX=$BUILD_SRC/libs/$1 install - common_run cd $BASE -} - -# Run the main program. -common_parse_arguments $@ -common_check_requirements -common_update $SCM_URL $SCM_TAG $BUILD_SRC - - -for ARCH in $BUILD_ARCH -do - case $ARCH in - "armeabi") - OARCH="arm" - ;; - "armeabi-v7a") - OARCH="arm" - ;; - "arm64-v8a") - OARCH="arm64" - ;; - *) - OARCH=$ARCH - ;; - esac - - echo "$ARCH=$OARCH" - - build $OARCH $NDK_TARGET - - if [ ! -d $BUILD_DST/$ARCH/include ]; - then - common_run mkdir -p $BUILD_DST/$ARCH/include - fi - - common_run cp -L -r $BUILD_SRC/libs/$OARCH/include/ $BUILD_DST/$ARCH/ - if [ ! -d $BUILD_DST/$ARCH ]; - then - common_run mkdir -p $BUILD_DST/$ARCH - fi - common_run cp -L $BUILD_SRC/libs/$OARCH/lib/*.so $BUILD_DST/$ARCH/ -done diff --git a/scripts/android-build-openssl.sh b/scripts/android-build-openssl.sh deleted file mode 100755 index 834e53a..0000000 --- a/scripts/android-build-openssl.sh +++ /dev/null @@ -1,77 +0,0 @@ -#!/bin/bash - -SCM_URL=https://github.com/openssl/openssl -SCM_TAG=master - -COMPILER=4.9 - -source $(dirname "${BASH_SOURCE[0]}")/android-build-common.sh - -function build { - if [ $# -ne 2 ]; - then - echo "Invalid arguments $@" - exit 1 - fi - - CONFIG=$1 - DST_PREFIX=$2 - - common_run export CC=clang - common_run export PATH=$(${SCRIPT_PATH}/toolchains_path.py --ndk ${ANDROID_NDK}):$ORG_PATH - common_run export ANDROID_NDK - - echo "CONFIG=$CONFIG" - echo "DST_PREFIX=$DST_PREFIX" - echo "PATH=$PATH" - - BASE=$(pwd) - DST_DIR=$BUILD_DST/$DST_PREFIX - common_run cd $BUILD_SRC - common_run ./Configure ${CONFIG} -D__ANDROID_API__=$NDK_TARGET - common_run make SHLIB_EXT=.so -j build_libs - - if [ ! -d $DST_DIR ]; - then - common_run mkdir -p $DST_DIR - fi - - common_run cp *.so $DST_DIR/ - common_run cd $BASE -} - -# Run the main program. -common_parse_arguments $@ -common_check_requirements -common_update $SCM_URL $SCM_TAG $BUILD_SRC - -ORG_PATH=$PATH -for ARCH in $BUILD_ARCH -do - - case $ARCH in - "armeabi-v7a") - build "android-arm" "armeabi-v7a" - ;; - "x86") - build "android-x86" "x86" - ;; - "arm64-v8a") - build "android-arm64" "arm64-v8a" - ;; - "x86_64") - build "android-x86_64" "x86_64" - ;; - *) - echo "[WARNING] Skipping unsupported architecture $ARCH" - continue - ;; - esac -done - -if [ ! -d $BUILD_DST/$ARCH/include ]; -then - common_run mkdir -p $BUILD_DST/$ARCH/include -fi -common_run cp -L -R $BUILD_SRC/include/openssl $BUILD_DST/$ARCH/include/ - diff --git a/scripts/android-build.conf b/scripts/android-build.conf deleted file mode 100644 index c8eb40c..0000000 --- a/scripts/android-build.conf +++ /dev/null @@ -1,29 +0,0 @@ -#!/bin/bash -# -# Android build confguration -# -# Note: This is a simple configuration to build all -# architectures in one rush. -# Since android 64 bit support was introduced with NDK API 21 -# this is the minimal common denominator. -# If you require support for older NDK API levels, -# create seperate configurations for each NDK API level -# and architecture you want to support. -WITH_JPEG=0 -WITH_OPENH264=0 -WITH_OPENSSL=1 -BUILD_DEPS=1 -DEPS_ONLY=0 -NDK_TARGET=26 - -JPEG_TAG=master -OPENH264_TAG=v1.8.0 # NOTE: NDK r15c or earlier needed in --openh624-ndk for v1.8.0 -OPENSSL_TAG=OpenSSL_1_1_1j - -SRC_DIR=$SCRIPT_PATH/.. -BUILD_DST=$SCRIPT_PATH/../client/Android/Studio/freeRDPCore/src/main/jniLibs -BUILD_SRC=$SRC_DIR/build - -CMAKE_BUILD_TYPE=Debug - -BUILD_ARCH="armeabi-v7a x86 arm64-v8a x86_64" diff --git a/uwac/libuwac/uwac-priv.h b/uwac/libuwac/uwac-priv.h index aed3898..cbc5704 100644 --- a/uwac/libuwac/uwac-priv.h +++ b/uwac/libuwac/uwac-priv.h @@ -255,6 +255,14 @@ struct uwac_window int pointer_current_cursor; }; +/**@brief data to pass to wl_buffer release listener */ +struct uwac_buffer_release_data +{ + UwacWindow* window; + int bufferIdx; +}; +typedef struct uwac_buffer_release_data UwacBufferReleaseData; + /* in uwa-display.c */ UwacEvent* UwacDisplayNewEvent(UwacDisplay* d, int type); int UwacDisplayWatchFd(UwacDisplay* display, int fd, uint32_t events, UwacTask* task); diff --git a/uwac/libuwac/uwac-window.c b/uwac/libuwac/uwac-window.c index bf70af2..8e6f08d 100644 --- a/uwac/libuwac/uwac-window.c +++ b/uwac/libuwac/uwac-window.c @@ -46,7 +46,8 @@ static int bppFromShmFormat(enum wl_shm_format format) static void buffer_release(void* data, struct wl_buffer* buffer) { - UwacBuffer* uwacBuffer = (UwacBuffer*)data; + UwacBufferReleaseData* releaseData = data; + UwacBuffer* uwacBuffer = &releaseData->window->buffers[releaseData->bufferIdx]; uwacBuffer->used = false; } @@ -64,7 +65,10 @@ static void UwacWindowDestroyBuffers(UwacWindow* w) #else region16_uninit(&buffer->damage); #endif + UwacBufferReleaseData* releaseData = + (UwacBufferReleaseData*)wl_buffer_get_user_data(buffer->wayland_buffer); wl_buffer_destroy(buffer->wayland_buffer); + free(releaseData); munmap(buffer->data, buffer->size); } @@ -342,7 +346,8 @@ int UwacWindowShmAllocBuffers(UwacWindow* w, int nbuffers, int allocSize, uint32 for (i = 0; i < nbuffers; i++) { - UwacBuffer* buffer = &w->buffers[w->nbuffers + i]; + int bufferIdx = w->nbuffers + i; + UwacBuffer* buffer = &w->buffers[bufferIdx]; #ifdef HAVE_PIXMAN_REGION pixman_region32_init(&buffer->damage); #else @@ -352,7 +357,10 @@ int UwacWindowShmAllocBuffers(UwacWindow* w, int nbuffers, int allocSize, uint32 buffer->size = allocSize; buffer->wayland_buffer = wl_shm_pool_create_buffer(pool, allocSize * i, width, height, w->stride, format); - wl_buffer_add_listener(buffer->wayland_buffer, &buffer_listener, buffer); + UwacBufferReleaseData* listener_data = xmalloc(sizeof(UwacBufferReleaseData)); + listener_data->window = w; + listener_data->bufferIdx = bufferIdx; + wl_buffer_add_listener(buffer->wayland_buffer, &buffer_listener, listener_data); } wl_shm_pool_destroy(pool); diff --git a/winpr/CMakeLists.txt b/winpr/CMakeLists.txt index 620f9a7..3bad25b 100644 --- a/winpr/CMakeLists.txt +++ b/winpr/CMakeLists.txt @@ -51,7 +51,7 @@ if (NOT WIN32) endif() # Soname versioning -set(RAW_VERSION_STRING "2.5.0") +set(RAW_VERSION_STRING "2.6.0") if(EXISTS "${CMAKE_SOURCE_DIR}/.source_tag") file(READ ${CMAKE_SOURCE_DIR}/.source_tag RAW_VERSION_STRING) elseif(USE_VERSION_FROM_GIT_TAG) diff --git a/winpr/libwinpr/crt/CMakeLists.txt b/winpr/libwinpr/crt/CMakeLists.txt index a2d0dda..c1645b9 100644 --- a/winpr/libwinpr/crt/CMakeLists.txt +++ b/winpr/libwinpr/crt/CMakeLists.txt @@ -30,7 +30,7 @@ endif(NOT WITH_ICU) if (WITH_ICU) find_package(ICU REQUIRED i18n uc io) - include_directories(${ICU_INCLUDE_DIRS}) + winpr_include_directory_add(${ICU_INCLUDE_DIRS}) winpr_library_add_private(${ICU_LIBRARIES}) endif (WITH_ICU) diff --git a/winpr/libwinpr/sspicli/sspicli.c b/winpr/libwinpr/sspicli/sspicli.c index 0394169..5a13b99 100644 --- a/winpr/libwinpr/sspicli/sspicli.c +++ b/winpr/libwinpr/sspicli/sspicli.c @@ -21,8 +21,11 @@ #include "config.h" #endif +#include #include +#define WINPR_ASSERT(x) assert(x) + /** * sspicli.dll: * @@ -60,6 +63,12 @@ #include #endif +#if defined(HAVE_GETPWUID_R) +#include +#include +#include +#endif + #include #include @@ -200,31 +209,33 @@ BOOL LogonUserExW(LPCWSTR lpszUsername, LPCWSTR lpszDomain, LPCWSTR lpszPassword BOOL GetUserNameExA(EXTENDED_NAME_FORMAT NameFormat, LPSTR lpNameBuffer, PULONG nSize) { - size_t length; - char login[MAX_PATH]; + WINPR_ASSERT(lpNameBuffer); + WINPR_ASSERT(nSize); switch (NameFormat) { case NameSamCompatible: -#ifndef HAVE_GETLOGIN_R - strncpy(login, getlogin(), sizeof(login)); -#else - if (getlogin_r(login, sizeof(login)) != 0) +#if defined(HAVE_GETPWUID_R) + { + int rc; + struct passwd pwd = { 0 }; + struct passwd* result = NULL; + uid_t uid = getuid(); + + rc = getpwuid_r(uid, &pwd, lpNameBuffer, *nSize, &result); + if (rc != 0) return FALSE; + if (result == NULL) + return FALSE; + } +#elif defined(HAVE_GETLOGIN_R) + if (getlogin_r(lpNameBuffer, *nSize) != 0) + return FALSE; +#else + strncpy(lpNameBuffer, getlogin(), *nSize); #endif - length = strlen(login); - - if (*nSize >= length) - { - CopyMemory(lpNameBuffer, login, length + 1); - return TRUE; - } - else - { - *nSize = length + 1; - } - - break; + *nSize = strnlen(lpNameBuffer, *nSize); + return TRUE; case NameFullyQualifiedDN: case NameDisplay: @@ -245,7 +256,29 @@ BOOL GetUserNameExA(EXTENDED_NAME_FORMAT NameFormat, LPSTR lpNameBuffer, PULONG BOOL GetUserNameExW(EXTENDED_NAME_FORMAT NameFormat, LPWSTR lpNameBuffer, PULONG nSize) { - return 0; + int res; + BOOL rc = FALSE; + char* name; + + WINPR_ASSERT(nSize); + WINPR_ASSERT(lpNameBuffer); + + name = calloc(1, *nSize + 1); + if (!name) + goto fail; + + if (!GetUserNameExA(NameFormat, name, nSize)) + goto fail; + + res = ConvertToUnicode(CP_UTF8, 0, name, -1, &lpNameBuffer, *nSize); + if (res < 0) + goto fail; + + *nSize = res + 1; + rc = TRUE; +fail: + free(name); + return rc; } #endif diff --git a/winpr/libwinpr/synch/test/TestSynchMultipleThreads.c b/winpr/libwinpr/synch/test/TestSynchMultipleThreads.c index b0bf8f2..30086d4 100644 --- a/winpr/libwinpr/synch/test/TestSynchMultipleThreads.c +++ b/winpr/libwinpr/synch/test/TestSynchMultipleThreads.c @@ -1,15 +1,14 @@ - #include #include #include #include -#define THREADS 24 +#define THREADS 8 static DWORD WINAPI test_thread(LPVOID arg) { - long timeout = 100 + (rand() % 1000); + long timeout = 30 + (rand() % 100); WINPR_UNUSED(arg); Sleep(timeout); ExitThread(0); @@ -22,7 +21,7 @@ static int start_threads(DWORD count, HANDLE* threads) for (i = 0; i < count; i++) { - threads[i] = CreateThread(NULL, 0, test_thread, NULL, 0, NULL); + threads[i] = CreateThread(NULL, 0, test_thread, NULL, CREATE_SUSPENDED, NULL); if (!threads[i]) { @@ -31,38 +30,45 @@ static int start_threads(DWORD count, HANDLE* threads) } } + for (i = 0; i < count; i++) + ResumeThread(threads[i]); return 0; } static int close_threads(DWORD count, HANDLE* threads) { + int rc = 0; DWORD i; for (i = 0; i < count; i++) { + if (!threads[i]) + continue; + if (!CloseHandle(threads[i])) { fprintf(stderr, "%s: CloseHandle [%" PRIu32 "] failure\n", __FUNCTION__, i); - return -1; + rc = -1; } + threads[i] = NULL; } - return 0; + return rc; } static BOOL TestWaitForAll(void) { BOOL rc = FALSE; DWORD ret; - HANDLE threads[THREADS]; + HANDLE threads[THREADS] = { 0 }; /* WaitForAll, timeout */ if (start_threads(THREADS, threads)) { fprintf(stderr, "%s: start_threads failed\n", __FUNCTION__); - return FALSE; + goto fail; } - ret = WaitForMultipleObjects(THREADS, threads, TRUE, 50); + ret = WaitForMultipleObjects(THREADS, threads, TRUE, 10); if (ret != WAIT_TIMEOUT) { fprintf(stderr, "%s: WaitForMultipleObjects bWaitAll, timeout 50 failed, ret=%d\n", @@ -76,14 +82,14 @@ static BOOL TestWaitForAll(void) goto fail; } + rc = TRUE; +fail: if (close_threads(THREADS, threads)) { fprintf(stderr, "%s: close_threads failed\n", __FUNCTION__); return FALSE; } - rc = TRUE; -fail: return rc; } @@ -91,12 +97,12 @@ static BOOL TestWaitOne(void) { BOOL rc = FALSE; DWORD ret; - HANDLE threads[THREADS]; + HANDLE threads[THREADS] = { 0 }; /* WaitForAll, timeout */ if (start_threads(THREADS, threads)) { fprintf(stderr, "%s: start_threads failed\n", __FUNCTION__); - return FALSE; + goto fail; } ret = WaitForMultipleObjects(THREADS, threads, FALSE, INFINITE); @@ -112,14 +118,14 @@ static BOOL TestWaitOne(void) goto fail; } + rc = TRUE; +fail: if (close_threads(THREADS, threads)) { fprintf(stderr, "%s: close_threads failed\n", __FUNCTION__); return FALSE; } - rc = TRUE; -fail: return rc; } @@ -127,15 +133,15 @@ static BOOL TestWaitOneTimeout(void) { BOOL rc = FALSE; DWORD ret; - HANDLE threads[THREADS]; + HANDLE threads[THREADS] = { 0 }; /* WaitForAll, timeout */ if (start_threads(THREADS, threads)) { fprintf(stderr, "%s: start_threads failed\n", __FUNCTION__); - return FALSE; + goto fail; } - ret = WaitForMultipleObjects(THREADS, threads, FALSE, 50); + ret = WaitForMultipleObjects(THREADS, threads, FALSE, 1); if (ret != WAIT_TIMEOUT) { fprintf(stderr, "%s: WaitForMultipleObjects timeout 50 failed, ret=%d\n", __FUNCTION__, @@ -148,15 +154,14 @@ static BOOL TestWaitOneTimeout(void) fprintf(stderr, "%s: WaitForMultipleObjects bWaitAll, INFINITE failed\n", __FUNCTION__); goto fail; } - + rc = TRUE; +fail: if (close_threads(THREADS, threads)) { fprintf(stderr, "%s: close_threads failed\n", __FUNCTION__); return FALSE; } - rc = TRUE; -fail: return rc; } @@ -164,12 +169,12 @@ static BOOL TestWaitOneTimeoutMultijoin(void) { BOOL rc = FALSE; DWORD ret, i; - HANDLE threads[THREADS]; + HANDLE threads[THREADS] = { 0 }; /* WaitForAll, timeout */ if (start_threads(THREADS, threads)) { fprintf(stderr, "%s: start_threads failed\n", __FUNCTION__); - return FALSE; + goto fail; } for (i = 0; i < THREADS; i++) @@ -177,7 +182,7 @@ static BOOL TestWaitOneTimeoutMultijoin(void) ret = WaitForMultipleObjects(THREADS, threads, FALSE, 0); if (ret != WAIT_TIMEOUT) { - fprintf(stderr, "%s: WaitForMultipleObjects timeout 50 failed, ret=%d\n", __FUNCTION__, + fprintf(stderr, "%s: WaitForMultipleObjects timeout 0 failed, ret=%d\n", __FUNCTION__, ret); goto fail; } @@ -189,34 +194,37 @@ static BOOL TestWaitOneTimeoutMultijoin(void) goto fail; } + rc = TRUE; +fail: if (close_threads(THREADS, threads)) { fprintf(stderr, "%s: close_threads failed\n", __FUNCTION__); return FALSE; } - rc = TRUE; -fail: return rc; } static BOOL TestDetach(void) { - HANDLE threads[THREADS]; + BOOL rc = FALSE; + HANDLE threads[THREADS] = { 0 }; /* WaitForAll, timeout */ if (start_threads(THREADS, threads)) { fprintf(stderr, "%s: start_threads failed\n", __FUNCTION__); - return FALSE; + goto fail; } + rc = TRUE; +fail: if (close_threads(THREADS, threads)) { fprintf(stderr, "%s: close_threads failed\n", __FUNCTION__); return FALSE; } - return TRUE; + return rc; } int TestSynchMultipleThreads(int argc, char* argv[]) diff --git a/winpr/libwinpr/utils/sam.c b/winpr/libwinpr/utils/sam.c index 094475f..7270bf6 100644 --- a/winpr/libwinpr/utils/sam.c +++ b/winpr/libwinpr/utils/sam.c @@ -173,23 +173,29 @@ static void SamLookupFinish(WINPR_SAM* sam) static void HexStrToBin(const char* str, BYTE* bin, size_t length) { size_t i; - CharUpperBuffA(str, length * 2); for (i = 0; i < length; i++) { - bin[i] = 0; + char cur = str[2 * i]; + char curNext = str[2 * i + 1]; + BYTE* curBin = &bin[i]; - if ((str[i * 2] >= '0') && (str[i * 2] <= '9')) - bin[i] |= (str[i * 2] - '0') << 4; + CharUpperBuffA(&cur, 1); + CharUpperBuffA(&curNext, 1); - if ((str[i * 2] >= 'A') && (str[i * 2] <= 'F')) - bin[i] |= (str[i * 2] - 'A' + 10) << 4; + *curBin = 0; - if ((str[i * 2 + 1] >= '0') && (str[i * 2 + 1] <= '9')) - bin[i] |= (str[i * 2 + 1] - '0'); + if ((cur >= '0') && (cur <= '9')) + *curBin |= (cur - '0') << 4; - if ((str[i * 2 + 1] >= 'A') && (str[i * 2 + 1] <= 'F')) - bin[i] |= (str[i * 2 + 1] - 'A' + 10); + if ((cur >= 'A') && (cur <= 'F')) + *curBin |= (cur - 'A' + 10) << 4; + + if ((curNext >= '0') && (curNext <= '9')) + *curBin |= (curNext - '0'); + + if ((curNext >= 'A') && (curNext <= 'F')) + *curBin |= (curNext - 'A' + 10); } }