[Spice-devel] [PATCH v3] streaming: Use the frame dimensions reported by the video decoder

Francois Gouget fgouget at codeweavers.com
Fri Jun 3 13:02:59 UTC 2016


The dimensions sent by the remote end are redundant and should not be
trusted.

Signed-off-by: Francois Gouget <fgouget at codeweavers.com>
---
 src/channel-display-gst.c   | 41 +++++++++++++++++++++++++++++++++--------
 src/channel-display-mjpeg.c | 11 ++++++-----
 src/channel-display-priv.h  |  3 +--
 src/channel-display.c       | 24 +-----------------------
 4 files changed, 41 insertions(+), 38 deletions(-)

diff --git a/src/channel-display-gst.c b/src/channel-display-gst.c
index ca6b6e7..c752639 100644
--- a/src/channel-display-gst.c
+++ b/src/channel-display-gst.c
@@ -87,26 +87,51 @@ static void schedule_frame(SpiceGstDecoder *decoder);
 static gboolean display_frame(gpointer video_decoder)
 {
     SpiceGstDecoder *decoder = (SpiceGstDecoder*)video_decoder;
+    SpiceFrame *frame;
+    GstCaps *caps;
+    gint width, height;
+    GstStructure *s;
+    GstBuffer *buffer;
+    GstMapInfo mapinfo;
 
     decoder->timer_id = 0;
 
     g_mutex_lock(&decoder->queues_mutex);
-    SpiceFrame *frame = g_queue_pop_head(decoder->display_queue);
+    frame = g_queue_pop_head(decoder->display_queue);
     g_mutex_unlock(&decoder->queues_mutex);
+    /* If the queue is empty we don't even need to reschedule */
     g_return_val_if_fail(frame, G_SOURCE_REMOVE);
 
-    GstBuffer *buffer = frame->sample ? gst_sample_get_buffer(frame->sample) : NULL;
-    GstMapInfo mapinfo;
     if (!frame->sample) {
         spice_warning("got a frame without a sample!");
-    } else if (gst_buffer_map(buffer, &mapinfo, GST_MAP_READ)) {
-        stream_display_frame(decoder->base.stream, frame->msg, mapinfo.data);
-        gst_buffer_unmap(buffer, &mapinfo);
-    } else {
+        goto error;
+    }
+
+    caps = gst_sample_get_caps(frame->sample);
+    if (!caps) {
+        spice_warning("GStreamer error: could not get the caps of the sample");
+        goto error;
+    }
+
+    s = gst_caps_get_structure(caps, 0);
+    if (!gst_structure_get_int(s, "width", &width) ||
+        !gst_structure_get_int(s, "height", &height)) {
+        spice_warning("GStreamer error: could not get the size of the frame");
+        goto error;
+    }
+
+    buffer = gst_sample_get_buffer(frame->sample);
+    if (!gst_buffer_map(buffer, &mapinfo, GST_MAP_READ)) {
         spice_warning("GStreamer error: could not map the buffer");
+        goto error;
     }
-    free_frame(frame);
 
+    stream_display_frame(decoder->base.stream, frame->msg,
+                         width, height, mapinfo.data);
+    gst_buffer_unmap(buffer, &mapinfo);
+
+ error:
+    free_frame(frame);
     schedule_frame(decoder);
     return G_SOURCE_REMOVE;
 }
diff --git a/src/channel-display-mjpeg.c b/src/channel-display-mjpeg.c
index a2dae82..4976d53 100644
--- a/src/channel-display-mjpeg.c
+++ b/src/channel-display-mjpeg.c
@@ -86,12 +86,13 @@ static gboolean mjpeg_decoder_decode_frame(gpointer video_decoder)
 {
     MJpegDecoder *decoder = (MJpegDecoder*)video_decoder;
     gboolean back_compat = decoder->base.stream->channel->priv->peer_hdr.major_version == 1;
-    int width;
-    int height;
+    JDIMENSION width, height;
     uint8_t *dest;
     uint8_t *lines[4];
 
-    stream_get_dimensions(decoder->base.stream, decoder->cur_frame_msg, &width, &height);
+    jpeg_read_header(&decoder->mjpeg_cinfo, 1);
+    width = decoder->mjpeg_cinfo.image_width;
+    height = decoder->mjpeg_cinfo.image_height;
     if (decoder->out_size < width * height * 4) {
         g_free(decoder->out_frame);
         decoder->out_size = width * height * 4;
@@ -99,7 +100,6 @@ static gboolean mjpeg_decoder_decode_frame(gpointer video_decoder)
     }
     dest = decoder->out_frame;
 
-    jpeg_read_header(&decoder->mjpeg_cinfo, 1);
 #ifdef JCS_EXTENSIONS
     // requires jpeg-turbo
     if (back_compat)
@@ -168,7 +168,8 @@ static gboolean mjpeg_decoder_decode_frame(gpointer video_decoder)
     jpeg_finish_decompress(&decoder->mjpeg_cinfo);
 
     /* Display the frame and dispose of it */
-    stream_display_frame(decoder->base.stream, decoder->cur_frame_msg, decoder->out_frame);
+    stream_display_frame(decoder->base.stream, decoder->cur_frame_msg,
+                         width, height, decoder->out_frame);
     spice_msg_in_unref(decoder->cur_frame_msg);
     decoder->cur_frame_msg = NULL;
     decoder->timer_id = 0;
diff --git a/src/channel-display-priv.h b/src/channel-display-priv.h
index 3155015..3fcf2e2 100644
--- a/src/channel-display-priv.h
+++ b/src/channel-display-priv.h
@@ -135,10 +135,9 @@ struct display_stream {
     uint32_t report_drops_seq_len;
 };
 
-void stream_get_dimensions(display_stream *st, SpiceMsgIn *frame_msg, int *width, int *height);
 guint32 stream_get_time(display_stream *st);
 void stream_dropped_frame_on_playback(display_stream *st);
-void stream_display_frame(display_stream *st, SpiceMsgIn *frame_msg, uint8_t* data);
+void stream_display_frame(display_stream *st, SpiceMsgIn *frame_msg, uint32_t width, uint32_t height, uint8_t *data);
 uint32_t spice_msg_in_frame_data(SpiceMsgIn *frame_msg, uint8_t **data);
 
 
diff --git a/src/channel-display.c b/src/channel-display.c
index 54bc30e..22e64e2 100644
--- a/src/channel-display.c
+++ b/src/channel-display.c
@@ -1174,26 +1174,6 @@ uint32_t spice_msg_in_frame_data(SpiceMsgIn *frame_msg, uint8_t **data)
 }
 
 G_GNUC_INTERNAL
-void stream_get_dimensions(display_stream *st, SpiceMsgIn *frame_msg, int *width, int *height)
-{
-    g_return_if_fail(width != NULL);
-    g_return_if_fail(height != NULL);
-
-    if (frame_msg == NULL ||
-        spice_msg_in_type(frame_msg) != SPICE_MSG_DISPLAY_STREAM_DATA_SIZED) {
-        SpiceMsgDisplayStreamCreate *info = spice_msg_in_parsed(st->msg_create);
-
-        *width = info->stream_width;
-        *height = info->stream_height;
-    } else {
-        SpiceMsgDisplayStreamDataSized *op = spice_msg_in_parsed(frame_msg);
-
-        *width = op->width;
-        *height = op->height;
-   }
-}
-
-G_GNUC_INTERNAL
 guint32 stream_get_time(display_stream *st)
 {
     SpiceSession *session = spice_channel_get_session(st->channel);
@@ -1210,13 +1190,11 @@ void stream_dropped_frame_on_playback(display_stream *st)
 /* main context */
 G_GNUC_INTERNAL
 void stream_display_frame(display_stream *st, SpiceMsgIn *frame_msg,
-                          uint8_t* data)
+                          uint32_t width, uint32_t height, uint8_t *data)
 {
-    int width, height;
     const SpiceRect *dest;
     int stride;
 
-    stream_get_dimensions(st, frame_msg, &width, &height);
     dest = stream_get_dest(st, frame_msg);
 
     stride = width * sizeof(uint32_t);
-- 
2.8.1


More information about the Spice-devel mailing list