diff --git a/tests/xrdp/Makefile.am b/tests/xrdp/Makefile.am index 02f8b3e26..9bb71da41 100644 --- a/tests/xrdp/Makefile.am +++ b/tests/xrdp/Makefile.am @@ -21,7 +21,13 @@ EXTRA_DIST = \ test_not4_8bit.bmp \ test_not4_24bit.bmp \ test1.jpg \ - test_alpha_blend.png + test_alpha_blend.png \ + gfx/gfx.toml\ + gfx/gfx_codec_order_undefined.toml \ + gfx/gfx_codec_h264_preferred.toml \ + gfx/gfx_codec_h264_only.toml \ + gfx/gfx_codec_rfx_preferred.toml \ + gfx/gfx_codec_rfx_only.toml TESTS = test_xrdp check_PROGRAMS = test_xrdp diff --git a/tests/xrdp/gfx/gfx_codec_h264_only.toml b/tests/xrdp/gfx/gfx_codec_h264_only.toml new file mode 100644 index 000000000..c7d45605b --- /dev/null +++ b/tests/xrdp/gfx/gfx_codec_h264_only.toml @@ -0,0 +1,18 @@ +[codec] +order = [ "H264" ] + +[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] +[x264.wan] +[x264.broadband_high] +[x264.satellite] +[x264.broadband_low] +[x264.modem] diff --git a/tests/xrdp/gfx/gfx_codec_h264_preferred.toml b/tests/xrdp/gfx/gfx_codec_h264_preferred.toml new file mode 100644 index 000000000..948f94201 --- /dev/null +++ b/tests/xrdp/gfx/gfx_codec_h264_preferred.toml @@ -0,0 +1,18 @@ +[codec] +order = [ "H264", "RFX" ] + +[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] +[x264.wan] +[x264.broadband_high] +[x264.satellite] +[x264.broadband_low] +[x264.modem] diff --git a/tests/xrdp/gfx/gfx_codec_order_undefined.toml b/tests/xrdp/gfx/gfx_codec_order_undefined.toml new file mode 100644 index 000000000..7432cb97b --- /dev/null +++ b/tests/xrdp/gfx/gfx_codec_order_undefined.toml @@ -0,0 +1,18 @@ +[codec] +order = [ ] + +[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] +[x264.wan] +[x264.broadband_high] +[x264.satellite] +[x264.broadband_low] +[x264.modem] diff --git a/tests/xrdp/gfx/gfx_codec_rfx_only.toml b/tests/xrdp/gfx/gfx_codec_rfx_only.toml new file mode 100644 index 000000000..9ab14ea2f --- /dev/null +++ b/tests/xrdp/gfx/gfx_codec_rfx_only.toml @@ -0,0 +1,18 @@ +[codec] +order = [ "RFX" ] + +[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] +[x264.wan] +[x264.broadband_high] +[x264.satellite] +[x264.broadband_low] +[x264.modem] diff --git a/tests/xrdp/gfx/gfx_codec_rfx_preferred.toml b/tests/xrdp/gfx/gfx_codec_rfx_preferred.toml new file mode 100644 index 000000000..b0b6a56a8 --- /dev/null +++ b/tests/xrdp/gfx/gfx_codec_rfx_preferred.toml @@ -0,0 +1,18 @@ +[codec] +order = [ "RFX", "H264" ] + +[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] +[x264.wan] +[x264.broadband_high] +[x264.satellite] +[x264.broadband_low] +[x264.modem] diff --git a/tests/xrdp/test_tconfig.c b/tests/xrdp/test_tconfig.c index 14f81c2b6..9bcffd3be 100644 --- a/tests/xrdp/test_tconfig.c +++ b/tests/xrdp/test_tconfig.c @@ -31,6 +31,40 @@ START_TEST(test_tconfig_gfx_x264_load_basic) } END_TEST +START_TEST(test_tconfig_gfx_codec_order) +{ + struct xrdp_tconfig_gfx gfxconfig; + + /* H264 earlier */ + tconfig_load_gfx("./gfx/gfx_codec_h264_preferred.toml", &gfxconfig); + ck_assert_int_gt(gfxconfig.codec.h264_idx, -1); + ck_assert_int_gt(gfxconfig.codec.rfx_idx, -1); + ck_assert_int_lt(gfxconfig.codec.h264_idx, gfxconfig.codec.rfx_idx); + + /* H264 only */ + tconfig_load_gfx("./gfx/gfx_codec_h264_only.toml", &gfxconfig); + ck_assert_int_gt(gfxconfig.codec.h264_idx, -1); + ck_assert_int_eq(gfxconfig.codec.rfx_idx, -1); + + /* RFX earlier */ + tconfig_load_gfx("./gfx/gfx_codec_rfx_preferred.toml", &gfxconfig); + ck_assert_int_gt(gfxconfig.codec.h264_idx, -1); + ck_assert_int_gt(gfxconfig.codec.rfx_idx, -1); + ck_assert_int_lt(gfxconfig.codec.rfx_idx, gfxconfig.codec.h264_idx); + + /* RFX only */ + tconfig_load_gfx("./gfx/gfx_codec_rfx_only.toml", &gfxconfig); + ck_assert_int_eq(gfxconfig.codec.h264_idx, -1); + ck_assert_int_gt(gfxconfig.codec.rfx_idx, -1); + + /* RFX is preferred if order undefined */ + tconfig_load_gfx("./gfx/gfx_codec_order_undefined.toml", &gfxconfig); + ck_assert_int_gt(gfxconfig.codec.h264_idx, -1); + ck_assert_int_gt(gfxconfig.codec.rfx_idx, -1); + ck_assert_int_lt(gfxconfig.codec.h264_idx, gfxconfig.codec.rfx_idx); +} +END_TEST + /******************************************************************************/ Suite * make_suite_tconfig_load_gfx(void) @@ -43,6 +77,7 @@ make_suite_tconfig_load_gfx(void) 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); + tcase_add_test(tc_tconfig_load_gfx, test_tconfig_gfx_codec_order); suite_add_tcase(s, tc_tconfig_load_gfx); diff --git a/xrdp/gfx.toml b/xrdp/gfx.toml index 5b7f27c41..367edab64 100644 --- a/xrdp/gfx.toml +++ b/xrdp/gfx.toml @@ -1,3 +1,6 @@ +[codec] +order = [ "H264", "RFX" ] + [x264.default] preset = "ultrafast" tune = "zerolatency" diff --git a/xrdp/xrdp_tconfig.c b/xrdp/xrdp_tconfig.c index d16a0f4a5..a34eb3b7d 100644 --- a/xrdp/xrdp_tconfig.c +++ b/xrdp/xrdp_tconfig.c @@ -52,16 +52,18 @@ static int tconfig_load_gfx_x264_ct(toml_table_t *tfile, const int connection_type, struct xrdp_tconfig_gfx_x264_param *param) { + TCLOG(LOG_LEVEL_TRACE, "[x264]"); + if (connection_type > NUM_CONNECTION_TYPES) { - TCLOG(LOG_LEVEL_ERROR, "Invalid connection type is given"); + TCLOG(LOG_LEVEL_ERROR, "[x264] 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"); + TCLOG(LOG_LEVEL_WARNING, "[x264] x264 params are not defined"); return 1; } @@ -88,8 +90,8 @@ tconfig_load_gfx_x264_ct(toml_table_t *tfile, const int connection_type, 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 "\"", + "[x264.%s] preset is not set, adopting the default value \"" + X264_DEFAULT_PRESET "\"", rdpbcgr_connection_type_names[connection_type]); g_strncpy(param[connection_type].preset, X264_DEFAULT_PRESET, @@ -108,8 +110,8 @@ tconfig_load_gfx_x264_ct(toml_table_t *tfile, const int connection_type, 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 "\"", + "[x264.%s] tune is not set, adopting the default value \"" + X264_DEFAULT_PRESET "\"", rdpbcgr_connection_type_names[connection_type]); g_strncpy(param[connection_type].tune, X264_DEFAULT_TUNE, @@ -128,8 +130,8 @@ tconfig_load_gfx_x264_ct(toml_table_t *tfile, const int connection_type, 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 "\"", + "[x264.%s] profile is not set, adopting the default value \"" + X264_DEFAULT_PRESET "\"", rdpbcgr_connection_type_names[connection_type]); g_strncpy(param[connection_type].profile, X264_DEFAULT_PROFILE, @@ -145,8 +147,7 @@ tconfig_load_gfx_x264_ct(toml_table_t *tfile, const int connection_type, 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]", + "[x264.%s] vbv_max_bitrate is not set, adopting the default value [0]", rdpbcgr_connection_type_names[connection_type]); param[connection_type].vbv_max_bitrate = 0; } @@ -160,8 +161,7 @@ tconfig_load_gfx_x264_ct(toml_table_t *tfile, const int connection_type, 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]", + "[x264.%s] vbv_buffer_size is not set, adopting the default value [0]", rdpbcgr_connection_type_names[connection_type]); param[connection_type].vbv_buffer_size = 0; } @@ -175,9 +175,9 @@ tconfig_load_gfx_x264_ct(toml_table_t *tfile, const int connection_type, 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]); + "[x264.%s] fps_num is not set, adopting the default value [%d]", + rdpbcgr_connection_type_names[connection_type], + X264_DEFAULT_FPS_NUM); param[connection_type].fps_num = X264_DEFAULT_FPS_NUM; } @@ -190,15 +190,79 @@ tconfig_load_gfx_x264_ct(toml_table_t *tfile, const int connection_type, 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; + "[x264.%s] fps_den is not set, adopting the default value [%d]", + rdpbcgr_connection_type_names[connection_type], + X264_DEFAULT_FPS_DEN); + param[connection_type].fps_den = X264_DEFAULT_FPS_DEN; } return 0; } +static int tconfig_load_gfx_order(toml_table_t *tfile, struct xrdp_tconfig_gfx *config) +{ + /* + * This config loader is not responsible to check if xrdp is built with + * H264/RFX support. Just loads configurations as-is. + */ + + TCLOG(LOG_LEVEL_TRACE, "[codec]"); + + int h264_found = 0; + int rfx_found = 0; + + config->codec.h264_idx = -1; + config->codec.rfx_idx = -1; + + toml_table_t *codec = toml_table_in(tfile, "codec"); + toml_array_t *order = toml_array_in(codec, "order"); + + if (codec && order) + { + for (int i = 0; ; i++) + { + toml_datum_t datum = toml_string_at(order, i); + + if (datum.ok) + { + if (g_strcasecmp(datum.u.s, "h264") == 0 || + g_strcasecmp(datum.u.s, "h.264") == 0) + { + h264_found = 1; + config->codec.h264_idx = i; + } + if (g_strcasecmp(datum.u.s, "rfx") == 0) + { + rfx_found = 1; + config->codec.rfx_idx = i; + } + free(datum.u.s); + } + else + { + break; + } + } + } + + if (h264_found == 0 && rfx_found == 0) + { + /* prefer H264 if no priority found */ + config->codec.h264_idx = 0; + config->codec.rfx_idx = 1; + + TCLOG(LOG_LEVEL_WARNING, "[codec] could not get GFX codec order, using default order" + " h264_idx [%d], rfx_idx [%d]", + config->codec.h264_idx, config->codec.rfx_idx); + + return 1; + } + + TCLOG(LOG_LEVEL_DEBUG, "[codec] h264_idx [%d], rfx_idx [%d]", + config->codec.h264_idx, config->codec.rfx_idx); + return 0; +} + int tconfig_load_gfx(const char *filename, struct xrdp_tconfig_gfx *config) { @@ -225,6 +289,9 @@ tconfig_load_gfx(const char *filename, struct xrdp_tconfig_gfx *config) memset(config, 0, sizeof(struct xrdp_tconfig_gfx)); + /* Load GFX order */ + tconfig_load_gfx_order(tfile, config); + /* First of all, read the default params and override later */ tconfig_load_gfx_x264_ct(tfile, 0, config->x264_param); diff --git a/xrdp/xrdp_tconfig.h b/xrdp/xrdp_tconfig.h index 6a5ba9704..8364dcd8d 100644 --- a/xrdp/xrdp_tconfig.h +++ b/xrdp/xrdp_tconfig.h @@ -42,8 +42,15 @@ struct xrdp_tconfig_gfx_x264_param int fps_den; }; +struct xrdp_tconfig_gfx_codec_order +{ + int h264_idx; + int rfx_idx; +}; + struct xrdp_tconfig_gfx { + struct xrdp_tconfig_gfx_codec_order codec; /* store x264 parameters for each connection type */ struct xrdp_tconfig_gfx_x264_param x264_param[NUM_CONNECTION_TYPES]; };