summaryrefslogtreecommitdiffstats
path: root/gst
diff options
context:
space:
mode:
authorDavid Schleef <ds@schleef.org>2005-02-11 22:01:19 +0000
committerDavid Schleef <ds@schleef.org>2005-02-11 22:01:19 +0000
commita970a323047d9241a4ee96f4126c9739fc9780cf (patch)
tree0cc2c90fba41e659ddfa701c08f9bc0b95545427 /gst
parent909da9fb0489c3744547e6386531461c072da5fc (diff)
downloadgst-plugins-bad-a970a323047d9241a4ee96f4126c9739fc9780cf.tar.gz
gst-plugins-bad-a970a323047d9241a4ee96f4126c9739fc9780cf.tar.bz2
gst-plugins-bad-a970a323047d9241a4ee96f4126c9739fc9780cf.zip
configure.ac: Pull in librfb from my CVS tree, because it is too small and annoying to be separate. Move rfbsrc plug...
Original commit message from CVS: * configure.ac: Pull in librfb from my CVS tree, because it is too small and annoying to be separate. Move rfbsrc plugin to gst/. * ext/Makefile.am: * ext/librfb/Makefile.am: * ext/librfb/gstrfbsrc.c: * gst/librfb/Makefile.am: * gst/librfb/gstrfbsrc.c: * gst/librfb/rfb.c: * gst/librfb/rfb.h: * gst/librfb/rfbbuffer.c: * gst/librfb/rfbbuffer.h: * gst/librfb/rfbbytestream.c: * gst/librfb/rfbbytestream.h: * gst/librfb/rfbcontext.h: * gst/librfb/rfbdecoder.c: * gst/librfb/rfbdecoder.h: * gst/librfb/rfbutil.h:
Diffstat (limited to 'gst')
-rw-r--r--gst/librfb/Makefile.am30
-rw-r--r--gst/librfb/gstrfbsrc.c554
-rw-r--r--gst/librfb/rfb.c31
-rw-r--r--gst/librfb/rfb.h10
-rw-r--r--gst/librfb/rfbbuffer.c27
-rw-r--r--gst/librfb/rfbbuffer.h26
-rw-r--r--gst/librfb/rfbbytestream.c122
-rw-r--r--gst/librfb/rfbbytestream.h33
-rw-r--r--gst/librfb/rfbcontext.h41
-rw-r--r--gst/librfb/rfbdecoder.c397
-rw-r--r--gst/librfb/rfbdecoder.h87
-rw-r--r--gst/librfb/rfbutil.h13
12 files changed, 1371 insertions, 0 deletions
diff --git a/gst/librfb/Makefile.am b/gst/librfb/Makefile.am
new file mode 100644
index 00000000..67505440
--- /dev/null
+++ b/gst/librfb/Makefile.am
@@ -0,0 +1,30 @@
+
+# please keep librfb easily extractable
+
+noinst_LTLIBRARIES = librfb.la
+plugin_LTLIBRARIES = libgstrfbsrc.la
+
+libgstrfbsrc_la_SOURCES = gstrfbsrc.c
+libgstrfbsrc_la_CFLAGS = $(GST_CFLAGS) -I/usr/local/include/librfb-0.1
+libgstrfbsrc_la_LIBADD = librfb.la
+libgstrfbsrc_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+
+
+noinst_HEADERS = \
+ rfb.h \
+ rfbdecoder.h \
+ rfbbuffer.h \
+ rfbbytestream.h
+
+librfb_la_SOURCES = \
+ rfb.h \
+ rfbdecoder.c \
+ rfbdecoder.h \
+ rfbbuffer.c \
+ rfbbuffer.h \
+ rfbbytestream.c \
+ rfbbytestream.h
+
+librfb_la_CFLAGS = $(RFB_CFLAGS)
+librfb_la_LIBADD = $(GLIB_LIBS)
+
diff --git a/gst/librfb/gstrfbsrc.c b/gst/librfb/gstrfbsrc.c
new file mode 100644
index 00000000..99e3144c
--- /dev/null
+++ b/gst/librfb/gstrfbsrc.c
@@ -0,0 +1,554 @@
+/* GStreamer
+ * Copyright (C) <2004> David A. Schleef <ds@schleef.org>
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst.h>
+#include <gst/video/video.h>
+
+#include <string.h>
+#include <stdlib.h>
+
+#include <librfb/rfb.h>
+
+
+#define GST_TYPE_RFBSRC \
+ (gst_rfbsrc_get_type())
+#define GST_RFBSRC(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RFBSRC,GstRfbsrc))
+#define GST_RFBSRC_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RFBSRC,GstRfbsrc))
+#define GST_IS_RFBSRC(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RFBSRC))
+#define GST_IS_RFBSRC_CLASS(obj) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RFBSRC))
+
+typedef struct _GstRfbsrc GstRfbsrc;
+typedef struct _GstRfbsrcClass GstRfbsrcClass;
+
+struct _GstRfbsrc
+{
+ GstElement element;
+
+ GstPad *srcpad;
+
+ RfbDecoder *decoder;
+
+ char *server;
+ int port;
+
+ guint8 *frame;
+ gboolean go;
+ gboolean inter;
+
+ unsigned int button_mask;
+
+ double framerate;
+};
+
+struct _GstRfbsrcClass
+{
+ GstElementClass parent_class;
+};
+
+GType
+gst_rfbsrc_get_type (void)
+ G_GNUC_CONST;
+
+
+
+ static GstElementDetails rfbsrc_details =
+ GST_ELEMENT_DETAILS ("Video test source",
+ "Source/Video",
+ "Creates a test video stream",
+ "David A. Schleef <ds@schleef.org>");
+
+/* GstRfbsrc signals and args */
+ enum
+ {
+ /* FILL ME */
+ LAST_SIGNAL
+ };
+
+ enum
+ {
+ ARG_0,
+ ARG_SERVER,
+ ARG_PORT,
+ /* FILL ME */
+ };
+
+ static void gst_rfbsrc_base_init (gpointer g_class);
+ static void gst_rfbsrc_class_init (GstRfbsrcClass * klass);
+ static void gst_rfbsrc_init (GstRfbsrc * rfbsrc);
+ static GstElementStateReturn gst_rfbsrc_change_state (GstElement *
+ element);
+
+ static void gst_rfbsrc_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec);
+ static void gst_rfbsrc_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
+
+ static GstData *gst_rfbsrc_get (GstPad * pad);
+
+ static const GstQueryType *gst_rfbsrc_get_query_types (GstPad * pad);
+ static gboolean gst_rfbsrc_src_query (GstPad * pad,
+ GstQueryType type, GstFormat * format, gint64 * value);
+ static void gst_rfbsrc_paint_rect (RfbDecoder * decoder, int x, int y,
+ int w, int h, guint8 * data);
+ static gboolean gst_rfbsrc_handle_src_event (GstPad * pad,
+ GstEvent * event);
+
+ static GstCaps *gst_rfbsrc_getcaps (GstPad * pad);
+ static GstPadLinkReturn gst_rfbsrc_link (GstPad * pad,
+ const GstCaps * caps);
+ static GstCaps *gst_rfbsrc_fixate (GstPad * pad, const GstCaps * caps);
+
+ static GstElementClass *parent_class = NULL;
+
+
+ static GstStaticPadTemplate gst_rfbsrc_src_template =
+ GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS ("video/x-raw-rgb, "
+ "bpp = (int) 32, "
+ "depth = (int) 24, "
+ "endianness = (int) BIG_ENDIAN, "
+ "red_mask = (int) 0x0000ff00, "
+ "green_mask = (int) 0x00ff0000, "
+ "blue_mask = (int) 0xff000000, "
+ "width = [ 16, 4096 ], "
+ "height = [ 16, 4096 ], " "framerate = [ 1.0, 60.0] ")
+ );
+
+GType
+gst_rfbsrc_get_type (void)
+{
+ static GType rfbsrc_type = 0;
+
+ if (!rfbsrc_type) {
+ static const GTypeInfo rfbsrc_info = {
+ sizeof (GstRfbsrcClass),
+ gst_rfbsrc_base_init,
+ NULL,
+ (GClassInitFunc) gst_rfbsrc_class_init,
+ NULL,
+ NULL,
+ sizeof (GstRfbsrc),
+ 0,
+ (GInstanceInitFunc) gst_rfbsrc_init,
+ };
+
+ rfbsrc_type =
+ g_type_register_static (GST_TYPE_ELEMENT, "GstRfbsrc", &rfbsrc_info, 0);
+ }
+ return rfbsrc_type;
+}
+
+static void
+gst_rfbsrc_base_init (gpointer g_class)
+{
+ GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
+
+ gst_element_class_set_details (element_class, &rfbsrc_details);
+
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&gst_rfbsrc_src_template));
+}
+
+static void
+gst_rfbsrc_class_init (GstRfbsrcClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+
+ gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
+
+#if 0
+ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_WIDTH,
+ g_param_spec_int ("width", "width", "Default width",
+ 1, G_MAXINT, 320, G_PARAM_READWRITE));
+#endif
+
+ parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
+
+ g_object_class_install_property (gobject_class, ARG_SERVER,
+ g_param_spec_string ("server", "Server", "Server",
+ "127.0.0.1", G_PARAM_READWRITE));
+ g_object_class_install_property (gobject_class, ARG_PORT,
+ g_param_spec_int ("port", "Port", "Port",
+ 1, 65535, 5900, G_PARAM_READWRITE));
+
+ gobject_class->set_property = gst_rfbsrc_set_property;
+ gobject_class->get_property = gst_rfbsrc_get_property;
+
+ gstelement_class->change_state = gst_rfbsrc_change_state;
+}
+
+static GstElementStateReturn
+gst_rfbsrc_change_state (GstElement * element)
+{
+ GstRfbsrc *rfbsrc;
+
+ rfbsrc = GST_RFBSRC (element);
+
+ switch (GST_STATE_TRANSITION (element)) {
+ case GST_STATE_NULL_TO_READY:
+ rfbsrc->decoder = rfb_decoder_new ();
+ rfb_decoder_connect_tcp (rfbsrc->decoder, rfbsrc->server, rfbsrc->port);
+ rfbsrc->decoder->paint_rect = gst_rfbsrc_paint_rect;
+ rfbsrc->decoder->decoder_private = rfbsrc;
+ break;
+ case GST_STATE_READY_TO_PAUSED:
+ break;
+ case GST_STATE_PAUSED_TO_PLAYING:
+ break;
+ case GST_STATE_PLAYING_TO_PAUSED:
+ break;
+ case GST_STATE_PAUSED_TO_READY:
+ //rfbsrc->timestamp_offset = 0;
+ //rfbsrc->n_frames = 0;
+ break;
+ case GST_STATE_READY_TO_NULL:
+ if (rfbsrc->frame) {
+ g_free (rfbsrc->frame);
+ rfbsrc->frame = NULL;
+ }
+ break;
+ }
+
+ return parent_class->change_state (element);
+}
+
+static void
+gst_rfbsrc_init (GstRfbsrc * rfbsrc)
+{
+ GST_DEBUG ("gst_rfbsrc_init");
+
+ rfbsrc->srcpad =
+ gst_pad_new_from_template (gst_static_pad_template_get
+ (&gst_rfbsrc_src_template), "src");
+ gst_element_add_pad (GST_ELEMENT (rfbsrc), rfbsrc->srcpad);
+ gst_pad_set_getcaps_function (rfbsrc->srcpad, gst_rfbsrc_getcaps);
+ gst_pad_set_link_function (rfbsrc->srcpad, gst_rfbsrc_link);
+ gst_pad_set_fixate_function (rfbsrc->srcpad, gst_rfbsrc_fixate);
+ gst_pad_set_get_function (rfbsrc->srcpad, gst_rfbsrc_get);
+ gst_pad_set_query_function (rfbsrc->srcpad, gst_rfbsrc_src_query);
+ gst_pad_set_query_type_function (rfbsrc->srcpad, gst_rfbsrc_get_query_types);
+ gst_pad_set_event_function (rfbsrc->srcpad, gst_rfbsrc_handle_src_event);
+
+ rfbsrc->server = g_strdup ("127.0.0.1");
+ rfbsrc->port = 5900;
+}
+
+static GstCaps *
+gst_rfbsrc_getcaps (GstPad * pad)
+{
+ GstRfbsrc *rfbsrc;
+ GstCaps *caps;
+
+ rfbsrc = GST_RFBSRC (gst_pad_get_parent (pad));
+
+ caps = gst_caps_copy (gst_pad_get_pad_template_caps (pad));
+
+ if (rfbsrc->decoder && rfbsrc->decoder->inited) {
+ gst_caps_set_simple (caps,
+ "width", G_TYPE_INT, rfbsrc->decoder->width,
+ "height", G_TYPE_INT, rfbsrc->decoder->height, NULL);
+ }
+
+ return caps;
+}
+
+static GstCaps *
+gst_rfbsrc_fixate (GstPad * pad, const GstCaps * caps)
+{
+ GstStructure *structure;
+ GstCaps *newcaps;
+
+ if (gst_caps_get_size (caps) > 1)
+ return NULL;
+
+ newcaps = gst_caps_copy (caps);
+ structure = gst_caps_get_structure (newcaps, 0);
+
+ if (gst_caps_structure_fixate_field_nearest_double (structure, "framerate",
+ 30.0)) {
+ return newcaps;
+ }
+
+ gst_caps_free (newcaps);
+ return NULL;
+}
+
+static GstPadLinkReturn
+gst_rfbsrc_link (GstPad * pad, const GstCaps * caps)
+{
+ GstRfbsrc *rfbsrc;
+ GstStructure *structure;
+
+ rfbsrc = GST_RFBSRC (gst_pad_get_parent (pad));
+
+ structure = gst_caps_get_structure (caps, 0);
+
+ gst_structure_get_double (structure, "framerate", &rfbsrc->framerate);
+
+ return GST_PAD_LINK_OK;
+}
+
+static const GstQueryType *
+gst_rfbsrc_get_query_types (GstPad * pad)
+{
+ static const GstQueryType query_types[] = {
+ GST_QUERY_POSITION,
+ 0,
+ };
+
+ return query_types;
+}
+
+static gboolean
+gst_rfbsrc_src_query (GstPad * pad,
+ GstQueryType type, GstFormat * format, gint64 * value)
+{
+ gboolean res = FALSE;
+
+ //GstRfbsrc *rfbsrc = GST_RFBSRC (gst_pad_get_parent (pad));
+
+ switch (type) {
+ case GST_QUERY_POSITION:
+ switch (*format) {
+ case GST_FORMAT_TIME:
+ //*value = rfbsrc->n_frames * GST_SECOND / (double) rfbsrc->rate;
+ res = TRUE;
+ break;
+ case GST_FORMAT_DEFAULT: /* frames */
+ //*value = rfbsrc->n_frames;
+ res = TRUE;
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return res;
+}
+
+static gboolean
+gst_rfbsrc_handle_src_event (GstPad * pad, GstEvent * event)
+{
+ GstRfbsrc *rfbsrc;
+ double x, y;
+ int button;
+ GstStructure *structure;
+ const char *event_type;
+
+ rfbsrc = GST_RFBSRC (gst_pad_get_parent (pad));
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_NAVIGATION:
+ structure = event->event_data.structure.structure;
+ event_type = gst_structure_get_string (structure, "event");
+ gst_structure_get_double (structure, "pointer_x", &x);
+ gst_structure_get_double (structure, "pointer_y", &y);
+ button = 0;
+
+ if (strcmp (event_type, "key-press") == 0) {
+ const char *key = gst_structure_get_string (structure, "key");
+
+ rfb_decoder_send_key_event (rfbsrc->decoder, key[0], 1);
+ rfb_decoder_send_key_event (rfbsrc->decoder, key[0], 0);
+ } else if (strcmp (event_type, "mouse-move") == 0) {
+ rfb_decoder_send_pointer_event (rfbsrc->decoder, rfbsrc->button_mask,
+ (int) x, (int) y);
+ } else if (strcmp (event_type, "mouse-button-release") == 0) {
+ rfbsrc->button_mask &= ~(1 << button);
+ rfb_decoder_send_pointer_event (rfbsrc->decoder, rfbsrc->button_mask,
+ (int) x, (int) y);
+ } else if (strcmp (event_type, "mouse-button-press") == 0) {
+ rfbsrc->button_mask |= (1 << button);
+ rfb_decoder_send_pointer_event (rfbsrc->decoder, rfbsrc->button_mask,
+ (int) x, (int) y);
+ }
+ break;
+ default:
+ break;
+ }
+
+ return TRUE;
+}
+
+static void
+gst_rfbsrc_paint_rect (RfbDecoder * decoder, int x, int y, int w, int h,
+ guint8 * data)
+{
+ int i, j;
+ guint8 *frame;
+ guint8 color;
+ GstRfbsrc *rfbsrc;
+ int width;
+ int offset;
+
+ GST_DEBUG ("painting %d,%d (%dx%d)\n", x, y, w, h);
+ rfbsrc = GST_RFBSRC (decoder->decoder_private);
+
+ frame = rfbsrc->frame;
+ width = decoder->width;
+ for (j = 0; j < h; j++) {
+ for (i = 0; i < w; i++) {
+ color = data[j * w + i];
+
+#define RGB332_R(x) ((((x)&0x07) * 0x124)>>3)
+#define RGB332_G(x) ((((x)&0x38) * 0x124)>>6)
+#define RGB332_B(x) ((((x)&0xc0) * 0x149)>>8)
+ offset = ((j + x) * width + (i + x)) * 4;
+ frame[offset + 0] = RGB332_B (color);
+ frame[offset + 1] = RGB332_G (color);
+ frame[offset + 2] = RGB332_R (color);
+ frame[offset + 3] = 0;
+ }
+ }
+
+ rfbsrc->go = FALSE;
+}
+
+static GstData *
+gst_rfbsrc_get (GstPad * pad)
+{
+ GstRfbsrc *rfbsrc;
+ gulong newsize;
+ GstBuffer *buf;
+ RfbDecoder *decoder;
+
+ GST_DEBUG ("gst_rfbsrc_get");
+
+ g_return_val_if_fail (pad != NULL, NULL);
+ g_return_val_if_fail (GST_IS_PAD (pad), NULL);
+
+ rfbsrc = GST_RFBSRC (gst_pad_get_parent (pad));
+ decoder = rfbsrc->decoder;
+
+ if (!decoder->inited) {
+ while (!decoder->inited) {
+ rfb_decoder_iterate (decoder);
+ }
+
+ gst_pad_renegotiate (rfbsrc->srcpad);
+
+ if (rfbsrc->frame)
+ g_free (rfbsrc->frame);
+ rfbsrc->frame = g_malloc (decoder->width * decoder->height * 4);
+
+ GST_DEBUG ("red_mask = %08x\n", decoder->red_max << decoder->red_shift);
+ GST_DEBUG ("green_mask = %08x\n",
+ decoder->green_max << decoder->green_shift);
+ GST_DEBUG ("blue_mask = %08x\n", decoder->blue_max << decoder->blue_shift);
+ rfbsrc->inter = FALSE;
+ }
+
+ rfb_decoder_send_update_request (decoder, rfbsrc->inter, 0, 0, decoder->width,
+ decoder->height);
+ //rfbsrc->inter = TRUE;
+
+ rfbsrc->go = TRUE;
+ while (rfbsrc->go) {
+ rfb_decoder_iterate (decoder);
+ GST_DEBUG ("iterate...\n");
+ }
+
+ newsize = decoder->width * decoder->height * 4;
+ g_return_val_if_fail (newsize > 0, NULL);
+
+ GST_DEBUG ("size=%ld %dx%d", newsize, decoder->width, decoder->height);
+
+ buf = gst_buffer_new_and_alloc (newsize);
+ g_return_val_if_fail (GST_BUFFER_DATA (buf) != NULL, NULL);
+
+ memcpy (GST_BUFFER_DATA (buf), rfbsrc->frame, newsize);
+
+ return GST_DATA (buf);
+}
+
+static void
+gst_rfbsrc_set_property (GObject * object, guint prop_id, const GValue * value,
+ GParamSpec * pspec)
+{
+ GstRfbsrc *src;
+
+ /* it's not null if we got it, but it might not be ours */
+ g_return_if_fail (GST_IS_RFBSRC (object));
+ src = GST_RFBSRC (object);
+
+ GST_DEBUG ("gst_rfbsrc_set_property");
+ switch (prop_id) {
+ case ARG_SERVER:
+ src->server = g_strdup (g_value_get_string (value));
+ break;
+ case ARG_PORT:
+ src->port = g_value_get_int (value);
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+gst_rfbsrc_get_property (GObject * object, guint prop_id, GValue * value,
+ GParamSpec * pspec)
+{
+ GstRfbsrc *src;
+
+ /* it's not null if we got it, but it might not be ours */
+ g_return_if_fail (GST_IS_RFBSRC (object));
+ src = GST_RFBSRC (object);
+
+ switch (prop_id) {
+ case ARG_SERVER:
+ g_value_set_string (value, src->server);
+ break;
+ case ARG_PORT:
+ g_value_set_int (value, src->port);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+ return gst_element_register (plugin, "rfbsrc", GST_RANK_NONE,
+ GST_TYPE_RFBSRC);
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+ GST_VERSION_MINOR,
+ "rfbsrc",
+ "Connects to a VNC server and decodes RFB stream",
+ plugin_init, VERSION, GST_LICENSE, GST_PACKAGE, GST_ORIGIN)
diff --git a/gst/librfb/rfb.c b/gst/librfb/rfb.c
new file mode 100644
index 00000000..ceed1856
--- /dev/null
+++ b/gst/librfb/rfb.c
@@ -0,0 +1,31 @@
+
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "rfb.h"
+
+
+int
+main (int argc, char *argv[])
+{
+ RfbDecoder *decoder;
+
+ //int fd = 0;
+
+ decoder = rfb_decoder_new ();
+
+ rfb_decoder_connect_tcp (decoder, "127.0.0.1", 5901);
+ //rfb_decoder_use_file_descriptor (decoder, fd);
+
+ while (!decoder->inited)
+ rfb_decoder_iterate (decoder);
+
+ rfb_decoder_send_update_request (decoder, FALSE, 0, 0, 100, 100);
+
+ while (1) {
+ rfb_decoder_iterate (decoder);
+ }
+
+ return 0;
+}
diff --git a/gst/librfb/rfb.h b/gst/librfb/rfb.h
new file mode 100644
index 00000000..27543140
--- /dev/null
+++ b/gst/librfb/rfb.h
@@ -0,0 +1,10 @@
+
+#ifndef _RFB_RFB_H_
+#define _RFB_RFB_H_
+
+#include <librfb/rfbdecoder.h>
+#include <librfb/rfbbytestream.h>
+#include <librfb/rfbbuffer.h>
+
+#endif
+
diff --git a/gst/librfb/rfbbuffer.c b/gst/librfb/rfbbuffer.c
new file mode 100644
index 00000000..e38def36
--- /dev/null
+++ b/gst/librfb/rfbbuffer.c
@@ -0,0 +1,27 @@
+
+#include <rfbbuffer.h>
+
+RfbBuffer *
+rfb_buffer_new (void)
+{
+ return g_new0 (RfbBuffer, 1);
+
+}
+
+RfbBuffer *
+rfb_buffer_new_and_alloc (int len)
+{
+ RfbBuffer *buffer = g_new0 (RfbBuffer, 1);
+
+ buffer->data = g_malloc (len);
+ buffer->free_data = (void *) g_free;
+
+ return buffer;
+}
+
+void
+rfb_buffer_free (RfbBuffer * buffer)
+{
+ buffer->free_data (buffer->data, buffer->buffer_private);
+
+}
diff --git a/gst/librfb/rfbbuffer.h b/gst/librfb/rfbbuffer.h
new file mode 100644
index 00000000..7c4d40b5
--- /dev/null
+++ b/gst/librfb/rfbbuffer.h
@@ -0,0 +1,26 @@
+
+#ifndef _LIBRFB_BUFFER_H_
+#define _LIBRFB_BUFFER_H_
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+typedef struct _RfbBuffer RfbBuffer;
+
+struct _RfbBuffer
+{
+ guint8 *data;
+ int length;
+
+ void (*free_data) (guint8 *data, gpointer priv);
+ gpointer buffer_private;
+};
+
+RfbBuffer *rfb_buffer_new (void);
+RfbBuffer *rfb_buffer_new_and_alloc (int len);
+void rfb_buffer_free (RfbBuffer *buffer);
+
+G_END_DECLS
+
+#endif
diff --git a/gst/librfb/rfbbytestream.c b/gst/librfb/rfbbytestream.c
new file mode 100644
index 00000000..bcdc1b08
--- /dev/null
+++ b/gst/librfb/rfbbytestream.c
@@ -0,0 +1,122 @@
+
+#include <rfbbytestream.h>
+#include <string.h>
+
+RfbBytestream *
+rfb_bytestream_new (void)
+{
+ return g_new0 (RfbBytestream, 1);
+}
+
+int
+rfb_bytestream_get (RfbBytestream * bs, int len)
+{
+ RfbBuffer *buffer;
+
+ buffer = bs->get_buffer (len, bs->user_data);
+
+ if (buffer) {
+ g_print ("got buffer (%d bytes)\n", buffer->length);
+ bs->buffer_list = g_list_append (bs->buffer_list, buffer);
+
+ bs->length += buffer->length;
+
+ return len;
+ }
+
+ return 0;
+}
+
+gboolean
+rfb_bytestream_check (RfbBytestream * bs, int len)
+{
+ while (bs->length < len) {
+ rfb_bytestream_get (bs, len - bs->length);
+ }
+ return TRUE;
+}
+
+static int
+rfb_bytestream_copy_nocheck (RfbBytestream * bs, RfbBuffer * buffer, int len)
+{
+ GList *item;
+ int offset;
+ int first_offset;
+ RfbBuffer *frombuf;
+ int n;
+
+ offset = 0;
+ first_offset = bs->offset;
+ for (item = bs->buffer_list; item; item = g_list_next (item)) {
+ frombuf = (RfbBuffer *) item->data;
+ n = MIN (len, frombuf->length - first_offset);
+ g_print ("copying %d bytes from %p\n", n, frombuf);
+ memcpy (buffer->data + offset, frombuf->data + first_offset, n);
+ first_offset = 0;
+ len -= n;
+ offset += n;
+ if (len == 0)
+ return len;
+ }
+
+ g_assert_not_reached ();
+ return 0;
+}
+
+int
+rfb_bytestream_read (RfbBytestream * bs, RfbBuffer ** buffer, int len)
+{
+ RfbBuffer *buf;
+
+ rfb_bytestream_check (bs, len);
+
+ buf = rfb_buffer_new_and_alloc (len);
+ rfb_bytestream_copy_nocheck (bs, buf, len);
+
+ rfb_bytestream_flush (bs, len);
+
+ *buffer = buf;
+ return len;
+}
+
+int
+rfb_bytestream_peek (RfbBytestream * bs, RfbBuffer ** buffer, int len)
+{
+ RfbBuffer *buf;
+
+ rfb_bytestream_check (bs, len);
+
+ buf = rfb_buffer_new_and_alloc (len);
+ rfb_bytestream_copy_nocheck (bs, buf, len);
+
+ *buffer = buf;
+ return len;
+}
+
+int
+rfb_bytestream_flush (RfbBytestream * bs, int len)
+{
+ GList *item;
+ RfbBuffer *buf;
+ int n;
+
+ while ((item = bs->buffer_list)) {
+ buf = (RfbBuffer *) item->data;
+
+ n = MIN (buf->length - bs->offset, len);
+ if (n <= len) {
+ bs->offset = 0;
+ bs->buffer_list = g_list_delete_link (bs->buffer_list, item);
+ rfb_buffer_free (buf);
+ } else {
+ bs->offset = bs->offset + len;
+ }
+ bs->length -= n;
+ len -= n;
+ if (len == 0)
+ return 0;
+ }
+
+ g_assert_not_reached ();
+ return 0;
+}
diff --git a/gst/librfb/rfbbytestream.h b/gst/librfb/rfbbytestream.h
new file mode 100644
index 00000000..8304169a
--- /dev/null
+++ b/gst/librfb/rfbbytestream.h
@@ -0,0 +1,33 @@
+
+#ifndef _LIBRFB_BYTESTREAM_H_
+#define _LIBRFB_BYTESTREAM_H_
+
+#include <glib.h>
+
+#include <librfb/rfbbuffer.h>
+
+G_BEGIN_DECLS
+
+typedef struct _RfbBytestream RfbBytestream;
+
+struct _RfbBytestream
+{
+ RfbBuffer * (*get_buffer) (int length, gpointer user_data);
+ gpointer user_data;
+
+ GList *buffer_list;
+ int length;
+ int offset;
+};
+
+
+RfbBytestream * rfb_bytestream_new (void);
+
+int rfb_bytestream_read (RfbBytestream *bs, RfbBuffer **buffer, int len);
+int rfb_bytestream_peek (RfbBytestream *bs, RfbBuffer **buffer, int len);
+int rfb_bytestream_flush (RfbBytestream *bs, int len);
+
+
+G_END_DECLS
+
+#endif
diff --git a/gst/librfb/rfbcontext.h b/gst/librfb/rfbcontext.h
new file mode 100644
index 00000000..df9ec1df
--- /dev/null
+++ b/gst/librfb/rfbcontext.h
@@ -0,0 +1,41 @@
+
+#ifndef _LIBRFB_RFBCONTEXT_H_
+#define _LIBRFB_RFBCONTEXT_H_
+
+G_BEGIN_DECLS
+
+#include <glib.h>
+
+typedef struct _RfbContext
+{
+ RfbConnection *connection;
+
+ guint8 *buffer1;
+ void *buffer1_alloc;
+ unsigned int buffer1_len;
+
+ guint8 *buffer2;
+ void *buffer2_alloc;
+ unsigned int buffer2_len;
+
+ char *name;
+} RfbContext;
+
+typedef struct _RfbRect
+{
+ RfbContext *context;
+
+ unsigned int x_pos;
+ unsigned int y_pos;
+ unsigned int width;
+ unsigned int height;
+ unsigned int encoding_type;
+
+ char *data;
+} RfbRect;
+
+
+
+G_END_DECLS
+
+#endif
diff --git a/gst/librfb/rfbdecoder.c b/gst/librfb/rfbdecoder.c
new file mode 100644
index 00000000..e8de9b06
--- /dev/null
+++ b/gst/librfb/rfbdecoder.c
@@ -0,0 +1,397 @@
+
+#include <rfb.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <errno.h>
+
+
+#if 0
+struct _RfbSocketPrivate
+{
+ int fd;
+ sockaddr sa;
+}
+#endif
+
+
+static RfbBuffer *
+rfb_socket_get_buffer (int length, gpointer user_data)
+{
+ RfbBuffer *buffer;
+ int fd = (int) user_data;
+ int ret;
+
+ buffer = rfb_buffer_new ();
+
+ buffer->data = g_malloc (length);
+ buffer->free_data = (void *) g_free;
+
+ g_print ("calling read(%d, %p, %d)\n", fd, buffer->data, length);
+ ret = read (fd, buffer->data, length);
+ if (ret <= 0) {
+ g_critical ("read: %s", strerror (errno));
+ rfb_buffer_free (buffer);
+ return NULL;
+ }
+
+ buffer->length = ret;
+
+ return buffer;
+}
+
+static int
+rfb_socket_send_buffer (guint8 * buffer, int length, gpointer user_data)
+{
+ int fd = (int) user_data;
+ int ret;
+
+ g_print ("calling write(%d, %p, %d)\n", fd, buffer, length);
+ ret = write (fd, buffer, length);
+ if (ret < 0) {
+ g_critical ("write: %s", strerror (errno));
+ return 0;
+ }
+
+ g_assert (ret == length);
+
+ return ret;
+}
+
+
+RfbDecoder *
+rfb_decoder_new (void)
+{
+ RfbDecoder *decoder = g_new0 (RfbDecoder, 1);
+
+ decoder->bytestream = rfb_bytestream_new ();
+
+ return decoder;
+}
+
+void
+rfb_decoder_use_file_descriptor (RfbDecoder * decoder, int fd)
+{
+ g_return_if_fail (decoder != NULL);
+ g_return_if_fail (!decoder->inited);
+ g_return_if_fail (fd >= 0);
+
+ decoder->bytestream->get_buffer = rfb_socket_get_buffer;
+ decoder->bytestream->user_data = (void *) fd;
+
+ decoder->send_data = rfb_socket_send_buffer;
+ decoder->buffer_handler_data = (void *) fd;
+}
+
+void
+rfb_decoder_connect_tcp (RfbDecoder * decoder, char *addr, unsigned int port)
+{
+ int fd;
+ struct sockaddr_in sa;
+
+ fd = socket (PF_INET, SOCK_STREAM, 0);
+
+ sa.sin_family = AF_INET;
+ sa.sin_port = htons (port);
+ inet_pton (AF_INET, addr, &sa.sin_addr);
+ connect (fd, (struct sockaddr *) &sa, sizeof (struct sockaddr));
+
+ rfb_decoder_use_file_descriptor (decoder, fd);
+}
+
+
+static gboolean rfb_decoder_state_wait_for_protocol_version (RfbDecoder *
+ decoder);
+static gboolean rfb_decoder_state_wait_for_security (RfbDecoder * decoder);
+static gboolean rfb_decoder_state_send_client_initialisation (RfbDecoder *
+ decoder);
+static gboolean rfb_decoder_state_wait_for_server_initialisation (RfbDecoder *
+ decoder);
+static gboolean rfb_decoder_state_normal (RfbDecoder * decoder);
+static gboolean rfb_decoder_state_framebuffer_update (RfbDecoder * decoder);
+static gboolean rfb_decoder_state_framebuffer_update_rectangle (RfbDecoder *
+ decoder);
+static gboolean rfb_decoder_state_set_colour_map_entries (RfbDecoder * decoder);
+static gboolean rfb_decoder_state_server_cut_text (RfbDecoder * decoder);
+
+gboolean
+rfb_decoder_iterate (RfbDecoder * decoder)
+{
+ g_return_val_if_fail (decoder != NULL, FALSE);
+
+ if (decoder->state == NULL) {
+ decoder->state = rfb_decoder_state_wait_for_protocol_version;
+ }
+
+ g_print ("iterating...\n");
+
+ return decoder->state (decoder);
+}
+
+#define RFB_GET_UINT32(ptr) GUINT32_FROM_BE (*(guint32 *)(ptr))
+#define RFB_GET_UINT16(ptr) GUINT16_FROM_BE (*(guint16 *)(ptr))
+#define RFB_GET_UINT8(ptr) (*(guint8 *)(ptr))
+
+#define RFB_SET_UINT32(ptr, val) (*(guint32 *)(ptr) = GUINT32_TO_BE (val))
+#define RFB_SET_UINT16(ptr, val) (*(guint16 *)(ptr) = GUINT16_TO_BE (val))
+#define RFB_SET_UINT8(ptr, val) (*(guint8 *)(ptr) = val)
+
+static gboolean
+rfb_decoder_state_wait_for_protocol_version (RfbDecoder * decoder)
+{
+ RfbBuffer *buffer;
+ guint8 *data;
+ int ret;
+
+ ret = rfb_bytestream_read (decoder->bytestream, &buffer, 12);
+ if (ret < 12)
+ return FALSE;
+
+ data = buffer->data;
+
+ g_assert (memcmp (buffer->data, "RFB 003.00", 10) == 0);
+ g_print ("\"%.11s\"\n", buffer->data);
+ rfb_buffer_free (buffer);
+
+ rfb_decoder_send (decoder, "RFB 003.003\n", 12);
+
+ decoder->state = rfb_decoder_state_wait_for_security;
+
+ return TRUE;
+}
+
+static gboolean
+rfb_decoder_state_wait_for_security (RfbDecoder * decoder)
+{
+ RfbBuffer *buffer;
+ int ret;
+
+ ret = rfb_bytestream_read (decoder->bytestream, &buffer, 4);
+ if (ret < 4)
+ return FALSE;
+
+ decoder->security_type = RFB_GET_UINT32 (buffer->data);
+ g_print ("security = %d\n", decoder->security_type);
+
+ rfb_buffer_free (buffer);
+
+ decoder->state = rfb_decoder_state_send_client_initialisation;
+ return TRUE;
+}
+
+static gboolean
+rfb_decoder_state_send_client_initialisation (RfbDecoder * decoder)
+{
+ guint8 shared_flag;
+
+ shared_flag = decoder->shared_flag;
+ rfb_decoder_send (decoder, &shared_flag, 1);
+
+ decoder->state = rfb_decoder_state_wait_for_server_initialisation;
+ return TRUE;
+}
+
+static gboolean
+rfb_decoder_state_wait_for_server_initialisation (RfbDecoder * decoder)
+{
+ RfbBuffer *buffer;
+ guint8 *data;
+ int ret;
+ guint32 name_length;
+
+ ret = rfb_bytestream_peek (decoder->bytestream, &buffer, 24);
+ if (ret < 24)
+ return FALSE;
+
+ data = buffer->data;
+
+ decoder->width = RFB_GET_UINT16 (data + 0);
+ decoder->height = RFB_GET_UINT16 (data + 2);
+ decoder->bpp = RFB_GET_UINT8 (data + 4);
+ decoder->depth = RFB_GET_UINT8 (data + 5);
+ decoder->big_endian = RFB_GET_UINT8 (data + 6);
+ decoder->true_colour = RFB_GET_UINT8 (data + 7);
+ decoder->red_max = RFB_GET_UINT16 (data + 8);
+ decoder->green_max = RFB_GET_UINT16 (data + 10);
+ decoder->blue_max = RFB_GET_UINT16 (data + 12);
+ decoder->red_shift = RFB_GET_UINT8 (data + 14);
+ decoder->green_shift = RFB_GET_UINT8 (data + 15);
+ decoder->blue_shift = RFB_GET_UINT8 (data + 16);
+
+ g_print ("width: %d\n", decoder->width);
+ g_print ("height: %d\n", decoder->height);
+
+ name_length = RFB_GET_UINT32 (data + 20);
+ rfb_buffer_free (buffer);
+
+ ret = rfb_bytestream_read (decoder->bytestream, &buffer, 24 + name_length);
+ if (ret < 24 + name_length)
+ return FALSE;
+
+ decoder->name = g_strndup ((char *) (buffer->data) + 24, name_length);
+ g_print ("name: %s\n", decoder->name);
+ rfb_buffer_free (buffer);
+
+ decoder->state = rfb_decoder_state_normal;
+ decoder->inited = TRUE;
+
+ return TRUE;
+}
+
+static gboolean
+rfb_decoder_state_normal (RfbDecoder * decoder)
+{
+ RfbBuffer *buffer;
+ int ret;
+ int message_type;
+
+ ret = rfb_bytestream_read (decoder->bytestream, &buffer, 1);
+ message_type = RFB_GET_UINT8 (buffer->data);
+
+ switch (message_type) {
+ case 0:
+ decoder->state = rfb_decoder_state_framebuffer_update;
+ break;
+ case 1:
+ decoder->state = rfb_decoder_state_set_colour_map_entries;
+ break;
+ case 2:
+ /* bell, ignored */
+ decoder->state = rfb_decoder_state_normal;
+ break;
+ case 3:
+ decoder->state = rfb_decoder_state_server_cut_text;
+ break;
+ default:
+ g_critical ("unknown message type %d", message_type);
+ }
+
+ rfb_buffer_free (buffer);
+
+ return TRUE;
+}
+
+static gboolean
+rfb_decoder_state_framebuffer_update (RfbDecoder * decoder)
+{
+ RfbBuffer *buffer;
+ int ret;
+
+ ret = rfb_bytestream_read (decoder->bytestream, &buffer, 3);
+
+ decoder->n_rects = RFB_GET_UINT16 (buffer->data + 1);
+ decoder->state = rfb_decoder_state_framebuffer_update_rectangle;
+
+ return TRUE;
+}
+
+static gboolean
+rfb_decoder_state_framebuffer_update_rectangle (RfbDecoder * decoder)
+{
+ RfbBuffer *buffer;
+ int ret;
+ int x, y, w, h;
+ int encoding;
+ int size;
+
+ ret = rfb_bytestream_peek (decoder->bytestream, &buffer, 12);
+ if (ret < 12)
+ return FALSE;
+
+ x = RFB_GET_UINT16 (buffer->data + 0);
+ y = RFB_GET_UINT16 (buffer->data + 2);
+ w = RFB_GET_UINT16 (buffer->data + 4);
+ h = RFB_GET_UINT16 (buffer->data + 6);
+ encoding = RFB_GET_UINT32 (buffer->data + 8);
+
+ if (encoding != 0)
+ g_critical ("unimplemented encoding\n");
+
+ rfb_buffer_free (buffer);
+
+ size = w * h;
+ ret = rfb_bytestream_read (decoder->bytestream, &buffer, size + 12);
+ if (ret < size)
+ return FALSE;
+
+ if (decoder->paint_rect) {
+ decoder->paint_rect (decoder, x, y, w, h, buffer->data + 12);
+ }
+
+ rfb_buffer_free (buffer);
+
+ decoder->n_rects--;
+ if (decoder->n_rects == 0) {
+ decoder->state = rfb_decoder_state_normal;
+ }
+ return TRUE;
+}
+
+static gboolean
+rfb_decoder_state_set_colour_map_entries (RfbDecoder * decoder)
+{
+ g_critical ("not implemented");
+
+ return FALSE;
+}
+
+static gboolean
+rfb_decoder_state_server_cut_text (RfbDecoder * decoder)
+{
+ g_critical ("not implemented");
+
+ return FALSE;
+}
+
+
+void
+rfb_decoder_send_update_request (RfbDecoder * decoder,
+ gboolean incremental, int x, int y, int width, int height)
+{
+ guint8 data[10];
+
+ data[0] = 3;
+ data[1] = incremental;
+ RFB_SET_UINT16 (data + 2, x);
+ RFB_SET_UINT16 (data + 4, y);
+ RFB_SET_UINT16 (data + 6, width);
+ RFB_SET_UINT16 (data + 8, height);
+
+ rfb_decoder_send (decoder, data, 10);
+}
+
+void
+rfb_decoder_send_key_event (RfbDecoder * decoder, unsigned int key,
+ gboolean down_flag)
+{
+ guint8 data[8];
+
+ data[0] = 4;
+ data[1] = down_flag;
+ RFB_SET_UINT16 (data + 2, 0);
+ RFB_SET_UINT32 (data + 4, key);
+
+ rfb_decoder_send (decoder, data, 8);
+}
+
+void
+rfb_decoder_send_pointer_event (RfbDecoder * decoder,
+ int button_mask, int x, int y)
+{
+ guint8 data[6];
+
+ data[0] = 5;
+ data[1] = button_mask;
+ RFB_SET_UINT16 (data + 2, x);
+ RFB_SET_UINT16 (data + 4, y);
+
+ rfb_decoder_send (decoder, data, 6);
+}
+
+int
+rfb_decoder_send (RfbDecoder * decoder, guint8 * buffer, int len)
+{
+ return decoder->send_data (buffer, len, decoder->buffer_handler_data);
+}
diff --git a/gst/librfb/rfbdecoder.h b/gst/librfb/rfbdecoder.h
new file mode 100644
index 00000000..db16cb2c
--- /dev/null
+++ b/gst/librfb/rfbdecoder.h
@@ -0,0 +1,87 @@
+
+#ifndef _LIBRFB_DECODER_H_
+#define _LIBRFB_DECODER_H_
+
+#include <glib.h>
+#include <librfb/rfbbytestream.h>
+
+G_BEGIN_DECLS
+
+typedef struct _RfbDecoder RfbDecoder;
+
+struct _RfbDecoder
+{
+ int (*send_data) (guint8 *buffer, int length, gpointer user_data);
+ gpointer buffer_handler_data;
+
+ RfbBytestream *bytestream;
+
+ gpointer decoder_private;
+
+ void (*paint_rect) (RfbDecoder *decoder, int x, int y, int w, int h,
+ guint8 *data);
+ void (*copy_rect) (RfbDecoder *decoder, int x, int y, int w, int h,
+ int src_x, int src_y);
+
+ /* settable properties */
+ gboolean shared_flag;
+
+ /* readable properties */
+ gboolean inited;
+
+ int protocol_major;
+ int protocol_minor;
+ unsigned int security_type;
+
+ unsigned int width;
+ unsigned int height;
+ unsigned int bpp;
+ unsigned int depth;
+ gboolean big_endian;
+ gboolean true_colour;
+ unsigned int red_max;
+ unsigned int green_max;
+ unsigned int blue_max;
+ unsigned int red_shift;
+ unsigned int green_shift;
+ unsigned int blue_shift;
+
+ char *name;
+
+ /* state information */
+ gboolean (*state) (RfbDecoder *decoder);
+ int n_rects;
+};
+
+#if 0
+typedef struct _RfbRect
+{
+ RfbConnection *connection;
+
+ unsigned int x_pos;
+ unsigned int y_pos;
+ unsigned int width;
+ unsigned int height;
+ unsigned int encoding_type;
+
+ char *data;
+} RfbRect;
+#endif
+
+
+RfbDecoder *rfb_decoder_new (void);
+void rfb_decoder_use_file_descriptor (RfbDecoder * decoder, int fd);
+void rfb_decoder_connect_tcp (RfbDecoder *decoder, char * addr, unsigned int port);
+void rfb_decoder_set_peer (RfbDecoder * decoder);
+gboolean rfb_decoder_iterate (RfbDecoder * decoder);
+int rfb_decoder_send (RfbDecoder * decoder, guint8 *data, int len);
+void rfb_decoder_send_update_request (RfbDecoder * decoder,
+ gboolean incremental, int x, int y, int width, int height);
+void rfb_decoder_send_key_event (RfbDecoder * decoder, unsigned int key,
+ gboolean down_flag);
+void rfb_decoder_send_pointer_event (RfbDecoder * decoder,
+ int button_mask, int x, int y);
+
+G_END_DECLS
+
+#endif
diff --git a/gst/librfb/rfbutil.h b/gst/librfb/rfbutil.h
new file mode 100644
index 00000000..2b9b95d5
--- /dev/null
+++ b/gst/librfb/rfbutil.h
@@ -0,0 +1,13 @@
+
+#ifndef _LIBRFB_UTIL_H_
+#define _LIBRFB_UTIL_H_
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+
+
+G_END_DECLS
+
+#endif