+2005-11-29 Thomas Vander Stichele <thomas (at) apestaart (dot) org>
+
+ * check/Makefile.am:
+ * configure.ac:
+ * docs/gst/Makefile.am:
+ * gst/Makefile.am:
+ * gst/base/.cvsignore:
+ * gst/base/Makefile.am:
+ * gst/base/README:
+ * gst/base/gstadapter.c:
+ * gst/base/gstadapter.h:
+ * gst/base/gstbasesink.c:
+ * gst/base/gstbasesink.h:
+ * gst/base/gstbasesrc.c:
+ * gst/base/gstbasesrc.h:
+ * gst/base/gstbasetransform.c:
+ * gst/base/gstbasetransform.h:
+ * gst/base/gstcollectpads.c:
+ * gst/base/gstcollectpads.h:
+ * gst/base/gstpushsrc.c:
+ * gst/base/gstpushsrc.h:
+ * gst/base/gsttypefindhelper.c:
+ * gst/base/gsttypefindhelper.h:
+ * gst/check/Makefile.am:
+ * gst/check/gstcheck.c:
+ * gst/check/gstcheck.h:
+ * gst/net/Makefile.am:
+ * gst/net/gstnet.h:
+ * gst/net/gstnetclientclock.c:
+ * gst/net/gstnetclientclock.h:
+ * gst/net/gstnettimepacket.c:
+ * gst/net/gstnettimepacket.h:
+ * gst/net/gstnettimeprovider.c:
+ * gst/net/gstnettimeprovider.h:
+ * libs/gst/Makefile.am:
+ * libs/gst/base/Makefile.am:
+ * libs/gst/base/gstbasetransform.c:
+ * libs/gst/check/Makefile.am:
+ * plugins/elements/Makefile.am:
+ * po/POTFILES.in:
+ CVS surgery + support to move base, check, and net out of gst
+ and into libs/gst
+
2005-11-29 Andy Wingo <wingo@pobox.com>
* gst/gstevent.h (struct _GstEvent): Only one pointer of padding.
noinst_HEADERS = gst/capslist.h
AM_CFLAGS = $(GST_OBJ_CFLAGS) $(CHECK_CFLAGS)
-LDADD = $(top_builddir)/gst/check/libgstcheck-@GST_MAJORMINOR@.la \
+LDADD = $(top_builddir)/libs/gst/check/libgstcheck-@GST_MAJORMINOR@.la \
$(GST_OBJ_LIBS) \
$(CHECK_LIBS)
$(LDADD)
net_gstnetclientclock_LDADD = \
- $(top_builddir)/gst/net/libgstnet-@GST_MAJORMINOR@.la \
+ $(top_builddir)/libs/gst/net/libgstnet-@GST_MAJORMINOR@.la \
$(LDADD)
net_gstnettimeprovider_LDADD = \
- $(top_builddir)/gst/net/libgstnet-@GST_MAJORMINOR@.la \
+ $(top_builddir)/libs/gst/net/libgstnet-@GST_MAJORMINOR@.la \
$(LDADD)
# valgrind testing
gst/Makefile
gst/gstconfig.h
gst/gstversion.h
-gst/base/Makefile
-gst/check/Makefile
-gst/net/Makefile
gst/parse/Makefile
libs/Makefile
libs/gst/Makefile
+libs/gst/base/Makefile
+libs/gst/check/Makefile
libs/gst/controller/Makefile
libs/gst/dataprotocol/Makefile
+libs/gst/net/Makefile
plugins/Makefile
plugins/indexers/Makefile
plugins/elements/Makefile
# The top-level SGML file. Change it if you want.
DOC_MAIN_SGML_FILE=$(DOC_MODULE)-docs.sgml
-# The directory containing the source code. Relative to $(top_srcdir).
-# gtk-doc will search all .c & .h files beneath here for inline comments
-# documenting functions and macros.
-DOC_SOURCE_DIR=$(top_srcdir)/gst
-DOC_BUILD_DIR=$(top_builddir)/gst
-
# Extra options to supply to gtkdoc-scan.
SCAN_OPTIONS=--deprecated-guards="GST_DISABLE_DEPRECATED"
# Extra options to supply to gtkdoc-fixref.
FIXXREF_OPTIONS=
-# Used for dependencies.
-HFILE_GLOB=$(DOC_SOURCE_DIR)/*.h
-CFILE_GLOB=$(DOC_SOURCE_DIR)/*.c
+# The files containing the source code. Relative to $(top_srcdir).
+# gtk-doc will search all .c & .h files beneath here for inline comments
+# documenting functions and macros.
+DOC_SOURCE_DIR = $(top_srcdir)/gst
+DOC_BUILD_DIR = $(top_builddir)/gst
+
+HFILE_GLOB=$(top_srcdir)/gst/*.h $(top_srcdir)/libs/gst/*/*.h
+CFILE_GLOB=$(top_srcdir)/gst/*.c $(top_srcdir)/libs/gst/*/*.c
# Dependencies for the intermediate scanobj tool
#SCANOBJ_DEPS = $(top_builddir)/gst/elements/libgstelements.la \
# $(top_builddir)/gst/schedulers/libgstbasicomegascheduler.la
SCANOBJ_DEPS = \
$(top_builddir)/plugins/elements/libgstelements.la \
- $(top_builddir)/gst/base/libgstbase-@GST_MAJORMINOR@.la \
- $(top_builddir)/gst/net/libgstnet-@GST_MAJORMINOR@.la
+ $(top_builddir)/libs/gst/base/libgstbase-@GST_MAJORMINOR@.la \
+ $(top_builddir)/libs/gst/net/libgstnet-@GST_MAJORMINOR@.la
# Header files to ignore when scanning. Use base file name, no paths
IGNORE_HFILES= \
lib_LTLIBRARIES = libgstreamer-@GST_MAJORMINOR@.la
-if HAVE_CHECK
-SUBDIRS_CHECK = check
-else
-SUBDIRS_CHECK =
-endif
-
if GST_DISABLE_LOADSAVE
GST_LOADSAVE_SRC =
else
GST_URI_SRC = gsturi.c
endif
-if GST_DISABLE_NET
-SUBDIRS_NET =
-else
-if HAVE_SYS_SOCKET_H
-SUBDIRS_NET = net
-else
-SUBDIRS_NET =
-endif
-endif
-
-SUBDIRS = \
- $(SUBDIRS_PARSE) \
- . \
- base \
- $(SUBDIRS_NET) \
- $(SUBDIRS_CHECK)
+SUBDIRS = $(SUBDIRS_PARSE)
-DIST_SUBDIRS = base parse net check
+DIST_SUBDIRS = parse
# make variables for all generated source and header files to make the
# distinction clear
+++ /dev/null
-lib_LTLIBRARIES = libgstbase-@GST_MAJORMINOR@.la
-
-libgstbase_@GST_MAJORMINOR@_la_DEPENDENCIES = \
- ../libgstreamer-@GST_MAJORMINOR@.la
-libgstbase_@GST_MAJORMINOR@_la_SOURCES = \
- gstadapter.c \
- gstbasesink.c \
- gstbasesrc.c \
- gstbasetransform.c \
- gstcollectpads.c \
- gstpushsrc.c \
- gsttypefindhelper.c
-
-libgstbase_@GST_MAJORMINOR@_la_CFLAGS = $(GST_OBJ_CFLAGS)
-libgstbase_@GST_MAJORMINOR@_la_LIBADD = $(GST_OBJ_LIBS)
-libgstbase_@GST_MAJORMINOR@_la_LDFLAGS = $(GST_LIB_LDFLAGS) $(GST_ALL_LDFLAGS) $(GST_LT_LDFLAGS)
-
-libgstbase_@GST_MAJORMINOR@includedir = \
- $(includedir)/gstreamer-@GST_MAJORMINOR@/gst/base
-
-libgstbase_@GST_MAJORMINOR@include_HEADERS = \
- gstadapter.h \
- gstbasesink.h \
- gstbasesrc.h \
- gstbasetransform.h \
- gstcollectpads.h \
- gstpushsrc.h \
- gsttypefindhelper.h
-
+++ /dev/null
-Base classes
-------------
-
-GstBaseSink
- FIXME: not much point making it operate in pull mode as a generic
- base class I guess...
+++ /dev/null
-/* GStreamer
- * Copyright (C) 2004 Benjamin Otte <otte@gnome.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-/**
- * SECTION:gstadapter
- * @short_description: adapts incoming data on a sink pad into chunks of N bytes
- *
- * This class is for elements that receive buffers in an undesired size.
- * While for example raw video contains one image per buffer, the same is not
- * true for a lot of other formats, especially those that come directly from
- * a file. So if you have undefined buffer sizes and require a specific size,
- * this object is for you.
- *
- * The theory of operation is like this: All buffers received are put
- * into the adapter using gst_adapter_push() and the data is then read back
- * in chunks of the desired size using gst_adapter_peek(). After the data is
- * processed, it is freed using gst_adapter_flush().
- *
- * For example, a sink pad's chain function that needs to pass data to a library
- * in 512-byte chunks could be implemented like this:
- * <programlisting>
- * static GstFlowReturn
- * sink_pad_chain (GstPad *pad, GstBuffer *buffer)
- * {
- * MyElement *this;
- * GstAdapter *adapter;
- * GstFlowReturn ret = GST_FLOW_OK;
- *
- * // will give the element an extra ref; remember to drop it
- * this = MY_ELEMENT (gst_pad_get_parent (pad));
- * adapter = this->adapter;
- *
- * // put buffer into adapter
- * #gst_adapter_push (adapter, buffer);
- * // while we can read out 512 bytes, process them
- * while (#gst_adapter_available (adapter) >= 512 && ret == GST_FLOW_OK) {
- * // use flowreturn as an error value
- * ret = my_library_foo (#gst_adapter_peek (adapter, 512));
- * #gst_adapter_flush (adapter, 512);
- * }
- *
- * gst_object_unref (this);
- * return ret;
- * }
- * </programlisting>
- * For another example, a simple element inside GStreamer that uses GstAdapter
- * is the libvisual element.
- *
- * An element using GstAdapter in its sink pad chain function should ensure that
- * when the FLUSH_STOP event is received, that any queued data is cleared using
- * gst_adapter_clear(). Data should also be cleared or processed on EOS and
- * when changing state from #GST_STATE_PAUSED to #GST_STATE_READY.
- *
- * A last thing to note is that while GstAdapter is pretty optimized,
- * merging buffers still might be an operation that requires a memcpy()
- * operation, and this operation is not the fastest. Because of this, some
- * functions like gst_adapter_available_fast() are provided to help speed up
- * such cases should you want to.
- *
- * GstAdapter is not MT safe. All operations on an adapter must be serialized by
- * the caller. This is not normally a problem, however, as the normal use case
- * of GstAdapter is inside one pad's chain function, in which case access is
- * serialized via the pad's stream lock.
- *
- * Last reviewed on 2005-11-08 (0.9.5).
- */
-
-#include <string.h>
-
-#include "gstadapter.h"
-
-/* default size for the assembled data buffer */
-#define DEFAULT_SIZE 16
-
-GST_DEBUG_CATEGORY_STATIC (gst_adapter_debug);
-#define GST_CAT_DEFAULT gst_adapter_debug
-
-#define _do_init(thing) \
- GST_DEBUG_CATEGORY_INIT (gst_adapter_debug, "adapter", 0, "object to splice and merge buffers to desired size")
-GST_BOILERPLATE_FULL (GstAdapter, gst_adapter, GObject, G_TYPE_OBJECT,
- _do_init);
-
-static void gst_adapter_dispose (GObject * object);
-static void gst_adapter_finalize (GObject * object);
-
-static void
-gst_adapter_base_init (gpointer g_class)
-{
- /* nop */
-}
-
-static void
-gst_adapter_class_init (GstAdapterClass * klass)
-{
- GObjectClass *object = G_OBJECT_CLASS (klass);
-
- object->dispose = gst_adapter_dispose;
- object->finalize = gst_adapter_finalize;
-}
-
-static void
-gst_adapter_init (GstAdapter * adapter, GstAdapterClass * g_class)
-{
- adapter->assembled_data = g_malloc (DEFAULT_SIZE);
- adapter->assembled_size = DEFAULT_SIZE;
-}
-
-static void
-gst_adapter_dispose (GObject * object)
-{
- GstAdapter *adapter = GST_ADAPTER (object);
-
- gst_adapter_clear (adapter);
-
- GST_CALL_PARENT (G_OBJECT_CLASS, dispose, (object));
-}
-
-static void
-gst_adapter_finalize (GObject * object)
-{
- GstAdapter *adapter = GST_ADAPTER (object);
-
- g_free (adapter->assembled_data);
-
- GST_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));
-}
-
-/**
- * gst_adapter_new:
- *
- * Creates a new #GstAdapter.
- *
- * Returns: a new #GstAdapter
- */
-GstAdapter *
-gst_adapter_new (void)
-{
- return g_object_new (GST_TYPE_ADAPTER, NULL);
-}
-
-/**
- * gst_adapter_clear:
- * @adapter: a #GstAdapter
- *
- * Removes all buffers from @adapter.
- */
-void
-gst_adapter_clear (GstAdapter * adapter)
-{
- g_return_if_fail (GST_IS_ADAPTER (adapter));
-
- g_slist_foreach (adapter->buflist, (GFunc) gst_mini_object_unref, NULL);
- g_slist_free (adapter->buflist);
- adapter->buflist = NULL;
- adapter->size = 0;
- adapter->skip = 0;
- adapter->assembled_len = 0;
-}
-
-/**
- * gst_adapter_push:
- * @adapter: a #GstAdapter
- * @buf: a #GstBuffer to add to queue in the adapter
- *
- * Adds the data from @buf to the data stored inside @adapter and takes
- * ownership of the buffer.
- */
-void
-gst_adapter_push (GstAdapter * adapter, GstBuffer * buf)
-{
- g_return_if_fail (GST_IS_ADAPTER (adapter));
- g_return_if_fail (GST_IS_BUFFER (buf));
-
- adapter->size += GST_BUFFER_SIZE (buf);
- adapter->buflist = g_slist_append (adapter->buflist, buf);
-}
-
-/**
- * gst_adapter_peek:
- * @adapter: a #GstAdapter
- * @size: the number of bytes to peek
- *
- * Gets the first @size bytes stored in the @adapter. The returned pointer is
- * valid until the next function is called on the adapter.
- *
- * Note that setting the returned pointer as the data of a #GstBuffer is
- * incorrect for general-purpose plugins. The reason is that if a downstream
- * element stores the buffer so that it has access to it outside of the bounds
- * of its chain function, the buffer will have an invalid data pointer after
- * your element flushes the bytes. In that case you should use
- * gst_adapter_take(), which returns a freshly-allocated buffer that you can set
- * as #GstBuffer malloc_data.
- *
- * Returns #NULL if @size bytes are not available.
- *
- * Returns: a pointer to the first @size bytes of data, or NULL.
- */
-const guint8 *
-gst_adapter_peek (GstAdapter * adapter, guint size)
-{
- GstBuffer *cur;
- GSList *cur_list;
- guint copied;
-
- g_return_val_if_fail (GST_IS_ADAPTER (adapter), NULL);
- g_return_val_if_fail (size > 0, NULL);
-
- /* we don't have enough data, return NULL */
- if (size > adapter->size)
- return NULL;
-
- /* we have enough assembled data, return it */
- if (adapter->assembled_len >= size)
- return adapter->assembled_data;
-
- /* our head buffer has enough data left, return it */
- cur = adapter->buflist->data;
- if (GST_BUFFER_SIZE (cur) >= size + adapter->skip)
- return GST_BUFFER_DATA (cur) + adapter->skip;
-
- if (adapter->assembled_size < size) {
- adapter->assembled_size = (size / DEFAULT_SIZE + 1) * DEFAULT_SIZE;
- GST_DEBUG_OBJECT (adapter, "setting size of internal buffer to %u",
- adapter->assembled_size);
- adapter->assembled_data =
- g_realloc (adapter->assembled_data, adapter->assembled_size);
- }
- adapter->assembled_len = size;
- copied = GST_BUFFER_SIZE (cur) - adapter->skip;
- memcpy (adapter->assembled_data, GST_BUFFER_DATA (cur) + adapter->skip,
- copied);
- cur_list = g_slist_next (adapter->buflist);
- while (copied < size) {
- g_assert (cur_list);
- cur = cur_list->data;
- cur_list = g_slist_next (cur_list);
- memcpy (adapter->assembled_data + copied, GST_BUFFER_DATA (cur),
- MIN (GST_BUFFER_SIZE (cur), size - copied));
- copied = MIN (size, copied + GST_BUFFER_SIZE (cur));
- }
-
- return adapter->assembled_data;
-}
-
-/**
- * gst_adapter_flush:
- * @adapter: a #GstAdapter
- * @flush: the number of bytes to flush
- *
- * Flushes the first @flush bytes in the @adapter. The caller must ensure that
- * at least this many bytes are available.
- *
- * See also: gst_adapter_peek().
- */
-void
-gst_adapter_flush (GstAdapter * adapter, guint flush)
-{
- GstBuffer *cur;
-
- g_return_if_fail (GST_IS_ADAPTER (adapter));
- g_return_if_fail (flush >= 0);
- g_return_if_fail (flush <= adapter->size);
-
- GST_LOG_OBJECT (adapter, "flushing %u bytes", flush);
- adapter->size -= flush;
- adapter->assembled_len = 0;
- while (flush > 0) {
- cur = adapter->buflist->data;
- if (GST_BUFFER_SIZE (cur) <= flush + adapter->skip) {
- /* can skip whole buffer */
- flush -= GST_BUFFER_SIZE (cur) - adapter->skip;
- adapter->skip = 0;
- adapter->buflist = g_slist_remove (adapter->buflist, cur);
- gst_buffer_unref (cur);
- } else {
- adapter->skip += flush;
- break;
- }
- }
-}
-
-/**
- * gst_adapter_take:
- * @adapter: a #GstAdapter
- * @nbytes: the number of bytes to take
- *
- * Returns a freshly allocated buffer containing the first @nbytes bytes of the
- * @adapter.
- *
- * Caller owns returned value.
- *
- * Returns: oven-fresh hot data, or #NULL if @nbytes bytes are not available
- */
-guint8 *
-gst_adapter_take (GstAdapter * adapter, guint nbytes)
-{
- const guint8 *cdata;
- guint8 *data;
-
- g_return_val_if_fail (GST_IS_ADAPTER (adapter), NULL);
- g_return_val_if_fail (nbytes > 0, NULL);
-
- GST_LOG_OBJECT (adapter, "taking %u bytes", nbytes);
-
- cdata = gst_adapter_peek (adapter, nbytes);
-
- if (!cdata)
- return NULL;
-
- data = g_malloc (nbytes);
- memcpy (data, cdata, nbytes);
-
- gst_adapter_flush (adapter, nbytes);
-
- return data;
-}
-
-/**
- * gst_adapter_available:
- * @adapter: a #GstAdapter
- *
- * Gets the maximum amount of bytes available, that is it returns the maximum
- * value that can be supplied to gst_adapter_peek() without that function
- * returning NULL.
- *
- * Returns: number of bytes available in @adapter
- */
-guint
-gst_adapter_available (GstAdapter * adapter)
-{
- g_return_val_if_fail (GST_IS_ADAPTER (adapter), 0);
-
- return adapter->size;
-}
-
-/**
- * gst_adapter_available_fast:
- * @adapter: a #GstAdapter
- *
- * Gets the maximum number of bytes available without the need to do expensive
- * operations (like copying the data into a temporary buffer).
- *
- * Returns: number of bytes available in @adapter without expensive operations
- */
-guint
-gst_adapter_available_fast (GstAdapter * adapter)
-{
- g_return_val_if_fail (GST_IS_ADAPTER (adapter), 0);
-
- if (!adapter->buflist)
- return 0;
- if (adapter->assembled_len)
- return adapter->assembled_len;
- g_assert (GST_BUFFER_SIZE (adapter->buflist->data) > adapter->skip);
- return GST_BUFFER_SIZE (adapter->buflist->data) - adapter->skip;
-}
+++ /dev/null
-/* GStreamer
- * Copyright (C) 2004 Benjamin Otte <otte@gnome.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#include <gst/gst.h>
-
-#ifndef __GST_ADAPTER_H__
-#define __GST_ADAPTER_H__
-
-G_BEGIN_DECLS
-
-
-#define GST_TYPE_ADAPTER \
- (gst_adapter_get_type())
-#define GST_ADAPTER(obj) \
- (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_ADAPTER, GstAdapter))
-#define GST_ADAPTER_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_ADAPTER, GstAdapterClass))
-#define GST_ADAPTER_GET_CLASS(obj) \
- (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_ADAPTER, GstAdapterClass))
-
-#define GST_IS_ADAPTER(obj) \
- (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_ADAPTER))
-#define GST_IS_ADAPTER_CLASS(obj) \
- (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_ADAPTER))
-
-typedef struct _GstAdapter GstAdapter;
-typedef struct _GstAdapterClass GstAdapterClass;
-
-/**
- * GstAdapter:
- *
- * The opaque #GstAdapter data structure.
- */
-struct _GstAdapter {
- GObject object;
-
- /*< private >*/
- GSList * buflist;
- guint size;
- guint skip;
-
- /* we keep state of assembled pieces */
- guint8 * assembled_data;
- guint assembled_size;
- guint assembled_len;
-
- gpointer _gst_reserved[GST_PADDING];
-};
-
-struct _GstAdapterClass {
- GObjectClass parent_class;
-
- /*< private >*/
- gpointer _gst_reserved[GST_PADDING];
-};
-
-GstAdapter * gst_adapter_new (void);
-
-void gst_adapter_clear (GstAdapter *adapter);
-void gst_adapter_push (GstAdapter *adapter, GstBuffer* buf);
-const guint8 * gst_adapter_peek (GstAdapter *adapter, guint size);
-void gst_adapter_flush (GstAdapter *adapter, guint flush);
-guint8* gst_adapter_take (GstAdapter * adapter, guint nbytes);
-guint gst_adapter_available (GstAdapter *adapter);
-guint gst_adapter_available_fast (GstAdapter *adapter);
-GType gst_adapter_get_type (void);
-
-G_END_DECLS
-
-#endif /* __GST_ADAPTER_H__ */
+++ /dev/null
-/* GStreamer
- * Copyright (C) 2005 Wim Taymans <wim@fluendo.com>
- *
- * gstbasesink.c: Base class for sink elements
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-/**
- * SECTION:gstbasesink
- * @short_description: Base class for sink elements
- * @see_also: #GstBaseTransform, #GstBaseSource
- *
- * GstBaseSink is the base class for sink elements in GStreamer, such as
- * xvimagesink or filesink. It is a layer on top of #GstElement that provides a
- * simplified interface to plugin writers. GstBaseSink handles many details for
- * you, for example preroll, clock synchronization, state changes, activation in
- * push or pull mode, and queries. In most cases, when writing sink elements,
- * there is no need to implement class methods from #GstElement or to set
- * functions on pads, because the GstBaseSink infrastructure is sufficient.
- *
- * There is only support in GstBaseSink for one sink pad, which should be named
- * "sink". A sink implementation (subclass of GstBaseSink) should install a pad
- * template in its base_init function, like so:
- * <programlisting>
- * static void
- * my_element_base_init (gpointer g_class)
- * {
- * GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
- *
- * // sinktemplate should be a #GstStaticPadTemplate with direction
- * // #GST_PAD_SINK and name "sink"
- * gst_element_class_add_pad_template (gstelement_class,
- * gst_static_pad_template_get (&sinktemplate));
- * // see #GstElementDetails
- * gst_element_class_set_details (gstelement_class, &details);
- * }
- * </programlisting>
- *
- * The one method which all subclasses of GstBaseSink must implement is
- * GstBaseSink::render. This method will be called...
- *
- * preroll()
- *
- * event(): mostly useful for file-like sinks (seeking or flushing)
- *
- * get_caps/set_caps/buffer_alloc
- *
- * start/stop for resource allocation
- *
- * unlock if you block on an fd, for example
- *
- * get_times i'm sure is for something :P
- *
- * provide example of textsink
- *
- * admonishment not to try to implement your own sink with prerolling...
- *
- * extending via subclassing, setting pad functions, gstelement vmethods.
- */
-
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#include "gstbasesink.h"
-#include <gst/gstmarshal.h>
-#include <gst/gst-i18n-lib.h>
-
-GST_DEBUG_CATEGORY_STATIC (gst_base_sink_debug);
-#define GST_CAT_DEFAULT gst_base_sink_debug
-
-/* BaseSink signals and properties */
-enum
-{
- /* FILL ME */
- SIGNAL_HANDOFF,
- LAST_SIGNAL
-};
-
-#define DEFAULT_SIZE 1024
-#define DEFAULT_CAN_ACTIVATE_PULL FALSE /* fixme: enable me */
-#define DEFAULT_CAN_ACTIVATE_PUSH TRUE
-
-#define DEFAULT_SYNC TRUE
-
-enum
-{
- PROP_0,
- PROP_PREROLL_QUEUE_LEN,
- PROP_SYNC
-};
-
-static GstElementClass *parent_class = NULL;
-
-static void gst_base_sink_base_init (gpointer g_class);
-static void gst_base_sink_class_init (GstBaseSinkClass * klass);
-static void gst_base_sink_init (GstBaseSink * trans, gpointer g_class);
-static void gst_base_sink_finalize (GObject * object);
-
-GType
-gst_base_sink_get_type (void)
-{
- static GType base_sink_type = 0;
-
- if (!base_sink_type) {
- static const GTypeInfo base_sink_info = {
- sizeof (GstBaseSinkClass),
- (GBaseInitFunc) gst_base_sink_base_init,
- NULL,
- (GClassInitFunc) gst_base_sink_class_init,
- NULL,
- NULL,
- sizeof (GstBaseSink),
- 0,
- (GInstanceInitFunc) gst_base_sink_init,
- };
-
- base_sink_type = g_type_register_static (GST_TYPE_ELEMENT,
- "GstBaseSink", &base_sink_info, G_TYPE_FLAG_ABSTRACT);
- }
- return base_sink_type;
-}
-
-static void gst_base_sink_set_property (GObject * object, guint prop_id,
- const GValue * value, GParamSpec * pspec);
-static void gst_base_sink_get_property (GObject * object, guint prop_id,
- GValue * value, GParamSpec * pspec);
-
-static gboolean gst_base_sink_send_event (GstElement * element,
- GstEvent * event);
-static gboolean gst_base_sink_query (GstElement * element, GstQuery * query);
-
-static GstCaps *gst_base_sink_get_caps (GstBaseSink * sink);
-static gboolean gst_base_sink_set_caps (GstBaseSink * sink, GstCaps * caps);
-static GstFlowReturn gst_base_sink_buffer_alloc (GstBaseSink * sink,
- guint64 offset, guint size, GstCaps * caps, GstBuffer ** buf);
-static void gst_base_sink_get_times (GstBaseSink * basesink, GstBuffer * buffer,
- GstClockTime * start, GstClockTime * end);
-
-static GstStateChangeReturn gst_base_sink_change_state (GstElement * element,
- GstStateChange transition);
-
-static GstFlowReturn gst_base_sink_chain (GstPad * pad, GstBuffer * buffer);
-static void gst_base_sink_loop (GstPad * pad);
-static gboolean gst_base_sink_activate (GstPad * pad);
-static gboolean gst_base_sink_activate_push (GstPad * pad, gboolean active);
-static gboolean gst_base_sink_activate_pull (GstPad * pad, gboolean active);
-static gboolean gst_base_sink_event (GstPad * pad, GstEvent * event);
-static inline GstFlowReturn gst_base_sink_handle_buffer (GstBaseSink * basesink,
- GstBuffer * buf);
-static inline gboolean gst_base_sink_handle_event (GstBaseSink * basesink,
- GstEvent * event);
-
-static void
-gst_base_sink_base_init (gpointer g_class)
-{
- GST_DEBUG_CATEGORY_INIT (gst_base_sink_debug, "basesink", 0,
- "basesink element");
-}
-
-static void
-gst_base_sink_class_init (GstBaseSinkClass * klass)
-{
- GObjectClass *gobject_class;
- GstElementClass *gstelement_class;
-
- gobject_class = (GObjectClass *) klass;
- gstelement_class = (GstElementClass *) klass;
-
- parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
-
- gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_base_sink_finalize);
- gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_base_sink_set_property);
- gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_base_sink_get_property);
-
- /* FIXME, this next value should be configured using an event from the
- * upstream element */
- g_object_class_install_property (G_OBJECT_CLASS (klass),
- PROP_PREROLL_QUEUE_LEN,
- g_param_spec_uint ("preroll-queue-len", "preroll-queue-len",
- "Number of buffers to queue during preroll", 0, G_MAXUINT, 0,
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
- g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SYNC,
- g_param_spec_boolean ("sync", "Sync", "Sync on the clock", DEFAULT_SYNC,
- G_PARAM_READWRITE));
-
- gstelement_class->change_state =
- GST_DEBUG_FUNCPTR (gst_base_sink_change_state);
- gstelement_class->send_event = GST_DEBUG_FUNCPTR (gst_base_sink_send_event);
- gstelement_class->query = GST_DEBUG_FUNCPTR (gst_base_sink_query);
-
- klass->get_caps = GST_DEBUG_FUNCPTR (gst_base_sink_get_caps);
- klass->set_caps = GST_DEBUG_FUNCPTR (gst_base_sink_set_caps);
- klass->buffer_alloc = GST_DEBUG_FUNCPTR (gst_base_sink_buffer_alloc);
- klass->get_times = GST_DEBUG_FUNCPTR (gst_base_sink_get_times);
-}
-
-static GstCaps *
-gst_base_sink_pad_getcaps (GstPad * pad)
-{
- GstBaseSinkClass *bclass;
- GstBaseSink *bsink;
- GstCaps *caps = NULL;
-
- bsink = GST_BASE_SINK (gst_pad_get_parent (pad));
- bclass = GST_BASE_SINK_GET_CLASS (bsink);
- if (bclass->get_caps)
- caps = bclass->get_caps (bsink);
-
- if (caps == NULL) {
- GstPadTemplate *pad_template;
-
- pad_template =
- gst_element_class_get_pad_template (GST_ELEMENT_CLASS (bclass), "sink");
- if (pad_template != NULL) {
- caps = gst_caps_ref (gst_pad_template_get_caps (pad_template));
- }
- }
- gst_object_unref (bsink);
-
- return caps;
-}
-
-static gboolean
-gst_base_sink_pad_setcaps (GstPad * pad, GstCaps * caps)
-{
- GstBaseSinkClass *bclass;
- GstBaseSink *bsink;
- gboolean res = FALSE;
-
- bsink = GST_BASE_SINK (gst_pad_get_parent (pad));
- bclass = GST_BASE_SINK_GET_CLASS (bsink);
-
- if (bclass->set_caps)
- res = bclass->set_caps (bsink, caps);
-
- gst_object_unref (bsink);
-
- return res;
-}
-
-static GstFlowReturn
-gst_base_sink_pad_buffer_alloc (GstPad * pad, guint64 offset, guint size,
- GstCaps * caps, GstBuffer ** buf)
-{
- GstBaseSinkClass *bclass;
- GstBaseSink *bsink;
- GstFlowReturn result = GST_FLOW_OK;
-
- bsink = GST_BASE_SINK (gst_pad_get_parent (pad));
- bclass = GST_BASE_SINK_GET_CLASS (bsink);
-
- if (bclass->buffer_alloc)
- result = bclass->buffer_alloc (bsink, offset, size, caps, buf);
- else
- *buf = NULL; /* fallback in gstpad.c will allocate generic buffer */
-
- gst_object_unref (bsink);
-
- return result;
-}
-
-static void
-gst_base_sink_init (GstBaseSink * basesink, gpointer g_class)
-{
- GstPadTemplate *pad_template;
-
- pad_template =
- gst_element_class_get_pad_template (GST_ELEMENT_CLASS (g_class), "sink");
- g_return_if_fail (pad_template != NULL);
-
- basesink->sinkpad = gst_pad_new_from_template (pad_template, "sink");
-
- gst_pad_set_getcaps_function (basesink->sinkpad,
- GST_DEBUG_FUNCPTR (gst_base_sink_pad_getcaps));
- gst_pad_set_setcaps_function (basesink->sinkpad,
- GST_DEBUG_FUNCPTR (gst_base_sink_pad_setcaps));
- gst_pad_set_bufferalloc_function (basesink->sinkpad,
- GST_DEBUG_FUNCPTR (gst_base_sink_pad_buffer_alloc));
- gst_pad_set_activate_function (basesink->sinkpad,
- GST_DEBUG_FUNCPTR (gst_base_sink_activate));
- gst_pad_set_activatepush_function (basesink->sinkpad,
- GST_DEBUG_FUNCPTR (gst_base_sink_activate_push));
- gst_pad_set_activatepull_function (basesink->sinkpad,
- GST_DEBUG_FUNCPTR (gst_base_sink_activate_pull));
- gst_pad_set_event_function (basesink->sinkpad,
- GST_DEBUG_FUNCPTR (gst_base_sink_event));
- gst_pad_set_chain_function (basesink->sinkpad,
- GST_DEBUG_FUNCPTR (gst_base_sink_chain));
- gst_element_add_pad (GST_ELEMENT (basesink), basesink->sinkpad);
-
- basesink->pad_mode = GST_ACTIVATE_NONE;
- GST_PAD_TASK (basesink->sinkpad) = NULL;
- basesink->preroll_queue = g_queue_new ();
-
- basesink->can_activate_push = DEFAULT_CAN_ACTIVATE_PUSH;
- basesink->can_activate_pull = DEFAULT_CAN_ACTIVATE_PULL;
-
- basesink->sync = DEFAULT_SYNC;
-
- GST_OBJECT_FLAG_SET (basesink, GST_ELEMENT_IS_SINK);
-}
-
-static void
-gst_base_sink_finalize (GObject * object)
-{
- GstBaseSink *basesink;
-
- basesink = GST_BASE_SINK (object);
-
- g_queue_free (basesink->preroll_queue);
-
- G_OBJECT_CLASS (parent_class)->finalize (object);
-}
-
-static void
-gst_base_sink_set_property (GObject * object, guint prop_id,
- const GValue * value, GParamSpec * pspec)
-{
- GstBaseSink *sink = GST_BASE_SINK (object);
-
- switch (prop_id) {
- case PROP_PREROLL_QUEUE_LEN:
- /* preroll lock necessary to serialize with finish_preroll */
- GST_PAD_PREROLL_LOCK (sink->sinkpad);
- sink->preroll_queue_max_len = g_value_get_uint (value);
- GST_PAD_PREROLL_UNLOCK (sink->sinkpad);
- break;
- case PROP_SYNC:
- sink->sync = g_value_get_boolean (value);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-gst_base_sink_get_property (GObject * object, guint prop_id, GValue * value,
- GParamSpec * pspec)
-{
- GstBaseSink *sink = GST_BASE_SINK (object);
-
- GST_OBJECT_LOCK (sink);
- switch (prop_id) {
- case PROP_PREROLL_QUEUE_LEN:
- g_value_set_uint (value, sink->preroll_queue_max_len);
- break;
- case PROP_SYNC:
- g_value_set_boolean (value, sink->sync);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
- GST_OBJECT_UNLOCK (sink);
-}
-
-static GstCaps *
-gst_base_sink_get_caps (GstBaseSink * sink)
-{
- return NULL;
-}
-
-static gboolean
-gst_base_sink_set_caps (GstBaseSink * sink, GstCaps * caps)
-{
- return TRUE;
-}
-
-static GstFlowReturn
-gst_base_sink_buffer_alloc (GstBaseSink * sink, guint64 offset, guint size,
- GstCaps * caps, GstBuffer ** buf)
-{
- *buf = NULL;
- return GST_FLOW_OK;
-}
-
-/* with PREROLL_LOCK */
-static GstFlowReturn
-gst_base_sink_preroll_queue_empty (GstBaseSink * basesink, GstPad * pad)
-{
- GstMiniObject *obj;
- GQueue *q = basesink->preroll_queue;
- GstFlowReturn ret;
-
- ret = GST_FLOW_OK;
-
- if (q) {
- GST_DEBUG_OBJECT (basesink, "emptying queue");
- while ((obj = g_queue_pop_head (q))) {
- gboolean is_buffer;
-
- is_buffer = GST_IS_BUFFER (obj);
- if (G_LIKELY (is_buffer)) {
- basesink->preroll_queued--;
- basesink->buffers_queued--;
- } else {
- switch (GST_EVENT_TYPE (obj)) {
- case GST_EVENT_EOS:
- basesink->preroll_queued--;
- break;
- default:
- break;
- }
- basesink->events_queued--;
- }
- /* we release the preroll lock while pushing so that we
- * can still flush it while blocking on the clock or
- * inside the element. */
- GST_PAD_PREROLL_UNLOCK (pad);
-
- if (G_LIKELY (is_buffer)) {
- GST_DEBUG_OBJECT (basesink, "popped buffer %p", obj);
- ret = gst_base_sink_handle_buffer (basesink, GST_BUFFER_CAST (obj));
- } else {
- GST_DEBUG_OBJECT (basesink, "popped event %p", obj);
- gst_base_sink_handle_event (basesink, GST_EVENT_CAST (obj));
- ret = GST_FLOW_OK;
- }
-
- GST_PAD_PREROLL_LOCK (pad);
- }
- GST_DEBUG_OBJECT (basesink, "queue empty");
- }
- return ret;
-}
-
-/* with PREROLL_LOCK */
-static void
-gst_base_sink_preroll_queue_flush (GstBaseSink * basesink, GstPad * pad)
-{
- GstMiniObject *obj;
- GQueue *q = basesink->preroll_queue;
-
- GST_DEBUG_OBJECT (basesink, "flushing queue %p", basesink);
- if (q) {
- while ((obj = g_queue_pop_head (q))) {
- GST_DEBUG_OBJECT (basesink, "popped %p", obj);
- gst_mini_object_unref (obj);
- }
- }
- /* we can't have EOS anymore now */
- basesink->eos = FALSE;
- basesink->eos_queued = FALSE;
- basesink->preroll_queued = 0;
- basesink->buffers_queued = 0;
- basesink->events_queued = 0;
- basesink->have_preroll = FALSE;
- /* and signal any waiters now */
- GST_PAD_PREROLL_SIGNAL (pad);
-}
-
-/* with PREROLL_LOCK */
-static gboolean
-gst_base_sink_commit_state (GstBaseSink * basesink)
-{
- /* commit state and proceed to next pending state */
- {
- GstState current, next, pending, post_pending;
- GstMessage *message;
- gboolean post_paused = FALSE;
- gboolean post_playing = FALSE;
-
- GST_OBJECT_LOCK (basesink);
- current = GST_STATE (basesink);
- next = GST_STATE_NEXT (basesink);
- pending = GST_STATE_PENDING (basesink);
- post_pending = pending;
-
- switch (pending) {
- case GST_STATE_PLAYING:
- basesink->need_preroll = FALSE;
- post_playing = TRUE;
- /* post PAUSED too when we were READY */
- if (current == GST_STATE_READY) {
- post_paused = TRUE;
- }
- break;
- case GST_STATE_PAUSED:
- basesink->need_preroll = TRUE;
- post_paused = TRUE;
- post_pending = GST_STATE_VOID_PENDING;
- break;
- case GST_STATE_READY:
- goto stopping;
- default:
- break;
- }
-
- if (pending != GST_STATE_VOID_PENDING) {
- GST_STATE (basesink) = pending;
- GST_STATE_NEXT (basesink) = GST_STATE_VOID_PENDING;
- GST_STATE_PENDING (basesink) = GST_STATE_VOID_PENDING;
- GST_STATE_RETURN (basesink) = GST_STATE_CHANGE_SUCCESS;
- }
- GST_OBJECT_UNLOCK (basesink);
-
- if (post_paused) {
- message = gst_message_new_state_changed (GST_OBJECT_CAST (basesink),
- current, next, post_pending);
- gst_element_post_message (GST_ELEMENT_CAST (basesink), message);
- }
- if (post_playing) {
- message = gst_message_new_state_changed (GST_OBJECT_CAST (basesink),
- next, pending, GST_STATE_VOID_PENDING);
- gst_element_post_message (GST_ELEMENT_CAST (basesink), message);
- }
- /* and mark dirty */
- if (post_paused || post_playing) {
- gst_element_post_message (GST_ELEMENT_CAST (basesink),
- gst_message_new_state_dirty (GST_OBJECT_CAST (basesink)));
- }
-
- GST_STATE_BROADCAST (basesink);
- }
- return TRUE;
-
-stopping:
- {
- /* app is going to READY */
- GST_OBJECT_UNLOCK (basesink);
- return FALSE;
- }
-}
-
-/* with STREAM_LOCK */
-static GstFlowReturn
-gst_base_sink_handle_object (GstBaseSink * basesink, GstPad * pad,
- GstMiniObject * obj)
-{
- gint length;
- gboolean have_event;
- GstFlowReturn ret;
-
- GST_PAD_PREROLL_LOCK (pad);
- /* push object on the queue */
- GST_DEBUG_OBJECT (basesink, "push %p on preroll_queue", obj);
- g_queue_push_tail (basesink->preroll_queue, obj);
-
- have_event = GST_IS_EVENT (obj);
- if (have_event) {
- GstEvent *event = GST_EVENT (obj);
-
- switch (GST_EVENT_TYPE (obj)) {
- case GST_EVENT_EOS:
- basesink->preroll_queued++;
- basesink->eos = TRUE;
- basesink->eos_queued = TRUE;
- break;
- case GST_EVENT_NEWSEGMENT:
- {
- gboolean update;
- gdouble rate;
- GstFormat format;
- gint64 start;
- gint64 stop;
- gint64 time;
-
- /* the newsegment event is needed to bring the buffer timestamps to the
- * stream time and to drop samples outside of the playback segment. */
- gst_event_parse_new_segment (event, &update, &rate, &format,
- &start, &stop, &time);
-
- basesink->have_newsegment = TRUE;
-
- gst_segment_set_newsegment (&basesink->segment, update, rate, format,
- start, stop, time);
-
- GST_DEBUG_OBJECT (basesink,
- "received NEWSEGMENT %" GST_TIME_FORMAT " -- %"
- GST_TIME_FORMAT ", time %" GST_TIME_FORMAT ", accum %"
- GST_TIME_FORMAT,
- GST_TIME_ARGS (basesink->segment.start),
- GST_TIME_ARGS (basesink->segment.stop),
- GST_TIME_ARGS (basesink->segment.time),
- GST_TIME_ARGS (basesink->segment.accum));
- break;
- }
- default:
- break;
- }
- basesink->events_queued++;
- } else {
- GstBuffer *buf = GST_BUFFER (obj);
-
- if (!basesink->have_newsegment) {
- GST_ELEMENT_WARNING (basesink, STREAM, FAILED,
- (_("Internal data flow problem.")),
- ("Received buffer without a new-segment. Cannot sync to clock."));
- basesink->have_newsegment = TRUE;
- /* this means this sink will not be able to sync to the clock */
- basesink->segment.start = -1;
- basesink->segment.stop = -1;
- }
-
- /* check if the buffer needs to be dropped */
- if (TRUE) {
- GstClockTime start = -1, end = -1;
-
- /* we don't use the subclassed method as it may not return
- * valid values for our purpose here */
- gst_base_sink_get_times (basesink, buf, &start, &end);
-
- GST_DEBUG_OBJECT (basesink, "got times start: %" GST_TIME_FORMAT
- ", end: %" GST_TIME_FORMAT, GST_TIME_ARGS (start),
- GST_TIME_ARGS (end));
-
- if (GST_CLOCK_TIME_IS_VALID (start) &&
- (basesink->segment.format == GST_FORMAT_TIME)) {
- if (!gst_segment_clip (&basesink->segment, GST_FORMAT_TIME,
- (gint64) start, (gint64) end, NULL, NULL))
- goto dropping;
- }
- }
- basesink->preroll_queued++;
- basesink->buffers_queued++;
- }
-
- GST_DEBUG_OBJECT (basesink,
- "now %d preroll, %d buffers, %d events on queue",
- basesink->preroll_queued,
- basesink->buffers_queued, basesink->events_queued);
-
- /* check if we are prerolling */
- if (!basesink->need_preroll)
- goto no_preroll;
-
- /* there is a buffer queued */
- if (basesink->buffers_queued == 1) {
- GST_DEBUG_OBJECT (basesink, "do preroll %p", obj);
-
- /* if it's a buffer, we need to call the preroll method */
- if (GST_IS_BUFFER (obj)) {
- GstBaseSinkClass *bclass;
- GstBuffer *buf = GST_BUFFER (obj);
-
- GST_DEBUG_OBJECT (basesink, "preroll buffer %" GST_TIME_FORMAT,
- GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
-
- bclass = GST_BASE_SINK_GET_CLASS (basesink);
- if (bclass->preroll)
- if ((ret = bclass->preroll (basesink, buf)) != GST_FLOW_OK)
- goto preroll_failed;
- }
- }
- length = basesink->preroll_queued;
- GST_DEBUG_OBJECT (basesink, "prerolled length %d", length);
-
- if (length == 1) {
-
- basesink->have_preroll = TRUE;
-
- /* commit state */
- if (!gst_base_sink_commit_state (basesink))
- goto stopping;
-
- GST_OBJECT_LOCK (pad);
- if (G_UNLIKELY (GST_PAD_IS_FLUSHING (pad)))
- goto flushing;
- GST_OBJECT_UNLOCK (pad);
-
- /* it is possible that commiting the state made us go to PLAYING
- * now in which case we don't need to block anymore. */
- if (!basesink->need_preroll)
- goto no_preroll;
-
- length = basesink->preroll_queued;
-
- /* FIXME: a pad probe could have made us lose the buffer, according
- * to one of the python tests */
- if (length == 0) {
- GST_ERROR_OBJECT (basesink,
- "preroll_queued dropped from 1 to 0 while committing state change");
- }
- g_assert (length <= 1);
- }
-
- /* see if we need to block now. We cannot block on events, only
- * on buffers, the reason is that events can be sent from the
- * application thread and we don't want to block there. */
- if (length > basesink->preroll_queue_max_len && !have_event) {
- /* block until the state changes, or we get a flush, or something */
- GST_DEBUG_OBJECT (basesink, "waiting to finish preroll");
- GST_PAD_PREROLL_WAIT (pad);
- GST_DEBUG_OBJECT (basesink, "done preroll");
- GST_OBJECT_LOCK (pad);
- if (G_UNLIKELY (GST_PAD_IS_FLUSHING (pad)))
- goto flushing;
- GST_OBJECT_UNLOCK (pad);
- }
- GST_PAD_PREROLL_UNLOCK (pad);
-
- return GST_FLOW_OK;
-
-no_preroll:
- {
- GST_DEBUG_OBJECT (basesink, "no preroll needed");
- /* maybe it was another sink that blocked in preroll, need to check for
- buffers to drain */
- basesink->have_preroll = FALSE;
- ret = gst_base_sink_preroll_queue_empty (basesink, pad);
- GST_PAD_PREROLL_UNLOCK (pad);
-
- return ret;
- }
-dropping:
- {
- GstBuffer *buf;
-
- buf = GST_BUFFER (g_queue_pop_tail (basesink->preroll_queue));
-
- gst_buffer_unref (buf);
- GST_PAD_PREROLL_UNLOCK (pad);
-
- return GST_FLOW_OK;
- }
-flushing:
- {
- GST_OBJECT_UNLOCK (pad);
- gst_base_sink_preroll_queue_flush (basesink, pad);
- GST_PAD_PREROLL_UNLOCK (pad);
- GST_DEBUG_OBJECT (basesink, "pad is flushing");
-
- return GST_FLOW_WRONG_STATE;
- }
-stopping:
- {
- GST_PAD_PREROLL_UNLOCK (pad);
- GST_DEBUG_OBJECT (basesink, "stopping");
-
- return GST_FLOW_WRONG_STATE;
- }
-preroll_failed:
- {
- GST_DEBUG_OBJECT (basesink, "preroll failed");
- gst_base_sink_preroll_queue_flush (basesink, pad);
- GST_PAD_PREROLL_UNLOCK (pad);
-
- GST_DEBUG_OBJECT (basesink, "abort state");
- gst_element_abort_state (GST_ELEMENT (basesink));
-
- return ret;
- }
-}
-
-static gboolean
-gst_base_sink_event (GstPad * pad, GstEvent * event)
-{
- GstBaseSink *basesink;
- gboolean result = TRUE;
- GstBaseSinkClass *bclass;
-
- basesink = GST_BASE_SINK (gst_pad_get_parent (pad));
-
- bclass = GST_BASE_SINK_GET_CLASS (basesink);
-
- GST_DEBUG_OBJECT (basesink, "event %p", event);
-
- switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_EOS:
- {
- GstFlowReturn ret;
-
- /* EOS also finishes the preroll */
- ret =
- gst_base_sink_handle_object (basesink, pad, GST_MINI_OBJECT (event));
- break;
- }
- case GST_EVENT_NEWSEGMENT:
- {
- GstFlowReturn ret;
-
- ret =
- gst_base_sink_handle_object (basesink, pad, GST_MINI_OBJECT (event));
- break;
- }
- case GST_EVENT_FLUSH_START:
- /* make sure we are not blocked on the clock also clear any pending
- * eos state. */
- if (bclass->event)
- bclass->event (basesink, event);
-
- GST_OBJECT_LOCK (basesink);
- basesink->flushing = TRUE;
- if (basesink->clock_id) {
- gst_clock_id_unschedule (basesink->clock_id);
- }
- GST_OBJECT_UNLOCK (basesink);
-
- GST_PAD_PREROLL_LOCK (pad);
- /* we need preroll after the flush */
- GST_DEBUG_OBJECT (basesink, "flushing, need preroll after flush");
- basesink->need_preroll = TRUE;
- /* unlock from a possible state change/preroll */
- gst_base_sink_preroll_queue_flush (basesink, pad);
- GST_PAD_PREROLL_UNLOCK (pad);
-
- /* and we need to commit our state again on the next
- * prerolled buffer */
- GST_PAD_STREAM_LOCK (pad);
- gst_element_lost_state (GST_ELEMENT (basesink));
- GST_PAD_STREAM_UNLOCK (pad);
- GST_DEBUG_OBJECT (basesink, "event unref %p %p", basesink, event);
- gst_event_unref (event);
- break;
- case GST_EVENT_FLUSH_STOP:
- if (bclass->event)
- bclass->event (basesink, event);
-
- /* now we are completely unblocked and the _chain method
- * will return */
- GST_OBJECT_LOCK (basesink);
- basesink->flushing = FALSE;
- GST_OBJECT_UNLOCK (basesink);
- /* we need new segment info after the flush. */
- gst_segment_init (&basesink->segment, GST_FORMAT_UNDEFINED);
-
- GST_DEBUG_OBJECT (basesink, "event unref %p %p", basesink, event);
- gst_event_unref (event);
- break;
- default:
- gst_event_unref (event);
- break;
- }
- gst_object_unref (basesink);
-
- return result;
-}
-
-/* default implementation to calculate the start and end
- * timestamps on a buffer, subclasses can override
- */
-static void
-gst_base_sink_get_times (GstBaseSink * basesink, GstBuffer * buffer,
- GstClockTime * start, GstClockTime * end)
-{
- GstClockTime timestamp, duration;
-
- timestamp = GST_BUFFER_TIMESTAMP (buffer);
- if (GST_CLOCK_TIME_IS_VALID (timestamp)) {
-
- /* get duration to calculate end time */
- duration = GST_BUFFER_DURATION (buffer);
- if (GST_CLOCK_TIME_IS_VALID (duration)) {
- *end = timestamp + duration;
- }
- *start = timestamp;
- }
-}
-
-/* with STREAM_LOCK and LOCK*/
-static GstClockReturn
-gst_base_sink_wait (GstBaseSink * basesink, GstClockTime time)
-{
- GstClockReturn ret;
- GstClockID id;
-
- /* no need to attempt a clock wait if we are flushing */
- if (basesink->flushing) {
- return GST_CLOCK_UNSCHEDULED;
- }
-
- /* clock_id should be NULL outside of this function */
- g_assert (basesink->clock_id == NULL);
- g_assert (GST_CLOCK_TIME_IS_VALID (time));
-
- id = gst_clock_new_single_shot_id (GST_ELEMENT_CLOCK (basesink), time);
-
- basesink->clock_id = id;
- /* release the object lock while waiting */
- GST_OBJECT_UNLOCK (basesink);
-
- ret = gst_clock_id_wait (id, NULL);
-
- GST_OBJECT_LOCK (basesink);
- gst_clock_id_unref (id);
- basesink->clock_id = NULL;
-
- return ret;
-}
-
-/* perform synchronisation on a buffer
- *
- * 1) check if we have a clock, if not, do nothing
- * 2) calculate the start and end time of the buffer
- * 3) create a single shot notification to wait on
- * the clock, save the entry so we can unlock it
- * 4) wait on the clock, this blocks
- * 5) unref the clockid again
- */
-static GstClockReturn
-gst_base_sink_do_sync (GstBaseSink * basesink, GstBuffer * buffer)
-{
- GstClockReturn result = GST_CLOCK_OK;
- GstClockTime start, end;
- gint64 cstart, cend;
- GstBaseSinkClass *bclass;
-
- bclass = GST_BASE_SINK_GET_CLASS (basesink);
-
- start = end = -1;
- if (bclass->get_times)
- bclass->get_times (basesink, buffer, &start, &end);
-
- GST_DEBUG_OBJECT (basesink, "got times start: %" GST_TIME_FORMAT
- ", end: %" GST_TIME_FORMAT, GST_TIME_ARGS (start), GST_TIME_ARGS (end));
-
- /* if we don't have a timestamp, we don't sync */
- if (!GST_CLOCK_TIME_IS_VALID (start)) {
- GST_DEBUG_OBJECT (basesink, "start not valid");
- goto done;
- }
-
- if (basesink->segment.format == GST_FORMAT_TIME) {
- /* save last times seen. */
- if (GST_CLOCK_TIME_IS_VALID (end))
- gst_segment_set_last_stop (&basesink->segment, GST_FORMAT_TIME,
- (gint64) end);
- else
- gst_segment_set_last_stop (&basesink->segment, GST_FORMAT_TIME,
- (gint64) start);
-
- /* clip */
- if (!gst_segment_clip (&basesink->segment, GST_FORMAT_TIME,
- (gint64) start, (gint64) end, &cstart, &cend))
- goto out_of_segment;
- } else {
- /* no clipping for formats different from GST_FORMAT_TIME */
- cstart = start;
- cend = end;
- }
-
- if (!basesink->sync) {
- GST_DEBUG_OBJECT (basesink, "no need to sync");
- goto done;
- }
-
- /* now do clocking */
- if (GST_ELEMENT_CLOCK (basesink)
- && ((basesink->segment.format == GST_FORMAT_TIME)
- || (basesink->segment.accum == 0))) {
- GstClockTime base_time;
- GstClockTimeDiff stream_start, stream_end;
-
- stream_start =
- gst_segment_to_running_time (&basesink->segment, GST_FORMAT_TIME,
- cstart);
- stream_end =
- gst_segment_to_running_time (&basesink->segment, GST_FORMAT_TIME, cend);
-
- GST_OBJECT_LOCK (basesink);
-
- base_time = GST_ELEMENT_CAST (basesink)->base_time;
-
- GST_LOG_OBJECT (basesink,
- "waiting for clock, base time %" GST_TIME_FORMAT
- " stream_start %" GST_TIME_FORMAT,
- GST_TIME_ARGS (base_time), GST_TIME_ARGS (stream_start));
-
- /* also save end_time of this buffer so that we can wait
- * to signal EOS */
- if (GST_CLOCK_TIME_IS_VALID (stream_end))
- basesink->end_time = stream_end + base_time;
- else
- basesink->end_time = GST_CLOCK_TIME_NONE;
-
- result = gst_base_sink_wait (basesink, stream_start + base_time);
-
- GST_OBJECT_UNLOCK (basesink);
-
- GST_LOG_OBJECT (basesink, "clock entry done: %d", result);
- } else {
- GST_DEBUG_OBJECT (basesink, "no clock, not syncing");
- }
-
-done:
- return result;
-
-out_of_segment:
- {
- GST_LOG_OBJECT (basesink, "buffer skipped, not in segment");
- return GST_CLOCK_UNSCHEDULED;
- }
-}
-
-
-/* handle an event
- *
- * 2) render the event
- * 3) unref the event
- */
-static inline gboolean
-gst_base_sink_handle_event (GstBaseSink * basesink, GstEvent * event)
-{
- GstBaseSinkClass *bclass;
- gboolean ret;
-
- switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_EOS:
- GST_OBJECT_LOCK (basesink);
- if (GST_ELEMENT_CLOCK (basesink)) {
- /* wait for last buffer to finish if we have a valid end time */
- if (GST_CLOCK_TIME_IS_VALID (basesink->end_time)) {
- gst_base_sink_wait (basesink, basesink->end_time);
- basesink->end_time = GST_CLOCK_TIME_NONE;
- }
- }
- GST_OBJECT_UNLOCK (basesink);
- break;
- default:
- break;
- }
-
- bclass = GST_BASE_SINK_GET_CLASS (basesink);
- if (bclass->event)
- ret = bclass->event (basesink, event);
- else
- ret = TRUE;
-
- switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_EOS:
- GST_PAD_PREROLL_LOCK (basesink->sinkpad);
- /* if we are still EOS, we can post the EOS message */
- if (basesink->eos) {
- /* ok, now we can post the message */
- GST_DEBUG_OBJECT (basesink, "Now posting EOS");
- gst_element_post_message (GST_ELEMENT_CAST (basesink),
- gst_message_new_eos (GST_OBJECT_CAST (basesink)));
- basesink->eos_queued = FALSE;
- }
- GST_PAD_PREROLL_UNLOCK (basesink->sinkpad);
- break;
- default:
- break;
- }
-
- GST_DEBUG_OBJECT (basesink, "event unref %p %p", basesink, event);
- gst_event_unref (event);
-
- return ret;
-}
-
-/* handle a buffer
- *
- * 1) first sync on the buffer
- * 2) render the buffer
- * 3) unref the buffer
- */
-static inline GstFlowReturn
-gst_base_sink_handle_buffer (GstBaseSink * basesink, GstBuffer * buf)
-{
- GstFlowReturn ret = GST_FLOW_OK;
- GstClockReturn status;
-
- status = gst_base_sink_do_sync (basesink, buf);
- switch (status) {
- case GST_CLOCK_EARLY:
- GST_DEBUG_OBJECT (basesink, "buffer too late!, rendering anyway");
- /* fallthrough for now */
- case GST_CLOCK_OK:
- {
- GstBaseSinkClass *bclass;
-
- bclass = GST_BASE_SINK_GET_CLASS (basesink);
- if (bclass->render)
- ret = bclass->render (basesink, buf);
- break;
- }
- default:
- GST_DEBUG_OBJECT (basesink, "clock returned %d, not rendering", status);
- break;
- }
-
- GST_DEBUG_OBJECT (basesink, "buffer unref after render %p", basesink, buf);
- gst_buffer_unref (buf);
-
- return ret;
-}
-
-static GstFlowReturn
-gst_base_sink_chain (GstPad * pad, GstBuffer * buf)
-{
- GstBaseSink *basesink;
- GstFlowReturn result;
-
- basesink = GST_BASE_SINK (gst_pad_get_parent (pad));
-
- if (!(basesink->pad_mode == GST_ACTIVATE_PUSH)) {
- GST_OBJECT_LOCK (pad);
- g_warning ("Push on pad %s:%s, but it was not activated in push mode",
- GST_DEBUG_PAD_NAME (pad));
- GST_OBJECT_UNLOCK (pad);
- result = GST_FLOW_UNEXPECTED;
- goto done;
- }
-
- result =
- gst_base_sink_handle_object (basesink, pad, GST_MINI_OBJECT_CAST (buf));
-
-done:
- gst_object_unref (basesink);
-
- return result;
-}
-
-static void
-gst_base_sink_loop (GstPad * pad)
-{
- GstBaseSink *basesink;
- GstBuffer *buf = NULL;
- GstFlowReturn result;
-
- basesink = GST_BASE_SINK (gst_pad_get_parent (pad));
-
- g_assert (basesink->pad_mode == GST_ACTIVATE_PULL);
-
- result = gst_pad_pull_range (pad, basesink->offset, DEFAULT_SIZE, &buf);
- if (result != GST_FLOW_OK)
- goto paused;
-
- result = gst_base_sink_handle_object (basesink, pad, GST_MINI_OBJECT (buf));
- if (result != GST_FLOW_OK)
- goto paused;
-
- gst_object_unref (basesink);
-
- /* default */
- return;
-
-paused:
- {
- gst_base_sink_event (pad, gst_event_new_eos ());
- gst_object_unref (basesink);
- gst_pad_pause_task (pad);
- return;
- }
-}
-
-static gboolean
-gst_base_sink_deactivate (GstBaseSink * basesink, GstPad * pad)
-{
- gboolean result = FALSE;
- GstBaseSinkClass *bclass;
-
- bclass = GST_BASE_SINK_GET_CLASS (basesink);
-
- /* step 1, unblock clock sync (if any) or any other blocking thing */
- GST_PAD_PREROLL_LOCK (pad);
- GST_OBJECT_LOCK (basesink);
- if (basesink->clock_id) {
- gst_clock_id_unschedule (basesink->clock_id);
- }
- GST_OBJECT_UNLOCK (basesink);
-
- /* unlock any subclasses */
- if (bclass->unlock)
- bclass->unlock (basesink);
-
- /* flush out the data thread if it's locked in finish_preroll */
- GST_DEBUG_OBJECT (basesink,
- "flushing out data thread, need preroll to FALSE");
- basesink->need_preroll = FALSE;
- gst_base_sink_preroll_queue_flush (basesink, pad);
- GST_PAD_PREROLL_SIGNAL (pad);
- GST_PAD_PREROLL_UNLOCK (pad);
-
- /* step 2, make sure streaming finishes */
- result = gst_pad_stop_task (pad);
-
- return result;
-}
-
-static gboolean
-gst_base_sink_activate (GstPad * pad)
-{
- gboolean result = FALSE;
- GstBaseSink *basesink;
-
- basesink = GST_BASE_SINK (gst_pad_get_parent (pad));
-
- GST_DEBUG_OBJECT (basesink, "Trying pull mode first");
-
- if (basesink->can_activate_pull && gst_pad_check_pull_range (pad)
- && gst_pad_activate_pull (pad, TRUE)) {
- GST_DEBUG_OBJECT (basesink, "Success activating pull mode");
- result = TRUE;
- } else {
- GST_DEBUG_OBJECT (basesink, "Falling back to push mode");
- if (gst_pad_activate_push (pad, TRUE)) {
- GST_DEBUG_OBJECT (basesink, "Success activating push mode");
- result = TRUE;
- }
- }
-
- if (!result) {
- GST_WARNING_OBJECT (basesink, "Could not activate pad in either mode");
- }
-
- gst_object_unref (basesink);
-
- return result;
-}
-
-static gboolean
-gst_base_sink_activate_push (GstPad * pad, gboolean active)
-{
- gboolean result;
- GstBaseSink *basesink;
-
- basesink = GST_BASE_SINK (gst_pad_get_parent (pad));
-
- if (active) {
- if (!basesink->can_activate_push) {
- result = FALSE;
- basesink->pad_mode = GST_ACTIVATE_NONE;
- } else {
- result = TRUE;
- basesink->pad_mode = GST_ACTIVATE_PUSH;
- }
- } else {
- if (G_UNLIKELY (basesink->pad_mode != GST_ACTIVATE_PUSH)) {
- g_warning ("Internal GStreamer activation error!!!");
- result = FALSE;
- } else {
- result = gst_base_sink_deactivate (basesink, pad);
- basesink->pad_mode = GST_ACTIVATE_NONE;
- }
- }
-
- gst_object_unref (basesink);
-
- return result;
-}
-
-/* this won't get called until we implement an activate function */
-static gboolean
-gst_base_sink_activate_pull (GstPad * pad, gboolean active)
-{
- gboolean result = FALSE;
- GstBaseSink *basesink;
-
- basesink = GST_BASE_SINK (gst_pad_get_parent (pad));
-
- if (active) {
- if (!basesink->can_activate_pull) {
- result = FALSE;
- basesink->pad_mode = GST_ACTIVATE_NONE;
- } else {
- GstPad *peer = gst_pad_get_peer (pad);
-
- if (G_UNLIKELY (peer == NULL)) {
- g_warning ("Trying to activate pad in pull mode, but no peer");
- result = FALSE;
- basesink->pad_mode = GST_ACTIVATE_NONE;
- } else {
- if (gst_pad_activate_pull (peer, TRUE)) {
- basesink->have_newsegment = TRUE;
- gst_segment_init (&basesink->segment, GST_FORMAT_UNDEFINED);
-
- /* set the pad mode before starting the task so that it's in the
- correct state for the new thread... */
- basesink->pad_mode = GST_ACTIVATE_PULL;
- result =
- gst_pad_start_task (pad, (GstTaskFunction) gst_base_sink_loop,
- pad);
- /* but if starting the thread fails, set it back */
- if (!result)
- basesink->pad_mode = GST_ACTIVATE_NONE;
- } else {
- GST_DEBUG_OBJECT (pad, "Failed to activate peer in pull mode");
- result = FALSE;
- basesink->pad_mode = GST_ACTIVATE_NONE;
- }
- gst_object_unref (peer);
- }
- }
- } else {
- if (G_UNLIKELY (basesink->pad_mode != GST_ACTIVATE_PULL)) {
- g_warning ("Internal GStreamer activation error!!!");
- result = FALSE;
- } else {
- basesink->have_newsegment = FALSE;
- result = gst_base_sink_deactivate (basesink, pad);
- basesink->pad_mode = GST_ACTIVATE_NONE;
- }
- }
-
- gst_object_unref (basesink);
-
- return result;
-}
-
-static gboolean
-gst_base_sink_send_event (GstElement * element, GstEvent * event)
-{
- GstPad *pad;
- GstBaseSink *basesink = GST_BASE_SINK (element);
- gboolean result;
-
- GST_OBJECT_LOCK (element);
- pad = basesink->sinkpad;
- gst_object_ref (pad);
- GST_OBJECT_UNLOCK (element);
-
- result = gst_pad_push_event (pad, event);
-
- gst_object_unref (pad);
-
- return result;
-}
-
-static gboolean
-gst_base_sink_peer_query (GstBaseSink * sink, GstQuery * query)
-{
- GstPad *peer;
- gboolean res = FALSE;
-
- if ((peer = gst_pad_get_peer (sink->sinkpad))) {
- res = gst_pad_query (peer, query);
- gst_object_unref (peer);
- }
- return res;
-}
-
-static gboolean
-gst_base_sink_get_position (GstBaseSink * basesink, GstFormat format,
- gint64 * cur)
-{
- GstClock *clock;
- gboolean res = FALSE;
-
- switch (format) {
- case GST_FORMAT_TIME:
- {
- /* we can answer time format */
- GST_OBJECT_LOCK (basesink);
- if ((clock = GST_ELEMENT_CLOCK (basesink))) {
- GstClockTime now;
- gint64 time;
-
- gst_object_ref (clock);
- GST_OBJECT_UNLOCK (basesink);
-
- now = gst_clock_get_time (clock);
-
- GST_OBJECT_LOCK (basesink);
- if (GST_CLOCK_TIME_IS_VALID (basesink->segment.time))
- time = basesink->segment.time;
- else
- time = 0;
-
- *cur = now - GST_ELEMENT_CAST (basesink)->base_time -
- basesink->segment.accum + time;
-
- GST_DEBUG_OBJECT (basesink,
- "now %" GST_TIME_FORMAT " + segment_time %" GST_TIME_FORMAT " = %"
- GST_TIME_FORMAT, GST_TIME_ARGS (now),
- GST_TIME_ARGS (time), GST_TIME_ARGS (*cur));
-
- gst_object_unref (clock);
-
- res = TRUE;
- }
- GST_OBJECT_UNLOCK (basesink);
- }
- default:
- break;
- }
- return res;
-}
-
-static gboolean
-gst_base_sink_query (GstElement * element, GstQuery * query)
-{
- gboolean res = FALSE;
-
- GstBaseSink *basesink = GST_BASE_SINK (element);
-
- switch (GST_QUERY_TYPE (query)) {
- case GST_QUERY_POSITION:
- {
- gint64 cur = 0;
- GstFormat format;
- gboolean eos;
-
- GST_PAD_PREROLL_LOCK (basesink->sinkpad);
- eos = basesink->eos;
- GST_PAD_PREROLL_UNLOCK (basesink->sinkpad);
-
- if (eos) {
- res = gst_base_sink_peer_query (basesink, query);
- } else {
- gst_query_parse_position (query, &format, NULL);
-
- GST_DEBUG_OBJECT (basesink, "current position format %d", format);
-
- if ((res = gst_base_sink_get_position (basesink, format, &cur))) {
- gst_query_set_position (query, format, cur);
- } else {
- res = gst_base_sink_peer_query (basesink, query);
- }
- }
- break;
- }
- case GST_QUERY_DURATION:
- res = gst_base_sink_peer_query (basesink, query);
- break;
- case GST_QUERY_LATENCY:
- break;
- case GST_QUERY_JITTER:
- break;
- case GST_QUERY_RATE:
- //gst_query_set_rate (query, basesink->segment_rate);
- res = TRUE;
- break;
- case GST_QUERY_SEGMENT:
- {
- /* FIXME, bring start/stop to stream time */
- gst_query_set_segment (query, basesink->segment.rate,
- GST_FORMAT_TIME, basesink->segment.start, basesink->segment.stop);
- break;
- }
- case GST_QUERY_SEEKING:
- case GST_QUERY_CONVERT:
- case GST_QUERY_FORMATS:
- default:
- res = gst_base_sink_peer_query (basesink, query);
- break;
- }
- return res;
-}
-
-static GstStateChangeReturn
-gst_base_sink_change_state (GstElement * element, GstStateChange transition)
-{
- GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
- GstBaseSink *basesink = GST_BASE_SINK (element);
- GstBaseSinkClass *bclass;
-
- bclass = GST_BASE_SINK_GET_CLASS (basesink);
-
- switch (transition) {
- case GST_STATE_CHANGE_NULL_TO_READY:
- if (bclass->start)
- if (!bclass->start (basesink))
- goto start_failed;
- break;
- case GST_STATE_CHANGE_READY_TO_PAUSED:
- /* need to complete preroll before this state change completes, there
- * is no data flow in READY so we can safely assume we need to preroll. */
- basesink->offset = 0;
- GST_PAD_PREROLL_LOCK (basesink->sinkpad);
- basesink->have_preroll = FALSE;
- GST_DEBUG_OBJECT (basesink, "READY to PAUSED, need preroll to FALSE");
- basesink->need_preroll = TRUE;
- GST_PAD_PREROLL_UNLOCK (basesink->sinkpad);
- gst_segment_init (&basesink->segment, GST_FORMAT_UNDEFINED);
- basesink->have_newsegment = FALSE;
- ret = GST_STATE_CHANGE_ASYNC;
- break;
- case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
- GST_PAD_PREROLL_LOCK (basesink->sinkpad);
- /* no preroll needed */
- basesink->need_preroll = FALSE;
-
- /* if we have EOS, we should empty the queue now as there will
- * be no more data received in the chain function.
- * FIXME, this could block the state change function too long when
- * we are pushing and syncing the buffers, better start a new
- * thread to do this. */
- if (basesink->eos) {
- gboolean do_eos = !basesink->eos_queued;
-
- gst_base_sink_preroll_queue_empty (basesink, basesink->sinkpad);
-
- /* need to post EOS message here if it was not in the preroll queue we
- * just emptied. */
- if (do_eos) {
- GST_DEBUG_OBJECT (basesink, "Now posting EOS");
- gst_element_post_message (GST_ELEMENT_CAST (basesink),
- gst_message_new_eos (GST_OBJECT_CAST (basesink)));
- }
- } else if (!basesink->have_preroll) {
- /* queue a commit_state */
- basesink->need_preroll = TRUE;
- GST_DEBUG_OBJECT (basesink,
- "PAUSED to PLAYING, !eos, !have_preroll, need preroll to TRUE");
- ret = GST_STATE_CHANGE_ASYNC;
- /* we know it's not waiting, no need to signal */
- } else {
- GST_DEBUG_OBJECT (basesink,
- "PAUSED to PLAYING, !eos, have_preroll, need preroll to FALSE");
- /* now let it play */
- GST_PAD_PREROLL_SIGNAL (basesink->sinkpad);
- }
- GST_PAD_PREROLL_UNLOCK (basesink->sinkpad);
- break;
- default:
- break;
- }
-
- {
- GstStateChangeReturn bret;
-
- bret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
- if (bret == GST_STATE_CHANGE_FAILURE)
- goto activate_failed;
- }
-
- switch (transition) {
- case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
- {
- GstBaseSinkClass *bclass;
-
- bclass = GST_BASE_SINK_GET_CLASS (basesink);
-
- GST_PAD_PREROLL_LOCK (basesink->sinkpad);
- GST_OBJECT_LOCK (basesink);
- /* unlock clock wait if any */
- if (basesink->clock_id) {
- gst_clock_id_unschedule (basesink->clock_id);
- }
- GST_OBJECT_UNLOCK (basesink);
-
- /* unlock any subclasses */
- if (bclass->unlock)
- bclass->unlock (basesink);
-
- /* if we don't have a preroll buffer and we have not received EOS,
- * we need to wait for a preroll */
- GST_DEBUG_OBJECT (basesink, "have_preroll: %d, EOS: %d",
- basesink->have_preroll, basesink->eos);
- if (!basesink->have_preroll && !basesink->eos
- && GST_STATE_PENDING (basesink) == GST_STATE_PAUSED) {
- GST_DEBUG_OBJECT (basesink, "PLAYING to PAUSED, need preroll to TRUE");
- basesink->need_preroll = TRUE;
- ret = GST_STATE_CHANGE_ASYNC;
- }
- GST_PAD_PREROLL_UNLOCK (basesink->sinkpad);
- break;
- }
- case GST_STATE_CHANGE_PAUSED_TO_READY:
- break;
- case GST_STATE_CHANGE_READY_TO_NULL:
- if (bclass->stop)
- if (!bclass->stop (basesink)) {
- GST_WARNING ("failed to stop");
- }
- break;
- default:
- break;
- }
-
- return ret;
-
- /* ERRORS */
-start_failed:
- {
- GST_DEBUG_OBJECT (basesink, "failed to start");
- return GST_STATE_CHANGE_FAILURE;
- }
-activate_failed:
- {
- GST_DEBUG_OBJECT (basesink,
- "element failed to change states -- activation problem?");
- return GST_STATE_CHANGE_FAILURE;
- }
-}
+++ /dev/null
-/* GStreamer
- * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
- * 2000 Wim Taymans <wtay@chello.be>
- *
- * gstbasesink.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., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#ifndef __GST_BASE_SINK_H__
-#define __GST_BASE_SINK_H__
-
-#include <gst/gst.h>
-
-G_BEGIN_DECLS
-
-
-#define GST_TYPE_BASE_SINK (gst_base_sink_get_type())
-#define GST_BASE_SINK(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_BASE_SINK,GstBaseSink))
-#define GST_BASE_SINK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_BASE_SINK,GstBaseSinkClass))
-#define GST_BASE_SINK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_BASE_SINK, GstBaseSinkClass))
-#define GST_IS_BASE_SINK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_BASE_SINK))
-#define GST_IS_BASE_SINK_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_BASE_SINK))
-#define GST_BASE_SINK_CAST(obj) ((GstBaseSink *) (obj))
-
-/**
- * GST_BASE_SINK_PAD:
- * @obj: base sink instance
- *
- * Gives the pointer to the #GstPad object of the element.
- */
-#define GST_BASE_SINK_PAD(obj) (GST_BASE_SINK_CAST (obj)->sinkpad)
-
-typedef struct _GstBaseSink GstBaseSink;
-typedef struct _GstBaseSinkClass GstBaseSinkClass;
-
-/**
- * GstBaseSink:
- *
- * The opaque #GstBaseSink data structure.
- */
-struct _GstBaseSink {
- GstElement element;
-
- /*< protected >*/
- GstPad *sinkpad;
- GstActivateMode pad_mode;
-
- /*< protected >*/ /* with LOCK */
- guint64 offset;
- gboolean can_activate_pull;
- gboolean can_activate_push;
-
- /*< protected >*/ /* with PREROLL_LOCK */
- GQueue *preroll_queue;
- gint preroll_queue_max_len;
- gint preroll_queued;
- gint buffers_queued;
- gint events_queued;
- gboolean eos;
- gboolean eos_queued;
- gboolean need_preroll;
- gboolean have_preroll;
- gboolean playing_async;
-
- /*< protected >*/ /* with STREAM_LOCK */
- gboolean have_newsegment;
- GstSegment segment;
-
- /*< private >*/ /* with LOCK */
- GstClockID clock_id;
- GstClockTime end_time;
- gboolean sync;
- gboolean flushing;
-
- /*< private >*/
- gpointer _gst_reserved[GST_PADDING];
-};
-
-struct _GstBaseSinkClass {
- GstElementClass parent_class;
-
- /* get caps from subclass */
- GstCaps* (*get_caps) (GstBaseSink *sink);
- /* notify subclass of new caps */
- gboolean (*set_caps) (GstBaseSink *sink, GstCaps *caps);
-
- /* allocate a new buffer with given caps */
- GstFlowReturn (*buffer_alloc) (GstBaseSink *sink, guint64 offset, guint size,
- GstCaps *caps, GstBuffer **buf);
-
- /* get the start and end times for syncing on this buffer */
- void (*get_times) (GstBaseSink *sink, GstBuffer *buffer,
- GstClockTime *start, GstClockTime *end);
-
- /* start and stop processing, ideal for opening/closing the resource */
- gboolean (*start) (GstBaseSink *sink);
- gboolean (*stop) (GstBaseSink *sink);
-
- /* unlock any pending access to the resource. subclasses should unlock
- * any function ASAP. */
- gboolean (*unlock) (GstBaseSink *sink);
-
- /* notify subclass of event, preroll buffer or real buffer */
- gboolean (*event) (GstBaseSink *sink, GstEvent *event);
- GstFlowReturn (*preroll) (GstBaseSink *sink, GstBuffer *buffer);
- GstFlowReturn (*render) (GstBaseSink *sink, GstBuffer *buffer);
-
- /*< private >*/
- gpointer _gst_reserved[GST_PADDING];
-};
-
-GType gst_base_sink_get_type(void);
-
-G_END_DECLS
-
-#endif /* __GST_BASE_SINK_H__ */
+++ /dev/null
-/* GStreamer
- * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
- * 2000,2005 Wim Taymans <wim@fluendo.com>
- *
- * gstbasesrc.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., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-/**
- * SECTION:gstbasesrc
- * @short_description: Base class for getrange based source elements
- * @see_also: #GstBaseTransform, #GstBaseSink
- *
- * This class is mostly useful for elements that do byte based
- * access to a random access resource, like files.
- * If random access is not possible, the live-mode should be set
- * to TRUE.
- *
- * <itemizedlist>
- * <listitem><para>one source pad</para></listitem>
- * <listitem><para>handles state changes</para></listitem>
- * <listitem><para>does flushing</para></listitem>
- * <listitem><para>preroll with optional preview</para></listitem>
- * <listitem><para>pull/push mode</para></listitem>
- * <listitem><para>EOS handling</para></listitem>
- * </itemizedlist>
- */
-
-#include <stdlib.h>
-#include <string.h>
-
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#include "gstbasesrc.h"
-#include "gsttypefindhelper.h"
-#include <gst/gstmarshal.h>
-#include <gst/gst-i18n-lib.h>
-
-#define DEFAULT_BLOCKSIZE 4096
-#define DEFAULT_NUM_BUFFERS -1
-
-GST_DEBUG_CATEGORY_STATIC (gst_base_src_debug);
-#define GST_CAT_DEFAULT gst_base_src_debug
-
-#define GST_LIVE_GET_LOCK(elem) (GST_BASE_SRC_CAST(elem)->live_lock)
-#define GST_LIVE_LOCK(elem) g_mutex_lock(GST_LIVE_GET_LOCK(elem))
-#define GST_LIVE_TRYLOCK(elem) g_mutex_trylock(GST_LIVE_GET_LOCK(elem))
-#define GST_LIVE_UNLOCK(elem) g_mutex_unlock(GST_LIVE_GET_LOCK(elem))
-#define GST_LIVE_GET_COND(elem) (GST_BASE_SRC_CAST(elem)->live_cond)
-#define GST_LIVE_WAIT(elem) g_cond_wait (GST_LIVE_GET_COND (elem), GST_LIVE_GET_LOCK (elem))
-#define GST_LIVE_TIMED_WAIT(elem, timeval) g_cond_timed_wait (GST_LIVE_GET_COND (elem), GST_LIVE_GET_LOCK (elem),\
- timeval)
-#define GST_LIVE_SIGNAL(elem) g_cond_signal (GST_LIVE_GET_COND (elem));
-#define GST_LIVE_BROADCAST(elem) g_cond_broadcast (GST_LIVE_GET_COND (elem));
-
-/* BaseSrc signals and args */
-enum
-{
- /* FILL ME */
- LAST_SIGNAL
-};
-
-enum
-{
- PROP_0,
- PROP_BLOCKSIZE,
- PROP_NUM_BUFFERS,
-};
-
-static GstElementClass *parent_class = NULL;
-
-static void gst_base_src_base_init (gpointer g_class);
-static void gst_base_src_class_init (GstBaseSrcClass * klass);
-static void gst_base_src_init (GstBaseSrc * src, gpointer g_class);
-static void gst_base_src_finalize (GObject * object);
-
-
-GType
-gst_base_src_get_type (void)
-{
- static GType base_src_type = 0;
-
- if (!base_src_type) {
- static const GTypeInfo base_src_info = {
- sizeof (GstBaseSrcClass),
- (GBaseInitFunc) gst_base_src_base_init,
- NULL,
- (GClassInitFunc) gst_base_src_class_init,
- NULL,
- NULL,
- sizeof (GstBaseSrc),
- 0,
- (GInstanceInitFunc) gst_base_src_init,
- };
-
- base_src_type = g_type_register_static (GST_TYPE_ELEMENT,
- "GstBaseSrc", &base_src_info, G_TYPE_FLAG_ABSTRACT);
- }
- return base_src_type;
-}
-static GstCaps *gst_base_src_getcaps (GstPad * pad);
-static gboolean gst_base_src_setcaps (GstPad * pad, GstCaps * caps);
-
-static gboolean gst_base_src_activate_push (GstPad * pad, gboolean active);
-static gboolean gst_base_src_activate_pull (GstPad * pad, gboolean active);
-static void gst_base_src_set_property (GObject * object, guint prop_id,
- const GValue * value, GParamSpec * pspec);
-static void gst_base_src_get_property (GObject * object, guint prop_id,
- GValue * value, GParamSpec * pspec);
-static gboolean gst_base_src_event_handler (GstPad * pad, GstEvent * event);
-static gboolean gst_base_src_send_event (GstElement * elem, GstEvent * event);
-
-static gboolean gst_base_src_query (GstPad * pad, GstQuery * query);
-
-static gboolean gst_base_src_default_negotiate (GstBaseSrc * basesrc);
-static gboolean gst_base_src_default_newsegment (GstBaseSrc * src);
-
-static gboolean gst_base_src_unlock (GstBaseSrc * basesrc);
-static gboolean gst_base_src_get_size (GstBaseSrc * basesrc, guint64 * size);
-static gboolean gst_base_src_start (GstBaseSrc * basesrc);
-static gboolean gst_base_src_stop (GstBaseSrc * basesrc);
-
-static GstStateChangeReturn gst_base_src_change_state (GstElement * element,
- GstStateChange transition);
-
-static void gst_base_src_loop (GstPad * pad);
-static gboolean gst_base_src_check_get_range (GstPad * pad);
-static GstFlowReturn gst_base_src_pad_get_range (GstPad * pad, guint64 offset,
- guint length, GstBuffer ** buf);
-static GstFlowReturn gst_base_src_get_range (GstBaseSrc * src, guint64 offset,
- guint length, GstBuffer ** buf);
-
-static void
-gst_base_src_base_init (gpointer g_class)
-{
- GST_DEBUG_CATEGORY_INIT (gst_base_src_debug, "basesrc", 0, "basesrc element");
-}
-
-static void
-gst_base_src_class_init (GstBaseSrcClass * klass)
-{
- GObjectClass *gobject_class;
- GstElementClass *gstelement_class;
-
- gobject_class = (GObjectClass *) klass;
- gstelement_class = (GstElementClass *) klass;
-
- parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
-
- gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_base_src_finalize);
- gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_base_src_set_property);
- gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_base_src_get_property);
-
- g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_BLOCKSIZE,
- g_param_spec_ulong ("blocksize", "Block size",
- "Size in bytes to read per buffer", 1, G_MAXULONG, DEFAULT_BLOCKSIZE,
- G_PARAM_READWRITE));
-
- g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_NUM_BUFFERS,
- g_param_spec_int ("num-buffers", "num-buffers",
- "Number of buffers to output before sending EOS", -1, G_MAXINT,
- DEFAULT_NUM_BUFFERS, G_PARAM_READWRITE));
-
- gstelement_class->change_state =
- GST_DEBUG_FUNCPTR (gst_base_src_change_state);
- gstelement_class->send_event = GST_DEBUG_FUNCPTR (gst_base_src_send_event);
-
- klass->negotiate = gst_base_src_default_negotiate;
- klass->newsegment = gst_base_src_default_newsegment;
-}
-
-static void
-gst_base_src_init (GstBaseSrc * basesrc, gpointer g_class)
-{
- GstPad *pad;
- GstPadTemplate *pad_template;
-
- basesrc->is_live = FALSE;
- basesrc->live_lock = g_mutex_new ();
- basesrc->live_cond = g_cond_new ();
- basesrc->num_buffers = DEFAULT_NUM_BUFFERS;
- basesrc->num_buffers_left = -1;
-
- basesrc->can_activate_push = TRUE;
- basesrc->pad_mode = GST_ACTIVATE_NONE;
-
- pad_template =
- gst_element_class_get_pad_template (GST_ELEMENT_CLASS (g_class), "src");
- g_return_if_fail (pad_template != NULL);
-
- GST_DEBUG_OBJECT (basesrc, "creating src pad");
- pad = gst_pad_new_from_template (pad_template, "src");
-
- GST_DEBUG_OBJECT (basesrc, "setting functions on src pad");
- gst_pad_set_activatepush_function (pad,
- GST_DEBUG_FUNCPTR (gst_base_src_activate_push));
- gst_pad_set_activatepull_function (pad,
- GST_DEBUG_FUNCPTR (gst_base_src_activate_pull));
- gst_pad_set_event_function (pad,
- GST_DEBUG_FUNCPTR (gst_base_src_event_handler));
- gst_pad_set_query_function (pad, GST_DEBUG_FUNCPTR (gst_base_src_query));
- gst_pad_set_checkgetrange_function (pad,
- GST_DEBUG_FUNCPTR (gst_base_src_check_get_range));
- gst_pad_set_getrange_function (pad,
- GST_DEBUG_FUNCPTR (gst_base_src_pad_get_range));
- gst_pad_set_getcaps_function (pad, GST_DEBUG_FUNCPTR (gst_base_src_getcaps));
- gst_pad_set_setcaps_function (pad, GST_DEBUG_FUNCPTR (gst_base_src_setcaps));
-
- /* hold pointer to pad */
- basesrc->srcpad = pad;
- GST_DEBUG_OBJECT (basesrc, "adding src pad");
- gst_element_add_pad (GST_ELEMENT (basesrc), pad);
-
- basesrc->blocksize = DEFAULT_BLOCKSIZE;
- basesrc->clock_id = NULL;
- gst_segment_init (&basesrc->segment, GST_FORMAT_BYTES);
-
- GST_OBJECT_FLAG_UNSET (basesrc, GST_BASE_SRC_STARTED);
-
- GST_DEBUG_OBJECT (basesrc, "init done");
-}
-
-static void
-gst_base_src_finalize (GObject * object)
-{
- GstBaseSrc *basesrc;
-
- basesrc = GST_BASE_SRC (object);
-
- g_mutex_free (basesrc->live_lock);
- g_cond_free (basesrc->live_cond);
-
- G_OBJECT_CLASS (parent_class)->finalize (object);
-}
-
-/**
- * gst_base_src_set_live:
- * @src: base source instance
- * @live: new live-mode
- *
- * If the element listens to a live source, the @livemode should
- * be set to %TRUE. This declares that this source can't seek.
- */
-void
-gst_base_src_set_live (GstBaseSrc * src, gboolean live)
-{
- GST_LIVE_LOCK (src);
- src->is_live = live;
- GST_LIVE_UNLOCK (src);
-}
-
-/**
- * gst_base_src_is_live:
- * @src: base source instance
- *
- * Check if an element is in live mode.
- *
- * Returns: %TRUE if element is in live mode.
- */
-gboolean
-gst_base_src_is_live (GstBaseSrc * src)
-{
- gboolean result;
-
- GST_LIVE_LOCK (src);
- result = src->is_live;
- GST_LIVE_UNLOCK (src);
-
- return result;
-}
-
-static gboolean
-gst_base_src_setcaps (GstPad * pad, GstCaps * caps)
-{
- GstBaseSrcClass *bclass;
- GstBaseSrc *bsrc;
- gboolean res = TRUE;
-
- bsrc = GST_BASE_SRC (GST_PAD_PARENT (pad));
- bclass = GST_BASE_SRC_GET_CLASS (bsrc);
-
- if (bclass->set_caps)
- res = bclass->set_caps (bsrc, caps);
-
- return res;
-}
-
-static GstCaps *
-gst_base_src_getcaps (GstPad * pad)
-{
- GstBaseSrcClass *bclass;
- GstBaseSrc *bsrc;
- GstCaps *caps = NULL;
-
- bsrc = GST_BASE_SRC (GST_PAD_PARENT (pad));
- bclass = GST_BASE_SRC_GET_CLASS (bsrc);
- if (bclass->get_caps)
- caps = bclass->get_caps (bsrc);
-
- if (caps == NULL) {
- GstPadTemplate *pad_template;
-
- pad_template =
- gst_element_class_get_pad_template (GST_ELEMENT_CLASS (bclass), "src");
- if (pad_template != NULL) {
- caps = gst_caps_ref (gst_pad_template_get_caps (pad_template));
- }
- }
- return caps;
-}
-
-static gboolean
-gst_base_src_query (GstPad * pad, GstQuery * query)
-{
- GstBaseSrc *src;
- gboolean res;
-
- src = GST_BASE_SRC (gst_pad_get_parent (pad));
-
- switch (GST_QUERY_TYPE (query)) {
- case GST_QUERY_POSITION:
- {
- GstFormat format;
-
- gst_query_parse_position (query, &format, NULL);
- switch (format) {
- case GST_FORMAT_DEFAULT:
- case GST_FORMAT_BYTES:
- gst_query_set_position (query, GST_FORMAT_BYTES, src->offset);
- res = TRUE;
- break;
- case GST_FORMAT_PERCENT:
- {
- gboolean b;
- gint64 i64;
- guint64 ui64;
-
- b = gst_base_src_get_size (src, &ui64);
- if (b && src->offset < ui64)
- i64 = gst_util_uint64_scale (GST_FORMAT_PERCENT_MAX, src->offset,
- ui64);
- else
- i64 = GST_FORMAT_PERCENT_MAX;
-
- gst_query_set_position (query, GST_FORMAT_PERCENT, i64);
- res = TRUE;
- break;
- }
- default:
- res = FALSE;
- break;
- }
- break;
- }
- case GST_QUERY_DURATION:
- {
- GstFormat format;
-
- gst_query_parse_duration (query, &format, NULL);
- switch (format) {
- case GST_FORMAT_DEFAULT:
- case GST_FORMAT_BYTES:
- {
- gboolean b;
- gint64 i64;
- guint64 ui64;
-
- b = gst_base_src_get_size (src, &ui64);
- /* better to make get_size take an int64 */
- i64 = b ? (gint64) ui64 : -1;
- gst_query_set_duration (query, GST_FORMAT_BYTES, i64);
- res = TRUE;
- break;
- }
- case GST_FORMAT_PERCENT:
- gst_query_set_duration (query, GST_FORMAT_PERCENT,
- GST_FORMAT_PERCENT_MAX);
- res = TRUE;
- break;
- default:
- res = FALSE;
- break;
- }
- break;
- }
-
- case GST_QUERY_SEEKING:
- gst_query_set_seeking (query, GST_FORMAT_BYTES,
- src->seekable, 0, src->size);
- res = TRUE;
- break;
-
- case GST_QUERY_SEGMENT:
- {
- gint64 start, stop;
-
- start = src->segment.start;
- /* no end segment configured, current size then */
- if ((stop = src->segment.stop) == -1)
- stop = src->size;
-
- /* FIXME, we can't report our rate as we did not store it, d'oh!.
- * Also, subclasses might want to support other formats. */
- gst_query_set_segment (query, 1.0, GST_FORMAT_BYTES, start, stop);
- res = TRUE;
- break;
- }
-
- case GST_QUERY_FORMATS:
- gst_query_set_formats (query, 3, GST_FORMAT_DEFAULT,
- GST_FORMAT_BYTES, GST_FORMAT_PERCENT);
- res = TRUE;
- break;
-
- case GST_QUERY_LATENCY:
- case GST_QUERY_JITTER:
- case GST_QUERY_RATE:
- case GST_QUERY_CONVERT:
- default:
- res = gst_pad_query_default (pad, query);
- break;
- }
-
- gst_object_unref (src);
- return res;
-}
-
-static gboolean
-gst_base_src_default_newsegment (GstBaseSrc * src)
-{
- GstEvent *event;
-
- GST_DEBUG_OBJECT (src, "Sending newsegment from %" G_GINT64_FORMAT
- " to %" G_GINT64_FORMAT, src->segment.start, src->segment.stop);
-
- event = gst_event_new_new_segment (FALSE, 1.0,
- GST_FORMAT_BYTES, src->segment.start, src->segment.stop,
- src->segment.start);
-
- return gst_pad_push_event (src->srcpad, event);
-}
-
-static gboolean
-gst_base_src_newsegment (GstBaseSrc * src)
-{
- GstBaseSrcClass *bclass;
- gboolean result = FALSE;
-
- bclass = GST_BASE_SRC_GET_CLASS (src);
-
- if (bclass->newsegment)
- result = bclass->newsegment (src);
-
- return result;
-}
-
-/* based on the event parameters configure the segment.start/stop
- * times. Called with STREAM_LOCK.
- */
-static gboolean
-gst_base_src_configure_segment (GstBaseSrc * src, GstEvent * event)
-{
- gdouble rate;
- GstFormat format;
- GstSeekFlags flags;
- GstSeekType cur_type, stop_type;
- gint64 cur, stop;
- gboolean update;
-
- gst_event_parse_seek (event, &rate, &format, &flags,
- &cur_type, &cur, &stop_type, &stop);
-
- gst_segment_set_seek (&src->segment, rate, format, flags,
- cur_type, cur, stop_type, stop, &update);
-
- /* update our offset if it was updated */
- if (update)
- src->offset = cur;
-
- GST_DEBUG_OBJECT (src, "segment configured from %" G_GINT64_FORMAT
- " to %" G_GINT64_FORMAT, src->segment.start, src->segment.stop);
-
- return TRUE;
-}
-
-/* this code implements the seeking. It is a good example
- * handling all cases (modulo the FIXMEs).
- *
- * A seek updates the currently configured segment.start
- * and segment.stop values based on the SEEK_TYPE. If the
- * segment.start value is updated, a seek to this new position
- * should be performed.
- *
- * The seek can only be executed when we are not currently
- * streaming any data, to make sure that this is the case, we
- * acquire the STREAM_LOCK which is taken when we are in the
- * _loop() function or when a getrange() is called. Normally
- * we will not receive a seek if we are operating in pull mode
- * though.
- *
- * When we are in the loop() function, we might be in the middle
- * of pushing a buffer, which might block in a sink. To make sure
- * that the push gets unblocked we push out a FLUSH_START event.
- * Our loop function will get a WRONG_STATE return value from
- * the push and will pause, effectively releasing the STREAM_LOCK.
- *
- * For a non-flushing seek, we pause the task, which might eventually
- * release the STREAM_LOCK. We say eventually because when the sink
- * blocks on the sample we might wait a very long time until the sink
- * unblocks the sample. In any case we acquire the STREAM_LOCK and
- * can continue the seek. A non-flushing seek is normally done in a
- * running pipeline to perform seamless playback.
- *
- * After updating the segment.start/stop values, we prepare for
- * streaming again. We push out a FLUSH_STOP to make the peer pad
- * accept data again and we start our task again.
- *
- * A segment seek posts a message on the bus saying that the playback
- * of the segment started. We store the segment flag internally because
- * when we reach the segment.stop we have to post a segment.done
- * instead of EOS when doing a segment seek.
- */
-static gboolean
-gst_base_src_do_seek (GstBaseSrc * src, GstEvent * event)
-{
- gdouble rate;
- GstFormat format;
- GstSeekFlags flags;
- gboolean flush;
-
- gst_event_parse_seek (event, &rate, &format, &flags, NULL, NULL, NULL, NULL);
-
- /* FIXME subclasses should be able to provide other formats */
- /* get seek format */
- if (format == GST_FORMAT_DEFAULT)
- format = GST_FORMAT_BYTES;
- /* we can only seek bytes */
- if (format != GST_FORMAT_BYTES)
- goto unsupported_seek;
-
- flush = flags & GST_SEEK_FLAG_FLUSH;
-
- /* send flush start */
- if (flush)
- gst_pad_push_event (src->srcpad, gst_event_new_flush_start ());
- else
- gst_pad_pause_task (src->srcpad);
-
- /* unblock streaming thread */
- gst_base_src_unlock (src);
-
- /* grab streaming lock, this should eventually be possible, either
- * because the task is paused or out streaming thread stopped
- * because our peer is flushing. */
- GST_PAD_STREAM_LOCK (src->srcpad);
-
- /* now configure the segment */
- gst_base_src_configure_segment (src, event);
-
- /* and prepare to continue streaming */
- if (flush)
- /* send flush stop, peer will accept data and events again. We
- * are not yet providing data as we still have the STREAM_LOCK. */
- gst_pad_push_event (src->srcpad, gst_event_new_flush_stop ());
-
- /* now make sure the newsegment will be send from the streaming
- * thread. We could opt to send it here too. */
- src->need_newsegment = TRUE;
-
- if (src->segment.flags & GST_SEEK_FLAG_SEGMENT) {
- /* FIXME subclasses should be able to provide other formats */
- gst_element_post_message (GST_ELEMENT (src),
- gst_message_new_segment_start (GST_OBJECT (src), GST_FORMAT_BYTES,
- src->segment.start));
- }
-
- /* and restart the task in case it got paused explicitely or by
- * the FLUSH_START event we pushed out. */
- gst_pad_start_task (src->srcpad, (GstTaskFunction) gst_base_src_loop,
- src->srcpad);
-
- /* and release the lock again so we can continue streaming */
- GST_PAD_STREAM_UNLOCK (src->srcpad);
-
- return TRUE;
-
- /* ERROR */
-unsupported_seek:
- {
- GST_DEBUG_OBJECT (src, "invalid format, seek aborted.");
-
- return FALSE;
- }
-}
-
-/* all events send to this element directly
- */
-static gboolean
-gst_base_src_send_event (GstElement * element, GstEvent * event)
-{
- GstBaseSrc *src;
- gboolean result;
-
- src = GST_BASE_SRC (element);
-
- switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_SEEK:
- result = gst_base_src_configure_segment (src, event);
- break;
- default:
- result = FALSE;
- break;
- }
-
- return result;
-}
-
-static gboolean
-gst_base_src_event_handler (GstPad * pad, GstEvent * event)
-{
- GstBaseSrc *src;
- GstBaseSrcClass *bclass;
- gboolean result;
-
- src = GST_BASE_SRC (gst_pad_get_parent (pad));
- bclass = GST_BASE_SRC_GET_CLASS (src);
-
- if (bclass->event) {
- if (!(result = bclass->event (src, event)))
- goto subclass_failed;
- }
-
- switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_SEEK:
- /* is normally called when in push mode */
- if (!src->seekable)
- goto not_seekable;
-
- result = gst_base_src_do_seek (src, event);
- break;
- case GST_EVENT_FLUSH_START:
- /* cancel any blocking getrange, is normally called
- * when in pull mode. */
- result = gst_base_src_unlock (src);
- break;
- case GST_EVENT_FLUSH_STOP:
- default:
- result = TRUE;
- break;
- }
- gst_event_unref (event);
- gst_object_unref (src);
-
- return result;
-
- /* ERRORS */
-subclass_failed:
- {
- GST_DEBUG_OBJECT (src, "subclass refused event");
- gst_object_unref (src);
- gst_event_unref (event);
- return result;
- }
-not_seekable:
- {
- GST_DEBUG_OBJECT (src, "is not seekable");
- gst_object_unref (src);
- gst_event_unref (event);
- return FALSE;
- }
-}
-
-static void
-gst_base_src_set_property (GObject * object, guint prop_id,
- const GValue * value, GParamSpec * pspec)
-{
- GstBaseSrc *src;
-
- src = GST_BASE_SRC (object);
-
- switch (prop_id) {
- case PROP_BLOCKSIZE:
- src->blocksize = g_value_get_ulong (value);
- break;
- case PROP_NUM_BUFFERS:
- src->num_buffers = g_value_get_int (value);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-gst_base_src_get_property (GObject * object, guint prop_id, GValue * value,
- GParamSpec * pspec)
-{
- GstBaseSrc *src;
-
- src = GST_BASE_SRC (object);
-
- switch (prop_id) {
- case PROP_BLOCKSIZE:
- g_value_set_ulong (value, src->blocksize);
- break;
- case PROP_NUM_BUFFERS:
- g_value_set_int (value, src->num_buffers);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-/* with STREAM_LOCK and LOCK*/
-static GstClockReturn
-gst_base_src_wait (GstBaseSrc * basesrc, GstClockTime time)
-{
- GstClockReturn ret;
- GstClockID id;
- GstClock *clock;
-
- if ((clock = GST_ELEMENT_CLOCK (basesrc)) == NULL)
- return GST_CLOCK_OK;
-
- /* clock_id should be NULL outside of this function */
- g_assert (basesrc->clock_id == NULL);
- g_assert (GST_CLOCK_TIME_IS_VALID (time));
-
- id = gst_clock_new_single_shot_id (clock, time);
-
- basesrc->clock_id = id;
- /* release the object lock while waiting */
- GST_OBJECT_UNLOCK (basesrc);
-
- ret = gst_clock_id_wait (id, NULL);
-
- GST_OBJECT_LOCK (basesrc);
- gst_clock_id_unref (id);
- basesrc->clock_id = NULL;
-
- return ret;
-}
-
-
-/* perform synchronisation on a buffer
- */
-static GstClockReturn
-gst_base_src_do_sync (GstBaseSrc * basesrc, GstBuffer * buffer)
-{
- GstClockReturn result = GST_CLOCK_OK;
- GstClockTime start, end;
- GstBaseSrcClass *bclass;
- gboolean start_valid;
- GstClockTime base_time;
-
- bclass = GST_BASE_SRC_GET_CLASS (basesrc);
-
- start = end = -1;
- if (bclass->get_times)
- bclass->get_times (basesrc, buffer, &start, &end);
-
- start_valid = GST_CLOCK_TIME_IS_VALID (start);
-
- /* if we don't have a timestamp, we don't sync */
- if (!start_valid) {
- GST_DEBUG_OBJECT (basesrc, "get_times returned invalid start");
- goto done;
- }
-
- GST_DEBUG_OBJECT (basesrc, "got times start: %" GST_TIME_FORMAT
- ", end: %" GST_TIME_FORMAT, GST_TIME_ARGS (start), GST_TIME_ARGS (end));
-
- /* now do clocking */
- GST_OBJECT_LOCK (basesrc);
- base_time = GST_ELEMENT_CAST (basesrc)->base_time;
-
- GST_LOG_OBJECT (basesrc,
- "waiting for clock, base time %" GST_TIME_FORMAT
- ", stream_start %" GST_TIME_FORMAT,
- GST_TIME_ARGS (base_time), GST_TIME_ARGS (start));
-
- result = gst_base_src_wait (basesrc, start + base_time);
- GST_OBJECT_UNLOCK (basesrc);
-
- GST_LOG_OBJECT (basesrc, "clock entry done: %d", result);
-
-done:
- return result;
-}
-
-
-static GstFlowReturn
-gst_base_src_get_range (GstBaseSrc * src, guint64 offset, guint length,
- GstBuffer ** buf)
-{
- GstFlowReturn ret;
- GstBaseSrcClass *bclass;
- gint64 maxsize;
- GstClockReturn status;
-
- bclass = GST_BASE_SRC_GET_CLASS (src);
-
- GST_LIVE_LOCK (src);
- if (src->is_live) {
- while (!src->live_running) {
- GST_DEBUG ("live source signal waiting");
- GST_LIVE_SIGNAL (src);
- GST_DEBUG ("live source waiting for running state");
- GST_LIVE_WAIT (src);
- GST_DEBUG ("live source unlocked");
- }
- /* FIXME, use another variable to signal stopping */
- GST_OBJECT_LOCK (src->srcpad);
- if (GST_PAD_IS_FLUSHING (src->srcpad))
- goto flushing;
- GST_OBJECT_UNLOCK (src->srcpad);
- }
- GST_LIVE_UNLOCK (src);
-
- if (!GST_OBJECT_FLAG_IS_SET (src, GST_BASE_SRC_STARTED))
- goto not_started;
-
- if (G_UNLIKELY (!bclass->create))
- goto no_function;
-
- /* the max amount of bytes to read is the total size or
- * up to the segment.stop if present. */
- if (src->segment.stop != -1)
- maxsize = MIN (src->size, src->segment.stop);
- else
- maxsize = src->size;
-
- GST_DEBUG_OBJECT (src,
- "reading offset %" G_GUINT64_FORMAT ", length %u, size %" G_GINT64_FORMAT
- ", segment.stop %" G_GINT64_FORMAT ", maxsize %" G_GINT64_FORMAT, offset,
- length, src->size, src->segment.stop, maxsize);
-
- /* check size */
- if (maxsize != -1) {
- if (offset > maxsize)
- goto unexpected_length;
-
- if (offset + length > maxsize) {
- /* see if length of the file changed */
- if (bclass->get_size)
- bclass->get_size (src, &src->size);
-
- if (src->segment.stop != -1)
- maxsize = MIN (src->size, src->segment.stop);
- else
- maxsize = src->size;
-
- if (offset + length > maxsize) {
- length = maxsize - offset;
- }
- }
- }
- if (length == 0)
- goto unexpected_length;
-
- if (src->num_buffers_left == 0) {
- goto reached_num_buffers;
- } else {
- if (src->num_buffers_left > 0)
- src->num_buffers_left--;
- }
-
- ret = bclass->create (src, offset, length, buf);
- if (ret != GST_FLOW_OK)
- goto done;
-
- /* now sync before pushing the buffer */
- status = gst_base_src_do_sync (src, *buf);
- switch (status) {
- case GST_CLOCK_EARLY:
- GST_DEBUG_OBJECT (src, "buffer too late!, returning anyway");
- break;
- case GST_CLOCK_OK:
- GST_DEBUG_OBJECT (src, "buffer ok");
- break;
- default:
- GST_DEBUG_OBJECT (src, "clock returned %d, not returning", status);
- gst_buffer_unref (*buf);
- *buf = NULL;
- ret = GST_FLOW_WRONG_STATE;
- break;
- }
-done:
- return ret;
-
- /* ERROR */
-flushing:
- {
- GST_DEBUG_OBJECT (src, "pad is flushing");
- GST_OBJECT_UNLOCK (src->srcpad);
- GST_LIVE_UNLOCK (src);
- return GST_FLOW_WRONG_STATE;
- }
-not_started:
- {
- GST_DEBUG_OBJECT (src, "getrange but not started");
- return GST_FLOW_WRONG_STATE;
- }
-no_function:
- {
- GST_DEBUG_OBJECT (src, "no create function");
- return GST_FLOW_ERROR;
- }
-unexpected_length:
- {
- GST_DEBUG_OBJECT (src, "unexpected length %u (offset=%" G_GUINT64_FORMAT
- ", size=%" G_GUINT64_FORMAT ")", length, offset, src->size);
- return GST_FLOW_UNEXPECTED;
- }
-reached_num_buffers:
- {
- GST_DEBUG_OBJECT (src, "sent all buffers");
- return GST_FLOW_UNEXPECTED;
- }
-}
-
-static GstFlowReturn
-gst_base_src_pad_get_range (GstPad * pad, guint64 offset, guint length,
- GstBuffer ** buf)
-{
- GstBaseSrc *src;
- GstFlowReturn res;
-
- src = GST_BASE_SRC (gst_pad_get_parent (pad));
-
- res = gst_base_src_get_range (src, offset, length, buf);
-
- gst_object_unref (src);
-
- return res;
-}
-
-static gboolean
-gst_base_src_check_get_range (GstPad * pad)
-{
- GstBaseSrc *src;
-
- src = GST_BASE_SRC (GST_OBJECT_PARENT (pad));
-
- if (!GST_OBJECT_FLAG_IS_SET (src, GST_BASE_SRC_STARTED)) {
- gst_base_src_start (src);
- gst_base_src_stop (src);
- }
-
- return src->seekable;
-}
-
-static void
-gst_base_src_loop (GstPad * pad)
-{
- GstBaseSrc *src;
- GstBuffer *buf = NULL;
- GstFlowReturn ret;
-
- src = GST_BASE_SRC (gst_pad_get_parent (pad));
-
- /* only send segments when operating in push mode */
- if (G_UNLIKELY (src->need_newsegment)) {
- /* now send newsegment */
- gst_base_src_newsegment (src);
- src->need_newsegment = FALSE;
- }
-
- ret = gst_base_src_get_range (src, src->offset, src->blocksize, &buf);
- if (G_UNLIKELY (ret != GST_FLOW_OK)) {
- if (ret == GST_FLOW_UNEXPECTED)
- goto eos;
- else
- goto pause;
- }
- if (G_UNLIKELY (buf == NULL))
- goto error;
-
- src->offset += GST_BUFFER_SIZE (buf);
-
- ret = gst_pad_push (pad, buf);
- if (G_UNLIKELY (ret != GST_FLOW_OK))
- goto pause;
-
- gst_object_unref (src);
- return;
-
- /* special cases */
-eos:
- {
- GST_DEBUG_OBJECT (src, "going to EOS, getrange returned UNEXPECTED");
- gst_pad_pause_task (pad);
- if (src->segment.flags & GST_SEEK_FLAG_SEGMENT) {
- /* FIXME, subclass might want to use another format */
- gst_element_post_message (GST_ELEMENT (src),
- gst_message_new_segment_done (GST_OBJECT (src),
- GST_FORMAT_BYTES, src->segment.stop));
- } else {
- gst_pad_push_event (pad, gst_event_new_eos ());
- }
-
- gst_object_unref (src);
- return;
- }
-pause:
- {
- const gchar *reason = gst_flow_get_name (ret);
-
- GST_DEBUG_OBJECT (src, "pausing task, reason %s", reason);
- gst_pad_pause_task (pad);
- if (GST_FLOW_IS_FATAL (ret) || ret == GST_FLOW_NOT_LINKED) {
- /* for fatal errors we post an error message */
- GST_ELEMENT_ERROR (src, STREAM, FAILED,
- (_("Internal data flow error.")),
- ("streaming task paused, reason %s", reason));
- gst_pad_push_event (pad, gst_event_new_eos ());
- }
- gst_object_unref (src);
- return;
- }
-error:
- {
- GST_ELEMENT_ERROR (src, STREAM, FAILED,
- (_("Internal data flow error.")), ("element returned NULL buffer"));
- gst_pad_pause_task (pad);
- gst_pad_push_event (pad, gst_event_new_eos ());
-
- gst_object_unref (src);
- return;
- }
-}
-
-/* this will always be called between start() and stop(). So you can rely on
- resources allocated by start() and freed from stop(). This needs to be added
- to the docs at some point. */
-static gboolean
-gst_base_src_unlock (GstBaseSrc * basesrc)
-{
- GstBaseSrcClass *bclass;
- gboolean result = TRUE;
-
- GST_DEBUG ("unlock");
- /* unblock whatever the subclass is doing */
- bclass = GST_BASE_SRC_GET_CLASS (basesrc);
- if (bclass->unlock)
- result = bclass->unlock (basesrc);
-
- GST_DEBUG ("unschedule clock");
- /* and unblock the clock as well, if any */
- GST_OBJECT_LOCK (basesrc);
- if (basesrc->clock_id) {
- gst_clock_id_unschedule (basesrc->clock_id);
- }
- GST_OBJECT_UNLOCK (basesrc);
-
- GST_DEBUG ("unlock done");
-
- return result;
-}
-
-static gboolean
-gst_base_src_get_size (GstBaseSrc * basesrc, guint64 * size)
-{
- GstBaseSrcClass *bclass;
- gboolean result = FALSE;
-
- bclass = GST_BASE_SRC_GET_CLASS (basesrc);
- if (bclass->get_size)
- result = bclass->get_size (basesrc, size);
-
- if (result)
- basesrc->size = *size;
-
- return result;
-}
-
-static gboolean
-gst_base_src_is_seekable (GstBaseSrc * basesrc)
-{
- GstBaseSrcClass *bclass;
-
- bclass = GST_BASE_SRC_GET_CLASS (basesrc);
-
- /* check if we can seek */
- if (bclass->is_seekable)
- basesrc->seekable = bclass->is_seekable (basesrc);
- else
- basesrc->seekable = FALSE;
-
- GST_DEBUG_OBJECT (basesrc, "is seekable: %d", basesrc->seekable);
-
- return basesrc->seekable;
-}
-
-/* default negotiation code */
-static gboolean
-gst_base_src_default_negotiate (GstBaseSrc * basesrc)
-{
- GstCaps *thiscaps;
- GstCaps *caps = NULL;
- GstCaps *peercaps = NULL;
- gboolean result = FALSE;
-
- /* first see what is possible on our source pad */
- thiscaps = gst_pad_get_caps (GST_BASE_SRC_PAD (basesrc));
- GST_DEBUG_OBJECT (basesrc, "caps of src: %" GST_PTR_FORMAT, thiscaps);
- /* nothing or anything is allowed, we're done */
- if (thiscaps == NULL || gst_caps_is_any (thiscaps))
- goto no_nego_needed;
-
- /* get the peer caps */
- peercaps = gst_pad_peer_get_caps (GST_BASE_SRC_PAD (basesrc));
- GST_DEBUG_OBJECT (basesrc, "caps of peer: %" GST_PTR_FORMAT, peercaps);
- if (peercaps) {
- GstCaps *icaps;
-
- /* get intersection */
- icaps = gst_caps_intersect (thiscaps, peercaps);
- GST_DEBUG_OBJECT (basesrc, "intersect: %" GST_PTR_FORMAT, icaps);
- gst_caps_unref (thiscaps);
- gst_caps_unref (peercaps);
- if (icaps) {
- /* take first (and best) possibility */
- caps = gst_caps_copy_nth (icaps, 0);
- gst_caps_unref (icaps);
- }
- } else {
- /* no peer, work with our own caps then */
- caps = thiscaps;
- }
- if (caps) {
- caps = gst_caps_make_writable (caps);
- gst_caps_truncate (caps);
-
- /* now fixate */
- if (!gst_caps_is_empty (caps)) {
- gst_pad_fixate_caps (GST_BASE_SRC_PAD (basesrc), caps);
- GST_DEBUG_OBJECT (basesrc, "fixated to: %" GST_PTR_FORMAT, caps);
-
- if (gst_caps_is_any (caps)) {
- /* hmm, still anything, so element can do anything and
- * nego is not needed */
- gst_caps_unref (caps);
- result = TRUE;
- } else if (gst_caps_is_fixed (caps)) {
- /* yay, fixed caps, use those then */
- gst_pad_set_caps (GST_BASE_SRC_PAD (basesrc), caps);
- gst_caps_unref (caps);
- result = TRUE;
- }
- }
- }
- return result;
-
-no_nego_needed:
- {
- GST_DEBUG_OBJECT (basesrc, "no negotiation needed");
- if (thiscaps)
- gst_caps_unref (thiscaps);
- return TRUE;
- }
-}
-
-static gboolean
-gst_base_src_negotiate (GstBaseSrc * basesrc)
-{
- GstBaseSrcClass *bclass;
- gboolean result = TRUE;
-
- bclass = GST_BASE_SRC_GET_CLASS (basesrc);
-
- if (bclass->negotiate)
- result = bclass->negotiate (basesrc);
-
- return result;
-}
-
-static gboolean
-gst_base_src_start (GstBaseSrc * basesrc)
-{
- GstBaseSrcClass *bclass;
- gboolean result;
-
- if (GST_OBJECT_FLAG_IS_SET (basesrc, GST_BASE_SRC_STARTED))
- return TRUE;
-
- GST_DEBUG_OBJECT (basesrc, "starting source");
-
- basesrc->num_buffers_left = basesrc->num_buffers;
-
- bclass = GST_BASE_SRC_GET_CLASS (basesrc);
- if (bclass->start)
- result = bclass->start (basesrc);
- else
- result = TRUE;
-
- if (!result)
- goto could_not_start;
-
- GST_OBJECT_FLAG_SET (basesrc, GST_BASE_SRC_STARTED);
-
- /* figure out the size */
- if (bclass->get_size) {
- result = bclass->get_size (basesrc, &basesrc->size);
- if (result == FALSE)
- basesrc->size = -1;
- } else {
- result = FALSE;
- basesrc->size = -1;
- }
-
- GST_DEBUG ("size %d %lld", result, basesrc->size);
-
- /* check if we can seek, updates ->seekable */
- gst_base_src_is_seekable (basesrc);
-
- basesrc->need_newsegment = TRUE;
-
- /* run typefind */
-#if 0
- if (basesrc->seekable) {
- GstCaps *caps;
-
- caps = gst_type_find_helper (basesrc->srcpad, basesrc->size);
- gst_pad_set_caps (basesrc->srcpad, caps);
- gst_caps_unref (caps);
- }
-#endif
-
- if (!gst_base_src_negotiate (basesrc))
- goto could_not_negotiate;
-
- return TRUE;
-
- /* ERROR */
-could_not_start:
- {
- GST_DEBUG_OBJECT (basesrc, "could not start");
- return FALSE;
- }
-could_not_negotiate:
- {
- GST_DEBUG_OBJECT (basesrc, "could not negotiate, stopping");
- GST_ELEMENT_ERROR (basesrc, STREAM, FORMAT,
- ("Could not connect source to pipeline"),
- ("Check your filtered caps, if any"));
- gst_base_src_stop (basesrc);
- return FALSE;
- }
-}
-
-static gboolean
-gst_base_src_stop (GstBaseSrc * basesrc)
-{
- GstBaseSrcClass *bclass;
- gboolean result = TRUE;
-
- if (!GST_OBJECT_FLAG_IS_SET (basesrc, GST_BASE_SRC_STARTED))
- return TRUE;
-
- GST_DEBUG_OBJECT (basesrc, "stopping source");
-
- bclass = GST_BASE_SRC_GET_CLASS (basesrc);
- if (bclass->stop)
- result = bclass->stop (basesrc);
-
- if (result)
- GST_OBJECT_FLAG_UNSET (basesrc, GST_BASE_SRC_STARTED);
-
- return result;
-}
-
-static gboolean
-gst_base_src_deactivate (GstBaseSrc * basesrc, GstPad * pad)
-{
- gboolean result;
-
- GST_LIVE_LOCK (basesrc);
- basesrc->live_running = TRUE;
- GST_LIVE_SIGNAL (basesrc);
- GST_LIVE_UNLOCK (basesrc);
-
- /* step 1, unblock clock sync (if any) */
- result = gst_base_src_unlock (basesrc);
-
- /* step 2, make sure streaming finishes */
- result &= gst_pad_stop_task (pad);
-
- return result;
-}
-
-static gboolean
-gst_base_src_activate_push (GstPad * pad, gboolean active)
-{
- GstBaseSrc *basesrc;
- gboolean res;
-
- basesrc = GST_BASE_SRC (GST_OBJECT_PARENT (pad));
-
- /* prepare subclass first */
- if (active) {
- GST_DEBUG_OBJECT (basesrc, "Activating in push mode");
-
- if (!basesrc->can_activate_push)
- goto no_push_activation;
-
- if (!gst_base_src_start (basesrc))
- goto error_start;
-
- res = gst_pad_start_task (pad, (GstTaskFunction) gst_base_src_loop, pad);
- } else {
- GST_DEBUG_OBJECT (basesrc, "Deactivating in push mode");
- res = gst_base_src_deactivate (basesrc, pad);
- }
- return res;
-
- /* ERRORS */
-no_push_activation:
- {
- GST_DEBUG_OBJECT (basesrc, "Subclass disabled push-mode activation");
- return FALSE;
- }
-error_start:
- {
- gst_base_src_stop (basesrc);
- GST_DEBUG_OBJECT (basesrc, "Failed to start in push mode");
- return FALSE;
- }
-}
-
-static gboolean
-gst_base_src_activate_pull (GstPad * pad, gboolean active)
-{
- GstBaseSrc *basesrc;
-
- basesrc = GST_BASE_SRC (GST_OBJECT_PARENT (pad));
-
- /* prepare subclass first */
- if (active) {
- GST_DEBUG_OBJECT (basesrc, "Activating in pull mode");
- if (!gst_base_src_start (basesrc))
- goto error_start;
-
- if (!basesrc->seekable) {
- gst_base_src_stop (basesrc);
- return FALSE;
- }
-
- return TRUE;
- } else {
- GST_DEBUG_OBJECT (basesrc, "Deactivating in pull mode");
-
- if (!gst_base_src_stop (basesrc))
- goto error_stop;
-
- return gst_base_src_deactivate (basesrc, pad);
- }
-
-error_start:
- {
- gst_base_src_stop (basesrc);
- GST_DEBUG_OBJECT (basesrc, "Failed to start in pull mode");
- return FALSE;
- }
-error_stop:
- {
- GST_DEBUG_OBJECT (basesrc, "Failed to stop in pull mode");
- return FALSE;
- }
-}
-
-static GstStateChangeReturn
-gst_base_src_change_state (GstElement * element, GstStateChange transition)
-{
- GstBaseSrc *basesrc;
- GstStateChangeReturn result;
- gboolean no_preroll = FALSE;
-
- basesrc = GST_BASE_SRC (element);
-
- switch (transition) {
- case GST_STATE_CHANGE_NULL_TO_READY:
- break;
- case GST_STATE_CHANGE_READY_TO_PAUSED:
- GST_LIVE_LOCK (element);
- if (basesrc->is_live) {
- no_preroll = TRUE;
- basesrc->live_running = FALSE;
- }
- GST_LIVE_UNLOCK (element);
- break;
- case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
- GST_LIVE_LOCK (element);
- if (basesrc->is_live) {
- basesrc->live_running = TRUE;
- GST_LIVE_SIGNAL (element);
- }
- GST_LIVE_UNLOCK (element);
- break;
- default:
- break;
- }
-
- if ((result =
- GST_ELEMENT_CLASS (parent_class)->change_state (element,
- transition)) == GST_STATE_CHANGE_FAILURE)
- goto failure;
-
- switch (transition) {
- case GST_STATE_CHANGE_NULL_TO_READY:
- /* we always run from start to end when in READY, after putting
- * the element to READY a seek can be done on the element to
- * configure the segment when going to PAUSED. */
- gst_segment_init (&basesrc->segment, GST_FORMAT_BYTES);
- basesrc->offset = 0;
- break;
- case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
- GST_LIVE_LOCK (element);
- if (basesrc->is_live) {
- no_preroll = TRUE;
- basesrc->live_running = FALSE;
- }
- GST_LIVE_UNLOCK (element);
- break;
- case GST_STATE_CHANGE_PAUSED_TO_READY:
- if (!gst_base_src_stop (basesrc))
- goto error_stop;
- /* we always run from start to end when in READY */
- gst_segment_init (&basesrc->segment, GST_FORMAT_BYTES);
- basesrc->offset = 0;
- break;
- case GST_STATE_CHANGE_READY_TO_NULL:
- break;
- default:
- break;
- }
-
- if (no_preroll && result == GST_STATE_CHANGE_SUCCESS)
- result = GST_STATE_CHANGE_NO_PREROLL;
-
- return result;
-
- /* ERRORS */
-failure:
- {
- GST_DEBUG_OBJECT (basesrc, "parent failed state change");
- gst_base_src_stop (basesrc);
- return result;
- }
-error_stop:
- {
- GST_DEBUG_OBJECT (basesrc, "Failed to stop");
- return GST_STATE_CHANGE_FAILURE;
- }
-}
+++ /dev/null
-/* GStreamer
- * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
- * 2000 Wim Taymans <wtay@chello.be>
- * 2005 Wim Taymans <wim@fluendo.com>
- *
- * gstbasesrc.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., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#ifndef __GST_BASE_SRC_H__
-#define __GST_BASE_SRC_H__
-
-#include <gst/gst.h>
-
-G_BEGIN_DECLS
-
-#define GST_TYPE_BASE_SRC (gst_base_src_get_type())
-#define GST_BASE_SRC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_BASE_SRC,GstBaseSrc))
-#define GST_BASE_SRC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_BASE_SRC,GstBaseSrcClass))
-#define GST_BASE_SRC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_BASE_SRC, GstBaseSrcClass))
-#define GST_IS_BASE_SRC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_BASE_SRC))
-#define GST_IS_BASE_SRC_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_BASE_SRC))
-#define GST_BASE_SRC_CAST(obj) ((GstBaseSrc *)(obj))
-
-/**
- * GstBaseSrcFlags:
- * @GST_BASE_SRC_STARTED: has source been started
- * @GST_BASE_SRC_FLAG_LAST: offset to define more flags
- *
- * The #GstElement flags that a basesrc element may have.
- */
-typedef enum {
- GST_BASE_SRC_STARTED = (GST_ELEMENT_FLAG_LAST << 0),
- /* padding */
- GST_BASE_SRC_FLAG_LAST = (GST_ELEMENT_FLAG_LAST << 2)
-} GstBaseSrcFlags;
-
-typedef struct _GstBaseSrc GstBaseSrc;
-typedef struct _GstBaseSrcClass GstBaseSrcClass;
-
-/**
- * GST_BASE_SRC_PAD:
- * @obj: base source instance
- *
- * Gives the pointer to the #GstPad object of the element.
- */
-#define GST_BASE_SRC_PAD(obj) (GST_BASE_SRC_CAST (obj)->srcpad)
-
-
-/**
- * GstBaseSrc:
- *
- * The opaque #GstBaseSrc data structure.
- */
-struct _GstBaseSrc {
- GstElement element;
-
- /*< protected >*/
- GstPad *srcpad;
-
- /* available to subclass implementations */
- /* MT-protected (with LIVE_LOCK) */
- GMutex *live_lock;
- GCond *live_cond;
- gboolean is_live;
- gboolean live_running;
-
- /* MT-protected (with LOCK) */
- gint blocksize; /* size of buffers when operating push based */
- gboolean can_activate_push; /* some scheduling properties */
- GstActivateMode pad_mode;
- gboolean seekable;
- gboolean random_access;
-
- GstClockID clock_id; /* for syncing */
- GstClockTime end_time;
-
- /* MT-protected (with STREAM_LOCK) */
- GstSegment segment;
- gboolean need_newsegment;
-
- guint64 offset; /* current offset in the resource */
- guint64 size; /* total size of the resource */
-
- gint num_buffers;
- gint num_buffers_left;
-
- /*< private >*/
- gpointer _gst_reserved[GST_PADDING];
-};
-
-/**
- * _GstBaseSrcClass:
- * @create: ask the subclass to create a buffer with offset and size
- * @start: start processing
- */
-struct _GstBaseSrcClass {
- GstElementClass parent_class;
-
- /*< public >*/
- /* virtual methods for subclasses */
-
- /* get caps from subclass */
- GstCaps* (*get_caps) (GstBaseSrc *src);
- /* notify the subclass of new caps */
- gboolean (*set_caps) (GstBaseSrc *src, GstCaps *caps);
-
- /* decide on caps */
- gboolean (*negotiate) (GstBaseSrc *src);
-
- /* generate and send a newsegment */
- gboolean (*newsegment) (GstBaseSrc *src);
-
- /* start and stop processing, ideal for opening/closing the resource */
- gboolean (*start) (GstBaseSrc *src);
- gboolean (*stop) (GstBaseSrc *src);
-
- /* given a buffer, return start and stop time when it should be pushed
- * out. The base class will sync on the clock using these times. */
- void (*get_times) (GstBaseSrc *src, GstBuffer *buffer,
- GstClockTime *start, GstClockTime *end);
-
- /* get the total size of the resource in bytes */
- gboolean (*get_size) (GstBaseSrc *src, guint64 *size);
-
- /* check if the resource is seekable */
- gboolean (*is_seekable) (GstBaseSrc *src);
- /* unlock any pending access to the resource. subclasses should unlock
- * any function ASAP. */
- gboolean (*unlock) (GstBaseSrc *src);
-
- /* notify subclasses of an event */
- gboolean (*event) (GstBaseSrc *src, GstEvent *event);
-
- /* ask the subclass to create a buffer with offset and size */
- GstFlowReturn (*create) (GstBaseSrc *src, guint64 offset, guint size,
- GstBuffer **buf);
-
- /*< private >*/
- gpointer _gst_reserved[GST_PADDING];
-};
-
-GType gst_base_src_get_type (void);
-
-void gst_base_src_set_live (GstBaseSrc *src, gboolean live);
-gboolean gst_base_src_is_live (GstBaseSrc *src);
-
-G_END_DECLS
-
-#endif /* __GST_BASE_SRC_H__ */
+++ /dev/null
-/* GStreamer
- * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
- * 2000 Wim Taymans <wtay@chello.be>
- * 2005 Wim Taymans <wim@fluendo.com>
- * 2005 Andy Wingo <wingo@fluendo.com>
- * 2005 Thomas Vander Stichele <thomas at apestaart dot org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-/**
- * SECTION:gstbasetransform
- * @short_description: Base class for simple tranform filters
- * @see_also: #GstBaseSrc, #GstBaseSink
- *
- * This base class is for filter elements that process data.
- *
- * It provides for:
- * <itemizedlist>
- * <listitem><para>one sinkpad and one srcpad</para></listitem>
- * <listitem><para>
- * Possible formats on sink and source pad implemented
- * with custom transform_caps function. By default uses
- * same format on sink and source.
- * </para></listitem>
- * <listitem><para>Handles state changes</para></listitem>
- * <listitem><para>Does flushing</para></listitem>
- * <listitem><para>Push mode</para></listitem>
- * <listitem><para>
- * Pull mode if the sub-class transform can operate on arbitrary data
- * </para></listitem>
- * </itemizedlist>
- *
- * Use Cases:
- * <orderedlist>
- * <listitem>
- * <itemizedlist><title>Passthrough mode</title>
- * <listitem><para>
- * Element has no interest in modifying the buffer. It may want to inspect it,
- * in which case the element should have a transform_ip function. If there
- * is no transform_ip function in passthrough mode, the buffer is pushed
- * intact.
- * </para></listitem>
- * <listitem><para>
- * On the GstBaseTransformClass is the passthrough_on_same_caps variable
- * which will automatically set/unset passthrough based on whether the
- * element negotiates the same caps on both pads.
- * </para></listitem>
- * <listitem><para>
- * passthrough_on_same_caps on an element that doesn't implement a transform_caps
- * function is useful for elements that only inspect data (such as level)
- * </para></listitem>
- * </itemizedlist>
- * <itemizedlist>
- * <title>Example elements</title>
- * <listitem>Level</listitem>
- * <listitem>Videoscale, audioconvert, ffmpegcolorspace, audioresample in certain modes.</listitem>
- * </itemizedlist>
- * </listitem>
- * <listitem>
- * <itemizedlist><title>Modifications in-place - input buffer and output buffer are the same thing.</title>
- * <listitem><para>
- * The element must implement a transform_ip function.
- * </para></listitem>
- * <listitem><para>
- * Output buffer size must <= input buffer size
- * </para></listitem>
- * <listitem><para>
- * If the always_in_place flag is set, non-writable buffers will be copied and
- * passed to the transform_ip function, otherwise a new buffer will be created
- * and the transform function called.
- * </para></listitem>
- * <listitem><para>
- * Incoming writable buffers will be passed to the transform_ip function immediately.
- * </para></listitem>
- * <listitem><para>
- * only implementing transform_ip and not transform implies always_in_place =
- * TRUE
- * </para></listitem>
- * </itemizedlist>
- * <itemizedlist>
- * <title>Example elements</title>
- * <listitem>Volume</listitem>
- * <listitem>Audioconvert in certain modes (signed/unsigned conversion)</listitem>
- * <listitem>ffmpegcolorspace in certain modes (endianness swapping)</listitem>
- * </itemizedlist>
- * </listitem>
- * <listitem>
- * <itemizedlist><title>Modifications only to the caps/metadata of a buffer</title>
- * <listitem><para>
- * The element does not require writable data, but non-writable buffers should
- * be subbuffered so that the meta-information can be replaced.
- * </para></listitem>
- * <listitem><para>
- * Elements wishing to operate in this mode should replace the
- * prepare_output_buffer method to create subbuffers of the input buffer and
- * set always_in_place to TRUE
- * </para></listitem>
- * </itemizedlist>
- * <itemizedlist>
- * <title>Example elements</title>
- * <listitem>Capsfilter when setting caps on outgoing buffers that have none.</listitem>
- * <listitem>identity when it is going to re-timestamp buffers by datarate.</listitem>
- * </itemizedlist>
- * </listitem>
- * <listitem>
- * <itemizedlist><title>Normal mode</title>
- * <listitem><para>
- * always_in_place flag is not set, or there is no transform_ip function
- * </para></listitem>
- * <listitem><para>
- * Element will receive an input buffer and output buffer to operate on.
- * </para></listitem>
- * <listitem><para>
- * Output buffer is allocated by calling the prepare_output_buffer function.
- * </para></listitem>
- * </itemizedlist>
- * <itemizedlist>
- * <title>Example elements</title>
- * <listitem>Videoscale, ffmpegcolorspace, audioconvert when doing scaling/conversions</listitem>
- * </itemizedlist>
- * </listitem>
- * <listitem>
- * <itemizedlist><title>Special output buffer allocations</title>
- * <listitem><para>
- * Elements which need to do special allocation of their output buffers other
- * than what gst_buffer_pad_alloc allows should implement a
- * prepare_output_buffer method, which calls the parent implementation and
- * passes the newly allocated buffer.
- * </para></listitem>
- * </itemizedlist>
- * <itemizedlist>
- * <title>Example elements</title>
- * <listitem>efence</listitem>
- * </itemizedlist>
- * </listitem>
- * </orderedlist>
- *
- * <itemizedlist><title>Sub-class settable flags on GstBaseTransform</title>
- * <listitem><para>
- * <itemizedlist><title>passthrough</title>
- * <listitem><para>
- * Implies that in the current configuration, the sub-class is not
- * interested in modifying the buffers.
- * </para></listitem>
- * <listitem><para>
- * Elements which are always in passthrough mode whenever the same caps has
- * been negotiated on both pads can set the class variable
- * passthrough_on_same_caps to have this behaviour automatically.
- * </para></listitem>
- * </itemizedlist>
- * </para></listitem>
- * <listitem><para>
- * <itemizedlist><title>always_in_place</title>
- * <listitem><para>
- * Determines whether a non-writable buffer will be copied before passing
- * to the transform_ip function.
- * </para></listitem>
- * <listitem><para>
- * Implied TRUE if no transform function is implemented.
- * </para></listitem>
- * <listitem><para>
- * Implied FALSE if ONLY transform function is implemented.
- * </para></listitem>
- * </itemizedlist>
- * </para></listitem>
- * </itemizedlist>
- *
-*/
-
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#include <stdlib.h>
-#include <string.h>
-
-#include "../gst-i18n-lib.h"
-#include "gstbasetransform.h"
-#include <gst/gstmarshal.h>
-
-GST_DEBUG_CATEGORY_STATIC (gst_base_transform_debug);
-#define GST_CAT_DEFAULT gst_base_transform_debug
-
-/* BaseTransform signals and args */
-enum
-{
- /* FILL ME */
- LAST_SIGNAL
-};
-
-enum
-{
- PROP_0,
-};
-
-static GstElementClass *parent_class = NULL;
-
-static void gst_base_transform_base_init (gpointer g_class);
-static void gst_base_transform_class_init (GstBaseTransformClass * klass);
-static void gst_base_transform_init (GstBaseTransform * trans,
- GstBaseTransformClass * klass);
-static GstFlowReturn gst_base_transform_prepare_output_buf (GstBaseTransform *
- trans, GstBuffer * input, gint size, GstCaps * caps, GstBuffer ** buf);
-
-GType
-gst_base_transform_get_type (void)
-{
- static GType base_transform_type = 0;
-
- if (!base_transform_type) {
- static const GTypeInfo base_transform_info = {
- sizeof (GstBaseTransformClass),
- (GBaseInitFunc) gst_base_transform_base_init,
- NULL,
- (GClassInitFunc) gst_base_transform_class_init,
- NULL,
- NULL,
- sizeof (GstBaseTransform),
- 0,
- (GInstanceInitFunc) gst_base_transform_init,
- };
-
- base_transform_type = g_type_register_static (GST_TYPE_ELEMENT,
- "GstBaseTransform", &base_transform_info, G_TYPE_FLAG_ABSTRACT);
- }
- return base_transform_type;
-}
-
-static void gst_base_transform_finalize (GObject * object);
-static void gst_base_transform_set_property (GObject * object, guint prop_id,
- const GValue * value, GParamSpec * pspec);
-static void gst_base_transform_get_property (GObject * object, guint prop_id,
- GValue * value, GParamSpec * pspec);
-static gboolean gst_base_transform_src_activate_pull (GstPad * pad,
- gboolean active);
-static gboolean gst_base_transform_sink_activate_push (GstPad * pad,
- gboolean active);
-static gboolean gst_base_transform_get_unit_size (GstBaseTransform * trans,
- GstCaps * caps, guint * size);
-
-static GstStateChangeReturn gst_base_transform_change_state (GstElement *
- element, GstStateChange transition);
-
-static gboolean gst_base_transform_event (GstPad * pad, GstEvent * event);
-static gboolean gst_base_transform_eventfunc (GstBaseTransform * trans,
- GstEvent * event);
-static GstFlowReturn gst_base_transform_getrange (GstPad * pad, guint64 offset,
- guint length, GstBuffer ** buffer);
-static GstFlowReturn gst_base_transform_chain (GstPad * pad,
- GstBuffer * buffer);
-static GstCaps *gst_base_transform_getcaps (GstPad * pad);
-static gboolean gst_base_transform_setcaps (GstPad * pad, GstCaps * caps);
-static GstFlowReturn gst_base_transform_buffer_alloc (GstPad * pad,
- guint64 offset, guint size, GstCaps * caps, GstBuffer ** buf);
-
-/* static guint gst_base_transform_signals[LAST_SIGNAL] = { 0 }; */
-
-static void
-gst_base_transform_base_init (gpointer g_class)
-{
- GST_DEBUG_CATEGORY_INIT (gst_base_transform_debug, "basetransform", 0,
- "basetransform element");
-}
-
-static void
-gst_base_transform_finalize (GObject * object)
-{
- GstBaseTransform *trans;
-
- trans = GST_BASE_TRANSFORM (object);
-
- g_mutex_free (trans->transform_lock);
-
- G_OBJECT_CLASS (parent_class)->finalize (object);
-}
-
-static void
-gst_base_transform_class_init (GstBaseTransformClass * klass)
-{
- GObjectClass *gobject_class;
- GstElementClass *gstelement_class;
-
- gobject_class = G_OBJECT_CLASS (klass);
- gstelement_class = GST_ELEMENT_CLASS (klass);
-
- parent_class = g_type_class_peek_parent (klass);
-
- gobject_class->set_property =
- GST_DEBUG_FUNCPTR (gst_base_transform_set_property);
- gobject_class->get_property =
- GST_DEBUG_FUNCPTR (gst_base_transform_get_property);
-
- gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_base_transform_finalize);
-
- gstelement_class->change_state =
- GST_DEBUG_FUNCPTR (gst_base_transform_change_state);
-
- klass->passthrough_on_same_caps = FALSE;
- klass->event = GST_DEBUG_FUNCPTR (gst_base_transform_eventfunc);
-}
-
-static void
-gst_base_transform_init (GstBaseTransform * trans,
- GstBaseTransformClass * bclass)
-{
- GstPadTemplate *pad_template;
-
- GST_DEBUG ("gst_base_transform_init");
-
- pad_template =
- gst_element_class_get_pad_template (GST_ELEMENT_CLASS (bclass), "sink");
- g_return_if_fail (pad_template != NULL);
- trans->sinkpad = gst_pad_new_from_template (pad_template, "sink");
- gst_pad_set_getcaps_function (trans->sinkpad,
- GST_DEBUG_FUNCPTR (gst_base_transform_getcaps));
- gst_pad_set_setcaps_function (trans->sinkpad,
- GST_DEBUG_FUNCPTR (gst_base_transform_setcaps));
- gst_pad_set_event_function (trans->sinkpad,
- GST_DEBUG_FUNCPTR (gst_base_transform_event));
- gst_pad_set_chain_function (trans->sinkpad,
- GST_DEBUG_FUNCPTR (gst_base_transform_chain));
- gst_pad_set_activatepush_function (trans->sinkpad,
- GST_DEBUG_FUNCPTR (gst_base_transform_sink_activate_push));
- gst_pad_set_bufferalloc_function (trans->sinkpad,
- GST_DEBUG_FUNCPTR (gst_base_transform_buffer_alloc));
- gst_element_add_pad (GST_ELEMENT (trans), trans->sinkpad);
-
- pad_template =
- gst_element_class_get_pad_template (GST_ELEMENT_CLASS (bclass), "src");
- g_return_if_fail (pad_template != NULL);
- trans->srcpad = gst_pad_new_from_template (pad_template, "src");
- gst_pad_set_getcaps_function (trans->srcpad,
- GST_DEBUG_FUNCPTR (gst_base_transform_getcaps));
- gst_pad_set_setcaps_function (trans->srcpad,
- GST_DEBUG_FUNCPTR (gst_base_transform_setcaps));
- gst_pad_set_getrange_function (trans->srcpad,
- GST_DEBUG_FUNCPTR (gst_base_transform_getrange));
- gst_pad_set_activatepull_function (trans->srcpad,
- GST_DEBUG_FUNCPTR (gst_base_transform_src_activate_pull));
- gst_element_add_pad (GST_ELEMENT (trans), trans->srcpad);
-
- trans->transform_lock = g_mutex_new ();
- trans->delay_configure = FALSE;
- trans->pending_configure = FALSE;
- trans->cache_caps1 = NULL;
- trans->cache_caps2 = NULL;
-
- trans->passthrough = FALSE;
- if (bclass->transform == NULL) {
- /* If no transform function, always_in_place is TRUE */
- GST_DEBUG_OBJECT (trans, "setting in_place TRUE");
- trans->always_in_place = TRUE;
-
- if (bclass->transform_ip == NULL)
- trans->passthrough = TRUE;
- }
-}
-
-static GstCaps *
-gst_base_transform_transform_caps (GstBaseTransform * trans,
- GstPadDirection direction, GstCaps * caps)
-{
- GstCaps *ret;
- GstBaseTransformClass *klass;
-
- klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
-
- /* if there is a custom transform function, use this */
- if (klass->transform_caps) {
- GstCaps *temp;
- gint i;
-
- ret = gst_caps_new_empty ();
-
- if (gst_caps_is_any (caps)) {
- /* for any caps we still have to call the transform function */
- GST_DEBUG_OBJECT (trans, "from ANY:");
- temp = klass->transform_caps (trans, direction, caps);
- GST_DEBUG_OBJECT (trans, " to: %" GST_PTR_FORMAT, temp);
-
- gst_caps_append (ret, temp);
- } else {
- /* we send caps with just one structure to the transform
- * function as this is easier for the element */
- for (i = 0; i < gst_caps_get_size (caps); i++) {
- GstCaps *nth;
-
- nth = gst_caps_copy_nth (caps, i);
- GST_DEBUG_OBJECT (trans, "from[%d]: %" GST_PTR_FORMAT, i, nth);
- temp = klass->transform_caps (trans, direction, nth);
- gst_caps_unref (nth);
- GST_DEBUG_OBJECT (trans, " to[%d]: %" GST_PTR_FORMAT, i, temp);
-
- gst_caps_append (ret, temp);
- }
- }
- } else {
- /* else use the identity transform */
- ret = gst_caps_ref (caps);
- }
-
- GST_DEBUG_OBJECT (trans, "to: %" GST_PTR_FORMAT, ret);
-
- return ret;
-}
-
-static gboolean
-gst_base_transform_transform_size (GstBaseTransform * trans,
- GstPadDirection direction, GstCaps * caps,
- guint size, GstCaps * othercaps, guint * othersize)
-{
- guint inunitsize, outunitsize, units;
- GstBaseTransformClass *klass;
- gint ret = -1;
-
- klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
-
- GST_DEBUG_OBJECT (trans, "asked to transform size %d for caps %"
- GST_PTR_FORMAT " to size for caps %" GST_PTR_FORMAT " in direction %s",
- size, caps, othercaps, direction == GST_PAD_SRC ? "SRC" : "SINK");
-
- /* if there is a custom transform function, use this */
- if (klass->transform_size) {
- ret = klass->transform_size (trans, direction, caps, size, othercaps,
- othersize);
- } else {
- gboolean got_in_unit_size, got_out_unit_size;
-
- got_in_unit_size = gst_base_transform_get_unit_size (trans, caps,
- &inunitsize);
- g_return_val_if_fail (got_in_unit_size == TRUE, FALSE);
- GST_DEBUG_OBJECT (trans, "input size %d, input unit size %d", size,
- inunitsize);
- g_return_val_if_fail (inunitsize != 0, FALSE);
- if (size % inunitsize != 0) {
- g_warning ("Size %u is not a multiple of unit size %u", size, inunitsize);
- return FALSE;
- }
-
- units = size / inunitsize;
- got_out_unit_size = gst_base_transform_get_unit_size (trans, othercaps,
- &outunitsize);
- g_return_val_if_fail (got_out_unit_size == TRUE, FALSE);
-
- *othersize = units * outunitsize;
- GST_DEBUG_OBJECT (trans, "transformed size to %d", *othersize);
- }
-
- return ret;
-}
-
-static GstCaps *
-gst_base_transform_getcaps (GstPad * pad)
-{
- GstBaseTransform *trans;
- GstPad *otherpad;
- GstCaps *caps;
-
- trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
-
- otherpad = (pad == trans->srcpad) ? trans->sinkpad : trans->srcpad;
-
- /* we can do what the peer can */
- caps = gst_pad_peer_get_caps (otherpad);
- if (caps) {
- GstCaps *temp;
- const GstCaps *templ;
-
- GST_DEBUG_OBJECT (pad, "peer caps %" GST_PTR_FORMAT, caps);
-
- /* filtered against our padtemplate */
- templ = gst_pad_get_pad_template_caps (otherpad);
- GST_DEBUG_OBJECT (pad, "our template %" GST_PTR_FORMAT, templ);
- temp = gst_caps_intersect (caps, templ);
- GST_DEBUG_OBJECT (pad, "intersected %" GST_PTR_FORMAT, temp);
- gst_caps_unref (caps);
- /* then see what we can tranform this to */
- caps = gst_base_transform_transform_caps (trans,
- GST_PAD_DIRECTION (otherpad), temp);
- GST_DEBUG_OBJECT (pad, "transformed %" GST_PTR_FORMAT, caps);
- gst_caps_unref (temp);
- if (caps == NULL)
- goto done;
-
- /* and filter against the template again */
- templ = gst_pad_get_pad_template_caps (pad);
- GST_DEBUG_OBJECT (pad, "our template %" GST_PTR_FORMAT, templ);
- temp = gst_caps_intersect (caps, templ);
- GST_DEBUG_OBJECT (pad, "intersected %" GST_PTR_FORMAT, temp);
- gst_caps_unref (caps);
- /* this is what we can do */
- caps = temp;
- } else {
- /* no peer, our padtemplate is enough then */
- caps = gst_caps_copy (gst_pad_get_pad_template_caps (pad));
- }
-
-done:
- GST_DEBUG_OBJECT (trans, "returning %" GST_PTR_FORMAT, caps);
-
- gst_object_unref (trans);
-
- return caps;
-}
-
-static gboolean
-gst_base_transform_configure_caps (GstBaseTransform * trans, GstCaps * in,
- GstCaps * out)
-{
- gboolean ret = TRUE;
- GstBaseTransformClass *klass;
-
- klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
-
- /* clear the cache */
- gst_caps_replace (&trans->cache_caps1, NULL);
- gst_caps_replace (&trans->cache_caps2, NULL);
-
- /* If we've a transform_ip method and same input/output caps, set in_place
- * by default. If for some reason the sub-class prefers using a transform
- * function, it can clear the in place flag in the set_caps */
- gst_base_transform_set_in_place (trans,
- klass->transform_ip && trans->have_same_caps);
-
- /* Set the passthrough if the class wants passthrough_on_same_caps
- * and we have the same caps on each pad */
- if (klass->passthrough_on_same_caps)
- gst_base_transform_set_passthrough (trans, trans->have_same_caps);
-
- /* now configure the element with the caps */
- if (klass->set_caps) {
- GST_DEBUG_OBJECT (trans, "Calling set_caps method to setup caps");
- ret = klass->set_caps (trans, in, out);
- }
-
- trans->negotiated = ret;
-
- return ret;
-}
-
-static gboolean
-gst_base_transform_setcaps (GstPad * pad, GstCaps * caps)
-{
- GstBaseTransform *trans;
- GstBaseTransformClass *klass;
- GstPad *otherpad, *otherpeer;
- GstCaps *othercaps = NULL;
- gboolean ret = TRUE;
- gboolean peer_checked = FALSE;
-
- trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
- klass = GST_BASE_TRANSFORM_GET_CLASS (trans);
-
- otherpad = (pad == trans->srcpad) ? trans->sinkpad : trans->srcpad;
- otherpeer = gst_pad_get_peer (otherpad);
-
- /* if we get called recursively, we bail out now to avoid an
- * infinite loop. */
- if (GST_PAD_IS_IN_SETCAPS (otherpad))
- goto done;
-
- /* caps must be fixed here */
- if (!gst_caps_is_fixed (caps))
- goto unfixed_caps;
-
- /* see how we can transform the input caps. */
- othercaps = gst_base_transform_transform_caps (trans,
- GST_PAD_DIRECTION (pad), caps);
-
- /* The caps we can actually output is the intersection of the transformed
- * caps with the pad template for the pad */
- if (othercaps) {
- GstCaps *intersect;
- const GstCaps *templ_caps;
-
- templ_caps = gst_pad_get_pad_template_caps (otherpad);
- intersect = gst_caps_intersect (othercaps, templ_caps);
-
- gst_caps_unref (othercaps);
- othercaps = intersect;
- }
-
- /* check if transform is empty */
- if (!othercaps || gst_caps_is_empty (othercaps))
- goto no_transform;
-
- /* if the othercaps are not fixed, we need to fixate them, first attempt
- * is by attempting passthrough if the othercaps are a superset of caps. */
- if (!gst_caps_is_fixed (othercaps)) {
- GstCaps *temp;
-
- GST_DEBUG_OBJECT (trans,
- "transform returned non fixed %" GST_PTR_FORMAT, othercaps);
-
- /* see if the target caps are a superset of the source caps, in this
- * case we can try to perform passthrough */
- temp = gst_caps_intersect (othercaps, caps);
- GST_DEBUG_OBJECT (trans, "intersect returned %" GST_PTR_FORMAT, temp);
- if (temp) {
- if (!gst_caps_is_empty (temp) && otherpeer) {
- GST_DEBUG_OBJECT (trans, "try passthrough with %" GST_PTR_FORMAT, caps);
- /* try passthrough. we know it's fixed, because caps is fixed */
- if (gst_pad_accept_caps (otherpeer, caps)) {
- GST_DEBUG_OBJECT (trans, "peer accepted %" GST_PTR_FORMAT, caps);
- /* peer accepted unmodified caps, we free the original non-fixed
- * caps and work with the passthrough caps */
- gst_caps_unref (othercaps);
- othercaps = gst_caps_ref (caps);
- /* mark that we checked othercaps with the peer, this
- * makes sure we don't call accept_caps again with these same
- * caps */
- peer_checked = TRUE;
- } else {
- GST_DEBUG_OBJECT (trans,
- "peer did not accept %" GST_PTR_FORMAT, caps);
- }
- }
- gst_caps_unref (temp);
- }
- }
-
- /* second attempt at fixation is done by intersecting with
- * the peer caps */
- if (!gst_caps_is_fixed (othercaps) && otherpeer) {
- /* intersect against what the peer can do */
- GstCaps *peercaps;
- GstCaps *intersect;
-
- GST_DEBUG_OBJECT (trans, "othercaps now %" GST_PTR_FORMAT, othercaps);
-
- peercaps = gst_pad_get_caps (otherpeer);
- intersect = gst_caps_intersect (peercaps, othercaps);
- gst_caps_unref (peercaps);
- gst_caps_unref (othercaps);
- othercaps = intersect;
- peer_checked = FALSE;
-
- GST_DEBUG_OBJECT (trans,
- "filtering against peer yields %" GST_PTR_FORMAT, othercaps);
- }
-
- if (gst_caps_is_empty (othercaps))
- goto no_transform_possible;
-
- /* third attempt at fixation, call the fixate vmethod and
- * ultimately call the pad fixate function. */
- if (!gst_caps_is_fixed (othercaps)) {
- GstCaps *temp;
-
- GST_DEBUG_OBJECT (trans,
- "trying to fixate %" GST_PTR_FORMAT " on pad %s:%s",
- othercaps, GST_DEBUG_PAD_NAME (otherpad));
-
- /* since we have no other way to fixate left, we might as well just take
- * the first of the caps list and fixate that */
-
- /* FIXME: when fixating using the vmethod, it might make sense to fixate
- * each of the caps; but Wim doesn't see a use case for that yet */
- temp = gst_caps_copy_nth (othercaps, 0);
- gst_caps_unref (othercaps);
- othercaps = temp;
- peer_checked = FALSE;
-
- if (klass->fixate_caps) {
- GST_DEBUG_OBJECT (trans, "trying to fixate %" GST_PTR_FORMAT
- " using caps %" GST_PTR_FORMAT
- " on pad %s:%s using fixate_caps vmethod", othercaps, caps,
- GST_DEBUG_PAD_NAME (otherpad));
- klass->fixate_caps (trans, GST_PAD_DIRECTION (pad), caps, othercaps);
- }
- /* if still not fixed, no other option but to let the default pad fixate
- * function do its job */
- if (!gst_caps_is_fixed (othercaps)) {
- GST_DEBUG_OBJECT (trans, "trying to fixate %" GST_PTR_FORMAT
- " on pad %s:%s using gst_pad_fixate_caps", othercaps,
- GST_DEBUG_PAD_NAME (otherpad));
- gst_pad_fixate_caps (otherpad, othercaps);
- }
- GST_DEBUG_OBJECT (trans, "after fixating %" GST_PTR_FORMAT, othercaps);
- }
-
- /* caps should be fixed now, if not we have to fail. */
- if (!gst_caps_is_fixed (othercaps))
- goto could_not_fixate;
-
- /* and peer should accept, don't check again if we already checked the
- * othercaps against the peer. */
- if (!peer_checked && otherpeer && !gst_pad_accept_caps (otherpeer, othercaps))
- goto peer_no_accept;
-
- GST_DEBUG_OBJECT (trans, "got final caps %" GST_PTR_FORMAT, othercaps);
-
- trans->have_same_caps = gst_caps_is_equal (caps, othercaps);
- GST_DEBUG_OBJECT (trans, "have_same_caps: %d", trans->have_same_caps);
-
- /* see if we have to configure the element now */
- if (!trans->delay_configure) {
- GstCaps *incaps, *outcaps;
-
- /* make sure in and out caps are correct */
- if (pad == trans->sinkpad) {
- incaps = caps;
- outcaps = othercaps;
- } else {
- incaps = othercaps;
- outcaps = caps;
- }
- /* call configure now */
- if (!(ret = gst_base_transform_configure_caps (trans, incaps, outcaps)))
- goto failed_configure;
- } else {
- /* set pending configure, the configure will happen later with the
- * caps we set on the pads above. */
- trans->pending_configure = TRUE;
- }
-
- /* we know this will work, we implement the setcaps */
- gst_pad_set_caps (otherpad, othercaps);
-
-done:
- if (otherpeer)
- gst_object_unref (otherpeer);
- if (othercaps)
- gst_caps_unref (othercaps);
-
- trans->negotiated = ret;
-
- gst_object_unref (trans);
-
- return ret;
-
- /* ERRORS */
-unfixed_caps:
- {
- GST_DEBUG_OBJECT (trans, "caps are not fixed %" GST_PTR_FORMAT, caps);
- ret = FALSE;
- goto done;
- }
-no_transform:
- {
- GST_DEBUG_OBJECT (trans,
- "transform returned useless %" GST_PTR_FORMAT, othercaps);
- ret = FALSE;
- goto done;
- }
-no_transform_possible:
- {
- GST_DEBUG_OBJECT (trans,
- "transform could not transform %" GST_PTR_FORMAT
- " in anything we support", caps);
- ret = FALSE;
- goto done;
- }
-could_not_fixate:
- {
- GST_ERROR_OBJECT (trans, "FAILED to fixate %" GST_PTR_FORMAT, othercaps);
- ret = FALSE;
- goto done;
- }
-peer_no_accept:
- {
- GST_DEBUG_OBJECT (trans, "FAILED to get peer of %" GST_PTR_FORMAT
- " to accept %" GST_PTR_FORMAT, otherpad, othercaps);
- ret = FALSE;
- goto done;
- }
-failed_configure:
- {
- GST_DEBUG_OBJECT (trans, "FAILED to configure caps %" GST_PTR_FORMAT
- " to accept %" GST_PTR_FORMAT, otherpad, othercaps);
- ret = FALSE;
- goto done;
- }
-}
-
-/* Allocate a buffer using gst_pad_alloc_buffer.
- *
- * This function can trigger a renegotiation on the source pad when the
- * peer alloc_buffer function sets new caps. Since we currently are
- * processing a buffer on the sinkpad when this function is called, we cannot
- * reconfigure the transform with sinkcaps different from those of the current
- * buffer. FIXME, we currently don't check if the pluging can transform to the
- * new srcpad caps using the same sinkcaps, we alloc a proper outbuf buffer
- * ourselves instead.
- */
-static GstFlowReturn
-gst_base_transform_prepare_output_buf (GstBaseTransform * trans,
- GstBuffer * in_buf, gint out_size, GstCaps * out_caps, GstBuffer ** out_buf)
-{
- GstBaseTransformClass *bclass;
- GstFlowReturn ret = GST_FLOW_OK;
- gboolean copy_inbuf = FALSE;
-
- bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
-
- /* we cannot reconfigure the element yet as we are still processing
- * the old buffer. We will therefore delay the reconfiguration of the
- * element until we have processed this last buffer. */
- trans->delay_configure = TRUE;
- /* out_caps is the caps of the src pad gathered through the GST_PAD_CAPS
- macro. If a set_caps occurs during this function this caps will become
- invalid. We want to keep them during preparation of the output buffer. */
- if (out_caps)
- gst_caps_ref (out_caps);
-
- /* see if the subclass wants to alloc a buffer */
- if (bclass->prepare_output_buffer) {
- ret =
- bclass->prepare_output_buffer (trans, in_buf, out_size, out_caps,
- out_buf);
- if (ret != GST_FLOW_OK)
- goto done;
- }
-
- /* See if we want to prepare the buffer for in place output */
- if (*out_buf == NULL && GST_BUFFER_SIZE (in_buf) == out_size
- && bclass->transform_ip) {
- if (gst_buffer_is_writable (in_buf)) {
- if (trans->have_same_caps) {
- /* Input buffer is already writable and caps are the same, just ref and return it */
- *out_buf = in_buf;
- gst_buffer_ref (in_buf);
- } else {
- /* Writable buffer, but need to change caps => subbuffer */
- *out_buf = gst_buffer_create_sub (in_buf, 0, GST_BUFFER_SIZE (in_buf));
- gst_caps_replace (&GST_BUFFER_CAPS (*out_buf), out_caps);
- }
- goto done;
- } else {
- /* Make a writable buffer below and copy the data */
- copy_inbuf = TRUE;
- }
- }
-
- if (*out_buf == NULL) {
- /* Sub-class didn't already provide a buffer for us. Make one */
- ret = gst_pad_alloc_buffer (trans->srcpad, GST_BUFFER_OFFSET (in_buf),
- out_size, out_caps, out_buf);
- if (ret != GST_FLOW_OK || *out_buf == NULL)
- goto done;
-
- /* allocated buffer could be of different caps than what we requested */
- if (G_UNLIKELY (!gst_caps_is_equal (out_caps, GST_BUFFER_CAPS (*out_buf)))) {
- /* FIXME, it is possible we can reconfigure the transform with new caps at this
- * point but for now we just create a buffer ourselves */
- gst_buffer_unref (*out_buf);
- *out_buf = gst_buffer_new_and_alloc (out_size);
- gst_buffer_set_caps (*out_buf, out_caps);
- }
- }
-
- /* If the output buffer metadata is modifiable, copy timestamps and
- * buffer flags */
- if (*out_buf != in_buf && GST_MINI_OBJECT_REFCOUNT_VALUE (*out_buf) == 1) {
-
- if (copy_inbuf && gst_buffer_is_writable (*out_buf))
- memcpy (GST_BUFFER_DATA (*out_buf), GST_BUFFER_DATA (in_buf), out_size);
-
- gst_buffer_stamp (*out_buf, in_buf);
- GST_BUFFER_FLAGS (*out_buf) |= GST_BUFFER_FLAGS (in_buf) &
- (GST_BUFFER_FLAG_PREROLL | GST_BUFFER_FLAG_IN_CAPS |
- GST_BUFFER_FLAG_DELTA_UNIT);
- }
-
-done:
- if (out_caps)
- gst_caps_unref (out_caps);
- trans->delay_configure = FALSE;
-
- return ret;
-}
-
-static gboolean
-gst_base_transform_get_unit_size (GstBaseTransform * trans, GstCaps * caps,
- guint * size)
-{
- gboolean res = FALSE;
- GstBaseTransformClass *bclass;
-
- /* see if we have the result cached */
- if (trans->cache_caps1 == caps) {
- *size = trans->cache_caps1_size;
- GST_DEBUG_OBJECT (trans, "get size returned cached 1 %d", *size);
- return TRUE;
- }
- if (trans->cache_caps2 == caps) {
- *size = trans->cache_caps2_size;
- GST_DEBUG_OBJECT (trans, "get size returned cached 2 %d", *size);
- return TRUE;
- }
-
- bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
- if (bclass->get_unit_size) {
- res = bclass->get_unit_size (trans, caps, size);
- GST_DEBUG_OBJECT (trans, "caps %" GST_PTR_FORMAT
- ") has unit size %d, result %s", caps, *size, res ? "TRUE" : "FALSE");
-
- if (res) {
- if (trans->cache_caps1 == NULL) {
- gst_caps_replace (&trans->cache_caps1, caps);
- trans->cache_caps1_size = *size;
- } else if (trans->cache_caps2 == NULL) {
- gst_caps_replace (&trans->cache_caps2, caps);
- trans->cache_caps2_size = *size;
- }
- }
- } else {
- GST_DEBUG ("Sub-class does not implement get_unit_size");
- }
- return res;
-}
-
-/* your upstream peer wants to send you a buffer
- * that buffer has the given offset, size and caps
- * you're requested to allocate a buffer
- */
-static GstFlowReturn
-gst_base_transform_buffer_alloc (GstPad * pad, guint64 offset, guint size,
- GstCaps * caps, GstBuffer ** buf)
-{
- GstBaseTransform *trans;
- GstFlowReturn res;
- guint new_size;
-
- trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
-
- /* we cannot run this when we are transforming data and as such doing
- * another negotiation in the transform method. */
- g_mutex_lock (trans->transform_lock);
-
- *buf = NULL;
-
- GST_DEBUG_OBJECT (trans, "allocating a buffer of size %d ...", size, offset);
- if (offset == GST_BUFFER_OFFSET_NONE)
- GST_DEBUG_OBJECT (trans, "... and offset NONE");
- else
- GST_DEBUG_OBJECT (trans, "... and offset %" G_GUINT64_FORMAT, offset);
-
- /* before any buffers are pushed, have_same_caps is TRUE; allocating can trigger
- * a renegotiation and change that to FALSE */
- if (trans->have_same_caps) {
- /* request a buffer with the same caps */
- GST_DEBUG_OBJECT (trans, "requesting buffer with same caps, size %d", size);
-
- res = gst_pad_alloc_buffer (trans->srcpad, offset, size, caps, buf);
- } else {
- /* if we are configured, request a buffer with the src caps */
- GstCaps *srccaps = gst_pad_get_negotiated_caps (trans->srcpad);
- GstCaps *sinkcaps = gst_pad_get_negotiated_caps (trans->sinkpad);
-
- if (!srccaps)
- goto not_configured;
-
- if (sinkcaps != NULL) {
- if (sinkcaps != caps || !gst_caps_is_equal (sinkcaps, caps)) {
- gst_caps_unref (sinkcaps);
- gst_caps_unref (srccaps);
- goto not_configured;
- }
- gst_caps_unref (sinkcaps);
- }
-
- GST_DEBUG_OBJECT (trans, "calling transform_size");
- if (!gst_base_transform_transform_size (trans,
- GST_PAD_DIRECTION (pad), caps, size, srccaps, &new_size)) {
- gst_caps_unref (srccaps);
- goto unknown_size;
- }
-
- res = gst_pad_alloc_buffer (trans->srcpad, offset, new_size, srccaps, buf);
- gst_caps_unref (srccaps);
- }
-
- if (res == GST_FLOW_OK && !trans->have_same_caps) {
- /* note that we might have had same caps before, but calling the
- alloc_buffer caused setcaps to switch us out of in_place -- in any case
- the alloc_buffer served to transmit caps information but we can't use the
- buffer. fall through and allocate a buffer corresponding to our sink
- caps, if any */
- GstCaps *sinkcaps = gst_pad_get_negotiated_caps (trans->sinkpad);
- GstCaps *srccaps = gst_pad_get_negotiated_caps (trans->srcpad);
-
- if (!sinkcaps)
- goto not_configured;
-
- if (!gst_base_transform_transform_size (trans,
- GST_PAD_DIRECTION (trans->srcpad), srccaps, GST_BUFFER_SIZE (*buf),
- sinkcaps, &new_size)) {
- gst_caps_unref (srccaps);
- gst_caps_unref (sinkcaps);
- goto unknown_size;
- }
-
- gst_buffer_unref (*buf);
-
- *buf = gst_buffer_new_and_alloc (new_size);
- gst_buffer_set_caps (*buf, sinkcaps);
- GST_BUFFER_OFFSET (*buf) = offset;
- res = GST_FLOW_OK;
-
- gst_caps_unref (srccaps);
- gst_caps_unref (sinkcaps);
- }
- g_mutex_unlock (trans->transform_lock);
-
- gst_object_unref (trans);
-
- return res;
-
-not_configured:
- {
- /* let the default allocator handle it */
- GST_DEBUG_OBJECT (trans, "not configured");
- if (*buf) {
- gst_buffer_unref (*buf);
- *buf = NULL;
- }
- g_mutex_unlock (trans->transform_lock);
- gst_object_unref (trans);
- return GST_FLOW_OK;
- }
-unknown_size:
- {
- /* let the default allocator handle it */
- GST_DEBUG_OBJECT (trans, "unknown size");
- if (*buf) {
- gst_buffer_unref (*buf);
- *buf = NULL;
- }
- g_mutex_unlock (trans->transform_lock);
- gst_object_unref (trans);
- return GST_FLOW_OK;
- }
-}
-
-static gboolean
-gst_base_transform_event (GstPad * pad, GstEvent * event)
-{
- GstBaseTransform *trans;
- GstBaseTransformClass *bclass;
- gboolean ret = TRUE;
-
- trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
- bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
-
- if (bclass->event)
- ret = bclass->event (trans, event);
-
- if (ret)
- ret = gst_pad_event_default (pad, event);
-
- gst_object_unref (trans);
-
- return ret;
-}
-
-static gboolean
-gst_base_transform_eventfunc (GstBaseTransform * trans, GstEvent * event)
-{
- switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_FLUSH_START:
- break;
- case GST_EVENT_FLUSH_STOP:
- /* we need new segment info after the flush. */
- gst_segment_init (&trans->segment, GST_FORMAT_UNDEFINED);
- break;
- case GST_EVENT_EOS:
- break;
- case GST_EVENT_TAG:
- break;
- case GST_EVENT_NEWSEGMENT:
- {
- GstFormat format;
- gdouble rate;
- gint64 start, stop, time;
- gboolean update;
-
- gst_event_parse_new_segment (event, &update, &rate, &format, &start,
- &stop, &time);
-
- gst_segment_set_newsegment (&trans->segment, update, rate, format, start,
- stop, time);
-
- trans->have_newsegment = TRUE;
-
- if (format == GST_FORMAT_TIME) {
- GST_DEBUG_OBJECT (trans, "received NEW_SEGMENT %" GST_TIME_FORMAT
- " -- %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT
- ", accum %" GST_TIME_FORMAT,
- GST_TIME_ARGS (trans->segment.start),
- GST_TIME_ARGS (trans->segment.stop),
- GST_TIME_ARGS (trans->segment.time),
- GST_TIME_ARGS (trans->segment.accum));
- } else {
- GST_DEBUG_OBJECT (trans, "received NEW_SEGMENT %" G_GINT64_FORMAT
- " -- %" G_GINT64_FORMAT ", time %" G_GINT64_FORMAT
- ", accum %" G_GINT64_FORMAT,
- trans->segment.start, trans->segment.stop,
- trans->segment.time, trans->segment.accum);
- }
- break;
- }
- default:
- break;
- }
-
- return TRUE;
-}
-
-static GstFlowReturn
-gst_base_transform_handle_buffer (GstBaseTransform * trans, GstBuffer * inbuf,
- GstBuffer ** outbuf)
-{
- GstBaseTransformClass *bclass;
- GstFlowReturn ret = GST_FLOW_OK;
- guint out_size;
- gboolean want_in_place;
-
- bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
-
- if (GST_BUFFER_OFFSET_IS_VALID (inbuf))
- GST_LOG_OBJECT (trans, "handling buffer %p of size %d and offset %"
- G_GUINT64_FORMAT, inbuf, GST_BUFFER_SIZE (inbuf),
- GST_BUFFER_OFFSET (inbuf));
- else
- GST_LOG_OBJECT (trans, "handling buffer %p of size %d and offset NONE",
- inbuf, GST_BUFFER_SIZE (inbuf));
-
- /* Don't allow buffer handling before negotiation, except in passthrough mode
- * or if the class doesn't implement a set_caps function (in which case it doesn't
- * care about caps)
- */
- if (!trans->negotiated && !trans->passthrough && (bclass->set_caps != NULL))
- goto not_negotiated;
-
- if (trans->passthrough) {
- /* In passthrough mode, give transform_ip a look at the
- * buffer, without making it writable, or just push the
- * data through */
- GST_LOG_OBJECT (trans, "element is in passthrough mode");
-
- if (bclass->transform_ip)
- ret = bclass->transform_ip (trans, inbuf);
-
- *outbuf = inbuf;
-
- return ret;
- }
-
- want_in_place = (bclass->transform_ip != NULL) && trans->always_in_place;
- *outbuf = NULL;
-
- if (want_in_place) {
- /* If want_in_place is TRUE, we may need to prepare a new output buffer
- * Sub-classes can implement a prepare_output_buffer function as they
- * wish. */
- GST_LOG_OBJECT (trans, "doing inplace transform");
-
- ret = gst_base_transform_prepare_output_buf (trans, inbuf,
- GST_BUFFER_SIZE (inbuf), GST_PAD_CAPS (trans->srcpad), outbuf);
- if (G_UNLIKELY (ret != GST_FLOW_OK))
- goto no_buffer;
-
- ret = bclass->transform_ip (trans, *outbuf);
-
- } else {
- GST_LOG_OBJECT (trans, "doing non-inplace transform");
-
- /* not transforming inplace, figure out the output size */
- if (trans->always_in_place) {
- out_size = GST_BUFFER_SIZE (inbuf);
- } else {
- if (!gst_base_transform_transform_size (trans,
- GST_PAD_DIRECTION (trans->sinkpad), GST_PAD_CAPS (trans->sinkpad),
- GST_BUFFER_SIZE (inbuf), GST_PAD_CAPS (trans->srcpad),
- &out_size)) {
- /* we have an error */
- goto no_size;
- }
- }
-
- /* no in place transform, get buffer, this might renegotiate. */
- ret = gst_base_transform_prepare_output_buf (trans, inbuf, out_size,
- GST_PAD_CAPS (trans->srcpad), outbuf);
- if (ret != GST_FLOW_OK)
- goto no_buffer;
-
- if (bclass->transform)
- ret = bclass->transform (trans, inbuf, *outbuf);
- else
- ret = GST_FLOW_NOT_SUPPORTED;
- }
-
- /* if we got renegotiated we can configure now */
- if (trans->pending_configure) {
- gboolean success;
-
- success =
- gst_base_transform_configure_caps (trans,
- GST_PAD_CAPS (trans->sinkpad), GST_PAD_CAPS (trans->srcpad));
-
- trans->pending_configure = FALSE;
-
- if (!success)
- goto configure_failed;
- }
- gst_buffer_unref (inbuf);
-
- return ret;
-
- /* ERRORS */
-not_negotiated:
- {
- gst_buffer_unref (inbuf);
- GST_ELEMENT_ERROR (trans, STREAM, NOT_IMPLEMENTED,
- ("not negotiated"), ("not negotiated"));
- return GST_FLOW_NOT_NEGOTIATED;
- }
-no_size:
- {
- gst_buffer_unref (inbuf);
- GST_ELEMENT_ERROR (trans, STREAM, NOT_IMPLEMENTED,
- ("subclass did not specify output size"),
- ("subclass did not specify output size"));
- return GST_FLOW_ERROR;
- }
-no_buffer:
- {
- gst_buffer_unref (inbuf);
- GST_DEBUG_OBJECT (trans, "could not get buffer from pool");
- return ret;
- }
-configure_failed:
- {
- gst_buffer_unref (inbuf);
- GST_DEBUG_OBJECT (trans, "could not negotiate");
- return GST_FLOW_NOT_NEGOTIATED;
- }
-}
-
-/* FIXME, getrange is broken, need to pull range from the other
- * end based on the transform_size result.
- */
-static GstFlowReturn
-gst_base_transform_getrange (GstPad * pad, guint64 offset,
- guint length, GstBuffer ** buffer)
-{
- GstBaseTransform *trans;
- GstFlowReturn ret;
- GstBuffer *inbuf;
-
- trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
-
- ret = gst_pad_pull_range (trans->sinkpad, offset, length, &inbuf);
- if (ret == GST_FLOW_OK) {
- g_mutex_lock (trans->transform_lock);
- ret = gst_base_transform_handle_buffer (trans, inbuf, buffer);
- g_mutex_unlock (trans->transform_lock);
- }
-
- gst_object_unref (trans);
-
- return ret;
-}
-
-static GstFlowReturn
-gst_base_transform_chain (GstPad * pad, GstBuffer * buffer)
-{
- GstBaseTransform *trans;
- GstFlowReturn ret;
- GstBuffer *outbuf = NULL;
-
- trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
-
- /* protect transform method and concurrent buffer alloc */
- g_mutex_lock (trans->transform_lock);
- ret = gst_base_transform_handle_buffer (trans, buffer, &outbuf);
- g_mutex_unlock (trans->transform_lock);
-
- if (ret == GST_FLOW_OK) {
- ret = gst_pad_push (trans->srcpad, outbuf);
- } else if (outbuf != NULL)
- gst_buffer_unref (outbuf);
-
- gst_object_unref (trans);
-
- return ret;
-}
-
-static void
-gst_base_transform_set_property (GObject * object, guint prop_id,
- const GValue * value, GParamSpec * pspec)
-{
- GstBaseTransform *trans;
-
- trans = GST_BASE_TRANSFORM (object);
-
- switch (prop_id) {
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-gst_base_transform_get_property (GObject * object, guint prop_id,
- GValue * value, GParamSpec * pspec)
-{
- GstBaseTransform *trans;
-
- trans = GST_BASE_TRANSFORM (object);
-
- switch (prop_id) {
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static gboolean
-gst_base_transform_sink_activate_push (GstPad * pad, gboolean active)
-{
- gboolean result = TRUE;
- GstBaseTransform *trans;
- GstBaseTransformClass *bclass;
-
- trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
- bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
-
- if (active) {
- if (bclass->start)
- result = bclass->start (trans);
- }
- gst_object_unref (trans);
-
- return result;
-}
-
-static gboolean
-gst_base_transform_src_activate_pull (GstPad * pad, gboolean active)
-{
- gboolean result = FALSE;
- GstBaseTransform *trans;
- GstBaseTransformClass *bclass;
-
- trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
- bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
-
- result = gst_pad_activate_pull (trans->sinkpad, active);
-
- if (active) {
- if (result && bclass->start)
- result &= bclass->start (trans);
- }
- gst_object_unref (trans);
-
- return result;
-}
-
-static GstStateChangeReturn
-gst_base_transform_change_state (GstElement * element,
- GstStateChange transition)
-{
- GstBaseTransform *trans;
- GstBaseTransformClass *bclass;
- GstStateChangeReturn result;
-
- trans = GST_BASE_TRANSFORM (element);
- bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
-
-
- switch (transition) {
- case GST_STATE_CHANGE_NULL_TO_READY:
- break;
- case GST_STATE_CHANGE_READY_TO_PAUSED:
- GST_OBJECT_LOCK (trans);
- if (GST_PAD_CAPS (trans->sinkpad) && GST_PAD_CAPS (trans->srcpad))
- trans->have_same_caps =
- gst_caps_is_equal (GST_PAD_CAPS (trans->sinkpad),
- GST_PAD_CAPS (trans->srcpad)) || trans->passthrough;
- else
- trans->have_same_caps = trans->passthrough;
- GST_DEBUG_OBJECT (trans, "have_same_caps %d", trans->have_same_caps);
- trans->negotiated = FALSE;
- trans->have_newsegment = FALSE;
- gst_segment_init (&trans->segment, GST_FORMAT_UNDEFINED);
- GST_OBJECT_UNLOCK (trans);
- break;
- case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
- break;
- case GST_STATE_CHANGE_PAUSED_TO_READY:
- gst_caps_replace (&trans->cache_caps1, NULL);
- gst_caps_replace (&trans->cache_caps2, NULL);
- default:
- break;
- }
-
- result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
-
- switch (transition) {
- case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
- break;
- case GST_STATE_CHANGE_PAUSED_TO_READY:
- if (bclass->stop)
- result = bclass->stop (trans);
- break;
- case GST_STATE_CHANGE_READY_TO_NULL:
- break;
- default:
- break;
- }
-
- return result;
-}
-
-/**
- * gst_base_transform_set_passthrough:
- * @trans: the #GstBaseTransform to set
- * @passthrough: boolean indicating passthrough mode.
- *
- * Set passthrough mode for this filter by default. This is mostly
- * useful for filters that do not care about negotiation.
- *
- * Always TRUE for filters which don't implement either a transform
- * or transform_ip method.
- *
- * MT safe.
- */
-void
-gst_base_transform_set_passthrough (GstBaseTransform * trans,
- gboolean passthrough)
-{
- GstBaseTransformClass *bclass;
-
- g_return_if_fail (trans != NULL);
-
- bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
-
- GST_OBJECT_LOCK (trans);
- if (passthrough == FALSE) {
- if (bclass->transform_ip || bclass->transform)
- trans->passthrough = FALSE;
- } else {
- trans->passthrough = TRUE;
- }
-
- GST_DEBUG_OBJECT (trans, "set passthrough %d", trans->passthrough);
- GST_OBJECT_UNLOCK (trans);
-}
-
-/**
- * gst_base_transform_is_passthrough:
- * @trans: the #GstBaseTransform to query
- *
- * See if @trans is configured as a passthrough transform.
- *
- * Returns: TRUE is the transform is configured in passthrough mode.
- *
- * MT safe.
- */
-gboolean
-gst_base_transform_is_passthrough (GstBaseTransform * trans)
-{
- gboolean result;
-
- g_return_val_if_fail (trans != NULL, FALSE);
-
- GST_OBJECT_LOCK (trans);
- result = trans->passthrough;
- GST_OBJECT_UNLOCK (trans);
-
- return result;
-}
-
-/**
- * gst_base_transform_set_in_place:
- * @trans: the #GstBaseTransform to modify
- * @in_place: Boolean value indicating that we would like to operate
- * on in_place buffers.
- *
- * Determines whether a non-writable buffer will be copied before passing
- * to the transform_ip function.
- * <itemizedlist>
- * <listitem>Always TRUE if no transform function is implemented.</listitem>
- * <listitem>Always FALSE if ONLY transform_ip function is implemented.</listitem>
- * </itemizedlist>
- *
- * MT safe.
- */
-void
-gst_base_transform_set_in_place (GstBaseTransform * trans, gboolean in_place)
-{
- GstBaseTransformClass *bclass;
-
- g_return_if_fail (trans != NULL);
-
- bclass = GST_BASE_TRANSFORM_GET_CLASS (trans);
-
- GST_OBJECT_LOCK (trans);
-
- if (in_place) {
- if (bclass->transform_ip) {
- GST_DEBUG_OBJECT (trans, "setting in_place TRUE");
- trans->always_in_place = TRUE;
- }
- } else {
- if (bclass->transform) {
- GST_DEBUG_OBJECT (trans, "setting in_place FALSE");
- trans->always_in_place = FALSE;
- }
- }
-
- GST_OBJECT_UNLOCK (trans);
-}
-
-/**
- * gst_base_transform_is_in_place:
- * @trans: the #GstBaseTransform to query
- *
- * See if @trans is configured as a in_place transform.
- *
- * Returns: TRUE is the transform is configured in in_place mode.
- *
- * MT safe.
- */
-gboolean
-gst_base_transform_is_in_place (GstBaseTransform * trans)
-{
- gboolean result;
-
- g_return_val_if_fail (trans != NULL, FALSE);
-
- GST_OBJECT_LOCK (trans);
- result = trans->always_in_place;
- GST_OBJECT_UNLOCK (trans);
-
- return result;
-}
+++ /dev/null
-/* GStreamer
- * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
- * 2005 Wim Taymans <wim@fluendo.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#ifndef __GST_BASE_TRANSFORM_H__
-#define __GST_BASE_TRANSFORM_H__
-
-#include <gst/gst.h>
-
-G_BEGIN_DECLS
-
-#define GST_TYPE_BASE_TRANSFORM (gst_base_transform_get_type())
-#define GST_BASE_TRANSFORM(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_BASE_TRANSFORM,GstBaseTransform))
-#define GST_BASE_TRANSFORM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_BASE_TRANSFORM,GstBaseTransformClass))
-#define GST_BASE_TRANSFORM_GET_CLASS(obj) \
- (G_TYPE_INSTANCE_GET_CLASS ((obj),GST_TYPE_BASE_TRANSFORM,GstBaseTransformClass))
-#define GST_IS_BASE_TRANSFORM(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_BASE_TRANSFORM))
-#define GST_IS_BASE_TRANSFORM_CLASS(obj)(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_BASE_TRANSFORM))
-
-/**
- * GST_BASE_TRANSFORM_SINK_NAME:
- *
- * the name of the templates for the sink pad
- */
-#define GST_BASE_TRANSFORM_SINK_NAME "sink"
-/**
- * GST_BASE_TRANSFORM_SRC_NAME:
- *
- * the name of the templates for the source pad
- */
-#define GST_BASE_TRANSFORM_SRC_NAME "src"
-
-typedef struct _GstBaseTransform GstBaseTransform;
-typedef struct _GstBaseTransformClass GstBaseTransformClass;
-
-/**
- * GstBaseTransform:
- *
- * The opaque #GstBaseTransform data structure.
- */
-struct _GstBaseTransform {
- GstElement element;
-
- /*< protected >*/
- /* source and sink pads */
- GstPad *sinkpad;
- GstPad *srcpad;
-
- /* Set by sub-class */
- gboolean passthrough;
- gboolean always_in_place;
-
- GstCaps *cache_caps1;
- guint cache_caps1_size;
- GstCaps *cache_caps2;
- guint cache_caps2_size;
- gboolean have_same_caps;
-
- gboolean delay_configure;
- gboolean pending_configure;
- gboolean negotiated;
-
- gboolean have_newsegment;
-
- /* MT-protected (with STREAM_LOCK) */
- GstSegment segment;
-
- GMutex *transform_lock;
-
- /*< private >*/
- gpointer _gst_reserved[GST_PADDING];
-};
-
-/**
- * GstBaseTransformClass::transform_caps:
- * @direction: the pad direction
- * @caps: the caps
- *
- * This method should answer the question "given this pad, and given these
- * caps, what caps would you allow on the other pad inside your element ?"
- */
-struct _GstBaseTransformClass {
- GstElementClass parent_class;
-
- /*< public >*/
- /* virtual methods for subclasses */
-
- /* given the (non-)fixed simple caps on the pad in the given direction,
- * what can I do on the other pad ? */
- GstCaps* (*transform_caps) (GstBaseTransform *trans,
- GstPadDirection direction,
- GstCaps *caps);
-
- /* given caps on one pad, how would you fixate caps on the other pad ? */
- void (*fixate_caps) (GstBaseTransform *trans,
- GstPadDirection direction, GstCaps *caps,
- GstCaps *othercaps);
-
- /* given the size of a buffer in the given direction with the given caps,
- * calculate the byte size of an buffer on the other side with the given
- * other caps; the default
- * implementation uses get_size and keeps the number of units the same */
- gboolean (*transform_size) (GstBaseTransform *trans,
- GstPadDirection direction,
- GstCaps *caps, guint size,
- GstCaps *othercaps, guint *othersize);
-
- /* get the byte size of one unit for a given caps.
- * Always needs to be implemented if the transform is not in-place. */
- gboolean (*get_unit_size) (GstBaseTransform *trans, GstCaps *caps,
- guint *size);
-
- /* notify the subclass of new caps */
- gboolean (*set_caps) (GstBaseTransform *trans, GstCaps *incaps,
- GstCaps *outcaps);
-
- /* start and stop processing, ideal for opening/closing the resource */
- gboolean (*start) (GstBaseTransform *trans);
- gboolean (*stop) (GstBaseTransform *trans);
-
- gboolean (*event) (GstBaseTransform *trans, GstEvent *event);
-
- /* transform one incoming buffer to one outgoing buffer.
- * Always needs to be implemented unless always operating in-place.
- * transform function is allowed to change size/timestamp/duration of
- * the outgoing buffer. */
- GstFlowReturn (*transform) (GstBaseTransform *trans, GstBuffer *inbuf,
- GstBuffer *outbuf);
-
- /* transform a buffer inplace */
- GstFlowReturn (*transform_ip) (GstBaseTransform *trans, GstBuffer *buf);
-
- /* FIXME: When adjusting the padding, more these to nicer places in the class */
- /* Set by child classes to automatically do passthrough mode */
- gboolean passthrough_on_same_caps;
-
- /* Subclasses can override this to do their own allocation of output buffers.
- * Elements that only do analysis can return a subbuffer or even just
- * increment the reference to the input buffer (if in passthrough mode)
- */
- GstFlowReturn (*prepare_output_buffer) (GstBaseTransform * trans,
- GstBuffer *input, gint size, GstCaps *caps, GstBuffer **buf);
-
- /*< private >*/
- gpointer _gst_reserved[GST_PADDING - 2];
-};
-
-GType gst_base_transform_get_type (void);
-
-void gst_base_transform_set_passthrough (GstBaseTransform *trans,
- gboolean passthrough);
-gboolean gst_base_transform_is_passthrough (GstBaseTransform *trans);
-
-void gst_base_transform_set_in_place (GstBaseTransform *trans,
- gboolean in_place);
-gboolean gst_base_transform_is_in_place (GstBaseTransform *trans);
-
-
-G_END_DECLS
-
-#endif /* __GST_BASE_TRANSFORM_H__ */
+++ /dev/null
-/* GStreamer
- * Copyright (C) 2005 Wim Taymans <wim@fluendo.com>
- *
- * gstcollectpads.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., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-/**
- * SECTION:gstcollectpads
- * @short_description: manages a set of pads that operate in collect mode
- * @see_also:
- *
- * Manages a set of pads that operate in collect mode. This means that control
- * is given to the manager of this object when all pads have data.
- * <itemizedlist>
- * <listitem><para>
- * Collectpads are created with gst_collect_pads_new(). A callback should then
- * be installed with gst_collect_pads_set_function ().
- * </para></listitem>
- * <listitem><para>
- * Pads are added to the collection with gst_collect_pads_add_pad()/
- * gst_collect_pads_remove_pad(). The pad
- * has to be a sinkpad. The chain function of the pad is
- * overridden. The element_private of the pad is used to store
- * private information.
- * </para></listitem>
- * <listitem><para>
- * For each pad, data is queued in the chain function or by
- * performing a pull_range.
- * </para></listitem>
- * <listitem><para>
- * When data is queued on all pads, the callback function is called.
- * </para></listitem>
- * <listitem><para>
- * Data can be dequeued from the pad with the gst_collect_pads_pop() method.
- * One can peek at the data with the gst_collect_pads_peek() function.
- * These functions will return NULL if the pad received an EOS event. When all
- * pads return NULL from a gst_collect_pads_peek(), the element can emit an EOS
- * event itself.
- * </para></listitem>
- * <listitem><para>
- * Data can also be dequeued in byte units using the gst_collect_pads_available(),
- * gst_collect_pads_read() and gst_collect_pads_flush() calls.
- * </para></listitem>
- * <listitem><para>
- * Elements should call gst_collect_pads_start() and gst_collect_pads_stop() in
- * their state change functions to start and stop the processing of the collecpads.
- * The gst_collect_pads_stop() call should be called before calling the parent
- * element state change function in the PAUSED_TO_READY state change to ensure
- * no pad is blocked and the element can finish streaming.
- * </para></listitem>
- * <listitem><para>
- * gst_collect_pads_collect() and gst_collect_pads_collect_range() can be used by
- * elements that start a #GstTask to drive the collect_pads.
- * </para></listitem>
- * </itemizedlist>
- */
-
-#include "gstcollectpads.h"
-
-GST_DEBUG_CATEGORY_STATIC (collect_pads_debug);
-#define GST_CAT_DEFAULT collect_pads_debug
-
-GST_BOILERPLATE (GstCollectPads, gst_collect_pads, GstObject, GST_TYPE_OBJECT)
-
- static GstFlowReturn gst_collect_pads_chain (GstPad * pad,
- GstBuffer * buffer);
- static gboolean gst_collect_pads_event (GstPad * pad, GstEvent * event);
- static void gst_collect_pads_finalize (GObject * object);
- static void gst_collect_pads_init (GstCollectPads * pads,
- GstCollectPadsClass * g_class);
-
- static void gst_collect_pads_base_init (gpointer g_class)
-{
- GST_DEBUG_CATEGORY_INIT (collect_pads_debug, "collect_pads", 0,
- "GstCollectPads");
-}
-
-static void
-gst_collect_pads_class_init (GstCollectPadsClass * klass)
-{
- GObjectClass *gobject_class = (GObjectClass *) klass;
-
- gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_collect_pads_finalize);
-}
-
-static void
-gst_collect_pads_init (GstCollectPads * pads, GstCollectPadsClass * g_class)
-{
- pads->cond = g_cond_new ();
- pads->data = NULL;
- pads->cookie = 0;
- pads->numpads = 0;
- pads->queuedpads = 0;
- pads->eospads = 0;
- pads->started = FALSE;
-}
-
-static void
-gst_collect_pads_finalize (GObject * object)
-{
- GstCollectPads *pads = GST_COLLECT_PADS (object);
-
- gst_collect_pads_stop (pads);
- g_cond_free (pads->cond);
- /* FIXME, free data */
-
- G_OBJECT_CLASS (parent_class)->finalize (object);
-}
-
-/**
- * gst_collect_pads_new:
- *
- * Create a new instance of #GstCollectsPads.
- *
- * Returns: a new #GstCollectPads, or NULL in case of an error.
- *
- * MT safe.
- */
-GstCollectPads *
-gst_collect_pads_new (void)
-{
- GstCollectPads *newcoll;
-
- newcoll = g_object_new (GST_TYPE_COLLECT_PADS, NULL);
-
- return newcoll;
-}
-
-/**
- * gst_collect_pads_set_function:
- * @pads: the collectspads to use
- * @func: the function to set
- * @user_data: user data passed to the function
- *
- * Set the callback function and user data that will be called when
- * all the pads added to the collection have buffers queued.
- *
- * MT safe.
- */
-void
-gst_collect_pads_set_function (GstCollectPads * pads,
- GstCollectPadsFunction func, gpointer user_data)
-{
- g_return_if_fail (pads != NULL);
- g_return_if_fail (GST_IS_COLLECT_PADS (pads));
-
- GST_OBJECT_LOCK (pads);
- pads->func = func;
- pads->user_data = user_data;
- GST_OBJECT_UNLOCK (pads);
-}
-
-/**
- * gst_collect_pads_add_pad:
- * @pads: the collectspads to use
- * @pad: the pad to add
- * @size: the size of the returned GstCollectData structure
- *
- * Add a pad to the collection of collect pads. The pad has to be
- * a sinkpad.
- *
- * You specify a size for the returned #GstCollectData structure
- * so that you can use it to store additional information.
- *
- * Returns: a new #GstCollectData to identify the new pad. Or NULL
- * if wrong parameters are supplied.
- *
- * MT safe.
- */
-GstCollectData *
-gst_collect_pads_add_pad (GstCollectPads * pads, GstPad * pad, guint size)
-{
- GstCollectData *data;
-
- g_return_val_if_fail (pads != NULL, NULL);
- g_return_val_if_fail (GST_IS_COLLECT_PADS (pads), NULL);
- g_return_val_if_fail (pad != NULL, NULL);
- g_return_val_if_fail (GST_PAD_IS_SINK (pad), NULL);
- g_return_val_if_fail (size >= sizeof (GstCollectData), NULL);
-
- data = g_malloc0 (size);
- data->collect = pads;
- data->pad = pad;
- data->buffer = NULL;
- gst_segment_init (&data->segment, GST_FORMAT_UNDEFINED);
-
- GST_OBJECT_LOCK (pads);
- pads->data = g_slist_append (pads->data, data);
- gst_pad_set_chain_function (pad, GST_DEBUG_FUNCPTR (gst_collect_pads_chain));
- gst_pad_set_event_function (pad, GST_DEBUG_FUNCPTR (gst_collect_pads_event));
- gst_pad_set_element_private (pad, data);
- pads->numpads++;
- pads->cookie++;
- GST_OBJECT_UNLOCK (pads);
-
- return data;
-}
-
-static gint
-find_pad (GstCollectData * data, GstPad * pad)
-{
- if (data->pad == pad)
- return 0;
- return 1;
-}
-
-/**
- * gst_collect_pads_remove_pad:
- * @pads: the collectspads to use
- * @pad: the pad to remove
- *
- * Remove a pad from the collection of collect pads.
- *
- * Returns: TRUE if the pad could be removed.
- *
- * MT safe.
- */
-gboolean
-gst_collect_pads_remove_pad (GstCollectPads * pads, GstPad * pad)
-{
- GSList *list;
-
- g_return_val_if_fail (pads != NULL, FALSE);
- g_return_val_if_fail (GST_IS_COLLECT_PADS (pads), FALSE);
- g_return_val_if_fail (pad != NULL, FALSE);
- g_return_val_if_fail (GST_IS_PAD (pad), FALSE);
-
- GST_OBJECT_LOCK (pads);
- list = g_slist_find_custom (pads->data, pad, (GCompareFunc) find_pad);
- if (list) {
- g_free (list->data);
- pads->data = g_slist_delete_link (pads->data, list);
- }
- pads->numpads--;
- pads->cookie++;
- GST_OBJECT_UNLOCK (pads);
-
- return list != NULL;
-}
-
-/**
- * gst_collect_pads_is_active:
- * @pads: the collectspads to use
- * @pad: the pad to check
- *
- * Check if a pad is active.
- *
- * Returns: TRUE if the pad is active.
- *
- * MT safe.
- */
-gboolean
-gst_collect_pads_is_active (GstCollectPads * pads, GstPad * pad)
-{
- g_return_val_if_fail (pads != NULL, FALSE);
- g_return_val_if_fail (GST_IS_COLLECT_PADS (pads), FALSE);
- g_return_val_if_fail (pad != NULL, FALSE);
- g_return_val_if_fail (GST_IS_PAD (pad), FALSE);
-
- g_warning ("gst_collect_pads_is_active() is not implemented");
-
- return FALSE;
-}
-
-/**
- * gst_collect_pads_collect:
- * @pads: the collectspads to use
- *
- * Collect data on all pads. This function is usually called
- * from a GstTask function in an element. This function is
- * currently not implemented.
- *
- * Returns: GstFlowReturn of the operation.
- *
- * MT safe.
- */
-GstFlowReturn
-gst_collect_pads_collect (GstCollectPads * pads)
-{
- g_return_val_if_fail (pads != NULL, GST_FLOW_ERROR);
- g_return_val_if_fail (GST_IS_COLLECT_PADS (pads), GST_FLOW_ERROR);
-
- g_warning ("gst_collect_pads_collect() is not implemented");
-
- return GST_FLOW_ERROR;
-}
-
-/**
- * gst_collect_pads_collect_range:
- * @pads: the collectspads to use
- * @offset: the offset to collect
- * @length: the length to collect
- *
- * Collect data with @offset and @length on all pads. This function
- * is typically called in the getrange function of an element. This
- * function is currently not implemented.
- *
- * Returns: GstFlowReturn of the operation.
- *
- * MT safe.
- */
-GstFlowReturn
-gst_collect_pads_collect_range (GstCollectPads * pads, guint64 offset,
- guint length)
-{
- g_return_val_if_fail (pads != NULL, GST_FLOW_ERROR);
- g_return_val_if_fail (GST_IS_COLLECT_PADS (pads), GST_FLOW_ERROR);
-
- g_warning ("gst_collect_pads_collect_range() is not implemented");
-
- return GST_FLOW_ERROR;
-}
-
-/**
- * gst_collect_pads_start:
- * @pads: the collectspads to use
- *
- * Starts the processing of data in the collect_pads.
- *
- * MT safe.
- */
-void
-gst_collect_pads_start (GstCollectPads * pads)
-{
- g_return_if_fail (pads != NULL);
- g_return_if_fail (GST_IS_COLLECT_PADS (pads));
-
- GST_OBJECT_LOCK (pads);
- pads->started = TRUE;
- GST_OBJECT_UNLOCK (pads);
-}
-
-/**
- * gst_collect_pads_stop:
- * @pads: the collectspads to use
- *
- * Stops the processing of data in the collect_pads. this function
- * will also unblock any blocking operations.
- *
- * MT safe.
- */
-void
-gst_collect_pads_stop (GstCollectPads * pads)
-{
- g_return_if_fail (pads != NULL);
- g_return_if_fail (GST_IS_COLLECT_PADS (pads));
-
- GST_OBJECT_LOCK (pads);
- pads->started = FALSE;
- GST_COLLECT_PADS_BROADCAST (pads);
- GST_OBJECT_UNLOCK (pads);
-}
-
-/**
- * gst_collect_pads_peek:
- * @pads: the collectspads to peek
- * @data: the data to use
- *
- * Peek at the buffer currently queued in @data. This function
- * should be called with the @pads LOCK held, such as in the callback
- * handler.
- *
- * Returns: The buffer in @data or NULL if no buffer is queued.
- * should unref the buffer after usage.
- *
- * MT safe.
- */
-GstBuffer *
-gst_collect_pads_peek (GstCollectPads * pads, GstCollectData * data)
-{
- GstBuffer *result;
-
- g_return_val_if_fail (pads != NULL, NULL);
- g_return_val_if_fail (GST_IS_COLLECT_PADS (pads), NULL);
- g_return_val_if_fail (data != NULL, NULL);
-
- result = data->buffer;
-
- if (result)
- gst_buffer_ref (result);
-
- GST_DEBUG ("Peeking at pad %s:%s: buffer=%p",
- GST_DEBUG_PAD_NAME (data->pad), result);
-
- return result;
-}
-
-/**
- * gst_collect_pads_pop:
- * @pads: the collectspads to pop
- * @data: the data to use
- *
- * Pop the buffer currently queued in @data. This function
- * should be called with the @pads LOCK held, such as in the callback
- * handler.
- *
- * Returns: The buffer in @data or NULL if no buffer was queued.
- * You should unref the buffer after usage.
- *
- * MT safe.
- */
-GstBuffer *
-gst_collect_pads_pop (GstCollectPads * pads, GstCollectData * data)
-{
- GstBuffer *result;
-
- g_return_val_if_fail (pads != NULL, NULL);
- g_return_val_if_fail (GST_IS_COLLECT_PADS (pads), NULL);
- g_return_val_if_fail (data != NULL, NULL);
-
- result = data->buffer;
- if (result) {
- gst_buffer_replace (&data->buffer, NULL);
- data->pos = 0;
- pads->queuedpads--;
- }
-
- GST_COLLECT_PADS_SIGNAL (pads);
-
- GST_DEBUG ("Pop buffer on pad %s:%s: buffer=%p",
- GST_DEBUG_PAD_NAME (data->pad), result);
-
- return result;
-}
-
-/**
- * gst_collect_pads_available:
- * @pads: the collectspads to query
- *
- * Query how much bytes can be read from each queued buffer. This means
- * that the result of this call is the maximum number of bytes that can
- * be read from each of the pads.
- *
- * This function should be called with @pads LOCK held, such as
- * in the callback.
- *
- * Returns: The maximum number of bytes queued on all pad. This function
- * returns 0 if a pad has no queued buffer.
- *
- * MT safe.
- */
-guint
-gst_collect_pads_available (GstCollectPads * pads)
-{
- GSList *collected;
- guint result = G_MAXUINT;
-
- g_return_val_if_fail (pads != NULL, 0);
- g_return_val_if_fail (GST_IS_COLLECT_PADS (pads), 0);
-
- for (collected = pads->data; collected; collected = g_slist_next (collected)) {
- GstCollectData *pdata;
- gint size;
-
- pdata = (GstCollectData *) collected->data;
-
- if (pdata->buffer == NULL)
- goto not_filled;
-
- size = GST_BUFFER_SIZE (pdata->buffer) - pdata->pos;
-
- if (size < result)
- result = size;
- }
- return result;
-
-not_filled:
- {
- return 0;
- }
-}
-
-/**
- * gst_collect_pads_read:
- * @pads: the collectspads to query
- * @data: the data to use
- * @bytes: a pointer to a byte array
- * @size: the number of bytes to read
- *
- * Get a pointer in @bytes where @size bytes can be read from the
- * given pad data.
- *
- * This function should be called with @pads LOCK held, such as
- * in the callback.
- *
- * Returns: The number of bytes available for consumption in the
- * memory pointed to by @bytes. This can be less than @size and
- * is 0 if the pad is end-of-stream.
- *
- * MT safe.
- */
-guint
-gst_collect_pads_read (GstCollectPads * pads, GstCollectData * data,
- guint8 ** bytes, guint size)
-{
- guint readsize;
-
- g_return_val_if_fail (pads != NULL, 0);
- g_return_val_if_fail (GST_IS_COLLECT_PADS (pads), 0);
- g_return_val_if_fail (data != NULL, 0);
- g_return_val_if_fail (bytes != NULL, 0);
-
- readsize = MIN (size, GST_BUFFER_SIZE (data->buffer) - data->pos);
-
- *bytes = GST_BUFFER_DATA (data->buffer) + data->pos;
-
- return readsize;
-}
-
-/**
- * gst_collect_pads_flush:
- * @pads: the collectspads to query
- * @data: the data to use
- * @size: the number of bytes to flush
- *
- * Flush @size bytes from the pad @data.
- *
- * This function should be called with @pads LOCK held, such as
- * in the callback.
- *
- * Returns: The number of bytes flushed This can be less than @size and
- * is 0 if the pad was end-of-stream.
- *
- * MT safe.
- */
-guint
-gst_collect_pads_flush (GstCollectPads * pads, GstCollectData * data,
- guint size)
-{
- guint flushsize;
-
- g_return_val_if_fail (pads != NULL, 0);
- g_return_val_if_fail (GST_IS_COLLECT_PADS (pads), 0);
- g_return_val_if_fail (data != NULL, 0);
-
- flushsize = MIN (size, GST_BUFFER_SIZE (data->buffer) - data->pos);
-
- data->pos += size;
-
- if (data->pos >= GST_BUFFER_SIZE (data->buffer)) {
- GstBuffer *buf;
-
- buf = gst_collect_pads_pop (pads, data);
- gst_buffer_unref (buf);
- }
-
- return flushsize;
-}
-
-static gboolean
-gst_collect_pads_event (GstPad * pad, GstEvent * event)
-{
- GstCollectData *data;
- GstCollectPads *pads;
-
- /* some magic to get the managing collect_pads */
- data = (GstCollectData *) gst_pad_get_element_private (pad);
- if (data == NULL)
- goto not_ours;
-
- pads = data->collect;
-
- GST_DEBUG ("Got %s event on pad %s:%s", GST_EVENT_TYPE_NAME (event),
- GST_DEBUG_PAD_NAME (data->pad));
-
- switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_EOS:
- {
- GstFlowReturn ret = GST_FLOW_OK;
-
- GST_OBJECT_LOCK (pads);
-
- pads->eospads++;
-
- /* if all pads are EOS and we have a function, call it */
- if ((pads->eospads == pads->numpads) && pads->func) {
- ret = pads->func (pads, pads->user_data);
- }
-
- GST_OBJECT_UNLOCK (pads);
-
- /* We eat this event */
- gst_event_unref (event);
- return TRUE;
- break;
- }
- case GST_EVENT_NEWSEGMENT:
- {
- gint64 start, stop, time;
- gdouble rate;
- GstFormat format;
- gboolean update;
-
- gst_event_parse_new_segment (event, &update, &rate, &format,
- &start, &stop, &time);
-
- gst_segment_set_newsegment (&data->segment, update, rate, format,
- start, stop, time);
- goto beach;
- }
- default:
- goto beach;
- }
-
-beach:
- return gst_pad_event_default (pad, event);
-
- /* ERRORS */
-not_ours:
- {
- GST_DEBUG ("collect_pads not ours");
- return FALSE;
- }
-}
-
-
-static GstFlowReturn
-gst_collect_pads_chain (GstPad * pad, GstBuffer * buffer)
-{
- GstCollectData *data;
- GstCollectPads *pads;
- guint64 size;
- GstFlowReturn ret;
-
- GST_DEBUG ("Got buffer for pad %s:%s", GST_DEBUG_PAD_NAME (pad));
-
- /* some magic to get the managing collect_pads */
- data = (GstCollectData *) gst_pad_get_element_private (pad);
- if (data == NULL)
- goto not_ours;
-
- pads = data->collect;
- size = GST_BUFFER_SIZE (buffer);
-
- GST_OBJECT_LOCK (pads);
-
- /* if not started, bail out */
- if (!pads->started)
- goto not_started;
-
- /* Call the collected callback until a pad with a buffer is popped. */
- while (((pads->queuedpads + pads->eospads) == pads->numpads) && pads->func)
- ret = pads->func (pads, pads->user_data);
-
- /* queue buffer on this pad, block if filled */
- while (data->buffer != NULL) {
- GST_DEBUG ("Pad %s:%s already has a buffer queued, waiting",
- GST_DEBUG_PAD_NAME (pad));
- GST_COLLECT_PADS_WAIT (pads);
- GST_DEBUG ("Pad %s:%s resuming", GST_DEBUG_PAD_NAME (pad));
- /* after a signal, we could be stopped */
- if (!pads->started)
- goto not_started;
- }
-
- GST_DEBUG ("Queuing buffer %p for pad %s:%s", buffer,
- GST_DEBUG_PAD_NAME (pad));
-
- pads->queuedpads++;
- gst_buffer_replace (&data->buffer, buffer);
-
- /* if all pads have data and we have a function, call it */
- if (((pads->queuedpads + pads->eospads) == pads->numpads) && pads->func) {
- GST_DEBUG ("All active pads have data, calling %s",
- GST_DEBUG_FUNCPTR_NAME (pads->func));
- ret = pads->func (pads, pads->user_data);
- } else {
- GST_DEBUG ("Not all active pads have data, continuing");
- ret = GST_FLOW_OK;
- }
- GST_OBJECT_UNLOCK (pads);
-
- return ret;
-
- /* ERRORS */
-not_ours:
- {
- GST_DEBUG ("collect_pads not ours");
- return GST_FLOW_ERROR;
- }
-not_started:
- {
- GST_OBJECT_UNLOCK (pads);
- GST_DEBUG ("collect_pads not started");
- return GST_FLOW_WRONG_STATE;
- }
-}
+++ /dev/null
-/* GStreamer
- * Copyright (C) 2005 Wim Taymans <wim@fluendo.com>
- *
- * gstcollect_pads.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., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#ifndef __GST_COLLECT_PADS_H__
-#define __GST_COLLECT_PADS_H__
-
-#include <gst/gst.h>
-
-G_BEGIN_DECLS
-
-#define GST_TYPE_COLLECT_PADS (gst_collect_pads_get_type())
-#define GST_COLLECT_PADS(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_COLLECT_PADS,GstCollectPads))
-#define GST_COLLECT_PADS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_COLLECT_PADS,GstCollectPadsClass))
-#define GST_COLLECT_PADS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),GST_TYPE_COLLECT_PADS,GstCollectPadsClass))
-#define GST_IS_COLLECT_PADS(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_COLLECT_PADS))
-#define GST_IS_COLLECT_PADS_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_COLLECT_PADS))
-
-typedef struct _GstCollectData GstCollectData;
-typedef struct _GstCollectPads GstCollectPads;
-typedef struct _GstCollectPadsClass GstCollectPadsClass;
-
-/**
- * GstCollectData:
- * @collect: owner #GstCollectPads
- * @pad: #GstPad managed by this data
- * @buffer: currently queued buffer.
- * @pos: position in the buffer
- * @segment: last segment received.
- *
- * Structure used by the collect_pads.
- */
-struct _GstCollectData
-{
- GstCollectPads *collect;
- GstPad *pad;
- GstBuffer *buffer;
- guint pos;
- GstSegment segment;
-
- /*< private >*/
- gpointer _gst_reserved[GST_PADDING];
-};
-
-/**
- * GstCollectPadsFunction:
- * @pads: the #GstCollectPads that trigered the callback
- * @user_data: user data passed to gst_collect_pads_set_function()
- *
- * A function that will be called when all pads have received data.
- *
- * Returns: GST_FLOW_OK for success
- */
-typedef GstFlowReturn (*GstCollectPadsFunction) (GstCollectPads *pads, gpointer user_data);
-
-#define GST_COLLECT_PADS_GET_COND(pads) (((GstCollectPads *)pads)->cond)
-#define GST_COLLECT_PADS_WAIT(pads) (g_cond_wait (GST_COLLECT_PADS_GET_COND (pads), GST_OBJECT_GET_LOCK (pads)))
-#define GST_COLLECT_PADS_SIGNAL(pads) (g_cond_signal (GST_COLLECT_PADS_GET_COND (pads)))
-#define GST_COLLECT_PADS_BROADCAST(pads)(g_cond_broadcast (GST_COLLECT_PADS_GET_COND (pads)))
-
-/**
- * GstCollectPads:
- * @data: #GList of #GstCollectData managed by this #GstCollectPads.
- *
- * Collectpads object.
- */
-struct _GstCollectPads {
- GstObject object;
-
- /*< public >*/ /* with LOCK */
- GSList *data;
-
- /*< private >*/
- guint32 cookie;
-
- GCond *cond; /* to signal removal of data */
-
- GstCollectPadsFunction func; /* function and user_data for callback */
- gpointer user_data;
-
- guint numpads; /* number of pads */
- guint queuedpads; /* number of pads with a buffer */
- guint eospads; /* number of pads that are EOS */
-
- gboolean started;
-
- /*< private >*/
- gpointer _gst_reserved[GST_PADDING];
-};
-
-struct _GstCollectPadsClass {
- GstObjectClass parent_class;
-
- /*< private >*/
- gpointer _gst_reserved[GST_PADDING];
-};
-
-GType gst_collect_pads_get_type(void);
-
-/* creating the object */
-GstCollectPads* gst_collect_pads_new (void);
-
-/* set the callback */
-void gst_collect_pads_set_function (GstCollectPads *pads, GstCollectPadsFunction func,
- gpointer user_data);
-
-/* pad management */
-GstCollectData* gst_collect_pads_add_pad (GstCollectPads *pads, GstPad *pad, guint size);
-gboolean gst_collect_pads_remove_pad (GstCollectPads *pads, GstPad *pad);
-gboolean gst_collect_pads_is_active (GstCollectPads *pads, GstPad *pad);
-
-/* start/stop collection */
-GstFlowReturn gst_collect_pads_collect (GstCollectPads *pads);
-GstFlowReturn gst_collect_pads_collect_range (GstCollectPads *pads, guint64 offset, guint length);
-
-void gst_collect_pads_start (GstCollectPads *pads);
-void gst_collect_pads_stop (GstCollectPads *pads);
-
-/* get collected buffers */
-GstBuffer* gst_collect_pads_peek (GstCollectPads *pads, GstCollectData *data);
-GstBuffer* gst_collect_pads_pop (GstCollectPads *pads, GstCollectData *data);
-
-/* get collected bytes */
-guint gst_collect_pads_available (GstCollectPads *pads);
-guint gst_collect_pads_read (GstCollectPads *pads, GstCollectData *data,
- guint8 **bytes, guint size);
-guint gst_collect_pads_flush (GstCollectPads *pads, GstCollectData *data,
- guint size);
-
-G_END_DECLS
-
-#endif /* __GST_COLLECT_PADS_H__ */
+++ /dev/null
-/* GStreamer
- * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
- * 2000,2005 Wim Taymans <wim@fluendo.com>
- *
- * gstpushsrc.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., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-/**
- * SECTION:gstpushsrc
- * @short_description: Base class for push based source elements
- * @see_also: #GstBaseSrc
- *
- * This class is mostly useful for elements that cannot do
- * random access, or at least very slowly. The source usually
- * prefers to push out a fixed size buffer.
- *
- * Classes extending this base class will usually be scheduled
- * in a push based mode. It the peer accepts to operate without
- * offsets and withing the limits of the allowed block size, this
- * class can operate in getrange based mode automatically.
- *
- * The subclass should extend the methods from the baseclass in
- * addition to the create method.
- *
- * Seeking, flushing, scheduling and sync is all handled by this
- * base class.
- */
-
-#include <stdlib.h>
-#include <string.h>
-
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#include "gstpushsrc.h"
-#include "gsttypefindhelper.h"
-#include <gst/gstmarshal.h>
-
-GST_DEBUG_CATEGORY_STATIC (gst_push_src_debug);
-#define GST_CAT_DEFAULT gst_push_src_debug
-
-#define _do_init(type) \
- GST_DEBUG_CATEGORY_INIT (gst_push_src_debug, "pushsrc", 0, \
- "pushsrc element");
-
-GST_BOILERPLATE_FULL (GstPushSrc, gst_push_src, GstBaseSrc, GST_TYPE_BASE_SRC,
- _do_init);
-
-static GstFlowReturn gst_push_src_create (GstBaseSrc * bsrc, guint64 offset,
- guint length, GstBuffer ** ret);
-
-static void
-gst_push_src_base_init (gpointer g_class)
-{
- /* nop */
-}
-
-static void
-gst_push_src_class_init (GstPushSrcClass * klass)
-{
- GstBaseSrcClass *gstbasesrc_class = (GstBaseSrcClass *) klass;
-
- gstbasesrc_class->create = GST_DEBUG_FUNCPTR (gst_push_src_create);
-}
-
-static void
-gst_push_src_init (GstPushSrc * pushsrc, GstPushSrcClass * klass)
-{
- /* nop */
-}
-
-static GstFlowReturn
-gst_push_src_create (GstBaseSrc * bsrc, guint64 offset, guint length,
- GstBuffer ** ret)
-{
- GstFlowReturn fret;
- GstPushSrc *src;
- GstPushSrcClass *pclass;
-
- src = GST_PUSH_SRC (bsrc);
- pclass = GST_PUSH_SRC_GET_CLASS (src);
- if (pclass->create)
- fret = pclass->create (src, ret);
- else
- fret = GST_FLOW_ERROR;
-
- return fret;
-}
+++ /dev/null
-/* GStreamer
- * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
- * 2000 Wim Taymans <wtay@chello.be>
- * 2005 Wim Taymans <wim@fluendo.com>
- *
- * gstpushsrc.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., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#ifndef __GST_PUSH_SRC_H__
-#define __GST_PUSH_SRC_H__
-
-#include <gst/gst.h>
-#include <gst/base/gstbasesrc.h>
-
-G_BEGIN_DECLS
-
-#define GST_TYPE_PUSH_SRC (gst_push_src_get_type())
-#define GST_PUSH_SRC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_PUSH_SRC,GstPushSrc))
-#define GST_PUSH_SRC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_PUSH_SRC,GstPushSrcClass))
-#define GST_PUSH_SRC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_PUSH_SRC, GstPushSrcClass))
-#define GST_IS_PUSH_SRC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_PUSH_SRC))
-#define GST_IS_PUSH_SRC_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_PUSH_SRC))
-
-typedef struct _GstPushSrc GstPushSrc;
-typedef struct _GstPushSrcClass GstPushSrcClass;
-
-/**
- * GstPushSrc:
- *
- * The opaque #GstPushSrc data structure.
- */
-struct _GstPushSrc {
- GstBaseSrc parent;
-
- /*< private >*/
- gpointer _gst_reserved[GST_PADDING];
-};
-
-struct _GstPushSrcClass {
- GstBaseSrcClass parent_class;
-
- /* ask the subclass to create a buffer */
- GstFlowReturn (*create) (GstPushSrc *src, GstBuffer **buf);
-
- /*< private >*/
- gpointer _gst_reserved[GST_PADDING];
-};
-
-GType gst_push_src_get_type(void);
-
-G_END_DECLS
-
-#endif /* __GST_PUSH_SRC_H__ */
+++ /dev/null
-/* GStreamer
- * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
- * 2000,2005 Wim Taymans <wim@fluendo.com>
- *
- * gsttypefindhelper.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., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#include <stdlib.h>
-#include <string.h>
-
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#include "gsttypefindhelper.h"
-
-/**
- * typefind code here
- */
-typedef struct
-{
- GstPad *src;
- guint best_probability;
- GstCaps *caps;
- guint64 size;
- GSList *buffers;
- GstTypeFindFactory *factory;
-}
-GstTypeFindHelper;
-
-static guint8 *
-helper_find_peek (gpointer data, gint64 offset, guint size)
-{
- GstTypeFindHelper *find;
- GstBuffer *buffer;
- GstPad *src;
- GstFlowReturn ret;
-
- find = (GstTypeFindHelper *) data;
- src = find->src;
-
- GST_LOG_OBJECT (src, "'%s' called peek (%" G_GINT64_FORMAT ", %u)",
- GST_PLUGIN_FEATURE_NAME (find->factory), offset, size);
-
- if (size == 0)
- return NULL;
-
- if (offset < 0) {
- if (find->size == -1 || find->size < -offset)
- return NULL;
-
- offset += find->size;
- }
-
- /* see if we have a matching buffer already in our list */
- if (size > 0) {
- GSList *walk;
-
- for (walk = find->buffers; walk; walk = walk->next) {
- GstBuffer *buf = GST_BUFFER_CAST (walk->data);
- guint64 buf_offset = GST_BUFFER_OFFSET (buf);
- guint buf_size = GST_BUFFER_SIZE (buf);
-
- if (buf_offset <= offset && (offset + size) < (buf_offset + buf_size))
- return GST_BUFFER_DATA (buf) + (offset - buf_offset);
- }
- }
-
- buffer = NULL;
- ret = GST_PAD_GETRANGEFUNC (src) (src, offset, size, &buffer);
-
- if (ret != GST_FLOW_OK)
- goto error;
-
- /* getrange might silently return shortened buffers at the end of a file,
- * we must, however, always return either the full requested data or NULL */
- if (GST_BUFFER_OFFSET (buffer) != offset || GST_BUFFER_SIZE (buffer) < size) {
- GST_DEBUG ("droping short buffer: %" G_GUINT64_FORMAT "-%" G_GUINT64_FORMAT
- " instead of %" G_GUINT64_FORMAT "-%" G_GUINT64_FORMAT,
- GST_BUFFER_OFFSET (buffer), GST_BUFFER_OFFSET (buffer) +
- GST_BUFFER_SIZE (buffer) - 1, offset, offset + size - 1);
- gst_buffer_unref (buffer);
- return NULL;
- }
-
- find->buffers = g_slist_prepend (find->buffers, buffer);
- return GST_BUFFER_DATA (buffer);
-
-error:
- {
- return NULL;
- }
-}
-
-static void
-helper_find_suggest (gpointer data, guint probability, const GstCaps * caps)
-{
- GstTypeFindHelper *find = (GstTypeFindHelper *) data;
-
- GST_LOG_OBJECT (find->src,
- "'%s' called called suggest (%u, %" GST_PTR_FORMAT ")",
- GST_PLUGIN_FEATURE_NAME (find->factory), probability, caps);
-
- if (probability > find->best_probability) {
- GstCaps *copy = gst_caps_copy (caps);
-
- gst_caps_replace (&find->caps, copy);
- gst_caps_unref (copy);
- find->best_probability = probability;
- }
-}
-
-/**
- * gst_type_find_helper:
- * @src: A source #GstPad
- * @size: The length in bytes
- *
- * Tries to find what type of data is flowing from the given source #GstPad.
- *
- * Returns: The #GstCaps corresponding to the data stream.
- * Returns #NULL if no #GstCaps matches the data stream.
- */
-
-GstCaps *
-gst_type_find_helper (GstPad * src, guint64 size)
-{
- GstTypeFind gst_find;
- GstTypeFindHelper find;
- GSList *l;
- GList *walk, *type_list = NULL;
- GstCaps *result = NULL;
-
- g_return_val_if_fail (src != NULL, NULL);
- g_return_val_if_fail (GST_PAD_GETRANGEFUNC (src) != NULL, NULL);
-
- walk = type_list = gst_type_find_factory_get_list ();
-
- find.src = src;
- find.best_probability = 0;
- find.caps = NULL;
- find.size = size;
- find.buffers = NULL;
- gst_find.data = &find;
- gst_find.peek = helper_find_peek;
- gst_find.suggest = helper_find_suggest;
- gst_find.get_length = NULL;
-
- while (walk) {
- GstTypeFindFactory *factory = GST_TYPE_FIND_FACTORY (walk->data);
-
- find.factory = factory;
-
- gst_type_find_factory_call_function (factory, &gst_find);
- if (find.best_probability >= GST_TYPE_FIND_MAXIMUM)
- break;
- walk = g_list_next (walk);
- }
-
- if (find.best_probability > 0)
- result = find.caps;
-
- for (l = find.buffers; l; l = l->next)
- gst_buffer_unref (GST_BUFFER_CAST (l->data));
- g_slist_free (find.buffers);
-
- return result;
-}
+++ /dev/null
-/* GStreamer
- * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
- * 2000,2005 Wim Taymans <wim@fluendo.com>
- *
- * gsttypefindhelper.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., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#ifndef __GST_TYPEFINDHELPER_H__
-#define __GST_TYPEFINDHELPER_H__
-
-#include <gst/gst.h>
-
-G_BEGIN_DECLS
-
-GstCaps * gst_type_find_helper (GstPad *src, guint64 size);
-
-G_END_DECLS
-
-#endif /* __GST_TYPEFINDHELPER_H__ */
+++ /dev/null
-lib_LTLIBRARIES = libgstcheck-@GST_MAJORMINOR@.la
-
-libgstcheck_@GST_MAJORMINOR@_la_DEPENDENCIES = \
- ../libgstreamer-@GST_MAJORMINOR@.la
-libgstcheck_@GST_MAJORMINOR@_la_SOURCES = \
- gstcheck.c
-
-libgstcheck_@GST_MAJORMINOR@_la_CFLAGS = $(GST_OBJ_CFLAGS) $(CHECK_CFLAGS)
-libgstcheck_@GST_MAJORMINOR@_la_LIBADD = $(GST_OBJ_LIBS) $(CHECK_LIBS) \
- ../libgstreamer-@GST_MAJORMINOR@.la
-libgstcheck_@GST_MAJORMINOR@_la_LDFLAGS = \
-libgstbase_@GST_MAJORMINOR@_la_LDFLAGS = $(GST_LIB_LDFLAGS) $(GST_ALL_LDFLAGS) $(GST_LT_LDFLAGS)
-
-libgstcheck_@GST_MAJORMINOR@includedir = \
- $(includedir)/gstreamer-@GST_MAJORMINOR@/gst/check
-
-libgstcheck_@GST_MAJORMINOR@include_HEADERS = \
- gstcheck.h
+++ /dev/null
-/* GStreamer
- *
- * Common code for GStreamer unittests
- *
- * Copyright (C) <2004> Thomas Vander Stichele <thomas at apestaart dot org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-/**
- * SECTION:gstcheck
- * @short_description: Common code for GStreamer unit tests
- *
- * These macros and functions are for internal use of the unit tests found
- * inside the 'check' directories of various GStreamer packages.
- */
-
-#include "gstcheck.h"
-
-GST_DEBUG_CATEGORY (check_debug);
-
-/* logging function for tests
- * a test uses g_message() to log a debug line
- * a gst unit test can be run with GST_TEST_DEBUG env var set to see the
- * messages
- */
-
-gboolean _gst_check_threads_running = FALSE;
-GList *thread_list = NULL;
-GMutex *mutex;
-GCond *start_cond; /* used to notify main thread of thread startups */
-GCond *sync_cond; /* used to synchronize all threads and main thread */
-
-gboolean _gst_check_debug = FALSE;
-gboolean _gst_check_raised_critical = FALSE;
-gboolean _gst_check_raised_warning = FALSE;
-gboolean _gst_check_expecting_log = FALSE;
-
-void gst_check_log_message_func
- (const gchar * log_domain, GLogLevelFlags log_level,
- const gchar * message, gpointer user_data)
-{
- if (_gst_check_debug) {
- g_print ("%s", message);
- }
-}
-
-void gst_check_log_critical_func
- (const gchar * log_domain, GLogLevelFlags log_level,
- const gchar * message, gpointer user_data)
-{
- if (!_gst_check_expecting_log) {
- g_print ("\n\nUnexpected critical/warning: %s\n", message);
- fail ("Unexpected critical/warning: %s", message);
- }
-
- if (_gst_check_debug) {
- g_print ("\nExpected critical/warning: %s\n", message);
- }
-
- if (log_level & G_LOG_LEVEL_CRITICAL)
- _gst_check_raised_critical = TRUE;
- if (log_level & G_LOG_LEVEL_WARNING)
- _gst_check_raised_warning = TRUE;
-}
-
-/* initialize GStreamer testing */
-void
-gst_check_init (int *argc, char **argv[])
-{
- gst_init (argc, argv);
-
- GST_DEBUG_CATEGORY_INIT (check_debug, "check", 0, "check regression tests");
-
- if (g_getenv ("GST_TEST_DEBUG"))
- _gst_check_debug = TRUE;
-
- g_log_set_handler (NULL, G_LOG_LEVEL_MESSAGE, gst_check_log_message_func,
- NULL);
- g_log_set_handler (NULL, G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING,
- gst_check_log_critical_func, NULL);
- g_log_set_handler ("GStreamer", G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING,
- gst_check_log_critical_func, NULL);
- g_log_set_handler ("GLib-GObject", G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING,
- gst_check_log_critical_func, NULL);
-}
-
-/* message checking */
-void
-gst_check_message_error (GstMessage * message, GstMessageType type,
- GQuark domain, gint code)
-{
- GError *error;
- gchar *debug;
-
- fail_unless_equals_int (GST_MESSAGE_TYPE (message), type);
- gst_message_parse_error (message, &error, &debug);
- fail_unless_equals_int (error->domain, domain);
- fail_unless_equals_int (error->code, code);
- g_error_free (error);
- g_free (debug);
-}
-
-/* helper functions */
-GstFlowReturn
-gst_check_chain_func (GstPad * pad, GstBuffer * buffer)
-{
- GST_DEBUG ("chain_func: received buffer %p", buffer);
- buffers = g_list_append (buffers, buffer);
-
- return GST_FLOW_OK;
-}
-
-/* setup an element for a filter test with mysrcpad and mysinkpad */
-GstElement *
-gst_check_setup_element (const gchar * factory)
-{
- GstElement *element;
-
- GST_DEBUG ("setup_element");
-
- element = gst_element_factory_make (factory, factory);
- fail_if (element == NULL, "Could not create a %s", factory);
- ASSERT_OBJECT_REFCOUNT (element, factory, 1);
- return element;
-}
-
-void
-gst_check_teardown_element (GstElement * element)
-{
- GST_DEBUG ("teardown_element");
-
- fail_unless (gst_element_set_state (element, GST_STATE_NULL) ==
- GST_STATE_CHANGE_SUCCESS, "could not set to null");
- ASSERT_OBJECT_REFCOUNT (element, "element", 1);
- gst_object_unref (element);
-}
-
-/* FIXME: set_caps isn't that useful
- */
-GstPad *
-gst_check_setup_src_pad (GstElement * element,
- GstStaticPadTemplate * template, GstCaps * caps)
-{
- GstPad *srcpad, *sinkpad;
-
- GST_DEBUG_OBJECT (element, "setting up sending pad");
- /* sending pad */
- srcpad = gst_pad_new_from_static_template (template, "src");
- fail_if (srcpad == NULL, "Could not create a srcpad");
- ASSERT_OBJECT_REFCOUNT (srcpad, "srcpad", 1);
-
- sinkpad = gst_element_get_pad (element, "sink");
- fail_if (sinkpad == NULL, "Could not get sink pad from %s",
- GST_ELEMENT_NAME (element));
- ASSERT_OBJECT_REFCOUNT (sinkpad, "sinkpad", 2);
- if (caps)
- fail_unless (gst_pad_set_caps (srcpad, caps));
- fail_unless (gst_pad_link (srcpad, sinkpad) == GST_PAD_LINK_OK,
- "Could not link source and %s sink pads", GST_ELEMENT_NAME (element));
- gst_object_unref (sinkpad); /* because we got it higher up */
- ASSERT_OBJECT_REFCOUNT (sinkpad, "sinkpad", 1);
-
- return srcpad;
-}
-
-void
-gst_check_teardown_src_pad (GstElement * element)
-{
- GstPad *srcpad, *sinkpad;
-
- /* clean up floating src pad */
- sinkpad = gst_element_get_pad (element, "sink");
- ASSERT_OBJECT_REFCOUNT (sinkpad, "sinkpad", 2);
- srcpad = gst_pad_get_peer (sinkpad);
-
- gst_pad_unlink (srcpad, sinkpad);
-
- /* pad refs held by both creator and this function (through _get) */
- ASSERT_OBJECT_REFCOUNT (sinkpad, "sinkpad", 2);
- gst_object_unref (sinkpad);
- /* one more ref is held by element itself */
-
- /* pad refs held by both creator and this function (through _get_peer) */
- ASSERT_OBJECT_REFCOUNT (srcpad, "srcpad", 2);
- gst_object_unref (srcpad);
- gst_object_unref (srcpad);
-}
-
-/* FIXME: set_caps isn't that useful; might want to check if fixed,
- * then use set_use_fixed or somesuch */
-GstPad *
-gst_check_setup_sink_pad (GstElement * element, GstStaticPadTemplate * template,
- GstCaps * caps)
-{
- GstPad *srcpad, *sinkpad;
-
- GST_DEBUG_OBJECT (element, "setting up receiving pad");
- /* receiving pad */
- sinkpad = gst_pad_new_from_static_template (template, "sink");
- fail_if (sinkpad == NULL, "Could not create a sinkpad");
-
- srcpad = gst_element_get_pad (element, "src");
- fail_if (srcpad == NULL, "Could not get source pad from %s",
- GST_ELEMENT_NAME (element));
- if (caps)
- fail_unless (gst_pad_set_caps (sinkpad, caps));
- gst_pad_set_chain_function (sinkpad, gst_check_chain_func);
-
- fail_unless (gst_pad_link (srcpad, sinkpad) == GST_PAD_LINK_OK,
- "Could not link %s source and sink pads", GST_ELEMENT_NAME (element));
- gst_object_unref (srcpad); /* because we got it higher up */
- ASSERT_OBJECT_REFCOUNT (srcpad, "srcpad", 1);
-
- return sinkpad;
-}
-
-void
-gst_check_teardown_sink_pad (GstElement * element)
-{
- GstPad *srcpad, *sinkpad;
-
- /* clean up floating sink pad */
- srcpad = gst_element_get_pad (element, "src");
- sinkpad = gst_pad_get_peer (srcpad);
- gst_pad_unlink (srcpad, sinkpad);
-
- /* pad refs held by both creator and this function (through _get_pad) */
- ASSERT_OBJECT_REFCOUNT (srcpad, "srcpad", 2);
- gst_object_unref (srcpad);
- /* one more ref is held by element itself */
-
- /* pad refs held by both creator and this function (through _get_peer) */
- ASSERT_OBJECT_REFCOUNT (sinkpad, "sinkpad", 2);
- gst_object_unref (sinkpad);
- gst_object_unref (sinkpad);
-}
+++ /dev/null
-/* GStreamer
- *
- * Common code for GStreamer unittests
- *
- * Copyright (C) <2004> Thomas Vander Stichele <thomas at apestaart dot org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#ifndef __GST_CHECK_H__
-#define __GST_CHECK_H__
-
-#include <signal.h>
-#include <string.h>
-#include <stdlib.h>
-
-#include <check.h>
-
-#include <gst/gst.h>
-
-GST_DEBUG_CATEGORY_EXTERN (check_debug);
-#define GST_CAT_DEFAULT check_debug
-
-/* logging function for tests
- * a test uses g_message() to log a debug line
- * a gst unit test can be run with GST_TEST_DEBUG env var set to see the
- * messages
- */
-extern gboolean _gst_check_threads_running;
-extern gboolean _gst_check_raised_critical;
-extern gboolean _gst_check_raised_warning;
-extern gboolean _gst_check_expecting_log;
-
-/* global variables used in test methods */
-GList * buffers;
-
-void gst_check_init (int *argc, char **argv[]);
-
-GstFlowReturn gst_check_chain_func (GstPad *pad, GstBuffer *buffer);
-
-void gst_check_message_error (GstMessage *message, GstMessageType type, GQuark domain, gint code);
-
-GstElement * gst_check_setup_element (const gchar *factory);
-void gst_check_teardown_element (GstElement *element);
-GstPad * gst_check_setup_src_pad (GstElement *element,
- GstStaticPadTemplate *template, GstCaps *caps);
-void gst_check_teardown_src_pad (GstElement *element);
-GstPad * gst_check_setup_sink_pad (GstElement *element,
- GstStaticPadTemplate *template, GstCaps *caps);
-void gst_check_teardown_sink_pad (GstElement *element);
-
-
-#define fail_unless_message_error(msg, domain, code) \
-gst_check_message_error (msg, GST_MESSAGE_ERROR, \
- GST_ ## domain ## _ERROR, GST_ ## domain ## _ERROR_ ## code)
-
-/***
- * wrappers for START_TEST and END_TEST
- */
-#define GST_START_TEST(__testname) \
-static void __testname (void)\
-{\
- GST_DEBUG ("test start"); \
- tcase_fn_start (""# __testname, __FILE__, __LINE__);
-
-#define GST_END_TEST END_TEST
-
-/* additional fail macros */
-#define fail_unless_equals_int(a, b) \
-G_STMT_START { \
- int first = a; \
- int second = b; \
- fail_unless(first == second, \
- "'" #a "' (%d) is not equal to '" #b"' (%d)", first, second); \
-} G_STMT_END;
-
-#define fail_unless_equals_uint64(a, b) \
-G_STMT_START { \
- guint64 first = a; \
- guint64 second = b; \
- fail_unless(first == second, \
- "'" #a "' (%" G_GUINT64_FORMAT ") is not equal to '" #b"' (%" \
- G_GUINT64_FORMAT ")", first, second); \
-} G_STMT_END;
-
-#define fail_unless_equals_string(a, b) \
-G_STMT_START { \
- gchar * first = a; \
- gchar * second = b; \
- fail_unless(strcmp (first, second) == 0, \
- "'" #a "' (%s) is not equal to '" #b"' (%s)", first, second); \
-} G_STMT_END;
-
-
-/***
- * thread test macros and variables
- */
-extern GList *thread_list;
-extern GMutex *mutex;
-extern GCond *start_cond; /* used to notify main thread of thread startups */
-extern GCond *sync_cond; /* used to synchronize all threads and main thread */
-
-#define MAIN_START_THREADS(count, function, data) \
-MAIN_INIT(); \
-MAIN_START_THREAD_FUNCTIONS(count, function, data); \
-MAIN_SYNCHRONIZE();
-
-#define MAIN_INIT() \
-G_STMT_START { \
- _gst_check_threads_running = TRUE; \
- \
- mutex = g_mutex_new (); \
- start_cond = g_cond_new (); \
- sync_cond = g_cond_new (); \
-} G_STMT_END;
-
-#define MAIN_START_THREAD_FUNCTIONS(count, function, data) \
-G_STMT_START { \
- int i; \
- for (i = 0; i < count; ++i) { \
- MAIN_START_THREAD_FUNCTION (i, function, data); \
- } \
-} G_STMT_END;
-
-#define MAIN_START_THREAD_FUNCTION(i, function, data) \
-G_STMT_START { \
- GThread *thread = NULL; \
- GST_DEBUG ("MAIN: creating thread %d", i); \
- g_mutex_lock (mutex); \
- thread = g_thread_create ((GThreadFunc) function, data, \
- TRUE, NULL); \
- /* wait for thread to signal us that it's ready */ \
- GST_DEBUG ("MAIN: waiting for thread %d", i); \
- g_cond_wait (start_cond, mutex); \
- g_mutex_unlock (mutex); \
- \
- thread_list = g_list_append (thread_list, thread); \
-} G_STMT_END;
-
-
-#define MAIN_SYNCHRONIZE() \
-G_STMT_START { \
- GST_DEBUG ("MAIN: synchronizing"); \
- g_cond_broadcast (sync_cond); \
- GST_DEBUG ("MAIN: synchronized"); \
-} G_STMT_END;
-
-#define MAIN_STOP_THREADS() \
-G_STMT_START { \
- _gst_check_threads_running = FALSE; \
- \
- /* join all threads */ \
- GST_DEBUG ("MAIN: joining"); \
- g_list_foreach (thread_list, (GFunc) g_thread_join, NULL); \
- GST_DEBUG ("MAIN: joined"); \
-} G_STMT_END;
-
-#define THREAD_START() \
-THREAD_STARTED(); \
-THREAD_SYNCHRONIZE();
-
-#define THREAD_STARTED() \
-G_STMT_START { \
- /* signal main thread that we started */ \
- GST_DEBUG ("THREAD %p: started", g_thread_self ()); \
- g_mutex_lock (mutex); \
- g_cond_signal (start_cond); \
-} G_STMT_END;
-
-#define THREAD_SYNCHRONIZE() \
-G_STMT_START { \
- /* synchronize everyone */ \
- GST_DEBUG ("THREAD %p: syncing", g_thread_self ()); \
- g_cond_wait (sync_cond, mutex); \
- GST_DEBUG ("THREAD %p: synced", g_thread_self ()); \
- g_mutex_unlock (mutex); \
-} G_STMT_END;
-
-#define THREAD_SWITCH() \
-G_STMT_START { \
- /* a minimal sleep is a context switch */ \
- g_usleep (1); \
-} G_STMT_END;
-
-#define THREAD_TEST_RUNNING() (_gst_check_threads_running == TRUE)
-
-/* additional assertions */
-#define ASSERT_CRITICAL(code) \
-G_STMT_START { \
- _gst_check_expecting_log = TRUE; \
- _gst_check_raised_critical = FALSE; \
- code; \
- _fail_unless (_gst_check_raised_critical, __FILE__, __LINE__, \
- "Expected g_critical, got nothing"); \
- _gst_check_expecting_log = FALSE; \
-} G_STMT_END
-
-#define ASSERT_WARNING(code) \
-G_STMT_START { \
- _gst_check_expecting_log = TRUE; \
- _gst_check_raised_warning = FALSE; \
- code; \
- _fail_unless (_gst_check_raised_warning, __FILE__, __LINE__, \
- "Expected g_warning, got nothing"); \
- _gst_check_expecting_log = FALSE; \
-} G_STMT_END
-
-
-#define ASSERT_OBJECT_REFCOUNT(object, name, value) \
-G_STMT_START { \
- int rc; \
- rc = GST_OBJECT_REFCOUNT_VALUE (object); \
- fail_unless (rc == value, \
- "%s (%p) refcount is %d instead of %d", \
- name, object, rc, value); \
-} G_STMT_END
-
-#define ASSERT_OBJECT_REFCOUNT_BETWEEN(object, name, lower, upper) \
-G_STMT_START { \
- int rc = GST_OBJECT_REFCOUNT_VALUE (object); \
- int lo = lower; \
- int hi = upper; \
- \
- fail_unless (rc >= lo, \
- "%s (%p) refcount %d is smaller than %d", \
- name, object, rc, lo); \
- fail_unless (rc <= hi, \
- "%s (%p) refcount %d is bigger than %d", \
- name, object, rc, hi); \
-} G_STMT_END
-
-
-#define ASSERT_CAPS_REFCOUNT(caps, name, value) \
- ASSERT_MINI_OBJECT_REFCOUNT(caps, name, value)
-
-#define ASSERT_BUFFER_REFCOUNT(buffer, name, value) \
- ASSERT_MINI_OBJECT_REFCOUNT(buffer, name, value)
-
-#define ASSERT_MINI_OBJECT_REFCOUNT(caps, name, value) \
-G_STMT_START { \
- int rc; \
- rc = GST_MINI_OBJECT_REFCOUNT_VALUE (caps); \
- fail_unless (rc == value, \
- name " refcount is %d instead of %d", rc, value);\
-} G_STMT_END
-
-
-#endif /* __GST_CHECK_H__ */
-
+++ /dev/null
-lib_LTLIBRARIES = libgstnet-@GST_MAJORMINOR@.la
-
-libgstnet_@GST_MAJORMINOR@_includedir = $(includedir)/gstreamer-@GST_MAJORMINOR@/gst/net
-libgstnet_@GST_MAJORMINOR@_include_HEADERS = \
- gstnet.h \
- gstnetclientclock.h \
- gstnettimepacket.h \
- gstnettimeprovider.h
-
-libgstnet_@GST_MAJORMINOR@_la_SOURCES = \
- gstnetclientclock.c \
- gstnettimepacket.c \
- gstnettimeprovider.c
-
-libgstnet_@GST_MAJORMINOR@_la_CFLAGS = $(GST_OBJ_CFLAGS)
-libgstnet_@GST_MAJORMINOR@_la_LIBADD = $(GST_OBJ_LIBS)
-libgstnet_@GST_MAJORMINOR@_la_LDFLAGS = $(GST_LIB_LDFLAGS) $(GST_ALL_LDFLAGS) $(GST_LT_LDFLAGS)
-
+++ /dev/null
-/* GStreamer
- * Copyright (C) 2005 Andy Wingo <wingo@pobox.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-
-#ifndef __GST_NET_H__
-#define __GST_NET_H__
-
-
-#include <gst/net/gstnetclientclock.h>
-#include <gst/net/gstnettimepacket.h>
-#include <gst/net/gstnettimeprovider.h>
-
-
-#endif /* __GST_NET_H__ */
+++ /dev/null
-/* GStreamer
- * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
- * 2005 Wim Taymans <wim@fluendo.com>
- * 2005 Andy Wingo <wingo@pobox.com>
- *
- * gstnetclientclock.h: clock that synchronizes itself to a time provider over
- * the network
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-/**
- * SECTION:gstnetclientclock
- * @short_description: Special clock that synchronizes to a remote time
- * provider.
- * @see_also: #GstClock, #GstNetTimeProvider, #GstPipeline
- *
- * This object implements a custom #GstClock that synchronizes its time
- * to a remote time provider such as #GstNetTimeProvider.
- *
- * A new clock is created with gst_net_client_clock_new() which takes the
- * address and port of the remote time provider along with a name and
- * an initial time.
- *
- * This clock will poll the time provider and will update its calibration
- * parameters based on the local and remote observations.
- *
- * Various parameters of the clock can be configured with the parent #GstClock
- * "timeout", "window-size" and "window-threshold" object properties.
- *
- * A #GstNetClientClock is typically set on a #GstPipeline with
- * gst_pipeline_use_clock().
- *
- * Last reviewed on 2005-11-23 (0.9.5)
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <unistd.h>
-
-#include "gstnettimepacket.h"
-#include "gstnetclientclock.h"
-
-GST_DEBUG_CATEGORY (ncc_debug);
-#define GST_CAT_DEFAULT (ncc_debug)
-
-/* #define DEBUGGING_ENABLED */
-
-#ifdef DEBUGGING_ENABLED
-#define DEBUG(x, args...) g_print (x "\n", ##args)
-#else
-#define DEBUG(x, args...) /* nop */
-#endif
-
-/* the select call is also performed on the control sockets, that way
- * we can send special commands to unblock or restart the select call */
-#define CONTROL_RESTART 'R' /* restart the select call */
-#define CONTROL_STOP 'S' /* stop the select call */
-#define CONTROL_SOCKETS(self) self->control_sock
-#define WRITE_SOCKET(self) self->control_sock[1]
-#define READ_SOCKET(self) self->control_sock[0]
-
-#define SEND_COMMAND(self, command) \
-G_STMT_START { \
- unsigned char c; c = command; \
- write (WRITE_SOCKET(self), &c, 1); \
-} G_STMT_END
-
-#define READ_COMMAND(self, command, res) \
-G_STMT_START { \
- res = read(READ_SOCKET(self), &command, 1); \
-} G_STMT_END
-
-#define DEFAULT_ADDRESS "127.0.0.1"
-#define DEFAULT_PORT 5637
-#define DEFAULT_TIMEOUT GST_SECOND
-
-enum
-{
- PROP_0,
- PROP_ADDRESS,
- PROP_PORT,
-};
-
-#define _do_init(type) \
- GST_DEBUG_CATEGORY_INIT (ncc_debug, "netclock", 0, "Network client clock");
-
-GST_BOILERPLATE_FULL (GstNetClientClock, gst_net_client_clock,
- GstSystemClock, GST_TYPE_SYSTEM_CLOCK, _do_init);
-
-static void gst_net_client_clock_finalize (GObject * object);
-static void gst_net_client_clock_set_property (GObject * object, guint prop_id,
- const GValue * value, GParamSpec * pspec);
-static void gst_net_client_clock_get_property (GObject * object, guint prop_id,
- GValue * value, GParamSpec * pspec);
-
-static void gst_net_client_clock_stop (GstNetClientClock * self);
-
-static void
-gst_net_client_clock_base_init (gpointer g_class)
-{
- /* nop */
-}
-
-static void
-gst_net_client_clock_class_init (GstNetClientClockClass * klass)
-{
- GObjectClass *gobject_class;
-
- gobject_class = (GObjectClass *) klass;
-
- gobject_class->finalize = gst_net_client_clock_finalize;
- gobject_class->get_property = gst_net_client_clock_get_property;
- gobject_class->set_property = gst_net_client_clock_set_property;
-
- g_object_class_install_property (gobject_class, PROP_ADDRESS,
- g_param_spec_string ("address", "address",
- "The address of the machine providing a time server, "
- "as a dotted quad (x.x.x.x)", DEFAULT_ADDRESS, G_PARAM_READWRITE));
- g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PORT,
- g_param_spec_int ("port", "port",
- "The port on which the remote server is listening", 0, G_MAXUINT16,
- DEFAULT_PORT, G_PARAM_READWRITE));
-}
-
-static void
-gst_net_client_clock_init (GstNetClientClock * self,
- GstNetClientClockClass * g_class)
-{
- GstClock *clock = GST_CLOCK_CAST (self);
-
- self->port = DEFAULT_PORT;
- self->address = g_strdup (DEFAULT_ADDRESS);
-
- clock->timeout = DEFAULT_TIMEOUT;
-
- self->sock = -1;
- self->thread = NULL;
-
- self->servaddr = NULL;
-
- READ_SOCKET (self) = -1;
- WRITE_SOCKET (self) = -1;
-}
-
-static void
-gst_net_client_clock_finalize (GObject * object)
-{
- GstNetClientClock *self = GST_NET_CLIENT_CLOCK (object);
-
- if (self->thread) {
- gst_net_client_clock_stop (self);
- g_assert (self->thread == NULL);
- }
-
- if (READ_SOCKET (self) != -1) {
- close (READ_SOCKET (self));
- close (WRITE_SOCKET (self));
- READ_SOCKET (self) = -1;
- WRITE_SOCKET (self) = -1;
- }
-
- g_free (self->address);
- self->address = NULL;
-
- g_free (self->servaddr);
- self->servaddr = NULL;
-
- G_OBJECT_CLASS (parent_class)->finalize (object);
-}
-
-static void
-gst_net_client_clock_set_property (GObject * object, guint prop_id,
- const GValue * value, GParamSpec * pspec)
-{
- GstNetClientClock *self = GST_NET_CLIENT_CLOCK (object);
-
- switch (prop_id) {
- case PROP_ADDRESS:
- g_free (self->address);
- if (g_value_get_string (value) == NULL)
- self->address = g_strdup (DEFAULT_ADDRESS);
- else
- self->address = g_strdup (g_value_get_string (value));
- break;
- case PROP_PORT:
- self->port = g_value_get_int (value);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-gst_net_client_clock_get_property (GObject * object, guint prop_id,
- GValue * value, GParamSpec * pspec)
-{
- GstNetClientClock *self = GST_NET_CLIENT_CLOCK (object);
-
- switch (prop_id) {
- case PROP_ADDRESS:
- g_value_set_string (value, self->address);
- break;
- case PROP_PORT:
- g_value_set_int (value, self->port);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-gst_net_client_clock_observe_times (GstNetClientClock * self,
- GstClockTime local_1, GstClockTime remote, GstClockTime local_2)
-{
- GstClockTime local_avg;
- gdouble r_squared;
- GstClock *clock;
-
- if (local_2 < local_1)
- goto bogus_observation;
-
- local_avg = (local_2 + local_1) / 2;
-
- clock = GST_CLOCK_CAST (self);
-
- gst_clock_add_observation (GST_CLOCK (self), local_avg, remote, &r_squared);
-
- GST_CLOCK_SLAVE_LOCK (self);
- if (clock->filling) {
- self->current_timeout = 0;
- } else {
- /* geto formula */
- self->current_timeout =
- (1e-3 / (1 - MIN (r_squared, 0.99999))) * GST_SECOND;
- self->current_timeout = MIN (self->current_timeout, clock->timeout);
- }
- GST_CLOCK_SLAVE_UNLOCK (clock);
-
- return;
-
-bogus_observation:
- {
- GST_WARNING_OBJECT (self, "time packet receive time < send time (%",
- GST_TIME_FORMAT, " < %" GST_TIME_FORMAT ")", GST_TIME_ARGS (local_1),
- GST_TIME_ARGS (local_2));
- return;
- }
-}
-
-static gint
-gst_net_client_clock_do_select (GstNetClientClock * self, fd_set * readfds)
-{
- gint max_sock;
- gint ret;
-
- while (TRUE) {
- FD_ZERO (readfds);
- FD_SET (self->sock, readfds);
- FD_SET (READ_SOCKET (self), readfds);
- max_sock = MAX (self->sock, READ_SOCKET (self));
-
- GST_LOG_OBJECT (self, "doing select");
- {
- GstClockTime diff;
- GTimeVal tv, *ptv = &tv;
-
- diff = gst_clock_get_internal_time (GST_CLOCK (self));
- GST_TIME_TO_TIMEVAL (self->current_timeout, tv);
-
- ret = select (max_sock + 1, readfds, NULL, NULL, (struct timeval *) ptv);
-
- diff = gst_clock_get_internal_time (GST_CLOCK (self)) - diff;
-
- if (diff > self->current_timeout)
- self->current_timeout = 0;
- else
- self->current_timeout -= diff;
- }
- GST_LOG_OBJECT (self, "select returned %d", ret);
-
- if (ret < 0) {
- if (errno != EAGAIN && errno != EINTR)
- goto select_error;
- else
- continue;
- } else {
- return ret;
- }
-
- g_assert_not_reached ();
-
- /* log errors and keep going */
- select_error:
- {
- GST_WARNING_OBJECT (self, "select error %d: %s (%d)", ret,
- g_strerror (errno), errno);
- continue;
- }
- }
-
- g_assert_not_reached ();
- return -1;
-}
-
-static gpointer
-gst_net_client_clock_thread (gpointer data)
-{
- GstNetClientClock *self = data;
- struct sockaddr_in tmpaddr;
- socklen_t len;
- fd_set read_fds;
- GstNetTimePacket *packet;
- gint ret;
- GstClock *clock = data;
-
- while (TRUE) {
- ret = gst_net_client_clock_do_select (self, &read_fds);
-
- if (FD_ISSET (READ_SOCKET (self), &read_fds)) {
- /* got control message */
- while (TRUE) {
- gchar command;
- int res;
-
- READ_COMMAND (self, command, res);
- if (res < 0) {
- GST_LOG_OBJECT (self, "no more commands");
- break;
- }
-
- DEBUG ("control message: '%c'", command);
- switch (command) {
- case CONTROL_STOP:
- /* break out of the select loop */
- GST_LOG_OBJECT (self, "stop");
- goto stopped;
- default:
- GST_WARNING_OBJECT (self, "unknown message: '%c'", command);
- g_warning ("netclientclock: unknown control message received");
- continue;
- }
-
- g_assert_not_reached ();
- }
-
- continue;
- } else if (ret == 0) {
- /* timed out, let's send another packet */
- DEBUG ("timed out");
-
- packet = gst_net_time_packet_new (NULL);
-
- packet->local_time = gst_clock_get_internal_time (GST_CLOCK (self));
-
- DEBUG ("sending packet, local time = %" GST_TIME_FORMAT,
- GST_TIME_ARGS (packet->local_time));
- gst_net_time_packet_send (packet, self->sock,
- (struct sockaddr *) self->servaddr, sizeof (struct sockaddr_in));
-
- g_free (packet);
-
- /* reset timeout */
- self->current_timeout = clock->timeout;
- continue;
- } else if (FD_ISSET (self->sock, &read_fds)) {
- /* got data in */
- GstClockTime new_local = gst_clock_get_internal_time (GST_CLOCK (self));
-
- len = sizeof (struct sockaddr);
- packet = gst_net_time_packet_receive (self->sock,
- (struct sockaddr *) &tmpaddr, &len);
-
- if (!packet)
- goto receive_error;
-
- DEBUG ("got packet back");
- DEBUG ("local_1 = %" GST_TIME_FORMAT, GST_TIME_ARGS (packet->local_time));
- DEBUG ("remote = %" GST_TIME_FORMAT, GST_TIME_ARGS (packet->remote_time));
- DEBUG ("local_2 = %" GST_TIME_FORMAT, GST_TIME_ARGS (new_local));
-
- /* observe_times will reset the timeout */
- gst_net_client_clock_observe_times (self, packet->local_time,
- packet->remote_time, new_local);
-
- g_free (packet);
- continue;
- } else {
- GST_WARNING_OBJECT (self, "unhandled select return state?");
- continue;
- }
-
- g_assert_not_reached ();
-
- stopped:
- {
- GST_DEBUG_OBJECT (self, "shutting down");
- /* socket gets closed in _stop() */
- return NULL;
- }
- receive_error:
- {
- GST_WARNING_OBJECT (self, "receive error");
- continue;
- }
-
- g_assert_not_reached ();
-
- }
-
- g_assert_not_reached ();
-
- return NULL;
-}
-
-static gboolean
-gst_net_client_clock_start (GstNetClientClock * self)
-{
- struct sockaddr_in servaddr, myaddr;
- socklen_t len;
- gint ret;
- GError *error;
-
- g_return_val_if_fail (self->address != NULL, FALSE);
- g_return_val_if_fail (self->servaddr == NULL, FALSE);
-
- if ((ret = socket (AF_INET, SOCK_DGRAM, 0)) < 0)
- goto no_socket;
-
- self->sock = ret;
-
- len = sizeof (myaddr);
- ret = getsockname (self->sock, (struct sockaddr *) &myaddr, &len);
- if (ret < 0)
- goto getsockname_error;
-
- GST_DEBUG_OBJECT (self, "socket opened on UDP port %hd",
- ntohs (servaddr.sin_port));
-
- memset (&servaddr, 0, sizeof (servaddr));
- servaddr.sin_family = AF_INET; /* host byte order */
- servaddr.sin_port = htons (self->port); /* short, network byte order */
- if (!inet_aton (self->address, &servaddr.sin_addr))
- goto bad_address;
-
- self->servaddr = g_malloc (sizeof (struct sockaddr_in));
- memcpy (self->servaddr, &servaddr, sizeof (servaddr));
-
- GST_DEBUG_OBJECT (self, "will communicate with %s:%d", self->address,
- self->port);
-
- self->thread = g_thread_create (gst_net_client_clock_thread, self, TRUE,
- &error);
- if (!self->thread)
- goto no_thread;
-
- return TRUE;
-
- /* ERRORS */
-no_socket:
- {
- GST_ERROR_OBJECT (self, "socket failed %d: %s (%d)", ret,
- g_strerror (errno), errno);
- return FALSE;
- }
-getsockname_error:
- {
- GST_ERROR_OBJECT (self, "getsockname failed %d: %s (%d)", ret,
- g_strerror (errno), errno);
- close (self->sock);
- self->sock = -1;
- return FALSE;
- }
-bad_address:
- {
- GST_ERROR_OBJECT (self, "inet_aton failed %d: %s (%d)", ret,
- g_strerror (errno), errno);
- close (self->sock);
- self->sock = -1;
- return FALSE;
- }
-no_thread:
- {
- GST_ERROR_OBJECT (self, "could not create thread: %s", error->message);
- close (self->sock);
- self->sock = -1;
- g_free (self->servaddr);
- self->servaddr = NULL;
- g_error_free (error);
- return FALSE;
- }
-}
-
-static void
-gst_net_client_clock_stop (GstNetClientClock * self)
-{
- SEND_COMMAND (self, CONTROL_STOP);
- g_thread_join (self->thread);
- self->thread = NULL;
-
- if (self->sock != -1) {
- close (self->sock);
- self->sock = -1;
- }
-}
-
-/**
- * gst_net_client_clock_new:
- * @name: a name for the clock
- * @remote_address: the address of the remote clock provider
- * @remote_port: the port of the remote clock provider
- * @base_time: initial time of the clock
- *
- * Create a new #GstNetClientClock that will report the time
- * provided by the #GstNetClockProvider on @remote_address and
- * @remote_port.
- *
- * Returns: a new #GstClock that receives a time from the remote
- * clock.
- */
-GstClock *
-gst_net_client_clock_new (gchar * name, const gchar * remote_address,
- gint remote_port, GstClockTime base_time)
-{
- GstNetClientClock *ret;
- GstClockTime internal;
- gint iret;
-
- g_return_val_if_fail (remote_address != NULL, NULL);
- g_return_val_if_fail (remote_port > 0, NULL);
- g_return_val_if_fail (remote_port <= G_MAXUINT16, NULL);
- g_return_val_if_fail (base_time != GST_CLOCK_TIME_NONE, NULL);
-
- ret = g_object_new (GST_TYPE_NET_CLIENT_CLOCK, "address", remote_address,
- "port", remote_port, NULL);
-
- /* gst_clock_get_time() values are guaranteed to be increasing. because no one
- * has called get_time on this clock yet we are free to adjust to any value
- * without worrying about worrying about MAX() issues with the clock's
- * internal time.
- */
-
- /* update our internal time so get_time() give something around base_time.
- assume that the rate is 1 in the beginning. */
- internal = gst_clock_get_internal_time (GST_CLOCK (ret));
- gst_clock_set_calibration (GST_CLOCK (ret), internal, base_time, 1, 1);
-
- {
- GstClockTime now = gst_clock_get_time (GST_CLOCK (ret));
-
- if (now < base_time || now > base_time + GST_SECOND)
- g_warning ("unable to set the base time, expect sync problems!");
- }
-
- GST_DEBUG_OBJECT (ret, "creating socket pair");
- if ((iret = socketpair (PF_UNIX, SOCK_STREAM, 0, CONTROL_SOCKETS (ret))) < 0)
- goto no_socket_pair;
-
- fcntl (READ_SOCKET (ret), F_SETFL, O_NONBLOCK);
- fcntl (WRITE_SOCKET (ret), F_SETFL, O_NONBLOCK);
-
- if (!gst_net_client_clock_start (ret))
- goto failed_start;
-
- /* all systems go, cap'n */
- return (GstClock *) ret;
-
-no_socket_pair:
- {
- GST_ERROR_OBJECT (ret, "no socket pair %d: %s (%d)", iret,
- g_strerror (errno), errno);
- gst_object_unref (ret);
- return NULL;
- }
-failed_start:
- {
- /* already printed a nice error */
- gst_object_unref (ret);
- return NULL;
- }
-}
+++ /dev/null
-/* GStreamer
- * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
- * 2005 Wim Taymans <wim@fluendo.com>
- * 2005 Andy Wingo <wingo@pobox.com>
- *
- * gstnetclientclock.h: clock that synchronizes itself to a time provider over
- * the network
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-
-#ifndef __GST_NET_CLIENT_CLOCK_H__
-#define __GST_NET_CLIENT_CLOCK_H__
-
-#include <gst/gst.h>
-#include <gst/gstsystemclock.h>
-
-G_BEGIN_DECLS
-
-#include <errno.h>
-#include <string.h>
-#include <sys/types.h>
-#include <netdb.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-
-#include <fcntl.h>
-
-#define GST_TYPE_NET_CLIENT_CLOCK \
- (gst_net_client_clock_get_type())
-#define GST_NET_CLIENT_CLOCK(obj) \
- (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_NET_CLIENT_CLOCK,GstNetClientClock))
-#define GST_NET_CLIENT_CLOCK_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_NET_CLIENT_CLOCK,GstNetClientClockClass))
-#define GST_IS_NET_CLIENT_CLOCK(obj) \
- (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_NET_CLIENT_CLOCK))
-#define GST_IS_NET_CLIENT_CLOCK_CLASS(obj) \
- (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_NET_CLIENT_CLOCK))
-
-typedef struct _GstNetClientClock GstNetClientClock;
-typedef struct _GstNetClientClockClass GstNetClientClockClass;
-
-/**
- * GstNetClientClock:
- *
- * Opaque #GstNetClientClock structure.
- */
-struct _GstNetClientClock {
- GstSystemClock clock;
-
- /*< protected >*/
- gchar *address;
- gint port;
-
- /*< private >*/
- int sock;
- int control_sock[2];
-
- GstClockTime current_timeout;
-
- struct sockaddr_id *servaddr;
-
- GThread *thread;
-
- /*< private >*/
- gpointer _gst_reserved[GST_PADDING];
-};
-
-struct _GstNetClientClockClass {
- GstSystemClockClass parent_class;
-
- /*< private >*/
- gpointer _gst_reserved[GST_PADDING];
-};
-
-GType gst_net_client_clock_get_type (void);
-GstClock* gst_net_client_clock_new (gchar *name, const gchar *remote_address,
- gint remote_port, GstClockTime base_time);
-
-G_END_DECLS
-
-#endif /* __GST_NET_CLIENT_CLOCK_H__ */
+++ /dev/null
-/* GStreamer
- * Copyright (C) 2005 Andy Wingo <wingo@pobox.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-/**
- * SECTION:gstnettimepacket
- * @short_description: Helper structure to construct clock packets used
- * by network clocks.
- * @see_also: #GstClock, #GstNetClientClock, #GstNetTimeProvider
- *
- * Various functions for receiving, sending an serializing #GstNetTimePacket
- * structures.
- *
- * Last reviewed on 2005-11-23 (0.9.5)
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "gstnettimepacket.h"
-
-
-/**
- * gst_net_time_packet_new:
- * @buffer: a buffer from which to construct the packet, or NULL
- *
- * Creates a new #GstNetTimePacket from a buffer received over the network. The
- * caller is responsible for ensuring that @buffer is at least
- * #GST_NET_TIME_PACKET_SIZE bytes long.
- *
- * If @buffer is #NULL, the local and remote times will be set to
- * #GST_CLOCK_TIME_NONE.
- *
- * MT safe. Caller owns return value (g_free to free).
- *
- * Returns: The new #GstNetTimePacket.
- */
-GstNetTimePacket *
-gst_net_time_packet_new (const guint8 * buffer)
-{
- GstNetTimePacket *ret;
-
- g_assert (sizeof (GstClockTime) == 8);
-
- ret = g_new0 (GstNetTimePacket, 1);
-
- if (buffer) {
- ret->local_time = GST_READ_UINT64_BE (buffer);
- ret->remote_time = GST_READ_UINT64_BE (buffer + sizeof (GstClockTime));
- } else {
- ret->local_time = GST_CLOCK_TIME_NONE;
- ret->remote_time = GST_CLOCK_TIME_NONE;
- }
-
- return ret;
-}
-
-/**
- * gst_net_time_packet_serialize:
- * @packet: the #GstNetTimePacket
- *
- * Serialized a #GstNetTimePacket into a newly-allocated sequence of
- * #GST_NET_TIME_PACKET_SIZE bytes, in network byte order. The value returned is
- * suitable for passing to write(2) or sendto(2) for communication over the
- * network.
- *
- * MT safe. Caller owns return value (g_free to free).
- *
- * Returns: A newly allocated sequence of #GST_NET_TIME_PACKET_SIZE bytes.
- */
-guint8 *
-gst_net_time_packet_serialize (const GstNetTimePacket * packet)
-{
- guint8 *ret;
-
- g_assert (sizeof (GstClockTime) == 8);
-
- ret = g_new0 (guint8, GST_NET_TIME_PACKET_SIZE);
-
- GST_WRITE_UINT64_BE (ret, packet->local_time);
- GST_WRITE_UINT64_BE (ret + sizeof (GstClockTime), packet->remote_time);
-
- return ret;
-}
-
-/**
- * gst_net_time_packet_receive:
- * @fd: a file descriptor created by socket(2)
- * @addr: a pointer to a sockaddr to hold the address of the sender
- * @len: a pointer to the size of the data pointed to by @addr
- *
- * Receives a #GstNetTimePacket over a socket. Handles interrupted system calls,
- * but otherwise returns NULL on error. See recvfrom(2) for more information on
- * how to interpret @sockaddr.
- *
- * MT safe. Caller owns return value (g_free to free).
- *
- * Returns: The new #GstNetTimePacket.
- */
-GstNetTimePacket *
-gst_net_time_packet_receive (gint fd, struct sockaddr * addr, socklen_t * len)
-{
- guint8 buffer[GST_NET_TIME_PACKET_SIZE];
- gint ret;
-
- while (TRUE) {
- ret = recvfrom (fd, buffer, GST_NET_TIME_PACKET_SIZE,
- 0, (struct sockaddr *) addr, len);
- if (ret < 0) {
- if (errno != EAGAIN && errno != EINTR)
- goto receive_error;
- else
- continue;
- } else if (ret < GST_NET_TIME_PACKET_SIZE) {
- goto short_packet;
- } else {
- return gst_net_time_packet_new (buffer);
- }
- }
-
-receive_error:
- {
- GST_DEBUG ("receive error %d: %s (%d)", ret, g_strerror (errno), errno);
- return NULL;
- }
-short_packet:
- {
- GST_DEBUG ("someone sent us a short packet (%d < %d)",
- ret, GST_NET_TIME_PACKET_SIZE);
- return NULL;
- }
-}
-
-/**
- * gst_net_time_packet_send:
- * @packet: the #GstNetTimePacket
- * @fd: a file descriptor created by socket(2)
- * @addr: a pointer to a sockaddr to hold the address of the sender
- * @len: the size of the data pointed to by @addr
- *
- * Sends a #GstNetTimePacket over a socket. Essentially a thin wrapper around
- * sendto(2) and gst_net_time_packet_serialize().
- *
- * MT safe.
- *
- * Returns: The return value of sendto(2).
- */
-gint
-gst_net_time_packet_send (const GstNetTimePacket * packet, gint fd,
- struct sockaddr * addr, socklen_t len)
-{
- guint8 *buffer;
- gint ret;
-
- g_return_val_if_fail (packet != NULL, -EINVAL);
-
- buffer = gst_net_time_packet_serialize (packet);
-
- ret = sendto (fd, buffer, GST_NET_TIME_PACKET_SIZE, MSG_DONTWAIT, addr, len);
-
- g_free (buffer);
-
- return ret;
-}
+++ /dev/null
-/* GStreamer
- * Copyright (C) 2005 Andy Wingo <wingo@pobox.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-
-#ifndef __GST_NET_TIME_PACKET_H__
-#define __GST_NET_TIME_PACKET_H__
-
-#include <gst/gst.h>
-
-G_BEGIN_DECLS
-
-#include <errno.h>
-#include <string.h>
-#include <sys/types.h>
-#include <netdb.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-
-/**
- * GST_NET_TIME_PACKET_SIZE:
- *
- * The size of the packets sent between network clocks.
- */
-#define GST_NET_TIME_PACKET_SIZE 16
-
-typedef struct _GstNetTimePacket GstNetTimePacket;
-
-/**
- * GstNetTimePacket:
- * @local_time: the local time when this packet was sent
- * @remote_time: the remote time observation
- *
- * Content of a #GstNetTimePacket.
- */
-struct _GstNetTimePacket {
- GstClockTime local_time;
- GstClockTime remote_time;
-};
-
-GstNetTimePacket* gst_net_time_packet_new (const guint8 *buffer);
-guint8* gst_net_time_packet_serialize (const GstNetTimePacket *packet);
-
-GstNetTimePacket* gst_net_time_packet_receive (gint fd, struct sockaddr *addr,
- socklen_t *len);
-gint gst_net_time_packet_send (const GstNetTimePacket *packet,
- gint fd, struct sockaddr *addr,
- socklen_t len);
-
-G_END_DECLS
-
-
-#endif /* __GST_NET_TIME_PACKET_H__ */
+++ /dev/null
-/* GStreamer
- * Copyright (C) 2005 Andy Wingo <wingo@pobox.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-/**
- * SECTION:gstnettimeprovider
- * @short_description: Special object that exposed the time of a clock
- * on the network.
- * @see_also: #GstClock, #GstNetClientClock, #GstPipeline
- *
- * This object exposes the time of a #GstClock on the network.
- *
- * A #GstNetTimeProvider is created with gst_net_time_provider_new() which
- * takes a #GstClock, an address and a port numner as arguments.
- *
- * After creating the object, a client clock such as #GstNetClientClock can
- * query the exposed clock for its values.
- *
- * The #GstNetTimeProvider typically wraps the clock used by a #GstPipeline.
- *
- * Last reviewed on 2005-11-23 (0.9.5)
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "gstnettimeprovider.h"
-#include "gstnettimepacket.h"
-
-#include <unistd.h>
-#include <sys/ioctl.h>
-
-#ifdef HAVE_FIONREAD_IN_SYS_FILIO
-#include <sys/filio.h>
-#endif
-
-GST_DEBUG_CATEGORY (ntp_debug);
-#define GST_CAT_DEFAULT (ntp_debug)
-
-/* the select call is also performed on the control sockets, that way
- * we can send special commands to unblock or restart the select call */
-#define CONTROL_RESTART 'R' /* restart the select call */
-#define CONTROL_STOP 'S' /* stop the select call */
-#define CONTROL_SOCKETS(self) self->control_sock
-#define WRITE_SOCKET(self) self->control_sock[1]
-#define READ_SOCKET(self) self->control_sock[0]
-
-#define SEND_COMMAND(self, command) \
-G_STMT_START { \
- unsigned char c; c = command; \
- write (WRITE_SOCKET(self), &c, 1); \
-} G_STMT_END
-
-#define READ_COMMAND(self, command, res) \
-G_STMT_START { \
- res = read(READ_SOCKET(self), &command, 1); \
-} G_STMT_END
-
-#define DEFAULT_ADDRESS "0.0.0.0"
-#define DEFAULT_PORT 5637
-
-enum
-{
- PROP_0,
- PROP_PORT,
- PROP_ADDRESS,
- PROP_CLOCK
- /* FILL ME */
-};
-
-static gboolean gst_net_time_provider_start (GstNetTimeProvider * bself);
-static void gst_net_time_provider_stop (GstNetTimeProvider * bself);
-
-static gpointer gst_net_time_provider_thread (gpointer data);
-
-static void gst_net_time_provider_finalize (GObject * object);
-static void gst_net_time_provider_set_property (GObject * object, guint prop_id,
- const GValue * value, GParamSpec * pspec);
-static void gst_net_time_provider_get_property (GObject * object, guint prop_id,
- GValue * value, GParamSpec * pspec);
-
-#define _do_init(type) \
- GST_DEBUG_CATEGORY_INIT (ntp_debug, "nettime", 0, "Network time provider");
-
-GST_BOILERPLATE_FULL (GstNetTimeProvider, gst_net_time_provider, GstObject,
- GST_TYPE_OBJECT, _do_init);
-
-static void
-gst_net_time_provider_base_init (gpointer g_class)
-{
- g_assert (sizeof (GstClockTime) == 8);
-}
-
-static void
-gst_net_time_provider_class_init (GstNetTimeProviderClass * klass)
-{
- GObjectClass *gobject_class;
-
- gobject_class = (GObjectClass *) klass;
-
- gobject_class->finalize = gst_net_time_provider_finalize;
- gobject_class->set_property = gst_net_time_provider_set_property;
- gobject_class->get_property = gst_net_time_provider_get_property;
-
- g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PORT,
- g_param_spec_int ("port", "port",
- "The port to receive the packets from, 0=allocate", 0, G_MAXUINT16,
- DEFAULT_PORT, G_PARAM_READWRITE));
- g_object_class_install_property (gobject_class, PROP_ADDRESS,
- g_param_spec_string ("address", "address",
- "The address to bind on, as a dotted quad (x.x.x.x)",
- DEFAULT_ADDRESS, G_PARAM_READWRITE));
- g_object_class_install_property (gobject_class, PROP_CLOCK,
- g_param_spec_object ("clock", "Clock",
- "The clock to export over the network", GST_TYPE_CLOCK,
- G_PARAM_READWRITE));
-}
-
-static void
-gst_net_time_provider_init (GstNetTimeProvider * self,
- GstNetTimeProviderClass * g_class)
-{
- self->port = DEFAULT_PORT;
- self->sock = -1;
- self->address = g_strdup (DEFAULT_ADDRESS);
- self->thread = NULL;
-
- READ_SOCKET (self) = -1;
- WRITE_SOCKET (self) = -1;
-}
-
-static void
-gst_net_time_provider_finalize (GObject * object)
-{
- GstNetTimeProvider *self = GST_NET_TIME_PROVIDER (object);
-
- if (self->thread) {
- gst_net_time_provider_stop (self);
- g_assert (self->thread == NULL);
- }
-
- if (READ_SOCKET (self) != -1) {
- close (READ_SOCKET (self));
- close (WRITE_SOCKET (self));
- READ_SOCKET (self) = -1;
- WRITE_SOCKET (self) = -1;
- }
-
- g_free (self->address);
- self->address = NULL;
-
- if (self->clock)
- gst_object_unref (self->clock);
- self->clock = NULL;
-
- G_OBJECT_CLASS (parent_class)->finalize (object);
-}
-
-static gpointer
-gst_net_time_provider_thread (gpointer data)
-{
- GstNetTimeProvider *self = data;
- struct sockaddr_in tmpaddr;
- socklen_t len;
- fd_set read_fds;
- guint max_sock;
- GstNetTimePacket *packet;
- gint ret;
-
- while (TRUE) {
- FD_ZERO (&read_fds);
- FD_SET (self->sock, &read_fds);
- FD_SET (READ_SOCKET (self), &read_fds);
- max_sock = MAX (self->sock, READ_SOCKET (self));
-
- GST_LOG_OBJECT (self, "doing select");
- ret = select (max_sock + 1, &read_fds, NULL, NULL, NULL);
- GST_LOG_OBJECT (self, "select returned %d", ret);
-
- if (ret <= 0) {
- if (errno != EAGAIN && errno != EINTR)
- goto select_error;
- else
- continue;
- } else if (FD_ISSET (READ_SOCKET (self), &read_fds)) {
- /* got control message */
- while (TRUE) {
- gchar command;
- int res;
-
- READ_COMMAND (self, command, res);
- if (res < 0) {
- GST_LOG_OBJECT (self, "no more commands");
- break;
- }
-
- switch (command) {
- case CONTROL_STOP:
- /* break out of the select loop */
- GST_LOG_OBJECT (self, "stop");
- goto stopped;
- default:
- GST_WARNING_OBJECT (self, "unkown");
- g_warning ("nettimeprovider: unknown control message received");
- continue;
- }
-
- g_assert_not_reached ();
- }
-
- continue;
- } else {
- /* got data in */
- len = sizeof (struct sockaddr);
-
- packet = gst_net_time_packet_receive (self->sock,
- (struct sockaddr *) &tmpaddr, &len);
-
- if (!packet)
- goto receive_error;
-
- /* do what we were asked to and send the packet back */
- packet->remote_time = gst_clock_get_time (self->clock);
-
- /* ignore errors */
- gst_net_time_packet_send (packet, self->sock,
- (struct sockaddr *) &tmpaddr, len);
-
- g_free (packet);
-
- continue;
- }
-
- g_assert_not_reached ();
-
- /* log errors and keep going */
- select_error:
- {
- GST_DEBUG_OBJECT (self, "select error %d: %s (%d)", ret,
- g_strerror (errno), errno);
- continue;
- }
- stopped:
- {
- GST_DEBUG_OBJECT (self, "shutting down");
- /* close socket */
- return NULL;
- }
- receive_error:
- {
- GST_DEBUG_OBJECT (self, "receive error");
- continue;
- }
-
- g_assert_not_reached ();
-
- }
-
- g_assert_not_reached ();
-
- return NULL;
-}
-
-static void
-gst_net_time_provider_set_property (GObject * object, guint prop_id,
- const GValue * value, GParamSpec * pspec)
-{
- GstNetTimeProvider *self = GST_NET_TIME_PROVIDER (object);
-
- switch (prop_id) {
- case PROP_PORT:
- self->port = g_value_get_int (value);
- break;
- case PROP_ADDRESS:
- g_free (self->address);
- if (g_value_get_string (value) == NULL)
- self->address = g_strdup (DEFAULT_ADDRESS);
- else
- self->address = g_strdup (g_value_get_string (value));
- break;
- case PROP_CLOCK:
- gst_object_replace ((GstObject **) & self->clock,
- (GstObject *) g_value_get_object (value));
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-gst_net_time_provider_get_property (GObject * object, guint prop_id,
- GValue * value, GParamSpec * pspec)
-{
- GstNetTimeProvider *self = GST_NET_TIME_PROVIDER (object);
-
- switch (prop_id) {
- case PROP_PORT:
- g_value_set_int (value, self->port);
- break;
- case PROP_ADDRESS:
- g_value_set_string (value, self->address);
- break;
- case PROP_CLOCK:
- g_value_set_object (value, self->clock);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static gboolean
-gst_net_time_provider_start (GstNetTimeProvider * self)
-{
- gint ru;
- struct sockaddr_in my_addr;
- guint len;
- int port;
- gint ret;
- GError *error;
-
- if ((ret = socket (AF_INET, SOCK_DGRAM, 0)) < 0)
- goto no_socket;
-
- self->sock = ret;
-
- ru = 1;
- ret = setsockopt (self->sock, SOL_SOCKET, SO_REUSEADDR, &ru, sizeof (ru));
- if (ret < 0)
- goto setsockopt_error;
-
- memset (&my_addr, 0, sizeof (my_addr));
- my_addr.sin_family = AF_INET; /* host byte order */
- my_addr.sin_port = htons ((gint16) self->port); /* short, network byte order */
- my_addr.sin_addr.s_addr = INADDR_ANY;
- if (self->address)
- inet_aton (self->address, &my_addr.sin_addr);
-
- GST_DEBUG_OBJECT (self, "binding on port %d", self->port);
- ret = bind (self->sock, (struct sockaddr *) &my_addr, sizeof (my_addr));
- if (ret < 0)
- goto bind_error;
-
- len = sizeof (my_addr);
- ret = getsockname (self->sock, (struct sockaddr *) &my_addr, &len);
- if (ret < 0)
- goto getsockname_error;
-
- port = ntohs (my_addr.sin_port);
- GST_DEBUG_OBJECT (self, "bound, on port %d", port);
-
- if (port != self->port) {
- self->port = port;
- GST_DEBUG_OBJECT (self, "notifying %d", port);
- g_object_notify (G_OBJECT (self), "port");
- }
-
- self->thread = g_thread_create (gst_net_time_provider_thread, self, TRUE,
- &error);
- if (!self->thread)
- goto no_thread;
-
- return TRUE;
-
- /* ERRORS */
-no_socket:
- {
- GST_ERROR_OBJECT (self, "socket failed %d: %s (%d)", ret,
- g_strerror (errno), errno);
- return FALSE;
- }
-setsockopt_error:
- {
- close (self->sock);
- self->sock = -1;
- GST_ERROR_OBJECT (self, "setsockopt failed %d: %s (%d)", ret,
- g_strerror (errno), errno);
- return FALSE;
- }
-bind_error:
- {
- close (self->sock);
- self->sock = -1;
- GST_ERROR_OBJECT (self, "bind failed %d: %s (%d)", ret,
- g_strerror (errno), errno);
- return FALSE;
- }
-getsockname_error:
- {
- close (self->sock);
- self->sock = -1;
- GST_ERROR_OBJECT (self, "getsockname failed %d: %s (%d)", ret,
- g_strerror (errno), errno);
- return FALSE;
- }
-no_thread:
- {
- close (self->sock);
- self->sock = -1;
- GST_ERROR_OBJECT (self, "could not create thread: %s", error->message);
- g_error_free (error);
- return FALSE;
- }
-}
-
-static void
-gst_net_time_provider_stop (GstNetTimeProvider * self)
-{
- SEND_COMMAND (self, CONTROL_STOP);
- g_thread_join (self->thread);
- self->thread = NULL;
-
- if (self->sock != -1) {
- close (self->sock);
- self->sock = -1;
- }
-}
-
-/**
- * gst_net_time_provider_new:
- * @clock: a #GstClock to export over the network
- * @address: an address to bind on as a dotted quad (xxx.xxx.xxx.xxx), or NULL
- * to bind to all addresses
- * @port: a port to bind on, or -1 to let the kernel choose
- *
- * Allows network clients to get the current time of @clock.
- *
- * Returns: The new #GstNetTimeProvider, or NULL on error.
- */
-GstNetTimeProvider *
-gst_net_time_provider_new (GstClock * clock, const gchar * address, gint port)
-{
- GstNetTimeProvider *ret;
- gint iret;
-
- g_return_val_if_fail (clock && GST_IS_CLOCK (clock), NULL);
- g_return_val_if_fail (port >= 0 && port <= G_MAXUINT16, NULL);
-
- ret = g_object_new (GST_TYPE_NET_TIME_PROVIDER, "clock", clock, "address",
- address, "port", port, NULL);
-
- GST_DEBUG_OBJECT (ret, "creating socket pair");
- if ((iret = socketpair (PF_UNIX, SOCK_STREAM, 0, CONTROL_SOCKETS (ret))) < 0)
- goto no_socket_pair;
-
- fcntl (READ_SOCKET (ret), F_SETFL, O_NONBLOCK);
- fcntl (WRITE_SOCKET (ret), F_SETFL, O_NONBLOCK);
-
- if (!gst_net_time_provider_start (ret))
- goto failed_start;
-
- /* all systems go, cap'n */
- return ret;
-
-no_socket_pair:
- {
- GST_ERROR_OBJECT (ret, "no socket pair %d: %s (%d)", iret,
- g_strerror (errno), errno);
- gst_object_unref (ret);
- return NULL;
- }
-failed_start:
- {
- /* already printed a nice error */
- gst_object_unref (ret);
- return NULL;
- }
-
-}
+++ /dev/null
-/* GStreamer
- * Copyright (C) 2005 Andy Wingo <wingo@pobox.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-
-#ifndef __GST_NET_TIME_PROVIDER_H__
-#define __GST_NET_TIME_PROVIDER_H__
-
-#include <gst/gst.h>
-
-G_BEGIN_DECLS
-
-#include <errno.h>
-#include <string.h>
-#include <sys/types.h>
-#include <netdb.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-
-#include <fcntl.h>
-
-#define GST_TYPE_NET_TIME_PROVIDER \
- (gst_net_time_provider_get_type())
-#define GST_NET_TIME_PROVIDER(obj) \
- (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_NET_TIME_PROVIDER,GstNetTimeProvider))
-#define GST_NET_TIME_PROVIDER_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_NET_TIME_PROVIDER,GstNetTimeProvider))
-#define GST_IS_NET_TIME_PROVIDER(obj) \
- (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_NET_TIME_PROVIDER))
-#define GST_IS_NET_TIME_PROVIDER_CLASS(obj) \
- (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_NET_TIME_PROVIDER))
-
-typedef struct _GstNetTimeProvider GstNetTimeProvider;
-typedef struct _GstNetTimeProviderClass GstNetTimeProviderClass;
-
-/**
- * GstNetTimeProvider:
- *
- * Opaque #GstNetTimeProvider structure.
- */
-struct _GstNetTimeProvider {
- GstObject parent;
-
- /*< private >*/
- gchar *address;
- int port;
-
- int sock;
- int control_sock[2];
-
- GThread *thread;
-
- GstClock *clock;
-
- /*< private >*/
- gpointer _gst_reserved[GST_PADDING];
-};
-
-struct _GstNetTimeProviderClass {
- GstObjectClass parent_class;
-};
-
-GType gst_net_time_provider_get_type (void);
-GstNetTimeProvider* gst_net_time_provider_new (GstClock *clock,
- const gchar *address,
- gint port);
-
-G_END_DECLS
-
-
-#endif /* __GST_NET_TIME_PROVIDER_H__ */
-SUBDIRS = controller dataprotocol
+if HAVE_CHECK
+SUBDIRS_CHECK = check
+else
+SUBDIRS_CHECK =
+endif
+
+if GST_DISABLE_NET
+SUBDIRS_NET =
+else
+if HAVE_SYS_SOCKET_H
+SUBDIRS_NET = net
+else
+SUBDIRS_NET =
+endif
+endif
+
+SUBDIRS_ALWAYS = base controller dataprotocol
+
+SUBDIRS = $(SUBDIRS_ALWAYS) $(SUBDIRS_CHECK) $(SUBDIRS_NET)
+DIST_SUBDIRS = $(SUBDIRS_ALWAYS) check net
lib_LTLIBRARIES = libgstbase-@GST_MAJORMINOR@.la
libgstbase_@GST_MAJORMINOR@_la_DEPENDENCIES = \
- ../libgstreamer-@GST_MAJORMINOR@.la
+ $(top_builddir)/gst/libgstreamer-@GST_MAJORMINOR@.la
libgstbase_@GST_MAJORMINOR@_la_SOURCES = \
gstadapter.c \
gstbasesink.c \
#include <stdlib.h>
#include <string.h>
-#include "../gst-i18n-lib.h"
+#include "../../../gst/gst-i18n-lib.h"
#include "gstbasetransform.h"
#include <gst/gstmarshal.h>
lib_LTLIBRARIES = libgstcheck-@GST_MAJORMINOR@.la
libgstcheck_@GST_MAJORMINOR@_la_DEPENDENCIES = \
- ../libgstreamer-@GST_MAJORMINOR@.la
+ $(top_builddir)/gst/libgstreamer-@GST_MAJORMINOR@.la
libgstcheck_@GST_MAJORMINOR@_la_SOURCES = \
gstcheck.c
libgstcheck_@GST_MAJORMINOR@_la_CFLAGS = $(GST_OBJ_CFLAGS) $(CHECK_CFLAGS)
libgstcheck_@GST_MAJORMINOR@_la_LIBADD = $(GST_OBJ_LIBS) $(CHECK_LIBS) \
- ../libgstreamer-@GST_MAJORMINOR@.la
+ $(top_builddir)/gst/libgstreamer-@GST_MAJORMINOR@.la
libgstcheck_@GST_MAJORMINOR@_la_LDFLAGS = \
libgstbase_@GST_MAJORMINOR@_la_LDFLAGS = $(GST_LIB_LDFLAGS) $(GST_ALL_LDFLAGS) $(GST_LT_LDFLAGS)
libgstelements_la_CFLAGS = $(GST_OBJ_CFLAGS)
libgstelements_la_LIBADD = \
- $(top_builddir)/gst/base/libgstbase-@GST_MAJORMINOR@.la \
+ $(top_builddir)/libs/gst/base/libgstbase-@GST_MAJORMINOR@.la \
$(GST_OBJ_LIBS)
libgstelements_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
gst/gstqueue.c
gst/gsttaglist.c
gst/parse/grammar.y
-gst/base/gstbasesrc.c
-gst/base/gstbasesink.c
+libs/gst/base/gstbasesrc.c
+libs/gst/base/gstbasesink.c
plugins/elements/gstfakesink.c
plugins/elements/gstfilesink.c
plugins/elements/gstfilesrc.c
noinst_HEADERS = gst/capslist.h
AM_CFLAGS = $(GST_OBJ_CFLAGS) $(CHECK_CFLAGS)
-LDADD = $(top_builddir)/gst/check/libgstcheck-@GST_MAJORMINOR@.la \
+LDADD = $(top_builddir)/libs/gst/check/libgstcheck-@GST_MAJORMINOR@.la \
$(GST_OBJ_LIBS) \
$(CHECK_LIBS)
$(LDADD)
net_gstnetclientclock_LDADD = \
- $(top_builddir)/gst/net/libgstnet-@GST_MAJORMINOR@.la \
+ $(top_builddir)/libs/gst/net/libgstnet-@GST_MAJORMINOR@.la \
$(LDADD)
net_gstnettimeprovider_LDADD = \
- $(top_builddir)/gst/net/libgstnet-@GST_MAJORMINOR@.la \
+ $(top_builddir)/libs/gst/net/libgstnet-@GST_MAJORMINOR@.la \
$(LDADD)
# valgrind testing