diff --git a/client/Wayland/CMakeLists.txt b/client/Wayland/CMakeLists.txt index 2256c397c..a9e19e36e 100644 --- a/client/Wayland/CMakeLists.txt +++ b/client/Wayland/CMakeLists.txt @@ -37,16 +37,7 @@ set(${MODULE_PREFIX}_SRCS wlf_channels.h ) -find_package(Cairo) - list (APPEND ${MODULE_PREFIX}_LIBS freerdp-client freerdp uwac) -if (CAIRO_FOUND) - add_definitions(-DCAIRO_FOUND=1) - include_directories(${CAIRO_INCLUDE_DIR}) - list(APPEND ${MODULE_PREFIX}_LIBS ${CAIRO_LIBRARY}) -else(CAIRO_FOUND) - message(WARNING "libcairo not detected, compiling without wayland smart scaling support!") -endif(CAIRO_FOUND) add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS}) diff --git a/client/Wayland/wlfreerdp.c b/client/Wayland/wlfreerdp.c index 99fa39fa3..09a49c1fb 100644 --- a/client/Wayland/wlfreerdp.c +++ b/client/Wayland/wlfreerdp.c @@ -34,9 +34,6 @@ #include #include -#if defined(CAIRO_FOUND) -#include -#endif #include "wlfreerdp.h" #include "wlf_input.h" @@ -623,44 +620,8 @@ BOOL wlf_copy_image(const void* src, size_t srcStride, size_t srcWidth, size_t s if (scale) { -#if defined(CAIRO_FOUND) - const double sx = (double)dstWidth / (double)srcWidth; - const double sy = (double)dstHeight / (double)srcHeight; - cairo_t* cairo_context; - cairo_surface_t* csrc, *cdst; - - if ((srcWidth > INT_MAX) || (srcHeight > INT_MAX) || (srcStride > INT_MAX)) - return FALSE; - - if ((dstWidth > INT_MAX) || (dstHeight > INT_MAX) || (dstStride > INT_MAX)) - return FALSE; - - csrc = cairo_image_surface_create_for_data((void*)src, CAIRO_FORMAT_ARGB32, (int)srcWidth, - (int)srcHeight, (int)srcStride); - cdst = cairo_image_surface_create_for_data(dst, CAIRO_FORMAT_ARGB32, (int)dstWidth, - (int)dstHeight, (int)dstStride); - - if (!csrc || !cdst) - goto fail; - - cairo_context = cairo_create(cdst); - - if (!cairo_context) - goto fail2; - - cairo_scale(cairo_context, sx, sy); - cairo_set_operator(cairo_context, CAIRO_OPERATOR_SOURCE); - cairo_set_source_surface(cairo_context, csrc, 0, 0); - cairo_paint(cairo_context); - rc = TRUE; - fail2: - cairo_destroy(cairo_context); - fail: - cairo_surface_destroy(csrc); - cairo_surface_destroy(cdst); -#else - WLog_WARN(TAG, "SmartScaling requested but compiled without libcairo support!"); -#endif + return freerdp_image_scale(dst, PIXEL_FORMAT_BGRA32, dstStride, 0, 0, dstWidth, dstHeight, + src, PIXEL_FORMAT_BGRA32, srcStride, 0, 0, srcWidth, srcHeight); } else { @@ -698,8 +659,6 @@ BOOL wlf_scale_coordinates(rdpContext* context, UINT32* px, UINT32* py, BOOL fro if (!context->settings->SmartSizing) return TRUE; - /* If libcairo is not compiled, smart scaling is ignored. */ -#if defined(CAIRO_FOUND) gdi = context->gdi; if (UwacWindowGetDrawingBufferGeometry(wlf->window, &geometry, NULL) != UWAC_SUCCESS) @@ -719,6 +678,5 @@ BOOL wlf_scale_coordinates(rdpContext* context, UINT32* px, UINT32* py, BOOL fro *py /= sy; } -#endif return TRUE; } diff --git a/cmake/ConfigOptions.cmake b/cmake/ConfigOptions.cmake index 3e3589fa0..12a826bae 100644 --- a/cmake/ConfigOptions.cmake +++ b/cmake/ConfigOptions.cmake @@ -145,11 +145,14 @@ endif(WITH_FFMPEG) option(USE_VERSION_FROM_GIT_TAG "Extract FreeRDP version from git tag." OFF) -if(ANDROID) -include(ConfigOptionsAndroid) +option(WITH_CAIRO "Use CAIRO image library for screen resizing" OFF) +option(WITH_SWSCALE "Use SWScale image library for screen resizing" OFF) + +if (ANDROID) + include(ConfigOptionsAndroid) endif(ANDROID) -if(IOS) -include(ConfigOptionsiOS) +if (IOS) + include(ConfigOptionsiOS) endif(IOS) diff --git a/cmake/FindSWScale.cmake b/cmake/FindSWScale.cmake new file mode 100644 index 000000000..aa7747963 --- /dev/null +++ b/cmake/FindSWScale.cmake @@ -0,0 +1,14 @@ + +include(FindPkgConfig) + +if (PKG_CONFIG_FOUND) + pkg_check_modules(SWScale swscale) +endif() + +find_path(SWScale_INCLUDE_DIR libswscale / swscale.h PATHS $ {SWScale_INCLUDE_DIRS}) +find_library(SWScale_LIBRARY swscale PATHS $ {SWScale_LIBRARY_DIRS}) + +FIND_PACKAGE_HANDLE_STANDARD_ARGS(SWScale DEFAULT_MSG SWScale_INCLUDE_DIR SWScale_LIBRARY) + +mark_as_advanced(SWScale_INCLUDE_DIR SWScale_LIBRARY) + diff --git a/include/freerdp/codec/color.h b/include/freerdp/codec/color.h index 7e439522b..d33c65c4f 100644 --- a/include/freerdp/codec/color.h +++ b/include/freerdp/codec/color.h @@ -752,7 +752,7 @@ static INLINE BOOL WriteColor(BYTE* dst, UINT32 format, UINT32 color) * @return The converted pixel color in dstFormat representation */ static INLINE UINT32 FreeRDPConvertColor(UINT32 color, UINT32 srcFormat, - UINT32 dstFormat, const gdiPalette* palette) + UINT32 dstFormat, const gdiPalette* palette) { BYTE r = 0; BYTE g = 0; @@ -862,6 +862,32 @@ FREERDP_API BOOL freerdp_image_copy(BYTE* pDstData, DWORD DstFormat, UINT32 nSrcStep, UINT32 nXSrc, UINT32 nYSrc, const gdiPalette* palette, UINT32 flags); +/*** + * + * @param pDstData destination buffer + * @param DstFormat destination buffer format + * @param nDstStep destination buffer stride (line in bytes) 0 for default + * @param nXDst destination buffer offset x + * @param nYDst destination buffer offset y + * @param nDstWidth width of destination in pixels + * @param nDstHeight height of destination in pixels + * @param pSrcData source buffer + * @param SrcFormat source buffer format + * @param nSrcStep source buffer stride (line in bytes) 0 for default + * @param nXSrc source buffer x offset in pixels + * @param nYSrc source buffer y offset in pixels + * @param nSrcWidth width of source in pixels + * @param nSrcHeight height of source in pixels + * + * @return TRUE if success, FALSE otherwise + */ +FREERDP_API BOOL freerdp_image_scale(BYTE* pDstData, DWORD DstFormat, + UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst, + UINT32 nDstWidth, UINT32 nDstHeight, + const BYTE* pSrcData, DWORD SrcFormat, + UINT32 nSrcStep, UINT32 nXSrc, UINT32 nYSrc, + UINT32 nSrcWidth, UINT32 nSrcHeight); + /*** * * @param pDstData destionation buffer diff --git a/libfreerdp/CMakeLists.txt b/libfreerdp/CMakeLists.txt index f64ce090b..97baf54db 100644 --- a/libfreerdp/CMakeLists.txt +++ b/libfreerdp/CMakeLists.txt @@ -79,6 +79,28 @@ macro (freerdp_definition_add) set (LIBFREERDP_DEFINITIONS ${LIBFREERDP_DEFINITIONS} PARENT_SCOPE) endmacro() +if (WITH_SWSCALE) + find_package(SWScale REQUIRED) +endif(WITH_SWSCALE) +if (WITH_CAIRO) + find_package(Cairo REQUIRED) +endif(WITH_CAIRO) + +if (SWScale_FOUND) + add_definitions(-DSWSCALE_FOUND=1) + include_directories(${SWScale_INCLUDE_DIR}) + freerdp_library_add(${SWScale_LIBRARY}) +else(SWScale_FOUND) + + if (CAIRO_FOUND) + add_definitions(-DCAIRO_FOUND=1) + include_directories(${CAIRO_INCLUDE_DIR}) + freerdp_library_add(${CAIRO_LIBRARY}) + else(CAIRO_FOUND) + message(WARNING "neigter swscale nor libcairo detected, compiling without image scaling support!") + endif(CAIRO_FOUND) +endif(SWScale_FOUND) + set(${MODULE_PREFIX}_SUBMODULES utils common diff --git a/libfreerdp/codec/color.c b/libfreerdp/codec/color.c index 8a5e37197..5a7a626ef 100644 --- a/libfreerdp/codec/color.c +++ b/libfreerdp/codec/color.c @@ -33,6 +33,14 @@ #include #include +#if defined(CAIRO_FOUND) +#include +#endif + +#if defined(SWSCALE_FOUND) +#include +#endif + #define TAG FREERDP_TAG("color") BYTE* freerdp_glyph_convert(UINT32 width, UINT32 height, const BYTE* data) @@ -570,3 +578,109 @@ BOOL freerdp_image_fill(BYTE* pDstData, DWORD DstFormat, return TRUE; } + +#if defined(SWSCALE_FOUND) +static int av_format_for_buffer(UINT32 format) +{ + switch (format) + { + case PIXEL_FORMAT_ARGB32: + return AV_PIX_FMT_BGRA; + + case PIXEL_FORMAT_XRGB32: + return AV_PIX_FMT_BGR0; + + case PIXEL_FORMAT_BGRA32: + return AV_PIX_FMT_RGBA; + + case PIXEL_FORMAT_BGRX32: + return AV_PIX_FMT_RGB0; + + default: + return AV_PIX_FMT_NONE; + } +} +#endif + +BOOL freerdp_image_scale(BYTE* pDstData, DWORD DstFormat, UINT32 nDstStep, + UINT32 nXDst, UINT32 nYDst, UINT32 nDstWidth, UINT32 nDstHeight, + const BYTE* pSrcData, DWORD SrcFormat, UINT32 nSrcStep, + UINT32 nXSrc, UINT32 nYSrc, UINT32 nSrcWidth, UINT32 nSrcHeight) +{ + BOOL rc = FALSE; + const BYTE* src = &pSrcData[nXSrc * 4 + nYSrc * nSrcStep]; + BYTE* dst = &pDstData[nXDst * 4 + nYDst * nDstStep]; +#if defined(SWSCALE_FOUND) + { + int res; + struct SwsContext* resize; + int srcFormat = av_format_for_buffer(SrcFormat); + int dstFormat = av_format_for_buffer(DstFormat); + const int srcStep[1] = { nSrcStep }; + const int dstStep[1] = { nDstStep }; + + if ((srcFormat == AV_PIX_FMT_NONE) || (dstFormat == AV_PIX_FMT_NONE)) + return FALSE; + + resize = sws_getContext(nSrcWidth + nXSrc, nSrcHeight + nYSrc, srcFormat, + nDstWidth + nXDst, nDstHeight + nYDst, dstFormat, + SWS_BICUBIC, NULL, NULL, NULL); + + if (!resize) + goto fail; + + res = sws_scale(resize, &pSrcData, srcStep, 0, nSrcHeight + nYSrc, &pDstData, dstStep); + rc = (res == (nDstHeight + nYDst)); + fail: + sws_freeContext(resize); + } +#elif defined(CAIRO_FOUND) + { + const double sx = (double)nDstWidth / (double)nSrcWidth; + const double sy = (double)nDstHeight / (double)nSrcHeight; + cairo_t* cairo_context; + cairo_surface_t* csrc, *cdst; + + if ((nSrcWidth > INT_MAX) || (nSrcHeight > INT_MAX) || (nSrcStep > INT_MAX)) + return FALSE; + + if ((nDstWidth > INT_MAX) || (nDstHeight > INT_MAX) || (nDstStep > INT_MAX)) + return FALSE; + + csrc = cairo_image_surface_create_for_data((void*)src, + CAIRO_FORMAT_ARGB32, (int)nSrcWidth, (int)nSrcHeight, (int)nSrcStep); + cdst = cairo_image_surface_create_for_data(dst, + CAIRO_FORMAT_ARGB32, (int)nDstWidth, (int)nDstHeight, (int)nDstStep); + + if (!csrc || !cdst) + goto fail; + + cairo_context = cairo_create(cdst); + + if (!cairo_context) + goto fail2; + + cairo_scale(cairo_context, sx, sy); + cairo_set_operator(cairo_context, CAIRO_OPERATOR_SOURCE); + cairo_set_source_surface(cairo_context, csrc, 0, 0); + cairo_paint(cairo_context); + rc = TRUE; + fail2: + cairo_destroy(cairo_context); + fail: + cairo_surface_destroy(csrc); + cairo_surface_destroy(cdst); + } +#else + + if ((nDstWidth == nSrcWidth) && (nDstHeight == nSrcHeight)) + { + return freerdp_image_copy(pDstData, DstFormat, nDstStep, nXDst, nYDst, nDstWidth, nDstHeight, + pSrcData, SrcFormat, nSrcStep, nXSrc, nYSrc, + NULL, FREERDP_FLIP_NONE); + } + + WLog_WARN(TAG, "SmartScaling requested but compiled without libcairo support!"); +#endif + return rc; +}