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

Pavel Grunt pgrunt at redhat.com
Mon Jun 6 07:07:29 UTC 2016


On Fri, 2016-06-03 at 15:02 +0200, Francois Gouget wrote:
> The dimensions sent by the remote end are redundant and should not be
> trusted.
> 
> Signed-off-by: Francois Gouget <fgouget at codeweavers.com>
Acked-by: Pavel Grunt <pgrunt at redhat.com>

Thanks,
Pavel
> ---
>  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);


More information about the Spice-devel mailing list