summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGerd Hoffmann <kraxel@redhat.com>2010-09-22 19:35:04 +0200
committerGerd Hoffmann <kraxel@redhat.com>2010-09-22 19:35:04 +0200
commitf4a31d41cd3e333a69dc6a459143ff49b8d544cd (patch)
tree5fe62c6cfc541f0d92ee29f85d1ed28898ef05f2
parentefc287891d76c5436583fb0d18e2b0e85ae2d7e8 (diff)
mjpeg decoder.
-rw-r--r--gtk/Makefile.am1
-rw-r--r--gtk/channel-display-mjpeg.c100
-rw-r--r--gtk/channel-display.c54
-rw-r--r--gtk/spice-channel-priv.h18
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);