mirror of
https://gitlab.uni-freiburg.de/opensourcevdi/spice-gtk
synced 2026-02-04 21:48:16 +00:00
display: video streaming: add support for frames of different sizes
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.
This commit is contained in:
parent
da0071300e
commit
f84e039f25
@ -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_current_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) {
|
||||
|
||||
@ -73,6 +73,9 @@ typedef struct display_stream {
|
||||
SpiceChannel *channel;
|
||||
} display_stream;
|
||||
|
||||
void stream_get_dimensions(display_stream *st, int *width, int *height);
|
||||
uint32_t stream_get_current_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);
|
||||
|
||||
@ -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,72 @@ static gboolean display_stream_schedule(display_stream *st)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static uint32_t stream_get_flags(display_stream *st)
|
||||
{
|
||||
SpiceMsgDisplayStreamCreate *info = spice_msg_in_parsed(st->msg_create);
|
||||
|
||||
return info->flags;
|
||||
}
|
||||
|
||||
G_GNUC_INTERNAL
|
||||
uint32_t stream_get_current_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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
G_GNUC_INTERNAL
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/* main context */
|
||||
static gboolean display_stream_render(display_stream *st)
|
||||
{
|
||||
@ -1008,14 +1075,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 +1096,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 +1125,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 +1400,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,
|
||||
|
||||
@ -1 +1 @@
|
||||
Subproject commit e96dbb4172ec7a47a5b15d3b9e921e12623fddaa
|
||||
Subproject commit 22fc0b0145876b90385c1c88923bcd72a6380812
|
||||
Loading…
Reference in New Issue
Block a user