[Spice-devel] [spice-gtk v1 1/2] Use libva to check video hardware accel capabilities

Christophe Fergeau cfergeau at redhat.com
Mon Feb 19 13:44:04 UTC 2018


Hey,

On Thu, Feb 15, 2018 at 10:05:04AM +0100, Victor Toso wrote:
> From: Victor Toso <me at victortoso.com>
> 
> 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()

This assumes that HW accelerated video decoding is going to go through
libva when using GStreamer. I assume it's not possible to directly query
GStreamer to know what it can hardware decode?

> 
> Signed-off-by: Victor Toso <victortoso at redhat.com>
> ---
>  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])

I don't think we'll necessarily have all of these installed?
PKG_CHECK_MODULES will error out if any of these is missing.

> +])
> +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)						\

Adding GDK_* to libspice_client_glib_2_0_la_LIBADD does not look good.
Maybe you want to move this to SpiceGtkSession rather than SpiceSession.

> +	$(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;

Here, session->priv->video_codecs should already be 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");

g_warning? but maybe g_debug() is enough?

> +        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");

g_new will never return NULL.

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

This is repeated twice, might deserve a small helper for improved
readability if you can come up with a good name.

> +            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);

This also needs to be _unref'ed in _dispose or _finalize.

Christophe

> +    }
> +
> +    g_array_unref(codecs);
> +    g_free(profile_list);
> +    vaTerminate(va_dpy);
> +#endif
> +}
> -- 
> 2.16.1
> 
> _______________________________________________
> Spice-devel mailing list
> Spice-devel at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/spice-devel
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <https://lists.freedesktop.org/archives/spice-devel/attachments/20180219/06fdb03e/attachment-0001.sig>


More information about the Spice-devel mailing list