Merge pull request #5381 from akallabeth/swscale

Added image scaling api for software drawing.
This commit is contained in:
Martin Fleisz 2019-05-07 11:07:50 +02:00 committed by GitHub
commit 49805aae89
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 186 additions and 58 deletions

View File

@ -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})

View File

@ -34,9 +34,6 @@
#include <linux/input.h>
#include <uwac/uwac.h>
#if defined(CAIRO_FOUND)
#include <cairo.h>
#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;
}

View File

@ -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)

14
cmake/FindSWScale.cmake Normal file
View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -33,6 +33,14 @@
#include <freerdp/freerdp.h>
#include <freerdp/primitives.h>
#if defined(CAIRO_FOUND)
#include <cairo.h>
#endif
#if defined(SWSCALE_FOUND)
#include <libswscale/swscale.h>
#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;
}