[Spice-devel,v7,04/23] server: Check the client video codec capabilities

Submitted by Francois Gouget on Dec. 16, 2015, 3:17 p.m.

Details

Message ID alpine.DEB.2.20.1512161121240.16981@amboise
State New
Headers show
Series "Add GStreamer support for video streaming" ( rev: 1 ) in Spice

Not browsing as part of any series.

Commit Message

Francois Gouget Dec. 16, 2015, 3:17 p.m.
Signed-off-by: Francois Gouget <fgouget@codeweavers.com>
---
 configure.ac    |  2 +-
 server/dcc.c    |  5 ++++-
 server/dcc.h    |  2 +-
 server/stream.c | 41 +++++++++++++++++++++++++++++------------
 4 files changed, 35 insertions(+), 15 deletions(-)

Note:
 * This depends on the spice-protocol changes of 01/23 and thus raises 
   the minimum Spice protocol version to 0.12.12. Adjust as appropriate.

Patch hide | download patch | download mbox

diff --git a/configure.ac b/configure.ac
index 141d874..20cf429 100644
--- a/configure.ac
+++ b/configure.ac
@@ -122,7 +122,7 @@  AS_IF([test x"$have_smartcard" = "xyes"], [
     AS_VAR_APPEND([SPICE_REQUIRES], [" libcacard >= 0.1.2"])
 ])
 
-SPICE_PROTOCOL_MIN_VER=0.12.10
+SPICE_PROTOCOL_MIN_VER=0.12.12
 PKG_CHECK_MODULES([SPICE_PROTOCOL], [spice-protocol >= $SPICE_PROTOCOL_MIN_VER])
 AC_SUBST([SPICE_PROTOCOL_MIN_VER])
 
diff --git a/server/dcc.c b/server/dcc.c
index 6a61f4c..5fe6dc9 100644
--- a/server/dcc.c
+++ b/server/dcc.c
@@ -407,7 +407,10 @@  static void dcc_create_all_streams(DisplayChannelClient *dcc)
 
     while ((item = ring_next(ring, item))) {
         Stream *stream = SPICE_CONTAINEROF(item, Stream, link);
-        dcc_create_stream(dcc, stream);
+        if (!dcc_create_stream(dcc, stream)) {
+            stream_stop(DCC_TO_DC(dcc), stream);
+            return;
+        }
     }
 }
 
diff --git a/server/dcc.h b/server/dcc.h
index b510254..34ca346 100644
--- a/server/dcc.h
+++ b/server/dcc.h
@@ -173,7 +173,7 @@  void                       dcc_destroy_surface                       (DisplayCha
                                                                       uint32_t surface_id);
 void                       dcc_stream_agent_clip                     (DisplayChannelClient* dcc,
                                                                       StreamAgent *agent);
-void                       dcc_create_stream                         (DisplayChannelClient *dcc,
+gboolean                   dcc_create_stream                         (DisplayChannelClient *dcc,
                                                                       Stream *stream);
 void                       dcc_create_surface                        (DisplayChannelClient *dcc,
                                                                       int surface_id);
diff --git a/server/stream.c b/server/stream.c
index 9c335b6..bbc7003 100644
--- a/server/stream.c
+++ b/server/stream.c
@@ -440,7 +440,12 @@  static void display_channel_create_stream(DisplayChannel *display, Drawable *dra
     display->streams_size_total += stream->width * stream->height;
     display->stream_count++;
     FOREACH_DCC(display, dcc_ring_item, next, dcc) {
-        dcc_create_stream(dcc, stream);
+        if (!dcc_create_stream(dcc, stream)) {
+            drawable->stream = NULL;
+            stream->current = NULL;
+            stream_stop(display, stream);
+            return;
+        }
     }
     spice_debug("stream %d %dx%d (%d, %d) (%d, %d) %u fps",
                 (int)(stream - display->streams_buf), stream->width,
@@ -695,25 +700,32 @@  static void update_client_playback_delay(void *opaque, uint32_t delay_ms)
 }
 
 /* A helper for dcc_create_stream(). */
-static VideoEncoder* dcc_create_video_encoder(uint64_t starting_bit_rate,
+static VideoEncoder* dcc_create_video_encoder(DisplayChannelClient *dcc,
+                                              uint64_t starting_bit_rate,
                                               VideoEncoderRateControlCbs *cbs,
                                               void *cbs_opaque)
 {
+    RedChannelClient *rcc = RED_CHANNEL_CLIENT(dcc);
+    int client_has_multi_codec = red_channel_client_test_remote_cap(rcc, SPICE_DISPLAY_CAP_MULTI_CODEC);
+    if (!client_has_multi_codec || red_channel_client_test_remote_cap(rcc, SPICE_DISPLAY_CAP_CODEC_MJPEG)) {
 #ifdef HAVE_GSTREAMER_1_0
-    VideoEncoder* video_encoder = gstreamer_encoder_new(starting_bit_rate, cbs, cbs_opaque);
-    if (video_encoder) {
-        return video_encoder;
-    }
+        VideoEncoder* video_encoder = gstreamer_encoder_new(starting_bit_rate, cbs, cbs_opaque);
+        if (video_encoder) {
+            return video_encoder;
+        }
 #endif
-    /* Use the builtin MJPEG video encoder as a fallback */
-    return mjpeg_encoder_new(starting_bit_rate, cbs, cbs_opaque);
+        /* Use the builtin MJPEG video encoder as a fallback */
+        return mjpeg_encoder_new(starting_bit_rate, cbs, cbs_opaque);
+    }
+
+    return NULL;
 }
 
-void dcc_create_stream(DisplayChannelClient *dcc, Stream *stream)
+gboolean dcc_create_stream(DisplayChannelClient *dcc, Stream *stream)
 {
     StreamAgent *agent = &dcc->stream_agents[get_stream_id(DCC_TO_DC(dcc), stream)];
 
-    spice_return_if_fail(region_is_empty(&agent->vis_region));
+    spice_return_val_if_fail(region_is_empty(&agent->vis_region), FALSE);
 
     stream->refs++;
     if (stream->current) {
@@ -736,9 +748,13 @@  void dcc_create_stream(DisplayChannelClient *dcc, Stream *stream)
         video_cbs.update_client_playback_delay = update_client_playback_delay;
 
         initial_bit_rate = get_initial_bit_rate(dcc, stream);
-        agent->video_encoder = dcc_create_video_encoder(initial_bit_rate, &video_cbs, agent);
+        agent->video_encoder = dcc_create_video_encoder(dcc, initial_bit_rate, &video_cbs, agent);
     } else {
-        agent->video_encoder = dcc_create_video_encoder(0, NULL, NULL);
+        agent->video_encoder = dcc_create_video_encoder(dcc, 0, NULL, NULL);
+    }
+    if (agent->video_encoder == NULL) {
+        stream->refs--;
+        return FALSE;
     }
     red_channel_client_pipe_add(RED_CHANNEL_CLIENT(dcc), &agent->create_item);
 
@@ -757,6 +773,7 @@  void dcc_create_stream(DisplayChannelClient *dcc, Stream *stream)
         agent->stats.start = stream->current->red_drawable->mm_time;
     }
 #endif
+    return TRUE;
 }
 
 void stream_agent_stop(StreamAgent *agent)