From: Thomas Vander Stichele Date: Tue, 29 Nov 2005 19:12:30 +0000 (+0000) Subject: CVS surgery + support to move base, check, and net out of gst and into libs/gst X-Git-Tag: RELEASE-0_9_7~67 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=a0c4c4812cee5473f0bebd52495fccdab02c7717;p=platform%2Fupstream%2Fgstreamer.git CVS surgery + support to move base, check, and net out of gst and into libs/gst Original commit message from CVS: CVS surgery + support to move base, check, and net out of gst and into libs/gst --- diff --git a/ChangeLog b/ChangeLog index 813c960..ab78ada 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,46 @@ +2005-11-29 Thomas Vander Stichele + + * 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 * gst/gstevent.h (struct _GstEvent): Only one pointer of padding. diff --git a/check/Makefile.am b/check/Makefile.am index 84a14d8..a4c5a2d 100644 --- a/check/Makefile.am +++ b/check/Makefile.am @@ -70,7 +70,7 @@ TESTS = $(check_PROGRAMS) 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) @@ -86,10 +86,10 @@ gst_libs_controller_LDADD = \ $(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 diff --git a/configure.ac b/configure.ac index 85c5e79..a96f997 100644 --- a/configure.ac +++ b/configure.ac @@ -473,14 +473,14 @@ Makefile 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 diff --git a/docs/gst/Makefile.am b/docs/gst/Makefile.am index 1ec7b17..ba8011b 100644 --- a/docs/gst/Makefile.am +++ b/docs/gst/Makefile.am @@ -33,12 +33,6 @@ include $(srcdir)/../upload.mak # 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" @@ -48,17 +42,22 @@ MKDB_OPTIONS=--sgml-mode --ignore-files=parse # 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= \ diff --git a/gst/Makefile.am b/gst/Makefile.am index 3b7cd22..4287581 100644 --- a/gst/Makefile.am +++ b/gst/Makefile.am @@ -1,11 +1,5 @@ lib_LTLIBRARIES = libgstreamer-@GST_MAJORMINOR@.la -if HAVE_CHECK -SUBDIRS_CHECK = check -else -SUBDIRS_CHECK = -endif - if GST_DISABLE_LOADSAVE GST_LOADSAVE_SRC = else @@ -52,24 +46,9 @@ 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 diff --git a/gst/base/.gitignore b/gst/base/.gitignore deleted file mode 100644 index 8fcaa76..0000000 --- a/gst/base/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.gcno diff --git a/gst/base/Makefile.am b/gst/base/Makefile.am deleted file mode 100644 index d0df11d..0000000 --- a/gst/base/Makefile.am +++ /dev/null @@ -1,29 +0,0 @@ -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 - diff --git a/gst/base/README b/gst/base/README deleted file mode 100644 index 7214ce2..0000000 --- a/gst/base/README +++ /dev/null @@ -1,6 +0,0 @@ -Base classes ------------- - -GstBaseSink - FIXME: not much point making it operate in pull mode as a generic - base class I guess... diff --git a/gst/base/gstadapter.c b/gst/base/gstadapter.c deleted file mode 100644 index 6c8720a..0000000 --- a/gst/base/gstadapter.c +++ /dev/null @@ -1,372 +0,0 @@ -/* GStreamer - * Copyright (C) 2004 Benjamin Otte - * - * 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: - * - * 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; - * } - * - * 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 - -#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; -} diff --git a/gst/base/gstadapter.h b/gst/base/gstadapter.h deleted file mode 100644 index 62565d7..0000000 --- a/gst/base/gstadapter.h +++ /dev/null @@ -1,86 +0,0 @@ -/* GStreamer - * Copyright (C) 2004 Benjamin Otte - * - * 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 - -#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__ */ diff --git a/gst/base/gstbasesink.c b/gst/base/gstbasesink.c deleted file mode 100644 index 2f143dd..0000000 --- a/gst/base/gstbasesink.c +++ /dev/null @@ -1,1583 +0,0 @@ -/* GStreamer - * Copyright (C) 2005 Wim Taymans - * - * 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: - * - * 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); - * } - * - * - * 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 -#include - -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; - } -} diff --git a/gst/base/gstbasesink.h b/gst/base/gstbasesink.h deleted file mode 100644 index fdb24af..0000000 --- a/gst/base/gstbasesink.h +++ /dev/null @@ -1,130 +0,0 @@ -/* GStreamer - * Copyright (C) 1999,2000 Erik Walthinsen - * 2000 Wim Taymans - * - * 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 - -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__ */ diff --git a/gst/base/gstbasesrc.c b/gst/base/gstbasesrc.c deleted file mode 100644 index 02111c3..0000000 --- a/gst/base/gstbasesrc.c +++ /dev/null @@ -1,1472 +0,0 @@ -/* GStreamer - * Copyright (C) 1999,2000 Erik Walthinsen - * 2000,2005 Wim Taymans - * - * 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. - * - * - * one source pad - * handles state changes - * does flushing - * preroll with optional preview - * pull/push mode - * EOS handling - * - */ - -#include -#include - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include "gstbasesrc.h" -#include "gsttypefindhelper.h" -#include -#include - -#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; - } -} diff --git a/gst/base/gstbasesrc.h b/gst/base/gstbasesrc.h deleted file mode 100644 index 908c7c3..0000000 --- a/gst/base/gstbasesrc.h +++ /dev/null @@ -1,164 +0,0 @@ -/* GStreamer - * Copyright (C) 1999,2000 Erik Walthinsen - * 2000 Wim Taymans - * 2005 Wim Taymans - * - * 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 - -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__ */ diff --git a/gst/base/gstbasetransform.c b/gst/base/gstbasetransform.c deleted file mode 100644 index 28e4660..0000000 --- a/gst/base/gstbasetransform.c +++ /dev/null @@ -1,1552 +0,0 @@ -/* GStreamer - * Copyright (C) 1999,2000 Erik Walthinsen - * 2000 Wim Taymans - * 2005 Wim Taymans - * 2005 Andy Wingo - * 2005 Thomas Vander Stichele - * - * 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: - * - * one sinkpad and one srcpad - * - * Possible formats on sink and source pad implemented - * with custom transform_caps function. By default uses - * same format on sink and source. - * - * Handles state changes - * Does flushing - * Push mode - * - * Pull mode if the sub-class transform can operate on arbitrary data - * - * - * - * Use Cases: - * - * - * Passthrough mode - * - * 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. - * - * - * 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. - * - * - * 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) - * - * - * - * Example elements - * Level - * Videoscale, audioconvert, ffmpegcolorspace, audioresample in certain modes. - * - * - * - * Modifications in-place - input buffer and output buffer are the same thing. - * - * The element must implement a transform_ip function. - * - * - * Output buffer size must <= input buffer size - * - * - * 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. - * - * - * Incoming writable buffers will be passed to the transform_ip function immediately. - * - * - * only implementing transform_ip and not transform implies always_in_place = - * TRUE - * - * - * - * Example elements - * Volume - * Audioconvert in certain modes (signed/unsigned conversion) - * ffmpegcolorspace in certain modes (endianness swapping) - * - * - * - * Modifications only to the caps/metadata of a buffer - * - * The element does not require writable data, but non-writable buffers should - * be subbuffered so that the meta-information can be replaced. - * - * - * 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 - * - * - * - * Example elements - * Capsfilter when setting caps on outgoing buffers that have none. - * identity when it is going to re-timestamp buffers by datarate. - * - * - * - * Normal mode - * - * always_in_place flag is not set, or there is no transform_ip function - * - * - * Element will receive an input buffer and output buffer to operate on. - * - * - * Output buffer is allocated by calling the prepare_output_buffer function. - * - * - * - * Example elements - * Videoscale, ffmpegcolorspace, audioconvert when doing scaling/conversions - * - * - * - * Special output buffer allocations - * - * 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. - * - * - * - * Example elements - * efence - * - * - * - * - * Sub-class settable flags on GstBaseTransform - * - * passthrough - * - * Implies that in the current configuration, the sub-class is not - * interested in modifying the buffers. - * - * - * 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. - * - * - * - * - * always_in_place - * - * Determines whether a non-writable buffer will be copied before passing - * to the transform_ip function. - * - * - * Implied TRUE if no transform function is implemented. - * - * - * Implied FALSE if ONLY transform function is implemented. - * - * - * - * - * -*/ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include -#include - -#include "../gst-i18n-lib.h" -#include "gstbasetransform.h" -#include - -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. - * - * Always TRUE if no transform function is implemented. - * Always FALSE if ONLY transform_ip function is implemented. - * - * - * 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; -} diff --git a/gst/base/gstbasetransform.h b/gst/base/gstbasetransform.h deleted file mode 100644 index 3b92cc8..0000000 --- a/gst/base/gstbasetransform.h +++ /dev/null @@ -1,177 +0,0 @@ -/* GStreamer - * Copyright (C) 1999,2000 Erik Walthinsen - * 2005 Wim Taymans - * - * 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 - -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__ */ diff --git a/gst/base/gstcollectpads.c b/gst/base/gstcollectpads.c deleted file mode 100644 index f06a42e..0000000 --- a/gst/base/gstcollectpads.c +++ /dev/null @@ -1,701 +0,0 @@ -/* GStreamer - * Copyright (C) 2005 Wim Taymans - * - * 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. - * - * - * Collectpads are created with gst_collect_pads_new(). A callback should then - * be installed with gst_collect_pads_set_function (). - * - * - * 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. - * - * - * For each pad, data is queued in the chain function or by - * performing a pull_range. - * - * - * When data is queued on all pads, the callback function is called. - * - * - * 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. - * - * - * Data can also be dequeued in byte units using the gst_collect_pads_available(), - * gst_collect_pads_read() and gst_collect_pads_flush() calls. - * - * - * 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. - * - * - * gst_collect_pads_collect() and gst_collect_pads_collect_range() can be used by - * elements that start a #GstTask to drive the collect_pads. - * - * - */ - -#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; - } -} diff --git a/gst/base/gstcollectpads.h b/gst/base/gstcollectpads.h deleted file mode 100644 index 9bbe831..0000000 --- a/gst/base/gstcollectpads.h +++ /dev/null @@ -1,149 +0,0 @@ -/* GStreamer - * Copyright (C) 2005 Wim Taymans - * - * 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 - -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__ */ diff --git a/gst/base/gstpushsrc.c b/gst/base/gstpushsrc.c deleted file mode 100644 index 90d10f8..0000000 --- a/gst/base/gstpushsrc.c +++ /dev/null @@ -1,104 +0,0 @@ -/* GStreamer - * Copyright (C) 1999,2000 Erik Walthinsen - * 2000,2005 Wim Taymans - * - * 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 -#include - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include "gstpushsrc.h" -#include "gsttypefindhelper.h" -#include - -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; -} diff --git a/gst/base/gstpushsrc.h b/gst/base/gstpushsrc.h deleted file mode 100644 index a7480b4..0000000 --- a/gst/base/gstpushsrc.h +++ /dev/null @@ -1,68 +0,0 @@ -/* GStreamer - * Copyright (C) 1999,2000 Erik Walthinsen - * 2000 Wim Taymans - * 2005 Wim Taymans - * - * 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 -#include - -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__ */ diff --git a/gst/base/gsttypefindhelper.c b/gst/base/gsttypefindhelper.c deleted file mode 100644 index 6656c06..0000000 --- a/gst/base/gsttypefindhelper.c +++ /dev/null @@ -1,182 +0,0 @@ -/* GStreamer - * Copyright (C) 1999,2000 Erik Walthinsen - * 2000,2005 Wim Taymans - * - * 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 -#include - -#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; -} diff --git a/gst/base/gsttypefindhelper.h b/gst/base/gsttypefindhelper.h deleted file mode 100644 index 994b239..0000000 --- a/gst/base/gsttypefindhelper.h +++ /dev/null @@ -1,34 +0,0 @@ -/* GStreamer - * Copyright (C) 1999,2000 Erik Walthinsen - * 2000,2005 Wim Taymans - * - * 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 - -G_BEGIN_DECLS - -GstCaps * gst_type_find_helper (GstPad *src, guint64 size); - -G_END_DECLS - -#endif /* __GST_TYPEFINDHELPER_H__ */ diff --git a/gst/check/Makefile.am b/gst/check/Makefile.am deleted file mode 100644 index a392c9f..0000000 --- a/gst/check/Makefile.am +++ /dev/null @@ -1,18 +0,0 @@ -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 diff --git a/gst/check/gstcheck.c b/gst/check/gstcheck.c deleted file mode 100644 index b41373c..0000000 --- a/gst/check/gstcheck.c +++ /dev/null @@ -1,249 +0,0 @@ -/* GStreamer - * - * Common code for GStreamer unittests - * - * Copyright (C) <2004> Thomas Vander Stichele - * - * 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); -} diff --git a/gst/check/gstcheck.h b/gst/check/gstcheck.h deleted file mode 100644 index 356617c..0000000 --- a/gst/check/gstcheck.h +++ /dev/null @@ -1,262 +0,0 @@ -/* GStreamer - * - * Common code for GStreamer unittests - * - * Copyright (C) <2004> Thomas Vander Stichele - * - * 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 -#include -#include - -#include - -#include - -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__ */ - diff --git a/gst/net/Makefile.am b/gst/net/Makefile.am deleted file mode 100644 index e3ef286..0000000 --- a/gst/net/Makefile.am +++ /dev/null @@ -1,18 +0,0 @@ -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) - diff --git a/gst/net/gstnet.h b/gst/net/gstnet.h deleted file mode 100644 index 078cad5..0000000 --- a/gst/net/gstnet.h +++ /dev/null @@ -1,30 +0,0 @@ -/* GStreamer - * Copyright (C) 2005 Andy Wingo - * - * 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 -#include -#include - - -#endif /* __GST_NET_H__ */ diff --git a/gst/net/gstnetclientclock.c b/gst/net/gstnetclientclock.c deleted file mode 100644 index 4f24f9a..0000000 --- a/gst/net/gstnetclientclock.c +++ /dev/null @@ -1,597 +0,0 @@ -/* GStreamer - * Copyright (C) 1999,2000 Erik Walthinsen - * 2005 Wim Taymans - * 2005 Andy Wingo - * - * 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 - -#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; - } -} diff --git a/gst/net/gstnetclientclock.h b/gst/net/gstnetclientclock.h deleted file mode 100644 index 1b7412e..0000000 --- a/gst/net/gstnetclientclock.h +++ /dev/null @@ -1,97 +0,0 @@ -/* GStreamer - * Copyright (C) 1999,2000 Erik Walthinsen - * 2005 Wim Taymans - * 2005 Andy Wingo - * - * 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 -#include - -G_BEGIN_DECLS - -#include -#include -#include -#include -#include -#include -#include - -#include - -#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__ */ diff --git a/gst/net/gstnettimepacket.c b/gst/net/gstnettimepacket.c deleted file mode 100644 index 16c311a..0000000 --- a/gst/net/gstnettimepacket.c +++ /dev/null @@ -1,179 +0,0 @@ -/* GStreamer - * Copyright (C) 2005 Andy Wingo - * - * 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; -} diff --git a/gst/net/gstnettimepacket.h b/gst/net/gstnettimepacket.h deleted file mode 100644 index 3a92a02..0000000 --- a/gst/net/gstnettimepacket.h +++ /dev/null @@ -1,69 +0,0 @@ -/* GStreamer - * Copyright (C) 2005 Andy Wingo - * - * 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 - -G_BEGIN_DECLS - -#include -#include -#include -#include -#include -#include -#include - -/** - * 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__ */ diff --git a/gst/net/gstnettimeprovider.c b/gst/net/gstnettimeprovider.c deleted file mode 100644 index 00e8094..0000000 --- a/gst/net/gstnettimeprovider.c +++ /dev/null @@ -1,485 +0,0 @@ -/* GStreamer - * Copyright (C) 2005 Andy Wingo - * - * 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 -#include - -#ifdef HAVE_FIONREAD_IN_SYS_FILIO -#include -#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; - } - -} diff --git a/gst/net/gstnettimeprovider.h b/gst/net/gstnettimeprovider.h deleted file mode 100644 index e05bad1..0000000 --- a/gst/net/gstnettimeprovider.h +++ /dev/null @@ -1,87 +0,0 @@ -/* GStreamer - * Copyright (C) 2005 Andy Wingo - * - * 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 - -G_BEGIN_DECLS - -#include -#include -#include -#include -#include -#include -#include - -#include - -#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__ */ diff --git a/libs/gst/Makefile.am b/libs/gst/Makefile.am index a609001..5839e5a 100644 --- a/libs/gst/Makefile.am +++ b/libs/gst/Makefile.am @@ -1 +1,20 @@ -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 diff --git a/libs/gst/base/Makefile.am b/libs/gst/base/Makefile.am index d0df11d..1936516 100644 --- a/libs/gst/base/Makefile.am +++ b/libs/gst/base/Makefile.am @@ -1,7 +1,7 @@ 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 \ diff --git a/libs/gst/base/gstbasetransform.c b/libs/gst/base/gstbasetransform.c index 28e4660..c1e7a9e 100644 --- a/libs/gst/base/gstbasetransform.c +++ b/libs/gst/base/gstbasetransform.c @@ -188,7 +188,7 @@ #include #include -#include "../gst-i18n-lib.h" +#include "../../../gst/gst-i18n-lib.h" #include "gstbasetransform.h" #include diff --git a/libs/gst/check/Makefile.am b/libs/gst/check/Makefile.am index a392c9f..2d0cd93 100644 --- a/libs/gst/check/Makefile.am +++ b/libs/gst/check/Makefile.am @@ -1,13 +1,13 @@ 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) diff --git a/plugins/elements/Makefile.am b/plugins/elements/Makefile.am index f2b426e..d142d0e 100644 --- a/plugins/elements/Makefile.am +++ b/plugins/elements/Makefile.am @@ -28,7 +28,7 @@ libgstelements_la_SOURCES = \ 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) diff --git a/po/POTFILES.in b/po/POTFILES.in index 4c50dec..426dc45 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -6,8 +6,8 @@ gst/gsterror.c 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 diff --git a/tests/check/Makefile.am b/tests/check/Makefile.am index 84a14d8..a4c5a2d 100644 --- a/tests/check/Makefile.am +++ b/tests/check/Makefile.am @@ -70,7 +70,7 @@ TESTS = $(check_PROGRAMS) 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) @@ -86,10 +86,10 @@ gst_libs_controller_LDADD = \ $(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