diff options
author | Sebastian Dröge <sebastian.droege@collabora.co.uk> | 2012-06-08 09:16:25 +0200 |
---|---|---|
committer | Sebastian Dröge <sebastian.droege@collabora.co.uk> | 2012-06-08 09:16:25 +0200 |
commit | bed72dff4210fac83b878ac3b0f3ecb78d30d1d2 (patch) | |
tree | 9dd932b51f35262b1051648bb79e174f72d275da /plugins | |
parent | 50f12103f5a136f45bd274ac6a99006a3db5ca4d (diff) |
Imported Upstream version 0.11.92upstream/0.11.92
Diffstat (limited to 'plugins')
-rw-r--r-- | plugins/Makefile.in | 9 | ||||
-rw-r--r-- | plugins/elements/Makefile.in | 9 | ||||
-rw-r--r-- | plugins/elements/gstfakesrc.c | 4 | ||||
-rw-r--r-- | plugins/elements/gstfakesrc.h | 3 | ||||
-rw-r--r-- | plugins/elements/gstfilesrc.c | 6 | ||||
-rw-r--r-- | plugins/elements/gstfunnel.c | 62 | ||||
-rw-r--r-- | plugins/elements/gstinputselector.c | 679 | ||||
-rw-r--r-- | plugins/elements/gstinputselector.h | 14 | ||||
-rw-r--r-- | plugins/elements/gstqueue2.c | 31 | ||||
-rw-r--r-- | plugins/elements/gsttypefindelement.c | 6 |
10 files changed, 656 insertions, 167 deletions
diff --git a/plugins/Makefile.in b/plugins/Makefile.in index 4d019da..099c0e4 100644 --- a/plugins/Makefile.in +++ b/plugins/Makefile.in @@ -50,6 +50,7 @@ PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ +target_triplet = @target@ subdir = plugins DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 @@ -256,6 +257,10 @@ GST_VERSION_MICRO = @GST_VERSION_MICRO@ GST_VERSION_MINOR = @GST_VERSION_MINOR@ GST_VERSION_NANO = @GST_VERSION_NANO@ GTKDOC_CHECK = @GTKDOC_CHECK@ +GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@ +GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@ +GTKDOC_MKPDF = @GTKDOC_MKPDF@ +GTKDOC_REBASE = @GTKDOC_REBASE@ HAVE_DOCBOOK2HTML = @HAVE_DOCBOOK2HTML@ HAVE_DOCBOOK2PS = @HAVE_DOCBOOK2PS@ HAVE_DVIPS = @HAVE_DVIPS@ @@ -408,7 +413,11 @@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ +target = @target@ target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ diff --git a/plugins/elements/Makefile.in b/plugins/elements/Makefile.in index 15c6d3d..56a2e0c 100644 --- a/plugins/elements/Makefile.in +++ b/plugins/elements/Makefile.in @@ -52,6 +52,7 @@ PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ +target_triplet = @target@ subdir = plugins/elements DIST_COMMON = $(noinst_HEADERS) $(srcdir)/Makefile.am \ $(srcdir)/Makefile.in @@ -301,6 +302,10 @@ GST_VERSION_MICRO = @GST_VERSION_MICRO@ GST_VERSION_MINOR = @GST_VERSION_MINOR@ GST_VERSION_NANO = @GST_VERSION_NANO@ GTKDOC_CHECK = @GTKDOC_CHECK@ +GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@ +GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@ +GTKDOC_MKPDF = @GTKDOC_MKPDF@ +GTKDOC_REBASE = @GTKDOC_REBASE@ HAVE_DOCBOOK2HTML = @HAVE_DOCBOOK2HTML@ HAVE_DOCBOOK2PS = @HAVE_DOCBOOK2PS@ HAVE_DVIPS = @HAVE_DVIPS@ @@ -453,7 +458,11 @@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ +target = @target@ target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ diff --git a/plugins/elements/gstfakesrc.c b/plugins/elements/gstfakesrc.c index c9b2c45..89eb17b 100644 --- a/plugins/elements/gstfakesrc.c +++ b/plugins/elements/gstfakesrc.c @@ -357,7 +357,6 @@ static void gst_fake_src_init (GstFakeSrc * fakesrc) { fakesrc->output = FAKE_SRC_FIRST_LAST_LOOP; - fakesrc->buffer_count = 0; fakesrc->silent = DEFAULT_SILENT; fakesrc->signal_handoffs = DEFAULT_SIGNAL_HANDOFFS; fakesrc->dump = DEFAULT_DUMP; @@ -781,7 +780,7 @@ gst_fake_src_create (GstBaseSrc * basesrc, guint64 offset, guint length, src = GST_FAKE_SRC (basesrc); buf = gst_fake_src_create_buffer (src, &size); - GST_BUFFER_OFFSET (buf) = src->buffer_count++; + GST_BUFFER_OFFSET (buf) = offset; if (src->datarate > 0) { time = (src->bytes_sent * GST_SECOND) / src->datarate; @@ -885,7 +884,6 @@ gst_fake_src_start (GstBaseSrc * basesrc) src = GST_FAKE_SRC (basesrc); - src->buffer_count = 0; src->pattern_byte = 0x00; src->bytes_sent = 0; diff --git a/plugins/elements/gstfakesrc.h b/plugins/elements/gstfakesrc.h index 00675c2..965fcb0 100644 --- a/plugins/elements/gstfakesrc.h +++ b/plugins/elements/gstfakesrc.h @@ -140,9 +140,6 @@ struct _GstFakeSrc { gboolean sync; GstClock *clock; - gint num_buffers; - gint rt_num_buffers; /* we are going to change this at runtime */ - gint64 buffer_count; gboolean silent; gboolean signal_handoffs; gboolean dump; diff --git a/plugins/elements/gstfilesrc.c b/plugins/elements/gstfilesrc.c index 8536f4a..a0672d1 100644 --- a/plugins/elements/gstfilesrc.c +++ b/plugins/elements/gstfilesrc.c @@ -461,7 +461,7 @@ could_not_stat: } } -/* open the file and mmap it, necessary to go to READY state */ +/* open the file, necessary to go to READY state */ static gboolean gst_file_src_start (GstBaseSrc * basesrc) { @@ -500,8 +500,8 @@ gst_file_src_start (GstBaseSrc * basesrc) off_t res = lseek (src->fd, 0, SEEK_END); if (res < 0) { - GST_LOG_OBJECT (src, "disabling seeking, not in mmap mode and lseek " - "failed: %s", g_strerror (errno)); + GST_LOG_OBJECT (src, "disabling seeking, lseek failed: %s", + g_strerror (errno)); src->seekable = FALSE; } else { src->seekable = TRUE; diff --git a/plugins/elements/gstfunnel.c b/plugins/elements/gstfunnel.c index 9a9f455..a15a9e6 100644 --- a/plugins/elements/gstfunnel.c +++ b/plugins/elements/gstfunnel.c @@ -67,6 +67,7 @@ struct _GstFunnelPad GstPad parent; GstSegment segment; + gboolean got_eos; }; struct _GstFunnelPadClass @@ -85,6 +86,7 @@ static void gst_funnel_pad_reset (GstFunnelPad * pad) { gst_segment_init (&pad->segment, GST_FORMAT_UNDEFINED); + pad->got_eos = FALSE; } static void @@ -203,16 +205,48 @@ gst_funnel_request_new_pad (GstElement * element, GstPadTemplate * templ, return sinkpad; } +static gboolean +gst_funnel_all_sinkpads_eos_unlocked (GstFunnel * funnel) +{ + GstElement *element = GST_ELEMENT_CAST (funnel); + GList *item; + + if (element->numsinkpads == 0) + return FALSE; + + for (item = element->sinkpads; item != NULL; item = g_list_next (item)) { + GstFunnelPad *sinkpad = item->data; + + if (!sinkpad->got_eos) + return FALSE; + } + + return TRUE; +} + static void gst_funnel_release_pad (GstElement * element, GstPad * pad) { GstFunnel *funnel = GST_FUNNEL (element); + GstFunnelPad *fpad = GST_FUNNEL_PAD_CAST (pad); + gboolean send_eos = FALSE; GST_DEBUG_OBJECT (funnel, "releasing pad"); gst_pad_set_active (pad, FALSE); gst_element_remove_pad (GST_ELEMENT_CAST (funnel), pad); + + GST_OBJECT_LOCK (funnel); + if (!fpad->got_eos && gst_funnel_all_sinkpads_eos_unlocked (funnel)) { + GST_DEBUG_OBJECT (funnel, "Pad removed. All others are EOS. Sending EOS"); + send_eos = TRUE; + } + GST_OBJECT_UNLOCK (funnel); + + if (send_eos) + if (!gst_pad_push_event (funnel->srcpad, gst_event_new_eos ())) + GST_WARNING_OBJECT (funnel, "Failure pushing EOS"); } static GstFlowReturn @@ -230,6 +264,15 @@ gst_funnel_sink_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer) GST_DEBUG_OBJECT (funnel, "received buffer %p", buffer); GST_OBJECT_LOCK (funnel); + + if (fpad->got_eos) { + GST_OBJECT_UNLOCK (funnel); + GST_WARNING_OBJECT (funnel, "Got buffer on pad that received EOS"); + res = GST_FLOW_EOS; + gst_buffer_unref (buffer); + goto out; + } + if (fpad->segment.format == GST_FORMAT_UNDEFINED) { GST_WARNING_OBJECT (funnel, "Got buffer without segment," " setting segment [0,inf["); @@ -267,6 +310,7 @@ gst_funnel_sink_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer) if (GST_BUFFER_CAPS (buffer) && GST_BUFFER_CAPS (buffer) != padcaps) { if (!gst_pad_set_caps (funnel->srcpad, GST_BUFFER_CAPS (buffer))) { res = GST_FLOW_NOT_NEGOTIATED; + gst_buffer_unref (buffer); goto out; } } @@ -276,9 +320,7 @@ gst_funnel_sink_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer) GST_LOG_OBJECT (funnel, "handled buffer %s", gst_flow_get_name (res)); -#if 0 out: -#endif return res; } @@ -306,6 +348,22 @@ gst_funnel_sink_event (GstPad * pad, GstObject * parent, GstEvent * event) GST_OBJECT_LOCK (funnel); gst_segment_init (&fpad->segment, GST_FORMAT_UNDEFINED); funnel->has_segment = FALSE; + fpad->got_eos = FALSE; + GST_OBJECT_UNLOCK (funnel); + } + break; + case GST_EVENT_EOS: + { + GST_OBJECT_LOCK (funnel); + fpad->got_eos = TRUE; + + if (!gst_funnel_all_sinkpads_eos_unlocked (funnel)) { + GST_DEBUG_OBJECT (funnel, + "Got EOS, but not from all sinkpads. Skipping"); + forward = FALSE; + } else { + GST_DEBUG_OBJECT (funnel, "Got EOS from all sinkpads. Forwarding"); + } GST_OBJECT_UNLOCK (funnel); break; } diff --git a/plugins/elements/gstinputselector.c b/plugins/elements/gstinputselector.c index eb6fba5..9133a8c 100644 --- a/plugins/elements/gstinputselector.c +++ b/plugins/elements/gstinputselector.c @@ -61,9 +61,47 @@ #include "gst/glib-compat-private.h" +#define DEBUG_CACHED_BUFFERS 0 + GST_DEBUG_CATEGORY_STATIC (input_selector_debug); #define GST_CAT_DEFAULT input_selector_debug +#define GST_TYPE_INPUT_SELECTOR_SYNC_MODE (gst_input_selector_sync_mode_get_type()) +static GType +gst_input_selector_sync_mode_get_type (void) +{ + static GType type = 0; + static const GEnumValue data[] = { + {GST_INPUT_SELECTOR_SYNC_MODE_ACTIVE_SEGMENT, + "Sync using the current active segment", + "active-segment"}, + {GST_INPUT_SELECTOR_SYNC_MODE_CLOCK, "Sync using the clock", "clock"}, + {0, NULL, NULL}, + }; + + if (!type) { + type = g_enum_register_static ("GstInputSelectorSyncMode", data); + } + return type; +} + +#if GLIB_CHECK_VERSION(2, 26, 0) +#define NOTIFY_MUTEX_LOCK() +#define NOTIFY_MUTEX_UNLOCK() +#else +static GStaticRecMutex notify_mutex = G_STATIC_REC_MUTEX_INIT; +#define NOTIFY_MUTEX_LOCK() g_static_rec_mutex_lock (¬ify_mutex) +#define NOTIFY_MUTEX_UNLOCK() g_static_rec_mutex_unlock (¬ify_mutex) +#endif + +#define GST_INPUT_SELECTOR_GET_LOCK(sel) (&((GstInputSelector*)(sel))->lock) +#define GST_INPUT_SELECTOR_GET_COND(sel) (&((GstInputSelector*)(sel))->cond) +#define GST_INPUT_SELECTOR_LOCK(sel) (g_mutex_lock (GST_INPUT_SELECTOR_GET_LOCK(sel))) +#define GST_INPUT_SELECTOR_UNLOCK(sel) (g_mutex_unlock (GST_INPUT_SELECTOR_GET_LOCK(sel))) +#define GST_INPUT_SELECTOR_WAIT(sel) (g_cond_wait (GST_INPUT_SELECTOR_GET_COND(sel), \ + GST_INPUT_SELECTOR_GET_LOCK(sel))) +#define GST_INPUT_SELECTOR_BROADCAST(sel) (g_cond_broadcast (GST_INPUT_SELECTOR_GET_COND(sel))) + static GstStaticPadTemplate gst_input_selector_sink_factory = GST_STATIC_PAD_TEMPLATE ("sink_%u", GST_PAD_SINK, @@ -81,11 +119,14 @@ enum PROP_0, PROP_N_PADS, PROP_ACTIVE_PAD, - PROP_SYNC_STREAMS + PROP_SYNC_STREAMS, + PROP_SYNC_MODE, + PROP_CACHE_BUFFERS }; #define DEFAULT_SYNC_STREAMS TRUE - +#define DEFAULT_SYNC_MODE GST_INPUT_SELECTOR_SYNC_MODE_ACTIVE_SEGMENT +#define DEFAULT_CACHE_BUFFERS FALSE #define DEFAULT_PAD_ALWAYS_OK TRUE enum @@ -106,6 +147,8 @@ enum }; static guint gst_input_selector_signals[LAST_SIGNAL] = { 0 }; +static void gst_input_selector_active_pad_changed (GstInputSelector * sel, + GParamSpec * pspec, gpointer user_data); static inline gboolean gst_input_selector_is_active_sinkpad (GstInputSelector * sel, GstPad * pad); static GstPad *gst_input_selector_activate_sinkpad (GstInputSelector * sel, @@ -128,6 +171,7 @@ static GstPad *gst_input_selector_get_linked_pad (GstInputSelector * sel, typedef struct _GstSelectorPad GstSelectorPad; typedef struct _GstSelectorPadClass GstSelectorPadClass; +typedef struct _GstSelectorPadCachedBuffer GstSelectorPadCachedBuffer; struct _GstSelectorPad { @@ -147,6 +191,15 @@ struct _GstSelectorPad guint32 segment_seqnum; /* sequence number of the current segment */ gboolean events_pending; /* TRUE if sticky events need to be updated */ + + gboolean sending_cached_buffers; + GQueue *cached_buffers; +}; + +struct _GstSelectorPadCachedBuffer +{ + GstBuffer *buffer; + GstSegment segment; }; struct _GstSelectorPadClass @@ -171,6 +224,9 @@ static GstIterator *gst_selector_pad_iterate_linked_pads (GstPad * pad, GstObject * parent); static GstFlowReturn gst_selector_pad_chain (GstPad * pad, GstObject * parent, GstBuffer * buf); +static void gst_selector_pad_cache_buffer (GstSelectorPad * selpad, + GstBuffer * buffer); +static void gst_selector_pad_free_cached_buffers (GstSelectorPad * selpad); G_DEFINE_TYPE (GstSelectorPad, gst_selector_pad, GST_TYPE_PAD); @@ -220,7 +276,8 @@ gst_selector_pad_finalize (GObject * object) pad = GST_SELECTOR_PAD_CAST (object); if (pad->tags) - gst_tag_list_free (pad->tags); + gst_tag_list_unref (pad->tags); + gst_selector_pad_free_cached_buffers (pad); G_OBJECT_CLASS (gst_selector_pad_parent_class)->finalize (object); } @@ -293,12 +350,13 @@ gst_selector_pad_get_running_time (GstSelectorPad * pad) } GST_OBJECT_UNLOCK (pad); - GST_DEBUG_OBJECT (pad, "running time: %" GST_TIME_FORMAT, - GST_TIME_ARGS (ret)); + GST_DEBUG_OBJECT (pad, "running time: %" GST_TIME_FORMAT + " segment: %" GST_SEGMENT_FORMAT, GST_TIME_ARGS (ret), &pad->segment); return ret; } +/* must be called with the SELECTOR_LOCK */ static void gst_selector_pad_reset (GstSelectorPad * pad) { @@ -312,9 +370,61 @@ gst_selector_pad_reset (GstSelectorPad * pad) pad->flushing = FALSE; pad->position = GST_CLOCK_TIME_NONE; gst_segment_init (&pad->segment, GST_FORMAT_UNDEFINED); + pad->sending_cached_buffers = FALSE; + gst_selector_pad_free_cached_buffers (pad); GST_OBJECT_UNLOCK (pad); } +static GstSelectorPadCachedBuffer * +gst_selector_pad_new_cached_buffer (GstSelectorPad * selpad, GstBuffer * buffer) +{ + GstSelectorPadCachedBuffer *cached_buffer = + g_slice_new (GstSelectorPadCachedBuffer); + cached_buffer->buffer = buffer; + cached_buffer->segment = selpad->segment; + return cached_buffer; +} + +static void +gst_selector_pad_free_cached_buffer (GstSelectorPadCachedBuffer * cached_buffer) +{ + gst_buffer_unref (cached_buffer->buffer); + g_slice_free (GstSelectorPadCachedBuffer, cached_buffer); +} + +/* must be called with the SELECTOR_LOCK */ +static void +gst_selector_pad_cache_buffer (GstSelectorPad * selpad, GstBuffer * buffer) +{ + if (selpad->segment.format != GST_FORMAT_TIME) { + GST_DEBUG_OBJECT (selpad, "Buffer %p with segment not in time format, " + "not caching", buffer); + return; + } + + GST_DEBUG_OBJECT (selpad, "Caching buffer %p", buffer); + if (!selpad->cached_buffers) + selpad->cached_buffers = g_queue_new (); + g_queue_push_tail (selpad->cached_buffers, + gst_selector_pad_new_cached_buffer (selpad, buffer)); +} + +/* must be called with the SELECTOR_LOCK */ +static void +gst_selector_pad_free_cached_buffers (GstSelectorPad * selpad) +{ + GstSelectorPadCachedBuffer *cached_buffer; + + if (!selpad->cached_buffers) + return; + + GST_DEBUG_OBJECT (selpad, "Freeing cached buffers"); + while ((cached_buffer = g_queue_pop_head (selpad->cached_buffers))) + gst_selector_pad_free_cached_buffer (cached_buffer); + g_queue_free (selpad->cached_buffers); + selpad->cached_buffers = NULL; +} + /* strictly get the linked pad from the sinkpad. If the pad is active we return * the srcpad else we return NULL */ static GstIterator * @@ -351,36 +461,34 @@ gst_selector_pad_event (GstPad * pad, GstObject * parent, GstEvent * event) sel = GST_INPUT_SELECTOR (parent); selpad = GST_SELECTOR_PAD_CAST (pad); + GST_DEBUG_OBJECT (selpad, "received event %" GST_PTR_FORMAT, event); GST_INPUT_SELECTOR_LOCK (sel); prev_active_sinkpad = sel->active_sinkpad; active_sinkpad = gst_input_selector_activate_sinkpad (sel, pad); - - /* only forward if we are dealing with the active sinkpad */ - forward = (pad == active_sinkpad); GST_INPUT_SELECTOR_UNLOCK (sel); if (prev_active_sinkpad != active_sinkpad && pad == active_sinkpad) { g_object_notify (G_OBJECT (sel), "active-pad"); } + GST_INPUT_SELECTOR_LOCK (sel); + active_sinkpad = gst_input_selector_activate_sinkpad (sel, pad); + + /* only forward if we are dealing with the active sinkpad */ + forward = (pad == active_sinkpad); + switch (GST_EVENT_TYPE (event)) { case GST_EVENT_FLUSH_START: /* Unblock the pad if it's waiting */ - GST_INPUT_SELECTOR_LOCK (sel); selpad->flushing = TRUE; GST_INPUT_SELECTOR_BROADCAST (sel); - GST_INPUT_SELECTOR_UNLOCK (sel); break; case GST_EVENT_FLUSH_STOP: - GST_INPUT_SELECTOR_LOCK (sel); gst_selector_pad_reset (selpad); - GST_INPUT_SELECTOR_UNLOCK (sel); break; case GST_EVENT_SEGMENT: { - GST_INPUT_SELECTOR_LOCK (sel); - GST_OBJECT_LOCK (selpad); gst_event_copy_segment (event, &selpad->segment); selpad->segment_seqnum = gst_event_get_seqnum (event); @@ -400,9 +508,6 @@ gst_selector_pad_event (GstPad * pad, GstObject * parent, GstEvent * event) } GST_DEBUG_OBJECT (pad, "configured SEGMENT %" GST_SEGMENT_FORMAT, &selpad->segment); - - GST_OBJECT_UNLOCK (selpad); - GST_INPUT_SELECTOR_UNLOCK (sel); break; } case GST_EVENT_TAG: @@ -411,15 +516,13 @@ gst_selector_pad_event (GstPad * pad, GstObject * parent, GstEvent * event) gst_event_parse_tag (event, &tags); - GST_OBJECT_LOCK (selpad); oldtags = selpad->tags; newtags = gst_tag_list_merge (oldtags, tags, GST_TAG_MERGE_REPLACE); selpad->tags = newtags; if (oldtags) - gst_tag_list_free (oldtags); + gst_tag_list_unref (oldtags); GST_DEBUG_OBJECT (pad, "received tags %" GST_PTR_FORMAT, newtags); - GST_OBJECT_UNLOCK (selpad); g_object_notify (G_OBJECT (selpad), "tags"); break; @@ -430,7 +533,7 @@ gst_selector_pad_event (GstPad * pad, GstObject * parent, GstEvent * event) if (forward) { selpad->eos_sent = TRUE; } else { - GstSelectorPad *tmp; + GstSelectorPad *active_selpad; /* If the active sinkpad is in EOS state but EOS * was not sent downstream this means that the pad @@ -438,18 +541,16 @@ gst_selector_pad_event (GstPad * pad, GstObject * parent, GstEvent * event) * the previously active pad got EOS after it was * active */ - GST_INPUT_SELECTOR_LOCK (sel); - active_sinkpad = gst_input_selector_activate_sinkpad (sel, pad); - tmp = GST_SELECTOR_PAD (active_sinkpad); - forward = (tmp->eos && !tmp->eos_sent); - tmp->eos_sent = TRUE; - GST_INPUT_SELECTOR_UNLOCK (sel); + active_selpad = GST_SELECTOR_PAD (active_sinkpad); + forward = (active_selpad->eos && !active_selpad->eos_sent); + active_selpad->eos_sent = TRUE; } GST_DEBUG_OBJECT (pad, "received EOS"); break; default: break; } + GST_INPUT_SELECTOR_UNLOCK (sel); if (forward) { GST_DEBUG_OBJECT (pad, "forwarding event"); res = gst_pad_push_event (sel->srcpad, event); @@ -495,103 +596,121 @@ gst_input_selector_wait (GstInputSelector * self, GstSelectorPad * pad) return self->flushing; } -/* must be called with the SELECTOR_LOCK, will block until the running time +/* must be called without the SELECTOR_LOCK, will wait until the running time * of the active pad is after this pad or return TRUE when flushing */ static gboolean gst_input_selector_wait_running_time (GstInputSelector * sel, - GstSelectorPad * pad, GstBuffer * buf) + GstSelectorPad * selpad, GstBuffer * buf) { - GstPad *active_sinkpad; - GstSelectorPad *active_selpad; - GstSegment *seg, *active_seg; - GstClockTime running_time, active_running_time = GST_CLOCK_TIME_NONE; - - seg = &pad->segment; - - active_sinkpad = - gst_input_selector_activate_sinkpad (sel, GST_PAD_CAST (pad)); - active_selpad = GST_SELECTOR_PAD_CAST (active_sinkpad); - active_seg = &active_selpad->segment; - - /* We can only sync if the segments are in time format or - * if the active pad had no newsegment event yet */ - if (seg->format != GST_FORMAT_TIME || - (active_seg->format != GST_FORMAT_TIME - && active_seg->format != GST_FORMAT_UNDEFINED)) - return FALSE; + GstSegment *seg; - /* If we have no valid timestamp we can't sync this buffer */ - if (!GST_BUFFER_TIMESTAMP_IS_VALID (buf)) - return FALSE; + GST_DEBUG_OBJECT (selpad, "entering wait for buffer %p", buf); - running_time = GST_BUFFER_TIMESTAMP (buf); - /* If possible try to get the running time at the end of the buffer */ - if (GST_BUFFER_DURATION_IS_VALID (buf)) - running_time += GST_BUFFER_DURATION (buf); - if (running_time > seg->stop) - running_time = seg->stop; - running_time = - gst_segment_to_running_time (seg, GST_FORMAT_TIME, running_time); - /* If this is outside the segment don't sync */ - if (running_time == -1) + /* If we have no valid timestamp we can't sync this buffer */ + if (!GST_BUFFER_TIMESTAMP_IS_VALID (buf)) { + GST_DEBUG_OBJECT (selpad, "leaving wait for buffer with " + "invalid timestamp"); return FALSE; + } - /* Get active pad's running time, if no configured segment yet keep at -1 */ - if (active_seg->format == GST_FORMAT_TIME) - active_running_time = - gst_segment_to_running_time (active_seg, GST_FORMAT_TIME, - active_selpad->position); + seg = &selpad->segment; /* Wait until * a) this is the active pad * b) the pad or the selector is flushing * c) the selector is not blocked - * d) the active pad has no running time or the active - * pad's running time is before this running time - * e) the active pad has a non-time segment - * f) the active pad changed and has not pushed anything + * d) the buffer running time is before the current running time + * (either active-seg or clock, depending on sync-mode) */ - while (pad != active_selpad && !sel->flushing && !pad->flushing - && active_selpad->pushed && (sel->blocked || active_running_time == -1 - || running_time >= active_running_time)) { - if (!sel->blocked) - GST_DEBUG_OBJECT (pad, - "Waiting for active streams to advance. %" GST_TIME_FORMAT " >= %" - GST_TIME_FORMAT, GST_TIME_ARGS (running_time), - GST_TIME_ARGS (active_running_time)); - - GST_INPUT_SELECTOR_WAIT (sel); - - /* Get new active pad, it might have changed */ + + GST_INPUT_SELECTOR_LOCK (sel); + while (TRUE) { + GstPad *active_sinkpad; + GstSelectorPad *active_selpad; + GstClock *clock; + gint64 cur_running_time; + GstClockTime running_time; + active_sinkpad = - gst_input_selector_activate_sinkpad (sel, GST_PAD_CAST (pad)); + gst_input_selector_activate_sinkpad (sel, GST_PAD_CAST (selpad)); active_selpad = GST_SELECTOR_PAD_CAST (active_sinkpad); - active_seg = &active_selpad->segment; - /* If the active segment is configured but not to time format - * we can't do any syncing at all */ - if (active_seg->format != GST_FORMAT_TIME - && active_seg->format != GST_FORMAT_UNDEFINED) - break; + if (seg->format != GST_FORMAT_TIME) { + GST_INPUT_SELECTOR_UNLOCK (sel); + return FALSE; + } - /* Get the new active pad running time */ - if (active_seg->format == GST_FORMAT_TIME) - active_running_time = - gst_segment_to_running_time (active_seg, GST_FORMAT_TIME, - active_selpad->position); - else - active_running_time = -1; + running_time = GST_BUFFER_TIMESTAMP (buf); + /* If possible try to get the running time at the end of the buffer */ + if (GST_BUFFER_DURATION_IS_VALID (buf)) + running_time += GST_BUFFER_DURATION (buf); + /* Only use the segment to convert to running time if the segment is + * in TIME format, otherwise do our best to try to sync */ + if (GST_CLOCK_TIME_IS_VALID (seg->stop)) { + if (running_time > seg->stop) { + running_time = seg->stop; + } + } + running_time = + gst_segment_to_running_time (seg, GST_FORMAT_TIME, running_time); + /* If this is outside the segment don't sync */ + if (running_time == -1) { + GST_INPUT_SELECTOR_UNLOCK (sel); + return FALSE; + } + + cur_running_time = GST_CLOCK_TIME_NONE; + if (sel->sync_mode == GST_INPUT_SELECTOR_SYNC_MODE_CLOCK) { + clock = gst_element_get_clock (GST_ELEMENT_CAST (sel)); + if (clock) { + GstClockTime base_time; + + cur_running_time = gst_clock_get_time (clock); + base_time = gst_element_get_base_time (GST_ELEMENT_CAST (sel)); + if (base_time <= cur_running_time) + cur_running_time -= base_time; + else + cur_running_time = 0; + } + } else { + GstSegment *active_seg; + + active_seg = &active_selpad->segment; + + /* If the active segment is configured but not to time format + * we can't do any syncing at all */ + if (active_seg->format != GST_FORMAT_TIME + && active_seg->format != GST_FORMAT_UNDEFINED) { + GST_INPUT_SELECTOR_UNLOCK (sel); + return FALSE; + } + + /* Get active pad's running time, if no configured segment yet keep at -1 */ + if (active_seg->format == GST_FORMAT_TIME) + cur_running_time = gst_segment_to_running_time (active_seg, + GST_FORMAT_TIME, active_seg->position); + } - if (!sel->blocked) - GST_DEBUG_OBJECT (pad, - "Waited for active streams to advance. %" GST_TIME_FORMAT " >= %" - GST_TIME_FORMAT, GST_TIME_ARGS (running_time), - GST_TIME_ARGS (active_running_time)); + if (selpad != active_selpad && !sel->flushing && !selpad->flushing && + (sel->cache_buffers || active_selpad->pushed) && + (sel->blocked || cur_running_time == -1 + || running_time >= cur_running_time)) { + if (!sel->blocked) { + GST_DEBUG_OBJECT (selpad, + "Waiting for active streams to advance. %" GST_TIME_FORMAT " >= %" + GST_TIME_FORMAT, GST_TIME_ARGS (running_time), + GST_TIME_ARGS (cur_running_time)); + } + GST_INPUT_SELECTOR_WAIT (sel); + } else { + GST_INPUT_SELECTOR_UNLOCK (sel); + break; + } } /* Return TRUE if the selector or the pad is flushing */ - return (sel->flushing || pad->flushing); + return (sel->flushing || selpad->flushing); } static gboolean @@ -614,6 +733,164 @@ forward_sticky_events (GstPad * sinkpad, GstEvent ** event, gpointer user_data) return TRUE; } +#if DEBUG_CACHED_BUFFERS +static void +gst_input_selector_debug_cached_buffers (GstInputSelector * sel) +{ + GList *walk; + + for (walk = GST_ELEMENT_CAST (sel)->sinkpads; walk; walk = g_list_next (walk)) { + GstSelectorPad *selpad; + GString *timestamps; + gchar *str; + int i; + + selpad = GST_SELECTOR_PAD_CAST (walk->data); + if (!selpad->cached_buffers) { + GST_DEBUG_OBJECT (selpad, "Cached buffers timestamps: <none>"); + continue; + } + + timestamps = g_string_new ("Cached buffers timestamps:"); + for (i = 0; i < selpad->cached_buffers->length; ++i) { + GstSelectorPadCachedBuffer *cached_buffer; + + cached_buffer = g_queue_peek_nth (selpad->cached_buffers, i); + g_string_append_printf (timestamps, " %" GST_TIME_FORMAT, + GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (cached_buffer->buffer))); + } + str = g_string_free (timestamps, FALSE); + GST_DEBUG_OBJECT (selpad, str); + g_free (str); + } +} +#endif + +/* must be called with the SELECTOR_LOCK */ +static void +gst_input_selector_cleanup_old_cached_buffers (GstInputSelector * sel, + GstPad * pad) +{ + GstClock *clock; + gint64 cur_running_time; + GList *walk; + + cur_running_time = GST_CLOCK_TIME_NONE; + if (sel->sync_mode == GST_INPUT_SELECTOR_SYNC_MODE_CLOCK) { + clock = gst_element_get_clock (GST_ELEMENT_CAST (sel)); + if (clock) { + GstClockTime base_time; + + cur_running_time = gst_clock_get_time (clock); + base_time = gst_element_get_base_time (GST_ELEMENT_CAST (sel)); + if (base_time <= cur_running_time) + cur_running_time -= base_time; + else + cur_running_time = 0; + } + } else { + GstPad *active_sinkpad; + GstSelectorPad *active_selpad; + GstSegment *active_seg; + + active_sinkpad = gst_input_selector_activate_sinkpad (sel, pad); + active_selpad = GST_SELECTOR_PAD_CAST (active_sinkpad); + active_seg = &active_selpad->segment; + + /* Get active pad's running time, if no configured segment yet keep at -1 */ + if (active_seg->format == GST_FORMAT_TIME) + cur_running_time = gst_segment_to_running_time (active_seg, + GST_FORMAT_TIME, active_seg->position); + } + + if (!GST_CLOCK_TIME_IS_VALID (cur_running_time)) + return; + + GST_DEBUG_OBJECT (sel, "Cleaning up old cached buffers"); + for (walk = GST_ELEMENT_CAST (sel)->sinkpads; walk; walk = g_list_next (walk)) { + GstSelectorPad *selpad; + GstSegment *seg; + GstSelectorPadCachedBuffer *cached_buffer; + GSList *maybe_remove; + guint queue_position; + + selpad = GST_SELECTOR_PAD_CAST (walk->data); + if (!selpad->cached_buffers) + continue; + + seg = &selpad->segment; + + maybe_remove = NULL; + queue_position = 0; + while ((cached_buffer = g_queue_peek_nth (selpad->cached_buffers, + queue_position))) { + GstBuffer *buffer = cached_buffer->buffer; + GstClockTime running_time; + GSList *l; + + /* If we have no valid timestamp we can't sync this buffer */ + if (!GST_BUFFER_TIMESTAMP_IS_VALID (buffer)) { + maybe_remove = g_slist_append (maybe_remove, cached_buffer); + queue_position = g_slist_length (maybe_remove); + continue; + } + + /* the buffer is still valid if its duration is valid and the + * timestamp + duration is >= time, or if its duration is invalid + * and the timestamp is >= time */ + running_time = GST_BUFFER_TIMESTAMP (buffer); + /* If possible try to get the running time at the end of the buffer */ + if (GST_BUFFER_DURATION_IS_VALID (buffer)) + running_time += GST_BUFFER_DURATION (buffer); + /* Only use the segment to convert to running time if the segment is + * in TIME format, otherwise do our best to try to sync */ + if (GST_CLOCK_TIME_IS_VALID (seg->stop)) { + if (running_time > seg->stop) { + running_time = seg->stop; + } + } + running_time = + gst_segment_to_running_time (seg, GST_FORMAT_TIME, running_time); + + GST_DEBUG_OBJECT (selpad, + "checking if buffer %p running time=%" GST_TIME_FORMAT + " >= stream time=%" GST_TIME_FORMAT, buffer, + GST_TIME_ARGS (running_time), GST_TIME_ARGS (cur_running_time)); + if (running_time >= cur_running_time) { + break; + } + + GST_DEBUG_OBJECT (selpad, "Removing old cached buffer %p", buffer); + g_queue_pop_nth (selpad->cached_buffers, queue_position); + gst_selector_pad_free_cached_buffer (cached_buffer); + + for (l = maybe_remove; l != NULL; l = g_slist_next (l)) { + /* A buffer after some invalid buffers was removed, it means the invalid buffers + * are old, lets also remove them */ + cached_buffer = l->data; + g_queue_remove (selpad->cached_buffers, cached_buffer); + gst_selector_pad_free_cached_buffer (cached_buffer); + } + + g_slist_free (maybe_remove); + maybe_remove = NULL; + queue_position = 0; + } + + g_slist_free (maybe_remove); + maybe_remove = NULL; + + if (g_queue_is_empty (selpad->cached_buffers)) { + g_queue_free (selpad->cached_buffers); + selpad->cached_buffers = NULL; + } + } + +#if DEBUG_CACHED_BUFFERS + gst_input_selector_debug_cached_buffers (sel); +#endif +} + static GstFlowReturn gst_selector_pad_chain (GstPad * pad, GstObject * parent, GstBuffer * buf) { @@ -627,10 +904,16 @@ gst_selector_pad_chain (GstPad * pad, GstObject * parent, GstBuffer * buf) sel = GST_INPUT_SELECTOR (parent); selpad = GST_SELECTOR_PAD_CAST (pad); + GST_DEBUG_OBJECT (selpad, + "entering chain for buf %p with timestamp %" GST_TIME_FORMAT, buf, + GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf))); + GST_INPUT_SELECTOR_LOCK (sel); /* wait or check for flushing */ - if (gst_input_selector_wait (sel, selpad)) + if (gst_input_selector_wait (sel, selpad)) { + GST_INPUT_SELECTOR_UNLOCK (sel); goto flushing; + } GST_LOG_OBJECT (pad, "getting active pad"); @@ -639,13 +922,57 @@ gst_selector_pad_chain (GstPad * pad, GstObject * parent, GstBuffer * buf) /* In sync mode wait until the active pad has advanced * after the running time of the current buffer */ - if (sel->sync_streams && active_sinkpad != pad) { - if (gst_input_selector_wait_running_time (sel, selpad, buf)) - goto flushing; - } + if (sel->sync_streams) { + /* call chain for each cached buffer if we are not the active pad + * or if we are the active pad but didn't push anything yet. */ + if (active_sinkpad != pad || !selpad->pushed) { + /* no need to check for sel->cache_buffers as selpad->cached_buffers + * will only be valid if cache_buffers is TRUE */ + if (selpad->cached_buffers && !selpad->sending_cached_buffers) { + GstSelectorPadCachedBuffer *cached_buffer; + GstSegment saved_segment; + + saved_segment = selpad->segment; + + selpad->sending_cached_buffers = TRUE; + while (!sel->flushing && !selpad->flushing && + (cached_buffer = g_queue_pop_head (selpad->cached_buffers))) { + GST_DEBUG_OBJECT (pad, "Cached buffers found, " + "invoking chain for cached buffer %p", cached_buffer->buffer); + + selpad->segment = cached_buffer->segment; + selpad->events_pending = TRUE; + GST_INPUT_SELECTOR_UNLOCK (sel); + gst_selector_pad_chain (pad, parent, cached_buffer->buffer); + GST_INPUT_SELECTOR_LOCK (sel); + + /* we may have cleaned up the queue in the meantime because of + * old buffers */ + if (!selpad->cached_buffers) { + break; + } + } + selpad->sending_cached_buffers = FALSE; - /* Might have changed while waiting */ - active_sinkpad = gst_input_selector_activate_sinkpad (sel, pad); + /* all cached buffers sent, restore segment for current buffer */ + selpad->segment = saved_segment; + selpad->events_pending = TRUE; + + /* Might have changed while calling chain for cached buffers */ + active_sinkpad = gst_input_selector_activate_sinkpad (sel, pad); + } + } + + if (active_sinkpad != pad) { + GST_INPUT_SELECTOR_UNLOCK (sel); + if (gst_input_selector_wait_running_time (sel, selpad, buf)) + goto flushing; + GST_INPUT_SELECTOR_LOCK (sel); + } + + /* Might have changed while waiting */ + active_sinkpad = gst_input_selector_activate_sinkpad (sel, pad); + } /* update the segment on the srcpad */ start_time = GST_BUFFER_TIMESTAMP (buf); @@ -693,10 +1020,29 @@ gst_selector_pad_chain (GstPad * pad, GstObject * parent, GstBuffer * buf) } /* forward */ - GST_LOG_OBJECT (pad, "Forwarding buffer %p", buf); + GST_LOG_OBJECT (pad, "Forwarding buffer %p with timestamp %" GST_TIME_FORMAT, + buf, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf))); + + res = gst_pad_push (sel->srcpad, gst_buffer_ref (buf)); + GST_LOG_OBJECT (pad, "Buffer %p forwarded result=%d", buf, res); + + GST_INPUT_SELECTOR_LOCK (sel); - res = gst_pad_push (sel->srcpad, buf); - selpad->pushed = TRUE; + if (sel->sync_streams && sel->cache_buffers) { + /* Might have changed while pushing */ + active_sinkpad = gst_input_selector_activate_sinkpad (sel, pad); + /* only set pad to pushed if we are still the active pad */ + if (active_sinkpad == pad) + selpad->pushed = TRUE; + + /* cache buffer as we may need it again if we change pads */ + gst_selector_pad_cache_buffer (selpad, buf); + gst_input_selector_cleanup_old_cached_buffers (sel, pad); + } else { + selpad->pushed = TRUE; + gst_buffer_unref (buf); + } + GST_INPUT_SELECTOR_UNLOCK (sel); done: return res; @@ -725,7 +1071,6 @@ ignore: flushing: { GST_DEBUG_OBJECT (pad, "We are flushing, discard buffer %p", buf); - GST_INPUT_SELECTOR_UNLOCK (sel); gst_buffer_unref (buf); res = GST_FLOW_FLUSHING; goto done; @@ -818,16 +1163,59 @@ gst_input_selector_class_init (GstInputSelectorClass * klass) * GstInputSelector:sync-streams * * If set to %TRUE all inactive streams will be synced to the - * running time of the active stream. This makes sure that no - * buffers are dropped by input-selector that might be needed - * when switching the active pad. + * running time of the active stream or to the current clock. + * + * To make sure no buffers are dropped by input-selector + * that might be needed when switching the active pad, + * sync-mode should be set to "clock" and cache-buffers to TRUE. * * Since: 0.10.36 */ g_object_class_install_property (gobject_class, PROP_SYNC_STREAMS, g_param_spec_boolean ("sync-streams", "Sync Streams", - "Synchronize inactive streams to the running time of the active stream", - DEFAULT_SYNC_STREAMS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + "Synchronize inactive streams to the running time of the active " + "stream or to the current clock", + DEFAULT_SYNC_STREAMS, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | + GST_PARAM_MUTABLE_READY)); + + /** + * GstInputSelector:sync-mode + * + * Select how input-selector will sync buffers when in sync-streams mode. + * + * Note that when using the "active-segment" mode, the "active-segment" may + * be ahead of current clock time when switching the active pad, as the current + * active pad may have pushed more buffers than what was displayed/consumed, + * which may cause delays and some missing buffers. + * + * Since: 0.10.36 + */ + g_object_class_install_property (gobject_class, PROP_SYNC_MODE, + g_param_spec_enum ("sync-mode", "Sync mode", + "Behavior in sync-streams mode", GST_TYPE_INPUT_SELECTOR_SYNC_MODE, + DEFAULT_SYNC_MODE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | + GST_PARAM_MUTABLE_READY)); + + /** + * GstInputSelector:cache-buffers + * + * If set to %TRUE and GstInputSelector:sync-streams is also set to %TRUE, + * the active pad will cache the buffers still considered valid (after current + * running time, see sync-mode) to avoid missing frames if/when the pad is + * reactivated. + * + * The active pad may push more buffers than what is currently displayed/consumed + * and when changing pads those buffers will be discarded and the only way to + * reactivate that pad without loosing the already consumed buffers is to enable cache. + */ + g_object_class_install_property (gobject_class, PROP_CACHE_BUFFERS, + g_param_spec_boolean ("cache-buffers", "Cache Buffers", + "Cache buffers for active-pad", + DEFAULT_CACHE_BUFFERS, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | + GST_PARAM_MUTABLE_READY)); /** * GstInputSelector::block: @@ -880,6 +1268,12 @@ gst_input_selector_init (GstInputSelector * sel) g_mutex_init (&sel->lock); g_cond_init (&sel->cond); sel->blocked = FALSE; + + /* lets give a change for downstream to do something on + * active-pad change before we start pushing new buffers */ + g_signal_connect_data (sel, "notify::active-pad", + (GCallback) gst_input_selector_active_pad_changed, NULL, + NULL, G_CONNECT_AFTER); } static void @@ -934,13 +1328,6 @@ gst_input_selector_set_active_pad (GstInputSelector * self, GstPad * pad) active_pad_p = &self->active_sinkpad; gst_object_replace ((GstObject **) active_pad_p, GST_OBJECT_CAST (pad)); - gst_pad_push_event (pad, gst_event_new_reconfigure ()); - - /* Wake up all non-active pads in sync mode, they might be - * the active pad now */ - if (self->sync_streams) - GST_INPUT_SELECTOR_BROADCAST (self); - GST_DEBUG_OBJECT (self, "New active pad is %" GST_PTR_FORMAT, self->active_sinkpad); @@ -961,17 +1348,35 @@ gst_input_selector_set_property (GObject * object, guint prop_id, pad = g_value_get_object (value); GST_INPUT_SELECTOR_LOCK (sel); + +#if DEBUG_CACHED_BUFFERS + gst_input_selector_debug_cached_buffers (sel); +#endif + gst_input_selector_set_active_pad (sel, pad); + +#if DEBUG_CACHED_BUFFERS + gst_input_selector_debug_cached_buffers (sel); +#endif + GST_INPUT_SELECTOR_UNLOCK (sel); break; } case PROP_SYNC_STREAMS: - { GST_INPUT_SELECTOR_LOCK (sel); sel->sync_streams = g_value_get_boolean (value); GST_INPUT_SELECTOR_UNLOCK (sel); break; - } + case PROP_SYNC_MODE: + GST_INPUT_SELECTOR_LOCK (sel); + sel->sync_mode = g_value_get_enum (value); + GST_INPUT_SELECTOR_UNLOCK (sel); + break; + case PROP_CACHE_BUFFERS: + GST_INPUT_SELECTOR_LOCK (object); + sel->cache_buffers = g_value_get_boolean (value); + GST_INPUT_SELECTOR_UNLOCK (object); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -979,6 +1384,16 @@ gst_input_selector_set_property (GObject * object, guint prop_id, } static void +gst_input_selector_active_pad_changed (GstInputSelector * sel, + GParamSpec * pspec, gpointer user_data) +{ + /* Wake up all non-active pads in sync mode, they might be + * the active pad now */ + if (sel->sync_streams) + GST_INPUT_SELECTOR_BROADCAST (sel); +} + +static void gst_input_selector_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) { @@ -1000,6 +1415,16 @@ gst_input_selector_get_property (GObject * object, guint prop_id, g_value_set_boolean (value, sel->sync_streams); GST_INPUT_SELECTOR_UNLOCK (object); break; + case PROP_SYNC_MODE: + GST_INPUT_SELECTOR_LOCK (object); + g_value_set_enum (value, sel->sync_mode); + GST_INPUT_SELECTOR_UNLOCK (object); + break; + case PROP_CACHE_BUFFERS: + GST_INPUT_SELECTOR_LOCK (object); + g_value_set_boolean (value, sel->cache_buffers); + GST_INPUT_SELECTOR_UNLOCK (object); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -1270,7 +1695,7 @@ gst_input_selector_reset (GstInputSelector * sel) gst_selector_pad_reset (selpad); if (selpad->tags) { - gst_tag_list_free (selpad->tags); + gst_tag_list_unref (selpad->tags); selpad->tags = NULL; } } diff --git a/plugins/elements/gstinputselector.h b/plugins/elements/gstinputselector.h index 8a5248a..dd48a51 100644 --- a/plugins/elements/gstinputselector.h +++ b/plugins/elements/gstinputselector.h @@ -48,6 +48,18 @@ typedef struct _GstInputSelectorClass GstInputSelectorClass; GST_INPUT_SELECTOR_GET_LOCK(sel))) #define GST_INPUT_SELECTOR_BROADCAST(sel) (g_cond_broadcast (GST_INPUT_SELECTOR_GET_COND(sel))) +/** + * GstInputSelectorSyncMode: + * @GST_INPUT_SELECTOR_SYNC_MODE_ACTIVE_SEGMENT: Sync using the current active segment. + * @GST_INPUT_SELECTOR_SYNC_MODE_CLOCK: Sync using the clock. + * + * The different ways that input-selector can behave when in sync-streams mode. + */ +typedef enum { + GST_INPUT_SELECTOR_SYNC_MODE_ACTIVE_SEGMENT, + GST_INPUT_SELECTOR_SYNC_MODE_CLOCK +} GstInputSelectorSyncMode; + struct _GstInputSelector { GstElement element; @@ -57,6 +69,8 @@ struct _GstInputSelector { guint n_pads; guint padcount; gboolean sync_streams; + GstInputSelectorSyncMode sync_mode; + gboolean cache_buffers; GMutex lock; GCond cond; diff --git a/plugins/elements/gstqueue2.c b/plugins/elements/gstqueue2.c index 82e2e11..158da10 100644 --- a/plugins/elements/gstqueue2.c +++ b/plugins/elements/gstqueue2.c @@ -41,7 +41,7 @@ * The default queue size limits are 100 buffers, 2MB of data, or * two seconds worth of data, whichever is reached first. * - * If you set temp-tmpl to a value such as /tmp/gstreamer-XXXXXX, the element + * If you set temp-template to a value such as /tmp/gstreamer-XXXXXX, the element * will allocate a random free filename and buffer data in the file. * By using this, it will buffer the entire stream data on the file independently * of the queue size limits, they will only be used for buffering statistics. @@ -2427,21 +2427,8 @@ next: if (item_type == GST_QUEUE2_ITEM_TYPE_BUFFER) { GstBuffer *buffer; -#if 0 - GstCaps *caps; -#endif buffer = GST_BUFFER_CAST (data); -#if 0 - caps = GST_BUFFER_CAPS (buffer); -#endif - -#if 0 - /* set caps before pushing the buffer so that core does not try to do - * something fancy to check if this is possible. */ - if (caps && caps != GST_PAD_CAPS (queue->srcpad)) - gst_pad_set_caps (queue->srcpad, caps); -#endif result = gst_pad_push (queue->srcpad, buffer); @@ -2471,23 +2458,9 @@ next: GST_QUEUE2_MUTEX_LOCK_CHECK (queue, queue->srcresult, out_flushing); } else if (item_type == GST_QUEUE2_ITEM_TYPE_BUFFER_LIST) { GstBufferList *buffer_list; -#if 0 - GstBuffer *first_buf; - GstCaps *caps; -#endif buffer_list = GST_BUFFER_LIST_CAST (data); -#if 0 - first_buf = gst_buffer_list_get (buffer_list, 0); - caps = (first_buf != NULL) ? GST_BUFFER_CAPS (first_buf) : NULL; - - /* set caps before pushing the buffer so that core does not try to do - * something fancy to check if this is possible. */ - if (caps && caps != GST_PAD_CAPS (queue->srcpad)) - gst_pad_set_caps (queue->srcpad, caps); -#endif - result = gst_pad_push_list (queue->srcpad, buffer_list); /* need to check for srcresult here as well */ @@ -3222,7 +3195,7 @@ gst_queue2_set_property (GObject * object, case PROP_TEMP_LOCATION: g_free (queue->temp_location); queue->temp_location = g_value_dup_string (value); - /* you can set the property back to NULL to make it use the temp-tmpl + /* you can set the property back to NULL to make it use the temp-template * property. */ queue->temp_location_set = queue->temp_location != NULL; break; diff --git a/plugins/elements/gsttypefindelement.c b/plugins/elements/gsttypefindelement.c index 436a4e9..e6c4de2 100644 --- a/plugins/elements/gsttypefindelement.c +++ b/plugins/elements/gsttypefindelement.c @@ -1190,6 +1190,12 @@ gst_type_find_element_activate_sink (GstPad * pad, GstObject * parent) g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE], 0, probability, found_caps); typefind->mode = MODE_NORMAL; + /* the signal above could have made a downstream element activate + * the pad in pull mode, we check if the pad is already active now and if + * so, we are done */ + if (gst_pad_is_active (pad)) + return TRUE; + goto typefind_push; } GST_OBJECT_UNLOCK (typefind); |