Added image scaling api for software drawing.

For future GFX channel functions an image scaling function is required.
This moves the implementation from wayland client to core library
and adds support for the much faster SWScale library.
This commit is contained in:
Armin Novak 2019-05-06 13:18:31 +02:00
parent ef104ed897
commit 6a8755a763
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;
}