Merge pull request #3214 from metalefty/x264-params

GFX: configurable x264 parameters
This commit is contained in:
metalefty 2024-08-23 14:24:41 +09:00 committed by GitHub
commit 854d060917
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 453 additions and 15 deletions

View File

@ -1,5 +1,6 @@
AM_CPPFLAGS = \
-DXRDP_TOP_SRCDIR=\"$(top_srcdir)\" \
-DXRDP_CFG_PATH=\"${sysconfdir}/xrdp\" \
-I$(top_builddir) \
-I$(top_srcdir)/xrdp \
-I$(top_srcdir)/libxrdp \
@ -31,6 +32,7 @@ test_xrdp_SOURCES = \
test_xrdp_egfx.c \
test_xrdp_keymap.c \
test_xrdp_region.c \
test_tconfig.c \
test_bitmap_load.c
test_xrdp_CFLAGS = \
@ -59,6 +61,7 @@ test_xrdp_LDADD = \
$(top_builddir)/xrdp/xrdp_encoder.o \
$(top_builddir)/xrdp/xrdp_process.o \
$(top_builddir)/xrdp/xrdp_login_wnd.o \
$(top_builddir)/xrdp/xrdp_tconfig.o \
$(top_builddir)/xrdp/xrdp_main_utils.o \
$(top_builddir)/libpainter/src/libpainter.la \
$(top_builddir)/librfxcodec/src/librfxencode.la \
@ -69,3 +72,10 @@ test_xrdp_LDADD = \
$(IMLIB2_LIBS) \
@CHECK_LIBS@ \
@CMOCKA_LIBS@
if XRDP_X264
AM_CPPFLAGS += -DXRDP_X264 $(XRDP_X264_CFLAGS)
test_xrdp_LDADD += \
$(top_builddir)/xrdp/xrdp_encoder_x264.o \
$(XRDP_X264_LIBS)
endif

50
tests/xrdp/test_tconfig.c Normal file
View File

@ -0,0 +1,50 @@
#if defined(HAVE_CONFIG_H)
#include "config_ac.h"
#endif
#include "xrdp_tconfig.h"
#include "test_xrdp.h"
#include "xrdp.h"
START_TEST(test_tconfig_gfx_always_success)
{
ck_assert_int_eq(1, 1);
}
END_TEST
START_TEST(test_tconfig_gfx_x264_load_basic)
{
struct xrdp_tconfig_gfx gfxconfig;
int rv = tconfig_load_gfx(XRDP_TOP_SRCDIR "/xrdp/gfx.toml", &gfxconfig);
ck_assert_int_eq(rv, 0);
/* default */
ck_assert_str_eq(gfxconfig.x264_param[0].preset, "ultrafast");
ck_assert_str_eq(gfxconfig.x264_param[0].tune, "zerolatency");
ck_assert_str_eq(gfxconfig.x264_param[0].profile, "main");
ck_assert_int_eq(gfxconfig.x264_param[0].vbv_max_bitrate, 0);
ck_assert_int_eq(gfxconfig.x264_param[0].vbv_buffer_size, 0);
ck_assert_int_eq(gfxconfig.x264_param[0].fps_num, 24);
ck_assert_int_eq(gfxconfig.x264_param[0].fps_den, 1);
}
END_TEST
/******************************************************************************/
Suite *
make_suite_tconfig_load_gfx(void)
{
Suite *s;
TCase *tc_tconfig_load_gfx;
s = suite_create("GfxLoad");
tc_tconfig_load_gfx = tcase_create("xrdp_tconfig_load_gfx");
tcase_add_test(tc_tconfig_load_gfx, test_tconfig_gfx_always_success);
tcase_add_test(tc_tconfig_load_gfx, test_tconfig_gfx_x264_load_basic);
suite_add_tcase(s, tc_tconfig_load_gfx);
return s;
}

View File

@ -7,5 +7,6 @@ Suite *make_suite_test_bitmap_load(void);
Suite *make_suite_test_keymap_load(void);
Suite *make_suite_egfx_base_functions(void);
Suite *make_suite_region(void);
Suite *make_suite_tconfig_load_gfx(void);
#endif /* TEST_XRDP_H */

View File

@ -58,6 +58,7 @@ int main (void)
srunner_add_suite(sr, make_suite_test_keymap_load());
srunner_add_suite(sr, make_suite_egfx_base_functions());
srunner_add_suite(sr, make_suite_region());
srunner_add_suite(sr, make_suite_tconfig_load_gfx());
srunner_set_tap(sr, "-");
srunner_run_all (sr, CK_ENV);

View File

@ -73,6 +73,8 @@ xrdp_SOURCES = \
xrdp_egfx.h \
xrdp_wm.c \
xrdp_main_utils.c \
xrdp_tconfig.c \
xrdp_tconfig.h \
$(XRDP_EXTRA_SOURCES)
xrdp_LDADD = \
@ -103,6 +105,7 @@ SUFFIXES = .in
$(subst_verbose)$(SUBST_VARS) $< > $@
dist_xrdpsysconf_DATA = \
gfx.toml \
xrdp_keyboard.ini
nodist_xrdpsysconf_DATA = \

37
xrdp/gfx.toml Normal file
View File

@ -0,0 +1,37 @@
[x264.default]
preset = "ultrafast"
tune = "zerolatency"
profile = "main" # profile is forced to baseline if preset == ultrafast
vbv_max_bitrate = 0
vbv_buffer_size = 0
fps_num = 24
fps_den = 1
[x264.lan]
# inherits default
[x264.wan]
vbv_max_bitrate = 15000
vbv_buffer_size = 1500
[x264.broadband_high]
preset = "superfast"
vbv_max_bitrate = 8000
vbv_buffer_Size = 800
[x264.satellite]
preset = "superfast"
vbv_max_bitrate = 5000
vbv_buffer_size = 500
[x264.broadband_low]
preset = "veryfast"
tune = "zerolatency"
vbv_max_bitrate = 1600
vbv_buffer_size = 66
[x264.modem]
preset = "fast"
tune = "zerolatency"
vbv_max_bitrate = 1200
vbv_buffer_size = 50

View File

@ -759,6 +759,9 @@ gfx_wiretosurface1(struct xrdp_encoder *self,
short *crects;
struct xrdp_enc_gfx_cmd *enc_gfx_cmd = &(enc->u.gfx);
int mon_index;
int connection_type;
connection_type = self->mm->wm->client_info->mcs_connection_type;
s = &ls;
g_memset(s, 0, sizeof(struct stream));
@ -912,7 +915,8 @@ gfx_wiretosurface1(struct xrdp_encoder *self,
width, height, twidth, theight, 0,
enc_gfx_cmd->data,
crects, num_rects_c,
s->p, &bitmap_data_length, NULL);
s->p, &bitmap_data_length,
connection_type, NULL);
if (error == 0)
{
xstream_seek(s, bitmap_data_length);

View File

@ -32,6 +32,7 @@
#include "arch.h"
#include "os_calls.h"
#include "xrdp_encoder_x264.h"
#include "xrdp_tconfig.h"
#define X264_MAX_ENCODERS 16
@ -47,6 +48,7 @@ struct x264_encoder
struct x264_global
{
struct x264_encoder encoders[X264_MAX_ENCODERS];
struct xrdp_tconfig_gfx_x264_param x264_param[NUM_CONNECTION_TYPES];
};
/*****************************************************************************/
@ -54,7 +56,17 @@ void *
xrdp_encoder_x264_create(void)
{
LOG_DEVEL(LOG_LEVEL_TRACE, "xrdp_encoder_x264_create:");
return g_new0(struct x264_global, 1);
struct x264_global *xg;
struct xrdp_tconfig_gfx gfxconfig;
xg = g_new0(struct x264_global, 1);
tconfig_load_gfx(GFX_CONF, &gfxconfig);
memcpy(&xg->x264_param, &gfxconfig.x264_param,
sizeof(struct xrdp_tconfig_gfx_x264_param) * NUM_CONNECTION_TYPES);
return xg;
}
/*****************************************************************************/
@ -89,7 +101,8 @@ xrdp_encoder_x264_encode(void *handle, int session, int left, int top,
int width, int height, int twidth, int theight,
int format, const char *data,
short *crects, int num_crects,
char *cdata, int *cdata_bytes, int *flags_ptr)
char *cdata, int *cdata_bytes, int connection_type,
int *flags_ptr)
{
struct x264_global *xg;
struct x264_encoder *xe;
@ -105,6 +118,7 @@ xrdp_encoder_x264_encode(void *handle, int session, int left, int top,
int y;
int cx;
int cy;
int ct; /* connection_type */
x264_picture_t pic_in;
x264_picture_t pic_out;
@ -113,6 +127,14 @@ xrdp_encoder_x264_encode(void *handle, int session, int left, int top,
flags = 0;
xg = (struct x264_global *) handle;
xe = &(xg->encoders[session % X264_MAX_ENCODERS]);
/* validate connection type */
ct = connection_type;
if (ct > CONNECTION_TYPE_LAN || ct < CONNECTION_TYPE_MODEM)
{
ct = CONNECTION_TYPE_LAN;
}
if ((xe->x264_enc_han == NULL) ||
(xe->width != width) || (xe->height != height))
{
@ -128,20 +150,19 @@ xrdp_encoder_x264_encode(void *handle, int session, int left, int top,
}
if ((width > 0) && (height > 0))
{
//x264_param_default_preset(&(xe->x264_params), "superfast", "zerolatency");
x264_param_default_preset(&(xe->x264_params), "ultrafast", "zerolatency");
x264_param_default_preset(&(xe->x264_params),
xg->x264_param[ct].preset,
xg->x264_param[ct].tune);
xe->x264_params.i_threads = 1;
xe->x264_params.i_width = (width + 15) & ~15;
xe->x264_params.i_height = (height + 15) & ~15;
xe->x264_params.i_fps_num = 24;
xe->x264_params.i_fps_den = 1;
//xe->x264_params.b_cabac = 1;
//xe->x264_params.i_bframe = 0;
//xe->x264_params.rc.i_rc_method = X264_RC_CQP;
//xe->x264_params.rc.i_qp_constant = 23;
//x264_param_apply_profile(&(xe->x264_params), "high");
x264_param_apply_profile(&(xe->x264_params), "main");
//x264_param_apply_profile(&(xe->x264_params), "baseline");
xe->x264_params.i_fps_num = xg->x264_param[ct].fps_num;
xe->x264_params.i_fps_den = xg->x264_param[ct].fps_den;
xe->x264_params.rc.i_rc_method = X264_RC_CRF;
xe->x264_params.rc.i_vbv_max_bitrate = xg->x264_param[ct].vbv_max_bitrate;
xe->x264_params.rc.i_vbv_buffer_size = xg->x264_param[ct].vbv_buffer_size;
x264_param_apply_profile(&(xe->x264_params),
xg->x264_param[ct].profile);
xe->x264_enc_han = x264_encoder_open(&(xe->x264_params));
LOG(LOG_LEVEL_INFO, "xrdp_encoder_x264_encode: "
"x264_encoder_open rv %p for width %d height %d",

View File

@ -32,7 +32,8 @@ xrdp_encoder_x264_encode(void *handle, int session, int left, int top,
int width, int height, int twidth, int theight,
int format, const char *data,
short *crects, int num_crects,
char *cdata, int *cdata_bytes, int *flags_ptr);
char *cdata, int *cdata_bytes, int connection_type,
int *flags_ptr);
#endif

244
xrdp/xrdp_tconfig.c Normal file
View File

@ -0,0 +1,244 @@
/**
* xrdp: A Remote Desktop Protocol server.
*
* Copyright (C) Koichiro Iwao
*
* 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.
*/
/**
*
* @file xrdp_tconfig.c
* @brief TOML config loader
* @author Koichiro Iwao
*
*/
#if defined(HAVE_CONFIG_H)
#include <config_ac.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "arch.h"
#include "os_calls.h"
#include "parse.h"
#include "toml.h"
#include "ms-rdpbcgr.h"
#include "xrdp_tconfig.h"
#include "string_calls.h"
#define TCLOG(log_level, args...) LOG(log_level, "TConfig: " args)
#define X264_DEFAULT_PRESET "ultrafast"
#define X264_DEFAULT_TUNE "zerolatency"
#define X264_DEFAULT_PROFILE "main"
#define X264_DEFAULT_FPS_NUM 24
#define X264_DEFAULT_FPS_DEN 1
static int
tconfig_load_gfx_x264_ct(toml_table_t *tfile, const int connection_type,
struct xrdp_tconfig_gfx_x264_param *param)
{
if (connection_type > NUM_CONNECTION_TYPES)
{
TCLOG(LOG_LEVEL_ERROR, "Invalid connection type is given");
return 1;
}
toml_table_t *x264 = toml_table_in(tfile, "x264");
if (!x264)
{
TCLOG(LOG_LEVEL_WARNING, "x264 params are not defined");
return 1;
}
toml_table_t *x264_ct =
toml_table_in(x264, rdpbcgr_connection_type_names[connection_type]);
toml_datum_t datum;
if (!x264_ct)
{
TCLOG(LOG_LEVEL_WARNING, "x264 params for connection type [%s] is not defined",
rdpbcgr_connection_type_names[connection_type]);
return 1;
}
/* preset */
datum = toml_string_in(x264_ct, "preset");
if (datum.ok)
{
g_strncpy(param[connection_type].preset,
datum.u.s,
sizeof(param[connection_type].preset) - 1);
free(datum.u.s);
}
else if (connection_type == 0)
{
TCLOG(LOG_LEVEL_WARNING,
"x264 param preset is not set for connection type [%s], "
"adopting the default value \"" X264_DEFAULT_PRESET "\"",
rdpbcgr_connection_type_names[connection_type]);
g_strncpy(param[connection_type].preset,
X264_DEFAULT_PRESET,
sizeof(param[connection_type].preset) - 1);
}
/* tune */
datum = toml_string_in(x264_ct, "tune");
if (datum.ok)
{
g_strncpy(param[connection_type].tune,
datum.u.s,
sizeof(param[connection_type].tune) - 1);
free(datum.u.s);
}
else if (connection_type == 0)
{
TCLOG(LOG_LEVEL_WARNING,
"x264 param tune is not set for connection type [%s], "
"adopting the default value \"" X264_DEFAULT_TUNE "\"",
rdpbcgr_connection_type_names[connection_type]);
g_strncpy(param[connection_type].tune,
X264_DEFAULT_TUNE,
sizeof(param[connection_type].tune) - 1);
}
/* profile */
datum = toml_string_in(x264_ct, "profile");
if (datum.ok)
{
g_strncpy(param[connection_type].profile,
datum.u.s,
sizeof(param[connection_type].profile) - 1);
free(datum.u.s);
}
else if (connection_type == 0)
{
TCLOG(LOG_LEVEL_WARNING,
"x264 param profile is not set for connection type [%s], "
"adopting the default value \"" X264_DEFAULT_PROFILE "\"",
rdpbcgr_connection_type_names[connection_type]);
g_strncpy(param[connection_type].profile,
X264_DEFAULT_PROFILE,
sizeof(param[connection_type].profile) - 1);
}
/* vbv_max_bitrate */
datum = toml_int_in(x264_ct, "vbv_max_bitrate");
if (datum.ok)
{
param[connection_type].vbv_max_bitrate = datum.u.i;
}
else if (connection_type == 0)
{
TCLOG(LOG_LEVEL_WARNING,
"x264 param vbv_max_bit_rate is not set for connection type [%s], "
"adopting the default value [0]",
rdpbcgr_connection_type_names[connection_type]);
param[connection_type].vbv_max_bitrate = 0;
}
/* vbv_buffer_size */
datum = toml_int_in(x264_ct, "vbv_buffer_size");
if (datum.ok)
{
param[connection_type].vbv_buffer_size = datum.u.i;
}
else if (connection_type == 0)
{
TCLOG(LOG_LEVEL_WARNING,
"x264 param vbv_buffer_size is not set for connection type [%s], "
"adopting the default value [0]",
rdpbcgr_connection_type_names[connection_type]);
param[connection_type].vbv_buffer_size = 0;
}
/* fps_num */
datum = toml_int_in(x264_ct, "fps_num");
if (datum.ok)
{
param[connection_type].fps_num = datum.u.i;
}
else if (connection_type == 0)
{
TCLOG(LOG_LEVEL_WARNING,
"x264 param fps_num is not set for connection type [%s], "
"adopting the default value [0]",
rdpbcgr_connection_type_names[connection_type]);
param[connection_type].fps_num = X264_DEFAULT_FPS_NUM;
}
/* fps_den */
datum = toml_int_in(x264_ct, "fps_den");
if (datum.ok)
{
param[connection_type].fps_den = datum.u.i;
}
else if (connection_type == 0)
{
TCLOG(LOG_LEVEL_WARNING,
"x264 param fps_den is not set for connection type [%s], "
"adopting the default value [0]",
rdpbcgr_connection_type_names[connection_type]);
param[connection_type].fps_num = X264_DEFAULT_FPS_DEN;
}
return 0;
}
int
tconfig_load_gfx(const char *filename, struct xrdp_tconfig_gfx *config)
{
FILE *fp;
char errbuf[200];
toml_table_t *tfile;
if ((fp = fopen(filename, "r")) == NULL)
{
TCLOG(LOG_LEVEL_ERROR, "Error loading GFX config file %s (%s)",
filename, g_get_strerror());
return 1;
}
else if ((tfile = toml_parse_file(fp, errbuf, sizeof(errbuf))) == NULL)
{
TCLOG(LOG_LEVEL_ERROR, "Error in GFX config file %s - %s", filename, errbuf);
fclose(fp);
return 1;
}
else
{
TCLOG(LOG_LEVEL_INFO, "Loading GFX config file %s", filename);
fclose(fp);
memset(config, 0, sizeof(struct xrdp_tconfig_gfx));
/* First of all, read the default params and override later */
tconfig_load_gfx_x264_ct(tfile, 0, config->x264_param);
for (int ct = CONNECTION_TYPE_MODEM; ct < NUM_CONNECTION_TYPES; ct++)
{
memcpy(&config->x264_param[ct], &config->x264_param[0],
sizeof(struct xrdp_tconfig_gfx_x264_param));
tconfig_load_gfx_x264_ct(tfile, ct, config->x264_param);
}
toml_free(tfile);
return 0;
}
}

66
xrdp/xrdp_tconfig.h Normal file
View File

@ -0,0 +1,66 @@
/**
* xrdp: A Remote Desktop Protocol server.
*
* Copyright (C) Koichiro Iwao
*
* 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.
*/
/**
*
* @file xrdp_tconfig.c
* @brief TOML config loader and structures
* @author Koichiro Iwao
*
*/
#ifndef _XRDP_TCONFIG_H_
#define _XRDP_TCONFIG_H_
/* The number of connection types in MS-RDPBCGR 2.2.1.3.2 */
#define NUM_CONNECTION_TYPES 7
#define GFX_CONF XRDP_CFG_PATH "/gfx.toml"
/* nc stands for new config */
struct xrdp_tconfig_gfx_x264_param
{
char preset[16];
char tune[16];
char profile[16];
int vbv_max_bitrate;
int vbv_buffer_size;
int fps_num;
int fps_den;
};
struct xrdp_tconfig_gfx
{
/* store x264 parameters for each connection type */
struct xrdp_tconfig_gfx_x264_param x264_param[NUM_CONNECTION_TYPES];
};
static const char *const rdpbcgr_connection_type_names[] =
{
"default", /* for xrdp internal use */
"modem",
"broadband_low",
"satellite",
"broadband_high",
"wan",
"lan",
"autodetect",
0
};
int tconfig_load_gfx(const char *filename, struct xrdp_tconfig_gfx *config);
#endif