[Spice-devel] [spice-server v2 9/9] dcc: handle preferred video codec message

Victor Toso victortoso at redhat.com
Wed Nov 2 17:30:39 UTC 2016


From: Victor Toso <me at victortoso.com>

[0] SPICE_MSGC_DISPLAY_PREFERRED_VIDEO_CODEC_TYPE

This message provides a list of video codecs based on client's order
of preference.

We duplicate the video codecs array from reds.c and sort it using the
order of codecs as reference.

This message will not change an ongoing streaming but it could change
newly created streams depending the rank value of each video codec
that can be set by spice_server_set_video_codecs()

Signed-off-by: Victor Toso <victortoso at redhat.com>
---
 configure.ac             |  2 +-
 server/dcc-private.h     |  2 ++
 server/dcc.c             | 65 ++++++++++++++++++++++++++++++++++++++++++++++++
 server/dcc.h             |  1 +
 server/display-channel.c |  1 +
 server/stream.c          |  9 +++++--
 6 files changed, 77 insertions(+), 3 deletions(-)

diff --git a/configure.ac b/configure.ac
index 68aed15..2d4aa3e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -143,7 +143,7 @@ AS_IF([test x"$have_smartcard" = "xyes"], [
     AS_VAR_APPEND([SPICE_REQUIRES], [" libcacard >= 0.1.2"])
 ])
 
-SPICE_PROTOCOL_MIN_VER=0.12.12
+SPICE_PROTOCOL_MIN_VER=0.12.13
 PKG_CHECK_MODULES([SPICE_PROTOCOL], [spice-protocol >= $SPICE_PROTOCOL_MIN_VER])
 AC_SUBST([SPICE_PROTOCOL_MIN_VER])
 
diff --git a/server/dcc-private.h b/server/dcc-private.h
index de6ea92..e5e9b65 100644
--- a/server/dcc-private.h
+++ b/server/dcc-private.h
@@ -51,6 +51,8 @@ struct DisplayChannelClientPrivate
         int num_pixmap_cache_items;
     } send_data;
 
+    GArray *preferred_video_codecs;
+
     uint8_t surface_client_created[NUM_SURFACES];
     QRegion surface_client_lossy_region[NUM_SURFACES];
 
diff --git a/server/dcc.c b/server/dcc.c
index 79fc7fd..1c1b0ea 100644
--- a/server/dcc.c
+++ b/server/dcc.c
@@ -105,6 +105,8 @@ static void
 display_channel_client_finalize(GObject *object)
 {
     DisplayChannelClient *self = DISPLAY_CHANNEL_CLIENT(object);
+
+    g_clear_pointer(&self->priv->preferred_video_codecs, g_array_unref);
     g_free(self->priv);
 
     G_OBJECT_CLASS(display_channel_client_parent_class)->finalize(object);
@@ -1098,6 +1100,66 @@ static int dcc_handle_preferred_compression(DisplayChannelClient *dcc,
     return TRUE;
 }
 
+static gint sort_by_client_preference(gconstpointer a_pointer,
+                                      gconstpointer b_pointer,
+                                      gpointer user_data)
+{
+    const RedVideoCodec *a = a_pointer;
+    const RedVideoCodec *b = b_pointer;
+
+    if (a->rank == b->rank) {
+        gint i;
+        SpiceMsgcDisplayPreferredVideoCodecType *msg = user_data;
+
+        for (i = 0; i < msg->num_of_codecs; i++) {
+            if (a->type == msg->codecs[i])
+                return -1;
+
+            if (b->type == msg->codecs[i])
+                return 1;
+        }
+    }
+
+    return (a->rank - b->rank);
+}
+
+static int dcc_handle_preferred_video_codec_type(DisplayChannelClient *dcc,
+         SpiceMsgcDisplayPreferredVideoCodecType *msg)
+{
+    RedsState *reds;
+    gint i;
+    GArray *client_codecs, *server_codecs;
+
+    reds = red_channel_get_server(red_channel_client_get_channel(&dcc->parent));
+    server_codecs = reds_get_video_codecs(reds);
+    spice_return_val_if_fail(server_codecs != NULL, FALSE);
+
+    g_clear_pointer(&dcc->priv->preferred_video_codecs, g_array_unref);
+    client_codecs = g_array_sized_new(FALSE, FALSE, sizeof(RedVideoCodec), msg->num_of_codecs);
+
+    for (i = 0; i < server_codecs->len; i++) {
+        RedVideoCodec codec = g_array_index(server_codecs, RedVideoCodec, i);
+        g_array_append_val(client_codecs, codec);
+    }
+
+    /* Server codecs is sorted by host's preference using ranking system. We
+     * will keep server ranking order but sort by client's preference when it is
+     * possible */
+    g_array_sort_with_data(client_codecs, sort_by_client_preference, msg);
+
+    /* FIXME: Should we handle dinamicaly changing the ranks in the host?
+     * We probably want to connect generating this GArray to
+     * reds:video-codecs in the future */
+    dcc->priv->preferred_video_codecs = client_codecs;
+
+    return TRUE;
+}
+
+GArray *dcc_get_preferred_video_codecs(DisplayChannelClient *dcc)
+{
+    return dcc->priv->preferred_video_codecs;
+}
+
 static int dcc_handle_gl_draw_done(DisplayChannelClient *dcc)
 {
     DisplayChannel *display = DCC_TO_DC(dcc);
@@ -1128,6 +1190,9 @@ int dcc_handle_message(RedChannelClient *rcc, uint32_t size, uint16_t type, void
             (SpiceMsgcDisplayPreferredCompression *)msg);
     case SPICE_MSGC_DISPLAY_GL_DRAW_DONE:
         return dcc_handle_gl_draw_done(dcc);
+    case SPICE_MSGC_DISPLAY_PREFERRED_VIDEO_CODEC_TYPE:
+        return dcc_handle_preferred_video_codec_type(dcc,
+            (SpiceMsgcDisplayPreferredVideoCodecType *)msg);
     default:
         return red_channel_client_handle_message(rcc, size, type, msg);
     }
diff --git a/server/dcc.h b/server/dcc.h
index e4fe788..18ef2a4 100644
--- a/server/dcc.h
+++ b/server/dcc.h
@@ -205,6 +205,7 @@ uint64_t dcc_get_max_stream_bit_rate(DisplayChannelClient *dcc);
 void dcc_set_max_stream_bit_rate(DisplayChannelClient *dcc, uint64_t rate);
 int dcc_config_socket(RedChannelClient *rcc);
 gboolean dcc_is_low_bandwidth(DisplayChannelClient *dcc);
+GArray *dcc_get_preferred_video_codecs(DisplayChannelClient *dcc);
 
 G_END_DECLS
 
diff --git a/server/display-channel.c b/server/display-channel.c
index bcdde13..32fff11 100644
--- a/server/display-channel.c
+++ b/server/display-channel.c
@@ -2055,6 +2055,7 @@ display_channel_constructed(GObject *object)
 
     red_channel_set_cap(channel, SPICE_DISPLAY_CAP_MONITORS_CONFIG);
     red_channel_set_cap(channel, SPICE_DISPLAY_CAP_PREF_COMPRESSION);
+    red_channel_set_cap(channel, SPICE_DISPLAY_CAP_PREF_VIDEO_CODEC_TYPE);
     red_channel_set_cap(channel, SPICE_DISPLAY_CAP_STREAM_REPORT);
 }
 
diff --git a/server/stream.c b/server/stream.c
index 4e70222..8a17449 100644
--- a/server/stream.c
+++ b/server/stream.c
@@ -731,9 +731,14 @@ static VideoEncoder* dcc_create_video_encoder(DisplayChannelClient *dcc,
     RedChannelClient *rcc = RED_CHANNEL_CLIENT(dcc);
     int client_has_multi_codec = red_channel_client_test_remote_cap(rcc, SPICE_DISPLAY_CAP_MULTI_CODEC);
     int i;
+    GArray *codecs;
 
-    for (i = 0; i < display->priv->video_codecs->len; i++) {
-        RedVideoCodec* video_codec = &g_array_index (display->priv->video_codecs, RedVideoCodec, i);
+    codecs = dcc_get_preferred_video_codecs(dcc);
+    if (codecs == NULL)
+        codecs = display->priv->video_codecs;
+
+    for (i = 0; i < codecs->len; i++) {
+        RedVideoCodec *video_codec = &g_array_index (codecs, RedVideoCodec, i);
 
         if (!client_has_multi_codec &&
             video_codec->type != SPICE_VIDEO_CODEC_TYPE_MJPEG) {
-- 
2.9.3



More information about the Spice-devel mailing list