eglglessink: Make more similar to latest master
authorSebastian Dröge <sebastian.droege@collabora.co.uk>
Thu, 21 Mar 2013 10:10:08 +0000 (11:10 +0100)
committerSebastian Dröge <sebastian.droege@collabora.co.uk>
Thu, 21 Mar 2013 10:10:08 +0000 (11:10 +0100)
configure.ac
ext/eglgles/Makefile.am
ext/eglgles/gstdataqueue.c [new file with mode: 0644]
ext/eglgles/gstdataqueue.h [new file with mode: 0644]
ext/eglgles/gsteglglessink.c
ext/eglgles/gsteglglessink.h
ext/eglgles/gstqueuearray.c [new file with mode: 0644]
ext/eglgles/gstqueuearray.h [new file with mode: 0644]
ext/eglgles/video_platform_wrapper.c

index b25522da2ee106362628316b7eea57e59444e111..19dbc40c368995bf62a92378195a0cd814f42d83 100644 (file)
@@ -159,6 +159,17 @@ if test "x$HAVE_PTHREAD_H" != "xyes"; then
   GST_PLUGINS_SELECTED=`echo $GST_PLUGINS_SELECTED | $SED -e s/dccp//`
 fi
 
+dnl x11 is optional for librfb and eglglessink
+HAVE_X11=NO
+PKG_CHECK_MODULES(X11, x11, HAVE_X11=yes, HAVE_X11=no)
+AC_SUBST(X11_LIBS)
+AC_SUBST(X11_CFLAGS)
+AC_SUBST(HAVE_X11)
+AM_CONDITIONAL(HAVE_X11, test "x$HAVE_X11" = "xyes")
+if test "x$HAVE_X11" = "xyes"; then
+  AC_DEFINE(HAVE_X11, 1, [Define if you have X11 library])
+fi
+
 dnl check for EGL
 AC_ARG_WITH([egl-window-system],
               AS_HELP_STRING([--with-egl-window-system],[EGL window system to use (x11, mali-fb, rpi, none)]),
@@ -393,17 +404,6 @@ PKG_CHECK_MODULES(GMODULE_EXPORT, gmodule-export-2.0, HAVE_GMODULE_EXPORT=yes, H
 dnl Needed by plugins that use g_module_*() API
 PKG_CHECK_MODULES(GMODULE_NO_EXPORT, gmodule-no-export-2.0)
 
-dnl x11 is optional for librfb and eglglessink
-HAVE_X11=NO
-PKG_CHECK_MODULES(X11, x11, HAVE_X11=yes, HAVE_X11=no)
-AC_SUBST(X11_LIBS)
-AC_SUBST(X11_CFLAGS)
-AC_SUBST(HAVE_X11)
-AM_CONDITIONAL(HAVE_X11, test "x$HAVE_X11" = "xyes")
-if test "x$HAVE_X11" = "xyes"; then
-  AC_DEFINE(HAVE_X11, 1, [Define if you have X11 library])
-fi
-
 dnl exif (used on jifmux tests) ****
 PKG_CHECK_MODULES(EXIF, libexif >= 0.6.16, HAVE_EXIF="yes", HAVE_EXIF="no")
 AC_SUBST(EXIF_LIBS)
index 3e4cc3e51ab8b08fcf63a03afcd5efb38fc42932..89c18681b3dc99d8b7c768809b7fdca3e9d4b254 100644 (file)
@@ -1,6 +1,6 @@
 plugin_LTLIBRARIES = libgsteglglessink.la
 
-libgsteglglessink_la_SOURCES = gsteglglessink.c video_platform_wrapper.c
+libgsteglglessink_la_SOURCES = gsteglglessink.c video_platform_wrapper.c gstqueuearray.c gstdataqueue.c
 
 libgsteglglessink_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) \
                               $(GST_BASE_CFLAGS) \
@@ -15,4 +15,4 @@ libgsteglglessink_la_LIBADD = $(GST_LIBS) $(GST_BASE_LIBS) \
 libgsteglglessink_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
 libgsteglglessink_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS)
 
-noinst_HEADERS = gsteglglessink.h video_platform_wrapper.h
+noinst_HEADERS = gsteglglessink.h video_platform_wrapper.h gstqueuearray.h gstdataqueue.h
diff --git a/ext/eglgles/gstdataqueue.c b/ext/eglgles/gstdataqueue.c
new file mode 100644 (file)
index 0000000..05bf310
--- /dev/null
@@ -0,0 +1,687 @@
+/* GStreamer
+ * Copyright (C) 2006 Edward Hervey <edward@fluendo.com>
+ *
+ * gstdataqueue.c:
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:gstdataqueue
+ * @short_description: Threadsafe queueing object
+ *
+ * #EGLGstDataQueue is an object that handles threadsafe queueing of objects. It
+ * also provides size-related functionality. This object should be used for
+ * any #GstElement that wishes to provide some sort of queueing functionality.
+ */
+
+#include <gst/gst.h>
+#include <string.h>
+
+#include "gstdataqueue.h"
+#include "gstqueuearray.h"
+
+GST_DEBUG_CATEGORY_STATIC (data_queue_debug);
+#define GST_CAT_DEFAULT (data_queue_debug)
+GST_DEBUG_CATEGORY_STATIC (data_queue_dataflow);
+
+
+/* Queue signals and args */
+enum
+{
+  SIGNAL_EMPTY,
+  SIGNAL_FULL,
+  LAST_SIGNAL
+};
+
+enum
+{
+  PROP_0,
+  PROP_CUR_LEVEL_VISIBLE,
+  PROP_CUR_LEVEL_BYTES,
+  PROP_CUR_LEVEL_TIME
+      /* FILL ME */
+};
+
+struct _EGLGstDataQueuePrivate
+{
+  /* the array of data we're keeping our grubby hands on */
+  EGLGstQueueArray *queue;
+
+  EGLGstDataQueueSize cur_level;   /* size of the queue */
+  EGLGstDataQueueCheckFullFunction checkfull;      /* Callback to check if the queue is full */
+  gpointer *checkdata;
+
+  GMutex qlock;                 /* lock for queue (vs object lock) */
+  gboolean waiting_add;
+  GCond item_add;               /* signals buffers now available for reading */
+  gboolean waiting_del;
+  GCond item_del;               /* signals space now available for writing */
+  gboolean flushing;            /* indicates whether conditions where signalled because
+                                 * of external flushing */
+  EGLGstDataQueueFullCallback fullcallback;
+  EGLGstDataQueueEmptyCallback emptycallback;
+};
+
+#define EGL_GST_DATA_QUEUE_MUTEX_LOCK(q) G_STMT_START {                     \
+    GST_CAT_TRACE (data_queue_dataflow,                                 \
+      "locking qlock from thread %p",                                   \
+      g_thread_self ());                                                \
+  g_mutex_lock (&q->priv->qlock);                                       \
+  GST_CAT_TRACE (data_queue_dataflow,                                   \
+      "locked qlock from thread %p",                                    \
+      g_thread_self ());                                                \
+} G_STMT_END
+
+#define EGL_GST_DATA_QUEUE_MUTEX_LOCK_CHECK(q, label) G_STMT_START {        \
+    EGL_GST_DATA_QUEUE_MUTEX_LOCK (q);                                      \
+    if (q->priv->flushing)                                              \
+      goto label;                                                       \
+  } G_STMT_END
+
+#define EGL_GST_DATA_QUEUE_MUTEX_UNLOCK(q) G_STMT_START {                   \
+    GST_CAT_TRACE (data_queue_dataflow,                                 \
+      "unlocking qlock from thread %p",                                 \
+      g_thread_self ());                                                \
+  g_mutex_unlock (&q->priv->qlock);                                     \
+} G_STMT_END
+
+#define STATUS(q, msg)                                                  \
+  GST_CAT_LOG (data_queue_dataflow,                                     \
+               "queue:%p " msg ": %u visible items, %u "                \
+               "bytes, %"G_GUINT64_FORMAT                               \
+               " ns, %u elements",                                      \
+               queue,                                                   \
+               q->priv->cur_level.visible,                              \
+               q->priv->cur_level.bytes,                                \
+               q->priv->cur_level.time,                                 \
+               egl_gst_queue_array_get_length (q->priv->queue))
+
+static void egl_gst_data_queue_finalize (GObject * object);
+
+static void egl_gst_data_queue_set_property (GObject * object,
+    guint prop_id, const GValue * value, GParamSpec * pspec);
+static void egl_gst_data_queue_get_property (GObject * object,
+    guint prop_id, GValue * value, GParamSpec * pspec);
+
+static guint egl_gst_data_queue_signals[LAST_SIGNAL] = { 0 };
+
+#define _do_init \
+{ \
+  GST_DEBUG_CATEGORY_INIT (data_queue_debug, "egldataqueue", 0, \
+      "data queue object"); \
+  GST_DEBUG_CATEGORY_INIT (data_queue_dataflow, "egldata_queue_dataflow", 0, \
+      "dataflow inside the data queue object"); \
+}
+
+#define parent_class egl_gst_data_queue_parent_class
+G_DEFINE_TYPE_WITH_CODE (EGLGstDataQueue, egl_gst_data_queue, G_TYPE_OBJECT, _do_init);
+
+static void
+egl_gst_data_queue_class_init (EGLGstDataQueueClass * klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+  g_type_class_add_private (klass, sizeof (EGLGstDataQueuePrivate));
+
+  gobject_class->set_property = egl_gst_data_queue_set_property;
+  gobject_class->get_property = egl_gst_data_queue_get_property;
+
+  /* signals */
+  /**
+   * EGLGstDataQueue::empty:
+   * @queue: the queue instance
+   *
+   * Reports that the queue became empty (empty).
+   * A queue is empty if the total amount of visible items inside it (num-visible, time,
+   * size) is lower than the boundary values which can be set through the GObject
+   * properties.
+   */
+  egl_gst_data_queue_signals[SIGNAL_EMPTY] =
+      g_signal_new ("empty", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST,
+      G_STRUCT_OFFSET (EGLGstDataQueueClass, empty), NULL, NULL,
+      g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
+
+  /**
+   * EGLGstDataQueue::full:
+   * @queue: the queue instance
+   *
+   * Reports that the queue became full (full).
+   * A queue is full if the total amount of data inside it (num-visible, time,
+   * size) is higher than the boundary values which can be set through the GObject
+   * properties.
+   */
+  egl_gst_data_queue_signals[SIGNAL_FULL] =
+      g_signal_new ("full", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST,
+      G_STRUCT_OFFSET (EGLGstDataQueueClass, full), NULL, NULL,
+      g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
+
+  /* properties */
+  g_object_class_install_property (gobject_class, PROP_CUR_LEVEL_BYTES,
+      g_param_spec_uint ("current-level-bytes", "Current level (kB)",
+          "Current amount of data in the queue (bytes)",
+          0, G_MAXUINT, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_CUR_LEVEL_VISIBLE,
+      g_param_spec_uint ("current-level-visible",
+          "Current level (visible items)",
+          "Current number of visible items in the queue", 0, G_MAXUINT, 0,
+          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_CUR_LEVEL_TIME,
+      g_param_spec_uint64 ("current-level-time", "Current level (ns)",
+          "Current amount of data in the queue (in ns)", 0, G_MAXUINT64, 0,
+          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+
+  gobject_class->finalize = egl_gst_data_queue_finalize;
+}
+
+static void
+egl_gst_data_queue_init (EGLGstDataQueue * queue)
+{
+  queue->priv =
+      G_TYPE_INSTANCE_GET_PRIVATE (queue, EGL_GST_TYPE_DATA_QUEUE,
+      EGLGstDataQueuePrivate);
+
+  queue->priv->cur_level.visible = 0;   /* no content */
+  queue->priv->cur_level.bytes = 0;     /* no content */
+  queue->priv->cur_level.time = 0;      /* no content */
+
+  queue->priv->checkfull = NULL;
+
+  g_mutex_init (&queue->priv->qlock);
+  g_cond_init (&queue->priv->item_add);
+  g_cond_init (&queue->priv->item_del);
+  queue->priv->queue = egl_gst_queue_array_new (50);
+
+  GST_DEBUG ("initialized queue's not_empty & not_full conditions");
+}
+
+/**
+ * egl_gst_data_queue_new:
+ * @checkfull: the callback used to tell if the element considers the queue full
+ * or not.
+ * @fullcallback: the callback which will be called when the queue is considered full.
+ * @emptycallback: the callback which will be called when the queue is considered empty.
+ * @checkdata: a #gpointer that will be given in the @checkfull callback.
+ *
+ * Creates a new #EGLGstDataQueue. The difference with @egl_gst_data_queue_new is that it will
+ * not emit the 'full' and 'empty' signals, but instead calling directly @fullcallback
+ * or @emptycallback.
+ *
+ * Returns: a new #EGLGstDataQueue.
+ *
+ * Since: 1.2.0
+ */
+EGLGstDataQueue *
+egl_gst_data_queue_new (EGLGstDataQueueCheckFullFunction checkfull,
+    EGLGstDataQueueFullCallback fullcallback,
+    EGLGstDataQueueEmptyCallback emptycallback, gpointer checkdata)
+{
+  EGLGstDataQueue *ret;
+
+  g_return_val_if_fail (checkfull != NULL, NULL);
+
+  ret = g_object_newv (EGL_GST_TYPE_DATA_QUEUE, 0, NULL);
+  ret->priv->checkfull = checkfull;
+  ret->priv->checkdata = checkdata;
+  ret->priv->fullcallback = fullcallback;
+  ret->priv->emptycallback = emptycallback;
+
+  return ret;
+}
+
+static void
+egl_gst_data_queue_cleanup (EGLGstDataQueue * queue)
+{
+  EGLGstDataQueuePrivate *priv = queue->priv;
+
+  while (!egl_gst_queue_array_is_empty (priv->queue)) {
+    EGLGstDataQueueItem *item = egl_gst_queue_array_pop_head (priv->queue);
+
+    /* Just call the destroy notify on the item */
+    item->destroy (item);
+  }
+  priv->cur_level.visible = 0;
+  priv->cur_level.bytes = 0;
+  priv->cur_level.time = 0;
+}
+
+/* called only once, as opposed to dispose */
+static void
+egl_gst_data_queue_finalize (GObject * object)
+{
+  EGLGstDataQueue *queue = EGL_GST_DATA_QUEUE (object);
+  EGLGstDataQueuePrivate *priv = queue->priv;
+
+  GST_DEBUG ("finalizing queue");
+
+  egl_gst_data_queue_cleanup (queue);
+  egl_gst_queue_array_free (priv->queue);
+
+  GST_DEBUG ("free mutex");
+  g_mutex_clear (&priv->qlock);
+  GST_DEBUG ("done free mutex");
+
+  g_cond_clear (&priv->item_add);
+  g_cond_clear (&priv->item_del);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static inline void
+egl_gst_data_queue_locked_flush (EGLGstDataQueue * queue)
+{
+  EGLGstDataQueuePrivate *priv = queue->priv;
+
+  STATUS (queue, "before flushing");
+  egl_gst_data_queue_cleanup (queue);
+  STATUS (queue, "after flushing");
+  /* we deleted something... */
+  if (priv->waiting_del)
+    g_cond_signal (&priv->item_del);
+}
+
+static inline gboolean
+egl_gst_data_queue_locked_is_empty (EGLGstDataQueue * queue)
+{
+  EGLGstDataQueuePrivate *priv = queue->priv;
+
+  return (egl_gst_queue_array_get_length (priv->queue) == 0);
+}
+
+static inline gboolean
+egl_gst_data_queue_locked_is_full (EGLGstDataQueue * queue)
+{
+  EGLGstDataQueuePrivate *priv = queue->priv;
+
+  return priv->checkfull (queue, priv->cur_level.visible,
+      priv->cur_level.bytes, priv->cur_level.time, priv->checkdata);
+}
+
+/**
+ * egl_gst_data_queue_flush:
+ * @queue: a #EGLGstDataQueue.
+ *
+ * Flushes all the contents of the @queue. Any call to #egl_gst_data_queue_push and
+ * #egl_gst_data_queue_pop will be released.
+ * MT safe.
+ *
+ * Since: 1.2.0
+ */
+void
+egl_gst_data_queue_flush (EGLGstDataQueue * queue)
+{
+  GST_DEBUG ("queue:%p", queue);
+  EGL_GST_DATA_QUEUE_MUTEX_LOCK (queue);
+  egl_gst_data_queue_locked_flush (queue);
+  EGL_GST_DATA_QUEUE_MUTEX_UNLOCK (queue);
+}
+
+/**
+ * egl_gst_data_queue_is_empty:
+ * @queue: a #EGLGstDataQueue.
+ *
+ * Queries if there are any items in the @queue.
+ * MT safe.
+ *
+ * Returns: #TRUE if @queue is empty.
+ *
+ * Since: 1.2.0
+ */
+gboolean
+egl_gst_data_queue_is_empty (EGLGstDataQueue * queue)
+{
+  gboolean res;
+
+  EGL_GST_DATA_QUEUE_MUTEX_LOCK (queue);
+  res = egl_gst_data_queue_locked_is_empty (queue);
+  EGL_GST_DATA_QUEUE_MUTEX_UNLOCK (queue);
+
+  return res;
+}
+
+/**
+ * egl_gst_data_queue_is_full:
+ * @queue: a #EGLGstDataQueue.
+ *
+ * Queries if @queue is full. This check will be done using the
+ * #EGLGstDataQueueCheckFullFunction registered with @queue.
+ * MT safe.
+ *
+ * Returns: #TRUE if @queue is full.
+ *
+ * Since: 1.2.0
+ */
+gboolean
+egl_gst_data_queue_is_full (EGLGstDataQueue * queue)
+{
+  gboolean res;
+
+  EGL_GST_DATA_QUEUE_MUTEX_LOCK (queue);
+  res = egl_gst_data_queue_locked_is_full (queue);
+  EGL_GST_DATA_QUEUE_MUTEX_UNLOCK (queue);
+
+  return res;
+}
+
+/**
+ * egl_gst_data_queue_set_flushing:
+ * @queue: a #EGLGstDataQueue.
+ * @flushing: a #gboolean stating if the queue will be flushing or not.
+ *
+ * Sets the queue to flushing state if @flushing is #TRUE. If set to flushing
+ * state, any incoming data on the @queue will be discarded. Any call currently
+ * blocking on #egl_gst_data_queue_push or #egl_gst_data_queue_pop will return straight
+ * away with a return value of #FALSE. While the @queue is in flushing state, 
+ * all calls to those two functions will return #FALSE.
+ *
+ * MT Safe.
+ *
+ * Since: 1.2.0
+ */
+void
+egl_gst_data_queue_set_flushing (EGLGstDataQueue * queue, gboolean flushing)
+{
+  EGLGstDataQueuePrivate *priv = queue->priv;
+
+  GST_DEBUG ("queue:%p , flushing:%d", queue, flushing);
+
+  EGL_GST_DATA_QUEUE_MUTEX_LOCK (queue);
+  priv->flushing = flushing;
+  if (flushing) {
+    /* release push/pop functions */
+    if (priv->waiting_add)
+      g_cond_signal (&priv->item_add);
+    if (priv->waiting_del)
+      g_cond_signal (&priv->item_del);
+  }
+  EGL_GST_DATA_QUEUE_MUTEX_UNLOCK (queue);
+}
+
+/**
+ * egl_gst_data_queue_push:
+ * @queue: a #EGLGstDataQueue.
+ * @item: a #EGLGstDataQueueItem.
+ *
+ * Pushes a #EGLGstDataQueueItem (or a structure that begins with the same fields)
+ * on the @queue. If the @queue is full, the call will block until space is
+ * available, OR the @queue is set to flushing state.
+ * MT safe.
+ *
+ * Note that this function has slightly different semantics than gst_pad_push()
+ * and gst_pad_push_event(): this function only takes ownership of @item and
+ * the #GstMiniObject contained in @item if the push was successful. If FALSE
+ * is returned, the caller is responsible for freeing @item and its contents.
+ *
+ * Returns: #TRUE if the @item was successfully pushed on the @queue.
+ *
+ * Since: 1.2.0
+ */
+gboolean
+egl_gst_data_queue_push (EGLGstDataQueue * queue, EGLGstDataQueueItem * item)
+{
+  EGLGstDataQueuePrivate *priv = queue->priv;
+
+  g_return_val_if_fail (EGL_GST_IS_DATA_QUEUE (queue), FALSE);
+  g_return_val_if_fail (item != NULL, FALSE);
+
+  EGL_GST_DATA_QUEUE_MUTEX_LOCK_CHECK (queue, flushing);
+
+  STATUS (queue, "before pushing");
+
+  /* We ALWAYS need to check for queue fillness */
+  if (egl_gst_data_queue_locked_is_full (queue)) {
+    EGL_GST_DATA_QUEUE_MUTEX_UNLOCK (queue);
+    if (G_LIKELY (priv->fullcallback))
+      priv->fullcallback (queue, priv->checkdata);
+    else
+      g_signal_emit (queue, egl_gst_data_queue_signals[SIGNAL_FULL], 0);
+    EGL_GST_DATA_QUEUE_MUTEX_LOCK_CHECK (queue, flushing);
+
+    /* signal might have removed some items */
+    while (egl_gst_data_queue_locked_is_full (queue)) {
+      priv->waiting_del = TRUE;
+      g_cond_wait (&priv->item_del, &priv->qlock);
+      priv->waiting_del = FALSE;
+      if (priv->flushing)
+        goto flushing;
+    }
+  }
+
+  egl_gst_queue_array_push_tail (priv->queue, item);
+
+  if (item->visible)
+    priv->cur_level.visible++;
+  priv->cur_level.bytes += item->size;
+  priv->cur_level.time += item->duration;
+
+  STATUS (queue, "after pushing");
+  if (priv->waiting_add)
+    g_cond_signal (&priv->item_add);
+
+  EGL_GST_DATA_QUEUE_MUTEX_UNLOCK (queue);
+
+  return TRUE;
+
+  /* ERRORS */
+flushing:
+  {
+    GST_DEBUG ("queue:%p, we are flushing", queue);
+    EGL_GST_DATA_QUEUE_MUTEX_UNLOCK (queue);
+    return FALSE;
+  }
+}
+
+/**
+ * egl_gst_data_queue_pop:
+ * @queue: a #EGLGstDataQueue.
+ * @item: pointer to store the returned #EGLGstDataQueueItem.
+ *
+ * Retrieves the first @item available on the @queue. If the queue is currently
+ * empty, the call will block until at least one item is available, OR the
+ * @queue is set to the flushing state.
+ * MT safe.
+ *
+ * Returns: #TRUE if an @item was successfully retrieved from the @queue.
+ *
+ * Since: 1.2.0
+ */
+gboolean
+egl_gst_data_queue_pop (EGLGstDataQueue * queue, EGLGstDataQueueItem ** item)
+{
+  EGLGstDataQueuePrivate *priv = queue->priv;
+
+  g_return_val_if_fail (EGL_GST_IS_DATA_QUEUE (queue), FALSE);
+  g_return_val_if_fail (item != NULL, FALSE);
+
+  EGL_GST_DATA_QUEUE_MUTEX_LOCK_CHECK (queue, flushing);
+
+  STATUS (queue, "before popping");
+
+  if (egl_gst_data_queue_locked_is_empty (queue)) {
+    EGL_GST_DATA_QUEUE_MUTEX_UNLOCK (queue);
+    if (G_LIKELY (priv->emptycallback))
+      priv->emptycallback (queue, priv->checkdata);
+    else
+      g_signal_emit (queue, egl_gst_data_queue_signals[SIGNAL_EMPTY], 0);
+    EGL_GST_DATA_QUEUE_MUTEX_LOCK_CHECK (queue, flushing);
+
+    while (egl_gst_data_queue_locked_is_empty (queue)) {
+      priv->waiting_add = TRUE;
+      g_cond_wait (&priv->item_add, &priv->qlock);
+      priv->waiting_add = FALSE;
+      if (priv->flushing)
+        goto flushing;
+    }
+  }
+
+  /* Get the item from the GQueue */
+  *item = egl_gst_queue_array_pop_head (priv->queue);
+
+  /* update current level counter */
+  if ((*item)->visible)
+    priv->cur_level.visible--;
+  priv->cur_level.bytes -= (*item)->size;
+  priv->cur_level.time -= (*item)->duration;
+
+  STATUS (queue, "after popping");
+  if (priv->waiting_del)
+    g_cond_signal (&priv->item_del);
+
+  EGL_GST_DATA_QUEUE_MUTEX_UNLOCK (queue);
+
+  return TRUE;
+
+  /* ERRORS */
+flushing:
+  {
+    GST_DEBUG ("queue:%p, we are flushing", queue);
+    EGL_GST_DATA_QUEUE_MUTEX_UNLOCK (queue);
+    return FALSE;
+  }
+}
+
+static gint
+is_of_type (gconstpointer a, gconstpointer b)
+{
+  return !G_TYPE_CHECK_INSTANCE_TYPE (a, GPOINTER_TO_SIZE (b));
+}
+
+/**
+ * egl_gst_data_queue_drop_head:
+ * @queue: The #EGLGstDataQueue to drop an item from.
+ * @type: The #GType of the item to drop.
+ *
+ * Pop and unref the head-most #GstMiniObject with the given #GType.
+ *
+ * Returns: TRUE if an element was removed.
+ *
+ * Since: 1.2.0
+ */
+gboolean
+egl_gst_data_queue_drop_head (EGLGstDataQueue * queue, GType type)
+{
+  gboolean res = FALSE;
+  EGLGstDataQueueItem *leak = NULL;
+  guint idx;
+  EGLGstDataQueuePrivate *priv = queue->priv;
+
+  g_return_val_if_fail (EGL_GST_IS_DATA_QUEUE (queue), FALSE);
+
+  GST_DEBUG ("queue:%p", queue);
+
+  EGL_GST_DATA_QUEUE_MUTEX_LOCK (queue);
+  idx = egl_gst_queue_array_find (priv->queue, is_of_type, GSIZE_TO_POINTER (type));
+
+  if (idx == -1)
+    goto done;
+
+  leak = egl_gst_queue_array_drop_element (priv->queue, idx);
+
+  if (leak->visible)
+    priv->cur_level.visible--;
+  priv->cur_level.bytes -= leak->size;
+  priv->cur_level.time -= leak->duration;
+
+  leak->destroy (leak);
+
+  res = TRUE;
+
+done:
+  EGL_GST_DATA_QUEUE_MUTEX_UNLOCK (queue);
+
+  GST_DEBUG ("queue:%p , res:%d", queue, res);
+
+  return res;
+}
+
+/**
+ * egl_gst_data_queue_limits_changed:
+ * @queue: The #EGLGstDataQueue 
+ *
+ * Inform the queue that the limits for the fullness check have changed and that
+ * any blocking egl_gst_data_queue_push() should be unblocked to recheck the limts.
+ *
+ * Since: 1.2.0
+ */
+void
+egl_gst_data_queue_limits_changed (EGLGstDataQueue * queue)
+{
+  EGLGstDataQueuePrivate *priv = queue->priv;
+
+  g_return_if_fail (EGL_GST_IS_DATA_QUEUE (queue));
+
+  EGL_GST_DATA_QUEUE_MUTEX_LOCK (queue);
+  if (priv->waiting_del) {
+    GST_DEBUG ("signal del");
+    g_cond_signal (&priv->item_del);
+  }
+  EGL_GST_DATA_QUEUE_MUTEX_UNLOCK (queue);
+}
+
+/**
+ * egl_gst_data_queue_get_level:
+ * @queue: The #EGLGstDataQueue
+ * @level: the location to store the result
+ *
+ * Get the current level of the queue.
+ *
+ * Since: 1.2.0
+ */
+void
+egl_gst_data_queue_get_level (EGLGstDataQueue * queue, EGLGstDataQueueSize * level)
+{
+  EGLGstDataQueuePrivate *priv = queue->priv;
+
+  memcpy (level, (&priv->cur_level), sizeof (EGLGstDataQueueSize));
+}
+
+static void
+egl_gst_data_queue_set_property (GObject * object,
+    guint prop_id, const GValue * value, GParamSpec * pspec)
+{
+  switch (prop_id) {
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+egl_gst_data_queue_get_property (GObject * object,
+    guint prop_id, GValue * value, GParamSpec * pspec)
+{
+  EGLGstDataQueue *queue = EGL_GST_DATA_QUEUE (object);
+  EGLGstDataQueuePrivate *priv = queue->priv;
+
+  EGL_GST_DATA_QUEUE_MUTEX_LOCK (queue);
+
+  switch (prop_id) {
+    case PROP_CUR_LEVEL_BYTES:
+      g_value_set_uint (value, priv->cur_level.bytes);
+      break;
+    case PROP_CUR_LEVEL_VISIBLE:
+      g_value_set_uint (value, priv->cur_level.visible);
+      break;
+    case PROP_CUR_LEVEL_TIME:
+      g_value_set_uint64 (value, priv->cur_level.time);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+
+  EGL_GST_DATA_QUEUE_MUTEX_UNLOCK (queue);
+}
diff --git a/ext/eglgles/gstdataqueue.h b/ext/eglgles/gstdataqueue.h
new file mode 100644 (file)
index 0000000..34eeb62
--- /dev/null
@@ -0,0 +1,163 @@
+/* GStreamer
+ * Copyright (C) 2006 Edward Hervey <edward@fluendo.com>
+ *
+ * gstdataqueue.h:
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+
+#ifndef __EGL_GST_DATA_QUEUE_H__
+#define __EGL_GST_DATA_QUEUE_H__
+
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+#define EGL_GST_TYPE_DATA_QUEUE \
+  (egl_gst_data_queue_get_type())
+#define EGL_GST_DATA_QUEUE(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),EGL_GST_TYPE_DATA_QUEUE,EGLGstDataQueue))
+#define EGL_GST_DATA_QUEUE_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),EGL_GST_TYPE_DATA_QUEUE,EGLGstDataQueueClass))
+#define EGL_GST_IS_DATA_QUEUE(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),EGL_GST_TYPE_DATA_QUEUE))
+#define EGL_GST_IS_DATA_QUEUE_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),EGL_GST_TYPE_DATA_QUEUE))
+typedef struct _EGLGstDataQueue EGLGstDataQueue;
+typedef struct _EGLGstDataQueueClass EGLGstDataQueueClass;
+typedef struct _EGLGstDataQueueSize EGLGstDataQueueSize;
+typedef struct _EGLGstDataQueueItem EGLGstDataQueueItem;
+typedef struct _EGLGstDataQueuePrivate EGLGstDataQueuePrivate;
+
+/**
+ * EGLGstDataQueueItem:
+ * @object: the #GstMiniObject to queue.
+ * @size: the size in bytes of the miniobject.
+ * @duration: the duration in #GstClockTime of the miniobject. Can not be
+ * #GST_CLOCK_TIME_NONE.
+ * @visible: #TRUE if @object should be considered as a visible object.
+ * @destroy: The #GDestroyNotify function to use to free the #EGLGstDataQueueItem.
+ * This function should also drop the reference to @object the owner of the
+ * #EGLGstDataQueueItem is assumed to hold.
+ *
+ * Structure used by #EGLGstDataQueue. You can supply a different structure, as
+ * long as the top of the structure is identical to this structure.
+ */
+
+struct _EGLGstDataQueueItem
+{
+  GstMiniObject *object;
+  guint size;
+  guint64 duration;
+  gboolean visible;
+
+  /* user supplied destroy function */
+  GDestroyNotify destroy;
+
+  /* < private > */
+  gpointer _gst_reserved[GST_PADDING];
+};
+
+/**
+ * EGLGstDataQueueSize:
+ * @visible: number of buffers
+ * @bytes: number of bytes
+ * @time: amount of time
+ *
+ * Structure describing the size of a queue.
+ */
+struct _EGLGstDataQueueSize
+{
+  guint visible;
+  guint bytes;
+  guint64 time;
+};
+
+/**
+ * EGLGstDataQueueCheckFullFunction:
+ * @queue: a #EGLGstDataQueue.
+ * @visible: The number of visible items currently in the queue.
+ * @bytes: The amount of bytes currently in the queue.
+ * @time: The accumulated duration of the items currently in the queue.
+ * @checkdata: The #gpointer registered when the #EGLGstDataQueue was created.
+ * 
+ * The prototype of the function used to inform the queue that it should be
+ * considered as full.
+ *
+ * Returns: #TRUE if the queue should be considered full.
+ */
+typedef gboolean (*EGLGstDataQueueCheckFullFunction) (EGLGstDataQueue * queue,
+    guint visible, guint bytes, guint64 time, gpointer checkdata);
+
+typedef void (*EGLGstDataQueueFullCallback) (EGLGstDataQueue * queue, gpointer checkdata);
+typedef void (*EGLGstDataQueueEmptyCallback) (EGLGstDataQueue * queue, gpointer checkdata);
+
+/**
+ * EGLGstDataQueue:
+ * @object: the parent structure
+ *
+ * Opaque #EGLGstDataQueue structure.
+ */
+struct _EGLGstDataQueue
+{
+  GObject object;
+
+  /*< private >*/
+  EGLGstDataQueuePrivate *priv;
+  gpointer _gst_reserved[GST_PADDING];
+};
+
+struct _EGLGstDataQueueClass
+{
+  GObjectClass parent_class;
+
+  /* signals */
+  void (*empty) (EGLGstDataQueue * queue);
+  void (*full) (EGLGstDataQueue * queue);
+
+  gpointer _gst_reserved[GST_PADDING];
+};
+
+G_GNUC_INTERNAL
+GType egl_gst_data_queue_get_type (void);
+
+G_GNUC_INTERNAL
+EGLGstDataQueue * egl_gst_data_queue_new            (EGLGstDataQueueCheckFullFunction checkfull,
+                                             EGLGstDataQueueFullCallback fullcallback,
+                                             EGLGstDataQueueEmptyCallback emptycallback,
+                                             gpointer checkdata) G_GNUC_MALLOC;
+G_GNUC_INTERNAL
+gboolean       egl_gst_data_queue_push           (EGLGstDataQueue * queue, EGLGstDataQueueItem * item);
+G_GNUC_INTERNAL
+gboolean       egl_gst_data_queue_pop            (EGLGstDataQueue * queue, EGLGstDataQueueItem ** item);
+G_GNUC_INTERNAL
+void           egl_gst_data_queue_flush          (EGLGstDataQueue * queue);
+G_GNUC_INTERNAL
+void           egl_gst_data_queue_set_flushing   (EGLGstDataQueue * queue, gboolean flushing);
+G_GNUC_INTERNAL
+gboolean       egl_gst_data_queue_drop_head      (EGLGstDataQueue * queue, GType type);
+G_GNUC_INTERNAL
+gboolean       egl_gst_data_queue_is_full        (EGLGstDataQueue * queue);
+G_GNUC_INTERNAL
+gboolean       egl_gst_data_queue_is_empty       (EGLGstDataQueue * queue);
+G_GNUC_INTERNAL
+void           egl_gst_data_queue_get_level      (EGLGstDataQueue * queue, EGLGstDataQueueSize *level);
+G_GNUC_INTERNAL
+void           egl_gst_data_queue_limits_changed (EGLGstDataQueue * queue);
+
+G_END_DECLS
+
+#endif /* __EGL_GST_DATA_QUEUE_H__ */
index 920de9ceecafc846c9972cb9dae76789730a7994..d1fc19d16776345ceb0d7977f7e3bfbe504e040f 100644 (file)
@@ -368,8 +368,9 @@ static gboolean gst_eglglessink_setup_vbo (GstEglGlesSink * eglglessink,
     gboolean reset);
 static gboolean
 gst_eglglessink_configure_caps (GstEglGlesSink * eglglessink, GstCaps * caps);
-static GstFlowReturn gst_eglglessink_render_and_display (GstEglGlesSink * sink,
+static GstFlowReturn gst_eglglessink_upload (GstEglGlesSink * sink,
     GstBuffer * buf);
+static GstFlowReturn gst_eglglessink_render (GstEglGlesSink * sink);
 static GstFlowReturn gst_eglglessink_queue_object (GstEglGlesSink * sink,
     GstMiniObject * obj);
 static inline gboolean got_gl_error (const char *wtf);
@@ -495,7 +496,7 @@ render_thread_func (GstEglGlesSink * eglglessink)
 {
   GstMessage *message;
   GValue val = { 0 };
-  GstDataQueueItem *item = NULL;
+  EGLGstDataQueueItem *item = NULL;
   GstFlowReturn last_flow = GST_FLOW_OK;
 
   g_value_init (&val, G_TYPE_POINTER);
@@ -509,40 +510,41 @@ render_thread_func (GstEglGlesSink * eglglessink)
 
   eglBindAPI (EGL_OPENGL_ES_API);
 
-  while (gst_data_queue_pop (eglglessink->queue, &item)) {
-    GST_DEBUG_OBJECT (eglglessink, "Handling object %" GST_PTR_FORMAT,
-        item->object);
+  while (egl_gst_data_queue_pop (eglglessink->queue, &item)) {
+    GstMiniObject *object = item->object;
 
-    if (GST_IS_CAPS (item->object)) {
-      GstCaps *caps = GST_CAPS_CAST (item->object);
+    GST_DEBUG_OBJECT (eglglessink, "Handling object %" GST_PTR_FORMAT, object);
+
+    if (GST_IS_CAPS (object)) {
+      GstCaps *caps = GST_CAPS_CAST (object);
 
       if (caps != eglglessink->configured_caps) {
         if (!gst_eglglessink_configure_caps (eglglessink, caps)) {
           last_flow = GST_FLOW_NOT_NEGOTIATED;
         }
       }
-    } else if (GST_IS_BUFFER (item->object) || !item->object) {
-      GstBuffer *buf = GST_BUFFER_CAST (item->object);
+    } else if (GST_IS_BUFFER (object) || !object) {
+      GstBuffer *buf = GST_BUFFER_CAST (object);
 
       if (eglglessink->configured_caps) {
-        last_flow = gst_eglglessink_render_and_display (eglglessink, buf);
+        last_flow = gst_eglglessink_upload (eglglessink, buf);
+        if (last_flow == GST_FLOW_OK)
+          last_flow = gst_eglglessink_render (eglglessink);
       } else {
         last_flow = GST_FLOW_OK;
         GST_DEBUG_OBJECT (eglglessink,
             "No caps configured yet, not drawing anything");
       }
+    } else {
+      g_assert_not_reached ();
     }
 
+    item->destroy (item);
+    g_mutex_lock (&eglglessink->render_lock);
+    eglglessink->last_flow = last_flow;
+    g_cond_broadcast (&eglglessink->render_cond);
+    g_mutex_unlock (&eglglessink->render_lock);
 
-    if (item->object) {
-      item->destroy (item);
-      g_mutex_lock (&eglglessink->render_lock);
-      eglglessink->last_flow = last_flow;
-      g_cond_broadcast (&eglglessink->render_cond);
-      g_mutex_unlock (&eglglessink->render_lock);
-    } else {
-      item->destroy (item);
-    }
     if (last_flow != GST_FLOW_OK)
       break;
     GST_DEBUG_OBJECT (eglglessink, "Successfully handled object");
@@ -580,6 +582,8 @@ render_thread_func (GstEglGlesSink * eglglessink)
 static void
 gst_eglglessink_wipe_eglglesctx (GstEglGlesSink * eglglessink)
 {
+  gint i;
+
   glUseProgram (0);
 
   if (eglglessink->have_vbo) {
@@ -595,26 +599,19 @@ gst_eglglessink_wipe_eglglesctx (GstEglGlesSink * eglglessink)
     eglglessink->eglglesctx.n_textures = 0;
   }
 
-  if (eglglessink->eglglesctx.glslprogram[0]) {
-    glDetachShader (eglglessink->eglglesctx.glslprogram[0],
-        eglglessink->eglglesctx.fragshader[0]);
-    glDetachShader (eglglessink->eglglesctx.glslprogram[0],
-        eglglessink->eglglesctx.vertshader[0]);
-    glDeleteProgram (eglglessink->eglglesctx.glslprogram[0]);
-    glDeleteShader (eglglessink->eglglesctx.fragshader[0]);
-    glDeleteShader (eglglessink->eglglesctx.vertshader[0]);
-    eglglessink->eglglesctx.glslprogram[0] = 0;
-  }
-
-  if (eglglessink->eglglesctx.glslprogram[1]) {
-    glDetachShader (eglglessink->eglglesctx.glslprogram[1],
-        eglglessink->eglglesctx.fragshader[1]);
-    glDetachShader (eglglessink->eglglesctx.glslprogram[1],
-        eglglessink->eglglesctx.vertshader[1]);
-    glDeleteProgram (eglglessink->eglglesctx.glslprogram[1]);
-    glDeleteShader (eglglessink->eglglesctx.fragshader[1]);
-    glDeleteShader (eglglessink->eglglesctx.vertshader[1]);
-    eglglessink->eglglesctx.glslprogram[1] = 0;
+  for (i = 0; i < 2; i++) {
+    if (eglglessink->eglglesctx.glslprogram[i]) {
+      glDetachShader (eglglessink->eglglesctx.glslprogram[i],
+          eglglessink->eglglesctx.fragshader[i]);
+      glDetachShader (eglglessink->eglglesctx.glslprogram[i],
+          eglglessink->eglglesctx.vertshader[i]);
+      glDeleteProgram (eglglessink->eglglesctx.glslprogram[i]);
+      glDeleteShader (eglglessink->eglglesctx.fragshader[i]);
+      glDeleteShader (eglglessink->eglglesctx.vertshader[i]);
+      eglglessink->eglglesctx.glslprogram[i] = 0;
+      eglglessink->eglglesctx.fragshader[i] = 0;
+      eglglessink->eglglesctx.vertshader[i] = 0;
+    }
   }
 
   gst_eglglessink_context_make_current (eglglessink, FALSE);
@@ -659,7 +656,7 @@ gst_eglglessink_start (GstEglGlesSink * eglglessink)
   eglglessink->display_region.w = 0;
   eglglessink->display_region.h = 0;
 
-  gst_data_queue_set_flushing (eglglessink->queue, FALSE);
+  egl_gst_data_queue_set_flushing (eglglessink->queue, FALSE);
 
 #if !GLIB_CHECK_VERSION (2, 31, 0)
   eglglessink->thread =
@@ -688,7 +685,7 @@ gst_eglglessink_stop (GstEglGlesSink * eglglessink)
 {
   GST_DEBUG_OBJECT (eglglessink, "Stopping");
 
-  gst_data_queue_set_flushing (eglglessink->queue, TRUE);
+  egl_gst_data_queue_set_flushing (eglglessink->queue, TRUE);
   g_mutex_lock (&eglglessink->render_lock);
   g_cond_broadcast (&eglglessink->render_cond);
   g_mutex_unlock (&eglglessink->render_lock);
@@ -1199,8 +1196,9 @@ gst_eglglessink_init_egl_surface (GstEglGlesSink * eglglessink)
         display_par > EGL_SANE_DAR_MAX) {
       GST_DEBUG_OBJECT (eglglessink, "Nonsensical PAR value returned: %d. "
           "Bad EGL implementation? "
-          "Will use default: %d/%d", eglglessink->eglglesctx.pixel_aspect_ratio,
-          EGL_DISPLAY_SCALING, EGL_DISPLAY_SCALING);
+          "Will use default: %d/%d",
+          eglglessink->eglglesctx.pixel_aspect_ratio, EGL_DISPLAY_SCALING,
+          EGL_DISPLAY_SCALING);
       eglglessink->eglglesctx.pixel_aspect_ratio = EGL_DISPLAY_SCALING;
     } else {
       eglglessink->eglglesctx.pixel_aspect_ratio = display_par;
@@ -1357,18 +1355,12 @@ gst_eglglessink_init_egl_surface (GstEglGlesSink * eglglessink)
   if (!eglglessink->have_texture) {
     GST_INFO_OBJECT (eglglessink, "Performing initial texture setup");
 
-    for (i = 0; i < eglglessink->eglglesctx.n_textures; i++) {
-      if (i == 0)
-        glActiveTexture (GL_TEXTURE0);
-      else if (i == 1)
-        glActiveTexture (GL_TEXTURE1);
-      else if (i == 2)
-        glActiveTexture (GL_TEXTURE2);
-
-      glGenTextures (1, &eglglessink->eglglesctx.texture[i]);
-      if (got_gl_error ("glGenTextures"))
-        goto HANDLE_ERROR_LOCKED;
+    glGenTextures (eglglessink->eglglesctx.n_textures,
+        eglglessink->eglglesctx.texture);
+    if (got_gl_error ("glGenTextures"))
+      goto HANDLE_ERROR_LOCKED;
 
+    for (i = 0; i < eglglessink->eglglesctx.n_textures; i++) {
       glBindTexture (GL_TEXTURE_2D, eglglessink->eglglesctx.texture[i]);
       if (got_gl_error ("glBindTexture"))
         goto HANDLE_ERROR;
@@ -1515,8 +1507,8 @@ gst_eglglessink_set_window_handle (GstVideoOverlay * overlay, guintptr id)
 }
 
 static void
-gst_eglglessink_set_render_rectangle (GstVideoOverlay * overlay, gint x, gint y,
-    gint width, gint height)
+gst_eglglessink_set_render_rectangle (GstVideoOverlay * overlay, gint x,
+    gint y, gint width, gint height)
 {
   GstEglGlesSink *eglglessink = GST_EGLGLESSINK (overlay);
 
@@ -1535,16 +1527,16 @@ gst_eglglessink_set_render_rectangle (GstVideoOverlay * overlay, gint x, gint y,
 }
 
 static void
-queue_item_destroy (GstDataQueueItem * item)
+queue_item_destroy (EGLGstDataQueueItem * item)
 {
   gst_mini_object_replace (&item->object, NULL);
-  g_slice_free (GstDataQueueItem, item);
+  g_slice_free (EGLGstDataQueueItem, item);
 }
 
 static GstFlowReturn
 gst_eglglessink_queue_object (GstEglGlesSink * eglglessink, GstMiniObject * obj)
 {
-  GstDataQueueItem *item;
+  EGLGstDataQueueItem *item;
   GstFlowReturn last_flow;
 
   g_mutex_lock (&eglglessink->render_lock);
@@ -1554,7 +1546,7 @@ gst_eglglessink_queue_object (GstEglGlesSink * eglglessink, GstMiniObject * obj)
   if (last_flow != GST_FLOW_OK)
     return last_flow;
 
-  item = g_slice_new0 (GstDataQueueItem);
+  item = g_slice_new0 (EGLGstDataQueueItem);
 
   item->object = obj ? gst_mini_object_ref (obj) : NULL;
   item->size = 0;
@@ -1564,23 +1556,21 @@ gst_eglglessink_queue_object (GstEglGlesSink * eglglessink, GstMiniObject * obj)
 
   GST_DEBUG_OBJECT (eglglessink, "Queueing object %" GST_PTR_FORMAT, obj);
 
-  if (obj)
-    g_mutex_lock (&eglglessink->render_lock);
-  if (!gst_data_queue_push (eglglessink->queue, item)) {
+  g_mutex_lock (&eglglessink->render_lock);
+
+  if (!egl_gst_data_queue_push (eglglessink->queue, item)) {
     item->destroy (item);
     g_mutex_unlock (&eglglessink->render_lock);
     GST_DEBUG_OBJECT (eglglessink, "Flushing");
     return GST_FLOW_FLUSHING;
   }
 
-  if (obj) {
-    GST_DEBUG_OBJECT (eglglessink, "Waiting for obj to be handled");
-    g_cond_wait (&eglglessink->render_cond, &eglglessink->render_lock);
-    GST_DEBUG_OBJECT (eglglessink, "Buffer rendered: %s",
-        gst_flow_get_name (eglglessink->last_flow));
-    last_flow = eglglessink->last_flow;
-    g_mutex_unlock (&eglglessink->render_lock);
-  }
+  GST_DEBUG_OBJECT (eglglessink, "Waiting for obj to be handled");
+  g_cond_wait (&eglglessink->render_cond, &eglglessink->render_lock);
+  GST_DEBUG_OBJECT (eglglessink, "Buffer rendered: %s",
+      gst_flow_get_name (eglglessink->last_flow));
+  last_flow = eglglessink->last_flow;
+  g_mutex_unlock (&eglglessink->render_lock);
 
   return (obj ? last_flow : GST_FLOW_OK);
 }
@@ -1602,426 +1592,415 @@ gst_eglglessink_crop_changed (GstEglGlesSink * eglglessink,
 }
 
 /* Rendering and display */
-static GstFlowReturn
-gst_eglglessink_render_and_display (GstEglGlesSink * eglglessink,
-    GstBuffer * buf)
+static gboolean
+gst_eglglessink_fill_texture (GstEglGlesSink * eglglessink, GstBuffer * buf)
 {
   GstVideoFrame vframe;
-  guint dar_n, dar_d;
-  GstVideoCropMeta *crop = NULL;
-  gint i;
+  gint w, h;
 
   memset (&vframe, 0, sizeof (vframe));
 
-  if (buf) {
-    crop = gst_buffer_get_video_crop_meta (buf);
-
-    if (!gst_video_frame_map (&vframe, &eglglessink->configured_info, buf,
-            GST_MAP_READ)) {
-      GST_ERROR_OBJECT (eglglessink, "Couldn't map frame");
-      goto HANDLE_ERROR;
-    }
-  } else {
-    GST_DEBUG_OBJECT (eglglessink, "Rendering previous buffer again");
+  if (!gst_video_frame_map (&vframe, &eglglessink->configured_info, buf,
+          GST_MAP_READ)) {
+    GST_ERROR_OBJECT (eglglessink, "Couldn't map frame");
+    goto HANDLE_ERROR;
   }
 
-  if (buf) {
-    gint w, h;
+  w = GST_VIDEO_FRAME_WIDTH (&vframe);
+  h = GST_VIDEO_FRAME_HEIGHT (&vframe);
 
-    w = GST_VIDEO_FRAME_WIDTH (&vframe);
-    h = GST_VIDEO_FRAME_HEIGHT (&vframe);
+  GST_DEBUG_OBJECT (eglglessink,
+      "Got buffer %p: %dx%d size %d", buf, w, h, gst_buffer_get_size (buf));
 
-    GST_DEBUG_OBJECT (eglglessink,
-        "Got buffer %p: %dx%d size %d", buf, w, h, gst_buffer_get_size (buf));
+  switch (eglglessink->configured_info.finfo->format) {
+    case GST_VIDEO_FORMAT_BGR:
+    case GST_VIDEO_FORMAT_RGB:{
+      gint stride;
+      gint stride_width;
+      gint c_w;
 
-    switch (eglglessink->configured_info.finfo->format) {
-      case GST_VIDEO_FORMAT_BGR:
-      case GST_VIDEO_FORMAT_RGB:{
-        gint stride;
-        gint stride_width;
-        gint c_w;
+      stride = GST_VIDEO_FRAME_PLANE_STRIDE (&vframe, 0);
+      stride_width = c_w = GST_VIDEO_FRAME_WIDTH (&vframe);
 
-        stride = GST_VIDEO_FRAME_PLANE_STRIDE (&vframe, 0);
-        stride_width = c_w = GST_VIDEO_FRAME_WIDTH (&vframe);
+      glActiveTexture (GL_TEXTURE0);
 
-        glActiveTexture (GL_TEXTURE0);
+      if (GST_ROUND_UP_8 (c_w * 3) == stride) {
+        glPixelStorei (GL_UNPACK_ALIGNMENT, 8);
+      } else if (GST_ROUND_UP_4 (c_w * 3) == stride) {
+        glPixelStorei (GL_UNPACK_ALIGNMENT, 4);
+      } else if (GST_ROUND_UP_2 (c_w * 3) == stride) {
+        glPixelStorei (GL_UNPACK_ALIGNMENT, 2);
+      } else if (c_w * 3 == stride) {
+        glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
+      } else {
+        stride_width = stride;
 
-        if (GST_ROUND_UP_8 (c_w * 3) == stride) {
+        if (GST_ROUND_UP_8 (stride_width * 3) == stride) {
           glPixelStorei (GL_UNPACK_ALIGNMENT, 8);
-        } else if (GST_ROUND_UP_4 (c_w * 3) == stride) {
+        } else if (GST_ROUND_UP_4 (stride_width * 3) == stride) {
           glPixelStorei (GL_UNPACK_ALIGNMENT, 4);
-        } else if (GST_ROUND_UP_2 (c_w * 3) == stride) {
+        } else if (GST_ROUND_UP_2 (stride_width * 3) == stride) {
           glPixelStorei (GL_UNPACK_ALIGNMENT, 2);
-        } else if (c_w * 3 == stride) {
+        } else if (stride_width * 3 == stride) {
           glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
         } else {
-          stride_width = stride;
-
-          if (GST_ROUND_UP_8 (stride_width * 3) == stride) {
-            glPixelStorei (GL_UNPACK_ALIGNMENT, 8);
-          } else if (GST_ROUND_UP_4 (stride_width * 3) == stride) {
-            glPixelStorei (GL_UNPACK_ALIGNMENT, 4);
-          } else if (GST_ROUND_UP_2 (stride_width * 3) == stride) {
-            glPixelStorei (GL_UNPACK_ALIGNMENT, 2);
-          } else if (stride_width * 3 == stride) {
-            glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
-          } else {
-            GST_ERROR_OBJECT (eglglessink, "Unsupported stride %d", stride);
-            goto HANDLE_ERROR;
-          }
-        }
-        if (got_gl_error ("glPixelStorei"))
+          GST_ERROR_OBJECT (eglglessink, "Unsupported stride %d", stride);
           goto HANDLE_ERROR;
-
-        eglglessink->stride[0] = ((gdouble) stride_width) / ((gdouble) c_w);
-        glBindTexture (GL_TEXTURE_2D, eglglessink->eglglesctx.texture[0]);
-        glTexImage2D (GL_TEXTURE_2D, 0, GL_RGB, stride_width, h, 0, GL_RGB,
-            GL_UNSIGNED_BYTE, GST_VIDEO_FRAME_PLANE_DATA (&vframe, 0));
-        break;
+        }
       }
-      case GST_VIDEO_FORMAT_RGB16:{
-        gint stride;
-        gint stride_width;
-        gint c_w;
+      if (got_gl_error ("glPixelStorei"))
+        goto HANDLE_ERROR;
+
+      eglglessink->stride[0] = ((gdouble) stride_width) / ((gdouble) c_w);
+
+      glBindTexture (GL_TEXTURE_2D, eglglessink->eglglesctx.texture[0]);
+      glTexImage2D (GL_TEXTURE_2D, 0, GL_RGB, stride_width, h, 0, GL_RGB,
+          GL_UNSIGNED_BYTE, GST_VIDEO_FRAME_PLANE_DATA (&vframe, 0));
+      break;
+    }
+    case GST_VIDEO_FORMAT_RGB16:{
+      gint stride;
+      gint stride_width;
+      gint c_w;
 
-        stride = GST_VIDEO_FRAME_PLANE_STRIDE (&vframe, 0);
-        stride_width = c_w = GST_VIDEO_FRAME_WIDTH (&vframe);
+      stride = GST_VIDEO_FRAME_PLANE_STRIDE (&vframe, 0);
+      stride_width = c_w = GST_VIDEO_FRAME_WIDTH (&vframe);
 
-        glActiveTexture (GL_TEXTURE0);
+      glActiveTexture (GL_TEXTURE0);
+
+      if (GST_ROUND_UP_8 (c_w * 2) == stride) {
+        glPixelStorei (GL_UNPACK_ALIGNMENT, 8);
+      } else if (GST_ROUND_UP_4 (c_w * 2) == stride) {
+        glPixelStorei (GL_UNPACK_ALIGNMENT, 4);
+      } else if (c_w * 2 == stride) {
+        glPixelStorei (GL_UNPACK_ALIGNMENT, 2);
+      } else {
+        stride_width = stride;
 
-        if (GST_ROUND_UP_8 (c_w * 2) == stride) {
+        if (GST_ROUND_UP_8 (stride_width * 4) == stride) {
           glPixelStorei (GL_UNPACK_ALIGNMENT, 8);
-        } else if (GST_ROUND_UP_4 (c_w * 2) == stride) {
+        } else if (GST_ROUND_UP_4 (stride_width * 2) == stride) {
           glPixelStorei (GL_UNPACK_ALIGNMENT, 4);
-        } else if (c_w * 2 == stride) {
+        } else if (stride_width * 2 == stride) {
           glPixelStorei (GL_UNPACK_ALIGNMENT, 2);
         } else {
-          stride_width = stride;
-
-          if (GST_ROUND_UP_8 (stride_width * 2) == stride) {
-            glPixelStorei (GL_UNPACK_ALIGNMENT, 8);
-          } else if (GST_ROUND_UP_4 (stride_width * 2) == stride) {
-            glPixelStorei (GL_UNPACK_ALIGNMENT, 4);
-          } else if (stride_width * 2 == stride) {
-            glPixelStorei (GL_UNPACK_ALIGNMENT, 2);
-          } else {
-            GST_ERROR_OBJECT (eglglessink, "Unsupported stride %d", stride);
-            goto HANDLE_ERROR;
-          }
-        }
-        if (got_gl_error ("glPixelStorei"))
+          GST_ERROR_OBJECT (eglglessink, "Unsupported stride %d", stride);
           goto HANDLE_ERROR;
-
-        eglglessink->stride[0] = ((gdouble) stride_width) / ((gdouble) c_w);
-        glBindTexture (GL_TEXTURE_2D, eglglessink->eglglesctx.texture[0]);
-        glTexImage2D (GL_TEXTURE_2D, 0, GL_RGB, stride_width, h, 0, GL_RGB,
-            GL_UNSIGNED_SHORT_5_6_5, GST_VIDEO_FRAME_PLANE_DATA (&vframe, 0));
-        break;
+        }
       }
-      case GST_VIDEO_FORMAT_RGBA:
-      case GST_VIDEO_FORMAT_BGRA:
-      case GST_VIDEO_FORMAT_ARGB:
-      case GST_VIDEO_FORMAT_ABGR:
-      case GST_VIDEO_FORMAT_RGBx:
-      case GST_VIDEO_FORMAT_BGRx:
-      case GST_VIDEO_FORMAT_xRGB:
-      case GST_VIDEO_FORMAT_xBGR:{
-        gint stride;
-        gint stride_width;
-        gint c_w;
-
-        stride = GST_VIDEO_FRAME_PLANE_STRIDE (&vframe, 0);
-        stride_width = c_w = GST_VIDEO_FRAME_WIDTH (&vframe);
-
-        glActiveTexture (GL_TEXTURE0);
-
-        if (GST_ROUND_UP_8 (c_w * 4) == stride) {
+      if (got_gl_error ("glPixelStorei"))
+        goto HANDLE_ERROR;
+
+      eglglessink->stride[0] = ((gdouble) stride_width) / ((gdouble) c_w);
+
+      glBindTexture (GL_TEXTURE_2D, eglglessink->eglglesctx.texture[0]);
+      glTexImage2D (GL_TEXTURE_2D, 0, GL_RGB, stride_width, h, 0, GL_RGB,
+          GL_UNSIGNED_SHORT_5_6_5, GST_VIDEO_FRAME_PLANE_DATA (&vframe, 0));
+      break;
+    }
+    case GST_VIDEO_FORMAT_RGBA:
+    case GST_VIDEO_FORMAT_BGRA:
+    case GST_VIDEO_FORMAT_ARGB:
+    case GST_VIDEO_FORMAT_ABGR:
+    case GST_VIDEO_FORMAT_RGBx:
+    case GST_VIDEO_FORMAT_BGRx:
+    case GST_VIDEO_FORMAT_xRGB:
+    case GST_VIDEO_FORMAT_xBGR:{
+      gint stride;
+      gint stride_width;
+      gint c_w;
+
+      stride = GST_VIDEO_FRAME_PLANE_STRIDE (&vframe, 0);
+      stride_width = c_w = GST_VIDEO_FRAME_WIDTH (&vframe);
+
+      glActiveTexture (GL_TEXTURE0);
+
+      if (GST_ROUND_UP_8 (c_w * 4) == stride) {
+        glPixelStorei (GL_UNPACK_ALIGNMENT, 8);
+      } else if (c_w * 4 == stride) {
+        glPixelStorei (GL_UNPACK_ALIGNMENT, 4);
+      } else {
+        stride_width = stride;
+
+        if (GST_ROUND_UP_8 (stride_width * 4) == stride) {
           glPixelStorei (GL_UNPACK_ALIGNMENT, 8);
-        } else if (c_w * 4 == stride) {
+        } else if (stride_width * 4 == stride) {
           glPixelStorei (GL_UNPACK_ALIGNMENT, 4);
         } else {
-          stride_width = stride;
-
-          if (GST_ROUND_UP_8 (stride_width * 4) == stride) {
-            glPixelStorei (GL_UNPACK_ALIGNMENT, 8);
-          } else if (stride_width * 4 == stride) {
-            glPixelStorei (GL_UNPACK_ALIGNMENT, 4);
-          } else {
-            GST_ERROR_OBJECT (eglglessink, "Unsupported stride %d", stride);
-            goto HANDLE_ERROR;
-          }
-        }
-        if (got_gl_error ("glPixelStorei"))
+          GST_ERROR_OBJECT (eglglessink, "Unsupported stride %d", stride);
           goto HANDLE_ERROR;
+        }
+      }
+      if (got_gl_error ("glPixelStorei"))
+        goto HANDLE_ERROR;
 
-        eglglessink->stride[0] = ((gdouble) stride_width) / ((gdouble) c_w);
+      eglglessink->stride[0] = ((gdouble) stride_width) / ((gdouble) c_w);
 
-        glBindTexture (GL_TEXTURE_2D, eglglessink->eglglesctx.texture[0]);
-        glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, stride_width, h, 0,
-            GL_RGBA, GL_UNSIGNED_BYTE, GST_VIDEO_FRAME_PLANE_DATA (&vframe, 0));
-        break;
-      }
-      case GST_VIDEO_FORMAT_AYUV:{
-        gint stride;
-        gint stride_width;
-        gint c_w;
+      glBindTexture (GL_TEXTURE_2D, eglglessink->eglglesctx.texture[0]);
+      glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, stride_width, h, 0,
+          GL_RGBA, GL_UNSIGNED_BYTE, GST_VIDEO_FRAME_PLANE_DATA (&vframe, 0));
+      break;
+    }
+    case GST_VIDEO_FORMAT_AYUV:{
+      gint stride;
+      gint stride_width;
+      gint c_w;
 
-        stride = GST_VIDEO_FRAME_PLANE_STRIDE (&vframe, 0);
-        stride_width = c_w = GST_VIDEO_FRAME_WIDTH (&vframe);
+      stride = GST_VIDEO_FRAME_PLANE_STRIDE (&vframe, 0);
+      stride_width = c_w = GST_VIDEO_FRAME_WIDTH (&vframe);
 
-        glActiveTexture (GL_TEXTURE0);
+      glActiveTexture (GL_TEXTURE0);
 
-        if (GST_ROUND_UP_8 (c_w * 4) == stride) {
+      if (GST_ROUND_UP_8 (c_w * 4) == stride) {
+        glPixelStorei (GL_UNPACK_ALIGNMENT, 8);
+      } else if (c_w * 4 == stride) {
+        glPixelStorei (GL_UNPACK_ALIGNMENT, 4);
+      } else {
+        stride_width = stride;
+
+        if (GST_ROUND_UP_8 (stride_width * 4) == stride) {
           glPixelStorei (GL_UNPACK_ALIGNMENT, 8);
-        } else if (c_w * 4 == stride) {
+        } else if (stride_width * 4 == stride) {
           glPixelStorei (GL_UNPACK_ALIGNMENT, 4);
         } else {
-          stride_width = stride;
-
-          if (GST_ROUND_UP_8 (stride_width * 4) == stride) {
-            glPixelStorei (GL_UNPACK_ALIGNMENT, 8);
-          } else if (stride_width * 4 == stride) {
-            glPixelStorei (GL_UNPACK_ALIGNMENT, 4);
-          } else {
-            GST_ERROR_OBJECT (eglglessink, "Unsupported stride %d", stride);
-            goto HANDLE_ERROR;
-          }
-        }
-        if (got_gl_error ("glPixelStorei"))
+          GST_ERROR_OBJECT (eglglessink, "Unsupported stride %d", stride);
           goto HANDLE_ERROR;
+        }
+      }
+      if (got_gl_error ("glPixelStorei"))
+        goto HANDLE_ERROR;
 
-        eglglessink->stride[0] = ((gdouble) stride_width) / ((gdouble) c_w);
+      eglglessink->stride[0] = ((gdouble) stride_width) / ((gdouble) c_w);
 
-        glBindTexture (GL_TEXTURE_2D, eglglessink->eglglesctx.texture[0]);
-        glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, stride_width, h, 0,
-            GL_RGBA, GL_UNSIGNED_BYTE, GST_VIDEO_FRAME_PLANE_DATA (&vframe, 0));
-        break;
-      }
-      case GST_VIDEO_FORMAT_Y444:
-      case GST_VIDEO_FORMAT_I420:
-      case GST_VIDEO_FORMAT_YV12:
-      case GST_VIDEO_FORMAT_Y42B:
-      case GST_VIDEO_FORMAT_Y41B:{
-        gint stride;
-        gint stride_width;
-        gint c_w;
+      glBindTexture (GL_TEXTURE_2D, eglglessink->eglglesctx.texture[0]);
+      glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, stride_width, h, 0,
+          GL_RGBA, GL_UNSIGNED_BYTE, GST_VIDEO_FRAME_PLANE_DATA (&vframe, 0));
+      break;
+    }
+    case GST_VIDEO_FORMAT_Y444:
+    case GST_VIDEO_FORMAT_I420:
+    case GST_VIDEO_FORMAT_YV12:
+    case GST_VIDEO_FORMAT_Y42B:
+    case GST_VIDEO_FORMAT_Y41B:{
+      gint stride;
+      gint stride_width;
+      gint c_w;
 
-        stride = GST_VIDEO_FRAME_PLANE_STRIDE (&vframe, 0);
-        stride_width = c_w = GST_VIDEO_FRAME_COMP_WIDTH (&vframe, 0);
+      stride = GST_VIDEO_FRAME_PLANE_STRIDE (&vframe, 0);
+      stride_width = c_w = GST_VIDEO_FRAME_COMP_WIDTH (&vframe, 0);
 
-        glActiveTexture (GL_TEXTURE0);
+      glActiveTexture (GL_TEXTURE0);
+
+      if (GST_ROUND_UP_8 (c_w) == stride) {
+        glPixelStorei (GL_UNPACK_ALIGNMENT, 8);
+      } else if (GST_ROUND_UP_4 (c_w) == stride) {
+        glPixelStorei (GL_UNPACK_ALIGNMENT, 4);
+      } else if (GST_ROUND_UP_2 (c_w) == stride) {
+        glPixelStorei (GL_UNPACK_ALIGNMENT, 2);
+      } else if (c_w == stride) {
+        glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
+      } else {
+        stride_width = stride;
 
-        if (GST_ROUND_UP_8 (c_w) == stride) {
+        if (GST_ROUND_UP_8 (stride_width) == stride) {
           glPixelStorei (GL_UNPACK_ALIGNMENT, 8);
-        } else if (GST_ROUND_UP_4 (c_w) == stride) {
+        } else if (GST_ROUND_UP_4 (stride_width) == stride) {
           glPixelStorei (GL_UNPACK_ALIGNMENT, 4);
-        } else if (GST_ROUND_UP_2 (c_w) == stride) {
+        } else if (GST_ROUND_UP_2 (stride_width) == stride) {
           glPixelStorei (GL_UNPACK_ALIGNMENT, 2);
-        } else if (c_w == stride) {
+        } else if (stride_width == stride) {
           glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
         } else {
-          stride_width = stride;
-
-          if (GST_ROUND_UP_8 (stride_width) == stride) {
-            glPixelStorei (GL_UNPACK_ALIGNMENT, 8);
-          } else if (GST_ROUND_UP_4 (stride_width) == stride) {
-            glPixelStorei (GL_UNPACK_ALIGNMENT, 4);
-          } else if (GST_ROUND_UP_2 (stride_width) == stride) {
-            glPixelStorei (GL_UNPACK_ALIGNMENT, 2);
-          } else if (stride_width == stride) {
-            glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
-          } else {
-            GST_ERROR_OBJECT (eglglessink, "Unsupported stride %d", stride);
-            goto HANDLE_ERROR;
-          }
-        }
-        if (got_gl_error ("glPixelStorei"))
+          GST_ERROR_OBJECT (eglglessink, "Unsupported stride %d", stride);
           goto HANDLE_ERROR;
+        }
+      }
+      if (got_gl_error ("glPixelStorei"))
+        goto HANDLE_ERROR;
 
-        eglglessink->stride[0] = ((gdouble) stride_width) / ((gdouble) c_w);
+      eglglessink->stride[0] = ((gdouble) stride_width) / ((gdouble) c_w);
 
-        glBindTexture (GL_TEXTURE_2D, eglglessink->eglglesctx.texture[0]);
-        glTexImage2D (GL_TEXTURE_2D, 0, GL_LUMINANCE,
-            stride_width,
-            GST_VIDEO_FRAME_COMP_HEIGHT (&vframe, 0),
-            0, GL_LUMINANCE, GL_UNSIGNED_BYTE,
-            GST_VIDEO_FRAME_COMP_DATA (&vframe, 0));
+      glBindTexture (GL_TEXTURE_2D, eglglessink->eglglesctx.texture[0]);
+      glTexImage2D (GL_TEXTURE_2D, 0, GL_LUMINANCE,
+          stride_width,
+          GST_VIDEO_FRAME_COMP_HEIGHT (&vframe, 0),
+          0, GL_LUMINANCE, GL_UNSIGNED_BYTE,
+          GST_VIDEO_FRAME_COMP_DATA (&vframe, 0));
 
 
-        stride = GST_VIDEO_FRAME_PLANE_STRIDE (&vframe, 1);
-        stride_width = c_w = GST_VIDEO_FRAME_COMP_WIDTH (&vframe, 1);
+      stride = GST_VIDEO_FRAME_PLANE_STRIDE (&vframe, 1);
+      stride_width = c_w = GST_VIDEO_FRAME_COMP_WIDTH (&vframe, 1);
 
-        glActiveTexture (GL_TEXTURE1);
+      glActiveTexture (GL_TEXTURE1);
+
+      if (GST_ROUND_UP_8 (c_w) == stride) {
+        glPixelStorei (GL_UNPACK_ALIGNMENT, 8);
+      } else if (GST_ROUND_UP_4 (c_w) == stride) {
+        glPixelStorei (GL_UNPACK_ALIGNMENT, 4);
+      } else if (GST_ROUND_UP_2 (c_w) == stride) {
+        glPixelStorei (GL_UNPACK_ALIGNMENT, 2);
+      } else if (c_w == stride) {
+        glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
+      } else {
+        stride_width = stride;
 
-        if (GST_ROUND_UP_8 (c_w) == stride) {
+        if (GST_ROUND_UP_8 (stride_width) == stride) {
           glPixelStorei (GL_UNPACK_ALIGNMENT, 8);
-        } else if (GST_ROUND_UP_4 (c_w) == stride) {
+        } else if (GST_ROUND_UP_4 (stride_width) == stride) {
           glPixelStorei (GL_UNPACK_ALIGNMENT, 4);
-        } else if (GST_ROUND_UP_2 (c_w) == stride) {
+        } else if (GST_ROUND_UP_2 (stride_width) == stride) {
           glPixelStorei (GL_UNPACK_ALIGNMENT, 2);
-        } else if (c_w == stride) {
+        } else if (stride_width == stride) {
           glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
         } else {
-          stride_width = stride;
-
-          if (GST_ROUND_UP_8 (stride_width) == stride) {
-            glPixelStorei (GL_UNPACK_ALIGNMENT, 8);
-          } else if (GST_ROUND_UP_4 (stride_width) == stride) {
-            glPixelStorei (GL_UNPACK_ALIGNMENT, 4);
-          } else if (GST_ROUND_UP_2 (stride_width) == stride) {
-            glPixelStorei (GL_UNPACK_ALIGNMENT, 2);
-          } else if (stride_width == stride) {
-            glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
-          } else {
-            GST_ERROR_OBJECT (eglglessink, "Unsupported stride %d", stride);
-            goto HANDLE_ERROR;
-          }
-        }
-        if (got_gl_error ("glPixelStorei"))
+          GST_ERROR_OBJECT (eglglessink, "Unsupported stride %d", stride);
           goto HANDLE_ERROR;
+        }
+      }
+      if (got_gl_error ("glPixelStorei"))
+        goto HANDLE_ERROR;
+
+      eglglessink->stride[1] = ((gdouble) stride_width) / ((gdouble) c_w);
 
-        eglglessink->stride[1] = ((gdouble) stride_width) / ((gdouble) c_w);
+      glBindTexture (GL_TEXTURE_2D, eglglessink->eglglesctx.texture[1]);
+      glTexImage2D (GL_TEXTURE_2D, 0, GL_LUMINANCE,
+          stride_width,
+          GST_VIDEO_FRAME_COMP_HEIGHT (&vframe, 1),
+          0, GL_LUMINANCE, GL_UNSIGNED_BYTE,
+          GST_VIDEO_FRAME_COMP_DATA (&vframe, 1));
 
-        glBindTexture (GL_TEXTURE_2D, eglglessink->eglglesctx.texture[1]);
-        glTexImage2D (GL_TEXTURE_2D, 0, GL_LUMINANCE,
-            stride_width,
-            GST_VIDEO_FRAME_COMP_HEIGHT (&vframe, 1),
-            0, GL_LUMINANCE, GL_UNSIGNED_BYTE,
-            GST_VIDEO_FRAME_COMP_DATA (&vframe, 1));
 
+      stride = GST_VIDEO_FRAME_PLANE_STRIDE (&vframe, 2);
+      stride_width = c_w = GST_VIDEO_FRAME_COMP_WIDTH (&vframe, 2);
 
-        stride = GST_VIDEO_FRAME_PLANE_STRIDE (&vframe, 2);
-        stride_width = c_w = GST_VIDEO_FRAME_COMP_WIDTH (&vframe, 2);
+      glActiveTexture (GL_TEXTURE2);
 
-        glActiveTexture (GL_TEXTURE2);
+      if (GST_ROUND_UP_8 (c_w) == stride) {
+        glPixelStorei (GL_UNPACK_ALIGNMENT, 8);
+      } else if (GST_ROUND_UP_4 (c_w) == stride) {
+        glPixelStorei (GL_UNPACK_ALIGNMENT, 4);
+      } else if (GST_ROUND_UP_2 (c_w) == stride) {
+        glPixelStorei (GL_UNPACK_ALIGNMENT, 2);
+      } else if (c_w == stride) {
+        glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
+      } else {
+        stride_width = stride;
 
-        if (GST_ROUND_UP_8 (c_w) == stride) {
+        if (GST_ROUND_UP_8 (stride_width) == stride) {
           glPixelStorei (GL_UNPACK_ALIGNMENT, 8);
-        } else if (GST_ROUND_UP_4 (c_w) == stride) {
+        } else if (GST_ROUND_UP_4 (stride_width) == stride) {
           glPixelStorei (GL_UNPACK_ALIGNMENT, 4);
-        } else if (GST_ROUND_UP_2 (c_w) == stride) {
+        } else if (GST_ROUND_UP_2 (stride_width) == stride) {
           glPixelStorei (GL_UNPACK_ALIGNMENT, 2);
-        } else if (c_w == stride) {
+        } else if (stride_width == stride) {
           glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
         } else {
-          stride_width = stride;
-
-          if (GST_ROUND_UP_8 (stride_width) == stride) {
-            glPixelStorei (GL_UNPACK_ALIGNMENT, 8);
-          } else if (GST_ROUND_UP_4 (stride_width) == stride) {
-            glPixelStorei (GL_UNPACK_ALIGNMENT, 4);
-          } else if (GST_ROUND_UP_2 (stride_width) == stride) {
-            glPixelStorei (GL_UNPACK_ALIGNMENT, 2);
-          } else if (stride_width == stride) {
-            glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
-          } else {
-            GST_ERROR_OBJECT (eglglessink, "Unsupported stride %d", stride);
-            goto HANDLE_ERROR;
-          }
-        }
-        if (got_gl_error ("glPixelStorei"))
+          GST_ERROR_OBJECT (eglglessink, "Unsupported stride %d", stride);
           goto HANDLE_ERROR;
+        }
+      }
+      if (got_gl_error ("glPixelStorei"))
+        goto HANDLE_ERROR;
 
-        eglglessink->stride[2] = ((gdouble) stride_width) / ((gdouble) c_w);
+      eglglessink->stride[2] = ((gdouble) stride_width) / ((gdouble) c_w);
 
-        glBindTexture (GL_TEXTURE_2D, eglglessink->eglglesctx.texture[2]);
-        glTexImage2D (GL_TEXTURE_2D, 0, GL_LUMINANCE,
-            stride_width,
-            GST_VIDEO_FRAME_COMP_HEIGHT (&vframe, 2),
-            0, GL_LUMINANCE, GL_UNSIGNED_BYTE,
-            GST_VIDEO_FRAME_COMP_DATA (&vframe, 2));
-        break;
-      }
-      case GST_VIDEO_FORMAT_NV12:
-      case GST_VIDEO_FORMAT_NV21:{
-        gint stride;
-        gint stride_width;
-        gint c_w;
+      glBindTexture (GL_TEXTURE_2D, eglglessink->eglglesctx.texture[2]);
+      glTexImage2D (GL_TEXTURE_2D, 0, GL_LUMINANCE,
+          stride_width,
+          GST_VIDEO_FRAME_COMP_HEIGHT (&vframe, 2),
+          0, GL_LUMINANCE, GL_UNSIGNED_BYTE,
+          GST_VIDEO_FRAME_COMP_DATA (&vframe, 2));
+      break;
+    }
+    case GST_VIDEO_FORMAT_NV12:
+    case GST_VIDEO_FORMAT_NV21:{
+      gint stride;
+      gint stride_width;
+      gint c_w;
 
-        stride = GST_VIDEO_FRAME_PLANE_STRIDE (&vframe, 0);
-        stride_width = c_w = GST_VIDEO_FRAME_COMP_WIDTH (&vframe, 0);
+      stride = GST_VIDEO_FRAME_PLANE_STRIDE (&vframe, 0);
+      stride_width = c_w = GST_VIDEO_FRAME_COMP_WIDTH (&vframe, 0);
 
-        glActiveTexture (GL_TEXTURE0);
+      glActiveTexture (GL_TEXTURE0);
+
+      if (GST_ROUND_UP_8 (c_w) == stride) {
+        glPixelStorei (GL_UNPACK_ALIGNMENT, 8);
+      } else if (GST_ROUND_UP_4 (c_w) == stride) {
+        glPixelStorei (GL_UNPACK_ALIGNMENT, 4);
+      } else if (GST_ROUND_UP_2 (c_w) == stride) {
+        glPixelStorei (GL_UNPACK_ALIGNMENT, 2);
+      } else if (c_w == stride) {
+        glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
+      } else {
+        stride_width = stride;
 
-        if (GST_ROUND_UP_8 (c_w) == stride) {
+        if (GST_ROUND_UP_8 (stride_width) == stride) {
           glPixelStorei (GL_UNPACK_ALIGNMENT, 8);
-        } else if (GST_ROUND_UP_4 (c_w) == stride) {
+        } else if (GST_ROUND_UP_4 (stride_width) == stride) {
           glPixelStorei (GL_UNPACK_ALIGNMENT, 4);
-        } else if (GST_ROUND_UP_2 (c_w) == stride) {
+        } else if (GST_ROUND_UP_2 (stride_width) == stride) {
           glPixelStorei (GL_UNPACK_ALIGNMENT, 2);
-        } else if (c_w == stride) {
+        } else if (stride_width == stride) {
           glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
         } else {
-          stride_width = stride;
-
-          if (GST_ROUND_UP_8 (stride_width) == stride) {
-            glPixelStorei (GL_UNPACK_ALIGNMENT, 8);
-          } else if (GST_ROUND_UP_4 (stride_width) == stride) {
-            glPixelStorei (GL_UNPACK_ALIGNMENT, 4);
-          } else if (GST_ROUND_UP_2 (stride_width) == stride) {
-            glPixelStorei (GL_UNPACK_ALIGNMENT, 2);
-          } else if (stride_width == stride) {
-            glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
-          } else {
-            GST_ERROR_OBJECT (eglglessink, "Unsupported stride %d", stride);
-            goto HANDLE_ERROR;
-          }
-        }
-        if (got_gl_error ("glPixelStorei"))
+          GST_ERROR_OBJECT (eglglessink, "Unsupported stride %d", stride);
           goto HANDLE_ERROR;
+        }
+      }
+      if (got_gl_error ("glPixelStorei"))
+        goto HANDLE_ERROR;
 
-        eglglessink->stride[0] = ((gdouble) stride_width) / ((gdouble) c_w);
+      eglglessink->stride[0] = ((gdouble) stride_width) / ((gdouble) c_w);
 
-        glBindTexture (GL_TEXTURE_2D, eglglessink->eglglesctx.texture[0]);
-        glTexImage2D (GL_TEXTURE_2D, 0, GL_LUMINANCE,
-            stride_width,
-            GST_VIDEO_FRAME_COMP_HEIGHT (&vframe, 0),
-            0, GL_LUMINANCE, GL_UNSIGNED_BYTE,
-            GST_VIDEO_FRAME_PLANE_DATA (&vframe, 0));
+      glBindTexture (GL_TEXTURE_2D, eglglessink->eglglesctx.texture[0]);
+      glTexImage2D (GL_TEXTURE_2D, 0, GL_LUMINANCE,
+          stride_width,
+          GST_VIDEO_FRAME_COMP_HEIGHT (&vframe, 0),
+          0, GL_LUMINANCE, GL_UNSIGNED_BYTE,
+          GST_VIDEO_FRAME_PLANE_DATA (&vframe, 0));
 
 
-        stride = GST_VIDEO_FRAME_PLANE_STRIDE (&vframe, 1);
-        stride_width = c_w = GST_VIDEO_FRAME_COMP_WIDTH (&vframe, 1);
+      stride = GST_VIDEO_FRAME_PLANE_STRIDE (&vframe, 1);
+      stride_width = c_w = GST_VIDEO_FRAME_COMP_WIDTH (&vframe, 1);
 
-        glActiveTexture (GL_TEXTURE1);
+      glActiveTexture (GL_TEXTURE1);
+
+      if (GST_ROUND_UP_8 (c_w * 2) == stride) {
+        glPixelStorei (GL_UNPACK_ALIGNMENT, 8);
+      } else if (GST_ROUND_UP_4 (c_w * 2) == stride) {
+        glPixelStorei (GL_UNPACK_ALIGNMENT, 4);
+      } else if (c_w * 2 == stride) {
+        glPixelStorei (GL_UNPACK_ALIGNMENT, 2);
+      } else {
+        stride_width = stride / 2;
 
-        if (GST_ROUND_UP_8 (c_w * 2) == stride) {
+        if (GST_ROUND_UP_8 (stride_width * 2) == stride) {
           glPixelStorei (GL_UNPACK_ALIGNMENT, 8);
-        } else if (GST_ROUND_UP_4 (c_w * 2) == stride) {
+        } else if (GST_ROUND_UP_4 (stride_width * 2) == stride) {
           glPixelStorei (GL_UNPACK_ALIGNMENT, 4);
-        } else if (c_w * 2 == stride) {
+        } else if (stride_width * 2 == stride) {
           glPixelStorei (GL_UNPACK_ALIGNMENT, 2);
         } else {
-          stride_width = stride / 2;
-
-          if (GST_ROUND_UP_8 (stride_width * 2) == stride) {
-            glPixelStorei (GL_UNPACK_ALIGNMENT, 8);
-          } else if (GST_ROUND_UP_4 (stride_width * 2) == stride) {
-            glPixelStorei (GL_UNPACK_ALIGNMENT, 4);
-          } else if (stride_width * 2 == stride) {
-            glPixelStorei (GL_UNPACK_ALIGNMENT, 2);
-          } else {
-            GST_ERROR_OBJECT (eglglessink, "Unsupported stride %d", stride);
-            goto HANDLE_ERROR;
-          }
-        }
-        if (got_gl_error ("glPixelStorei"))
+          GST_ERROR_OBJECT (eglglessink, "Unsupported stride %d", stride);
           goto HANDLE_ERROR;
+        }
+      }
+      if (got_gl_error ("glPixelStorei"))
+        goto HANDLE_ERROR;
 
-        eglglessink->stride[1] = ((gdouble) stride_width) / ((gdouble) c_w);
+      eglglessink->stride[1] = ((gdouble) stride_width) / ((gdouble) c_w);
 
-        glBindTexture (GL_TEXTURE_2D, eglglessink->eglglesctx.texture[1]);
-        glTexImage2D (GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA,
-            stride_width,
-            GST_VIDEO_FRAME_COMP_HEIGHT (&vframe, 1),
-            0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE,
-            GST_VIDEO_FRAME_PLANE_DATA (&vframe, 1));
-        break;
-      }
-      default:
-        g_assert_not_reached ();
-        break;
+      glBindTexture (GL_TEXTURE_2D, eglglessink->eglglesctx.texture[1]);
+      glTexImage2D (GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA,
+          stride_width,
+          GST_VIDEO_FRAME_COMP_HEIGHT (&vframe, 1),
+          0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE,
+          GST_VIDEO_FRAME_PLANE_DATA (&vframe, 1));
+      break;
     }
+    default:
+      g_assert_not_reached ();
+      break;
   }
 
   if (got_gl_error ("glTexImage2D"))
@@ -2048,8 +2027,6 @@ gst_eglglessink_upload (GstEglGlesSink * eglglessink, GstBuffer * buf)
   if (!buf) {
     GST_DEBUG_OBJECT (eglglessink, "Rendering previous buffer again");
   } else if (buf) {
-    GstMemory *mem;
-
     crop = gst_buffer_get_video_crop_meta (buf);
 
     if (gst_eglglessink_crop_changed (eglglessink, crop)) {
@@ -2065,12 +2042,27 @@ gst_eglglessink_upload (GstEglGlesSink * eglglessink, GstBuffer * buf)
         eglglessink->crop.h = eglglessink->configured_info.height;
       }
       eglglessink->crop_changed = TRUE;
-  >>>>>>>ebe5849 ... eglglessink:Always use an RGBA configuration}
+    }
 
-    if (got_gl_error ("glTexImage2D"))
+    if (!gst_eglglessink_fill_texture (eglglessink, buf))
       goto HANDLE_ERROR;
   }
 
+  return GST_FLOW_OK;
+
+HANDLE_ERROR:
+  {
+    GST_ERROR_OBJECT (eglglessink, "Failed to upload texture");
+    return GST_FLOW_ERROR;
+  }
+}
+
+static GstFlowReturn
+gst_eglglessink_render (GstEglGlesSink * eglglessink)
+{
+  guint dar_n, dar_d;
+  gint i;
+
   /* If no one has set a display rectangle on us initialize
    * a sane default. According to the docs on the xOverlay
    * interface we are supposed to fill the overlay 100%. We
@@ -2081,7 +2073,7 @@ gst_eglglessink_upload (GstEglGlesSink * eglglessink, GstBuffer * buf)
   if (gst_eglglessink_update_surface_dimensions (eglglessink) ||
       eglglessink->render_region_changed ||
       !eglglessink->display_region.w || !eglglessink->display_region.h ||
-      gst_eglglessink_crop_changed (eglglessink, crop)) {
+      eglglessink->crop_changed) {
     GST_OBJECT_LOCK (eglglessink);
 
     if (!eglglessink->render_region_user) {
@@ -2091,18 +2083,7 @@ gst_eglglessink_upload (GstEglGlesSink * eglglessink, GstBuffer * buf)
       eglglessink->render_region.h = eglglessink->eglglesctx.surface_height;
     }
     eglglessink->render_region_changed = FALSE;
-
-    if (crop) {
-      eglglessink->crop.x = crop->x;
-      eglglessink->crop.y = crop->y;
-      eglglessink->crop.w = crop->width;
-      eglglessink->crop.h = crop->height;
-    } else if (buf) {
-      eglglessink->crop.x = 0;
-      eglglessink->crop.y = 0;
-      eglglessink->crop.w = eglglessink->configured_info.width;
-      eglglessink->crop.h = eglglessink->configured_info.height;
-    }
+    eglglessink->crop_changed = FALSE;
 
     if (!eglglessink->force_aspect_ratio) {
       eglglessink->display_region.x = 0;
@@ -2210,13 +2191,6 @@ gst_eglglessink_upload (GstEglGlesSink * eglglessink, GstBuffer * buf)
       eglglessink->stride[2], 1);
 
   for (i = 0; i < eglglessink->eglglesctx.n_textures; i++) {
-    if (i == 0)
-      glActiveTexture (GL_TEXTURE0);
-    else if (i == 1)
-      glActiveTexture (GL_TEXTURE1);
-    else if (i == 2)
-      glActiveTexture (GL_TEXTURE2);
-
     glUniform1i (eglglessink->eglglesctx.tex_loc[0][i], i);
     if (got_gl_error ("glUniform1i"))
       goto HANDLE_ERROR;
@@ -2227,8 +2201,8 @@ gst_eglglessink_upload (GstEglGlesSink * eglglessink, GstBuffer * buf)
   if (got_gl_error ("glVertexAttribPointer"))
     goto HANDLE_ERROR;
 
-  glVertexAttribPointer (eglglessink->eglglesctx.texpos_loc[0], 2, GL_FLOAT,
-      GL_FALSE, sizeof (coord5), (gpointer) (3 * sizeof (gfloat)));
+  glVertexAttribPointer (eglglessink->eglglesctx.texpos_loc[0], 2,
+      GL_FLOAT, GL_FALSE, sizeof (coord5), (gpointer) (3 * sizeof (gfloat)));
   if (got_gl_error ("glVertexAttribPointer"))
     goto HANDLE_ERROR;
 
@@ -2243,16 +2217,12 @@ gst_eglglessink_upload (GstEglGlesSink * eglglessink, GstBuffer * buf)
     goto HANDLE_ERROR;
   }
 
-  if (buf)
-    gst_video_frame_unmap (&vframe);
 
   GST_DEBUG_OBJECT (eglglessink, "Succesfully rendered 1 frame");
   return GST_FLOW_OK;
 
 HANDLE_ERROR:
   GST_ERROR_OBJECT (eglglessink, "Rendering disabled for this frame");
-  if (vframe.buffer)
-    gst_video_frame_unmap (&vframe);
 
   return GST_FLOW_ERROR;
 }
@@ -2606,7 +2576,7 @@ gst_eglglessink_class_init (GstEglGlesSinkClass * klass)
 }
 
 static gboolean
-queue_check_full_func (GstDataQueue * queue, guint visible, guint bytes,
+queue_check_full_func (EGLGstDataQueue * queue, guint visible, guint bytes,
     guint64 time, gpointer checkdata)
 {
   return visible != 0;
@@ -2632,7 +2602,7 @@ gst_eglglessink_init (GstEglGlesSink * eglglessink)
   g_mutex_init (&eglglessink->render_lock);
   g_cond_init (&eglglessink->render_cond);
   eglglessink->queue =
-      gst_data_queue_new (queue_check_full_func, NULL, NULL, NULL);
+      egl_gst_data_queue_new (queue_check_full_func, NULL, NULL, NULL);
   eglglessink->last_flow = GST_FLOW_FLUSHING;
 
   eglglessink->render_region.x = 0;
index e3d70873df9cab1bcabd9ec3e570f9d1b3496b34..88a5b4658e42ee60c03d809d3815d09d8ee5780b 100644 (file)
@@ -49,7 +49,7 @@
 #include <gst/gst.h>
 #include <gst/video/video.h>
 #include <gst/video/gstvideosink.h>
-#include <gst/base/gstdataqueue.h>
+#include "gstdataqueue.h"
 
 #include <EGL/egl.h>
 #include <EGL/eglext.h>
@@ -121,9 +121,9 @@ struct _GstEglGlesRenderContext
   EGLNativeWindowType window, used_window;
   EGLSurface surface;
   gboolean buffer_preserved;
-  GLuint fragshader[3]; /* frame, border, frame-platform */
-  GLuint vertshader[3]; /* frame, border, frame-platform */
-  GLuint glslprogram[3]; /* frame, border, frame-platform */
+  GLuint fragshader[2]; /* frame, border */
+  GLuint vertshader[2]; /* frame, border */
+  GLuint glslprogram[2]; /* frame, border */
   GLuint texture[3]; /* RGB/Y, U/UV, V */
   EGLint surface_width;
   EGLint surface_height;
@@ -132,10 +132,10 @@ struct _GstEglGlesRenderContext
   gint n_textures;
 
   /* shader vars */
-  GLuint position_loc[3]; /* frame, border, frame-platform */
-  GLuint texpos_loc[2]; /* frame, frame-platform */
-  GLuint tex_scale_loc[2][3]; /* [frame, frame-platform] RGB/Y, U/UV, V */
-  GLuint tex_loc[2][3]; /* [frame, frame-platform] RGB/Y, U/UV, V */
+  GLuint position_loc[2]; /* frame, border */
+  GLuint texpos_loc[1]; /* frame */
+  GLuint tex_scale_loc[1][3]; /* [frame] RGB/Y, U/UV, V */
+  GLuint tex_loc[1][3]; /* [frame] RGB/Y, U/UV, V */
   coord5 position_array[12];    /* 4 x Frame, 4 x Border1, 4 x Border2 */
   unsigned short index_array[4];
   unsigned int position_buffer, index_buffer;
@@ -176,6 +176,7 @@ struct _GstEglGlesSink
   GstVideoRectangle display_region;
 
   GstVideoRectangle crop;
+  gboolean crop_changed;
   GstCaps *sinkcaps;
   GstCaps *current_caps, *configured_caps;
   GstVideoInfo configured_info;
@@ -195,7 +196,7 @@ struct _GstEglGlesSink
 
   GThread *thread;
   gboolean thread_running;
-  GstDataQueue *queue;
+  EGLGstDataQueue *queue;
   GCond render_cond;
   GMutex render_lock;
   GstFlowReturn last_flow;
diff --git a/ext/eglgles/gstqueuearray.c b/ext/eglgles/gstqueuearray.c
new file mode 100644 (file)
index 0000000..55476a9
--- /dev/null
@@ -0,0 +1,341 @@
+/* GStreamer
+ * Copyright (C) 2009 Edward Hervey <bilboed@bilboed.com>
+ *
+ * gstqueuearray.c:
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * SECTION:gstqueuearray
+ * @short_description: Array based queue object
+ *
+ * #EGLGstQueueArray is an object that provides standard queue functionality
+ * based on an array instead of linked lists. This reduces the overhead
+ * caused by memory managment by a large factor.
+ */
+
+
+#include <string.h>
+#include <gst/gst.h>
+#include "gstqueuearray.h"
+
+struct _EGLGstQueueArray
+{
+  /* < private > */
+  gpointer *array;
+  guint size;
+  guint head;
+  guint tail;
+  guint length;
+};
+
+/**
+ * egl_gst_queue_array_new:
+ * @initial_size: Initial size of the new queue
+ *
+ * Allocates a new #EGLGstQueueArray object with an initial
+ * queue size of @initial_size.
+ *
+ * Returns: a new #EGLGstQueueArray object
+ *
+ * Since: 1.2.0
+ */
+EGLGstQueueArray *
+egl_gst_queue_array_new (guint initial_size)
+{
+  EGLGstQueueArray *array;
+
+  array = g_slice_new (EGLGstQueueArray);
+  array->size = initial_size;
+  array->array = g_new0 (gpointer, initial_size);
+  array->head = 0;
+  array->tail = 0;
+  array->length = 0;
+  return array;
+}
+
+
+/**
+ * egl_gst_queue_array_free:
+ * @array: a #EGLGstQueueArray object
+ *
+ * Frees queue @array and all memory associated to it.
+ *
+ * Since: 1.2.0
+ */
+void
+egl_gst_queue_array_free (EGLGstQueueArray * array)
+{
+  g_free (array->array);
+  g_slice_free (EGLGstQueueArray, array);
+}
+
+/**
+ * egl_gst_queue_array_pop_head:
+ * @array: a #EGLGstQueueArray object
+ *
+ * Returns and head of the queue @array and removes
+ * it from the queue.
+ *
+ * Returns: The head of the queue
+ *
+ * Since: 1.2.0
+ */
+gpointer
+egl_gst_queue_array_pop_head (EGLGstQueueArray * array)
+{
+  gpointer ret;
+
+  /* empty array */
+  if (G_UNLIKELY (array->length == 0))
+    return NULL;
+  ret = array->array[array->head];
+  array->head++;
+  array->head %= array->size;
+  array->length--;
+  return ret;
+}
+
+/**
+ * egl_gst_queue_array_pop_head:
+ * @array: a #EGLGstQueueArray object
+ *
+ * Returns and head of the queue @array and does not
+ * remove it from the queue.
+ *
+ * Returns: The head of the queue
+ *
+ * Since: 1.2.0
+ */
+gpointer
+egl_gst_queue_array_peek_head (EGLGstQueueArray * array)
+{
+  /* empty array */
+  if (G_UNLIKELY (array->length == 0))
+    return NULL;
+  return array->array[array->head];
+}
+
+/**
+ * egl_gst_queue_array_push_tail:
+ * @array: a #EGLGstQueueArray object
+ * @data: object to push
+ *
+ * Pushes @data to the tail of the queue @array.
+ *
+ * Since: 1.2.0
+ */
+void
+egl_gst_queue_array_push_tail (EGLGstQueueArray * array, gpointer data)
+{
+  /* Check if we need to make room */
+  if (G_UNLIKELY (array->length == array->size)) {
+    /* newsize is 50% bigger */
+    guint newsize = (3 * array->size) / 2;
+
+    /* copy over data */
+    if (array->tail != 0) {
+      gpointer *array2 = g_new0 (gpointer, newsize);
+      guint t1 = array->head;
+      guint t2 = array->size - array->head;
+
+      /* [0-----TAIL][HEAD------SIZE]
+       *
+       * We want to end up with
+       * [HEAD------------------TAIL][----FREEDATA------NEWSIZE]
+       *
+       * 1) move [HEAD-----SIZE] part to beginning of new array
+       * 2) move [0-------TAIL] part new array, after previous part
+       */
+
+      memcpy (array2, &array->array[array->head], t2 * sizeof (gpointer));
+      memcpy (&array2[t2], array->array, t1 * sizeof (gpointer));
+
+      g_free (array->array);
+      array->array = array2;
+      array->head = 0;
+    } else {
+      /* Fast path, we just need to grow the array */
+      array->array = g_renew (gpointer, array->array, newsize);
+    }
+    array->tail = array->size;
+    array->size = newsize;
+  }
+
+  array->array[array->tail] = data;
+  array->tail++;
+  array->tail %= array->size;
+  array->length++;
+}
+
+/**
+ * egl_gst_queue_array_is_empty:
+ * @array: a #EGLGstQueueArray object
+ *
+ * Checks if the queue @array is empty.
+ *
+ * Returns: %TRUE if the queue @array is empty
+ *
+ * Since: 1.2.0
+ */
+gboolean
+egl_gst_queue_array_is_empty (EGLGstQueueArray * array)
+{
+  return (array->length == 0);
+}
+
+/**
+ * egl_gst_queue_array_drop_element:
+ * @array: a #EGLGstQueueArray object
+ * @idx: index to drop
+ *
+ * Drops the queue element at position @idx from queue @array.
+ *
+ * Returns: the dropped element
+ *
+ * Since: 1.2.0
+ */
+gpointer
+egl_gst_queue_array_drop_element (EGLGstQueueArray * array, guint idx)
+{
+  int first_item_index, last_item_index;
+  gpointer element;
+
+  g_return_val_if_fail (array->length > 0, NULL);
+  g_return_val_if_fail (idx < array->size, NULL);
+
+  first_item_index = array->head;
+
+  /* tail points to the first free spot */
+  last_item_index = (array->tail - 1 + array->size) % array->size;
+
+  element = array->array[idx];
+
+  /* simple case idx == first item */
+  if (idx == first_item_index) {
+    /* move the head plus one */
+    array->head++;
+    array->head %= array->size;
+    array->length--;
+    return element;
+  }
+
+  /* simple case idx == last item */
+  if (idx == last_item_index) {
+    /* move tail minus one, potentially wrapping */
+    array->tail = (array->tail - 1 + array->size) % array->size;
+    array->length--;
+    return element;
+  }
+
+  /* non-wrapped case */
+  if (first_item_index < last_item_index) {
+    g_assert (first_item_index < idx && idx < last_item_index);
+    /* move everything beyond idx one step towards zero in array */
+    memmove (&array->array[idx],
+        &array->array[idx + 1], (last_item_index - idx) * sizeof (gpointer));
+    /* tail might wrap, ie if tail == 0 (and last_item_index == size) */
+    array->tail = (array->tail - 1 + array->size) % array->size;
+    array->length--;
+    return element;
+  }
+
+  /* only wrapped cases left */
+  g_assert (first_item_index > last_item_index);
+
+  if (idx < last_item_index) {
+    /* idx is before last_item_index, move data towards zero */
+    memmove (&array->array[idx],
+        &array->array[idx + 1], (last_item_index - idx) * sizeof (gpointer));
+    /* tail should not wrap in this case! */
+    g_assert (array->tail > 0);
+    array->tail--;
+    array->length--;
+    return element;
+  }
+
+  if (idx > first_item_index) {
+    element = array->array[idx];
+    /* idx is after first_item_index, move data to higher indices */
+    memmove (&array->array[first_item_index + 1],
+        &array->array[first_item_index],
+        (idx - first_item_index) * sizeof (gpointer));
+    array->head++;
+    /* head should not wrap in this case! */
+    g_assert (array->head < array->size);
+    array->length--;
+    return element;
+  }
+
+  g_return_val_if_reached (NULL);
+}
+
+/**
+ * egl_gst_queue_array_find:
+ * @array: a #EGLGstQueueArray object
+ * @func: (allow-none): comparison function, or %NULL to find @data by value
+ * @data: data for comparison function
+ *
+ * Finds an element in the queue @array, either by comparing every element
+ * with @func or by looking up @data if no compare function @func is provided,
+ * and returning the index of the found element.
+ *
+ * Note that the index is not 0-based, but an internal index number with a
+ * random offset. The index can be used in connection with
+ * egl_gst_queue_array_drop_element(). FIXME: return index 0-based and make
+ * _drop_element() take a 0-based index.
+ *
+ * Returns: Index of the found element or -1 if nothing was found.
+ *
+ * Since: 1.2.0
+ */
+guint
+egl_gst_queue_array_find (EGLGstQueueArray * array, GCompareFunc func, gpointer data)
+{
+  guint i;
+
+  if (func != NULL) {
+    /* Scan from head to tail */
+    for (i = 0; i < array->length; i++) {
+      if (func (array->array[(i + array->head) % array->size], data) == 0)
+        return (i + array->head) % array->size;
+    }
+  } else {
+    for (i = 0; i < array->length; i++) {
+      if (array->array[(i + array->head) % array->size] == data)
+        return (i + array->head) % array->size;
+    }
+  }
+
+  return -1;
+}
+
+/**
+ * egl_gst_queue_array_get_length:
+ * @array: a #EGLGstQueueArray object
+ *
+ * Returns the length of the queue @array
+ *
+ * Returns: the length of the queue @array.
+ *
+ * Since: 1.2.0
+ */
+guint
+egl_gst_queue_array_get_length (EGLGstQueueArray * array)
+{
+  return array->length;
+}
diff --git a/ext/eglgles/gstqueuearray.h b/ext/eglgles/gstqueuearray.h
new file mode 100644 (file)
index 0000000..0d04d14
--- /dev/null
@@ -0,0 +1,52 @@
+/* GStreamer
+ * Copyright (C) 2009-2010 Edward Hervey <bilboed@bilboed.com>
+ *
+ * gstqueuearray.h:
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <glib.h>
+
+#ifndef __EGL_GST_QUEUE_ARRAY_H__
+#define __EGL_GST_QUEUE_ARRAY_H__
+
+typedef struct _EGLGstQueueArray EGLGstQueueArray;
+
+G_GNUC_INTERNAL
+EGLGstQueueArray * egl_gst_queue_array_new       (guint initial_size);
+G_GNUC_INTERNAL
+void            egl_gst_queue_array_free      (EGLGstQueueArray * array);
+G_GNUC_INTERNAL
+gpointer        egl_gst_queue_array_pop_head  (EGLGstQueueArray * array);
+G_GNUC_INTERNAL
+gpointer        egl_gst_queue_array_peek_head (EGLGstQueueArray * array);
+G_GNUC_INTERNAL
+void            egl_gst_queue_array_push_tail (EGLGstQueueArray * array,
+                                           gpointer        data);
+G_GNUC_INTERNAL
+gboolean        egl_gst_queue_array_is_empty  (EGLGstQueueArray * array);
+G_GNUC_INTERNAL
+gpointer        egl_gst_queue_array_drop_element (EGLGstQueueArray * array,
+                                              guint           idx);
+G_GNUC_INTERNAL
+guint           egl_gst_queue_array_find (EGLGstQueueArray * array,
+                                      GCompareFunc    func,
+                                      gpointer        data);
+G_GNUC_INTERNAL
+guint           egl_gst_queue_array_get_length (EGLGstQueueArray * array);
+
+#endif
index 735136a5387e6422a514a7bac03cadb4d8173da3..e44b7dbe4cd8e18aaaf8e4bf8df01746bb29b928 100644 (file)
@@ -160,7 +160,6 @@ platform_destroy_native_window (EGLNativeDisplayType display,
   GST_ERROR ("Can't destroy native window");
   return TRUE;
 }
-
 #endif
 
 #ifdef USE_EGL_RPI