From: Victor Toso <me@xxxxxxxxxxxxxx> Libva is an implementation for VA-API. This can be used to automatically send to the server the preferred video codecs as the client would prefer streams with video codecs that can be decoded with gpu support. We can also use the profiles to detect and set upper limit for video streams quality. e.g: Don't start UHD video stream if client's hardware don't support it. This patch makes usage of libva in spice-session and exposes this information to all available channel-displays with the internal function spice_session_get_hw_accel_video_codecs() Signed-off-by: Victor Toso <victortoso@xxxxxxxxxx> --- configure.ac | 20 +++++++ src/Makefile.am | 12 ++++ src/spice-session-priv.h | 1 + src/spice-session.c | 139 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 172 insertions(+) diff --git a/configure.ac b/configure.ac index 2a14055..0b0db0f 100644 --- a/configure.ac +++ b/configure.ac @@ -321,6 +321,25 @@ AC_SUBST(Z_LIBS) SPICE_CHECK_SMARTCARD AM_CONDITIONAL([WITH_SMARTCARD], [test "x$have_smartcard" = "xyes"]) +AC_ARG_ENABLE([libva], + AS_HELP_STRING([--enable-libva=@<:@auto/yes/no@:>@], [Enable auto detection of hardware accelerate video decoding support @<:@default=auto@:>@]), + [], + [enable_libva="auto"]) +AS_IF([test "x$enable_libva" != "xno"], + [PKG_CHECK_MODULES(LIBVA, [libva >= 1.0.0], + [AC_DEFINE([HAVE_LIBVA], 1, [Have libva support?]) + enable_libva="yes"], + [AS_IF([test "x$enable_libva" = "xyes"], + AC_MSG_ERROR([Auto detection of hardware accelerated video decoding explicitly requested, but some required packages are not available])) + enable_libva="no" + ]) + PKG_CHECK_MODULES([LIBVA_X11], [libva-x11 >= 1.0.0]) + PKG_CHECK_MODULES([LIBVA_WAYLAND], [libva-wayland >= 1.0.0]) + PKG_CHECK_MODULES([GDK_X11], [gdk-x11-3.0]) + PKG_CHECK_MODULES([GDK_WAYLAND], [gdk-wayland-3.0]) +]) +AM_CONDITIONAL([HAVE_LIBVA], [test "x$enable_libva" = "xyes"]) + AC_ARG_ENABLE([usbredir], AS_HELP_STRING([--enable-usbredir=@<:@auto/yes/no@:>@], [Enable usbredir support @<:@default=auto@:>@]), @@ -635,6 +654,7 @@ AC_MSG_NOTICE([ DBus: ${have_dbus} WebDAV support: ${have_phodav} LZ4 support: ${have_lz4} + Libva support: ${enable_libva} Now type 'make' to build $PACKAGE diff --git a/src/Makefile.am b/src/Makefile.am index 4b6e46d..7b74220 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -75,6 +75,9 @@ SPICE_COMMON_CPPFLAGS = \ $(PIXMAN_CFLAGS) \ $(PULSE_CFLAGS) \ $(GTK_CFLAGS) \ + $(GDK_CFLAGS) \ + $(GDK_X11_CFLAGS) \ + $(GDK_WAYLAND_CFLAGS) \ $(CAIRO_CFLAGS) \ $(GLIB2_CFLAGS) \ $(GIO_CFLAGS) \ @@ -88,6 +91,9 @@ SPICE_COMMON_CPPFLAGS = \ $(GUDEV_CFLAGS) \ $(SOUP_CFLAGS) \ $(PHODAV_CFLAGS) \ + $(LIBVA_CFLAGS) \ + $(LIBVA_X11_CFLAGS) \ + $(LIBVA_WAYLAND_CFLAGS) \ $(X11_CFLAGS) \ $(LZ4_CFLAGS) \ $(NULL) @@ -195,6 +201,12 @@ libspice_client_glib_2_0_la_LIBADD = \ $(USBREDIR_LIBS) \ $(GUDEV_LIBS) \ $(PHODAV_LIBS) \ + $(GDK_LIBS) \ + $(GDK_X11_LIBS) \ + $(GDK_WAYLAND_LIBS) \ + $(LIBVA_LIBS) \ + $(LIBVA_X11_LIBS) \ + $(LIBVA_WAYLAND_LIBS) \ $(NULL) if WITH_POLKIT diff --git a/src/spice-session-priv.h b/src/spice-session-priv.h index 03005aa..7137cf6 100644 --- a/src/spice-session-priv.h +++ b/src/spice-session-priv.h @@ -100,6 +100,7 @@ void spice_session_set_main_channel(SpiceSession *session, SpiceChannel *channel gboolean spice_session_set_migration_session(SpiceSession *session, SpiceSession *mig_session); SpiceAudio *spice_audio_get(SpiceSession *session, GMainContext *context); const gchar* spice_audio_data_mode_to_string(gint mode); +const GArray *spice_session_get_hw_accel_video_codecs(SpiceSession *session); G_END_DECLS #endif /* __SPICE_CLIENT_SESSION_PRIV_H__ */ diff --git a/src/spice-session.c b/src/spice-session.c index 2aabf58..e26d375 100644 --- a/src/spice-session.c +++ b/src/spice-session.c @@ -23,6 +23,19 @@ #include <gio/gunixsocketaddress.h> #endif #include "common/ring.h" +#ifdef HAVE_LIBVA +#include <gdk/gdk.h> +#include <va/va.h> +#include <va/va_str.h> +#ifdef GDK_WINDOWING_WAYLAND +#include <gdk/gdkwayland.h> +#include <va/va_wayland.h> +#endif +#ifdef GDK_WINDOWING_X11 +#include <gdk/gdkx.h> +#include <va/va_x11.h> +#endif +#endif #include "spice-client.h" #include "spice-common.h" @@ -33,6 +46,7 @@ #include "spice-uri-priv.h" #include "channel-playback-priv.h" #include "spice-audio-priv.h" +#include "channel-display-priv.h" struct channel { SpiceChannel *channel; @@ -116,6 +130,9 @@ struct _SpiceSessionPrivate { guint8 uuid[16]; gchar *name; SpiceImageCompression preferred_compression; + + /* Array of SpiceVideoCodecType with hw accelerated video decoding capability */ + GArray *video_codecs; /* associated objects */ SpiceAudio *audio_manager; @@ -248,6 +265,7 @@ spice_image_compress_get_type (void) static guint signals[SPICE_SESSION_LAST_SIGNAL]; static void spice_session_channel_destroy(SpiceSession *session, SpiceChannel *channel); +static void spice_session_check_video_hw_caps(SpiceSession *session); static void update_proxy(SpiceSession *self, const gchar *str) { @@ -299,6 +317,9 @@ static void spice_session_init(SpiceSession *session) SPICE_DEBUG("Could not initialize SpiceUsbDeviceManager - %s", err->message); g_clear_error(&err); } + + session->priv->video_codecs = NULL; + spice_session_check_video_hw_caps(session); } static void @@ -2801,3 +2822,121 @@ gboolean spice_session_set_migration_session(SpiceSession *session, SpiceSession return TRUE; } + +G_GNUC_INTERNAL +const GArray *spice_session_get_hw_accel_video_codecs(SpiceSession *session) +{ + g_return_val_if_fail(SPICE_IS_SESSION(session), NULL); + return session->priv->video_codecs; +} + +static void +spice_session_check_video_hw_caps(SpiceSession *session) +{ +#ifdef HAVE_LIBVA + VADisplay va_dpy = NULL; + VAStatus va_status; + GdkDisplay *display; + int major_version, minor_version; + GArray *codecs; + const gchar *last_profile = NULL; + VAProfile *profile_list = NULL; + int num_profiles, max_num_profiles, i; + int num_entrypoint; + + display = gdk_display_get_default(); + spice_debug("Display: %s", gdk_display_get_name(display)); + +#ifdef GDK_WINDOWING_X11 + if (GDK_IS_X11_DISPLAY(display)) + va_dpy = vaGetDisplay(gdk_x11_display_get_xdisplay(display)); +#endif +#ifdef GDK_WINDOWING_WAYLAND + if (GDK_IS_WAYLAND_DISPLAY(display)) + va_dpy = vaGetDisplayWl(gdk_wayland_display_get_wl_display(display)); +#endif + + if (va_dpy == NULL) { + spice_warning("Failed to get VADisplay, unable to detect hardware capabilities"); + return; + } + + va_status = vaInitialize(va_dpy, &major_version, &minor_version); + if (va_status != VA_STATUS_SUCCESS) { + spice_warning("Failed to initialize libva"); + return; + } + + max_num_profiles = vaMaxNumProfiles(va_dpy); + profile_list = g_new(VAProfile, max_num_profiles); + + if (!profile_list) { + spice_warning("libva: failed to allocate memory for profile list"); + vaTerminate(va_dpy); + return; + } + + va_status = vaQueryConfigProfiles(va_dpy, profile_list, &num_profiles); + if (va_status != VA_STATUS_SUCCESS) { + spice_warning("libva: failed to query profiles"); + g_free(profile_list); + vaTerminate(va_dpy); + return; + } + + codecs = g_array_new(FALSE, FALSE, sizeof(gint)); + for (i = 0; i < num_profiles; i++) { + int j; + VAEntrypoint entrypoints[50]; + VAProfile profile = profile_list[i]; + const char *profile_str = vaProfileStr(profile); + + /* Spice protocol does not support different profiles for a given codec + * at the moment, which means that we can jump to the next codec. */ + if (last_profile != NULL && + g_ascii_strncasecmp(profile_str + strlen("VAProfile"), + last_profile, + strlen(last_profile)) == 0) + continue; + + va_status = vaQueryConfigEntrypoints(va_dpy, profile, entrypoints, &num_entrypoint); + if (va_status == VA_STATUS_ERROR_UNSUPPORTED_PROFILE) + continue; + else if (va_status != VA_STATUS_SUCCESS) { + spice_warning("Error on vaQueryConfigEntrypoints()"); + break; + } + + /* Find if current profile has decoding support */ + for (j = 0; j < num_entrypoint; j++) { + int k; + + if (entrypoints[j] != VAEntrypointVLD) + continue; + + /* Found decoding entrypoing, check if it is supported by Spice protocol */ + for (k = 1; k < SPICE_VIDEO_CODEC_TYPE_ENUM_END; k++) { + if (g_ascii_strncasecmp(profile_str + strlen("VAProfile"), + gst_opts[k].name, + strlen(gst_opts[k].name)) == 0) { + last_profile = gst_opts[k].name; + g_array_append_val(codecs, k); + spice_debug("Support to decode %s found with profile %s", + gst_opts[k].name, profile_str); + break; + } + } + break; + } + } + + if (codecs->len > 0) { + g_clear_pointer(&session->priv->video_codecs, g_array_unref); + session->priv->video_codecs = g_array_ref(codecs); + } + + g_array_unref(codecs); + g_free(profile_list); + vaTerminate(va_dpy); +#endif +} -- 2.16.1 _______________________________________________ Spice-devel mailing list Spice-devel@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/spice-devel