diff --git a/elements/CMakeLists.txt b/elements/CMakeLists.txt
index 7bdde6c..79dbdfd 100644
--- a/elements/CMakeLists.txt
+++ b/elements/CMakeLists.txt
@@ -16,4 +16,10 @@ if (GSTREAMER_BASE_LIBRARY_FOUND AND GSTREAMER_VIDEO_LIBRARY_FOUND)
                                               ${GOBJECT_LIBRARIES} ${GSTREAMER_LIBRARY}
                                               ${GSTREAMER_BASE_LIBRARY} ${GSTREAMER_VIDEO_LIBRARY})
     install(TARGETS gstqwidgetvideosink DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/gstreamer-0.10)
+
+    automoc4_add_library(gstqimagevideosink MODULE gstqimagevideosink.cpp)
+    target_link_libraries(gstqimagevideosink ${QT_QTCORE_LIBRARY} ${QT_QTGUI_LIBRARY}
+                                              ${GOBJECT_LIBRARIES} ${GSTREAMER_LIBRARY}
+                                              ${GSTREAMER_BASE_LIBRARY} ${GSTREAMER_VIDEO_LIBRARY})
+    install(TARGETS gstqimagevideosink DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/gstreamer-0.10)
 endif()
diff --git a/elements/gstqimagevideosink.cpp b/elements/gstqimagevideosink.cpp
new file mode 100644
index 0000000..64f31fa
--- /dev/null
+++ b/elements/gstqimagevideosink.cpp
@@ -0,0 +1,672 @@
+/*
+    Copyright (C) 2010 George Kiagiadakis <kiagiadakis.george@gmail.com>
+
+    This library is free software; you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published
+    by the Free Software Foundation; either version 2.1 of the License, or
+    (at your option) any later version.
+
+    This program 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 General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * SECTION:element-qimagevideosink
+ *
+ * qimagevideosink is a video sink element that can draw directly on a QObject
+ * using the QPainter API. To use it, you only have to set a QObject pointer as
+ * the "widget" property and the video will then be rendered on that QObject.
+ *
+ * This is useful for cases where you cannot or you do not want to use one of the
+ * sinks that implement the GstXOverlay interface, for example for rendering video
+ * inside a QGraphicsView or for rendering video on the QWS (Qt/Embedded) platform.
+ * This sink is guaranteed to work on all platforms supported by Qt, however it
+ * is not recommended to use it if you have another choice. For example, on X11 it
+ * is recommended to use "xvimagesink" instead, which uses hardware acceleration.
+ *
+ * There are certain rules for using qimagevideosink with threads. It must be
+ * created in the main thread, it must be destructed in the main thread and the
+ * "widget" property may only be read or written from the main thread as well.
+ * This is a (reasonable) limitation implied by Qt.
+ */
+
+#include <gst/gst.h>
+#include <gst/video/gstvideosink.h>
+#include <gst/video/video.h>
+#include <QtCore/QCoreApplication>
+#include <QtCore/QWeakPointer>
+#include <QtCore/QEvent>
+#include <QtCore/QMutex>
+#include <QtCore/QDebug>
+#include <QtGui/QResizeEvent>
+#include <QtGui/QPainter>
+
+//BEGIN ******** declarations ********
+
+enum {
+    BufferEventType = QEvent::User,
+    DeactivateEventType
+};
+
+class BufferEvent : public QEvent
+{
+public:
+    inline BufferEvent(GstBuffer *buf)
+        : QEvent(static_cast<QEvent::Type>(BufferEventType)),
+          buffer(gst_buffer_ref(buf))
+    {
+    }
+
+    GstBuffer *buffer;
+};
+
+class DeactivateEvent : public QEvent
+{
+public:
+    inline DeactivateEvent()
+        : QEvent(static_cast<QEvent::Type>(DeactivateEventType))
+    {
+    }
+};
+
+class WidgetProxy : public QObject
+{
+    Q_OBJECT
+public:
+    WidgetProxy(GObject *sink);
+    virtual ~WidgetProxy();
+
+    // "widget" property
+    QObject *widget() const;
+    void setWidget(QObject *widget);
+
+    // "force-aspect-ratio" property
+    bool forceAspectRatio() const;
+    void setForceAspectRatio(bool force);
+
+    bool isActive() const;
+    void setActive(bool active);
+
+    QSize widgetSize() const;
+    void setWidgetSize(const QSize & size);
+
+    void scheduleRepaint();
+    
+    void setWidth(int w);
+    void setHeight(int h);
+    
+private Q_SLOTS:
+    void widgetDestroyed();
+    void imageRequested(QImage* image);
+
+protected:
+    virtual bool event(QEvent *event);
+    virtual bool eventFilter(QObject *filteredObject, QEvent *event);
+
+private:
+#ifndef GST_DISABLE_GST_DEBUG
+    //used for calling the Gst debug macros
+    GObject *m_sink;
+#endif
+
+    // "widget" property
+    QWeakPointer<QObject> m_widget;
+
+    // "force-aspect-ratio" property
+    bool m_forceAspectRatio : 1;
+
+    // whether the sink is active (PAUSED or PLAYING)
+    bool m_isActive : 1;
+    mutable QMutex m_isActiveMutex;
+
+    // the current widget size, used for caps negotiation
+    mutable QMutex m_widgetSizeMutex;
+    QSize m_widgetSize;
+
+    // the buffer to be drawn next
+    GstBuffer *m_buffer;
+};
+
+
+GST_DEBUG_CATEGORY_STATIC(gst_qimage_video_sink_debug);
+#define GST_CAT_DEFAULT gst_qimage_video_sink_debug
+
+static const char *qimagevideosink_description = "A video sink that passes an image to a QObject";
+
+#define GST_TYPE_QIMAGEVIDEOSINK \
+  (gst_qimage_video_sink_get_type())
+#define GST_QIMAGEVIDEOSINK(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_QIMAGEVIDEOSINK,GstQImageVideoSink))
+#define GST_QIMAGEVIDEOSINK_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_QIMAGEVIDEOSINK,GstQImageVideoSinkClass))
+
+typedef struct _GstQImageVideoSink      GstQImageVideoSink;
+typedef struct _GstQImageVideoSinkClass GstQImageVideoSinkClass;
+
+struct _GstQImageVideoSink
+{
+    GstVideoSink element;
+    WidgetProxy *proxy;
+};
+
+struct _GstQImageVideoSinkClass
+{
+    GstVideoSinkClass parent_class;
+};
+
+enum {
+    PROP_0,
+    PROP_WIDGET,
+    PROP_HEIGHT,
+    PROP_WIDTH,
+    PROP_FORCE_ASPECT_RATIO
+};
+
+static void
+gst_qimage_video_sink_finalize(GObject *object);
+
+static void
+gst_qimage_video_sink_set_property(GObject *object, guint prop_id,
+                                    const GValue *value, GParamSpec *pspec);
+
+static void
+gst_qimage_video_sink_get_property(GObject *object, guint prop_id,
+                                    GValue *value, GParamSpec *pspec);
+
+static GstStateChangeReturn
+gst_qimage_video_sink_change_state(GstElement *element, GstStateChange transition);
+
+static GstFlowReturn
+gst_qimage_video_sink_buffer_alloc(GstBaseSink *sink, guint64 offset,
+                                    guint size, GstCaps *caps, GstBuffer **buf);
+
+static GstFlowReturn
+gst_qimage_video_sink_show_frame(GstVideoSink *video_sink, GstBuffer *buf);
+
+//END ******** declarations ********
+//BEGIN ******** WidgetProxy ********
+
+WidgetProxy::WidgetProxy(GObject *sink)
+    : QObject(),
+#ifndef GST_DISABLE_GST_DEBUG
+    m_sink(sink),
+#endif
+    m_forceAspectRatio(false),
+    m_isActive(false),
+    m_buffer(NULL)
+{
+}
+
+WidgetProxy::~WidgetProxy()
+{
+    if (m_buffer) {
+        gst_buffer_unref(m_buffer);
+    }
+    setWidget(NULL);
+}
+
+QObject *WidgetProxy::widget() const
+{
+    return m_widget.data();
+}
+
+void WidgetProxy::setWidget(QObject *widget)
+{
+    GST_DEBUG_OBJECT(m_sink, "Setting \"widget\" property to %"GST_PTR_FORMAT, widget);
+
+    if (m_widget) {
+        m_widget.data()->removeEventFilter(this);
+        scheduleRepaint();
+        disconnect(m_widget.data(), SIGNAL(destroyed(QObject*)), this, SLOT(widgetDestroyed()));
+
+        m_widget = QWeakPointer<QObject>();
+    }
+
+    if (widget) {
+        widget->installEventFilter(this);
+        scheduleRepaint();
+        connect(widget, SIGNAL(destroyed(QObject*)), this, SLOT(widgetDestroyed()));
+        connect(widget, SIGNAL(imageRequest(QImage*)), this, SLOT(imageRequested(QImage*)));
+
+        m_widget = widget;
+    }
+}
+
+void WidgetProxy::widgetDestroyed()
+{
+    m_widget = QWeakPointer<QObject>();
+}
+
+void WidgetProxy::imageRequested(QImage* image)
+{
+    if (m_buffer && isActive()) {
+        GstCaps *caps = GST_BUFFER_CAPS(m_buffer);
+        GstStructure *structure = gst_caps_get_structure(caps, 0);
+
+        GstVideoRectangle srcRect;
+        srcRect.x = srcRect.y = 0;
+        gst_structure_get_int(structure, "width", &srcRect.w);
+        gst_structure_get_int(structure, "height", &srcRect.h);
+
+        QRect drawRect;
+        if (m_forceAspectRatio) {
+            GstVideoRectangle destRect;
+            destRect.x = destRect.y = 0;
+            destRect.w = widgetSize().width();
+            destRect.h = widgetSize().height();
+
+            GstVideoRectangle resultRect;
+            gst_video_sink_center_rect(srcRect, destRect, &resultRect, TRUE);
+            drawRect = QRect(resultRect.x, resultRect.y, resultRect.w, resultRect.h);
+        } else {
+            drawRect = QRect(QPoint(0,0), widgetSize());
+        }
+
+        GST_LOG_OBJECT(m_sink, "Rendering buffer %"GST_PTR_FORMAT". "
+                                "Frame size is (%d, %d), "
+                                "widget size is (%d, %d), "
+                                "calculated draw area is (%d, %d)",
+                                m_buffer,
+                                srcRect.w, srcRect.h,
+                                widgetSize().width(), widgetSize().height(),
+                                drawRect.width(), drawRect.height());
+
+        *image=QImage(m_buffer->data, srcRect.w, srcRect.h, QImage::Format_RGB32);
+    } else {
+        GST_LOG_OBJECT(m_sink, "Filling widget with black");
+        image->fill(Qt::black);
+    }
+}
+
+void WidgetProxy::scheduleRepaint()
+{
+    if(m_widget)
+        QCoreApplication::postEvent(m_widget.data(), new QEvent(QEvent::User));
+}
+
+bool WidgetProxy::forceAspectRatio() const
+{
+    return m_forceAspectRatio;
+}
+
+void WidgetProxy::setForceAspectRatio(bool force)
+{
+    GST_DEBUG_OBJECT(m_sink, "Setting \"force-aspect-ratio\" property to %s", force ? "true" : "false");
+
+    m_forceAspectRatio = force;
+}
+
+bool WidgetProxy::isActive() const
+{
+    QMutexLocker lock(&m_isActiveMutex);
+    return m_isActive;
+}
+
+void WidgetProxy::setActive(bool active)
+{
+    GST_INFO_OBJECT(m_sink, active ? "Activating" : "Deactivating");
+
+    QMutexLocker lock(&m_isActiveMutex);
+    m_isActive = active;
+    if (!active) {
+        QCoreApplication::postEvent(this, new DeactivateEvent());
+    }
+}
+
+QSize WidgetProxy::widgetSize() const
+{
+    QMutexLocker lock(&m_widgetSizeMutex);
+    return m_widgetSize;
+}
+
+void WidgetProxy::setHeight(int h)
+{
+    QSize s = widgetSize();
+    s.setHeight(h);
+    setWidgetSize(s);
+}
+
+void WidgetProxy::setWidth(int w)
+{
+    QSize s = widgetSize();
+    s.setWidth(w);
+    setWidgetSize(s);
+}
+
+void WidgetProxy::setWidgetSize(const QSize & size)
+{
+    GST_DEBUG_OBJECT(m_sink, "Widget size changed to (%d, %d)", size.width(), size.height());
+
+    QMutexLocker lock(&m_widgetSizeMutex);
+    m_widgetSize = size;
+}
+
+bool WidgetProxy::event(QEvent *event)
+{
+    switch(event->type()) {
+    case BufferEventType:
+    {
+        BufferEvent *bufEvent = dynamic_cast<BufferEvent*>(event);
+        Q_ASSERT(bufEvent);
+
+        GST_LOG_OBJECT(m_sink, "Received buffer %"GST_PTR_FORMAT, bufEvent->buffer);
+
+        if (m_buffer) {
+            //free the previous buffer
+            gst_buffer_unref(m_buffer);
+            m_buffer = NULL;
+        }
+
+        if (m_widget && isActive()) {
+            //schedule this frame for rendering
+            m_buffer = bufEvent->buffer;
+            scheduleRepaint();
+        } else {
+            //no widget, drop the frame
+            gst_buffer_unref(bufEvent->buffer);
+        }
+
+        return true;
+    }
+    case DeactivateEventType:
+    {
+        GST_LOG_OBJECT(m_sink, "Received deactivate event");
+
+        if (m_buffer) {
+            gst_buffer_unref(m_buffer);
+            m_buffer = NULL;
+        }
+
+        if (m_widget) {
+            scheduleRepaint();
+        }
+
+        return true;
+    }
+    default:
+        return QObject::event(event);
+    }
+}
+
+bool WidgetProxy::eventFilter(QObject *filteredObject, QEvent *event)
+{
+    if (filteredObject == m_widget.data()) {
+        switch(event->type()) {
+        case QEvent::User:
+            QMetaObject::invokeMethod(m_widget.data(), "updateImage", Qt::QueuedConnection);
+            return true;
+        default:
+            return false;
+        }
+    } else {
+        return QObject::eventFilter(filteredObject, event);
+    }
+}
+
+//END ******** WidgetProxy ********
+//BEGIN ******** GstQImageVideoSink pad template & boilerplate ********
+
+static GstStaticPadTemplate pad_template =
+    GST_STATIC_PAD_TEMPLATE("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
+                            GST_STATIC_CAPS (GST_VIDEO_CAPS_xRGB_HOST_ENDIAN));
+
+GST_BOILERPLATE(GstQImageVideoSink, gst_qimage_video_sink, GstVideoSink, GST_TYPE_VIDEO_SINK);
+
+//END ******** GstQImageVideoSink pad template & boilerplate ********
+//BEGIN ******** GstQImageVideoSinkClass initialization methods ********
+
+static void gst_qimage_video_sink_base_init(gpointer gclass)
+{
+    GstElementClass *element_class = GST_ELEMENT_CLASS(gclass);
+
+    gst_element_class_set_details_simple(element_class, "QImageVideoSink", "Sink/Video",
+                                         qimagevideosink_description,
+                                         "Aleix Pol Gonzalez <aleixpol@kde.org>");
+
+    gst_element_class_add_pad_template(element_class, gst_static_pad_template_get(&pad_template));
+}
+
+/* initialize the class vtable */
+static void gst_qimage_video_sink_class_init(GstQImageVideoSinkClass *klass)
+{
+    GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
+    gobject_class->finalize = gst_qimage_video_sink_finalize;
+    gobject_class->set_property = gst_qimage_video_sink_set_property;
+    gobject_class->get_property = gst_qimage_video_sink_get_property;
+
+    GstElementClass *element_class = GST_ELEMENT_CLASS(klass);
+    element_class->change_state = gst_qimage_video_sink_change_state;
+
+    GstBaseSinkClass *basesink_class = GST_BASE_SINK_CLASS(klass);
+    basesink_class->buffer_alloc = gst_qimage_video_sink_buffer_alloc;
+
+    GstVideoSinkClass *videosink_class = GST_VIDEO_SINK_CLASS(klass);
+    videosink_class->show_frame = gst_qimage_video_sink_show_frame;
+
+    /**
+     * GstQImageVideoSink::widget
+     *
+     * This property holds a pointer to the QObject on which the sink will paint the video.
+     * You can set this property at any time, even if the element is in PLAYING
+     * state. You can also set this property to NULL at any time to release
+     * the widget. In this case, qimagevideosink will behave like a fakesink,
+     * i.e. it will silently drop all the frames that it receives. It is also safe
+     * to delete the widget that has been set as this property; the sink will be
+     * signaled and this property will automatically be set to NULL.
+     **/
+    g_object_class_install_property(gobject_class, PROP_WIDGET,
+        g_param_spec_pointer("widget", "Widget",
+                             "The object that will recieve the images.",
+                             static_cast<GParamFlags>(G_PARAM_READWRITE)));
+
+    /**
+     * GstQImageVideoSink::force-aspect-ratio
+     *
+     * If set to TRUE, the sink will scale the video respecting its original aspect ratio
+     * and any remaining space will be filled with black.
+     * If set to FALSE, the sink will scale the video to fit the whole widget.
+     **/
+    g_object_class_install_property(gobject_class, PROP_FORCE_ASPECT_RATIO,
+        g_param_spec_boolean("force-aspect-ratio", "Force aspect ratio",
+                             "When enabled, scaling will respect original aspect ratio",
+                             FALSE, static_cast<GParamFlags>(G_PARAM_READWRITE)));
+    
+    g_object_class_install_property(gobject_class, PROP_WIDTH,
+        g_param_spec_boolean("width", "Suggest output width",
+                             "",
+                             FALSE, static_cast<GParamFlags>(G_PARAM_READWRITE)));
+    
+    g_object_class_install_property(gobject_class, PROP_HEIGHT,
+        g_param_spec_boolean("height", "Suggest output height",
+                             "",
+                             FALSE, static_cast<GParamFlags>(G_PARAM_READWRITE)));
+}
+
+//END ******** GstQImageVideoSinkClass initialization methods ********
+//BEGIN ******** GstQImageVideoSink instance virtual methods ********
+
+/* element constructor */
+static void gst_qimage_video_sink_init(GstQImageVideoSink *sink, GstQImageVideoSinkClass*)
+{
+    GST_INFO_OBJECT(sink, "Initializing qimagevideosink");
+    sink->proxy = new WidgetProxy(G_OBJECT(sink));
+}
+
+/* element destructor */
+static void gst_qimage_video_sink_finalize(GObject *object)
+{
+    GstQImageVideoSink *sink = GST_QIMAGEVIDEOSINK(object);
+
+    delete sink->proxy;
+    sink->proxy = NULL;
+    GST_INFO_OBJECT(sink, "Finalized qimagevideosink");
+
+    G_OBJECT_CLASS(parent_class)->finalize(object);
+}
+
+static void gst_qimage_video_sink_set_property(GObject *object, guint prop_id,
+                                                const GValue *value, GParamSpec *pspec)
+{
+    GstQImageVideoSink *sink = GST_QIMAGEVIDEOSINK(object);
+
+    switch (prop_id) {
+    case PROP_WIDGET:
+        sink->proxy->setWidget(static_cast<QObject*>(g_value_get_pointer(value)));
+        break;
+    case PROP_FORCE_ASPECT_RATIO:
+        sink->proxy->setForceAspectRatio(g_value_get_boolean(value));
+        break;
+    case PROP_WIDTH:
+        sink->proxy->setWidth(g_value_get_int(value));
+        break;
+    case PROP_HEIGHT:
+        sink->proxy->setHeight(g_value_get_int(value));
+        break;
+    default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+        break;
+    }
+}
+
+static void gst_qimage_video_sink_get_property(GObject *object, guint prop_id,
+                                                GValue *value, GParamSpec *pspec)
+{
+    GstQImageVideoSink *sink = GST_QIMAGEVIDEOSINK(object);
+
+    switch (prop_id) {
+    case PROP_WIDGET:
+        g_value_set_pointer(value, sink->proxy->widget());
+        break;
+    case PROP_FORCE_ASPECT_RATIO:
+        g_value_set_boolean(value, sink->proxy->forceAspectRatio());
+        break;
+    case PROP_HEIGHT:
+        g_value_set_int(value, sink->proxy->widgetSize().height());
+        break;
+    case PROP_WIDTH:
+        g_value_set_int(value, sink->proxy->widgetSize().width());
+        break;
+    default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+        break;
+    }
+}
+
+static GstStateChangeReturn gst_qimage_video_sink_change_state(GstElement *element,
+                                                                GstStateChange transition)
+{
+    GstQImageVideoSink *sink = GST_QIMAGEVIDEOSINK(element);
+
+    switch(transition) {
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+        sink->proxy->setActive(true);
+        break;
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+        sink->proxy->setActive(false);
+        break;
+    default:
+        break;
+    }
+
+    return GST_ELEMENT_CLASS(parent_class)->change_state(element, transition);
+}
+
+static GstFlowReturn gst_qimage_video_sink_buffer_alloc(GstBaseSink *base_sink, guint64 offset,
+                                                         guint size, GstCaps *caps, GstBuffer **buf)
+{
+    GstQImageVideoSink *sink = GST_QIMAGEVIDEOSINK(base_sink);
+
+    bool unrefCaps = false;
+    GstStructure *structure = gst_caps_get_structure(caps, 0);
+
+    GstVideoRectangle srcRect;
+    srcRect.x = srcRect.y = 0;
+    if (!gst_structure_get_int(structure, "width", &srcRect.w) ||
+        !gst_structure_get_int(structure, "height", &srcRect.h))
+    {
+        return GST_FLOW_NOT_NEGOTIATED;
+    }
+
+    GstVideoRectangle destRect;
+    destRect.x = destRect.y = 0;
+    QSize widgetSize = sink->proxy->widgetSize();
+    destRect.w = widgetSize.width();
+    destRect.h = widgetSize.height();
+
+    GstVideoRectangle resultRect;
+    if (sink->proxy->forceAspectRatio()) {
+        gst_video_sink_center_rect(srcRect, destRect, &resultRect, TRUE);
+    } else {
+        resultRect = destRect;
+    }
+
+    if (resultRect.w != srcRect.w || resultRect.h != srcRect.h) {
+        GstCaps *desiredCaps = gst_caps_copy(caps);
+        GstStructure *structure = gst_caps_get_structure(desiredCaps, 0);
+        gst_structure_set(structure, "width", G_TYPE_INT, resultRect.w,
+                                     "height", G_TYPE_INT, resultRect.h, NULL);
+
+        if (gst_pad_peer_accept_caps(GST_VIDEO_SINK_PAD(sink), desiredCaps)) {
+            caps = desiredCaps;
+            unrefCaps = true;
+            size = resultRect.w * resultRect.h * 4;
+        } else {
+            gst_caps_unref(desiredCaps);
+        }
+    }
+
+    *buf = gst_buffer_new_and_alloc(size);
+    gst_buffer_set_caps(*buf, caps);
+    GST_BUFFER_OFFSET(*buf) = offset;
+
+    if (unrefCaps) {
+        gst_caps_unref(caps);
+    }
+
+    GST_LOG_OBJECT(sink, "Requested buffer was (%d, %d), allocated was (%d, %d)",
+                          srcRect.w, srcRect.h, resultRect.w, resultRect.h);
+
+    return GST_FLOW_OK;
+}
+
+static GstFlowReturn gst_qimage_video_sink_show_frame(GstVideoSink *video_sink, GstBuffer *buf)
+{
+    GstQImageVideoSink *sink = GST_QIMAGEVIDEOSINK(video_sink);
+    GST_LOG_OBJECT(sink, "Posting new buffer (%"GST_PTR_FORMAT") for rendering", buf);
+    QCoreApplication::postEvent(sink->proxy, new BufferEvent(buf));
+    return GST_FLOW_OK;
+}
+
+//END ******** GstQImageVideoSink instance virtual methods ********
+//BEGIN ******** plugin interface ********
+
+/* entry point to initialize the plug-in */
+static gboolean plugin_init(GstPlugin *plugin)
+{
+    GST_DEBUG_CATEGORY_INIT(gst_qimage_video_sink_debug, "qimagevideosink",
+                            0, qimagevideosink_description);
+
+    return gst_element_register(plugin, "qimagevideosink",
+                                GST_RANK_NONE, GST_TYPE_QIMAGEVIDEOSINK);
+}
+
+GST_PLUGIN_DEFINE (
+    GST_VERSION_MAJOR,
+    GST_VERSION_MINOR,
+    "qimagevideosink",
+    qimagevideosink_description,
+    plugin_init,
+    PACKAGE_VERSION,
+    "LGPL",
+    PACKAGE_NAME,
+    PACKAGE_ORIGIN
+)
+
+//END ******** plugin interface ********
+
+#include "gstqimagevideosink.moc"
diff --git a/tests/manual/CMakeLists.txt b/tests/manual/CMakeLists.txt
index 5d4ac2b..21d225b 100644
--- a/tests/manual/CMakeLists.txt
+++ b/tests/manual/CMakeLists.txt
@@ -18,3 +18,7 @@ target_link_libraries(videowidgetpipelinetest ${QTGSTREAMER_UI_LIBRARIES})
 qt4_wrap_ui(VIDEOORIENTATIONTEST_UI videoorientationtest.ui)
 automoc4_add_executable(videoorientationtest videoorientationtest.cpp ${VIDEOORIENTATIONTEST_UI})
 target_link_libraries(videoorientationtest ${QTGSTREAMER_UI_LIBRARIES})
+
+qt4_wrap_ui(QIMAGEVIDEOSINKTEST_UI qimagevideosinktest.ui)
+automoc4_add_executable(qimagevideosinktest qimagevideosinktest.cpp ${QIMAGEVIDEOSINKTEST_UI})
+target_link_libraries(qimagevideosinktest ${QTGSTREAMER_UI_LIBRARIES})
diff --git a/tests/manual/qimagevideosinktest.cpp b/tests/manual/qimagevideosinktest.cpp
new file mode 100644
index 0000000..4746a38
--- /dev/null
+++ b/tests/manual/qimagevideosinktest.cpp
@@ -0,0 +1,203 @@
+/*
+    Copyright (C) 2010 George Kiagiadakis <kiagiadakis.george@gmail.com>
+
+    This library is free software; you can redistribute it and/or modify
+    it under the terms of the GNU Lesser General Public License as published
+    by the Free Software Foundation; either version 2.1 of the License, or
+    (at your option) any later version.
+
+    This program 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 General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+#include <QGst/Init>
+#include <QGst/Pipeline>
+#include <QGst/ElementFactory>
+#include <QtGui/QApplication>
+#include <QtGui/QMessageBox>
+#include <QtGui/QButtonGroup>
+#include <QtGui/QGraphicsPixmapItem>
+#include "ui_qimagevideosinktest.h"
+#include <QtCore/QPropertyAnimation>
+
+
+class VideoGraphicsItem : public QObject, public QGraphicsPixmapItem
+{
+    Q_OBJECT
+    Q_PROPERTY(qreal rotation READ rotation WRITE setRotation)
+    Q_PROPERTY(QPointF position READ pos WRITE setPos)
+    public:
+        VideoGraphicsItem(QGraphicsItem* parent=0) : QGraphicsPixmapItem(parent) {}
+        
+    public Q_SLOTS:
+        void updateImage();
+        void setSink(QGst::ElementPtr elem);
+        QGst::ElementPtr sink() const { return m_sink; }
+        
+    Q_SIGNALS:
+        void imageRequest(QImage* image);
+        
+    private:
+        QGst::ElementPtr m_sink;
+};
+
+class VideoWidgetTest : public QWidget
+{
+    Q_OBJECT
+public:
+    VideoWidgetTest(QWidget* parent = 0, Qt::WindowFlags f = 0);
+
+private Q_SLOTS:
+    void onButtonClicked(int id);
+    void on_forceAspectRatioCheckBox_toggled(bool on);
+    void updateItems(int items);
+
+private:
+    Ui::QImageVideoSinkTest m_ui;
+    QGst::PipelinePtr m_pipeline;
+    QGst::ElementPtr m_src;
+    
+    QList<VideoGraphicsItem*> m_items;
+};
+
+VideoWidgetTest::VideoWidgetTest(QWidget *parent, Qt::WindowFlags f)
+    : QWidget(parent, f)
+{
+    m_ui.setupUi(this);
+
+    QButtonGroup *group = new QButtonGroup(this);
+    group->addButton(m_ui.playingButton, QGst::StatePlaying);
+    group->addButton(m_ui.pausedButton, QGst::StatePaused);
+    group->addButton(m_ui.readyButton, QGst::StateReady);
+    group->addButton(m_ui.nullButton, QGst::StateNull);
+    connect(group, SIGNAL(buttonClicked(int)), SLOT(onButtonClicked(int)));
+    
+    connect(m_ui.itemsCount, SIGNAL(valueChanged(int)), this, SLOT(updateItems(int)));
+    
+    //Definition of the graphicsview
+    m_ui.view->setScene(new QGraphicsScene(this));
+    
+    //some animations to make it funnier :D
+//     QPropertyAnimation* anim = new QPropertyAnimation(m_item, "rotation", m_item);
+//     anim->setStartValue(0);
+//     anim->setEndValue(360);
+//     anim->setDuration(5000);
+//     anim->setLoopCount(-1);
+//     anim->setEasingCurve(QEasingCurve::InExpo);
+//     anim->start();
+    
+    //Definition of the pipeline
+    m_pipeline = QGst::Pipeline::create();
+    QGst::ElementPtr videotest = QGst::ElementFactory::make("videotestsrc");
+    QGst::ElementPtr tee = QGst::ElementFactory::make("tee");
+
+    m_pipeline->add(videotest);
+    m_pipeline->add(tee);
+    videotest->link(tee);
+    
+    m_src=tee;
+    if (!m_src) {
+        throw std::runtime_error("Unable to create a videotestsrc");
+    }
+}
+
+void VideoWidgetTest::onButtonClicked(int id)
+{
+    if (!m_items.isEmpty()) {
+        QGst::State state = static_cast<QGst::State>(id);
+        m_pipeline->setState(state);
+    }
+}
+
+void VideoWidgetTest::updateItems(int items)
+{
+//     Q_ASSERT(items!=m_items.size());
+    
+    QGst::State currentState;
+    m_pipeline->getState(&currentState, NULL, 0);
+
+    if (!m_items.isEmpty()) {
+        m_pipeline->setState(QGst::State(QGst::State::StateNull));
+    }
+    
+    for(; items>m_items.size(); ) {
+        VideoGraphicsItem* item = new VideoGraphicsItem;
+        m_ui.view->scene()->addItem(item);
+        
+        QGst::ElementPtr queue = QGst::ElementFactory::make("queue");
+        QGst::ElementPtr sink = QGst::ElementFactory::make("qimagevideosink");
+        Q_ASSERT(sink);
+        
+        m_pipeline->add(queue);
+        m_pipeline->add(sink);
+        m_src->link(queue);
+        queue->link(sink);
+        
+        item->setSink(sink);
+        m_items.append(item);
+    }
+    
+    for(; items<m_items.size(); ) {
+        VideoGraphicsItem* toremove=m_items.takeLast();
+        m_src->unlink(toremove->sink());
+        m_pipeline->remove(toremove->sink());
+        delete toremove;
+    }
+    
+    qreal angle = (2*M_PI)/items;
+    QRectF rect=m_ui.view->sceneRect();
+    qreal radius=qMin(rect.height(), rect.width())/2.3;
+    for(int i=0; i<items; i++) {
+        m_items[i]->setPos(radius*cos(i*angle), radius*sin(i*angle));
+    }
+    
+    if (!m_items.isEmpty()) {
+        m_pipeline->setState(currentState);
+    }
+}
+
+void VideoWidgetTest::on_forceAspectRatioCheckBox_toggled(bool on)
+{
+    Q_FOREACH(VideoGraphicsItem* v, m_items) {
+        v->sink()->setProperty("force-aspect-ratio", on);
+    }
+}
+
+void VideoGraphicsItem::updateImage()
+{
+    QImage image;
+    Q_EMIT imageRequest(&image);
+    
+    QPixmap px=QPixmap::fromImage(image);
+    setPixmap(px);
+}
+
+void VideoGraphicsItem::setSink(QGst::ElementPtr sink)
+{
+//     sink->setProperty<uint>("width", 320);
+//     sink->setProperty<uint>("height", 240);
+    sink->setProperty<void*>("widget", this);
+    
+    QPixmap p(120,140);
+    p.fill(Qt::red);
+    setPixmap(p);
+
+    m_sink=sink;
+}
+
+int main(int argc, char **argv)
+{
+    QApplication app(argc, argv);
+    QGst::init(&argc, &argv);
+
+    VideoWidgetTest test;
+    test.show();
+
+    return app.exec();
+}
+
+#include "qimagevideosinktest.moc"
diff --git a/tests/manual/qimagevideosinktest.ui b/tests/manual/qimagevideosinktest.ui
new file mode 100644
index 0000000..9e42141
--- /dev/null
+++ b/tests/manual/qimagevideosinktest.ui
@@ -0,0 +1,110 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>QImageVideoSinkTest</class>
+ <widget class="QWidget" name="QImageVideoSinkTest">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>544</width>
+    <height>300</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>VideoWidgetTest</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <item>
+    <widget class="QGroupBox" name="groupBox_2">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="title">
+      <string>Set pipeline state</string>
+     </property>
+     <layout class="QHBoxLayout" name="horizontalLayout_3">
+      <item>
+       <widget class="QSpinBox" name="itemsCount"/>
+      </item>
+      <item>
+       <widget class="QPushButton" name="playingButton">
+        <property name="text">
+         <string>PLAYING</string>
+        </property>
+        <property name="checkable">
+         <bool>true</bool>
+        </property>
+        <property name="checked">
+         <bool>false</bool>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QPushButton" name="pausedButton">
+        <property name="text">
+         <string>PAUSED</string>
+        </property>
+        <property name="checkable">
+         <bool>true</bool>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QPushButton" name="readyButton">
+        <property name="text">
+         <string>READY</string>
+        </property>
+        <property name="checkable">
+         <bool>true</bool>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QPushButton" name="nullButton">
+        <property name="text">
+         <string>NULL</string>
+        </property>
+        <property name="checkable">
+         <bool>true</bool>
+        </property>
+        <property name="checked">
+         <bool>true</bool>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <widget class="QGroupBox" name="groupBox_3">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="Minimum" vsizetype="Preferred">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="title">
+      <string>Misc</string>
+     </property>
+     <layout class="QVBoxLayout" name="verticalLayout_2">
+      <item>
+       <widget class="QCheckBox" name="forceAspectRatioCheckBox">
+        <property name="text">
+         <string>force-aspect-ratio</string>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <widget class="QGraphicsView" name="view"/>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
