diff options
author | Gerd Hoffmann <kraxel@redhat.com> | 2010-09-22 19:35:04 +0200 |
---|---|---|
committer | Gerd Hoffmann <kraxel@redhat.com> | 2010-09-22 19:35:04 +0200 |
commit | f4a31d41cd3e333a69dc6a459143ff49b8d544cd (patch) | |
tree | 5fe62c6cfc541f0d92ee29f85d1ed28898ef05f2 | |
parent | efc287891d76c5436583fb0d18e2b0e85ae2d7e8 (diff) |
mjpeg decoder.
-rw-r--r-- | gtk/Makefile.am | 1 | ||||
-rw-r--r-- | gtk/channel-display-mjpeg.c | 100 | ||||
-rw-r--r-- | gtk/channel-display.c | 54 | ||||
-rw-r--r-- | gtk/spice-channel-priv.h | 18 |
4 files changed, 156 insertions, 17 deletions
diff --git a/gtk/Makefile.am b/gtk/Makefile.am index fcb975f..5d788a8 100644 --- a/gtk/Makefile.am +++ b/gtk/Makefile.am @@ -109,6 +109,7 @@ libspice_client_glib_la_SOURCES = \ channel-base.c \ channel-main.c \ channel-display.c \ + channel-display-mjpeg.c \ channel-cursor.c \ channel-inputs.c \ channel-playback.c \ diff --git a/gtk/channel-display-mjpeg.c b/gtk/channel-display-mjpeg.c new file mode 100644 index 0000000..2c3d31b --- /dev/null +++ b/gtk/channel-display-mjpeg.c @@ -0,0 +1,100 @@ +#include "spice-client.h" +#include "spice-channel-priv.h" + +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); + + cinfo->src->next_input_byte = data->data; + cinfo->src->bytes_in_buffer = data->data_size; +} + +static int mjpeg_src_fill(struct jpeg_decompress_struct *cinfo) +{ + PANIC("need more input data"); +} + +static void mjpeg_src_skip(struct jpeg_decompress_struct *cinfo, + long num_bytes) +{ + cinfo->src->next_input_byte += num_bytes; +} + +static void mjpeg_src_term(struct jpeg_decompress_struct *cinfo) +{ + /* nothing */ +} + +void stream_mjpeg_init(display_stream *st) +{ + st->mjpeg_cinfo.err = jpeg_std_error(&st->mjpeg_jerr); + jpeg_create_decompress(&st->mjpeg_cinfo); + + st->mjpeg_src.init_source = mjpeg_src_init; + st->mjpeg_src.fill_input_buffer = mjpeg_src_fill; + st->mjpeg_src.skip_input_data = mjpeg_src_skip; + st->mjpeg_src.resync_to_restart = jpeg_resync_to_restart; + st->mjpeg_src.term_source = mjpeg_src_term; + st->mjpeg_cinfo.src = &st->mjpeg_src; +} + +static void mjpeg_convert_scanline(uint8_t *dest, uint8_t *src, int width, int compat) +{ + uint32_t *row = (void*)dest; + uint32_t c; + int x; + + if (compat) { + /* + * We need to check for the old major and for backwards compat + * a) swap r and b (done) + * b) to-yuv with right values and then from-yuv with old wrong values (TODO) + */ + for (x = 0; x < width; x++) { + c = src[2] << 16 | src[1] << 8 | src[0]; + src += 3; + *row++ = c; + } + } else { + for (x = 0; x < width; x++) { + c = src[0] << 16 | src[1] << 8 | src[2]; + src += 3; + *row++ = c; + } + } +} + +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; + uint8_t *line, *dest; + int i; + + line = malloc(width * 4); + dest = malloc(width * height * 4); + + if (st->out_frame) { + free(st->out_frame); + } + st->out_frame = dest; + + jpeg_read_header(&st->mjpeg_cinfo, 1); + st->mjpeg_cinfo.out_color_space = JCS_RGB; + jpeg_start_decompress(&st->mjpeg_cinfo); + for (i = 0; i < height; i++) { + jpeg_read_scanlines(&st->mjpeg_cinfo, &line, 1); + mjpeg_convert_scanline(dest, line, width, 0 /* FIXME: compat */); + dest += 4 * width; + } + jpeg_finish_decompress(&st->mjpeg_cinfo); + + free(line); +} + +void stream_mjpeg_cleanup(display_stream *st) +{ + jpeg_destroy_decompress(&st->mjpeg_cinfo); +} diff --git a/gtk/channel-display.c b/gtk/channel-display.c index 108925e..5ccf5dd 100644 --- a/gtk/channel-display.c +++ b/gtk/channel-display.c @@ -305,7 +305,6 @@ static void display_handle_inv_palette_all(SpiceChannel *channel, spice_msg_in * static void display_handle_stream_create(SpiceChannel *channel, spice_msg_in *in) { -#if 0 spice_channel *c = SPICE_CHANNEL_GET_PRIVATE(channel); SpiceMsgDisplayStreamCreate *op = spice_msg_in_parsed(in); display_stream *st; @@ -318,25 +317,47 @@ static void display_handle_stream_create(SpiceChannel *channel, spice_msg_in *in st = c->display.streams[op->id]; st->msg_create = in; - st->clip = &op->clip; spice_msg_in_get(in); -#endif + st->clip = &op->clip; + st->codec = op->codec_type; + st->surface = find_surface(channel, op->surface_id); + + switch (st->codec) { + case SPICE_VIDEO_CODEC_TYPE_MJPEG: + stream_mjpeg_init(st); + break; + } } static void display_handle_stream_data(SpiceChannel *channel, spice_msg_in *in) { -#if 0 -// spice_channel *c = SPICE_CHANNEL_GET_PRIVATE(channel); + spice_channel *c = SPICE_CHANNEL_GET_PRIVATE(channel); SpiceMsgDisplayStreamData *op = spice_msg_in_parsed(in); -// display_stream *st = c->display.streams[op->id]; + display_stream *st = c->display.streams[op->id]; - fprintf(stderr, "%s: TODO (id %d)\n", __FUNCTION__, op->id); -#endif + st->msg_data = in; + + switch (st->codec) { + case SPICE_VIDEO_CODEC_TYPE_MJPEG: + stream_mjpeg_data(st); + break; + } + + if (st->out_frame) { + SpiceMsgDisplayStreamCreate *info = spice_msg_in_parsed(st->msg_create); + st->surface->canvas->ops->put_image + (st->surface->canvas, &info->dest, st->out_frame, + info->src_width, info->src_height, info->src_width * 4, + NULL /* FIXME: st->clip */ ); + if (st->surface->primary) + emit_invalidate(channel, &info->dest); + } + + st->msg_data = NULL; } static void display_handle_stream_clip(SpiceChannel *channel, spice_msg_in *in) { -#if 0 spice_channel *c = SPICE_CHANNEL_GET_PRIVATE(channel); SpiceMsgDisplayStreamClip *op = spice_msg_in_parsed(in); display_stream *st = c->display.streams[op->id]; @@ -348,41 +369,40 @@ static void display_handle_stream_clip(SpiceChannel *channel, spice_msg_in *in) st->msg_clip = in; st->clip = &op->clip; fprintf(stderr, "%s: TODO (id %d)\n", __FUNCTION__, op->id); -#endif } static void destroy_stream(SpiceChannel *channel, int id) { -#if 0 spice_channel *c = SPICE_CHANNEL_GET_PRIVATE(channel); display_stream *st = c->display.streams[id]; if (!st) return; + switch (st->codec) { + case SPICE_VIDEO_CODEC_TYPE_MJPEG: + stream_mjpeg_cleanup(st); + break; + } + if (st->msg_clip) - spice_msg_in_put(st->msg_create); + spice_msg_in_put(st->msg_clip); spice_msg_in_put(st->msg_create); free(st); c->display.streams[id] = NULL; -#endif } static void display_handle_stream_destroy(SpiceChannel *channel, spice_msg_in *in) { -#if 0 SpiceMsgDisplayStreamDestroy *op = spice_msg_in_parsed(in); fprintf(stderr, "%s: id %d\n", __FUNCTION__, op->id); destroy_stream(channel, op->id); -#endif } static void display_handle_stream_destroy_all(SpiceChannel *channel, spice_msg_in *in) { -#if 0 fprintf(stderr, "%s: TODO\n", __FUNCTION__); -#endif } /* ------------------------------------------------------------------ */ diff --git a/gtk/spice-channel-priv.h b/gtk/spice-channel-priv.h index c5de9ee..81bb9e7 100644 --- a/gtk/spice-channel-priv.h +++ b/gtk/spice-channel-priv.h @@ -2,6 +2,7 @@ #define __SPICE_CLIENT_CHANNEL_PRIV_H__ #include <pixman.h> +#include <jpeglib.h> #include <openssl/ssl.h> @@ -82,7 +83,19 @@ typedef struct display_cursor { typedef struct display_stream { spice_msg_in *msg_create; spice_msg_in *msg_clip; + spice_msg_in *msg_data; + + /* from messages */ + display_surface *surface; SpiceClip *clip; + int codec; + + /* mjpeg decoder */ + struct jpeg_source_mgr mjpeg_src; + struct jpeg_decompress_struct mjpeg_cinfo; + struct jpeg_error_mgr mjpeg_jerr; + + uint8_t *out_frame; } display_stream; typedef struct display_cache_item { @@ -188,6 +201,11 @@ enum { extern guint channel_signals[SPICE_CHANNEL_LAST_SIGNAL]; +/* channel-display-mjpeg.c */ +void stream_mjpeg_init(display_stream *st); +void stream_mjpeg_data(display_stream *st); +void stream_mjpeg_cleanup(display_stream *st); + /* channel-*.c */ void base_handle_set_ack(SpiceChannel *channel, spice_msg_in *in); void base_handle_ping(SpiceChannel *channel, spice_msg_in *in); |