diff options
author | Sebastian Dröge <sebastian@centricular.com> | 2014-06-22 17:16:06 +0200 |
---|---|---|
committer | Sebastian Dröge <sebastian@centricular.com> | 2014-06-22 17:16:06 +0200 |
commit | 5254e8378f4c28705a571d7bfbbad5fbd1adb3d3 (patch) | |
tree | 3f6cac985731dee5f68347ea99ad30ed19462168 /libs | |
parent | 1adbba7bfff7853fca8b02aec57dbe1850d4a55c (diff) |
Imported Upstream version 1.3.3
Diffstat (limited to 'libs')
50 files changed, 1558 insertions, 493 deletions
diff --git a/libs/Makefile.in b/libs/Makefile.in index 2f00606..b19c609 100644 --- a/libs/Makefile.in +++ b/libs/Makefile.in @@ -86,7 +86,6 @@ am__aclocal_m4_deps = $(top_srcdir)/common/m4/as-ac-expand.m4 \ $(top_srcdir)/common/m4/as-compiler-flag.m4 \ $(top_srcdir)/common/m4/as-docbook.m4 \ $(top_srcdir)/common/m4/as-libtool.m4 \ - $(top_srcdir)/common/m4/as-scrub-include.m4 \ $(top_srcdir)/common/m4/as-version.m4 \ $(top_srcdir)/common/m4/ax_create_stdint_h.m4 \ $(top_srcdir)/common/m4/gst-arch.m4 \ diff --git a/libs/gst/Makefile.in b/libs/gst/Makefile.in index 5eaf2f1..6f9e86f 100644 --- a/libs/gst/Makefile.in +++ b/libs/gst/Makefile.in @@ -86,7 +86,6 @@ am__aclocal_m4_deps = $(top_srcdir)/common/m4/as-ac-expand.m4 \ $(top_srcdir)/common/m4/as-compiler-flag.m4 \ $(top_srcdir)/common/m4/as-docbook.m4 \ $(top_srcdir)/common/m4/as-libtool.m4 \ - $(top_srcdir)/common/m4/as-scrub-include.m4 \ $(top_srcdir)/common/m4/as-version.m4 \ $(top_srcdir)/common/m4/ax_create_stdint_h.m4 \ $(top_srcdir)/common/m4/gst-arch.m4 \ diff --git a/libs/gst/base/Makefile.am b/libs/gst/base/Makefile.am index 076dc02..738e718 100644 --- a/libs/gst/base/Makefile.am +++ b/libs/gst/base/Makefile.am @@ -13,6 +13,7 @@ libgstbase_@GST_API_VERSION@_la_SOURCES = \ gstbytewriter.c \ gstcollectpads.c \ gstdataqueue.c \ + gstflowcombiner.c \ gstpushsrc.c \ gstqueuearray.c \ gsttypefindhelper.c @@ -36,6 +37,7 @@ libgstbase_@GST_API_VERSION@include_HEADERS = \ gstbytewriter.h \ gstcollectpads.h \ gstdataqueue.h \ + gstflowcombiner.h \ gstpushsrc.h \ gstqueuearray.h \ gsttypefindhelper.h @@ -89,7 +91,7 @@ GstBase-@GST_API_VERSION@.gir: $(INTROSPECTION_SCANNER) libgstbase-@GST_API_VERS --library-path=$(top_builddir)/gst \ --library=libgstbase-@GST_API_VERSION@.la \ --include=Gst-@GST_API_VERSION@ \ - --libtool="$(top_builddir)/libtool" \ + --libtool="${LIBTOOL}" \ --pkg gstreamer-@GST_API_VERSION@ \ --pkg-export gstreamer-base-@GST_API_VERSION@ \ --add-init-section="gst_init(NULL,NULL);" \ diff --git a/libs/gst/base/Makefile.in b/libs/gst/base/Makefile.in index 21884e8..601edaf 100644 --- a/libs/gst/base/Makefile.in +++ b/libs/gst/base/Makefile.in @@ -93,7 +93,6 @@ am__aclocal_m4_deps = $(top_srcdir)/common/m4/as-ac-expand.m4 \ $(top_srcdir)/common/m4/as-compiler-flag.m4 \ $(top_srcdir)/common/m4/as-docbook.m4 \ $(top_srcdir)/common/m4/as-libtool.m4 \ - $(top_srcdir)/common/m4/as-scrub-include.m4 \ $(top_srcdir)/common/m4/as-version.m4 \ $(top_srcdir)/common/m4/ax_create_stdint_h.m4 \ $(top_srcdir)/common/m4/gst-arch.m4 \ @@ -173,6 +172,7 @@ am_libgstbase_@GST_API_VERSION@_la_OBJECTS = \ libgstbase_@GST_API_VERSION@_la-gstbytewriter.lo \ libgstbase_@GST_API_VERSION@_la-gstcollectpads.lo \ libgstbase_@GST_API_VERSION@_la-gstdataqueue.lo \ + libgstbase_@GST_API_VERSION@_la-gstflowcombiner.lo \ libgstbase_@GST_API_VERSION@_la-gstpushsrc.lo \ libgstbase_@GST_API_VERSION@_la-gstqueuearray.lo \ libgstbase_@GST_API_VERSION@_la-gsttypefindhelper.lo @@ -541,6 +541,7 @@ libgstbase_@GST_API_VERSION@_la_SOURCES = \ gstbytewriter.c \ gstcollectpads.c \ gstdataqueue.c \ + gstflowcombiner.c \ gstpushsrc.c \ gstqueuearray.c \ gsttypefindhelper.c @@ -563,6 +564,7 @@ libgstbase_@GST_API_VERSION@include_HEADERS = \ gstbytewriter.h \ gstcollectpads.h \ gstdataqueue.h \ + gstflowcombiner.h \ gstpushsrc.h \ gstqueuearray.h \ gsttypefindhelper.h @@ -674,6 +676,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstbase_@GST_API_VERSION@_la-gstbytewriter.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstbase_@GST_API_VERSION@_la-gstcollectpads.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstbase_@GST_API_VERSION@_la-gstdataqueue.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstbase_@GST_API_VERSION@_la-gstflowcombiner.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstbase_@GST_API_VERSION@_la-gstpushsrc.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstbase_@GST_API_VERSION@_la-gstqueuearray.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgstbase_@GST_API_VERSION@_la-gsttypefindhelper.Plo@am__quote@ @@ -772,6 +775,13 @@ libgstbase_@GST_API_VERSION@_la-gstdataqueue.lo: gstdataqueue.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstbase_@GST_API_VERSION@_la_CFLAGS) $(CFLAGS) -c -o libgstbase_@GST_API_VERSION@_la-gstdataqueue.lo `test -f 'gstdataqueue.c' || echo '$(srcdir)/'`gstdataqueue.c +libgstbase_@GST_API_VERSION@_la-gstflowcombiner.lo: gstflowcombiner.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstbase_@GST_API_VERSION@_la_CFLAGS) $(CFLAGS) -MT libgstbase_@GST_API_VERSION@_la-gstflowcombiner.lo -MD -MP -MF $(DEPDIR)/libgstbase_@GST_API_VERSION@_la-gstflowcombiner.Tpo -c -o libgstbase_@GST_API_VERSION@_la-gstflowcombiner.lo `test -f 'gstflowcombiner.c' || echo '$(srcdir)/'`gstflowcombiner.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstbase_@GST_API_VERSION@_la-gstflowcombiner.Tpo $(DEPDIR)/libgstbase_@GST_API_VERSION@_la-gstflowcombiner.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gstflowcombiner.c' object='libgstbase_@GST_API_VERSION@_la-gstflowcombiner.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstbase_@GST_API_VERSION@_la_CFLAGS) $(CFLAGS) -c -o libgstbase_@GST_API_VERSION@_la-gstflowcombiner.lo `test -f 'gstflowcombiner.c' || echo '$(srcdir)/'`gstflowcombiner.c + libgstbase_@GST_API_VERSION@_la-gstpushsrc.lo: gstpushsrc.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgstbase_@GST_API_VERSION@_la_CFLAGS) $(CFLAGS) -MT libgstbase_@GST_API_VERSION@_la-gstpushsrc.lo -MD -MP -MF $(DEPDIR)/libgstbase_@GST_API_VERSION@_la-gstpushsrc.Tpo -c -o libgstbase_@GST_API_VERSION@_la-gstpushsrc.lo `test -f 'gstpushsrc.c' || echo '$(srcdir)/'`gstpushsrc.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgstbase_@GST_API_VERSION@_la-gstpushsrc.Tpo $(DEPDIR)/libgstbase_@GST_API_VERSION@_la-gstpushsrc.Plo @@ -1112,7 +1122,7 @@ Android.mk: Makefile.am @HAVE_INTROSPECTION_TRUE@ --library-path=$(top_builddir)/gst \ @HAVE_INTROSPECTION_TRUE@ --library=libgstbase-@GST_API_VERSION@.la \ @HAVE_INTROSPECTION_TRUE@ --include=Gst-@GST_API_VERSION@ \ -@HAVE_INTROSPECTION_TRUE@ --libtool="$(top_builddir)/libtool" \ +@HAVE_INTROSPECTION_TRUE@ --libtool="${LIBTOOL}" \ @HAVE_INTROSPECTION_TRUE@ --pkg gstreamer-@GST_API_VERSION@ \ @HAVE_INTROSPECTION_TRUE@ --pkg-export gstreamer-base-@GST_API_VERSION@ \ @HAVE_INTROSPECTION_TRUE@ --add-init-section="gst_init(NULL,NULL);" \ diff --git a/libs/gst/base/base.h b/libs/gst/base/base.h index e741145..6646ce3 100644 --- a/libs/gst/base/base.h +++ b/libs/gst/base/base.h @@ -32,6 +32,7 @@ #include <gst/base/gstbytewriter.h> #include <gst/base/gstcollectpads.h> #include <gst/base/gstdataqueue.h> +#include <gst/base/gstflowcombiner.h> #include <gst/base/gstpushsrc.h> #include <gst/base/gstqueuearray.h> #include <gst/base/gsttypefindhelper.h> diff --git a/libs/gst/base/gstadapter.c b/libs/gst/base/gstadapter.c index 4c3e730..3d23fdb 100644 --- a/libs/gst/base/gstadapter.c +++ b/libs/gst/base/gstadapter.c @@ -70,13 +70,13 @@ * } * ]| * - * For another example, a simple element inside GStreamer that uses GstAdapter + * 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 + * 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. + * when changing state from %GST_STATE_PAUSED to %GST_STATE_READY. * * Also check the GST_BUFFER_FLAG_DISCONT flag on the buffer. Some elements might * need to clear the adapter after a discontinuity. @@ -92,7 +92,7 @@ * gst_adapter_prev_pts_at_offset() can be used to determine the last * seen timestamp at a particular offset in the adapter. * - * A last thing to note is that while GstAdapter is pretty optimized, + * A last thing to note is that while #GstAdapter is pretty optimized, * merging buffers still might be an operation that requires a malloc() and * memcpy() operation, and these operations are not the fastest. Because of * this, some functions like gst_adapter_available_fast() are provided to help @@ -100,17 +100,15 @@ * gst_adapter_copy() can be used to copy data into a (statically allocated) * user provided buffer. * - * GstAdapter is not MT safe. All operations on an adapter must be serialized by + * #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 + * of #GstAdapter is inside one pad's chain function, in which case access is * serialized via the pad's STREAM_LOCK. * * Note that gst_adapter_push() takes ownership of the buffer passed. Use * gst_buffer_ref() before pushing it into the adapter if you still want to * access the buffer later. The adapter will never modify the data in the * buffer pushed in it. - * - * Last reviewed on 2009-05-13 (0.10.24). */ #include <gst/gst_private.h> @@ -354,7 +352,7 @@ gst_adapter_push (GstAdapter * adapter, GstBuffer * buf) /* Internal method only. Tries to merge buffers at the head of the queue * to form a single larger buffer of size 'size'. * - * Returns TRUE if it managed to merge anything. + * Returns %TRUE if it managed to merge anything. */ static gboolean gst_adapter_try_to_merge_up (GstAdapter * adapter, gsize size) @@ -425,10 +423,10 @@ gst_adapter_try_to_merge_up (GstAdapter * adapter, gsize size) * as #GstBuffer memory or the potentially more performant * gst_adapter_take_buffer(). * - * Returns #NULL if @size bytes are not available. + * Returns %NULL if @size bytes are not available. * * Returns: (transfer none) (array length=size) (element-type guint8): - * a pointer to the first @size bytes of data, or NULL + * a pointer to the first @size bytes of data, or %NULL */ gconstpointer gst_adapter_map (GstAdapter * adapter, gsize size) @@ -526,7 +524,7 @@ gst_adapter_unmap (GstAdapter * adapter) } /** - * gst_adapter_copy: + * gst_adapter_copy: (skip) * @adapter: a #GstAdapter * @dest: (out caller-allocates) (array length=size) (element-type guint8): * the memory to copy into @@ -534,7 +532,7 @@ gst_adapter_unmap (GstAdapter * adapter) * @size: the number of bytes to copy * * Copies @size bytes of data starting at @offset out of the buffers - * contained in @GstAdapter into an array @dest provided by the caller. + * contained in #GstAdapter into an array @dest provided by the caller. * * The array @dest should be large enough to contain @size bytes. * The user should check that the adapter has (@offset + @size) bytes @@ -550,6 +548,32 @@ gst_adapter_copy (GstAdapter * adapter, gpointer dest, gsize offset, gsize size) copy_into_unchecked (adapter, dest, offset + adapter->skip, size); } +/** + * gst_adapter_copy_bytes: + * @adapter: a #GstAdapter + * @offset: the bytes offset in the adapter to start from + * @size: the number of bytes to copy + * + * Similar to gst_adapter_copy, but more suitable for language bindings. @size + * bytes of data starting at @offset will be copied out of the buffers contained + * in @adapter and into a new #GBytes structure which is returned. Depending on + * the value of the @size argument an empty #GBytes structure may be returned. + * + * Returns: (transfer full): A new #GBytes structure containing the copied data. + * + * Rename to: gst_adapter_copy + * + * Since: 1.4 + */ +GBytes * +gst_adapter_copy_bytes (GstAdapter * adapter, gsize offset, gsize size) +{ + gpointer data; + data = g_malloc (size); + gst_adapter_copy (adapter, data, offset, size); + return g_bytes_new_take (data, size); +} + /*Flushes the first @flush bytes in the @adapter*/ static void gst_adapter_flush_unchecked (GstAdapter * adapter, gsize flush) @@ -685,7 +709,7 @@ gst_adapter_take_internal (GstAdapter * adapter, gsize nbytes) * Free-function: g_free * * Returns: (transfer full) (array length=nbytes) (element-type guint8): - * oven-fresh hot data, or #NULL if @nbytes bytes are not available + * oven-fresh hot data, or %NULL if @nbytes bytes are not available */ gpointer gst_adapter_take (GstAdapter * adapter, gsize nbytes) @@ -735,7 +759,7 @@ gst_adapter_take (GstAdapter * adapter, gsize nbytes) * Free-function: gst_buffer_unref * * Returns: (transfer full): a #GstBuffer containing the first @nbytes of - * the adapter, or #NULL if @nbytes bytes are not available. + * the adapter, or %NULL if @nbytes bytes are not available. * gst_buffer_unref() when no longer needed. * * Since: 1.2 @@ -817,7 +841,7 @@ done: * Free-function: gst_buffer_unref * * Returns: (transfer full): a #GstBuffer containing the first @nbytes of - * the adapter, or #NULL if @nbytes bytes are not available. + * the adapter, or %NULL if @nbytes bytes are not available. * gst_buffer_unref() when no longer needed. */ GstBuffer * @@ -894,7 +918,7 @@ done: * buffer in the list before freeing the list after usage. * * Returns: (element-type Gst.Buffer) (transfer full): a #GList of buffers - * containing the first @nbytes of the adapter, or #NULL if @nbytes bytes + * containing the first @nbytes of the adapter, or %NULL if @nbytes bytes * are not available */ GList * @@ -929,7 +953,7 @@ gst_adapter_take_list (GstAdapter * adapter, gsize nbytes) * * Gets the maximum amount of bytes available, that is it returns the maximum * value that can be supplied to gst_adapter_map() without that function - * returning NULL. + * returning %NULL. * * Returns: number of bytes available in @adapter */ @@ -986,7 +1010,7 @@ gst_adapter_available_fast (GstAdapter * adapter) /** * gst_adapter_prev_pts: * @adapter: a #GstAdapter - * @distance: (out) (allow-none): pointer to location for distance, or NULL + * @distance: (out) (allow-none): pointer to location for distance, or %NULL * * Get the pts that was before the current byte in the adapter. When * @distance is given, the amount of bytes between the pts and the current @@ -1013,7 +1037,7 @@ gst_adapter_prev_pts (GstAdapter * adapter, guint64 * distance) /** * gst_adapter_prev_dts: * @adapter: a #GstAdapter - * @distance: (out) (allow-none): pointer to location for distance, or NULL + * @distance: (out) (allow-none): pointer to location for distance, or %NULL * * Get the dts that was before the current byte in the adapter. When * @distance is given, the amount of bytes between the dts and the current @@ -1041,7 +1065,7 @@ gst_adapter_prev_dts (GstAdapter * adapter, guint64 * distance) * gst_adapter_prev_pts_at_offset: * @adapter: a #GstAdapter * @offset: the offset in the adapter at which to get timestamp - * @distance: (out) (allow-none): pointer to location for distance, or NULL + * @distance: (out) (allow-none): pointer to location for distance, or %NULL * * Get the pts that was before the byte at offset @offset in the adapter. When * @distance is given, the amount of bytes between the pts and the current @@ -1065,7 +1089,6 @@ gst_adapter_prev_pts_at_offset (GstAdapter * adapter, gsize offset, GstClockTime pts = adapter->pts; g_return_val_if_fail (GST_IS_ADAPTER (adapter), GST_CLOCK_TIME_NONE); - g_return_val_if_fail (offset >= 0, GST_CLOCK_TIME_NONE); g = adapter->buflist; @@ -1090,7 +1113,7 @@ gst_adapter_prev_pts_at_offset (GstAdapter * adapter, gsize offset, * gst_adapter_prev_dts_at_offset: * @adapter: a #GstAdapter * @offset: the offset in the adapter at which to get timestamp - * @distance: (out) (allow-none): pointer to location for distance, or NULL + * @distance: (out) (allow-none): pointer to location for distance, or %NULL * * Get the dts that was before the byte at offset @offset in the adapter. When * @distance is given, the amount of bytes between the dts and the current @@ -1114,7 +1137,6 @@ gst_adapter_prev_dts_at_offset (GstAdapter * adapter, gsize offset, GstClockTime dts = adapter->dts; g_return_val_if_fail (GST_IS_ADAPTER (adapter), GST_CLOCK_TIME_NONE); - g_return_val_if_fail (offset >= 0, GST_CLOCK_TIME_NONE); g = adapter->buflist; @@ -1270,7 +1292,7 @@ gst_adapter_masked_scan_uint32_peek (GstAdapter * adapter, guint32 mask, * It is an error to call this function without making sure that there is * enough data (offset+size bytes) in the adapter. * - * This function calls gst_adapter_masked_scan_uint32_peek() passing NULL + * This function calls gst_adapter_masked_scan_uint32_peek() passing %NULL * for value. * * Returns: offset of the first match, or -1 if no match was found. diff --git a/libs/gst/base/gstadapter.h b/libs/gst/base/gstadapter.h index 9683f3b..f82fbfb 100644 --- a/libs/gst/base/gstadapter.h +++ b/libs/gst/base/gstadapter.h @@ -56,6 +56,8 @@ gconstpointer gst_adapter_map (GstAdapter *adapter, gs void gst_adapter_unmap (GstAdapter *adapter); void gst_adapter_copy (GstAdapter *adapter, gpointer dest, gsize offset, gsize size); +GBytes * gst_adapter_copy_bytes (GstAdapter *adapter, + gsize offset, gsize size); void gst_adapter_flush (GstAdapter *adapter, gsize flush); gpointer gst_adapter_take (GstAdapter *adapter, gsize nbytes); GstBuffer* gst_adapter_take_buffer (GstAdapter *adapter, gsize nbytes); diff --git a/libs/gst/base/gstbaseparse.c b/libs/gst/base/gstbaseparse.c index ec01738..c3e63e1 100644 --- a/libs/gst/base/gstbaseparse.c +++ b/libs/gst/base/gstbaseparse.c @@ -50,22 +50,22 @@ * <listitem> * <itemizedlist><title>Set-up phase</title> * <listitem><para> - * GstBaseParse calls @start to inform subclass that data processing is + * #GstBaseParse calls @start to inform subclass that data processing is * about to start now. * </para></listitem> * <listitem><para> - * GstBaseParse class calls @set_sink_caps to inform the subclass about + * #GstBaseParse class calls @set_sink_caps to inform the subclass about * incoming sinkpad caps. Subclass could already set the srcpad caps * accordingly, but this might be delayed until calling * gst_base_parse_finish_frame() with a non-queued frame. * </para></listitem> * <listitem><para> - * At least at this point subclass needs to tell the GstBaseParse class + * At least at this point subclass needs to tell the #GstBaseParse class * how big data chunks it wants to receive (min_frame_size). It can do * this with gst_base_parse_set_min_frame_size(). * </para></listitem> * <listitem><para> - * GstBaseParse class sets up appropriate data passing mode (pull/push) + * #GstBaseParse class sets up appropriate data passing mode (pull/push) * and starts to process the data. * </para></listitem> * </itemizedlist> @@ -74,7 +74,7 @@ * <itemizedlist> * <title>Parsing phase</title> * <listitem><para> - * GstBaseParse gathers at least min_frame_size bytes of data either + * #GstBaseParse gathers at least min_frame_size bytes of data either * by pulling it from upstream or collecting buffers in an internal * #GstAdapter. * </para></listitem> @@ -101,7 +101,7 @@ * </para><para> * Subclass is also responsible for setting the buffer metadata * (e.g. buffer timestamp and duration, or keyframe if applicable). - * (although the latter can also be done by GstBaseParse if it is + * (although the latter can also be done by #GstBaseParse if it is * appropriately configured, see below). Frame is provided with * timestamp derived from upstream (as much as generally possible), * duration obtained from configuration (see below), and offset @@ -118,7 +118,7 @@ * events, or to perform custom (segment) filtering. * </para></listitem> * <listitem><para> - * During the parsing process GstBaseParseClass will handle both srcpad + * During the parsing process #GstBaseParseClass will handle both srcpad * and sinkpad events. They will be passed to subclass if @event or * @src_event callbacks have been provided. * </para></listitem> @@ -127,7 +127,7 @@ * <listitem> * <itemizedlist><title>Shutdown phase</title> * <listitem><para> - * GstBaseParse class calls @stop to inform the subclass that data + * #GstBaseParse class calls @stop to inform the subclass that data * parsing will be stopped. * </para></listitem> * </itemizedlist> @@ -139,12 +139,12 @@ * needs to set the fixed caps on srcpad, when the format is ensured (e.g. * when base class calls subclass' @set_sink_caps function). * - * This base class uses #GST_FORMAT_DEFAULT as a meaning of frames. So, + * This base class uses %GST_FORMAT_DEFAULT as a meaning of frames. So, * subclass conversion routine needs to know that conversion from - * #GST_FORMAT_TIME to #GST_FORMAT_DEFAULT must return the + * %GST_FORMAT_TIME to %GST_FORMAT_DEFAULT must return the * frame number that can be found from the given byte position. * - * GstBaseParse uses subclasses conversion methods also for seeking (or + * #GstBaseParse uses subclasses conversion methods also for seeking (or * otherwise uses its own default one, see also below). * * Subclass @start and @stop functions will be called to inform the beginning @@ -180,11 +180,11 @@ * <listitem><para> * In particular, if subclass is unable to determine a duration, but * parsing (or specs) yields a frames per seconds rate, then this can be - * provided to GstBaseParse to enable it to cater for + * provided to #GstBaseParse to enable it to cater for * buffer time metadata (which will be taken from upstream as much as * possible). Internally keeping track of frame durations and respective - * sizes that have been pushed provides GstBaseParse with an estimated - * bitrate. A default @convert (used if not overriden) will then use these + * sizes that have been pushed provides #GstBaseParse with an estimated + * bitrate. A default @convert (used if not overridden) will then use these * rates to perform obvious conversions. These rates are also used to * update (estimated) duration at regular frame intervals. * </para></listitem> @@ -561,11 +561,11 @@ gst_base_parse_class_init (GstBaseParseClass * klass) /** * GstBaseParse:disable-passthrough: * - * If set to #TRUE, baseparse will unconditionally force parsing of the + * If set to %TRUE, baseparse will unconditionally force parsing of the * incoming data. This can be required in the rare cases where the incoming * side-data (caps, pts, dts, ...) is not trusted by the user and wants to * force validation and parsing of the incoming data. - * If set to #FALSE, decision of whether to parse the data or not is up to + * If set to %FALSE, decision of whether to parse the data or not is up to * the implementation (standard behaviour). */ g_object_class_install_property (gobject_class, PROP_DISABLE_PASSTHROUGH, @@ -898,7 +898,7 @@ gst_base_parse_parse_frame (GstBaseParse * parse, GstBaseParseFrame * frame) * * Converts using configured "convert" vmethod in #GstBaseParse class. * - * Returns: TRUE if conversion was successful. + * Returns: %TRUE if conversion was successful. */ static gboolean gst_base_parse_convert (GstBaseParse * parse, @@ -949,7 +949,7 @@ gst_base_parse_convert (GstBaseParse * parse, * * Handler for sink pad events. * - * Returns: TRUE if the event was handled. + * Returns: %TRUE if the event was handled. */ static gboolean gst_base_parse_sink_event (GstPad * pad, GstObject * parent, GstEvent * event) @@ -1012,6 +1012,8 @@ gst_base_parse_sink_event_default (GstBaseParse * parse, GstEvent * event) gst_event_parse_segment (event, &in_segment); gst_segment_init (&out_segment, GST_FORMAT_TIME); + out_segment.rate = in_segment->rate; + out_segment.applied_rate = in_segment->applied_rate; GST_DEBUG_OBJECT (parse, "segment %" GST_SEGMENT_FORMAT, in_segment); @@ -1349,7 +1351,7 @@ gst_base_parse_src_query (GstPad * pad, GstObject * parent, GstQuery * query) * * Handler for source pad events. * - * Returns: TRUE if the event was handled. + * Returns: %TRUE if the event was handled. */ static gboolean gst_base_parse_src_event (GstPad * pad, GstObject * parent, GstEvent * event) @@ -1386,7 +1388,7 @@ gst_base_parse_is_seekable (GstBaseParse * parse) * * Default srcpad event handler. * - * Returns: TRUE if the event was handled and can be dropped. + * Returns: %TRUE if the event was handled and can be dropped. */ static gboolean gst_base_parse_src_event_default (GstBaseParse * parse, GstEvent * event) @@ -1417,7 +1419,7 @@ gst_base_parse_src_event_default (GstBaseParse * parse, GstEvent * event) * * Default implementation of "convert" vmethod in #GstBaseParse class. * - * Returns: TRUE if conversion was successful. + * Returns: %TRUE if conversion was successful. */ gboolean gst_base_parse_convert_default (GstBaseParse * parse, @@ -2502,6 +2504,7 @@ gst_base_parse_send_buffers (GstBaseParse * parse) GSList *send = NULL; GstBuffer *buf; GstFlowReturn ret = GST_FLOW_OK; + gboolean first = TRUE; send = parse->priv->buffers_send; @@ -2515,6 +2518,13 @@ gst_base_parse_send_buffers (GstBaseParse * parse) GST_TIME_ARGS (GST_BUFFER_PTS (buf)), GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), GST_BUFFER_OFFSET (buf)); + /* Make sure the first buffer is always DISCONT. If we split + * GOPs inside the parser this is otherwise not guaranteed */ + if (first) { + GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT); + first = FALSE; + } + /* iterate output queue an push downstream */ ret = gst_pad_push (parse->srcpad, buf); send = g_slist_delete_link (send, send); @@ -2670,8 +2680,10 @@ gst_base_parse_finish_fragment (GstBaseParse * parse, gboolean prev_head) parse->priv->buffers_queued); } - /* audio may have all marked as keyframe, so arrange to send here */ - if (!seen_delta) + /* audio may have all marked as keyframe, so arrange to send here. Also + * we might have ended the loop above on a keyframe, in which case we + * should */ + if (!seen_delta || seen_key) ret = gst_base_parse_send_buffers (parse); /* any trailing unused no longer usable (ideally none) */ @@ -3591,13 +3603,13 @@ gst_base_parse_set_pts_interpolation (GstBaseParse * parse, * By default, the base class might try to infer PTS from DTS and vice * versa. While this is generally correct for audio data, it may not * be otherwise. Sub-classes implementing such formats should disable - * timestamp infering. + * timestamp inferring. */ void gst_base_parse_set_infer_ts (GstBaseParse * parse, gboolean infer_ts) { parse->priv->infer_ts = infer_ts; - GST_INFO_OBJECT (parse, "TS infering: %s", (infer_ts) ? "yes" : "no"); + GST_INFO_OBJECT (parse, "TS inferring: %s", (infer_ts) ? "yes" : "no"); } /** @@ -4492,7 +4504,7 @@ gst_base_parse_change_state (GstElement * element, GstStateChange transition) * * This function should only be called from a @handle_frame implementation. * - * GstBaseParse creates initial timestamps for frames by using the last + * #GstBaseParse creates initial timestamps for frames by using the last * timestamp seen in the stream before the frame starts. In certain * cases, the correct timestamps will occur in the stream after the * start of the frame, but before the start of the actual picture data. @@ -4507,7 +4519,6 @@ gst_base_parse_set_ts_at_offset (GstBaseParse * parse, gsize offset) GstClockTime pts, dts; g_return_if_fail (GST_IS_BASE_PARSE (parse)); - g_return_if_fail (offset >= 0); pts = gst_adapter_prev_pts_at_offset (parse->priv->adapter, offset, NULL); dts = gst_adapter_prev_dts_at_offset (parse->priv->adapter, offset, NULL); diff --git a/libs/gst/base/gstbaseparse.h b/libs/gst/base/gstbaseparse.h index 7393770..f84d973 100644 --- a/libs/gst/base/gstbaseparse.h +++ b/libs/gst/base/gstbaseparse.h @@ -94,7 +94,7 @@ G_BEGIN_DECLS * that regular segment clipping can still be performed (as opposed to * any custom one having been done). * @GST_BASE_PARSE_FRAME_FLAG_DROP: indicates to @finish_frame that the - * the frame should be dropped (and might be handled internall by subclass) + * the frame should be dropped (and might be handled internally by subclass) * @GST_BASE_PARSE_FRAME_FLAG_QUEUE: indicates to @finish_frame that the * the frame should be queued for now and processed fully later * when the first non-queued frame is finished diff --git a/libs/gst/base/gstbasesink.c b/libs/gst/base/gstbasesink.c index 9fcacd6..b6fc1fc 100644 --- a/libs/gst/base/gstbasesink.c +++ b/libs/gst/base/gstbasesink.c @@ -44,7 +44,7 @@ * GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass); * * // sinktemplate should be a #GstStaticPadTemplate with direction - * // #GST_PAD_SINK and name "sink" + * // %GST_PAD_SINK and name "sink" * gst_element_class_add_pad_template (gstelement_class, * gst_static_pad_template_get (&sinktemplate)); * @@ -57,14 +57,14 @@ * ]| * * #GstBaseSink will handle the prerolling correctly. This means that it will - * return #GST_STATE_CHANGE_ASYNC from a state change to PAUSED until the first + * return %GST_STATE_CHANGE_ASYNC from a state change to PAUSED until the first * buffer arrives in this element. The base class will call the * #GstBaseSinkClass.preroll() vmethod with this preroll buffer and will then * commit the state change to the next asynchronously pending state. * * When the element is set to PLAYING, #GstBaseSink will synchronise on the * clock using the times returned from #GstBaseSinkClass.get_times(). If this - * function returns #GST_CLOCK_TIME_NONE for the start time, no synchronisation + * function returns %GST_CLOCK_TIME_NONE for the start time, no synchronisation * will be done. Synchronisation can be disabled entirely by setting the object * #GstBaseSink:sync property to %FALSE. * @@ -84,14 +84,14 @@ * element receives EOS in PAUSED, preroll completes, the event is queued and an * EOS message is posted when going to PLAYING. * - * #GstBaseSink will internally use the #GST_EVENT_SEGMENT events to schedule + * #GstBaseSink will internally use the %GST_EVENT_SEGMENT events to schedule * synchronisation and clipping of buffers. Buffers that fall completely outside * of the current segment are dropped. Buffers that fall partially in the * segment are rendered (and prerolled). Subclasses should do any subbuffer * clipping themselves when needed. * * #GstBaseSink will by default report the current playback position in - * #GST_FORMAT_TIME based on the current clock time and segment information. + * %GST_FORMAT_TIME based on the current clock time and segment information. * If no clock has been set on the element, the query will be forwarded * upstream. * @@ -105,7 +105,7 @@ * #GstBaseSinkClass.start() and #GstBaseSinkClass.stop() calls. * * The #GstBaseSinkClass.event() virtual method will be called when an event is - * received by #GstBaseSink. Normally this method should only be overriden by + * received by #GstBaseSink. Normally this method should only be overridden by * very specific elements (such as file sinks) which need to handle the * newsegment event specially. * @@ -138,8 +138,6 @@ * The #GstBaseSink:async property can be used to instruct the sink to never * perform an ASYNC state change. This feature is mostly usable when dealing * with non-synchronized streams or sparse streams. - * - * Last reviewed on 2007-08-29 (0.10.15) */ #ifdef HAVE_CONFIG_H @@ -279,7 +277,7 @@ struct _GstBaseSinkPrivate #define UPDATE_RUNNING_AVG(avg,val) DO_RUNNING_AVG(avg,val,8) /* the windows for these running averages are experimentally obtained. - * possitive values get averaged more while negative values use a small + * positive values get averaged more while negative values use a small * window so we can react faster to badness. */ #define UPDATE_RUNNING_AVG_P(avg,val) DO_RUNNING_AVG(avg,val,16) #define UPDATE_RUNNING_AVG_N(avg,val) DO_RUNNING_AVG(avg,val,4) @@ -444,8 +442,8 @@ gst_base_sink_class_init (GstBaseSinkClass * klass) /** * GstBaseSink:async: * - * If set to #TRUE, the basesink will perform asynchronous state changes. - * When set to #FALSE, the sink will not signal the parent when it prerolls. + * If set to %TRUE, the basesink will perform asynchronous state changes. + * When set to %FALSE, the sink will not signal the parent when it prerolls. * Use this option when dealing with sparse streams or when synchronisation is * not required. */ @@ -468,9 +466,9 @@ gst_base_sink_class_init (GstBaseSinkClass * klass) /** * GstBaseSink:enable-last-sample: * - * Enable the last-sample property. If FALSE, basesink doesn't keep a + * Enable the last-sample property. If %FALSE, basesink doesn't keep a * reference to the last buffer arrived and the last-sample property is always - * set to NULL. This can be useful if you need buffers to be released as soon + * set to %NULL. This can be useful if you need buffers to be released as soon * as possible, eg. if you're using a buffer pool. */ g_object_class_install_property (gobject_class, PROP_ENABLE_LAST_SAMPLE, @@ -483,7 +481,7 @@ gst_base_sink_class_init (GstBaseSinkClass * klass) * * The last buffer that arrived in the sink and was used for preroll or for * rendering. This property can be used to generate thumbnails. This property - * can be NULL when the sink has not yet received a bufer. + * can be %NULL when the sink has not yet received a buffer. */ g_object_class_install_property (gobject_class, PROP_LAST_SAMPLE, g_param_spec_boxed ("last-sample", "Last Sample", @@ -529,7 +527,7 @@ gst_base_sink_class_init (GstBaseSinkClass * klass) * Setting this property to a value bigger than 0 will make the sink delay * rendering of the buffers when it would exceed to max-bitrate. * - * Since: 1.1.1 + * Since: 1.2 */ g_object_class_install_property (gobject_class, PROP_MAX_BITRATE, g_param_spec_uint64 ("max-bitrate", "Max Bitrate", @@ -690,8 +688,8 @@ gst_base_sink_finalize (GObject * object) * @sync: the new sync value. * * Configures @sink to synchronize on the clock or not. When - * @sync is FALSE, incoming samples will be played as fast as - * possible. If @sync is TRUE, the timestamps of the incomming + * @sync is %FALSE, incoming samples will be played as fast as + * possible. If @sync is %TRUE, the timestamps of the incoming * buffers will be used to schedule the exact render time of its * contents. */ @@ -712,7 +710,7 @@ gst_base_sink_set_sync (GstBaseSink * sink, gboolean sync) * Checks if @sink is currently configured to synchronize against the * clock. * - * Returns: TRUE if the sink is configured to synchronize against the clock. + * Returns: %TRUE if the sink is configured to synchronize against the clock. */ gboolean gst_base_sink_get_sync (GstBaseSink * sink) @@ -795,7 +793,7 @@ gst_base_sink_set_qos_enabled (GstBaseSink * sink, gboolean enabled) * Checks if @sink is currently configured to send Quality-of-Service events * upstream. * - * Returns: TRUE if the sink is configured to perform Quality-of-Service. + * Returns: %TRUE if the sink is configured to perform Quality-of-Service. */ gboolean gst_base_sink_is_qos_enabled (GstBaseSink * sink) @@ -814,7 +812,7 @@ gst_base_sink_is_qos_enabled (GstBaseSink * sink) * @sink: the sink * @enabled: the new async value. * - * Configures @sink to perform all state changes asynchronusly. When async is + * Configures @sink to perform all state changes asynchronously. When async is * disabled, the sink will immediately go to PAUSED instead of waiting for a * preroll buffer. This feature is useful if the sink does not synchronize * against the clock or when it is dealing with sparse streams. @@ -837,7 +835,7 @@ gst_base_sink_set_async_enabled (GstBaseSink * sink, gboolean enabled) * Checks if @sink is currently configured to perform asynchronous state * changes to PAUSED. * - * Returns: TRUE if the sink is configured to perform asynchronous state + * Returns: %TRUE if the sink is configured to perform asynchronous state * changes. */ gboolean @@ -907,7 +905,7 @@ gst_base_sink_get_ts_offset (GstBaseSink * sink) * Free-function: gst_sample_unref * * Returns: (transfer full): a #GstSample. gst_sample_unref() after usage. - * This function returns NULL when no buffer has arrived in the sink yet + * This function returns %NULL when no buffer has arrived in the sink yet * or when the sink is not in PAUSED or PLAYING. */ GstSample * @@ -996,7 +994,7 @@ gst_base_sink_set_last_sample_enabled (GstBaseSink * sink, gboolean enabled) * Checks if @sink is currently configured to store the last received sample in * the last-sample property. * - * Returns: TRUE if the sink is configured to store the last received sample. + * Returns: %TRUE if the sink is configured to store the last received sample. */ gboolean gst_base_sink_is_last_sample_enabled (GstBaseSink * sink) @@ -1035,17 +1033,17 @@ gst_base_sink_get_latency (GstBaseSink * sink) * @max_latency: (out) (allow-none): the max latency of the upstream elements * * Query the sink for the latency parameters. The latency will be queried from - * the upstream elements. @live will be TRUE if @sink is configured to - * synchronize against the clock. @upstream_live will be TRUE if an upstream + * the upstream elements. @live will be %TRUE if @sink is configured to + * synchronize against the clock. @upstream_live will be %TRUE if an upstream * element is live. * - * If both @live and @upstream_live are TRUE, the sink will want to compensate + * If both @live and @upstream_live are %TRUE, the sink will want to compensate * for the latency introduced by the upstream elements by setting the - * @min_latency to a strictly possitive value. + * @min_latency to a strictly positive value. * * This function is mostly used by subclasses. * - * Returns: TRUE if the query succeeded. + * Returns: %TRUE if the query succeeded. */ gboolean gst_base_sink_query_latency (GstBaseSink * sink, gboolean * live, @@ -1280,7 +1278,7 @@ gst_base_sink_get_throttle_time (GstBaseSink * sink) * * Set the maximum amount of bits per second that the sink will render. * - * Since: 1.1.1 + * Since: 1.2 */ void gst_base_sink_set_max_bitrate (GstBaseSink * sink, guint64 max_bitrate) @@ -1301,7 +1299,7 @@ gst_base_sink_set_max_bitrate (GstBaseSink * sink, guint64 max_bitrate) * * Returns: the maximum number of bits per second @sink will render. * - * Since: 1.1.1 + * Since: 1.2 */ guint64 gst_base_sink_get_max_bitrate (GstBaseSink * sink) @@ -1528,8 +1526,8 @@ nothing_pending: /* Depending on the state, set our vars. We get in this situation when the * state change function got a change to update the state vars before the * streaming thread did. This is fine but we need to make sure that we - * update the need_preroll var since it was TRUE when we got here and might - * become FALSE if we got to PLAYING. */ + * update the need_preroll var since it was %TRUE when we got here and might + * become %FALSE if we got to PLAYING. */ GST_DEBUG_OBJECT (basesink, "nothing to commit, now in %s", gst_element_state_get_name (current)); switch (current) { @@ -1789,7 +1787,7 @@ handle_stepping (GstBaseSink * sink, GstSegment * segment, /* with STREAM_LOCK, PREROLL_LOCK * - * Returns TRUE if the object needs synchronisation and takes therefore + * Returns %TRUE if the object needs synchronisation and takes therefore * part in prerolling. * * rsstart/rsstop contain the start/stop in stream time. @@ -1981,7 +1979,7 @@ eos_done: out_of_segment: { /* we usually clip in the chain function already but stepping could cause - * the segment to be updated later. we return FALSE so that we don't try + * the segment to be updated later. we return %FALSE so that we don't try * to sync on it. */ GST_LOG_OBJECT (basesink, "buffer skipped, not in segment"); return FALSE; @@ -2002,7 +2000,7 @@ gst_base_sink_adjust_time (GstBaseSink * basesink, GstClockTime time) time += basesink->priv->latency; - /* apply offset, be carefull for underflows */ + /* apply offset, be careful for underflows */ ts_offset = basesink->priv->ts_offset; if (ts_offset < 0) { ts_offset = -ts_offset; @@ -2026,14 +2024,14 @@ gst_base_sink_adjust_time (GstBaseSink * basesink, GstClockTime time) * gst_base_sink_wait_clock: * @sink: the sink * @time: the running_time to be reached - * @jitter: (out) (allow-none): the jitter to be filled with time diff, or NULL + * @jitter: (out) (allow-none): the jitter to be filled with time diff, or %NULL * * This function will block until @time is reached. It is usually called by * subclasses that use their own internal synchronisation. * - * If @time is not valid, no sycnhronisation is done and #GST_CLOCK_BADTIME is + * If @time is not valid, no synchronisation is done and %GST_CLOCK_BADTIME is * returned. Likewise, if synchronisation is disabled in the element or there - * is no clock, no synchronisation is done and #GST_CLOCK_BADTIME is returned. + * is no clock, no synchronisation is done and %GST_CLOCK_BADTIME is returned. * * This function should only be called with the PREROLL_LOCK held, like when * receiving an EOS event in the #GstBaseSinkClass.event() vmethod or when @@ -2076,8 +2074,8 @@ gst_base_sink_wait_clock (GstBaseSink * sink, GstClockTime time, /* FIXME: Casting to GstClockEntry only works because the types * are the same */ if (G_LIKELY (sink->priv->cached_clock_id != NULL - && GST_CLOCK_ENTRY_CLOCK ((GstClockEntry *) sink->priv-> - cached_clock_id) == clock)) { + && GST_CLOCK_ENTRY_CLOCK ((GstClockEntry *) sink-> + priv->cached_clock_id) == clock)) { if (!gst_clock_single_shot_id_reinit (clock, sink->priv->cached_clock_id, time)) { gst_clock_id_unref (sink->priv->cached_clock_id); @@ -2134,14 +2132,14 @@ no_clock: * and call this method before continuing to render the remaining data. * * This function will block until a state change to PLAYING happens (in which - * case this function returns #GST_FLOW_OK) or the processing must be stopped due + * case this function returns %GST_FLOW_OK) or the processing must be stopped due * to a state change to READY or a FLUSH event (in which case this function - * returns #GST_FLOW_FLUSHING). + * returns %GST_FLOW_FLUSHING). * * This function should only be called with the PREROLL_LOCK held, like in the * render function. * - * Returns: #GST_FLOW_OK if the preroll completed and processing can + * Returns: %GST_FLOW_OK if the preroll completed and processing can * continue. Any other return value should be returned from the render vmethod. */ GstFlowReturn @@ -2186,7 +2184,7 @@ step_unlocked: * * This function should be called with the PREROLL_LOCK held. * - * Returns: #GST_FLOW_OK if the preroll completed and processing can + * Returns: %GST_FLOW_OK if the preroll completed and processing can * continue. Any other return value should be returned from the render vmethod. */ GstFlowReturn @@ -2276,7 +2274,7 @@ preroll_failed: * gst_base_sink_wait: * @sink: the sink * @time: the running_time to be reached - * @jitter: (out) (allow-none): the jitter to be filled with time diff, or NULL + * @jitter: (out) (allow-none): the jitter to be filled with time diff, or %NULL * * This function will wait for preroll to complete and will then block until @time * is reached. It is usually called by subclasses that use their own internal @@ -2362,7 +2360,7 @@ flushing: * immediately returns GST_FLOW_OK. * * for objects that arrive later than max-lateness to be synchronized to the - * clock have the @late boolean set to TRUE. + * clock have the @late boolean set to %TRUE. * * This function keeps a running average of the jitter (the diff between the * clock time and the requested sync time). The jitter is negative for @@ -2732,7 +2730,7 @@ gst_base_sink_reset_qos (GstBaseSink * sink) * * status and jitter contain the return values from the clock wait. * - * returns TRUE if the buffer was too late. + * returns %TRUE if the buffer was too late. */ static gboolean gst_base_sink_is_too_late (GstBaseSink * basesink, GstMiniObject * obj, @@ -2857,6 +2855,44 @@ gst_base_sink_do_render_stats (GstBaseSink * basesink, gboolean start) } static void +gst_base_sink_update_start_time (GstBaseSink * basesink) +{ + GstClock *clock; + + GST_OBJECT_LOCK (basesink); + if ((clock = GST_ELEMENT_CLOCK (basesink))) { + GstClockTime now; + + gst_object_ref (clock); + GST_OBJECT_UNLOCK (basesink); + + /* calculate the time when we stopped */ + now = gst_clock_get_time (clock); + gst_object_unref (clock); + + GST_OBJECT_LOCK (basesink); + /* store the current running time */ + if (GST_ELEMENT_START_TIME (basesink) != GST_CLOCK_TIME_NONE) { + if (now != GST_CLOCK_TIME_NONE) + GST_ELEMENT_START_TIME (basesink) = + now - GST_ELEMENT_CAST (basesink)->base_time; + else + GST_WARNING_OBJECT (basesink, + "Clock %s returned invalid time, can't calculate " + "running_time when going to the PAUSED state", + GST_OBJECT_NAME (clock)); + } + GST_DEBUG_OBJECT (basesink, + "start_time=%" GST_TIME_FORMAT ", now=%" GST_TIME_FORMAT + ", base_time %" GST_TIME_FORMAT, + GST_TIME_ARGS (GST_ELEMENT_START_TIME (basesink)), + GST_TIME_ARGS (now), + GST_TIME_ARGS (GST_ELEMENT_CAST (basesink)->base_time)); + } + GST_OBJECT_UNLOCK (basesink); +} + +static void gst_base_sink_flush_start (GstBaseSink * basesink, GstPad * pad) { /* make sure we are not blocked on the clock also clear any pending @@ -2872,6 +2908,7 @@ gst_base_sink_flush_start (GstBaseSink * basesink, GstPad * pad) * prerolled buffer */ basesink->playing_async = TRUE; if (basesink->priv->async_enabled) { + gst_base_sink_update_start_time (basesink); gst_element_lost_state (GST_ELEMENT_CAST (basesink)); } else { /* start time reset in above case as well; @@ -3236,7 +3273,7 @@ gst_base_sink_chain_unlocked (GstBaseSink * basesink, GstPad * pad, GstSegment *segment; GstBuffer *sync_buf; gint do_qos; - gboolean late, step_end; + gboolean late, step_end, prepared = FALSE; if (G_UNLIKELY (basesink->flushing)) goto flushing; @@ -3310,11 +3347,15 @@ gst_base_sink_chain_unlocked (GstBaseSink * basesink, GstPad * pad, gst_base_sink_get_sync_times (basesink, obj, &sstart, &sstop, &rstart, &rstop, &rnext, &do_sync, &stepped, current, &step_end); - if (!stepped && syncable && do_sync) + if (G_UNLIKELY (stepped)) + goto dropped; + + if (syncable && do_sync) late = gst_base_sink_is_too_late (basesink, obj, rstart, rstop, GST_CLOCK_EARLY, 0, FALSE); - if (late) + + if (G_UNLIKELY (late)) goto dropped; if (!is_list) { @@ -3330,6 +3371,8 @@ gst_base_sink_chain_unlocked (GstBaseSink * basesink, GstPad * pad, goto prepare_failed; } } + + prepared = TRUE; } again: @@ -3343,6 +3386,9 @@ again: if (G_UNLIKELY (ret != GST_FLOW_OK)) goto sync_failed; + /* Don't skip if prepare() was called on time */ + late = late && !prepared; + /* drop late buffers unconditionally, let's hope it's unlikely */ if (G_UNLIKELY (late)) goto dropped; @@ -3819,6 +3865,7 @@ gst_base_sink_perform_step (GstBaseSink * sink, GstPad * pad, GstEvent * event) sink->playing_async = TRUE; priv->pending_step.need_preroll = TRUE; sink->need_preroll = FALSE; + gst_base_sink_update_start_time (sink); gst_element_lost_state (GST_ELEMENT_CAST (sink)); } else { sink->priv->have_latency = TRUE; @@ -4128,7 +4175,7 @@ gst_base_sink_negotiate_pull (GstBaseSink * basesink) result = FALSE; /* this returns the intersection between our caps and the peer caps. If there - * is no peer, it returns NULL and we can't operate in pull mode so we can + * is no peer, it returns %NULL and we can't operate in pull mode so we can * fail the negotiation. */ caps = gst_pad_get_allowed_caps (GST_BASE_SINK_PAD (basesink)); if (caps == NULL || gst_caps_is_empty (caps)) @@ -4431,9 +4478,8 @@ gst_base_sink_get_position (GstBaseSink * basesink, GstFormat format, start = basesink->priv->current_sstart; stop = basesink->priv->current_sstop; - if (in_paused || last_seen) { - /* in paused or when we don't use the clock, we use the last position - * as a lower bound */ + if (last_seen) { + /* when we don't use the clock, we use the last position as a lower bound */ if (stop == -1 || segment->rate > 0.0) last = start; else @@ -4442,7 +4488,7 @@ gst_base_sink_get_position (GstBaseSink * basesink, GstFormat format, GST_DEBUG_OBJECT (basesink, "in PAUSED using last %" GST_TIME_FORMAT, GST_TIME_ARGS (last)); } else { - /* in playing, use last stop time as upper bound */ + /* in playing and paused, use last stop time as upper bound */ if (start == -1 || segment->rate > 0.0) last = stop; else @@ -4519,15 +4565,9 @@ gst_base_sink_get_position (GstBaseSink * basesink, GstFormat format, *cur = time + gst_guint64_to_gdouble (now - base_time) * rate; - if (in_paused) { - /* never report less than segment values in paused */ - if (last != -1) - *cur = MAX (last, *cur); - } else { - /* never report more than last seen position in playing */ - if (last != -1) - *cur = MIN (last, *cur); - } + /* never report more than last seen position */ + if (last != -1) + *cur = MIN (last, *cur); GST_DEBUG_OBJECT (basesink, "now %" GST_TIME_FORMAT " - base_time %" GST_TIME_FORMAT " - base %" @@ -4785,14 +4825,27 @@ gst_base_sink_default_query (GstBaseSink * basesink, GstQuery * query) gst_query_parse_accept_caps (query, &caps); allowed = gst_base_sink_query_caps (basesink, basesink->sinkpad, NULL); subset = gst_caps_is_subset (caps, allowed); + GST_DEBUG_OBJECT (basesink, "Checking if requested caps %" GST_PTR_FORMAT + " are a subset of pad caps %" GST_PTR_FORMAT " result %d", caps, + allowed, subset); gst_caps_unref (allowed); gst_query_set_accept_caps_result (query, subset); res = TRUE; break; } case GST_QUERY_DRAIN: + { + GstBuffer *old; + + GST_OBJECT_LOCK (basesink); + if ((old = basesink->priv->last_buffer)) + basesink->priv->last_buffer = gst_buffer_copy (old); + GST_OBJECT_UNLOCK (basesink); + if (old) + gst_buffer_unref (old); res = TRUE; break; + } default: res = gst_pad_query_default (basesink->sinkpad, GST_OBJECT_CAST (basesink), diff --git a/libs/gst/base/gstbasesink.h b/libs/gst/base/gstbasesink.h index 6f2ade7..d09b7e8 100644 --- a/libs/gst/base/gstbasesink.h +++ b/libs/gst/base/gstbasesink.h @@ -137,7 +137,7 @@ struct _GstBaseSink { * @preroll: Called to present the preroll buffer if desired. * @render: Called when a buffer should be presented or output, at the * correct moment if the #GstBaseSink has been set to sync to the clock. - * @render_list: Same as @render but used whith buffer lists instead of + * @render_list: Same as @render but used with buffer lists instead of * buffers. * * Subclasses can override any of the available virtual methods or not, as diff --git a/libs/gst/base/gstbasesrc.c b/libs/gst/base/gstbasesrc.c index dd55e32..eb861a3 100644 --- a/libs/gst/base/gstbasesrc.c +++ b/libs/gst/base/gstbasesrc.c @@ -25,7 +25,7 @@ * @short_description: Base class for getrange based source elements * @see_also: #GstPushSrc, #GstBaseTransform, #GstBaseSink * - * This is a generice base class for source elements. The following + * This is a generic base class for source elements. The following * types of sources are supported: * <itemizedlist> * <listitem><para>random access sources like files</para></listitem> @@ -35,13 +35,13 @@ * * The source can be configured to operate in any #GstFormat with the * gst_base_src_set_format() method. The currently set format determines - * the format of the internal #GstSegment and any #GST_EVENT_SEGMENT - * events. The default format for #GstBaseSrc is #GST_FORMAT_BYTES. + * the format of the internal #GstSegment and any %GST_EVENT_SEGMENT + * events. The default format for #GstBaseSrc is %GST_FORMAT_BYTES. * * #GstBaseSrc always supports push mode scheduling. If the following * conditions are met, it also supports pull mode scheduling: * <itemizedlist> - * <listitem><para>The format is set to #GST_FORMAT_BYTES (default).</para> + * <listitem><para>The format is set to %GST_FORMAT_BYTES (default).</para> * </listitem> * <listitem><para>#GstBaseSrcClass.is_seekable() returns %TRUE.</para> * </listitem> @@ -50,7 +50,7 @@ * If all the conditions are met for operating in pull mode, #GstBaseSrc is * automatically seekable in push mode as well. The following conditions must * be met to make the element seekable in push mode when the format is not - * #GST_FORMAT_BYTES: + * %GST_FORMAT_BYTES: * <itemizedlist> * <listitem><para> * #GstBaseSrcClass.is_seekable() returns %TRUE. @@ -82,7 +82,7 @@ * #GstBaseSrcClass.create() method will not be called in PAUSED but only in * PLAYING. To signal the pipeline that the element will not produce data, the * return value from the READY to PAUSED state will be - * #GST_STATE_CHANGE_NO_PREROLL. + * %GST_STATE_CHANGE_NO_PREROLL. * * A typical live source will timestamp the buffers it creates with the * current running time of the pipeline. This is one reason why a live source @@ -118,7 +118,7 @@ * { * GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass); * // srctemplate should be a #GstStaticPadTemplate with direction - * // #GST_PAD_SRC and name "src" + * // %GST_PAD_SRC and name "src" * gst_element_class_add_pad_template (gstelement_class, * gst_static_pad_template_get (&srctemplate)); * @@ -144,14 +144,12 @@ * * An application may send an EOS event to a source element to make it * perform the EOS logic (send EOS event downstream or post a - * #GST_MESSAGE_SEGMENT_DONE on the bus). This can typically be done + * %GST_MESSAGE_SEGMENT_DONE on the bus). This can typically be done * with the gst_element_send_event() function on the element or its parent bin. * * After the EOS has been sent to the element, the application should wait for * an EOS message to be posted on the pipeline's bus. Once this EOS message is * received, it may safely shut down the entire pipeline. - * - * Last reviewed on 2007-12-19 (0.10.16) * </para> * </refsect2> */ @@ -188,6 +186,12 @@ GST_DEBUG_CATEGORY_STATIC (gst_base_src_debug); #define GST_ASYNC_WAIT(elem) g_cond_wait (GST_ASYNC_GET_COND (elem), GST_OBJECT_GET_LOCK (elem)) #define GST_ASYNC_SIGNAL(elem) g_cond_signal (GST_ASYNC_GET_COND (elem)); +#define CLEAR_PENDING_EOS(bsrc) \ + G_STMT_START { \ + g_atomic_int_set (&bsrc->priv->has_pending_eos, FALSE); \ + gst_event_replace (&bsrc->priv->pending_eos, NULL); \ + } G_STMT_END + /* BaseSrc signals and args */ enum @@ -230,7 +234,11 @@ struct _GstBaseSrcPrivate guint32 segment_seqnum; /* if EOS is pending (atomic) */ - gint pending_eos; + GstEvent *pending_eos; + gint has_pending_eos; + + /* if the eos was caused by a forced eos from the application */ + gboolean forced_eos; /* startup latency is the time it takes between going to PLAYING and producing * the first BUFFER with running_time 0. This value is included in the latency @@ -242,6 +250,7 @@ struct _GstBaseSrcPrivate gboolean do_timestamp; volatile gint dynamic_size; + volatile gint automatic_eos; /* stream sequence number */ guint32 seqnum; @@ -425,6 +434,7 @@ gst_base_src_init (GstBaseSrc * basesrc, gpointer g_class) g_cond_init (&basesrc->live_cond); basesrc->num_buffers = DEFAULT_NUM_BUFFERS; basesrc->num_buffers_left = -1; + basesrc->priv->automatic_eos = TRUE; basesrc->can_activate_push = TRUE; @@ -496,11 +506,11 @@ gst_base_src_finalize (GObject * object) * and call this method before continuing to produce the remaining data. * * This function will block until a state change to PLAYING happens (in which - * case this function returns #GST_FLOW_OK) or the processing must be stopped due + * case this function returns %GST_FLOW_OK) or the processing must be stopped due * to a state change to READY or a FLUSH event (in which case this function - * returns #GST_FLOW_FLUSHING). + * returns %GST_FLOW_FLUSHING). * - * Returns: #GST_FLOW_OK if @src is PLAYING and processing can + * Returns: %GST_FLOW_OK if @src is PLAYING and processing can * continue. Any other return value should be returned from the create vmethod. */ GstFlowReturn @@ -582,7 +592,7 @@ gst_base_src_is_live (GstBaseSrc * src) * for sending SEGMENT events and for performing seeks. * * If a format of GST_FORMAT_BYTES is set, the element will be able to - * operate in pull mode if the #GstBaseSrcClass.is_seekable() returns TRUE. + * operate in pull mode if the #GstBaseSrcClass.is_seekable() returns %TRUE. * * This function must only be called in states < %GST_STATE_PAUSED. */ @@ -615,6 +625,26 @@ gst_base_src_set_dynamic_size (GstBaseSrc * src, gboolean dynamic) } /** + * gst_base_src_set_automatic_eos: + * @src: base source instance + * @automatic_eos: automatic eos + * + * If @automatic_eos is %TRUE, basesrc will automatically go EOS if a buffer + * after the total size is returned. By default this is %TRUE but sources + * that can't return an authoritative size and only know that they're EOS + * when trying to read more should set this to %FALSE. + * + * Since: 1.4 + */ +void +gst_base_src_set_automatic_eos (GstBaseSrc * src, gboolean automatic_eos) +{ + g_return_if_fail (GST_IS_BASE_SRC (src)); + + g_atomic_int_set (&src->priv->automatic_eos, automatic_eos); +} + +/** * gst_base_src_set_async: * @src: base source instance * @async: new async mode @@ -664,14 +694,14 @@ gst_base_src_is_async (GstBaseSrc * src) * @min_latency: (out) (allow-none): the min latency of the source * @max_latency: (out) (allow-none): the max latency of the source * - * Query the source for the latency parameters. @live will be TRUE when @src is + * Query the source for the latency parameters. @live will be %TRUE when @src is * configured as a live source. @min_latency will be set to the difference * between the running time and the timestamp of the first buffer. * @max_latency is always the undefined value of -1. * * This function is mostly used by subclasses. * - * Returns: TRUE if the query succeeded. + * Returns: %TRUE if the query succeeded. */ gboolean gst_base_src_query_latency (GstBaseSrc * src, gboolean * live, @@ -763,6 +793,8 @@ gst_base_src_set_do_timestamp (GstBaseSrc * src, gboolean timestamp) GST_OBJECT_LOCK (src); src->priv->do_timestamp = timestamp; + if (timestamp && src->segment.format != GST_FORMAT_TIME) + gst_segment_init (&src->segment, GST_FORMAT_TIME); GST_OBJECT_UNLOCK (src); } @@ -793,7 +825,7 @@ gst_base_src_get_do_timestamp (GstBaseSrc * src) * @src: The source * @start: The new start value for the segment * @stop: Stop value for the new segment - * @time: The new time value for the start of the new segent + * @time: The new time value for the start of the new segment * * Prepare a new seamless segment for emission downstream. This function must * only be called by derived sub-classes, and only from the create() function, @@ -1727,7 +1759,12 @@ gst_base_src_send_event (GstElement * element, GstEvent * event) GST_LIVE_LOCK (src); src->priv->flushing = TRUE; /* clear pending EOS if any */ - g_atomic_int_set (&src->priv->pending_eos, FALSE); + if (g_atomic_int_get (&src->priv->has_pending_eos)) { + GST_OBJECT_LOCK (src); + CLEAR_PENDING_EOS (src); + src->priv->forced_eos = FALSE; + GST_OBJECT_UNLOCK (src); + } if (bclass->unlock_stop) bclass->unlock_stop (src); if (src->clock_id) @@ -1768,18 +1805,24 @@ gst_base_src_send_event (GstElement * element, GstEvent * event) * * We have two possibilities: * - * - Before we are to enter the _create function, we check the pending_eos + * - Before we are to enter the _create function, we check the has_pending_eos * first and do EOS instead of entering it. * - If we are in the _create function or we did not manage to set the * flag fast enough and we are about to enter the _create function, * we unlock it so that we exit with FLUSHING immediately. We then * check the EOS flag and do the EOS logic. */ - g_atomic_int_set (&src->priv->pending_eos, TRUE); - GST_DEBUG_OBJECT (src, "EOS marked, calling unlock"); + GST_OBJECT_LOCK (src); + g_atomic_int_set (&src->priv->has_pending_eos, TRUE); + if (src->priv->pending_eos) + gst_event_unref (src->priv->pending_eos); + src->priv->pending_eos = event; + event = NULL; + GST_OBJECT_UNLOCK (src); + GST_DEBUG_OBJECT (src, "EOS marked, calling unlock"); - /* unlock the _create function so that we can check the pending_eos flag + /* unlock the _create function so that we can check the has_pending_eos flag * and we can do EOS. This will eventually release the LIVE_LOCK again so * that we can grab it and stop the unlock again. We don't take the stream * lock so that this operation is guaranteed to never block. */ @@ -2185,7 +2228,11 @@ gst_base_src_do_sync (GstBaseSrc * basesrc, GstBuffer * buffer) if (do_timestamp) { dts = running_time; } else { - dts = 0; + if (GST_CLOCK_TIME_IS_VALID (basesrc->segment.start)) { + dts = basesrc->segment.start; + } else { + dts = 0; + } } GST_BUFFER_DTS (buffer) = dts; @@ -2277,10 +2324,14 @@ gst_base_src_update_length (GstBaseSrc * src, guint64 offset, guint * length, if (format != GST_FORMAT_BYTES) return TRUE; - /* the max amount of bytes to read is the total size or - * up to the segment.stop if present. */ - if (stop != -1) - maxsize = MIN (size, stop); + /* when not doing automatic EOS, just use the stop position. We don't use + * the size to check for EOS */ + if (!g_atomic_int_get (&src->priv->automatic_eos)) + maxsize = stop; + /* Otherwise, the max amount of bytes to read is the total + * size or up to the segment.stop if present. */ + else if (stop != -1) + maxsize = size != -1 ? MIN (size, stop) : stop; else maxsize = size; @@ -2317,8 +2368,8 @@ gst_base_src_update_length (GstBaseSrc * src, guint64 offset, guint * length, } } - /* keep track of current duration. - * segment is in bytes, we checked that above. */ + /* keep track of current duration. segment is in bytes, we checked + * that above. */ GST_OBJECT_LOCK (src); src->segment.duration = size; GST_OBJECT_UNLOCK (src); @@ -2379,9 +2430,11 @@ again: } /* don't enter the create function if a pending EOS event was set. For the - * logic of the pending_eos, check the event function of this class. */ - if (G_UNLIKELY (g_atomic_int_get (&src->priv->pending_eos))) + * logic of the has_pending_eos, check the event function of this class. */ + if (G_UNLIKELY (g_atomic_int_get (&src->priv->has_pending_eos))) { + src->priv->forced_eos = TRUE; goto eos; + } GST_DEBUG_OBJECT (src, "calling create offset %" G_GUINT64_FORMAT " length %u, time %" @@ -2394,11 +2447,12 @@ again: /* The create function could be unlocked because we have a pending EOS. It's * possible that we have a valid buffer from create that we need to * discard when the create function returned _OK. */ - if (G_UNLIKELY (g_atomic_int_get (&src->priv->pending_eos))) { + if (G_UNLIKELY (g_atomic_int_get (&src->priv->has_pending_eos))) { if (ret == GST_FLOW_OK) { if (*buf == NULL) gst_buffer_unref (res_buf); } + src->priv->forced_eos = TRUE; goto eos; } @@ -2628,10 +2682,12 @@ gst_base_src_loop (GstPad * pad) if (gst_pad_check_reconfigure (pad)) { if (!gst_base_src_negotiate (src)) { gst_pad_mark_reconfigure (pad); - if (GST_PAD_IS_FLUSHING (pad)) + if (GST_PAD_IS_FLUSHING (pad)) { + GST_LIVE_LOCK (src); goto flushing; - else + } else { goto negotiate_failed; + } } } @@ -2786,7 +2842,9 @@ gst_base_src_loop (GstPad * pad) goto pause; } - if (G_UNLIKELY (eos)) { + /* Segment pending means that a new segment was configured + * during this loop run */ + if (G_UNLIKELY (eos && !src->priv->segment_pending)) { GST_INFO_OBJECT (src, "pausing after end of segment"); ret = GST_FLOW_EOS; goto pause; @@ -2831,12 +2889,19 @@ pause: GstFormat format; gint64 position; - /* perform EOS logic */ flag_segment = (src->segment.flags & GST_SEGMENT_FLAG_SEGMENT) != 0; format = src->segment.format; position = src->segment.position; - if (flag_segment) { + /* perform EOS logic */ + if (src->priv->forced_eos) { + g_assert (g_atomic_int_get (&src->priv->has_pending_eos)); + GST_OBJECT_LOCK (src); + event = src->priv->pending_eos; + src->priv->pending_eos = NULL; + GST_OBJECT_UNLOCK (src); + + } else if (flag_segment) { GstMessage *message; message = gst_message_new_segment_done (GST_OBJECT_CAST (src), @@ -2845,12 +2910,15 @@ pause: gst_element_post_message (GST_ELEMENT_CAST (src), message); event = gst_event_new_segment_done (format, position); gst_event_set_seqnum (event, src->priv->seqnum); - gst_pad_push_event (pad, event); + } else { event = gst_event_new_eos (); gst_event_set_seqnum (event, src->priv->seqnum); - gst_pad_push_event (pad, event); } + + gst_pad_push_event (pad, event); + src->priv->forced_eos = FALSE; + } else if (ret == GST_FLOW_NOT_LINKED || ret <= GST_FLOW_EOS) { event = gst_event_new_eos (); gst_event_set_seqnum (event, src->priv->seqnum); @@ -2987,7 +3055,25 @@ gst_base_src_decide_allocation_default (GstBaseSrc * basesrc, GstQuery * query) config = gst_buffer_pool_get_config (pool); gst_buffer_pool_config_set_params (config, outcaps, size, min, max); gst_buffer_pool_config_set_allocator (config, allocator, ¶ms); - gst_buffer_pool_set_config (pool, config); + + /* buffer pool may have to do some changes */ + if (!gst_buffer_pool_set_config (pool, config)) { + config = gst_buffer_pool_get_config (pool); + + /* If change are not acceptable, fallback to generic pool */ + if (!gst_buffer_pool_config_validate_params (config, outcaps, size, min, + max)) { + GST_DEBUG_OBJECT (basesrc, "unsuported pool, making new pool"); + + gst_object_unref (pool); + pool = gst_buffer_pool_new (); + gst_buffer_pool_config_set_params (config, outcaps, size, min, max); + gst_buffer_pool_config_set_allocator (config, allocator, ¶ms); + } + + if (!gst_buffer_pool_set_config (pool, config)) + goto config_failed; + } } if (update_allocator) @@ -3003,6 +3089,12 @@ gst_base_src_decide_allocation_default (GstBaseSrc * basesrc, GstQuery * query) } return TRUE; + +config_failed: + GST_ELEMENT_ERROR (basesrc, RESOURCE, SETTINGS, + ("Failed to configure the buffer pool"), + ("Configuration is most likely invalid, please report this issue.")); + return FALSE; } static gboolean @@ -3191,6 +3283,7 @@ gst_base_src_start (GstBaseSrc * basesrc) basesrc->running = FALSE; basesrc->priv->segment_pending = FALSE; basesrc->priv->segment_seqnum = gst_util_seqnum_next (); + basesrc->priv->forced_eos = FALSE; GST_LIVE_UNLOCK (basesrc); bclass = GST_BASE_SRC_GET_CLASS (basesrc); @@ -3305,24 +3398,30 @@ gst_base_src_start_complete (GstBaseSrc * basesrc, GstFlowReturn ret) /* take the stream lock here, we only want to let the task run when we have * set the STARTED flag */ GST_PAD_STREAM_LOCK (basesrc->srcpad); - if (mode == GST_PAD_MODE_PUSH) { - /* do initial seek, which will start the task */ - GST_OBJECT_LOCK (basesrc); - event = basesrc->pending_seek; - basesrc->pending_seek = NULL; - GST_OBJECT_UNLOCK (basesrc); - - /* The perform seek code will start the task when finished. We don't have to - * unlock the streaming thread because it is not running yet */ - if (G_UNLIKELY (!gst_base_src_perform_seek (basesrc, event, FALSE))) - goto seek_failed; - - if (event) - gst_event_unref (event); - } else { - /* if not random_access, we cannot operate in pull mode for now */ - if (G_UNLIKELY (!basesrc->random_access)) - goto no_get_range; + switch (mode) { + case GST_PAD_MODE_PUSH: + /* do initial seek, which will start the task */ + GST_OBJECT_LOCK (basesrc); + event = basesrc->pending_seek; + basesrc->pending_seek = NULL; + GST_OBJECT_UNLOCK (basesrc); + + /* The perform seek code will start the task when finished. We don't have to + * unlock the streaming thread because it is not running yet */ + if (G_UNLIKELY (!gst_base_src_perform_seek (basesrc, event, FALSE))) + goto seek_failed; + + if (event) + gst_event_unref (event); + break; + case GST_PAD_MODE_PULL: + /* if not random_access, we cannot operate in pull mode for now */ + if (G_UNLIKELY (!basesrc->random_access)) + goto no_get_range; + break; + default: + goto not_activated_yet; + break; } GST_OBJECT_LOCK (basesrc); @@ -3354,6 +3453,14 @@ no_get_range: ret = GST_FLOW_ERROR; goto error; } +not_activated_yet: + { + GST_PAD_STREAM_UNLOCK (basesrc->srcpad); + gst_base_src_stop (basesrc); + GST_WARNING_OBJECT (basesrc, "pad not activated yet"); + ret = GST_FLOW_ERROR; + goto error; + } error: { GST_OBJECT_LOCK (basesrc); @@ -3461,7 +3568,12 @@ gst_base_src_set_flushing (GstBaseSrc * basesrc, basesrc->live_running = TRUE; /* clear pending EOS if any */ - g_atomic_int_set (&basesrc->priv->pending_eos, FALSE); + if (g_atomic_int_get (&basesrc->priv->has_pending_eos)) { + GST_OBJECT_LOCK (basesrc); + CLEAR_PENDING_EOS (basesrc); + basesrc->priv->forced_eos = FALSE; + GST_OBJECT_UNLOCK (basesrc); + } /* step 1, now that we have the LIVE lock, clear our unlock request */ if (bclass->unlock_stop) @@ -3632,6 +3744,8 @@ gst_base_src_activate_mode (GstPad * pad, GstObject * parent, src->priv->stream_start_pending = FALSE; + GST_DEBUG_OBJECT (pad, "activating in mode %d", mode); + switch (mode) { case GST_PAD_MODE_PULL: res = gst_base_src_activate_pull (pad, parent, active); @@ -3693,7 +3807,11 @@ gst_base_src_change_state (GstElement * element, GstStateChange transition) { /* we don't need to unblock anything here, the pad deactivation code * already did this */ - g_atomic_int_set (&basesrc->priv->pending_eos, FALSE); + if (g_atomic_int_get (&basesrc->priv->has_pending_eos)) { + GST_OBJECT_LOCK (basesrc); + CLEAR_PENDING_EOS (basesrc); + GST_OBJECT_UNLOCK (basesrc); + } gst_event_replace (&basesrc->pending_seek, NULL); break; } @@ -3740,7 +3858,7 @@ gst_base_src_get_buffer_pool (GstBaseSrc * src) * @allocator: (out) (allow-none) (transfer full): the #GstAllocator * used * @params: (out) (allow-none) (transfer full): the - * #GstAllocatorParams of @allocator + * #GstAllocationParams of @allocator * * Lets #GstBaseSrc sub-classes to know the memory @allocator * used by the base class and its @params. diff --git a/libs/gst/base/gstbasesrc.h b/libs/gst/base/gstbasesrc.h index 9afd5e0..75de438 100644 --- a/libs/gst/base/gstbasesrc.h +++ b/libs/gst/base/gstbasesrc.h @@ -129,28 +129,31 @@ struct _GstBaseSrc { * these times. * @get_size: Return the total size of the resource, in the configured format. * @is_seekable: Check if the source can seek - * @prepare_seek_segment: Prepare the GstSegment that will be passed to the - * do_seek vmethod for executing a seek request. Sub-classes should override - * this if they support seeking in formats other than the configured native - * format. By default, it tries to convert the seek arguments to the - * configured native format and prepare a segment in that format. + * @prepare_seek_segment: Prepare the #GstSegment that will be passed to the + * #GstBaseSrcClass.do_seek() vmethod for executing a seek + * request. Sub-classes should override this if they support seeking in + * formats other than the configured native format. By default, it tries to + * convert the seek arguments to the configured native format and prepare a + * segment in that format. * @do_seek: Perform seeking on the resource to the indicated segment. - * @unlock: Unlock any pending access to the resource. Subclasses should - * unblock any blocked function ASAP. In particular, any create() function in + * @unlock: Unlock any pending access to the resource. Subclasses should unblock + * any blocked function ASAP. In particular, any create() function in * progress should be unblocked and should return GST_FLOW_FLUSHING. Any - * future @create<!-- -->() function call should also return GST_FLOW_FLUSHING - * until the @unlock_stop<!-- -->() function has been called. - * @unlock_stop: Clear the previous unlock request. Subclasses should clear - * any state they set during unlock(), such as clearing command queues. + * future #GstBaseSrcClass.create() function call should also return + * GST_FLOW_FLUSHING until the #GstBaseSrcClass.unlock_stop() function has + * been called. + * @unlock_stop: Clear the previous unlock request. Subclasses should clear any + * state they set during #GstBaseSrcClass.unlock(), such as clearing command + * queues. * @query: Handle a requested query. * @event: Override this to implement custom event handling. - * @create: Ask the subclass to create a buffer with offset and size. - * When the subclass returns GST_FLOW_OK, it MUST return a buffer of the - * requested size unless fewer bytes are available because an EOS condition - * is near. No buffer should be returned when the return value is different - * from GST_FLOW_OK. A return value of GST_FLOW_EOS signifies that the - * end of stream is reached. The default implementation will call @alloc and - * then call @fill. + * @create: Ask the subclass to create a buffer with offset and size. When the + * subclass returns GST_FLOW_OK, it MUST return a buffer of the requested size + * unless fewer bytes are available because an EOS condition is near. No + * buffer should be returned when the return value is different from + * GST_FLOW_OK. A return value of GST_FLOW_EOS signifies that the end of + * stream is reached. The default implementation will call + * #GstBaseSrcClass.alloc() and then call #GstBaseSrcClass.fill(). * @alloc: Ask the subclass to allocate a buffer with for offset and size. The * default implementation will create a new buffer from the negotiated allocator. * @fill: Ask the subclass to fill the buffer with data for offset and size. The @@ -239,6 +242,8 @@ void gst_base_src_set_format (GstBaseSrc *src, GstFormat format void gst_base_src_set_dynamic_size (GstBaseSrc * src, gboolean dynamic); +void gst_base_src_set_automatic_eos (GstBaseSrc * src, gboolean automatic_eos); + void gst_base_src_set_async (GstBaseSrc *src, gboolean async); gboolean gst_base_src_is_async (GstBaseSrc *src); diff --git a/libs/gst/base/gstbasetransform.c b/libs/gst/base/gstbasetransform.c index 8e28154..c20a613 100644 --- a/libs/gst/base/gstbasetransform.c +++ b/libs/gst/base/gstbasetransform.c @@ -57,14 +57,14 @@ * intact. * </para></listitem> * <listitem><para> - * On the GstBaseTransformClass is the passthrough_on_same_caps variable - * which will automatically set/unset passthrough based on whether the + * The #GstBaseTransformClass.passthrough_on_same_caps variable + * will automatically set/unset passthrough based on whether the * element negotiates the same caps on both pads. * </para></listitem> * <listitem><para> - * passthrough_on_same_caps on an element that doesn't implement a - * transform_caps function is useful for elements that only inspect data - * (such as level) + * #GstBaseTransformClass.passthrough_on_same_caps on an element that + * doesn't implement a transform_caps function is useful for elements that + * only inspect data (such as level) * </para></listitem> * </itemizedlist> * <itemizedlist> @@ -94,7 +94,7 @@ * immediately. </para></listitem> * <listitem><para> * only implementing transform_ip and not transform implies always_in_place - * = TRUE + * = %TRUE * </para></listitem> * </itemizedlist> * <itemizedlist> @@ -116,7 +116,7 @@ * <listitem><para> * Elements wishing to operate in this mode should replace the * prepare_output_buffer method to create subbuffers of the input buffer - * and set always_in_place to TRUE + * and set always_in_place to %TRUE * </para></listitem> * </itemizedlist> * <itemizedlist> @@ -185,10 +185,10 @@ * to the transform_ip function. * </para></listitem> * <listitem><para> - * Implied TRUE if no transform function is implemented. + * Implied %TRUE if no transform function is implemented. * </para></listitem> * <listitem><para> - * Implied FALSE if ONLY transform function is implemented. + * Implied %FALSE if ONLY transform function is implemented. * </para></listitem> * </itemizedlist> * </para></listitem> @@ -844,7 +844,7 @@ gst_base_transform_default_decide_allocation (GstBaseTransform * trans, /* by default we remove all metadata, subclasses should implement a * filter_meta function */ - if (gst_meta_api_type_has_tag (api, GST_META_TAG_MEMORY)) { + if (gst_meta_api_type_has_tag (api, _gst_meta_tag_memory)) { /* remove all memory dependent metadata because we are going to have to * allocate different memory for input and output. */ GST_LOG_OBJECT (trans, "removing memory specific metadata %s", @@ -899,7 +899,25 @@ gst_base_transform_default_decide_allocation (GstBaseTransform * trans, config = gst_buffer_pool_get_config (pool); gst_buffer_pool_config_set_params (config, outcaps, size, min, max); gst_buffer_pool_config_set_allocator (config, allocator, ¶ms); - gst_buffer_pool_set_config (pool, config); + + /* buffer pool may have to do some changes */ + if (!gst_buffer_pool_set_config (pool, config)) { + config = gst_buffer_pool_get_config (pool); + + /* If change are not acceptable, fallback to generic pool */ + if (!gst_buffer_pool_config_validate_params (config, outcaps, size, min, + max)) { + GST_DEBUG_OBJECT (trans, "unsuported pool, making new pool"); + + gst_object_unref (pool); + pool = gst_buffer_pool_new (); + gst_buffer_pool_config_set_params (config, outcaps, size, min, max); + gst_buffer_pool_config_set_allocator (config, allocator, ¶ms); + } + + if (!gst_buffer_pool_set_config (pool, config)) + goto config_failed; + } } if (update_allocator) @@ -915,6 +933,12 @@ gst_base_transform_default_decide_allocation (GstBaseTransform * trans, } return TRUE; + +config_failed: + GST_ELEMENT_ERROR (trans, RESOURCE, SETTINGS, + ("Failed to configure the buffer pool"), + ("Configuration is most likely invalid, please report this issue.")); + return FALSE; } static gboolean @@ -1433,16 +1457,15 @@ gst_base_transform_default_query (GstBaseTransform * trans, case GST_QUERY_ALLOCATION: { GstQuery *decide_query = NULL; - gboolean negotiated; /* can only be done on the sinkpad */ if (direction != GST_PAD_SINK) goto done; GST_OBJECT_LOCK (trans); - if (G_UNLIKELY (!(negotiated = priv->negotiated))) { + if (!priv->negotiated && !priv->passthrough && (klass->set_caps != NULL)) { GST_DEBUG_OBJECT (trans, - "not negotiated yet, can't answer ALLOCATION query"); + "not negotiated yet but need negotiation, can't answer ALLOCATION query"); GST_OBJECT_UNLOCK (trans); goto done; } @@ -1558,7 +1581,7 @@ default_prepare_output_buffer (GstBaseTransform * trans, /* figure out how to allocate an output buffer */ if (priv->passthrough) { - /* passthrough, we will not modify the incomming buffer so we can just + /* passthrough, we will not modify the incoming buffer so we can just * reuse it */ GST_DEBUG_OBJECT (trans, "passthrough: reusing input buffer"); *outbuf = inbuf; @@ -1682,7 +1705,7 @@ foreach_metadata (GstBuffer * inbuf, GstMeta ** meta, gpointer user_data) GST_DEBUG_OBJECT (trans, "not copying pooled metadata %s", g_type_name (info->api)); do_copy = FALSE; - } else if (gst_meta_api_type_has_tag (info->api, GST_META_TAG_MEMORY)) { + } else if (gst_meta_api_type_has_tag (info->api, _gst_meta_tag_memory)) { /* never call the transform_meta with memory specific metadata */ GST_DEBUG_OBJECT (trans, "not copying memory specific metadata %s", g_type_name (info->api)); @@ -1694,7 +1717,7 @@ foreach_metadata (GstBuffer * inbuf, GstMeta ** meta, gpointer user_data) } /* we only copy metadata when the subclass implemented a transform_meta - * function and when it returns TRUE */ + * function and when it returns %TRUE */ if (do_copy) { GstMetaTransformCopy copy_data = { FALSE, 0, -1 }; GST_DEBUG_OBJECT (trans, "copy metadata %s", g_type_name (info->api)); @@ -1755,7 +1778,7 @@ not_writable: * We have two cache locations to store the size, one for the source caps * and one for the sink caps. * - * this function returns FALSE if no size could be calculated. + * this function returns %FALSE if no size could be calculated. */ static gboolean gst_base_transform_get_unit_size (GstBaseTransform * trans, GstCaps * caps, @@ -2416,7 +2439,7 @@ gst_base_transform_src_activate_mode (GstPad * pad, GstObject * parent, * 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 + * Always %TRUE for filters which don't implement either a transform * or transform_ip method. * * MT safe. @@ -2449,7 +2472,7 @@ gst_base_transform_set_passthrough (GstBaseTransform * trans, * * See if @trans is configured as a passthrough transform. * - * Returns: TRUE is the transform is configured in passthrough mode. + * Returns: %TRUE is the transform is configured in passthrough mode. * * MT safe. */ @@ -2476,8 +2499,8 @@ gst_base_transform_is_passthrough (GstBaseTransform * trans) * Determines whether a non-writable buffer will be copied before passing * to the transform_ip function. * <itemizedlist> - * <listitem>Always TRUE if no transform function is implemented.</listitem> - * <listitem>Always FALSE if ONLY transform function is implemented.</listitem> + * <listitem>Always %TRUE if no transform function is implemented.</listitem> + * <listitem>Always %FALSE if ONLY transform function is implemented.</listitem> * </itemizedlist> * * MT safe. @@ -2514,7 +2537,7 @@ gst_base_transform_set_in_place (GstBaseTransform * trans, gboolean in_place) * * See if @trans is configured as a in_place transform. * - * Returns: TRUE is the transform is configured in in_place mode. + * Returns: %TRUE is the transform is configured in in_place mode. * * MT safe. */ @@ -2589,7 +2612,7 @@ gst_base_transform_set_qos_enabled (GstBaseTransform * trans, gboolean enabled) * * Queries if the transform will handle QoS. * - * Returns: TRUE if QoS is enabled. + * Returns: %TRUE if QoS is enabled. * * MT safe. */ @@ -2642,7 +2665,7 @@ gst_base_transform_set_gap_aware (GstBaseTransform * trans, gboolean gap_aware) * transform_caps vmethod. * * If set to %FALSE, the element must order the caps returned from the - * transform_caps function in such a way that the prefered format is + * transform_caps function in such a way that the preferred format is * first in the list. This can be interesting for transforms that can do * passthrough transforms but prefer to do something else, like a * capsfilter. @@ -2722,7 +2745,7 @@ gst_base_transform_get_buffer_pool (GstBaseTransform * trans) * @allocator: (out) (allow-none) (transfer full): the #GstAllocator * used * @params: (out) (allow-none) (transfer full): the - * #GstAllocatorParams of @allocator + * #GstAllocationParams of @allocator * * Lets #GstBaseTransform sub-classes to know the memory @allocator * used by the base class and its @params. diff --git a/libs/gst/base/gstbasetransform.h b/libs/gst/base/gstbasetransform.h index 3330503..3043a62 100644 --- a/libs/gst/base/gstbasetransform.h +++ b/libs/gst/base/gstbasetransform.h @@ -129,16 +129,16 @@ struct _GstBaseTransform { * downstream allocation query. This function is only called * when not operating in passthrough mode. The default * implementation will remove all memory dependent metadata. - * If there is ia @filter_meta method implementation, it will + * If there is a @filter_meta method implementation, it will * be called for all metadata API in the downstream query, * otherwise the metadata API is removed. - * @filter_meta: Return TRUE if the metadata API should be proposed in the - * upstream allocation query. The default implementation is NULL + * @filter_meta: Return %TRUE if the metadata API should be proposed in the + * upstream allocation query. The default implementation is %NULL * and will cause all metadata to be removed. * @propose_allocation: Propose buffer allocation parameters for upstream elements. * This function must be implemented if the element reads or * writes the buffer content. The query that was passed to - * the decide_allocation is passed in this method (or NULL + * the decide_allocation is passed in this method (or %NULL * when the element is in passthrough mode). The default * implementation will pass the query downstream when in * passthrough mode and will copy all the filtered metadata @@ -176,9 +176,9 @@ struct _GstBaseTransform { * The default implementation will copy the flags, timestamps and * offsets of the buffer. * @transform_meta: Optional. Transform the metadata on the input buffer to the - * output buffer. By default this method is NULL and no + * output buffer. By default this method is %NULL and no * metadata is copied. subclasses can implement this method and - * return TRUE if the metadata is to be copied. + * return %TRUE if the metadata is to be copied. * @before_transform: Optional. * This method is called right before the base class will * start processing. Dynamic properties or other delayed diff --git a/libs/gst/base/gstbytereader.c b/libs/gst/base/gstbytereader.c index a5f9e40..b73a679 100644 --- a/libs/gst/base/gstbytereader.c +++ b/libs/gst/base/gstbytereader.c @@ -775,23 +775,21 @@ gst_byte_reader_dup_data (GstByteReader * reader, guint size, guint8 ** val) static inline gint _scan_for_start_code (const guint8 * data, guint offset, guint size) { - guint i = 0; - - while (i <= (size - 4)) { - if (data[i + 2] > 1) { - i += 3; - } else if (data[i + 1]) { - i += 2; - } else if (data[i] || data[i + 2] != 1) { - i++; + guint8 *pdata = (guint8 *) data; + guint8 *pend = (guint8 *) (data + size - 4); + + while (pdata <= pend) { + if (pdata[2] > 1) { + pdata += 3; + } else if (pdata[1]) { + pdata += 2; + } else if (pdata[0] || pdata[2] != 1) { + pdata++; } else { - break; + return (pdata - data + offset); } } - if (i <= (size - 4)) - return i + offset; - /* nothing found */ return -1; } @@ -986,7 +984,7 @@ GST_BYTE_READER_SKIP_STRING (32); * gst_byte_reader_peek_string: * @reader: a #GstByteReader instance * @str: (out) (transfer none) (array zero-terminated=1): address of a - * #gchar pointer varieble in which to store the result + * #gchar pointer variable in which to store the result * * Returns a constant pointer to the current data position if there is * a NUL-terminated string in the data (this could be just a NUL terminator). @@ -1002,7 +1000,7 @@ GST_BYTE_READER_SKIP_STRING (32); * gst_byte_reader_peek_string_utf8: * @reader: a #GstByteReader instance * @str: (out) (transfer none) (array zero-terminated=1): address of a - * #gchar pointer varieble in which to store the result + * #gchar pointer variable in which to store the result * * Returns a constant pointer to the current data position if there is * a NUL-terminated string in the data (this could be just a NUL terminator). @@ -1035,7 +1033,7 @@ gst_byte_reader_peek_string_utf8 (const GstByteReader * reader, * gst_byte_reader_get_string_utf8: * @reader: a #GstByteReader instance * @str: (out) (transfer none) (array zero-terminated=1): address of a - * #gchar pointer varieble in which to store the result + * #gchar pointer variable in which to store the result * * Returns a constant pointer to the current data position if there is * a NUL-terminated string in the data (this could be just a NUL terminator), @@ -1091,7 +1089,7 @@ gst_byte_reader_dup_string_utf##bits (GstByteReader * reader, type ** str) \ * gst_byte_reader_dup_string_utf8: * @reader: a #GstByteReader instance * @str: (out) (transfer full) (array zero-terminated=1): address of a - * #gchar pointer varieble in which to store the result + * #gchar pointer variable in which to store the result * * Free-function: g_free * @@ -1111,7 +1109,7 @@ GST_BYTE_READER_DUP_STRING (8, gchar); * gst_byte_reader_dup_string_utf16: * @reader: a #GstByteReader instance * @str: (out) (transfer full) (array zero-terminated=1): address of a - * #guint16 pointer varieble in which to store the result + * #guint16 pointer variable in which to store the result * * Free-function: g_free * @@ -1137,7 +1135,7 @@ GST_BYTE_READER_DUP_STRING (16, guint16); * gst_byte_reader_dup_string_utf32: * @reader: a #GstByteReader instance * @str: (out) (transfer full) (array zero-terminated=1): address of a - * #guint32 pointer varieble in which to store the result + * #guint32 pointer variable in which to store the result * * Free-function: g_free * diff --git a/libs/gst/base/gstbytereader.h b/libs/gst/base/gstbytereader.h index 6ed0296..8745ef6 100644 --- a/libs/gst/base/gstbytereader.h +++ b/libs/gst/base/gstbytereader.h @@ -333,6 +333,9 @@ __GST_BYTE_READER_GET_PEEK_BITS_INLINE(64,gdouble,float64_be) #ifndef GST_BYTE_READER_DISABLE_INLINES +#define gst_byte_reader_init(reader,data,size) \ + _gst_byte_reader_init_inline(reader,data,size) + #define gst_byte_reader_get_remaining(reader) \ _gst_byte_reader_get_remaining_inline(reader) @@ -436,6 +439,16 @@ __GST_BYTE_READER_GET_PEEK_BITS_INLINE(64,gdouble,float64_be) #endif /* GST_BYTE_READER_DISABLE_INLINES */ +static inline void +_gst_byte_reader_init_inline (GstByteReader * reader, const guint8 * data, guint size) +{ + g_return_if_fail (reader != NULL); + + reader->data = data; + reader->size = size; + reader->byte = 0; +} + static inline gboolean _gst_byte_reader_dup_data_inline (GstByteReader * reader, guint size, guint8 ** val) { diff --git a/libs/gst/base/gstbytewriter-docs.h b/libs/gst/base/gstbytewriter-docs.h index 562eeae..3cc5962 100644 --- a/libs/gst/base/gstbytewriter-docs.h +++ b/libs/gst/base/gstbytewriter-docs.h @@ -258,8 +258,9 @@ void gst_byte_writer_put_data_unchecked (GstByteWriter *writer, const guint8 *da /** * gst_byte_writer_fill_unchecked: * @writer: #GstByteWriter instance - * @value: Value to be writen - * @size: Number of bytes to be writen + * @value: Value to be written + * @size: Number of bytes to be written + * * Writes @size bytes containing @value to @writer without * checking if there is enough free space available in the byte writer. diff --git a/libs/gst/base/gstbytewriter.c b/libs/gst/base/gstbytewriter.c index 2d99480..a30dac6 100644 --- a/libs/gst/base/gstbytewriter.c +++ b/libs/gst/base/gstbytewriter.c @@ -661,8 +661,8 @@ CREATE_WRITE_STRING_FUNC (32, guint32); /** * gst_byte_writer_fill: * @writer: #GstByteWriter instance - * @value: Value to be writen - * @size: Number of bytes to be writen + * @value: Value to be written + * @size: Number of bytes to be written * * Writes @size bytes containing @value to @writer. * diff --git a/libs/gst/base/gstcollectpads.c b/libs/gst/base/gstcollectpads.c index a30e10a..8f97b71 100644 --- a/libs/gst/base/gstcollectpads.c +++ b/libs/gst/base/gstcollectpads.c @@ -49,8 +49,8 @@ * <listitem><para> * Data can be dequeued from the pad with the gst_collect_pads_pop() method. * One can peek at the data with the gst_collect_pads_peek() function. - * These functions will return NULL if the pad received an EOS event. When all - * pads return NULL from a gst_collect_pads_peek(), the element can emit an EOS + * These functions will return %NULL if the pad received an EOS event. When all + * pads return %NULL from a gst_collect_pads_peek(), the element can emit an EOS * event itself. * </para></listitem> * <listitem><para> @@ -65,19 +65,12 @@ * no pad is blocked and the element can finish streaming. * </para></listitem> * <listitem><para> - * gst_collect_pads_collect() and gst_collect_pads_collect_range() can be used by - * elements that start a #GstTask to drive the collect_pads. This feature is however - * not yet implemented. - * </para></listitem> - * <listitem><para> * gst_collect_pads_set_waiting() sets a pad to waiting or non-waiting mode. * CollectPads element is not waiting for data to be collected on non-waiting pads. * Thus these pads may but need not have data when the callback is called. * All pads are in waiting mode by default. * </para></listitem> * </itemizedlist> - * - * Last reviewed on 2011-10-28 (0.10.36) */ #ifdef HAVE_CONFIG_H @@ -132,11 +125,17 @@ struct _GstCollectPadsPrivate gpointer query_user_data; GstCollectPadsClipFunction clip_func; gpointer clip_user_data; + GstCollectPadsFlushFunction flush_func; + gpointer flush_user_data; /* no other lock needed */ GMutex evt_lock; /* these make up sort of poor man's event signaling */ GCond evt_cond; guint32 evt_cookie; + + gboolean seeking; + gboolean pending_flush_start; + gboolean pending_flush_stop; }; static void gst_collect_pads_clear (GstCollectPads * pads, @@ -260,6 +259,13 @@ gst_collect_pads_init (GstCollectPads * pads) g_mutex_init (&pads->priv->evt_lock); g_cond_init (&pads->priv->evt_cond); pads->priv->evt_cookie = 0; + + pads->priv->seeking = FALSE; + pads->priv->pending_flush_start = FALSE; + pads->priv->pending_flush_stop = FALSE; + + /* clear floating flag */ + gst_object_ref_sink (pads); } static void @@ -290,7 +296,7 @@ gst_collect_pads_finalize (GObject * object) * * MT safe. * - * Returns: (transfer full): a new #GstCollectPads, or NULL in case of an error. + * Returns: (transfer full): a new #GstCollectPads, or %NULL in case of an error. */ GstCollectPads * gst_collect_pads_new (void) @@ -318,7 +324,7 @@ gst_collect_pads_set_buffer_function_locked (GstCollectPads * pads, * @user_data: (closure): user data passed to the function * * Set the callback function and user data that will be called with - * the oldest buffer when all pads have been collected, or NULL on EOS. + * the oldest buffer when all pads have been collected, or %NULL on EOS. * If a buffer is passed, the callback owns a reference and must unref * it. * @@ -522,7 +528,7 @@ gst_collect_pads_clip_running_time (GstCollectPads * pads, return GST_FLOW_OK; } - /** +/** * gst_collect_pads_set_clip_function: * @pads: the collectpads to use * @clipfunc: clip function to install @@ -543,6 +549,29 @@ gst_collect_pads_set_clip_function (GstCollectPads * pads, } /** + * gst_collect_pads_set_flush_function: + * @pads: the collectpads to use + * @func: flush function to install + * @user_data: user data to pass to @func + * + * Install a flush function that is called when the internal + * state of all pads should be flushed as part of flushing seek + * handling. See #GstCollectPadsFlushFunction for more info. + * + * Since: 1.4 + */ +void +gst_collect_pads_set_flush_function (GstCollectPads * pads, + GstCollectPadsFlushFunction func, gpointer user_data) +{ + g_return_if_fail (pads != NULL); + g_return_if_fail (GST_IS_COLLECT_PADS (pads)); + + pads->priv->flush_func = func; + pads->priv->flush_user_data = user_data; +} + +/** * gst_collect_pads_add_pad: * @pads: the collectpads to use * @pad: (transfer none): the pad to add @@ -577,7 +606,7 @@ gst_collect_pads_set_clip_function (GstCollectPads * pads, * * MT safe. * - * Returns: a new #GstCollectData to identify the new pad. Or NULL + * Returns: a new #GstCollectData to identify the new pad. Or %NULL * if wrong parameters are supplied. */ GstCollectData * @@ -895,7 +924,7 @@ gst_collect_pads_stop (GstCollectPads * pads) * * MT safe. * - * Returns: The buffer in @data or NULL if no buffer is queued. + * Returns: The buffer in @data or %NULL if no buffer is queued. * should unref the buffer after usage. */ GstBuffer * @@ -927,7 +956,7 @@ gst_collect_pads_peek (GstCollectPads * pads, GstCollectData * data) * * MT safe. * - * Returns: (transfer full): The buffer in @data or NULL if no buffer was + * Returns: (transfer full): The buffer in @data or %NULL if no buffer was * queued. You should unref the buffer after usage. */ GstBuffer * @@ -1095,7 +1124,7 @@ gst_collect_pads_flush (GstCollectPads * pads, GstCollectData * data, * MT safe. * * Returns: (transfer full): A sub buffer. The size of the buffer can be less that requested. - * A return of NULL signals that the pad is end-of-stream. + * A return of %NULL signals that the pad is end-of-stream. * Unref the buffer after use. */ GstBuffer * @@ -1134,7 +1163,7 @@ gst_collect_pads_read_buffer (GstCollectPads * pads, GstCollectData * data, * MT safe. * * Returns: A sub buffer. The size of the buffer can be less that requested. - * A return of NULL signals that the pad is end-of-stream. + * A return of %NULL signals that the pad is end-of-stream. * Unref the buffer after use. */ GstBuffer * @@ -1285,6 +1314,10 @@ gst_collect_pads_check_collected (GstCollectPads * pads) GST_DEBUG_OBJECT (pads, "All active pads (%d) are EOS, calling %s", pads->priv->numpads, GST_DEBUG_FUNCPTR_NAME (func)); + if (G_UNLIKELY (g_atomic_int_compare_and_exchange (&pads->priv->seeking, + TRUE, FALSE) == TRUE)) { + GST_INFO_OBJECT (pads, "finished seeking"); + } do { flow_ret = func (pads, user_data); } while (flow_ret == GST_FLOW_OK); @@ -1299,6 +1332,10 @@ gst_collect_pads_check_collected (GstCollectPads * pads) pads->priv->queuedpads, pads->priv->eospads, pads->priv->numpads, GST_DEBUG_FUNCPTR_NAME (func)); + if (G_UNLIKELY (g_atomic_int_compare_and_exchange (&pads->priv->seeking, + TRUE, FALSE) == TRUE)) { + GST_INFO_OBJECT (pads, "finished seeking"); + } flow_ret = func (pads, user_data); collected = TRUE; @@ -1329,7 +1366,7 @@ gst_collect_pads_check_collected (GstCollectPads * pads) * * Must be called with STREAM_LOCK. * - * Returns TRUE if a pad was set to waiting + * Returns %TRUE if a pad was set to waiting * (from non-waiting state). */ static gboolean @@ -1602,7 +1639,7 @@ gst_collect_pads_clip_time (GstCollectPads * pads, GstCollectData * data, * @event: event being processed * @discard: process but do not send event downstream * - * Default GstCollectPads event handling that elements should always + * Default #GstCollectPads event handling that elements should always * chain up to to ensure proper operation. Element might however indicate * event should not be forwarded downstream. */ @@ -1625,33 +1662,59 @@ gst_collect_pads_event_default (GstCollectPads * pads, GstCollectData * data, switch (GST_EVENT_TYPE (event)) { case GST_EVENT_FLUSH_START: { - /* forward event to unblock check_collected */ - GST_DEBUG_OBJECT (pad, "forwarding flush start"); - res = gst_pad_event_default (pad, parent, event); - event = NULL; - - /* now unblock the chain function. - * no cond per pad, so they all unblock, - * non-flushing block again */ - GST_COLLECT_PADS_STREAM_LOCK (pads); - GST_COLLECT_PADS_STATE_SET (data, GST_COLLECT_PADS_STATE_FLUSHING); - gst_collect_pads_clear (pads, data); - - /* cater for possible default muxing functionality */ - if (buffer_func) { - /* restore to initial state */ - gst_collect_pads_set_waiting (pads, data, TRUE); - /* if the current pad is affected, reset state, recalculate later */ - if (pads->priv->earliest_data == data) { - unref_data (data); - pads->priv->earliest_data = NULL; - pads->priv->earliest_time = GST_CLOCK_TIME_NONE; + if (g_atomic_int_get (&pads->priv->seeking)) { + /* drop all but the first FLUSH_STARTs when seeking */ + if (g_atomic_int_compare_and_exchange (&pads->priv->pending_flush_start, + TRUE, FALSE) == FALSE) + goto eat; + + /* unblock collect pads */ + gst_pad_event_default (pad, parent, event); + event = NULL; + + GST_COLLECT_PADS_STREAM_LOCK (pads); + /* Start flushing. We never call gst_collect_pads_set_flushing (FALSE), we + * instead wait until each pad gets its FLUSH_STOP and let that reset the pad to + * non-flushing (which happens in gst_collect_pads_event_default). + */ + gst_collect_pads_set_flushing (pads, TRUE); + + if (pads->priv->flush_func) + pads->priv->flush_func (pads, pads->priv->flush_user_data); + + g_atomic_int_set (&pads->priv->pending_flush_stop, TRUE); + GST_COLLECT_PADS_STREAM_UNLOCK (pads); + + goto eat; + } else { + /* forward event to unblock check_collected */ + GST_DEBUG_OBJECT (pad, "forwarding flush start"); + res = gst_pad_event_default (pad, parent, event); + event = NULL; + + /* now unblock the chain function. + * no cond per pad, so they all unblock, + * non-flushing block again */ + GST_COLLECT_PADS_STREAM_LOCK (pads); + GST_COLLECT_PADS_STATE_SET (data, GST_COLLECT_PADS_STATE_FLUSHING); + gst_collect_pads_clear (pads, data); + + /* cater for possible default muxing functionality */ + if (buffer_func) { + /* restore to initial state */ + gst_collect_pads_set_waiting (pads, data, TRUE); + /* if the current pad is affected, reset state, recalculate later */ + if (pads->priv->earliest_data == data) { + unref_data (data); + pads->priv->earliest_data = NULL; + pads->priv->earliest_time = GST_CLOCK_TIME_NONE; + } } - } - GST_COLLECT_PADS_STREAM_UNLOCK (pads); + GST_COLLECT_PADS_STREAM_UNLOCK (pads); - goto eat; + goto eat; + } } case GST_EVENT_FLUSH_STOP: { @@ -1669,12 +1732,22 @@ gst_collect_pads_event_default (GstCollectPads * pads, GstCollectData * data, if (!GST_COLLECT_PADS_STATE_IS_SET (data, GST_COLLECT_PADS_STATE_WAITING)) pads->priv->queuedpads++; - pads->priv->eospads--; + if (!g_atomic_int_get (&pads->priv->seeking)) { + pads->priv->eospads--; + } GST_COLLECT_PADS_STATE_UNSET (data, GST_COLLECT_PADS_STATE_EOS); } GST_COLLECT_PADS_STREAM_UNLOCK (pads); - goto forward; + if (g_atomic_int_get (&pads->priv->seeking)) { + if (g_atomic_int_compare_and_exchange (&pads->priv->pending_flush_stop, + TRUE, FALSE)) + goto forward; + else + goto eat; + } else { + goto forward; + } } case GST_EVENT_EOS: { @@ -1777,6 +1850,99 @@ forward: return gst_pad_event_default (pad, parent, event); } +typedef struct +{ + GstEvent *event; + gboolean result; +} EventData; + +static gboolean +event_forward_func (GstPad * pad, EventData * data) +{ + gboolean ret = TRUE; + GstPad *peer = gst_pad_get_peer (pad); + + if (peer) { + ret = gst_pad_send_event (peer, gst_event_ref (data->event)); + gst_object_unref (peer); + } + + data->result &= ret; + /* Always send to all pads */ + return FALSE; +} + +static gboolean +forward_event_to_all_sinkpads (GstPad * srcpad, GstEvent * event) +{ + EventData data; + + data.event = event; + data.result = TRUE; + + gst_pad_forward (srcpad, (GstPadForwardFunction) event_forward_func, &data); + + gst_event_unref (event); + + return data.result; +} + +/** + * gst_collect_pads_src_event_default: + * @pads: the collectpads to use + * @pad: src #GstPad that received the event + * @event: event being processed + * + * Default #GstCollectPads event handling for the src pad of elements. + * Elements can chain up to this to let flushing seek event handling + * be done by GstCollectPads. + * + * Since: 1.4 + */ +gboolean +gst_collect_pads_src_event_default (GstCollectPads * pads, GstPad * pad, + GstEvent * event) +{ + GstObject *parent; + gboolean res = TRUE; + + parent = GST_OBJECT_PARENT (pad); + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_SEEK:{ + GstSeekFlags flags; + + pads->priv->eospads = 0; + + GST_INFO_OBJECT (pads, "starting seek"); + + gst_event_parse_seek (event, NULL, NULL, &flags, NULL, NULL, NULL, NULL); + if (flags & GST_SEEK_FLAG_FLUSH) { + g_atomic_int_set (&pads->priv->seeking, TRUE); + g_atomic_int_set (&pads->priv->pending_flush_start, TRUE); + /* forward the seek upstream */ + res = forward_event_to_all_sinkpads (pad, event); + event = NULL; + if (!res) { + g_atomic_int_set (&pads->priv->seeking, FALSE); + g_atomic_int_set (&pads->priv->pending_flush_start, FALSE); + } + } + + GST_INFO_OBJECT (pads, "seek done, result: %d", res); + + break; + } + default: + break; + } + + if (event) + res = gst_pad_event_default (pad, parent, event); + + return res; +} + static gboolean gst_collect_pads_event_default_internal (GstCollectPads * pads, GstCollectData * data, GstEvent * event, gpointer user_data) @@ -1844,7 +2010,7 @@ pad_removed: * @query: query being processed * @discard: process but do not send event downstream * - * Default GstCollectPads query handling that elements should always + * Default #GstCollectPads query handling that elements should always * chain up to to ensure proper operation. Element might however indicate * query should not be forwarded downstream. */ diff --git a/libs/gst/base/gstcollectpads.h b/libs/gst/base/gstcollectpads.h index 4c99d58..0ba2dee 100644 --- a/libs/gst/base/gstcollectpads.h +++ b/libs/gst/base/gstcollectpads.h @@ -134,27 +134,27 @@ struct _GstCollectData /** * GstCollectPadsFunction: - * @pads: the #GstCollectPads that trigered the callback + * @pads: the #GstCollectPads that triggered 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 + * Returns: %GST_FLOW_OK for success */ typedef GstFlowReturn (*GstCollectPadsFunction) (GstCollectPads *pads, gpointer user_data); /** * GstCollectPadsBufferFunction: - * @pads: the #GstCollectPads that trigered the callback + * @pads: the #GstCollectPads that triggered the callback * @data: the #GstCollectData of pad that has received the buffer * @buffer: (transfer full): the #GstBuffer * @user_data: user data passed to gst_collect_pads_set_buffer_function() * * A function that will be called when a (considered oldest) buffer can be muxed. - * If all pads have reached EOS, this function is called with NULL @buffer - * and NULL @data. + * If all pads have reached EOS, this function is called with %NULL @buffer + * and %NULL @data. * - * Returns: #GST_FLOW_OK for success + * Returns: %GST_FLOW_OK for success */ typedef GstFlowReturn (*GstCollectPadsBufferFunction) (GstCollectPads *pads, GstCollectData *data, GstBuffer *buffer, gpointer user_data); @@ -172,7 +172,7 @@ typedef GstFlowReturn (*GstCollectPadsBufferFunction) (GstCollectPads *pads, Gst * * Returns: Integer less than zero when first timestamp is deemed older than the second one. * Zero if the timestamps are deemed equally old. - * Integer greate than zero when second timestamp is deemed older than the first one. + * Integer greater than zero when second timestamp is deemed older than the first one. */ typedef gint (*GstCollectPadsCompareFunction) (GstCollectPads *pads, GstCollectData * data1, GstClockTime timestamp1, @@ -181,7 +181,7 @@ typedef gint (*GstCollectPadsCompareFunction) (GstCollectPads *pads, /** * GstCollectPadsEventFunction: - * @pads: the #GstCollectPads that trigered the callback + * @pads: the #GstCollectPads that triggered the callback * @pad: the #GstPad that received an event * @event: the #GstEvent received * @user_data: user data passed to gst_collect_pads_set_event_function() @@ -199,7 +199,7 @@ typedef gboolean (*GstCollectPadsEventFunction) (GstCollectPads *pads, Gs /** * GstCollectPadsQueryFunction: - * @pads: the #GstCollectPads that trigered the callback + * @pads: the #GstCollectPads that triggered the callback * @pad: the #GstPad that received an event * @query: the #GstEvent received * @user_data: user data passed to gst_collect_pads_set_query_function() @@ -222,7 +222,7 @@ typedef gboolean (*GstCollectPadsQueryFunction) (GstCollectPads *pads, Gs * @user_data: user data * * A function that will be called when @inbuffer is received on the pad managed - * by @data in the collecpad object @pads. + * by @data in the collectpad object @pads. * * The function should use the segment of @data and the negotiated media type on * the pad to perform clipping of @inbuffer. @@ -236,6 +236,23 @@ typedef GstFlowReturn (*GstCollectPadsClipFunction) (GstCollectPads *pads, GstCo GstBuffer *inbuffer, GstBuffer **outbuffer, gpointer user_data); + +/** + * GstCollectPadsFlushFunction: + * @pads: a #GstCollectPads + * @user_data: user data + * + * A function that will be called while processing a flushing seek event. + * + * The function should flush any internal state of the element and the state of + * all the pads. It should clear only the state not directly managed by the + * @pads object. It is therefore not necessary to call + * gst_collect_pads_set_flushing nor gst_collect_pads_clear from this function. + * + * Since: 1.4 + */ +typedef void (*GstCollectPadsFlushFunction) (GstCollectPads *pads, gpointer user_data); + /** * GST_COLLECT_PADS_GET_STREAM_LOCK: * @pads: a #GstCollectPads @@ -311,6 +328,9 @@ void gst_collect_pads_set_compare_function (GstCollectPads *pads, void gst_collect_pads_set_clip_function (GstCollectPads *pads, GstCollectPadsClipFunction clipfunc, gpointer user_data); +void gst_collect_pads_set_flush_function (GstCollectPads *pads, + GstCollectPadsFlushFunction func, + gpointer user_data); /* pad management */ GstCollectData* gst_collect_pads_add_pad (GstCollectPads *pads, GstPad *pad, guint size, @@ -349,6 +369,8 @@ GstFlowReturn gst_collect_pads_clip_running_time (GstCollectPads * pads, /* default handlers */ gboolean gst_collect_pads_event_default (GstCollectPads * pads, GstCollectData * data, GstEvent * event, gboolean discard); +gboolean gst_collect_pads_src_event_default (GstCollectPads * pads, GstPad * pad, + GstEvent * event); gboolean gst_collect_pads_query_default (GstCollectPads * pads, GstCollectData * data, GstQuery * query, gboolean discard); diff --git a/libs/gst/base/gstdataqueue.c b/libs/gst/base/gstdataqueue.c index 0c46f0c..e34b265 100644 --- a/libs/gst/base/gstdataqueue.c +++ b/libs/gst/base/gstdataqueue.c @@ -209,12 +209,13 @@ gst_data_queue_init (GstDataQueue * queue) } /** - * gst_data_queue_new: + * gst_data_queue_new: (skip) * @checkfull: the callback used to tell if the element considers the queue full * or not. * @fullcallback: the callback which will be called when the queue is considered full. * @emptycallback: the callback which will be called when the queue is considered empty. - * @checkdata: a #gpointer that will be given in the @checkfull callback. + * @checkdata: a #gpointer that will be passed to the @checkfull, @fullcallback, + * and @emptycallback callbacks. * * Creates a new #GstDataQueue. The difference with @gst_data_queue_new is that it will * not emit the 'full' and 'empty' signals, but instead calling directly @fullcallback @@ -222,7 +223,7 @@ gst_data_queue_init (GstDataQueue * queue) * * Returns: a new #GstDataQueue. * - * Since: 1.2.0 + * Since: 1.2 */ GstDataQueue * gst_data_queue_new (GstDataQueueCheckFullFunction checkfull, @@ -318,7 +319,7 @@ gst_data_queue_locked_is_full (GstDataQueue * queue) * #gst_data_queue_pop will be released. * MT safe. * - * Since: 1.2.0 + * Since: 1.2 */ void gst_data_queue_flush (GstDataQueue * queue) @@ -336,9 +337,9 @@ gst_data_queue_flush (GstDataQueue * queue) * Queries if there are any items in the @queue. * MT safe. * - * Returns: #TRUE if @queue is empty. + * Returns: %TRUE if @queue is empty. * - * Since: 1.2.0 + * Since: 1.2 */ gboolean gst_data_queue_is_empty (GstDataQueue * queue) @@ -360,9 +361,9 @@ gst_data_queue_is_empty (GstDataQueue * queue) * #GstDataQueueCheckFullFunction registered with @queue. * MT safe. * - * Returns: #TRUE if @queue is full. + * Returns: %TRUE if @queue is full. * - * Since: 1.2.0 + * Since: 1.2 */ gboolean gst_data_queue_is_full (GstDataQueue * queue) @@ -381,15 +382,15 @@ gst_data_queue_is_full (GstDataQueue * queue) * @queue: a #GstDataQueue. * @flushing: a #gboolean stating if the queue will be flushing or not. * - * Sets the queue to flushing state if @flushing is #TRUE. If set to flushing + * Sets the queue to flushing state if @flushing is %TRUE. If set to flushing * state, any incoming data on the @queue will be discarded. Any call currently * blocking on #gst_data_queue_push or #gst_data_queue_pop will return straight - * away with a return value of #FALSE. While the @queue is in flushing state, - * all calls to those two functions will return #FALSE. + * away with a return value of %FALSE. While the @queue is in flushing state, + * all calls to those two functions will return %FALSE. * * MT Safe. * - * Since: 1.2.0 + * Since: 1.2 */ void gst_data_queue_set_flushing (GstDataQueue * queue, gboolean flushing) @@ -436,12 +437,12 @@ gst_data_queue_push_force_unlocked (GstDataQueue * queue, * * Note that this function has slightly different semantics than gst_pad_push() * and gst_pad_push_event(): this function only takes ownership of @item and - * the #GstMiniObject contained in @item if the push was successful. If FALSE + * the #GstMiniObject contained in @item if the push was successful. If %FALSE * is returned, the caller is responsible for freeing @item and its contents. * - * Returns: #TRUE if the @item was successfully pushed on the @queue. + * Returns: %TRUE if the @item was successfully pushed on the @queue. * - * Since: 1.2.0 + * Since: 1.2 */ gboolean gst_data_queue_push_force (GstDataQueue * queue, GstDataQueueItem * item) @@ -484,12 +485,12 @@ flushing: * * Note that this function has slightly different semantics than gst_pad_push() * and gst_pad_push_event(): this function only takes ownership of @item and - * the #GstMiniObject contained in @item if the push was successful. If FALSE + * the #GstMiniObject contained in @item if the push was successful. If %FALSE * is returned, the caller is responsible for freeing @item and its contents. * - * Returns: #TRUE if the @item was successfully pushed on the @queue. + * Returns: %TRUE if the @item was successfully pushed on the @queue. * - * Since: 1.2.0 + * Since: 1.2 */ gboolean gst_data_queue_push (GstDataQueue * queue, GstDataQueueItem * item) @@ -566,9 +567,9 @@ _gst_data_queue_wait_non_empty (GstDataQueue * queue) * @queue is set to the flushing state. * MT safe. * - * Returns: #TRUE if an @item was successfully retrieved from the @queue. + * Returns: %TRUE if an @item was successfully retrieved from the @queue. * - * Since: 1.2.0 + * Since: 1.2 */ gboolean gst_data_queue_pop (GstDataQueue * queue, GstDataQueueItem ** item) @@ -636,9 +637,9 @@ is_of_type (gconstpointer a, gconstpointer b) * one item is available, OR the @queue is set to the flushing state. * MT safe. * - * Returns: #TRUE if an @item was successfully retrieved from the @queue. + * Returns: %TRUE if an @item was successfully retrieved from the @queue. * - * Since: 1.2.0 + * Since: 1.2 */ gboolean gst_data_queue_peek (GstDataQueue * queue, GstDataQueueItem ** item) @@ -688,9 +689,9 @@ flushing: * * Pop and unref the head-most #GstMiniObject with the given #GType. * - * Returns: TRUE if an element was removed. + * Returns: %TRUE if an element was removed. * - * Since: 1.2.0 + * Since: 1.2 */ gboolean gst_data_queue_drop_head (GstDataQueue * queue, GType type) @@ -731,12 +732,12 @@ done: /** * gst_data_queue_limits_changed: - * @queue: The #GstDataQueue + * @queue: The #GstDataQueue * * Inform the queue that the limits for the fullness check have changed and that - * any blocking gst_data_queue_push() should be unblocked to recheck the limts. + * any blocking gst_data_queue_push() should be unblocked to recheck the limits. * - * Since: 1.2.0 + * Since: 1.2 */ void gst_data_queue_limits_changed (GstDataQueue * queue) @@ -760,7 +761,7 @@ gst_data_queue_limits_changed (GstDataQueue * queue) * * Get the current level of the queue. * - * Since: 1.2.0 + * Since: 1.2 */ void gst_data_queue_get_level (GstDataQueue * queue, GstDataQueueSize * level) diff --git a/libs/gst/base/gstdataqueue.h b/libs/gst/base/gstdataqueue.h index c707c8b..7350c42 100644 --- a/libs/gst/base/gstdataqueue.h +++ b/libs/gst/base/gstdataqueue.h @@ -47,8 +47,8 @@ typedef struct _GstDataQueuePrivate GstDataQueuePrivate; * @object: the #GstMiniObject to queue. * @size: the size in bytes of the miniobject. * @duration: the duration in #GstClockTime of the miniobject. Can not be - * #GST_CLOCK_TIME_NONE. - * @visible: #TRUE if @object should be considered as a visible object. + * %GST_CLOCK_TIME_NONE. + * @visible: %TRUE if @object should be considered as a visible object. * @destroy: The #GDestroyNotify function to use to free the #GstDataQueueItem. * This function should also drop the reference to @object the owner of the * #GstDataQueueItem is assumed to hold. @@ -97,7 +97,7 @@ struct _GstDataQueueSize * The prototype of the function used to inform the queue that it should be * considered as full. * - * Returns: #TRUE if the queue should be considered full. + * Returns: %TRUE if the queue should be considered full. */ typedef gboolean (*GstDataQueueCheckFullFunction) (GstDataQueue * queue, guint visible, guint bytes, guint64 time, gpointer checkdata); diff --git a/libs/gst/base/gstflowcombiner.c b/libs/gst/base/gstflowcombiner.c new file mode 100644 index 0000000..e21f6c2 --- /dev/null +++ b/libs/gst/base/gstflowcombiner.c @@ -0,0 +1,248 @@ +/* GStreamer + * + * Copyright (C) 2014 Samsung Electronics. All rights reserved. + * Author: Thiago Santos <ts.santos@sisa.samsung.com> + * + * gstflowcombiner.c: utility to combine multiple flow returns into a single one + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +/** + * SECTION:gstflowcombiner + * @short_description: Utility to combine multiple flow returns into one + * + * Utility struct to help handling #GstFlowReturn combination. Useful for + * #GstElement<!-- -->s that have multiple source pads and need to combine + * the different #GstFlowReturn for those pads. + * + * #GstFlowCombiner works by using the last #GstFlowReturn for all #GstPad + * it has in its list and computes the combined return value and provides + * it to the caller. + * + * To add a new pad to the #GstFlowCombiner use gst_flow_combiner_add_pad(). + * The new #GstPad is stored with a default value of %GST_FLOW_OK. + * + * In case you want a #GstPad to be removed, use gst_flow_combiner_remove_pad(). + * + * Please be aware that this struct isn't thread safe as its designed to be + * used by demuxers, those usually will have a single thread operating it. + * + * None of these functions will take refs on the passed #GstPad<!-- -->s, it + * is the caller's responsibility to make sure that the #GstPad exists as long + * as this struct exists. + * + * Aside from reducing the user's code size, the main advantage of using this + * helper struct is to follow the standard rules for #GstFlowReturn combination. + * These rules are: + * + * * %GST_FLOW_EOS: only if all returns are EOS too + * * %GST_FLOW_NOT_LINKED: only if all returns are NOT_LINKED too + * * %GST_FLOW_ERROR or below: if at least one returns an error return + * * %GST_FLOW_NOT_NEGOTIATED: if at least one returns a not-negotiated return + * * %GST_FLOW_FLUSHING: if at least one returns flushing + * * %GST_FLOW_OK: otherwise + * + * %GST_FLOW_ERROR or below, GST_FLOW_NOT_NEGOTIATED and GST_FLOW_FLUSHING are + * returned immediatelly from the gst_flow_combiner_update_flow() function. + * + * Since: 1.4 + */ + +#include <gst/gst.h> +#include "gstflowcombiner.h" + +struct _GstFlowCombiner +{ + GQueue pads; + + GstFlowReturn last_ret; + volatile gint ref_count; +}; + +static GstFlowCombiner *gst_flow_combiner_ref (GstFlowCombiner * combiner); +static void gst_flow_combiner_unref (GstFlowCombiner * combiner); + +G_DEFINE_BOXED_TYPE (GstFlowCombiner, gst_flow_combiner, + (GBoxedCopyFunc) gst_flow_combiner_ref, + (GBoxedFreeFunc) gst_flow_combiner_unref); + +/** + * gst_flow_combiner_new: + * + * Creates a new #GstFlowCombiner, use gst_flow_combiner_free() to free it. + * + * Returns: A new #GstFlowCombiner + * Since: 1.4 + */ +GstFlowCombiner * +gst_flow_combiner_new (void) +{ + GstFlowCombiner *combiner = g_slice_new (GstFlowCombiner); + + g_queue_init (&combiner->pads); + combiner->last_ret = GST_FLOW_OK; + combiner->ref_count = 1; + + return combiner; +} + +/** + * gst_flow_combiner_free: + * @combiner: the #GstFlowCombiner to free + * + * Frees a #GstFlowCombiner struct and all its internal data. + * + * Since: 1.4 + */ +void +gst_flow_combiner_free (GstFlowCombiner * combiner) +{ + gst_flow_combiner_unref (combiner); +} + +static GstFlowCombiner * +gst_flow_combiner_ref (GstFlowCombiner * combiner) +{ + g_return_val_if_fail (combiner != NULL, NULL); + + g_atomic_int_inc (&combiner->ref_count); + + return combiner; +} + +static void +gst_flow_combiner_unref (GstFlowCombiner * combiner) +{ + g_return_if_fail (combiner != NULL); + g_return_if_fail (combiner->ref_count > 0); + + if (g_atomic_int_dec_and_test (&combiner->ref_count)) { + GstPad *pad; + + while ((pad = g_queue_pop_head (&combiner->pads))) + gst_object_unref (pad); + + g_slice_free (GstFlowCombiner, combiner); + } +} + +static GstFlowReturn +gst_flow_combiner_get_flow (GstFlowCombiner * combiner) +{ + GstFlowReturn cret = GST_FLOW_OK; + gboolean all_eos = TRUE; + gboolean all_notlinked = TRUE; + GList *iter; + + GST_DEBUG ("Combining flow returns"); + + for (iter = combiner->pads.head; iter; iter = iter->next) { + GstFlowReturn fret = GST_PAD_LAST_FLOW_RETURN (iter->data); + + if (fret <= GST_FLOW_NOT_NEGOTIATED || fret == GST_FLOW_FLUSHING) { + GST_DEBUG ("Error flow return found, returning"); + cret = fret; + goto done; + } + + if (fret != GST_FLOW_NOT_LINKED) { + all_notlinked = FALSE; + if (fret != GST_FLOW_EOS) + all_eos = FALSE; + } + } + if (all_notlinked) + cret = GST_FLOW_NOT_LINKED; + else if (all_eos) + cret = GST_FLOW_EOS; + +done: + GST_DEBUG ("Combined flow return: %s (%d)", gst_flow_get_name (cret), cret); + return cret; +} + +/** + * gst_flow_combiner_update_flow: + * @combiner: the #GstFlowCombiner + * @fret: the latest #GstFlowReturn received for a pad in this #GstFlowCombiner + * + * Computes the combined flow return for the pads in it. + * + * The #GstFlowReturn paramter should be the last flow return update for a pad + * in this #GstFlowCombiner. It will use this value to be able to shortcut some + * combinations and avoid looking over all pads again. e.g. The last combined + * return is the same as the latest obtained #GstFlowReturn. + * + * Returns: The combined #GstFlowReturn + * Since: 1.4 + */ +GstFlowReturn +gst_flow_combiner_update_flow (GstFlowCombiner * combiner, GstFlowReturn fret) +{ + GstFlowReturn ret; + + g_return_val_if_fail (combiner != NULL, GST_FLOW_ERROR); + + if (combiner->last_ret == fret) { + return fret; + } + + if (fret <= GST_FLOW_NOT_NEGOTIATED || fret == GST_FLOW_FLUSHING) { + ret = fret; + } else { + ret = gst_flow_combiner_get_flow (combiner); + } + combiner->last_ret = ret; + return ret; +} + +/** + * gst_flow_combiner_add_pad: + * @combiner: the #GstFlowCombiner + * @pad: (transfer none): the #GstPad that is being added + * + * Adds a new #GstPad to the #GstFlowCombiner. + * + * Since: 1.4 + */ +void +gst_flow_combiner_add_pad (GstFlowCombiner * combiner, GstPad * pad) +{ + g_return_if_fail (combiner != NULL); + g_return_if_fail (pad != NULL); + + g_queue_push_head (&combiner->pads, gst_object_ref (pad)); +} + +/** + * gst_flow_combiner_remove_pad: + * @combiner: the #GstFlowCombiner + * @pad: (transfer none): the #GstPad to remove + * + * Removes a #GstPad from the #GstFlowCombiner. + * + * Since: 1.4 + */ +void +gst_flow_combiner_remove_pad (GstFlowCombiner * combiner, GstPad * pad) +{ + g_return_if_fail (combiner != NULL); + g_return_if_fail (pad != NULL); + + if (g_queue_remove (&combiner->pads, pad)) + gst_object_unref (pad); +} diff --git a/libs/gst/base/gstflowcombiner.h b/libs/gst/base/gstflowcombiner.h new file mode 100644 index 0000000..43c37e3 --- /dev/null +++ b/libs/gst/base/gstflowcombiner.h @@ -0,0 +1,58 @@ +/* GStreamer + * + * Copyright (C) 2014 Samsung Electronics. All rights reserved. + * Author: Thiago Santos <ts.santos@sisa.samsung.com> + * + * gstflowcombiner.h: utility to combine multiple flow returns into a single one + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + + +#ifndef __GST_FLOW_COMBINER_H__ +#define __GST_FLOW_COMBINER_H__ + +#include <glib.h> +#include <gst/gst.h> + +G_BEGIN_DECLS + +#define GST_TYPE_FLOW_COMBINER gst_flow_combiner_get_type() + +/** + * GstFlowCombiner: + * + * Opaque helper structure to aggregate flow returns. + * + * Since: 1.4 + */ +typedef struct _GstFlowCombiner GstFlowCombiner; + +GstFlowCombiner * gst_flow_combiner_new (void); + +void gst_flow_combiner_free (GstFlowCombiner * combiner); + +GstFlowReturn gst_flow_combiner_update_flow (GstFlowCombiner * combiner, GstFlowReturn fret); + +void gst_flow_combiner_add_pad (GstFlowCombiner * combiner, GstPad * pad); + +void gst_flow_combiner_remove_pad (GstFlowCombiner * combiner, GstPad * pad); + +GType gst_flow_combiner_get_type (void); + +G_END_DECLS + +#endif /* __GST_FLOW_COMBINER_H__ */ diff --git a/libs/gst/base/gstindex.c b/libs/gst/base/gstindex.c index 3786e95..b614d2c 100644 --- a/libs/gst/base/gstindex.c +++ b/libs/gst/base/gstindex.c @@ -25,7 +25,7 @@ * @short_description: Generate indexes on objects * @see_also: #GstIndexFactory * - * GstIndex is used to generate a stream index of one or more elements + * #GstIndex is used to generate a stream index of one or more elements * in a pipeline. * * Elements will overload the set_index and get_index virtual methods in @@ -368,7 +368,7 @@ gst_index_new_group (GstIndex * index) * * Set the current groupnumber to the given argument. * - * Returns: TRUE if the operation succeeded, FALSE if the group + * Returns: %TRUE if the operation succeeded, %FALSE if the group * did not exist. */ gboolean @@ -571,7 +571,7 @@ gst_index_entry_free (GstIndexEntry * entry) * @format: the format to add to the index * * Adds a format entry into the index. This function is - * used to map dynamic GstFormat ids to their original + * used to map dynamic #GstFormat ids to their original * format key. * * Free-function: gst_index_entry_free @@ -676,7 +676,7 @@ gst_index_gtype_resolver (GstIndex * index, GstObject * writer, /** * gst_index_get_writer_id: * @index: the index to get a unique write id for - * @writer: the GstObject to allocate an id for + * @writer: the #GstObject to allocate an id for * @id: a pointer to a gint to hold the id * * Before entries can be added to the index, a writer @@ -688,12 +688,12 @@ gst_index_gtype_resolver (GstIndex * index, GstObject * writer, * in the index. * * <note> - * The caller must not hold @writer's #GST_OBJECT_LOCK, as the default + * The caller must not hold @writer's GST_OBJECT_LOCK(), as the default * resolver may call functions that take the object lock as well, and * the lock is not recursive. * </note> * - * Returns: TRUE if the writer would be mapped to an id. + * Returns: %TRUE if the writer would be mapped to an id. */ gboolean gst_index_get_writer_id (GstIndex * index, GstObject * writer, gint * id) @@ -775,7 +775,7 @@ gst_index_add_entry (GstIndex * index, GstIndexEntry * entry) * @id: the id of the index writer * @flags: optinal flags for this entry * @n: number of associations - * @list: list of associations + * @list: (array length=n): list of associations * * Associate given format/value pairs with each other. * @@ -918,7 +918,7 @@ gst_index_compare_func (gconstpointer a, gconstpointer b, gpointer user_data) * * Finds the given format/value in the index * - * Returns: the entry associated with the value or NULL if the + * Returns: the entry associated with the value or %NULL if the * value was not found. */ GstIndexEntry * @@ -949,7 +949,7 @@ gst_index_get_assoc_entry (GstIndex * index, gint id, * Finds the given format/value in the index with the given * compare function and user_data. * - * Returns: the entry associated with the value or NULL if the + * Returns: the entry associated with the value or %NULL if the * value was not found. */ GstIndexEntry * @@ -981,7 +981,7 @@ gst_index_get_assoc_entry_full (GstIndex * index, gint id, * * Gets alternative formats associated with the indexentry. * - * Returns: TRUE if there was a value associated with the given + * Returns: %TRUE if there was a value associated with the given * format. */ gboolean diff --git a/libs/gst/base/gstpushsrc.c b/libs/gst/base/gstpushsrc.c index f89fa0a..7af8147 100644 --- a/libs/gst/base/gstpushsrc.c +++ b/libs/gst/base/gstpushsrc.c @@ -44,8 +44,6 @@ * * Seeking, flushing, scheduling and sync is all handled by this * base class. - * - * Last reviewed on 2006-07-04 (0.10.9) */ #ifdef HAVE_CONFIG_H diff --git a/libs/gst/base/gstqueuearray.c b/libs/gst/base/gstqueuearray.c index 4b83959..d37535d 100644 --- a/libs/gst/base/gstqueuearray.c +++ b/libs/gst/base/gstqueuearray.c @@ -25,7 +25,7 @@ * * #GstQueueArray is an object that provides standard queue functionality * based on an array instead of linked lists. This reduces the overhead - * caused by memory managment by a large factor. + * caused by memory management by a large factor. */ @@ -52,7 +52,7 @@ struct _GstQueueArray * * Returns: a new #GstQueueArray object * - * Since: 1.2.0 + * Since: 1.2 */ GstQueueArray * gst_queue_array_new (guint initial_size) @@ -75,7 +75,7 @@ gst_queue_array_new (guint initial_size) * * Frees queue @array and all memory associated to it. * - * Since: 1.2.0 + * Since: 1.2 */ void gst_queue_array_free (GstQueueArray * array) @@ -93,7 +93,7 @@ gst_queue_array_free (GstQueueArray * array) * * Returns: The head of the queue * - * Since: 1.2.0 + * Since: 1.2 */ gpointer gst_queue_array_pop_head (GstQueueArray * array) @@ -111,7 +111,7 @@ gst_queue_array_pop_head (GstQueueArray * array) } /** - * gst_queue_array_pop_head: + * gst_queue_array_peek_head: * @array: a #GstQueueArray object * * Returns and head of the queue @array and does not @@ -119,7 +119,7 @@ gst_queue_array_pop_head (GstQueueArray * array) * * Returns: The head of the queue * - * Since: 1.2.0 + * Since: 1.2 */ gpointer gst_queue_array_peek_head (GstQueueArray * array) @@ -137,7 +137,7 @@ gst_queue_array_peek_head (GstQueueArray * array) * * Pushes @data to the tail of the queue @array. * - * Since: 1.2.0 + * Since: 1.2 */ void gst_queue_array_push_tail (GstQueueArray * array, gpointer data) @@ -145,7 +145,7 @@ gst_queue_array_push_tail (GstQueueArray * array, gpointer data) /* Check if we need to make room */ if (G_UNLIKELY (array->length == array->size)) { /* newsize is 50% bigger */ - guint newsize = (3 * array->size) / 2; + guint newsize = MAX ((3 * array->size) / 2, array->size + 1); /* copy over data */ if (array->tail != 0) { @@ -190,7 +190,7 @@ gst_queue_array_push_tail (GstQueueArray * array, gpointer data) * * Returns: %TRUE if the queue @array is empty * - * Since: 1.2.0 + * Since: 1.2 */ gboolean gst_queue_array_is_empty (GstQueueArray * array) @@ -207,7 +207,7 @@ gst_queue_array_is_empty (GstQueueArray * array) * * Returns: the dropped element * - * Since: 1.2.0 + * Since: 1.2 */ gpointer gst_queue_array_drop_element (GstQueueArray * array, guint idx) @@ -297,11 +297,11 @@ gst_queue_array_drop_element (GstQueueArray * array, guint idx) * Note that the index is not 0-based, but an internal index number with a * random offset. The index can be used in connection with * gst_queue_array_drop_element(). FIXME: return index 0-based and make - * _drop_element() take a 0-based index. + * gst_queue_array_drop_element() take a 0-based index. * * Returns: Index of the found element or -1 if nothing was found. * - * Since: 1.2.0 + * Since: 1.2 */ guint gst_queue_array_find (GstQueueArray * array, GCompareFunc func, gpointer data) @@ -332,7 +332,7 @@ gst_queue_array_find (GstQueueArray * array, GCompareFunc func, gpointer data) * * Returns: the length of the queue @array. * - * Since: 1.2.0 + * Since: 1.2 */ guint gst_queue_array_get_length (GstQueueArray * array) diff --git a/libs/gst/base/gsttypefindhelper.c b/libs/gst/base/gsttypefindhelper.c index 5f30c8c..1a0d327 100644 --- a/libs/gst/base/gsttypefindhelper.c +++ b/libs/gst/base/gsttypefindhelper.c @@ -163,7 +163,7 @@ helper_find_peek (gpointer data, gint64 offset, guint size) #endif /* getrange might silently return shortened buffers at the end of a file, - * we must, however, always return either the full requested data or NULL */ + * we must, however, always return either the full requested data or %NULL */ buf_offset = GST_BUFFER_OFFSET (buffer); buf_size = gst_buffer_get_size (buffer); @@ -246,13 +246,13 @@ helper_find_get_length (gpointer data) /** * gst_type_find_helper_get_range: * @obj: A #GstObject that will be passed as first argument to @func - * @parent: (allow-none): the parent of @obj or NULL + * @parent: (allow-none): the parent of @obj or %NULL * @func: (scope call): A generic #GstTypeFindHelperGetRangeFunction that will * be used to access data at random offsets when doing the typefinding * @size: The length in bytes * @extension: extension of the media * @prob: (out) (allow-none): location to store the probability of the found - * caps, or #NULL + * caps, or %NULL * * Utility function to do pull-based typefinding. Unlike gst_type_find_helper() * however, this function will use the specified function @func to obtain the @@ -263,14 +263,14 @@ helper_find_get_length (gpointer data) * callback can then call the upstream peer pad with offsets adjusted for the * tag size, for example). * - * When @extension is not NULL, this function will first try the typefind + * When @extension is not %NULL, this function will first try the typefind * functions for the given extension, which might speed up the typefinding * in many cases. * * Free-function: gst_caps_unref * * Returns: (transfer full): the #GstCaps corresponding to the data stream. - * Returns #NULL if no #GstCaps matches the data stream. + * Returns %NULL if no #GstCaps matches the data stream. */ GstCaps * gst_type_find_helper_get_range (GstObject * obj, GstObject * parent, @@ -389,7 +389,7 @@ gst_type_find_helper_get_range (GstObject * obj, GstObject * parent, * Free-function: gst_caps_unref * * Returns: (transfer full): the #GstCaps corresponding to the data stream. - * Returns #NULL if no #GstCaps matches the data stream. + * Returns %NULL if no #GstCaps matches the data stream. */ GstCaps * @@ -480,26 +480,26 @@ buf_helper_find_suggest (gpointer data, GstTypeFindProbability probability, /** * gst_type_find_helper_for_data: - * @obj: (allow-none): object doing the typefinding, or NULL (used for logging) + * @obj: (allow-none): object doing the typefinding, or %NULL (used for logging) * @data: (in) (transfer none): a pointer with data to typefind * @size: (in) (transfer none): the size of @data * @prob: (out) (allow-none): location to store the probability of the found - * caps, or #NULL + * caps, or %NULL * * Tries to find what type of data is contained in the given @data, the * assumption being that the data represents the beginning of the stream or * file. * * All available typefinders will be called on the data in order of rank. If - * a typefinding function returns a probability of #GST_TYPE_FIND_MAXIMUM, + * a typefinding function returns a probability of %GST_TYPE_FIND_MAXIMUM, * typefinding is stopped immediately and the found caps will be returned * right away. Otherwise, all available typefind functions will the tried, - * and the caps with the highest probability will be returned, or #NULL if + * and the caps with the highest probability will be returned, or %NULL if * the content of @data could not be identified. * * Free-function: gst_caps_unref * - * Returns: (transfer full): the #GstCaps corresponding to the data, or #NULL + * Returns: (transfer full): the #GstCaps corresponding to the data, or %NULL * if no type could be found. The caller should free the caps returned * with gst_caps_unref(). */ @@ -552,25 +552,25 @@ gst_type_find_helper_for_data (GstObject * obj, const guint8 * data, gsize size, /** * gst_type_find_helper_for_buffer: - * @obj: (allow-none): object doing the typefinding, or NULL (used for logging) + * @obj: (allow-none): object doing the typefinding, or %NULL (used for logging) * @buf: (in) (transfer none): a #GstBuffer with data to typefind * @prob: (out) (allow-none): location to store the probability of the found - * caps, or #NULL + * caps, or %NULL * * Tries to find what type of data is contained in the given #GstBuffer, the * assumption being that the buffer represents the beginning of the stream or * file. * * All available typefinders will be called on the data in order of rank. If - * a typefinding function returns a probability of #GST_TYPE_FIND_MAXIMUM, + * a typefinding function returns a probability of %GST_TYPE_FIND_MAXIMUM, * typefinding is stopped immediately and the found caps will be returned * right away. Otherwise, all available typefind functions will the tried, - * and the caps with the highest probability will be returned, or #NULL if + * and the caps with the highest probability will be returned, or %NULL if * the content of the buffer could not be identified. * * Free-function: gst_caps_unref * - * Returns: (transfer full): the #GstCaps corresponding to the data, or #NULL + * Returns: (transfer full): the #GstCaps corresponding to the data, or %NULL * if no type could be found. The caller should free the caps returned * with gst_caps_unref(). */ @@ -596,7 +596,7 @@ gst_type_find_helper_for_buffer (GstObject * obj, GstBuffer * buf, /** * gst_type_find_helper_for_extension: - * @obj: (allow-none): object doing the typefinding, or NULL (used for logging) + * @obj: (allow-none): object doing the typefinding, or %NULL (used for logging) * @extension: an extension * * Tries to find the best #GstCaps associated with @extension. @@ -608,7 +608,7 @@ gst_type_find_helper_for_buffer (GstObject * obj, GstBuffer * buf, * Free-function: gst_caps_unref * * Returns: (transfer full): the #GstCaps corresponding to @extension, or - * #NULL if no type could be found. The caller should free the caps + * %NULL if no type could be found. The caller should free the caps * returned with gst_caps_unref(). */ GstCaps * diff --git a/libs/gst/base/gsttypefindhelper.h b/libs/gst/base/gsttypefindhelper.h index 9447f9b..6770e4f 100644 --- a/libs/gst/base/gsttypefindhelper.h +++ b/libs/gst/base/gsttypefindhelper.h @@ -44,7 +44,7 @@ GstCaps * gst_type_find_helper_for_extension (GstObject * obj, /** * GstTypeFindHelperGetRangeFunction: * @obj: a #GstObject that will handle the getrange request - * @parent: (allow-none): the parent of @obj or NULL + * @parent: (allow-none): the parent of @obj or %NULL * @offset: the offset of the range * @length: the length of the range * @buffer: a memory location to hold the result buffer diff --git a/libs/gst/check/Makefile.am b/libs/gst/check/Makefile.am index 155bff8..1389270 100644 --- a/libs/gst/check/Makefile.am +++ b/libs/gst/check/Makefile.am @@ -82,9 +82,13 @@ LIBGSTCHECK_EXPORTED_FUNCS = \ gst_check_setup_events \ gst_check_setup_events_with_stream_id \ gst_check_setup_sink_pad \ + gst_check_setup_sink_pad_from_template \ gst_check_setup_sink_pad_by_name \ + gst_check_setup_sink_pad_by_name_from_template \ gst_check_setup_src_pad \ + gst_check_setup_src_pad_from_template \ gst_check_setup_src_pad_by_name \ + gst_check_setup_src_pad_by_name_from_template \ gst_check_teardown_element \ gst_check_teardown_pad_by_name \ gst_check_teardown_sink_pad \ @@ -104,7 +108,11 @@ LIBGSTCHECK_EXPORTED_FUNCS = \ gst_test_clock_wait_for_next_pending_id \ gst_test_clock_wait_for_pending_id_count \ gst_test_clock_process_next_clock_id \ - gst_test_clock_get_next_entry_time + gst_test_clock_get_next_entry_time \ + gst_test_clock_wait_for_multiple_pending_ids \ + gst_test_clock_process_id_list \ + gst_test_clock_id_list_get_latest_time + LIBGSTCHECK_EXPORTED_SYMBOLS = \ $(LIBGSTCHECK_EXPORTED_VARS) \ @@ -146,7 +154,7 @@ GstCheck-@GST_API_VERSION@.gir: $(INTROSPECTION_SCANNER) libgstcheck-@GST_API_VE --library-path=$(top_builddir)/gst \ --library=libgstcheck-@GST_API_VERSION@.la \ --include=Gst-@GST_API_VERSION@ \ - --libtool="$(top_builddir)/libtool" \ + --libtool="${LIBTOOL}" \ --pkg gstreamer-@GST_API_VERSION@ \ --pkg-export gstreamer-check-@GST_API_VERSION@ \ --add-init-section="gst_init(NULL,NULL);" \ diff --git a/libs/gst/check/Makefile.in b/libs/gst/check/Makefile.in index ce1bce9..9f470d4 100644 --- a/libs/gst/check/Makefile.in +++ b/libs/gst/check/Makefile.in @@ -92,7 +92,6 @@ am__aclocal_m4_deps = $(top_srcdir)/common/m4/as-ac-expand.m4 \ $(top_srcdir)/common/m4/as-compiler-flag.m4 \ $(top_srcdir)/common/m4/as-docbook.m4 \ $(top_srcdir)/common/m4/as-libtool.m4 \ - $(top_srcdir)/common/m4/as-scrub-include.m4 \ $(top_srcdir)/common/m4/as-version.m4 \ $(top_srcdir)/common/m4/ax_create_stdint_h.m4 \ $(top_srcdir)/common/m4/gst-arch.m4 \ @@ -634,9 +633,13 @@ LIBGSTCHECK_EXPORTED_FUNCS = \ gst_check_setup_events \ gst_check_setup_events_with_stream_id \ gst_check_setup_sink_pad \ + gst_check_setup_sink_pad_from_template \ gst_check_setup_sink_pad_by_name \ + gst_check_setup_sink_pad_by_name_from_template \ gst_check_setup_src_pad \ + gst_check_setup_src_pad_from_template \ gst_check_setup_src_pad_by_name \ + gst_check_setup_src_pad_by_name_from_template \ gst_check_teardown_element \ gst_check_teardown_pad_by_name \ gst_check_teardown_sink_pad \ @@ -656,7 +659,10 @@ LIBGSTCHECK_EXPORTED_FUNCS = \ gst_test_clock_wait_for_next_pending_id \ gst_test_clock_wait_for_pending_id_count \ gst_test_clock_process_next_clock_id \ - gst_test_clock_get_next_entry_time + gst_test_clock_get_next_entry_time \ + gst_test_clock_wait_for_multiple_pending_ids \ + gst_test_clock_process_id_list \ + gst_test_clock_id_list_get_latest_time LIBGSTCHECK_EXPORTED_SYMBOLS = \ $(LIBGSTCHECK_EXPORTED_VARS) \ @@ -1237,7 +1243,7 @@ $(SYMBOLS_FILE): $(libgstcheck_@GST_API_VERSION@include_HEADERS) libcheck/check. @HAVE_INTROSPECTION_TRUE@ --library-path=$(top_builddir)/gst \ @HAVE_INTROSPECTION_TRUE@ --library=libgstcheck-@GST_API_VERSION@.la \ @HAVE_INTROSPECTION_TRUE@ --include=Gst-@GST_API_VERSION@ \ -@HAVE_INTROSPECTION_TRUE@ --libtool="$(top_builddir)/libtool" \ +@HAVE_INTROSPECTION_TRUE@ --libtool="${LIBTOOL}" \ @HAVE_INTROSPECTION_TRUE@ --pkg gstreamer-@GST_API_VERSION@ \ @HAVE_INTROSPECTION_TRUE@ --pkg-export gstreamer-check-@GST_API_VERSION@ \ @HAVE_INTROSPECTION_TRUE@ --add-init-section="gst_init(NULL,NULL);" \ diff --git a/libs/gst/check/gstcheck.c b/libs/gst/check/gstcheck.c index 091a223..454ebb2 100644 --- a/libs/gst/check/gstcheck.c +++ b/libs/gst/check/gstcheck.c @@ -26,6 +26,10 @@ * * These macros and functions are for internal use of the unit tests found * inside the 'check' directories of various GStreamer packages. + * + * One notable feature is that one can use the environment variables GST_CHECK + * and GST_CHECK_IGNORE to select which tests to run or skip. Both variables + * can contain a comman separated list of test name globs (e.g. test_*). */ #ifdef HAVE_CONFIG_H #include "config.h" @@ -259,10 +263,47 @@ GstPad * gst_check_setup_src_pad_by_name (GstElement * element, GstStaticPadTemplate * tmpl, const gchar * name) { + GstPadTemplate *ptmpl = gst_static_pad_template_get (tmpl); + GstPad *srcpad; + + srcpad = + gst_check_setup_src_pad_by_name_from_template (element, ptmpl, "sink"); + + gst_object_unref (ptmpl); + + return srcpad; +} + +/** + * gst_check_setup_src_pad_from_template: + * @element: element to setup pad on + * @tmpl: pad template + * + * Returns: (transfer full): a new pad + */ +GstPad * +gst_check_setup_src_pad_from_template (GstElement * element, + GstPadTemplate * tmpl) +{ + return gst_check_setup_src_pad_by_name_from_template (element, tmpl, "sink"); +} + +/** + * gst_check_setup_src_pad_by_name_from_template: + * @element: element to setup pad on + * @tmpl: pad template + * @name: name + * + * Returns: (transfer full): a new pad + */ +GstPad * +gst_check_setup_src_pad_by_name_from_template (GstElement * element, + GstPadTemplate * tmpl, const gchar * name) +{ GstPad *srcpad, *sinkpad; /* sending pad */ - srcpad = gst_pad_new_from_static_template (tmpl, "src"); + srcpad = gst_pad_new_from_template (tmpl, "src"); GST_DEBUG_OBJECT (element, "setting up sending pad %p", srcpad); fail_if (srcpad == NULL, "Could not create a srcpad"); ASSERT_OBJECT_REFCOUNT (srcpad, "srcpad", 1); @@ -345,10 +386,47 @@ GstPad * gst_check_setup_sink_pad_by_name (GstElement * element, GstStaticPadTemplate * tmpl, const gchar * name) { + GstPadTemplate *ptmpl = gst_static_pad_template_get (tmpl); + GstPad *sinkpad; + + sinkpad = + gst_check_setup_sink_pad_by_name_from_template (element, ptmpl, "src"); + + gst_object_unref (ptmpl); + + return sinkpad; +} + +/** + * gst_check_setup_sink_pad_from_template: + * @element: element to setup pad on + * @tmpl: pad template + * + * Returns: (transfer full): a new pad + */ +GstPad * +gst_check_setup_sink_pad_from_template (GstElement * element, + GstPadTemplate * tmpl) +{ + return gst_check_setup_sink_pad_by_name_from_template (element, tmpl, "src"); +} + +/** + * gst_check_setup_sink_pad_by_name_from_template: + * @element: element to setup pad on + * @tmpl: pad template + * @name: name + * + * Returns: (transfer full): a new pad + */ +GstPad * +gst_check_setup_sink_pad_by_name_from_template (GstElement * element, + GstPadTemplate * tmpl, const gchar * name) +{ GstPad *srcpad, *sinkpad; /* receiving pad */ - sinkpad = gst_pad_new_from_static_template (tmpl, "sink"); + sinkpad = gst_pad_new_from_template (tmpl, "sink"); GST_DEBUG_OBJECT (element, "setting up receiving pad %p", sinkpad); fail_if (sinkpad == NULL, "Could not create a sinkpad"); @@ -460,7 +538,7 @@ buffer_event_function (GstPad * pad, GstObject * noparent, GstEvent * event) * gst_check_element_push_buffer_list: * @element_name: name of the element that needs to be created * @buffer_in: (element-type GstBuffer) (transfer full): a list of buffers that needs to be - * puched to the element + * pushed to the element * @buffer_out: (element-type GstBuffer) (transfer full): a list of buffers that we expect from * the element * @last_flow_return: the last buffer push needs to give this GstFlowReturn @@ -697,18 +775,26 @@ gst_check_run_suite (Suite * suite, const gchar * name, const gchar * fname) return nf; } -gboolean -_gst_check_run_test_func (const gchar * func_name) +static gboolean +gst_check_have_checks_list (const gchar * env_var_name) +{ + const gchar *env_val; + + env_val = g_getenv (env_var_name); + return (env_val != NULL && *env_val != '\0'); +} + +static gboolean +gst_check_func_is_in_list (const gchar * env_var, const gchar * func_name) { const gchar *gst_checks; gboolean res = FALSE; gchar **funcs, **f; - gst_checks = g_getenv ("GST_CHECKS"); + gst_checks = g_getenv (env_var); - /* no filter specified => run all checks */ if (gst_checks == NULL || *gst_checks == '\0') - return TRUE; + return FALSE; /* only run specified functions */ funcs = g_strsplit (gst_checks, ",", -1); @@ -722,6 +808,21 @@ _gst_check_run_test_func (const gchar * func_name) return res; } +gboolean +_gst_check_run_test_func (const gchar * func_name) +{ + /* if we have a whitelist, run it only if it's in the whitelist */ + if (gst_check_have_checks_list ("GST_CHECKS")) + return gst_check_func_is_in_list ("GST_CHECKS", func_name); + + /* if we have a blacklist, run it only if it's not in the blacklist */ + if (gst_check_have_checks_list ("GST_CHECKS_IGNORE")) + return !gst_check_func_is_in_list ("GST_CHECKS_IGNORE", func_name); + + /* no filter specified => run all checks */ + return TRUE; +} + /** * gst_check_setup_events_with_stream_id: * @srcpad: The src #GstPad to push on @@ -730,7 +831,7 @@ _gst_check_run_test_func (const gchar * func_name) * @format: The #GstFormat of the default segment to send * @stream_id: A unique identifier for the stream * - * Push stream-start, caps and segment event, which concist of the minimum + * Push stream-start, caps and segment event, which consist of the minimum * required events to allow streaming. Caps is optional to allow raw src * testing. */ @@ -756,7 +857,7 @@ gst_check_setup_events_with_stream_id (GstPad * srcpad, GstElement * element, * @caps: (allow-none): #GstCaps in case caps event must be sent * @format: The #GstFormat of the default segment to send * - * Push stream-start, caps and segment event, which concist of the minimum + * Push stream-start, caps and segment event, which consist of the minimum * required events to allow streaming. Caps is optional to allow raw src * testing. If @element has more than one src or sink pad, use * gst_check_setup_events_with_stream_id() instead. diff --git a/libs/gst/check/gstcheck.h b/libs/gst/check/gstcheck.h index 7b4b9d4..ee92579 100644 --- a/libs/gst/check/gstcheck.h +++ b/libs/gst/check/gstcheck.h @@ -73,10 +73,20 @@ GstElement *gst_check_setup_element (const gchar * factory); void gst_check_teardown_element (GstElement * element); GstPad *gst_check_setup_src_pad (GstElement * element, GstStaticPadTemplate * tmpl); +GstPad *gst_check_setup_src_pad_from_template (GstElement * element, + GstPadTemplate * tmpl); GstPad * gst_check_setup_src_pad_by_name (GstElement * element, GstStaticPadTemplate * tmpl, const gchar *name); +GstPad * gst_check_setup_src_pad_by_name_from_template (GstElement * element, + GstPadTemplate * tmpl, const gchar *name); +GstPad *gst_check_setup_sink_pad (GstElement * element, + GstStaticPadTemplate * tmpl); +GstPad *gst_check_setup_sink_pad_from_template (GstElement * element, + GstPadTemplate * tmpl); GstPad * gst_check_setup_sink_pad_by_name (GstElement * element, GstStaticPadTemplate * tmpl, const gchar *name); +GstPad * gst_check_setup_sink_pad_by_name_from_template (GstElement * element, + GstPadTemplate * tmpl, const gchar *name); void gst_check_teardown_pad_by_name (GstElement * element, const gchar *name); void gst_check_teardown_src_pad (GstElement * element); void gst_check_drop_buffers (void); @@ -88,8 +98,6 @@ void gst_check_element_push_buffer_list (const gchar * element_name, void gst_check_element_push_buffer (const gchar * element_name, GstBuffer * buffer_in, GstCaps * caps_in, GstBuffer * buffer_out, GstCaps *caps_out); -GstPad *gst_check_setup_sink_pad (GstElement * element, - GstStaticPadTemplate * tmpl); void gst_check_teardown_sink_pad (GstElement * element); void gst_check_abi_list (GstCheckABIStruct list[], gboolean have_abi_sizes); gint gst_check_run_suite (Suite * suite, const gchar * name, @@ -558,7 +566,8 @@ int main (int argc, char **argv) \ } /* Hack to allow run-time selection of unit tests to run via the - * GST_CHECKS environment variable (test function names, comma-separated) */ + * GST_CHECKS environment variable (test function names globs, comma + * separated), or GST_CHECKS_IGNORE with the same semantics */ gboolean _gst_check_run_test_func (const gchar * func_name); @@ -573,12 +582,13 @@ __gst_tcase_add_test (TCase * tc, TFun tf, const char * fname, int signal, #define _tcase_add_test __gst_tcase_add_test -/* add define to skip broken tests */ +/* A special variant to add broken tests. These are normally skipped, but can be + * forced to run via GST_CHECKS */ #define tcase_skip_broken_test(chain,test_func) \ G_STMT_START { \ const char *env = g_getenv ("GST_CHECKS"); \ \ - if (env != NULL && strstr (env, G_STRINGIFY (test_func))) { \ + if (env != NULL && g_pattern_match_simple (env, G_STRINGIFY (test_func))) { \ tcase_add_test(chain,test_func); \ } else { \ g_printerr ("FIXME: skipping test %s because it's broken\n", G_STRINGIFY (test_func)); \ diff --git a/libs/gst/check/gsttestclock.c b/libs/gst/check/gsttestclock.c index f9737a6..a609766 100644 --- a/libs/gst/check/gsttestclock.c +++ b/libs/gst/check/gsttestclock.c @@ -2,6 +2,8 @@ * * Copyright (C) 2008 Ole André Vadla Ravnås <ole.andre.ravnas@tandberg.com> * Copyright (C) 2012 Sebastian Rasmussen <sebastian.rasmussen@axis.com> + * Copyright (C) 2012 Havard Graff <havard@pexip.com> + * Copyright (C) 2013 Haakon Sporsheim <haakon@pexip.com> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -57,12 +59,12 @@ * #GstClock allows for setting up single shot or periodic clock notifications * as well as waiting for these notifications synchronously (using * gst_clock_id_wait()) or asynchronously (using gst_clock_id_wait_async() or - * gst_clock_id_wait_async_full()). This is used by many GStreamer elements, + * gst_clock_id_wait_async()). This is used by many GStreamer elements, * among them #GstBaseSrc and #GstBaseSink. * * #GstTestClock keeps track of these clock notifications. By calling * gst_test_clock_wait_for_next_pending_id() or - * gst_test_clock_wait_for_pending_id_count() a unit tests may wait for the + * gst_test_clock_wait_for_multiple_pending_ids() a unit tests may wait for the * next one or several clock notifications to be requested. Additionally unit * tests may release blocked waits in a controlled fashion by calling * gst_test_clock_process_next_clock_id(). This way a unit test can control the @@ -76,12 +78,12 @@ * * N.B.: When a unit test waits for a certain amount of clock notifications to * be requested in gst_test_clock_wait_for_next_pending_id() or - * gst_test_clock_wait_for_pending_id_count() then these functions may block + * gst_test_clock_wait_for_multiple_pending_ids() then these functions may block * for a long time. If they block forever then the expected clock notifications * were never requested from #GstTestClock, and so the assumptions in the code - * of the unit test are wrong. The unit test case runner in #GstCheck is + * of the unit test are wrong. The unit test case runner in gstcheck is * expected to catch these cases either by the default test case timeout or the - * one set for the unit test by calling tcase_set_timeout(). + * one set for the unit test by calling tcase_set_timeout\(\). * * The sample code below assumes that the element under test will delay a * buffer pushed on the source pad by some latency until it arrives on the sink @@ -388,6 +390,7 @@ gst_test_clock_set_property (GObject * object, guint property_id, static GstClockTime gst_test_clock_get_resolution (GstClock * clock) { + (void) clock; return 1; } @@ -592,6 +595,51 @@ gst_clock_entry_context_compare_func (gconstpointer a, gconstpointer b) return gst_clock_id_compare_func (ctx_a->clock_entry, ctx_b->clock_entry); } +static void +process_entry_context_unlocked (GstTestClock * test_clock, + GstClockEntryContext * ctx) +{ + GstTestClockPrivate *priv = GST_TEST_CLOCK_GET_PRIVATE (test_clock); + GstClockEntry *entry = ctx->clock_entry; + + if (ctx->time_diff >= 0) + GST_CLOCK_ENTRY_STATUS (entry) = GST_CLOCK_OK; + else + GST_CLOCK_ENTRY_STATUS (entry) = GST_CLOCK_EARLY; + + if (entry->func != NULL) { + GST_OBJECT_UNLOCK (test_clock); + entry->func (GST_CLOCK (test_clock), priv->internal_time, entry, + entry->user_data); + GST_OBJECT_LOCK (test_clock); + } + + gst_test_clock_remove_entry (test_clock, entry); + + if (GST_CLOCK_ENTRY_TYPE (entry) == GST_CLOCK_ENTRY_PERIODIC) { + GST_CLOCK_ENTRY_TIME (entry) += GST_CLOCK_ENTRY_INTERVAL (entry); + + if (entry->func != NULL) + gst_test_clock_add_entry (test_clock, entry, NULL); + } +} + +static GList * +gst_test_clock_get_pending_id_list_unlocked (GstTestClock * test_clock) +{ + GstTestClockPrivate *priv = GST_TEST_CLOCK_GET_PRIVATE (test_clock); + GQueue queue = G_QUEUE_INIT; + GList *cur; + + for (cur = priv->entry_contexts; cur != NULL; cur = cur->next) { + GstClockEntryContext *ctx = cur->data; + + g_queue_push_tail (&queue, gst_clock_id_ref (ctx->clock_entry)); + } + + return queue.head; +} + /** * gst_test_clock_new: * @@ -832,31 +880,26 @@ gst_test_clock_wait_for_next_pending_id (GstTestClock * test_clock, * @test_clock. There is no timeout for this wait, see the main description of * #GstTestClock. * - * MT safe. - * * Since: 1.2 + * + * Deprecated: use gst_test_clock_wait_for_multiple_pending_ids() instead. */ +#ifndef GST_REMOVE_DEPRECATED +#ifdef GST_DISABLE_DEPRECATED +void gst_test_clock_wait_for_pending_id_count (GstTestClock * test_clock, + guint count); +#endif void gst_test_clock_wait_for_pending_id_count (GstTestClock * test_clock, guint count) { - GstTestClockPrivate *priv; - - g_return_if_fail (GST_IS_TEST_CLOCK (test_clock)); - - priv = GST_TEST_CLOCK_GET_PRIVATE (test_clock); - - GST_OBJECT_LOCK (test_clock); - - while (gst_test_clock_peek_id_count_unlocked (test_clock) < count) - g_cond_wait (&priv->entry_added_cond, GST_OBJECT_GET_LOCK (test_clock)); - - GST_OBJECT_UNLOCK (test_clock); + gst_test_clock_wait_for_multiple_pending_ids (test_clock, count, NULL); } +#endif /** * gst_test_clock_process_next_clock_id: - * @test_clock: a #GstTestClock for which to retrive the next pending clock + * @test_clock: a #GstTestClock for which to retrieve the next pending clock * notification * * MT safe. @@ -888,30 +931,8 @@ gst_test_clock_process_next_clock_id (GstTestClock * test_clock) result = gst_clock_id_ref (ctx->clock_entry); } - if (result != NULL) { - GstClockEntry *entry = ctx->clock_entry; - - if (ctx->time_diff >= 0) - GST_CLOCK_ENTRY_STATUS (entry) = GST_CLOCK_OK; - else - GST_CLOCK_ENTRY_STATUS (entry) = GST_CLOCK_EARLY; - - if (entry->func != NULL) { - GST_OBJECT_UNLOCK (test_clock); - entry->func (GST_CLOCK (test_clock), priv->internal_time, entry, - entry->user_data); - GST_OBJECT_LOCK (test_clock); - } - - gst_test_clock_remove_entry (test_clock, entry); - - if (GST_CLOCK_ENTRY_TYPE (entry) == GST_CLOCK_ENTRY_PERIODIC) { - GST_CLOCK_ENTRY_TIME (entry) += GST_CLOCK_ENTRY_INTERVAL (entry); - - if (entry->func != NULL) - gst_test_clock_add_entry (test_clock, entry, NULL); - } - } + if (result != NULL) + process_entry_context_unlocked (test_clock, ctx); GST_OBJECT_UNLOCK (test_clock); @@ -957,3 +978,103 @@ gst_test_clock_get_next_entry_time (GstTestClock * test_clock) return result; } + +/** + * gst_test_clock_wait_for_multiple_pending_ids: + * @test_clock: #GstTestClock for which to await having enough pending clock + * @count: the number of pending clock notifications to wait for + * @pending_list: (out) (element-type Gst.ClockID) (transfer full) (allow-none): Address + * of a #GList pointer variable to store the list of pending #GstClockIDs + * that expired, or NULL + * + * Blocks until at least @count clock notifications have been requested from + * @test_clock. There is no timeout for this wait, see the main description of + * #GstTestClock. + * + * MT safe. + * + * Since: 1.4 + */ +void +gst_test_clock_wait_for_multiple_pending_ids (GstTestClock * test_clock, + guint count, GList ** pending_list) +{ + GstTestClockPrivate *priv; + + g_return_if_fail (GST_IS_TEST_CLOCK (test_clock)); + priv = GST_TEST_CLOCK_GET_PRIVATE (test_clock); + + GST_OBJECT_LOCK (test_clock); + + while (g_list_length (priv->entry_contexts) < count) + g_cond_wait (&priv->entry_added_cond, GST_OBJECT_GET_LOCK (test_clock)); + + if (pending_list) + *pending_list = gst_test_clock_get_pending_id_list_unlocked (test_clock); + + GST_OBJECT_UNLOCK (test_clock); +} + +/** + * gst_test_clock_process_id_list: + * @test_clock: #GstTestClock for which to process the pending IDs + * @pending_list: (element-type Gst.ClockID) (transfer none) (allow-none): List + * of pending #GstClockIDs + * + * Processes and releases the pending IDs in the list. + * + * MT safe. + * + * Since: 1.4 + */ +guint +gst_test_clock_process_id_list (GstTestClock * test_clock, + const GList * pending_list) +{ + const GList *cur; + guint result = 0; + + g_return_val_if_fail (GST_IS_TEST_CLOCK (test_clock), 0); + + GST_OBJECT_LOCK (test_clock); + + for (cur = pending_list; cur != NULL; cur = cur->next) { + GstClockID pending_id = cur->data; + GstClockEntryContext *ctx = + gst_test_clock_lookup_entry_context (test_clock, pending_id); + if (ctx) { + process_entry_context_unlocked (test_clock, ctx); + result++; + } + } + GST_OBJECT_UNLOCK (test_clock); + + return result; +} + +/** + * gst_test_clock_id_list_get_latest_time: + * @pending_list: (element-type Gst.ClockID) (transfer none) (allow-none): List + * of of pending #GstClockIDs + * + * Finds the latest time inside the list. + * + * MT safe. + * + * Since: 1.4 + */ +GstClockTime +gst_test_clock_id_list_get_latest_time (const GList * pending_list) +{ + const GList *cur; + GstClockTime result = 0; + + for (cur = pending_list; cur != NULL; cur = cur->next) { + GstClockID *pending_id = cur->data; + GstClockTime time = gst_clock_id_get_time (pending_id); + if (time > result) + result = time; + } + + return result; +} diff --git a/libs/gst/check/gsttestclock.h b/libs/gst/check/gsttestclock.h index 699e169..af7a5f1 100644 --- a/libs/gst/check/gsttestclock.h +++ b/libs/gst/check/gsttestclock.h @@ -2,6 +2,8 @@ * * Copyright (C) 2008 Ole André Vadla Ravnås <ole.andre.ravnas@tandberg.com> * Copyright (C) 2012 Sebastian Rasmussen <sebastian.rasmussen@axis.com> + * Copyright (C) 2012 Havard Graff <havard@pexip.com> + * Copyright (C) 2013 Haakon Sporsheim <haakon@pexip.com> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -78,11 +80,11 @@ GstClock * gst_test_clock_new (void); GstClock * gst_test_clock_new_with_start_time (GstClockTime start_time); -void gst_test_clock_set_time (GstTestClock * test_clock, - GstClockTime new_time); +void gst_test_clock_set_time (GstTestClock * test_clock, + GstClockTime new_time); -void gst_test_clock_advance_time (GstTestClock * test_clock, - GstClockTimeDiff delta); +void gst_test_clock_advance_time (GstTestClock * test_clock, + GstClockTimeDiff delta); guint gst_test_clock_peek_id_count (GstTestClock * test_clock); @@ -91,16 +93,27 @@ gboolean gst_test_clock_has_id (GstTestClock * test_clock, GstClockID id); gboolean gst_test_clock_peek_next_pending_id (GstTestClock * test_clock, GstClockID * pending_id); -void gst_test_clock_wait_for_next_pending_id (GstTestClock * test_clock, - GstClockID * pending_id); +void gst_test_clock_wait_for_next_pending_id (GstTestClock * test_clock, + GstClockID * pending_id); +#ifndef GST_DISABLE_DEPRECATED void gst_test_clock_wait_for_pending_id_count (GstTestClock * test_clock, guint count); +#endif GstClockID gst_test_clock_process_next_clock_id (GstTestClock * test_clock); GstClockTime gst_test_clock_get_next_entry_time (GstTestClock * test_clock); +void gst_test_clock_wait_for_multiple_pending_ids (GstTestClock * test_clock, + guint count, + GList ** pending_list); + +guint gst_test_clock_process_id_list (GstTestClock * test_clock, + const GList * pending_list); + +GstClockTime gst_test_clock_id_list_get_latest_time (const GList * pending_list); + G_END_DECLS #endif /* __GST_TEST_CLOCK_H__ */ diff --git a/libs/gst/check/libcheck/Makefile.in b/libs/gst/check/libcheck/Makefile.in index ad69bac..1d3988f 100644 --- a/libs/gst/check/libcheck/Makefile.in +++ b/libs/gst/check/libcheck/Makefile.in @@ -89,7 +89,6 @@ am__aclocal_m4_deps = $(top_srcdir)/common/m4/as-ac-expand.m4 \ $(top_srcdir)/common/m4/as-compiler-flag.m4 \ $(top_srcdir)/common/m4/as-docbook.m4 \ $(top_srcdir)/common/m4/as-libtool.m4 \ - $(top_srcdir)/common/m4/as-scrub-include.m4 \ $(top_srcdir)/common/m4/as-version.m4 \ $(top_srcdir)/common/m4/ax_create_stdint_h.m4 \ $(top_srcdir)/common/m4/gst-arch.m4 \ diff --git a/libs/gst/check/libcheck/check.c b/libs/gst/check/libcheck/check.c index 9aba434..2b7f481 100644 --- a/libs/gst/check/libcheck/check.c +++ b/libs/gst/check/libcheck/check.c @@ -248,7 +248,7 @@ _fail_unless (int result, const char *file, int line, const char *expr, ...) send_failure_info (buf); if (cur_fork_status () == CK_FORK) { #ifdef _POSIX_VERSION - exit (1); + _exit (1); #endif /* _POSIX_VERSION */ } } diff --git a/libs/gst/controller/Makefile.am b/libs/gst/controller/Makefile.am index 3ae4098..4050f27 100644 --- a/libs/gst/controller/Makefile.am +++ b/libs/gst/controller/Makefile.am @@ -63,7 +63,7 @@ GstController-@GST_API_VERSION@.gir: $(INTROSPECTION_SCANNER) libgstcontroller-@ --library-path=$(top_builddir)/gst \ --library=libgstcontroller-@GST_API_VERSION@.la \ --include=Gst-@GST_API_VERSION@ \ - --libtool="$(top_builddir)/libtool" \ + --libtool="${LIBTOOL}" \ --pkg gstreamer-@GST_API_VERSION@ \ --pkg-export gstreamer-controller-@GST_API_VERSION@ \ --add-init-section="gst_init(NULL,NULL);" \ diff --git a/libs/gst/controller/Makefile.in b/libs/gst/controller/Makefile.in index 3badfc6..8a02328 100644 --- a/libs/gst/controller/Makefile.in +++ b/libs/gst/controller/Makefile.in @@ -92,7 +92,6 @@ am__aclocal_m4_deps = $(top_srcdir)/common/m4/as-ac-expand.m4 \ $(top_srcdir)/common/m4/as-compiler-flag.m4 \ $(top_srcdir)/common/m4/as-docbook.m4 \ $(top_srcdir)/common/m4/as-libtool.m4 \ - $(top_srcdir)/common/m4/as-scrub-include.m4 \ $(top_srcdir)/common/m4/as-version.m4 \ $(top_srcdir)/common/m4/ax_create_stdint_h.m4 \ $(top_srcdir)/common/m4/gst-arch.m4 \ @@ -958,7 +957,7 @@ Android.mk: Makefile.am @HAVE_INTROSPECTION_TRUE@ --library-path=$(top_builddir)/gst \ @HAVE_INTROSPECTION_TRUE@ --library=libgstcontroller-@GST_API_VERSION@.la \ @HAVE_INTROSPECTION_TRUE@ --include=Gst-@GST_API_VERSION@ \ -@HAVE_INTROSPECTION_TRUE@ --libtool="$(top_builddir)/libtool" \ +@HAVE_INTROSPECTION_TRUE@ --libtool="${LIBTOOL}" \ @HAVE_INTROSPECTION_TRUE@ --pkg gstreamer-@GST_API_VERSION@ \ @HAVE_INTROSPECTION_TRUE@ --pkg-export gstreamer-controller-@GST_API_VERSION@ \ @HAVE_INTROSPECTION_TRUE@ --add-init-section="gst_init(NULL,NULL);" \ diff --git a/libs/gst/controller/gstinterpolationcontrolsource.c b/libs/gst/controller/gstinterpolationcontrolsource.c index 0aea6cd..b8a3c22 100644 --- a/libs/gst/controller/gstinterpolationcontrolsource.c +++ b/libs/gst/controller/gstinterpolationcontrolsource.c @@ -524,7 +524,7 @@ static gboolean { GstControlSource *csource = GST_CONTROL_SOURCE (self); - if (mode >= num_interpolation_modes && (int) mode < 0) { + if (mode >= num_interpolation_modes || (int) mode < 0) { GST_WARNING ("interpolation mode %d invalid or not implemented yet", mode); return FALSE; } diff --git a/libs/gst/controller/gsttimedvaluecontrolsource.c b/libs/gst/controller/gsttimedvaluecontrolsource.c index 19cb927..0d0b8be 100644 --- a/libs/gst/controller/gsttimedvaluecontrolsource.c +++ b/libs/gst/controller/gsttimedvaluecontrolsource.c @@ -26,7 +26,7 @@ * SECTION:gsttimedvaluecontrolsource * @short_description: timed value control source base class * - * Base class for #GstContrlSources that use time-stamped values. + * Base class for #GstControlSource that use time-stamped values. * * When overriding bind, chain up first to give this bind implementation a * chance to setup things. diff --git a/libs/gst/helpers/Makefile.in b/libs/gst/helpers/Makefile.in index 6e640f6..67cb892 100644 --- a/libs/gst/helpers/Makefile.in +++ b/libs/gst/helpers/Makefile.in @@ -89,7 +89,6 @@ am__aclocal_m4_deps = $(top_srcdir)/common/m4/as-ac-expand.m4 \ $(top_srcdir)/common/m4/as-compiler-flag.m4 \ $(top_srcdir)/common/m4/as-docbook.m4 \ $(top_srcdir)/common/m4/as-libtool.m4 \ - $(top_srcdir)/common/m4/as-scrub-include.m4 \ $(top_srcdir)/common/m4/as-version.m4 \ $(top_srcdir)/common/m4/ax_create_stdint_h.m4 \ $(top_srcdir)/common/m4/gst-arch.m4 \ diff --git a/libs/gst/net/Makefile.am b/libs/gst/net/Makefile.am index dbd342b..f022b92 100644 --- a/libs/gst/net/Makefile.am +++ b/libs/gst/net/Makefile.am @@ -63,7 +63,7 @@ GstNet-@GST_API_VERSION@.gir: $(INTROSPECTION_SCANNER) libgstnet-@GST_API_VERSIO --library=libgstnet-@GST_API_VERSION@.la \ --include=Gst-@GST_API_VERSION@ \ --include=Gio-2.0 \ - --libtool="$(top_builddir)/libtool" \ + --libtool="${LIBTOOL}" \ --pkg gstreamer-@GST_API_VERSION@ \ --pkg gio-2.0 \ --pkg-export="gstreamer-net-@GST_API_VERSION@" \ diff --git a/libs/gst/net/Makefile.in b/libs/gst/net/Makefile.in index 2ec6f6e..abc967e 100644 --- a/libs/gst/net/Makefile.in +++ b/libs/gst/net/Makefile.in @@ -92,7 +92,6 @@ am__aclocal_m4_deps = $(top_srcdir)/common/m4/as-ac-expand.m4 \ $(top_srcdir)/common/m4/as-compiler-flag.m4 \ $(top_srcdir)/common/m4/as-docbook.m4 \ $(top_srcdir)/common/m4/as-libtool.m4 \ - $(top_srcdir)/common/m4/as-scrub-include.m4 \ $(top_srcdir)/common/m4/as-version.m4 \ $(top_srcdir)/common/m4/ax_create_stdint_h.m4 \ $(top_srcdir)/common/m4/gst-arch.m4 \ @@ -939,7 +938,7 @@ Android.mk: Makefile.am @HAVE_INTROSPECTION_TRUE@ --library=libgstnet-@GST_API_VERSION@.la \ @HAVE_INTROSPECTION_TRUE@ --include=Gst-@GST_API_VERSION@ \ @HAVE_INTROSPECTION_TRUE@ --include=Gio-2.0 \ -@HAVE_INTROSPECTION_TRUE@ --libtool="$(top_builddir)/libtool" \ +@HAVE_INTROSPECTION_TRUE@ --libtool="${LIBTOOL}" \ @HAVE_INTROSPECTION_TRUE@ --pkg gstreamer-@GST_API_VERSION@ \ @HAVE_INTROSPECTION_TRUE@ --pkg gio-2.0 \ @HAVE_INTROSPECTION_TRUE@ --pkg-export="gstreamer-net-@GST_API_VERSION@" \ diff --git a/libs/gst/net/gstnetaddressmeta.c b/libs/gst/net/gstnetaddressmeta.c index 118a685..164ce4f 100644 --- a/libs/gst/net/gstnetaddressmeta.c +++ b/libs/gst/net/gstnetaddressmeta.c @@ -24,8 +24,6 @@ * #GstNetAddress can be used to store a network address. #GstNetAddressMeta can * be used to store a network address in a #GstBuffer so that it network * elements can track the to and from address of the buffer. - * - * Last reviewed on 2011-11-03 (0.11.2) */ #include <string.h> diff --git a/libs/gst/net/gstnetclientclock.c b/libs/gst/net/gstnetclientclock.c index 7d9843f..dd1dafe 100644 --- a/libs/gst/net/gstnetclientclock.c +++ b/libs/gst/net/gstnetclientclock.c @@ -38,13 +38,13 @@ * This clock will poll the time provider and will update its calibration * parameters based on the local and remote observations. * + * The "round-trip" property limits the maximum round trip packets can take. + * * 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 @@ -62,12 +62,14 @@ GST_DEBUG_CATEGORY_STATIC (ncc_debug); #define DEFAULT_ADDRESS "127.0.0.1" #define DEFAULT_PORT 5637 #define DEFAULT_TIMEOUT GST_SECOND +#define DEFAULT_ROUNDTRIP_LIMIT GST_SECOND enum { PROP_0, PROP_ADDRESS, - PROP_PORT + PROP_PORT, + PROP_ROUNDTRIP_LIMIT }; #define GST_NET_CLIENT_CLOCK_GET_PRIVATE(obj) \ @@ -82,6 +84,8 @@ struct _GstNetClientClockPrivate GCancellable *cancel; GstClockTime timeout_expiration; + GstClockTime roundtrip_limit; + GstClockTime rtt_avg; gchar *address; gint port; @@ -122,6 +126,26 @@ gst_net_client_clock_class_init (GstNetClientClockClass * klass) g_param_spec_int ("port", "port", "The port on which the remote server is listening", 0, G_MAXUINT16, DEFAULT_PORT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + /** + * GstNetClientClock::round-trip-limit: + * + * Maximum allowed round-trip for packets. If this property is set to a nonzero + * value, all packets with a round-trip interval larger than this limit will be + * ignored. This is useful for networks with severe and fluctuating transport + * delays. Filtering out these packets increases stability of the synchronization. + * On the other hand, the lower the limit, the higher the amount of filtered + * packets. Empirical tests are typically necessary to estimate a good value + * for the limit. + * If the property is set to zero, the limit is disabled. + * + * Since: 1.4 + */ + g_object_class_install_property (gobject_class, PROP_ROUNDTRIP_LIMIT, + g_param_spec_uint64 ("round-trip-limit", "round-trip limit", + "Maximum tolerable round-trip interval for packets, in nanoseconds " + "(0 = no limit)", 0, G_MAXUINT64, DEFAULT_ROUNDTRIP_LIMIT, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); } static void @@ -140,6 +164,8 @@ gst_net_client_clock_init (GstNetClientClock * self) priv->thread = NULL; priv->servaddr = NULL; + priv->rtt_avg = GST_CLOCK_TIME_NONE; + priv->roundtrip_limit = DEFAULT_ROUNDTRIP_LIMIT; } static void @@ -184,6 +210,9 @@ gst_net_client_clock_set_property (GObject * object, guint prop_id, case PROP_PORT: self->priv->port = g_value_get_int (value); break; + case PROP_ROUNDTRIP_LIMIT: + self->priv->roundtrip_limit = g_value_get_uint64 (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -203,6 +232,9 @@ gst_net_client_clock_get_property (GObject * object, guint prop_id, case PROP_PORT: g_value_set_int (value, self->priv->port); break; + case PROP_ROUNDTRIP_LIMIT: + g_value_set_uint64 (value, self->priv->roundtrip_limit); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -213,21 +245,58 @@ static void gst_net_client_clock_observe_times (GstNetClientClock * self, GstClockTime local_1, GstClockTime remote, GstClockTime local_2) { + GstNetClientClockPrivate *priv = self->priv; GstClockTime current_timeout; GstClockTime local_avg; gdouble r_squared; GstClock *clock; + GstClockTime rtt; - if (local_2 < local_1) + if (local_2 < local_1) { + GST_LOG_OBJECT (self, "Dropping observation: receive time %" GST_TIME_FORMAT + " < send time %" GST_TIME_FORMAT, GST_TIME_ARGS (local_1), + GST_TIME_ARGS (local_2)); goto bogus_observation; + } + + rtt = GST_CLOCK_DIFF (local_1, local_2); + + if ((self->priv->roundtrip_limit > 0) && (rtt > self->priv->roundtrip_limit)) { + GST_LOG_OBJECT (self, + "Dropping observation: RTT %" GST_TIME_FORMAT " > limit %" + GST_TIME_FORMAT, GST_TIME_ARGS (rtt), + GST_TIME_ARGS (self->priv->roundtrip_limit)); + goto bogus_observation; + } + + /* Track an average round trip time, for a bit of smoothing */ + /* Always update before discarding a sample, so genuine changes in + * the network get picked up, eventually */ + if (priv->rtt_avg == GST_CLOCK_TIME_NONE) + priv->rtt_avg = rtt; + else if (rtt < priv->rtt_avg) /* Shorter RTTs carry more weight than longer */ + priv->rtt_avg = (3 * priv->rtt_avg + rtt) / 4; + else + priv->rtt_avg = (7 * priv->rtt_avg + rtt) / 8; + + if (rtt > 2 * priv->rtt_avg) { + GST_LOG_OBJECT (self, + "Dropping observation, long RTT %" GST_TIME_FORMAT " > 2 * avg %" + GST_TIME_FORMAT, GST_TIME_ARGS (rtt), GST_TIME_ARGS (priv->rtt_avg)); + goto bogus_observation; + } local_avg = (local_2 + local_1) / 2; + GST_LOG_OBJECT (self, "local1 %" G_GUINT64_FORMAT " remote %" G_GUINT64_FORMAT + " localavg %" G_GUINT64_FORMAT " local2 %" G_GUINT64_FORMAT, + local_1, remote, local_avg, local_2); + clock = GST_CLOCK_CAST (self); if (gst_clock_add_observation (GST_CLOCK (self), local_avg, remote, &r_squared)) { - /* geto formula */ + /* ghetto formula - shorter timeout for bad correlations */ current_timeout = (1e-3 / (1 - MIN (r_squared, 0.99999))) * GST_SECOND; current_timeout = MIN (current_timeout, gst_clock_get_timeout (clock)); } else { @@ -240,12 +309,9 @@ gst_net_client_clock_observe_times (GstNetClientClock * self, 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; - } + /* Schedule a new packet again soon */ + self->priv->timeout_expiration = gst_util_get_timestamp () + (GST_SECOND / 4); + return; } static gpointer @@ -487,7 +553,7 @@ gst_net_client_clock_stop (GstNetClientClock * self) * clock. */ GstClock * -gst_net_client_clock_new (gchar * name, const gchar * remote_address, +gst_net_client_clock_new (const gchar * name, const gchar * remote_address, gint remote_port, GstClockTime base_time) { /* FIXME: gst_net_client_clock_new() should be a thin wrapper for g_object_new() */ diff --git a/libs/gst/net/gstnetclientclock.h b/libs/gst/net/gstnetclientclock.h index 8e59807..b7243f1 100644 --- a/libs/gst/net/gstnetclientclock.h +++ b/libs/gst/net/gstnetclientclock.h @@ -70,7 +70,7 @@ struct _GstNetClientClockClass { GType gst_net_client_clock_get_type (void); -GstClock* gst_net_client_clock_new (gchar *name, const gchar *remote_address, +GstClock* gst_net_client_clock_new (const gchar *name, const gchar *remote_address, gint remote_port, GstClockTime base_time); G_END_DECLS diff --git a/libs/gst/net/gstnettimepacket.c b/libs/gst/net/gstnettimepacket.c index f6b3bef..7541995 100644 --- a/libs/gst/net/gstnettimepacket.c +++ b/libs/gst/net/gstnettimepacket.c @@ -26,8 +26,6 @@ * * Various functions for receiving, sending an serializing #GstNetTimePacket * structures. - * - * Last reviewed on 2005-11-23 (0.9.5) */ #ifdef HAVE_CONFIG_H @@ -210,7 +208,7 @@ short_packet: * * MT safe. * - * Returns: TRUE if successful, FALSE in case an error occured. + * Returns: TRUE if successful, FALSE in case an error occurred. */ gboolean gst_net_time_packet_send (const GstNetTimePacket * packet, diff --git a/libs/gst/net/gstnettimeprovider.c b/libs/gst/net/gstnettimeprovider.c index 202b6c7..8e030d7 100644 --- a/libs/gst/net/gstnettimeprovider.c +++ b/libs/gst/net/gstnettimeprovider.c @@ -31,8 +31,6 @@ * query the exposed clock over the network 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 @@ -209,8 +207,7 @@ gst_net_time_provider_thread (gpointer data) } } - if (err != NULL) - g_error_free (err); + g_error_free (err); GST_INFO_OBJECT (self, "time provider thread is stopping"); return NULL; @@ -325,7 +322,8 @@ gst_net_time_provider_start (GstNetTimeProvider * self) GST_DEBUG_OBJECT (self, "notifying port %d", port); g_object_notify (G_OBJECT (self), "port"); } - GST_DEBUG_OBJECT (self, "bound on UDP address %s, port %d", address, port); + GST_DEBUG_OBJECT (self, "bound on UDP address %s, port %d", + self->priv->address, port); g_object_unref (bound_addr); self->priv->socket = socket; |