[Spice-devel] [PATCH spice-gtk] display: video streaming: add support for frames of different sizes
Yonit Halperin
yhalperi at redhat.com
Wed May 2 07:05:32 PDT 2012
rhbz #815426
When playing a youtube video on Windows guest, the driver sometimes sends
images which contain a video frame, but also other parts of the
screen (e.g., the you tube process bar). In order to prevent glitches, we send these
images as part of the stream, using SPICE_MSG_DISPLAY_STREAM_DATA_SIZED.
---
gtk/channel-display-mjpeg.c | 12 +++---
gtk/channel-display-priv.h | 5 ++
gtk/channel-display.c | 96 ++++++++++++++++++++++++++++++++++++++-----
spice-common | 2 +-
4 files changed, 97 insertions(+), 18 deletions(-)
diff --git a/gtk/channel-display-mjpeg.c b/gtk/channel-display-mjpeg.c
index aed3adf..4bbcefc 100644
--- a/gtk/channel-display-mjpeg.c
+++ b/gtk/channel-display-mjpeg.c
@@ -24,10 +24,10 @@
static void mjpeg_src_init(struct jpeg_decompress_struct *cinfo)
{
display_stream *st = SPICE_CONTAINEROF(cinfo->src, display_stream, mjpeg_src);
- SpiceMsgDisplayStreamData *data = spice_msg_in_parsed(st->msg_data);
+ uint8_t *data;
- cinfo->src->next_input_byte = data->data;
- cinfo->src->bytes_in_buffer = data->data_size;
+ cinfo->src->bytes_in_buffer = stream_get_mjpeg_frame(st, &data);
+ cinfo->src->next_input_byte = data;
}
static boolean mjpeg_src_fill(struct jpeg_decompress_struct *cinfo)
@@ -64,13 +64,13 @@ void stream_mjpeg_init(display_stream *st)
G_GNUC_INTERNAL
void stream_mjpeg_data(display_stream *st)
{
- SpiceMsgDisplayStreamCreate *info = spice_msg_in_parsed(st->msg_create);
gboolean back_compat = st->channel->priv->peer_hdr.major_version == 1;
- int width = info->stream_width;
- int height = info->stream_height;
+ int width;
+ int height;
uint8_t *dest;
uint8_t *lines[4];
+ stream_get_dimensions(st, &width, &height);
dest = malloc(width * height * 4);
if (st->out_frame) {
diff --git a/gtk/channel-display-priv.h b/gtk/channel-display-priv.h
index 6fb624a..1969697 100644
--- a/gtk/channel-display-priv.h
+++ b/gtk/channel-display-priv.h
@@ -73,6 +73,11 @@ typedef struct display_stream {
SpiceChannel *channel;
} display_stream;
+void stream_get_dimensions(display_stream *st, int *width, int *height);
+SpiceRect *stream_get_dest(display_stream *st);
+uint32_t stream_get_flags(display_stream *st);
+uint32_t stream_get_mjpeg_frame(display_stream *st, uint8_t **data);
+
/* channel-display-mjpeg.c */
void stream_mjpeg_init(display_stream *st);
void stream_mjpeg_data(display_stream *st);
diff --git a/gtk/channel-display.c b/gtk/channel-display.c
index d3109bc..a8e830b 100644
--- a/gtk/channel-display.c
+++ b/gtk/channel-display.c
@@ -597,6 +597,7 @@ static void spice_display_channel_init(SpiceDisplayChannel *channel)
#if defined(WIN32)
c->dc = create_compatible_dc();
#endif
+ spice_channel_set_capability(SPICE_CHANNEL(channel), SPICE_DISPLAY_CAP_SIZED_STREAM);
}
/* ------------------------------------------------------------------ */
@@ -962,7 +963,7 @@ static void display_handle_stream_create(SpiceChannel *channel, SpiceMsgIn *in)
static gboolean display_stream_schedule(display_stream *st)
{
guint32 time, d;
- SpiceMsgDisplayStreamData *op;
+ SpiceStreamDataHeader *op;
SpiceMsgIn *in;
if (st->timeout)
@@ -989,6 +990,69 @@ static gboolean display_stream_schedule(display_stream *st)
return FALSE;
}
+void stream_get_dimensions(display_stream *st, int *width, int *height)
+{
+ g_return_if_fail(width != NULL);
+ g_return_if_fail(height != NULL);
+
+ if (st->msg_data == NULL ||
+ spice_msg_in_type(st->msg_data) != 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(st->msg_data);
+
+ *width = op->width;
+ *height = op->height;
+ }
+}
+
+SpiceRect *stream_get_dest(display_stream *st)
+{
+ if (st->msg_data == NULL ||
+ spice_msg_in_type(st->msg_data) != SPICE_MSG_DISPLAY_STREAM_DATA_SIZED) {
+ SpiceMsgDisplayStreamCreate *info = spice_msg_in_parsed(st->msg_create);
+
+ return &info->dest;
+ } else {
+ SpiceMsgDisplayStreamDataSized *op = spice_msg_in_parsed(st->msg_data);
+
+ return &op->dest;
+ }
+
+}
+
+uint32_t stream_get_flags(display_stream *st)
+{
+ SpiceMsgDisplayStreamCreate *info = spice_msg_in_parsed(st->msg_create);
+
+ return info->flags;
+}
+
+uint32_t stream_get_mjpeg_frame(display_stream *st, uint8_t **data)
+{
+ if (st->msg_data == NULL) {
+ *data = NULL;
+ return 0;
+ }
+
+ if (spice_msg_in_type(st->msg_data) == SPICE_MSG_DISPLAY_STREAM_DATA) {
+ SpiceMsgDisplayStreamData *op = spice_msg_in_parsed(st->msg_data);
+
+ *data = op->data;
+ return op->data_size;
+ } else {
+ SpiceMsgDisplayStreamDataSized *op = spice_msg_in_parsed(st->msg_data);
+
+ g_return_val_if_fail(spice_msg_in_type(st->msg_data) ==
+ SPICE_MSG_DISPLAY_STREAM_DATA_SIZED, 0);
+ *data = op->data;
+ return op->data_size;
+ }
+
+}
/* main context */
static gboolean display_stream_render(display_stream *st)
{
@@ -1008,14 +1072,19 @@ static gboolean display_stream_render(display_stream *st)
}
if (st->out_frame) {
- SpiceMsgDisplayStreamCreate *info = spice_msg_in_parsed(st->msg_create);
+ int width;
+ int height;
+ SpiceRect *dest;
uint8_t *data;
int stride;
+ stream_get_dimensions(st, &width, &height);
+ dest = stream_get_dest(st);
+
data = st->out_frame;
- stride = info->stream_width * sizeof(uint32_t);
- if (!(info->flags & SPICE_STREAM_FLAGS_TOP_DOWN)) {
- data += stride * (info->src_height - 1);
+ stride = width * sizeof(uint32_t);
+ if (!(stream_get_flags(st) & SPICE_STREAM_FLAGS_TOP_DOWN)) {
+ data += stride * (height - 1);
stride = -stride;
}
@@ -1024,15 +1093,15 @@ static gboolean display_stream_render(display_stream *st)
#ifdef WIN32
SPICE_DISPLAY_CHANNEL(st->channel)->priv->dc,
#endif
- &info->dest, data,
- info->src_width, info->src_height, stride,
+ dest, data,
+ width, height, stride,
st->have_region ? &st->region : NULL);
if (st->surface->primary)
g_signal_emit(st->channel, signals[SPICE_DISPLAY_INVALIDATE], 0,
- info->dest.left, info->dest.top,
- info->dest.right - info->dest.left,
- info->dest.bottom - info->dest.top);
+ dest->left, dest->top,
+ dest->right - dest->left,
+ dest->bottom - dest->top);
}
st->msg_data = NULL;
@@ -1053,12 +1122,16 @@ static gboolean display_stream_render(display_stream *st)
static void display_handle_stream_data(SpiceChannel *channel, SpiceMsgIn *in)
{
SpiceDisplayChannelPrivate *c = SPICE_DISPLAY_CHANNEL(channel)->priv;
- SpiceMsgDisplayStreamData *op = spice_msg_in_parsed(in);
+ SpiceStreamDataHeader *op = spice_msg_in_parsed(in);
display_stream *st = c->streams[op->id];
guint32 mmtime;
mmtime = spice_session_get_mm_time(spice_channel_get_session(channel));
+ if (spice_msg_in_type(in) == SPICE_MSG_DISPLAY_STREAM_DATA_SIZED) {
+ SPICE_DEBUG("stream %d contains sized data", op->id);
+ }
+
if (op->multi_media_time == 0) {
g_critical("Received frame with invalid 0 timestamp! perhaps wrong graphic driver?");
op->multi_media_time = mmtime + 100; /* workaround... */
@@ -1324,6 +1397,7 @@ static const spice_msg_handler display_handlers[] = {
[ SPICE_MSG_DISPLAY_STREAM_CLIP ] = display_handle_stream_clip,
[ SPICE_MSG_DISPLAY_STREAM_DESTROY ] = display_handle_stream_destroy,
[ SPICE_MSG_DISPLAY_STREAM_DESTROY_ALL ] = display_handle_stream_destroy_all,
+ [ SPICE_MSG_DISPLAY_STREAM_DATA_SIZED ] = display_handle_stream_data,
[ SPICE_MSG_DISPLAY_DRAW_FILL ] = display_handle_draw_fill,
[ SPICE_MSG_DISPLAY_DRAW_OPAQUE ] = display_handle_draw_opaque,
diff --git a/spice-common b/spice-common
index e96dbb4..22fc0b0 160000
--- a/spice-common
+++ b/spice-common
@@ -1 +1 @@
-Subproject commit e96dbb4172ec7a47a5b15d3b9e921e12623fddaa
+Subproject commit 22fc0b0145876b90385c1c88923bcd72a6380812
--
1.7.7.6
More information about the Spice-devel
mailing list