[Spice-devel] [PATCH spice-gtk 1/3] display: video streaming: add support for frames of different sizes
Yonit Halperin
yhalperi at redhat.com
Sun Apr 8 08:44:00 PDT 2012
When playing a youtube video on Windows guest, the driver sometimes sends
images which contain the videe frames, 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.
Signed-off-by: Yonit Halperin <yhalperi at redhat.com>
---
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 cb1bc87..abdf74f 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,12 +64,12 @@ 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);
- 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 8269705..6f0dd95 100644
--- a/gtk/channel-display.c
+++ b/gtk/channel-display.c
@@ -606,6 +606,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);
}
/* ------------------------------------------------------------------ */
@@ -975,7 +976,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)
@@ -1002,6 +1003,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)
{
@@ -1021,14 +1085,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;
}
@@ -1037,15 +1106,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;
@@ -1066,12 +1135,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... */
@@ -1337,6 +1410,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 e3f6941..cc613c0 160000
--- a/spice-common
+++ b/spice-common
@@ -1 +1 @@
-Subproject commit e3f6941895085c7138abcb49a98572ea1479ac1a
+Subproject commit cc613c0c3c1ba3fe7017528d0da998a210a35d75
--
1.7.7.6
More information about the Spice-devel
mailing list