[Spice-devel] [RFC spice-server 1/3] stream-channel: Add preferred video codec capability

Kevin Pouget kpouget at redhat.com
Tue Aug 6 15:34:45 UTC 2019


This patch enables the SPICE_DISPLAY_CAP_PREF_VIDEO_CODEC_TYPE
capability for the stream-channel.

video_stream_parse_preferred_codecs: new function for parsing the
SPICE protocol message. This code used to be inside
dcc_handle_preferred_video_codec_type.

struct StreamChannelClient::client_preferred_video_codecs: new field.

Signed-off-by: Kevin Pouget <kpouget at redhat.com>
---
 server/dcc.c            | 30 +-----------------------------
 server/stream-channel.c | 40 ++++++++++++++++++++++++++++++++++++++++
 server/video-stream.c   | 36 ++++++++++++++++++++++++++++++++++++
 server/video-stream.h   |  1 +
 4 files changed, 78 insertions(+), 29 deletions(-)

diff --git a/server/dcc.c b/server/dcc.c
index 21e8598e..538f1f51 100644
--- a/server/dcc.c
+++ b/server/dcc.c
@@ -1158,38 +1158,10 @@ static void on_display_video_codecs_update(GObject *gobject, GParamSpec *pspec,
 static int dcc_handle_preferred_video_codec_type(DisplayChannelClient *dcc,
                                                  SpiceMsgcDisplayPreferredVideoCodecType *msg)
 {
-    gint i, len;
-    gint indexes[SPICE_VIDEO_CODEC_TYPE_ENUM_END];
-    GArray *client;
-
     g_return_val_if_fail(msg->num_of_codecs > 0, TRUE);

-    /* set default to a big and positive number */
-    memset(indexes, 0x7f, sizeof(indexes));
-
-    for (len = 0, i = 0; i < msg->num_of_codecs; i++) {
-        gint video_codec = msg->codecs[i];
-
-        if (video_codec < SPICE_VIDEO_CODEC_TYPE_MJPEG ||
-            video_codec >= SPICE_VIDEO_CODEC_TYPE_ENUM_END) {
-            spice_debug("Client has sent unknown video-codec (value %d at index %d). "
-                        "Ignoring as server can't handle it",
-                         video_codec, i);
-            continue;
-        }
-
-        if (indexes[video_codec] < SPICE_VIDEO_CODEC_TYPE_ENUM_END) {
-            continue;
-        }
-
-        len++;
-        indexes[video_codec] = len;
-    }
-    client = g_array_sized_new(FALSE, FALSE, sizeof(gint), SPICE_VIDEO_CODEC_TYPE_ENUM_END);
-    g_array_append_vals(client, indexes, SPICE_VIDEO_CODEC_TYPE_ENUM_END);
-
     g_clear_pointer(&dcc->priv->client_preferred_video_codecs, g_array_unref);
-    dcc->priv->client_preferred_video_codecs = client;
+    dcc->priv->client_preferred_video_codecs = video_stream_parse_preferred_codecs(msg);

     /* New client preference */
     dcc_update_preferred_video_codecs(dcc);
diff --git a/server/stream-channel.c b/server/stream-channel.c
index 7953018e..fa4804f1 100644
--- a/server/stream-channel.c
+++ b/server/stream-channel.c
@@ -22,6 +22,7 @@
 #include <spice/stream-device.h>

 #include "red-channel-client.h"
+#include "red-client.h"
 #include "stream-channel.h"
 #include "reds.h"
 #include "common-graphics-channel.h"
@@ -52,6 +53,9 @@ struct StreamChannelClient {
     /* current video stream id, <0 if not initialized or
      * we are not sending a stream */
     int stream_id;
+    /* Array with SPICE_VIDEO_CODEC_TYPE_ENUM_END elements, with the client
+     * preference order (index) as value */
+    GArray *client_preferred_video_codecs;
 };

 struct StreamChannelClientClass {
@@ -114,6 +118,8 @@ typedef struct StreamDataItem {
 #define PRIMARY_SURFACE_ID 0

 static void stream_channel_client_on_disconnect(RedChannelClient *rcc);
+static bool stream_channel_handle_preferred_video_codec_type(RedChannelClient *rcc,
+                                                      SpiceMsgcDisplayPreferredVideoCodecType *msg);

 RECORDER(stream_channel_data, 32, "Stream channel data packet");

@@ -324,6 +330,10 @@ handle_message(RedChannelClient *rcc, uint16_t type, uint32_t size, void *msg)
     case SPICE_MSGC_DISPLAY_GL_DRAW_DONE:
         /* client should not send this message */
         return false;
+    case SPICE_MSGC_DISPLAY_PREFERRED_VIDEO_CODEC_TYPE:
+        return stream_channel_handle_preferred_video_codec_type(rcc,
+            (SpiceMsgcDisplayPreferredVideoCodecType *)msg);
+        return false;
     default:
         return red_channel_client_handle_message(rcc, type, size, msg);
     }
@@ -390,6 +400,20 @@ stream_channel_get_supported_codecs(StreamChannel *channel, uint8_t *out_codecs)
     return num;
 }

+static bool
+stream_channel_handle_preferred_video_codec_type(RedChannelClient *rcc,
+                                                 SpiceMsgcDisplayPreferredVideoCodecType *msg)
+{
+    StreamChannelClient *scc = STREAM_CHANNEL_CLIENT(rcc);
+
+    g_return_val_if_fail(msg->num_of_codecs > 0, TRUE);
+
+    g_clear_pointer(&scc->client_preferred_video_codecs, g_array_unref);
+    scc->client_preferred_video_codecs = video_stream_parse_preferred_codecs(msg);
+
+    return TRUE;
+}
+
 static void
 stream_channel_connect(RedChannel *red_channel, RedClient *red_client, RedStream *stream,
                        int migration, RedChannelCapabilities *caps)
@@ -448,10 +472,25 @@ stream_channel_constructed(GObject *object)

     red_channel_set_cap(red_channel, SPICE_DISPLAY_CAP_MONITORS_CONFIG);
     red_channel_set_cap(red_channel, SPICE_DISPLAY_CAP_STREAM_REPORT);
+    red_channel_set_cap(red_channel, SPICE_DISPLAY_CAP_PREF_VIDEO_CODEC_TYPE);

     reds_register_channel(reds, red_channel);
 }

+static void
+stream_channel_finalize(GObject *object)
+{
+    StreamChannel *self = STREAM_CHANNEL(object);
+    RedChannelClient *rcc;
+
+    FOREACH_CLIENT(self, rcc) {
+        StreamChannelClient *scc = STREAM_CHANNEL_CLIENT(rcc);
+        g_clear_pointer(&scc->client_preferred_video_codecs, g_array_unref);
+    }
+
+    G_OBJECT_CLASS(stream_channel_parent_class)->finalize(object);
+}
+
 static void
 stream_channel_class_init(StreamChannelClass *klass)
 {
@@ -459,6 +498,7 @@ stream_channel_class_init(StreamChannelClass *klass)
     RedChannelClass *channel_class = RED_CHANNEL_CLASS(klass);

     object_class->constructed = stream_channel_constructed;
+    object_class->finalize = stream_channel_finalize;

     channel_class->parser = spice_get_client_channel_parser(SPICE_CHANNEL_DISPLAY, NULL);
     channel_class->handle_message = handle_message;
diff --git a/server/video-stream.c b/server/video-stream.c
index 6aa859a0..a61c8ab2 100644
--- a/server/video-stream.c
+++ b/server/video-stream.c
@@ -20,6 +20,7 @@
 #include "display-channel-private.h"
 #include "main-channel-client.h"
 #include "red-client.h"
+#include "stream-channel.h"

 #define FPS_TEST_INTERVAL 1
 #define FOREACH_STREAMS(display, item)                  \
@@ -468,6 +469,41 @@ static bool video_stream_add_frame(DisplayChannel *display,
     return FALSE;
 }

+/* Returns an array with SPICE_VIDEO_CODEC_TYPE_ENUM_END elements,
+ * with the client preference order (index) as value */
+GArray *video_stream_parse_preferred_codecs(SpiceMsgcDisplayPreferredVideoCodecType *msg)
+{
+    gint i, len;
+    gint indexes[SPICE_VIDEO_CODEC_TYPE_ENUM_END];
+    GArray *client;
+
+    /* set default to a big and positive number */
+    memset(indexes, 0x7f, sizeof(indexes));
+
+    for (len = 0, i = 0; i < msg->num_of_codecs; i++) {
+        gint video_codec = msg->codecs[i];
+
+        if (video_codec < SPICE_VIDEO_CODEC_TYPE_MJPEG ||
+            video_codec >= SPICE_VIDEO_CODEC_TYPE_ENUM_END) {
+            spice_debug("Client has sent unknown video-codec (value %d at index %d). "
+                        "Ignoring as server can't handle it",
+                         video_codec, i);
+            continue;
+        }
+
+        if (indexes[video_codec] < SPICE_VIDEO_CODEC_TYPE_ENUM_END) {
+            continue;
+        }
+
+        len++;
+        indexes[video_codec] = len;
+    }
+    client = g_array_sized_new(FALSE, FALSE, sizeof(gint), SPICE_VIDEO_CODEC_TYPE_ENUM_END);
+    g_array_append_vals(client, indexes, SPICE_VIDEO_CODEC_TYPE_ENUM_END);
+
+    return client;
+}
+
 /* TODO: document the difference between the 2 functions below */
 void video_stream_trace_update(DisplayChannel *display, Drawable *drawable)
 {
diff --git a/server/video-stream.h b/server/video-stream.h
index 46b076fd..73435515 100644
--- a/server/video-stream.h
+++ b/server/video-stream.h
@@ -147,6 +147,7 @@ void video_stream_detach_and_stop(DisplayChannel *display);
 void video_stream_trace_add_drawable(DisplayChannel *display, Drawable *item);
 void video_stream_detach_behind(DisplayChannel *display, QRegion *region,
                                 Drawable *drawable);
+GArray *video_stream_parse_preferred_codecs(SpiceMsgcDisplayPreferredVideoCodecType *msg);

 void video_stream_agent_unref(DisplayChannel *display, VideoStreamAgent *agent);
 void video_stream_agent_stop(VideoStreamAgent *agent);
--
2.21.0


More information about the Spice-devel mailing list