c82b0d46ff9ee3b29df3b95c6c4dcee41dc764eb
[platform/upstream/gstreamer.git] / libs / gst / base / gstcollectpads.c
1 /* GStreamer
2  * Copyright (C) 2005 Wim Taymans <wim@fluendo.com>
3  * Copyright (C) 2008 Mark Nauwelaerts <mnauw@users.sourceforge.net>
4  * Copyright (C) 2010 Sebastian Dröge <sebastian.droege@collabora.co.uk>
5  *
6  * gstcollectpads.c:
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public
19  * License along with this library; if not, write to the
20  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
21  * Boston, MA 02110-1301, USA.
22  */
23 /**
24  * SECTION:gstcollectpads
25  * @short_description: manages a set of pads that operate in collect mode
26  * @see_also:
27  *
28  * Manages a set of pads that operate in collect mode. This means that control
29  * is given to the manager of this object when all pads have data.
30  * <itemizedlist>
31  *   <listitem><para>
32  *     Collectpads are created with gst_collect_pads_new(). A callback should then
33  *     be installed with gst_collect_pads_set_function ().
34  *   </para></listitem>
35  *   <listitem><para>
36  *     Pads are added to the collection with gst_collect_pads_add_pad()/
37  *     gst_collect_pads_remove_pad(). The pad
38  *     has to be a sinkpad. The chain and event functions of the pad are
39  *     overridden. The element_private of the pad is used to store
40  *     private information for the collectpads.
41  *   </para></listitem>
42  *   <listitem><para>
43  *     For each pad, data is queued in the _chain function or by
44  *     performing a pull_range.
45  *   </para></listitem>
46  *   <listitem><para>
47  *     When data is queued on all pads in waiting mode, the callback function is called.
48  *   </para></listitem>
49  *   <listitem><para>
50  *     Data can be dequeued from the pad with the gst_collect_pads_pop() method.
51  *     One can peek at the data with the gst_collect_pads_peek() function.
52  *     These functions will return NULL if the pad received an EOS event. When all
53  *     pads return NULL from a gst_collect_pads_peek(), the element can emit an EOS
54  *     event itself.
55  *   </para></listitem>
56  *   <listitem><para>
57  *     Data can also be dequeued in byte units using the gst_collect_pads_available(),
58  *     gst_collect_pads_read_buffer() and gst_collect_pads_flush() calls.
59  *   </para></listitem>
60  *   <listitem><para>
61  *     Elements should call gst_collect_pads_start() and gst_collect_pads_stop() in
62  *     their state change functions to start and stop the processing of the collectpads.
63  *     The gst_collect_pads_stop() call should be called before calling the parent
64  *     element state change function in the PAUSED_TO_READY state change to ensure
65  *     no pad is blocked and the element can finish streaming.
66  *   </para></listitem>
67  *   <listitem><para>
68  *     gst_collect_pads_set_waiting() sets a pad to waiting or non-waiting mode.
69  *     CollectPads element is not waiting for data to be collected on non-waiting pads.
70  *     Thus these pads may but need not have data when the callback is called.
71  *     All pads are in waiting mode by default.
72  *   </para></listitem>
73  * </itemizedlist>
74  *
75  * Last reviewed on 2011-10-28 (0.10.36)
76  */
77
78 #ifdef HAVE_CONFIG_H
79 #  include "config.h"
80 #endif
81
82 #include <gst/gst_private.h>
83
84 #include "gstcollectpads.h"
85
86 #include "../../../gst/glib-compat-private.h"
87
88 GST_DEBUG_CATEGORY_STATIC (collect_pads_debug);
89 #define GST_CAT_DEFAULT collect_pads_debug
90
91 #define parent_class gst_collect_pads_parent_class
92 G_DEFINE_TYPE (GstCollectPads, gst_collect_pads, GST_TYPE_OBJECT);
93
94 struct _GstCollectDataPrivate
95 {
96   /* refcounting for struct, and destroy callback */
97   GstCollectDataDestroyNotify destroy_notify;
98   gint refcount;
99 };
100
101 struct _GstCollectPadsPrivate
102 {
103   /* with LOCK and/or STREAM_LOCK */
104   gboolean started;
105
106   /* with STREAM_LOCK */
107   guint32 cookie;               /* @data list cookie */
108   guint numpads;                /* number of pads in @data */
109   guint queuedpads;             /* number of pads with a buffer */
110   guint eospads;                /* number of pads that are EOS */
111   GstClockTime earliest_time;   /* Current earliest time */
112   GstCollectData *earliest_data;        /* Pad data for current earliest time */
113
114   /* with LOCK */
115   GSList *pad_list;             /* updated pad list */
116   guint32 pad_cookie;           /* updated cookie */
117
118   GstCollectPadsFunction func;  /* function and user_data for callback */
119   gpointer user_data;
120   GstCollectPadsBufferFunction buffer_func;     /* function and user_data for buffer callback */
121   gpointer buffer_user_data;
122   GstCollectPadsCompareFunction compare_func;
123   gpointer compare_user_data;
124   GstCollectPadsEventFunction event_func;       /* function and data for event callback */
125   gpointer event_user_data;
126   GstCollectPadsQueryFunction query_func;
127   gpointer query_user_data;
128   GstCollectPadsClipFunction clip_func;
129   gpointer clip_user_data;
130   GstCollectPadsFlushFunction flush_func;
131   gpointer flush_user_data;
132
133   /* no other lock needed */
134   GMutex evt_lock;              /* these make up sort of poor man's event signaling */
135   GCond evt_cond;
136   guint32 evt_cookie;
137
138   gboolean seeking;
139   gboolean pending_flush_start;
140   gboolean pending_flush_stop;
141 };
142
143 static void gst_collect_pads_clear (GstCollectPads * pads,
144     GstCollectData * data);
145 static GstFlowReturn gst_collect_pads_chain (GstPad * pad, GstObject * parent,
146     GstBuffer * buffer);
147 static gboolean gst_collect_pads_event (GstPad * pad, GstObject * parent,
148     GstEvent * event);
149 static gboolean gst_collect_pads_query (GstPad * pad, GstObject * parent,
150     GstQuery * query);
151 static void gst_collect_pads_finalize (GObject * object);
152 static GstFlowReturn gst_collect_pads_default_collected (GstCollectPads *
153     pads, gpointer user_data);
154 static gint gst_collect_pads_default_compare_func (GstCollectPads * pads,
155     GstCollectData * data1, GstClockTime timestamp1, GstCollectData * data2,
156     GstClockTime timestamp2, gpointer user_data);
157 static gboolean gst_collect_pads_recalculate_full (GstCollectPads * pads);
158 static void ref_data (GstCollectData * data);
159 static void unref_data (GstCollectData * data);
160
161 static gboolean gst_collect_pads_event_default_internal (GstCollectPads *
162     pads, GstCollectData * data, GstEvent * event, gpointer user_data);
163 static gboolean gst_collect_pads_query_default_internal (GstCollectPads *
164     pads, GstCollectData * data, GstQuery * query, gpointer user_data);
165
166
167 /* Some properties are protected by LOCK, others by STREAM_LOCK
168  * However, manipulating either of these partitions may require
169  * to signal/wake a _WAIT, so use a separate (sort of) event to prevent races
170  * Alternative implementations are possible, e.g. some low-level re-implementing
171  * of the 2 above locks to drop both of them atomically when going into _WAIT.
172  */
173 #define GST_COLLECT_PADS_GET_EVT_COND(pads) (&((GstCollectPads *)pads)->priv->evt_cond)
174 #define GST_COLLECT_PADS_GET_EVT_LOCK(pads) (&((GstCollectPads *)pads)->priv->evt_lock)
175 #define GST_COLLECT_PADS_EVT_WAIT(pads, cookie) G_STMT_START {    \
176   g_mutex_lock (GST_COLLECT_PADS_GET_EVT_LOCK (pads));            \
177   /* should work unless a lot of event'ing and thread starvation */\
178   while (cookie == ((GstCollectPads *) pads)->priv->evt_cookie)         \
179     g_cond_wait (GST_COLLECT_PADS_GET_EVT_COND (pads),            \
180         GST_COLLECT_PADS_GET_EVT_LOCK (pads));                    \
181   cookie = ((GstCollectPads *) pads)->priv->evt_cookie;                 \
182   g_mutex_unlock (GST_COLLECT_PADS_GET_EVT_LOCK (pads));          \
183 } G_STMT_END
184 #define GST_COLLECT_PADS_EVT_WAIT_TIMED(pads, cookie, timeout) G_STMT_START { \
185   GTimeVal __tv; \
186   \
187   g_get_current_time (&tv); \
188   g_time_val_add (&tv, timeout); \
189   \
190   g_mutex_lock (GST_COLLECT_PADS_GET_EVT_LOCK (pads));            \
191   /* should work unless a lot of event'ing and thread starvation */\
192   while (cookie == ((GstCollectPads *) pads)->priv->evt_cookie)         \
193     g_cond_timed_wait (GST_COLLECT_PADS_GET_EVT_COND (pads),            \
194         GST_COLLECT_PADS_GET_EVT_LOCK (pads), &tv);                    \
195   cookie = ((GstCollectPads *) pads)->priv->evt_cookie;                 \
196   g_mutex_unlock (GST_COLLECT_PADS_GET_EVT_LOCK (pads));          \
197 } G_STMT_END
198 #define GST_COLLECT_PADS_EVT_BROADCAST(pads) G_STMT_START {       \
199   g_mutex_lock (GST_COLLECT_PADS_GET_EVT_LOCK (pads));            \
200   /* never mind wrap-around */                                     \
201   ++(((GstCollectPads *) pads)->priv->evt_cookie);                      \
202   g_cond_broadcast (GST_COLLECT_PADS_GET_EVT_COND (pads));        \
203   g_mutex_unlock (GST_COLLECT_PADS_GET_EVT_LOCK (pads));          \
204 } G_STMT_END
205 #define GST_COLLECT_PADS_EVT_INIT(cookie) G_STMT_START {          \
206   g_mutex_lock (GST_COLLECT_PADS_GET_EVT_LOCK (pads));            \
207   cookie = ((GstCollectPads *) pads)->priv->evt_cookie;                 \
208   g_mutex_unlock (GST_COLLECT_PADS_GET_EVT_LOCK (pads));          \
209 } G_STMT_END
210
211 static void
212 gst_collect_pads_class_init (GstCollectPadsClass * klass)
213 {
214   GObjectClass *gobject_class = (GObjectClass *) klass;
215
216   g_type_class_add_private (klass, sizeof (GstCollectPadsPrivate));
217
218   GST_DEBUG_CATEGORY_INIT (collect_pads_debug, "collectpads", 0,
219       "GstCollectPads");
220
221   gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_collect_pads_finalize);
222 }
223
224 static void
225 gst_collect_pads_init (GstCollectPads * pads)
226 {
227   pads->priv =
228       G_TYPE_INSTANCE_GET_PRIVATE (pads, GST_TYPE_COLLECT_PADS,
229       GstCollectPadsPrivate);
230
231   pads->data = NULL;
232   pads->priv->cookie = 0;
233   pads->priv->numpads = 0;
234   pads->priv->queuedpads = 0;
235   pads->priv->eospads = 0;
236   pads->priv->started = FALSE;
237
238   g_rec_mutex_init (&pads->stream_lock);
239
240   pads->priv->func = gst_collect_pads_default_collected;
241   pads->priv->user_data = NULL;
242   pads->priv->event_func = NULL;
243   pads->priv->event_user_data = NULL;
244
245   /* members for default muxing */
246   pads->priv->buffer_func = NULL;
247   pads->priv->buffer_user_data = NULL;
248   pads->priv->compare_func = gst_collect_pads_default_compare_func;
249   pads->priv->compare_user_data = NULL;
250   pads->priv->earliest_data = NULL;
251   pads->priv->earliest_time = GST_CLOCK_TIME_NONE;
252
253   pads->priv->event_func = gst_collect_pads_event_default_internal;
254   pads->priv->query_func = gst_collect_pads_query_default_internal;
255
256   /* members to manage the pad list */
257   pads->priv->pad_cookie = 0;
258   pads->priv->pad_list = NULL;
259
260   /* members for event */
261   g_mutex_init (&pads->priv->evt_lock);
262   g_cond_init (&pads->priv->evt_cond);
263   pads->priv->evt_cookie = 0;
264
265   pads->priv->seeking = FALSE;
266   pads->priv->pending_flush_start = FALSE;
267   pads->priv->pending_flush_stop = FALSE;
268 }
269
270 static void
271 gst_collect_pads_finalize (GObject * object)
272 {
273   GstCollectPads *pads = GST_COLLECT_PADS (object);
274
275   GST_DEBUG_OBJECT (object, "finalize");
276
277   g_rec_mutex_clear (&pads->stream_lock);
278
279   g_cond_clear (&pads->priv->evt_cond);
280   g_mutex_clear (&pads->priv->evt_lock);
281
282   /* Remove pads and free pads list */
283   g_slist_foreach (pads->priv->pad_list, (GFunc) unref_data, NULL);
284   g_slist_foreach (pads->data, (GFunc) unref_data, NULL);
285   g_slist_free (pads->data);
286   g_slist_free (pads->priv->pad_list);
287
288   G_OBJECT_CLASS (parent_class)->finalize (object);
289 }
290
291 /**
292  * gst_collect_pads_new:
293  *
294  * Create a new instance of #GstCollectPads.
295  *
296  * MT safe.
297  *
298  * Returns: (transfer full): a new #GstCollectPads, or NULL in case of an error.
299  */
300 GstCollectPads *
301 gst_collect_pads_new (void)
302 {
303   GstCollectPads *newcoll;
304
305   newcoll = g_object_new (GST_TYPE_COLLECT_PADS, NULL);
306
307   return newcoll;
308 }
309
310 /* Must be called with GstObject lock! */
311 static void
312 gst_collect_pads_set_buffer_function_locked (GstCollectPads * pads,
313     GstCollectPadsBufferFunction func, gpointer user_data)
314 {
315   pads->priv->buffer_func = func;
316   pads->priv->buffer_user_data = user_data;
317 }
318
319 /**
320  * gst_collect_pads_set_buffer_function:
321  * @pads: the collectpads to use
322  * @func: the function to set
323  * @user_data: (closure): user data passed to the function
324  *
325  * Set the callback function and user data that will be called with
326  * the oldest buffer when all pads have been collected, or NULL on EOS.
327  * If a buffer is passed, the callback owns a reference and must unref
328  * it.
329  *
330  * MT safe.
331  */
332 void
333 gst_collect_pads_set_buffer_function (GstCollectPads * pads,
334     GstCollectPadsBufferFunction func, gpointer user_data)
335 {
336   g_return_if_fail (pads != NULL);
337   g_return_if_fail (GST_IS_COLLECT_PADS (pads));
338
339   GST_OBJECT_LOCK (pads);
340   gst_collect_pads_set_buffer_function_locked (pads, func, user_data);
341   GST_OBJECT_UNLOCK (pads);
342 }
343
344 /**
345  * gst_collect_pads_set_compare_function:
346  * @pads: the pads to use
347  * @func: the function to set
348  * @user_data: (closure): user data passed to the function
349  *
350  * Set the timestamp comparison function.
351  *
352  * MT safe.
353  */
354 /* NOTE allowing to change comparison seems not advisable;
355 no known use-case, and collaboration with default algorithm is unpredictable.
356 If custom compairing/operation is needed, just use a collect function of
357 your own */
358 void
359 gst_collect_pads_set_compare_function (GstCollectPads * pads,
360     GstCollectPadsCompareFunction func, gpointer user_data)
361 {
362   g_return_if_fail (pads != NULL);
363   g_return_if_fail (GST_IS_COLLECT_PADS (pads));
364
365   GST_OBJECT_LOCK (pads);
366   pads->priv->compare_func = func;
367   pads->priv->compare_user_data = user_data;
368   GST_OBJECT_UNLOCK (pads);
369 }
370
371 /**
372  * gst_collect_pads_set_function:
373  * @pads: the collectpads to use
374  * @func: the function to set
375  * @user_data: user data passed to the function
376  *
377  * CollectPads provides a default collection algorithm that will determine
378  * the oldest buffer available on all of its pads, and then delegate
379  * to a configured callback.
380  * However, if circumstances are more complicated and/or more control
381  * is desired, this sets a callback that will be invoked instead when
382  * all the pads added to the collection have buffers queued.
383  * Evidently, this callback is not compatible with
384  * gst_collect_pads_set_buffer_function() callback.
385  * If this callback is set, the former will be unset.
386  *
387  * MT safe.
388  */
389 void
390 gst_collect_pads_set_function (GstCollectPads * pads,
391     GstCollectPadsFunction func, gpointer user_data)
392 {
393   g_return_if_fail (pads != NULL);
394   g_return_if_fail (GST_IS_COLLECT_PADS (pads));
395
396   GST_OBJECT_LOCK (pads);
397   pads->priv->func = func;
398   pads->priv->user_data = user_data;
399   gst_collect_pads_set_buffer_function_locked (pads, NULL, NULL);
400   GST_OBJECT_UNLOCK (pads);
401 }
402
403 static void
404 ref_data (GstCollectData * data)
405 {
406   g_assert (data != NULL);
407
408   g_atomic_int_inc (&(data->priv->refcount));
409 }
410
411 static void
412 unref_data (GstCollectData * data)
413 {
414   g_assert (data != NULL);
415   g_assert (data->priv->refcount > 0);
416
417   if (!g_atomic_int_dec_and_test (&(data->priv->refcount)))
418     return;
419
420   if (data->priv->destroy_notify)
421     data->priv->destroy_notify (data);
422
423   g_object_unref (data->pad);
424   if (data->buffer) {
425     gst_buffer_unref (data->buffer);
426   }
427   g_free (data->priv);
428   g_free (data);
429 }
430
431 /**
432  * gst_collect_pads_set_event_function:
433  * @pads: the collectpads to use
434  * @func: the function to set
435  * @user_data: user data passed to the function
436  *
437  * Set the event callback function and user data that will be called when
438  * collectpads has received an event originating from one of the collected
439  * pads.  If the event being processed is a serialized one, this callback is
440  * called with @pads STREAM_LOCK held, otherwise not.  As this lock should be
441  * held when calling a number of CollectPads functions, it should be acquired
442  * if so (unusually) needed.
443  *
444  * MT safe.
445  */
446 void
447 gst_collect_pads_set_event_function (GstCollectPads * pads,
448     GstCollectPadsEventFunction func, gpointer user_data)
449 {
450   g_return_if_fail (pads != NULL);
451   g_return_if_fail (GST_IS_COLLECT_PADS (pads));
452
453   GST_OBJECT_LOCK (pads);
454   pads->priv->event_func = func;
455   pads->priv->event_user_data = user_data;
456   GST_OBJECT_UNLOCK (pads);
457 }
458
459 /**
460  * gst_collect_pads_set_query_function:
461  * @pads: the collectpads to use
462  * @func: the function to set
463  * @user_data: user data passed to the function
464  *
465  * Set the query callback function and user data that will be called after
466  * collectpads has received a query originating from one of the collected
467  * pads.  If the query being processed is a serialized one, this callback is
468  * called with @pads STREAM_LOCK held, otherwise not.  As this lock should be
469  * held when calling a number of CollectPads functions, it should be acquired
470  * if so (unusually) needed.
471  *
472  * MT safe.
473  */
474 void
475 gst_collect_pads_set_query_function (GstCollectPads * pads,
476     GstCollectPadsQueryFunction func, gpointer user_data)
477 {
478   g_return_if_fail (pads != NULL);
479   g_return_if_fail (GST_IS_COLLECT_PADS (pads));
480
481   GST_OBJECT_LOCK (pads);
482   pads->priv->query_func = func;
483   pads->priv->query_user_data = user_data;
484   GST_OBJECT_UNLOCK (pads);
485 }
486
487 /**
488 * gst_collect_pads_clip_running_time:
489 * @pads: the collectpads to use
490 * @cdata: collect data of corresponding pad
491 * @buf: buffer being clipped
492 * @outbuf: (allow-none): output buffer with running time, or NULL if clipped
493 * @user_data: user data (unused)
494 *
495 * Convenience clipping function that converts incoming buffer's timestamp
496 * to running time, or clips the buffer if outside configured segment.
497 */
498 GstFlowReturn
499 gst_collect_pads_clip_running_time (GstCollectPads * pads,
500     GstCollectData * cdata, GstBuffer * buf, GstBuffer ** outbuf,
501     gpointer user_data)
502 {
503   GstClockTime time;
504
505   *outbuf = buf;
506   time = GST_BUFFER_PTS (buf);
507
508   /* invalid left alone and passed */
509   if (G_LIKELY (GST_CLOCK_TIME_IS_VALID (time))) {
510     time = gst_segment_to_running_time (&cdata->segment, GST_FORMAT_TIME, time);
511     if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (time))) {
512       GST_DEBUG_OBJECT (cdata->pad, "clipping buffer on pad outside segment");
513       gst_buffer_unref (buf);
514       *outbuf = NULL;
515     } else {
516       GST_LOG_OBJECT (cdata->pad, "buffer ts %" GST_TIME_FORMAT " -> %"
517           GST_TIME_FORMAT " running time",
518           GST_TIME_ARGS (GST_BUFFER_PTS (buf)), GST_TIME_ARGS (time));
519       *outbuf = gst_buffer_make_writable (buf);
520       GST_BUFFER_PTS (*outbuf) = time;
521       GST_BUFFER_DTS (*outbuf) = gst_segment_to_running_time (&cdata->segment,
522           GST_FORMAT_TIME, GST_BUFFER_DTS (*outbuf));
523     }
524   }
525
526   return GST_FLOW_OK;
527 }
528
529 /**
530  * gst_collect_pads_set_clip_function:
531  * @pads: the collectpads to use
532  * @clipfunc: clip function to install
533  * @user_data: user data to pass to @clip_func
534  *
535  * Install a clipping function that is called right after a buffer is received
536  * on a pad managed by @pads. See #GstCollectPadsClipFunction for more info.
537  */
538 void
539 gst_collect_pads_set_clip_function (GstCollectPads * pads,
540     GstCollectPadsClipFunction clipfunc, gpointer user_data)
541 {
542   g_return_if_fail (pads != NULL);
543   g_return_if_fail (GST_IS_COLLECT_PADS (pads));
544
545   pads->priv->clip_func = clipfunc;
546   pads->priv->clip_user_data = user_data;
547 }
548
549 /**
550  * gst_collect_pads_set_flush_function:
551  * @pads: the collectpads to use
552  * @func: flush function to install
553  * @user_data: user data to pass to @func
554  *
555  * Install a flush function that is called when the internal
556  * state of all pads should be flushed as part of flushing seek
557  * handling. See #GstCollectPadsFlushFunction for more info.
558  *
559  * Since: 1.4
560  */
561 void
562 gst_collect_pads_set_flush_function (GstCollectPads * pads,
563     GstCollectPadsFlushFunction func, gpointer user_data)
564 {
565   g_return_if_fail (pads != NULL);
566   g_return_if_fail (GST_IS_COLLECT_PADS (pads));
567
568   pads->priv->flush_func = func;
569   pads->priv->flush_user_data = user_data;
570 }
571
572 /**
573  * gst_collect_pads_add_pad:
574  * @pads: the collectpads to use
575  * @pad: (transfer none): the pad to add
576  * @size: the size of the returned #GstCollectData structure
577  * @destroy_notify: function to be called before the returned #GstCollectData
578  * structure is freed
579  * @lock: whether to lock this pad in usual waiting state
580  *
581  * Add a pad to the collection of collect pads. The pad has to be
582  * a sinkpad. The refcount of the pad is incremented. Use
583  * gst_collect_pads_remove_pad() to remove the pad from the collection
584  * again.
585  *
586  * You specify a size for the returned #GstCollectData structure
587  * so that you can use it to store additional information.
588  *
589  * You can also specify a #GstCollectDataDestroyNotify that will be called
590  * just before the #GstCollectData structure is freed. It is passed the
591  * pointer to the structure and should free any custom memory and resources
592  * allocated for it.
593  *
594  * Keeping a pad locked in waiting state is only relevant when using
595  * the default collection algorithm (providing the oldest buffer).
596  * It ensures a buffer must be available on this pad for a collection
597  * to take place.  This is of typical use to a muxer element where
598  * non-subtitle streams should always be in waiting state,
599  * e.g. to assure that caps information is available on all these streams
600  * when initial headers have to be written.
601  *
602  * The pad will be automatically activated in push mode when @pads is
603  * started.
604  *
605  * MT safe.
606  *
607  * Returns: a new #GstCollectData to identify the new pad. Or NULL
608  *   if wrong parameters are supplied.
609  */
610 GstCollectData *
611 gst_collect_pads_add_pad (GstCollectPads * pads, GstPad * pad, guint size,
612     GstCollectDataDestroyNotify destroy_notify, gboolean lock)
613 {
614   GstCollectData *data;
615
616   g_return_val_if_fail (pads != NULL, NULL);
617   g_return_val_if_fail (GST_IS_COLLECT_PADS (pads), NULL);
618   g_return_val_if_fail (pad != NULL, NULL);
619   g_return_val_if_fail (GST_PAD_IS_SINK (pad), NULL);
620   g_return_val_if_fail (size >= sizeof (GstCollectData), NULL);
621
622   GST_DEBUG_OBJECT (pads, "adding pad %s:%s", GST_DEBUG_PAD_NAME (pad));
623
624   data = g_malloc0 (size);
625   data->priv = g_new0 (GstCollectDataPrivate, 1);
626   data->collect = pads;
627   data->pad = gst_object_ref (pad);
628   data->buffer = NULL;
629   data->pos = 0;
630   gst_segment_init (&data->segment, GST_FORMAT_UNDEFINED);
631   data->state = GST_COLLECT_PADS_STATE_WAITING;
632   data->state |= lock ? GST_COLLECT_PADS_STATE_LOCKED : 0;
633   data->priv->refcount = 1;
634   data->priv->destroy_notify = destroy_notify;
635
636   GST_OBJECT_LOCK (pads);
637   GST_OBJECT_LOCK (pad);
638   gst_pad_set_element_private (pad, data);
639   GST_OBJECT_UNLOCK (pad);
640   pads->priv->pad_list = g_slist_append (pads->priv->pad_list, data);
641   gst_pad_set_chain_function (pad, GST_DEBUG_FUNCPTR (gst_collect_pads_chain));
642   gst_pad_set_event_function (pad, GST_DEBUG_FUNCPTR (gst_collect_pads_event));
643   gst_pad_set_query_function (pad, GST_DEBUG_FUNCPTR (gst_collect_pads_query));
644   /* backward compat, also add to data if stopped, so that the element already
645    * has this in the public data list before going PAUSED (typically)
646    * this can only be done when we are stopped because we don't take the
647    * STREAM_LOCK to protect the pads->data list. */
648   if (!pads->priv->started) {
649     pads->data = g_slist_append (pads->data, data);
650     ref_data (data);
651   }
652   /* activate the pad when needed */
653   if (pads->priv->started)
654     gst_pad_set_active (pad, TRUE);
655   pads->priv->pad_cookie++;
656   GST_OBJECT_UNLOCK (pads);
657
658   return data;
659 }
660
661 static gint
662 find_pad (GstCollectData * data, GstPad * pad)
663 {
664   if (data->pad == pad)
665     return 0;
666   return 1;
667 }
668
669 /**
670  * gst_collect_pads_remove_pad:
671  * @pads: the collectpads to use
672  * @pad: (transfer none): the pad to remove
673  *
674  * Remove a pad from the collection of collect pads. This function will also
675  * free the #GstCollectData and all the resources that were allocated with
676  * gst_collect_pads_add_pad().
677  *
678  * The pad will be deactivated automatically when @pads is stopped.
679  *
680  * MT safe.
681  *
682  * Returns: %TRUE if the pad could be removed.
683  */
684 gboolean
685 gst_collect_pads_remove_pad (GstCollectPads * pads, GstPad * pad)
686 {
687   GstCollectData *data;
688   GSList *list;
689
690   g_return_val_if_fail (pads != NULL, FALSE);
691   g_return_val_if_fail (GST_IS_COLLECT_PADS (pads), FALSE);
692   g_return_val_if_fail (pad != NULL, FALSE);
693   g_return_val_if_fail (GST_IS_PAD (pad), FALSE);
694
695   GST_DEBUG_OBJECT (pads, "removing pad %s:%s", GST_DEBUG_PAD_NAME (pad));
696
697   GST_OBJECT_LOCK (pads);
698   list =
699       g_slist_find_custom (pads->priv->pad_list, pad, (GCompareFunc) find_pad);
700   if (!list)
701     goto unknown_pad;
702
703   data = (GstCollectData *) list->data;
704
705   GST_DEBUG_OBJECT (pads, "found pad %s:%s at %p", GST_DEBUG_PAD_NAME (pad),
706       data);
707
708   /* clear the stuff we configured */
709   gst_pad_set_chain_function (pad, NULL);
710   gst_pad_set_event_function (pad, NULL);
711   GST_OBJECT_LOCK (pad);
712   gst_pad_set_element_private (pad, NULL);
713   GST_OBJECT_UNLOCK (pad);
714
715   /* backward compat, also remove from data if stopped, note that this function
716    * can only be called when we are stopped because we don't take the
717    * STREAM_LOCK to protect the pads->data list. */
718   if (!pads->priv->started) {
719     GSList *dlist;
720
721     dlist = g_slist_find_custom (pads->data, pad, (GCompareFunc) find_pad);
722     if (dlist) {
723       GstCollectData *pdata = dlist->data;
724
725       pads->data = g_slist_delete_link (pads->data, dlist);
726       unref_data (pdata);
727     }
728   }
729   /* remove from the pad list */
730   pads->priv->pad_list = g_slist_delete_link (pads->priv->pad_list, list);
731   pads->priv->pad_cookie++;
732
733   /* signal waiters because something changed */
734   GST_COLLECT_PADS_EVT_BROADCAST (pads);
735
736   /* deactivate the pad when needed */
737   if (!pads->priv->started)
738     gst_pad_set_active (pad, FALSE);
739
740   /* clean and free the collect data */
741   unref_data (data);
742
743   GST_OBJECT_UNLOCK (pads);
744
745   return TRUE;
746
747 unknown_pad:
748   {
749     GST_WARNING_OBJECT (pads, "cannot remove unknown pad %s:%s",
750         GST_DEBUG_PAD_NAME (pad));
751     GST_OBJECT_UNLOCK (pads);
752     return FALSE;
753   }
754 }
755
756 /*
757  * Must be called with STREAM_LOCK and OBJECT_LOCK.
758  */
759 static void
760 gst_collect_pads_set_flushing_unlocked (GstCollectPads * pads,
761     gboolean flushing)
762 {
763   GSList *walk = NULL;
764
765   /* Update the pads flushing flag */
766   for (walk = pads->priv->pad_list; walk; walk = g_slist_next (walk)) {
767     GstCollectData *cdata = walk->data;
768
769     if (GST_IS_PAD (cdata->pad)) {
770       GST_OBJECT_LOCK (cdata->pad);
771       if (flushing)
772         GST_PAD_SET_FLUSHING (cdata->pad);
773       else
774         GST_PAD_UNSET_FLUSHING (cdata->pad);
775       if (flushing)
776         GST_COLLECT_PADS_STATE_SET (cdata, GST_COLLECT_PADS_STATE_FLUSHING);
777       else
778         GST_COLLECT_PADS_STATE_UNSET (cdata, GST_COLLECT_PADS_STATE_FLUSHING);
779       gst_collect_pads_clear (pads, cdata);
780       GST_OBJECT_UNLOCK (cdata->pad);
781     }
782   }
783
784   /* inform _chain of changes */
785   GST_COLLECT_PADS_EVT_BROADCAST (pads);
786 }
787
788 /**
789  * gst_collect_pads_set_flushing:
790  * @pads: the collectpads to use
791  * @flushing: desired state of the pads
792  *
793  * Change the flushing state of all the pads in the collection. No pad
794  * is able to accept anymore data when @flushing is %TRUE. Calling this
795  * function with @flushing %FALSE makes @pads accept data again.
796  * Caller must ensure that downstream streaming (thread) is not blocked,
797  * e.g. by sending a FLUSH_START downstream.
798  *
799  * MT safe.
800  */
801 void
802 gst_collect_pads_set_flushing (GstCollectPads * pads, gboolean flushing)
803 {
804   g_return_if_fail (pads != NULL);
805   g_return_if_fail (GST_IS_COLLECT_PADS (pads));
806
807   /* NOTE since this eventually calls _pop, some (STREAM_)LOCK is needed here */
808   GST_COLLECT_PADS_STREAM_LOCK (pads);
809   GST_OBJECT_LOCK (pads);
810   gst_collect_pads_set_flushing_unlocked (pads, flushing);
811   GST_OBJECT_UNLOCK (pads);
812   GST_COLLECT_PADS_STREAM_UNLOCK (pads);
813 }
814
815 /**
816  * gst_collect_pads_start:
817  * @pads: the collectpads to use
818  *
819  * Starts the processing of data in the collect_pads.
820  *
821  * MT safe.
822  */
823 void
824 gst_collect_pads_start (GstCollectPads * pads)
825 {
826   GSList *collected;
827
828   g_return_if_fail (pads != NULL);
829   g_return_if_fail (GST_IS_COLLECT_PADS (pads));
830
831   GST_DEBUG_OBJECT (pads, "starting collect pads");
832
833   /* make sure stop and collect cannot be called anymore */
834   GST_COLLECT_PADS_STREAM_LOCK (pads);
835
836   /* make pads streamable */
837   GST_OBJECT_LOCK (pads);
838
839   /* loop over the master pad list and reset the segment */
840   collected = pads->priv->pad_list;
841   for (; collected; collected = g_slist_next (collected)) {
842     GstCollectData *data;
843
844     data = collected->data;
845     gst_segment_init (&data->segment, GST_FORMAT_UNDEFINED);
846   }
847
848   gst_collect_pads_set_flushing_unlocked (pads, FALSE);
849
850   /* Start collect pads */
851   pads->priv->started = TRUE;
852   GST_OBJECT_UNLOCK (pads);
853   GST_COLLECT_PADS_STREAM_UNLOCK (pads);
854 }
855
856 /**
857  * gst_collect_pads_stop:
858  * @pads: the collectpads to use
859  *
860  * Stops the processing of data in the collect_pads. this function
861  * will also unblock any blocking operations.
862  *
863  * MT safe.
864  */
865 void
866 gst_collect_pads_stop (GstCollectPads * pads)
867 {
868   GSList *collected;
869
870   g_return_if_fail (pads != NULL);
871   g_return_if_fail (GST_IS_COLLECT_PADS (pads));
872
873   GST_DEBUG_OBJECT (pads, "stopping collect pads");
874
875   /* make sure collect and start cannot be called anymore */
876   GST_COLLECT_PADS_STREAM_LOCK (pads);
877
878   /* make pads not accept data anymore */
879   GST_OBJECT_LOCK (pads);
880   gst_collect_pads_set_flushing_unlocked (pads, TRUE);
881
882   /* Stop collect pads */
883   pads->priv->started = FALSE;
884   pads->priv->eospads = 0;
885   pads->priv->queuedpads = 0;
886
887   /* loop over the master pad list and flush buffers */
888   collected = pads->priv->pad_list;
889   for (; collected; collected = g_slist_next (collected)) {
890     GstCollectData *data;
891     GstBuffer **buffer_p;
892
893     data = collected->data;
894     if (data->buffer) {
895       buffer_p = &data->buffer;
896       gst_buffer_replace (buffer_p, NULL);
897       data->pos = 0;
898     }
899     GST_COLLECT_PADS_STATE_UNSET (data, GST_COLLECT_PADS_STATE_EOS);
900   }
901
902   if (pads->priv->earliest_data)
903     unref_data (pads->priv->earliest_data);
904   pads->priv->earliest_data = NULL;
905   pads->priv->earliest_time = GST_CLOCK_TIME_NONE;
906
907   GST_OBJECT_UNLOCK (pads);
908   /* Wake them up so they can end the chain functions. */
909   GST_COLLECT_PADS_EVT_BROADCAST (pads);
910
911   GST_COLLECT_PADS_STREAM_UNLOCK (pads);
912 }
913
914 /**
915  * gst_collect_pads_peek:
916  * @pads: the collectpads to peek
917  * @data: the data to use
918  *
919  * Peek at the buffer currently queued in @data. This function
920  * should be called with the @pads STREAM_LOCK held, such as in the callback
921  * handler.
922  *
923  * MT safe.
924  *
925  * Returns: The buffer in @data or NULL if no buffer is queued.
926  *  should unref the buffer after usage.
927  */
928 GstBuffer *
929 gst_collect_pads_peek (GstCollectPads * pads, GstCollectData * data)
930 {
931   GstBuffer *result;
932
933   g_return_val_if_fail (pads != NULL, NULL);
934   g_return_val_if_fail (GST_IS_COLLECT_PADS (pads), NULL);
935   g_return_val_if_fail (data != NULL, NULL);
936
937   if ((result = data->buffer))
938     gst_buffer_ref (result);
939
940   GST_DEBUG_OBJECT (pads, "Peeking at pad %s:%s: buffer=%p",
941       GST_DEBUG_PAD_NAME (data->pad), result);
942
943   return result;
944 }
945
946 /**
947  * gst_collect_pads_pop:
948  * @pads: the collectpads to pop
949  * @data: the data to use
950  *
951  * Pop the buffer currently queued in @data. This function
952  * should be called with the @pads STREAM_LOCK held, such as in the callback
953  * handler.
954  *
955  * MT safe.
956  *
957  * Returns: (transfer full): The buffer in @data or NULL if no buffer was
958  *   queued. You should unref the buffer after usage.
959  */
960 GstBuffer *
961 gst_collect_pads_pop (GstCollectPads * pads, GstCollectData * data)
962 {
963   GstBuffer *result;
964
965   g_return_val_if_fail (pads != NULL, NULL);
966   g_return_val_if_fail (GST_IS_COLLECT_PADS (pads), NULL);
967   g_return_val_if_fail (data != NULL, NULL);
968
969   if ((result = data->buffer)) {
970     data->buffer = NULL;
971     data->pos = 0;
972     /* one less pad with queued data now */
973     if (GST_COLLECT_PADS_STATE_IS_SET (data, GST_COLLECT_PADS_STATE_WAITING))
974       pads->priv->queuedpads--;
975   }
976
977   GST_COLLECT_PADS_EVT_BROADCAST (pads);
978
979   GST_DEBUG_OBJECT (pads, "Pop buffer on pad %s:%s: buffer=%p",
980       GST_DEBUG_PAD_NAME (data->pad), result);
981
982   return result;
983 }
984
985 /* pop and unref the currently queued buffer, should be called with STREAM_LOCK
986  * held */
987 static void
988 gst_collect_pads_clear (GstCollectPads * pads, GstCollectData * data)
989 {
990   GstBuffer *buf;
991
992   if ((buf = gst_collect_pads_pop (pads, data)))
993     gst_buffer_unref (buf);
994 }
995
996 /**
997  * gst_collect_pads_available:
998  * @pads: the collectpads to query
999  *
1000  * Query how much bytes can be read from each queued buffer. This means
1001  * that the result of this call is the maximum number of bytes that can
1002  * be read from each of the pads.
1003  *
1004  * This function should be called with @pads STREAM_LOCK held, such as
1005  * in the callback.
1006  *
1007  * MT safe.
1008  *
1009  * Returns: The maximum number of bytes queued on all pads. This function
1010  * returns 0 if a pad has no queued buffer.
1011  */
1012 /* we might pre-calculate this in some struct field,
1013  * but would then have to maintain this in _chain and particularly _pop, etc,
1014  * even if element is never interested in this information */
1015 guint
1016 gst_collect_pads_available (GstCollectPads * pads)
1017 {
1018   GSList *collected;
1019   guint result = G_MAXUINT;
1020
1021   g_return_val_if_fail (pads != NULL, 0);
1022   g_return_val_if_fail (GST_IS_COLLECT_PADS (pads), 0);
1023
1024   collected = pads->data;
1025   for (; collected; collected = g_slist_next (collected)) {
1026     GstCollectData *pdata;
1027     GstBuffer *buffer;
1028     gint size;
1029
1030     pdata = (GstCollectData *) collected->data;
1031
1032     /* ignore pad with EOS */
1033     if (G_UNLIKELY (GST_COLLECT_PADS_STATE_IS_SET (pdata,
1034                 GST_COLLECT_PADS_STATE_EOS))) {
1035       GST_DEBUG_OBJECT (pads, "pad %p is EOS", pdata);
1036       continue;
1037     }
1038
1039     /* an empty buffer without EOS is weird when we get here.. */
1040     if (G_UNLIKELY ((buffer = pdata->buffer) == NULL)) {
1041       GST_WARNING_OBJECT (pads, "pad %p has no buffer", pdata);
1042       goto not_filled;
1043     }
1044
1045     /* this is the size left of the buffer */
1046     size = gst_buffer_get_size (buffer) - pdata->pos;
1047     GST_DEBUG_OBJECT (pads, "pad %p has %d bytes left", pdata, size);
1048
1049     /* need to return the min of all available data */
1050     if (size < result)
1051       result = size;
1052   }
1053   /* nothing changed, all must be EOS then, return 0 */
1054   if (G_UNLIKELY (result == G_MAXUINT))
1055     result = 0;
1056
1057   return result;
1058
1059 not_filled:
1060   {
1061     return 0;
1062   }
1063 }
1064
1065 /**
1066  * gst_collect_pads_flush:
1067  * @pads: the collectpads to query
1068  * @data: the data to use
1069  * @size: the number of bytes to flush
1070  *
1071  * Flush @size bytes from the pad @data.
1072  *
1073  * This function should be called with @pads STREAM_LOCK held, such as
1074  * in the callback.
1075  *
1076  * MT safe.
1077  *
1078  * Returns: The number of bytes flushed This can be less than @size and
1079  * is 0 if the pad was end-of-stream.
1080  */
1081 guint
1082 gst_collect_pads_flush (GstCollectPads * pads, GstCollectData * data,
1083     guint size)
1084 {
1085   guint flushsize;
1086   gsize bsize;
1087   GstBuffer *buffer;
1088
1089   g_return_val_if_fail (pads != NULL, 0);
1090   g_return_val_if_fail (GST_IS_COLLECT_PADS (pads), 0);
1091   g_return_val_if_fail (data != NULL, 0);
1092
1093   /* no buffer, must be EOS */
1094   if ((buffer = data->buffer) == NULL)
1095     return 0;
1096
1097   bsize = gst_buffer_get_size (buffer);
1098
1099   /* this is what we can flush at max */
1100   flushsize = MIN (size, bsize - data->pos);
1101
1102   data->pos += size;
1103
1104   if (data->pos >= bsize)
1105     /* _clear will also reset data->pos to 0 */
1106     gst_collect_pads_clear (pads, data);
1107
1108   return flushsize;
1109 }
1110
1111 /**
1112  * gst_collect_pads_read_buffer:
1113  * @pads: the collectpads to query
1114  * @data: the data to use
1115  * @size: the number of bytes to read
1116  *
1117  * Get a subbuffer of @size bytes from the given pad @data.
1118  *
1119  * This function should be called with @pads STREAM_LOCK held, such as in the
1120  * callback.
1121  *
1122  * MT safe.
1123  *
1124  * Returns: (transfer full): A sub buffer. The size of the buffer can be less that requested.
1125  * A return of NULL signals that the pad is end-of-stream.
1126  * Unref the buffer after use.
1127  */
1128 GstBuffer *
1129 gst_collect_pads_read_buffer (GstCollectPads * pads, GstCollectData * data,
1130     guint size)
1131 {
1132   guint readsize;
1133   GstBuffer *buffer;
1134
1135   g_return_val_if_fail (pads != NULL, NULL);
1136   g_return_val_if_fail (GST_IS_COLLECT_PADS (pads), NULL);
1137   g_return_val_if_fail (data != NULL, NULL);
1138
1139   /* no buffer, must be EOS */
1140   if ((buffer = data->buffer) == NULL)
1141     return NULL;
1142
1143   readsize = MIN (size, gst_buffer_get_size (buffer) - data->pos);
1144
1145   return gst_buffer_copy_region (buffer, GST_BUFFER_COPY_ALL, data->pos,
1146       readsize);
1147 }
1148
1149 /**
1150  * gst_collect_pads_take_buffer:
1151  * @pads: the collectpads to query
1152  * @data: the data to use
1153  * @size: the number of bytes to read
1154  *
1155  * Get a subbuffer of @size bytes from the given pad @data. Flushes the amount
1156  * of read bytes.
1157  *
1158  * This function should be called with @pads STREAM_LOCK held, such as in the
1159  * callback.
1160  *
1161  * MT safe.
1162  *
1163  * Returns: A sub buffer. The size of the buffer can be less that requested.
1164  * A return of NULL signals that the pad is end-of-stream.
1165  * Unref the buffer after use.
1166  */
1167 GstBuffer *
1168 gst_collect_pads_take_buffer (GstCollectPads * pads, GstCollectData * data,
1169     guint size)
1170 {
1171   GstBuffer *buffer = gst_collect_pads_read_buffer (pads, data, size);
1172
1173   if (buffer) {
1174     gst_collect_pads_flush (pads, data, gst_buffer_get_size (buffer));
1175   }
1176   return buffer;
1177 }
1178
1179 /**
1180  * gst_collect_pads_set_waiting:
1181  * @pads: the collectpads
1182  * @data: the data to use
1183  * @waiting: boolean indicating whether this pad should operate
1184  *           in waiting or non-waiting mode
1185  *
1186  * Sets a pad to waiting or non-waiting mode, if at least this pad
1187  * has not been created with locked waiting state,
1188  * in which case nothing happens.
1189  *
1190  * This function should be called with @pads STREAM_LOCK held, such as
1191  * in the callback.
1192  *
1193  * MT safe.
1194  */
1195 void
1196 gst_collect_pads_set_waiting (GstCollectPads * pads, GstCollectData * data,
1197     gboolean waiting)
1198 {
1199   g_return_if_fail (pads != NULL);
1200   g_return_if_fail (GST_IS_COLLECT_PADS (pads));
1201   g_return_if_fail (data != NULL);
1202
1203   GST_DEBUG_OBJECT (pads, "Setting pad %s to waiting %d, locked %d",
1204       GST_PAD_NAME (data->pad), waiting,
1205       GST_COLLECT_PADS_STATE_IS_SET (data, GST_COLLECT_PADS_STATE_LOCKED));
1206
1207   /* Do something only on a change and if not locked */
1208   if (!GST_COLLECT_PADS_STATE_IS_SET (data, GST_COLLECT_PADS_STATE_LOCKED) &&
1209       (GST_COLLECT_PADS_STATE_IS_SET (data, GST_COLLECT_PADS_STATE_WAITING) !=
1210           ! !waiting)) {
1211     /* Set waiting state for this pad */
1212     if (waiting)
1213       GST_COLLECT_PADS_STATE_SET (data, GST_COLLECT_PADS_STATE_WAITING);
1214     else
1215       GST_COLLECT_PADS_STATE_UNSET (data, GST_COLLECT_PADS_STATE_WAITING);
1216     /* Update number of queued pads if needed */
1217     if (!data->buffer &&
1218         !GST_COLLECT_PADS_STATE_IS_SET (data, GST_COLLECT_PADS_STATE_EOS)) {
1219       if (waiting)
1220         pads->priv->queuedpads--;
1221       else
1222         pads->priv->queuedpads++;
1223     }
1224
1225     /* signal waiters because something changed */
1226     GST_COLLECT_PADS_EVT_BROADCAST (pads);
1227   }
1228 }
1229
1230 /* see if pads were added or removed and update our stats. Any pad
1231  * added after releasing the LOCK will get collected in the next
1232  * round.
1233  *
1234  * We can do a quick check by checking the cookies, that get changed
1235  * whenever the pad list is updated.
1236  *
1237  * Must be called with STREAM_LOCK.
1238  */
1239 static void
1240 gst_collect_pads_check_pads (GstCollectPads * pads)
1241 {
1242   /* the master list and cookie are protected with LOCK */
1243   GST_OBJECT_LOCK (pads);
1244   if (G_UNLIKELY (pads->priv->pad_cookie != pads->priv->cookie)) {
1245     GSList *collected;
1246
1247     /* clear list and stats */
1248     g_slist_foreach (pads->data, (GFunc) unref_data, NULL);
1249     g_slist_free (pads->data);
1250     pads->data = NULL;
1251     pads->priv->numpads = 0;
1252     pads->priv->queuedpads = 0;
1253     pads->priv->eospads = 0;
1254     if (pads->priv->earliest_data)
1255       unref_data (pads->priv->earliest_data);
1256     pads->priv->earliest_data = NULL;
1257     pads->priv->earliest_time = GST_CLOCK_TIME_NONE;
1258
1259     /* loop over the master pad list */
1260     collected = pads->priv->pad_list;
1261     for (; collected; collected = g_slist_next (collected)) {
1262       GstCollectData *data;
1263
1264       /* update the stats */
1265       pads->priv->numpads++;
1266       data = collected->data;
1267       if (GST_COLLECT_PADS_STATE_IS_SET (data, GST_COLLECT_PADS_STATE_EOS))
1268         pads->priv->eospads++;
1269       else if (data->buffer || !GST_COLLECT_PADS_STATE_IS_SET (data,
1270               GST_COLLECT_PADS_STATE_WAITING))
1271         pads->priv->queuedpads++;
1272
1273       /* add to the list of pads to collect */
1274       ref_data (data);
1275       /* preserve order of adding/requesting pads */
1276       pads->data = g_slist_append (pads->data, data);
1277     }
1278     /* and update the cookie */
1279     pads->priv->cookie = pads->priv->pad_cookie;
1280   }
1281   GST_OBJECT_UNLOCK (pads);
1282 }
1283
1284 /* checks if all the pads are collected and call the collectfunction
1285  *
1286  * Should be called with STREAM_LOCK.
1287  *
1288  * Returns: The #GstFlowReturn of collection.
1289  */
1290 static GstFlowReturn
1291 gst_collect_pads_check_collected (GstCollectPads * pads)
1292 {
1293   GstFlowReturn flow_ret = GST_FLOW_OK;
1294   GstCollectPadsFunction func;
1295   gpointer user_data;
1296
1297   g_return_val_if_fail (GST_IS_COLLECT_PADS (pads), GST_FLOW_ERROR);
1298
1299   GST_OBJECT_LOCK (pads);
1300   func = pads->priv->func;
1301   user_data = pads->priv->user_data;
1302   GST_OBJECT_UNLOCK (pads);
1303
1304   g_return_val_if_fail (pads->priv->func != NULL, GST_FLOW_NOT_SUPPORTED);
1305
1306   /* check for new pads, update stats etc.. */
1307   gst_collect_pads_check_pads (pads);
1308
1309   if (G_UNLIKELY (pads->priv->eospads == pads->priv->numpads)) {
1310     /* If all our pads are EOS just collect once to let the element
1311      * do its final EOS handling. */
1312     GST_DEBUG_OBJECT (pads, "All active pads (%d) are EOS, calling %s",
1313         pads->priv->numpads, GST_DEBUG_FUNCPTR_NAME (func));
1314
1315     if (G_UNLIKELY (g_atomic_int_compare_and_exchange (&pads->priv->seeking,
1316                 TRUE, FALSE) == TRUE)) {
1317       GST_INFO_OBJECT (pads, "finished seeking");
1318     }
1319     do {
1320       flow_ret = func (pads, user_data);
1321     } while (flow_ret == GST_FLOW_OK);
1322   } else {
1323     gboolean collected = FALSE;
1324
1325     /* We call the collected function as long as our condition matches. */
1326     while (((pads->priv->queuedpads + pads->priv->eospads) >=
1327             pads->priv->numpads)) {
1328       GST_DEBUG_OBJECT (pads,
1329           "All active pads (%d + %d >= %d) have data, " "calling %s",
1330           pads->priv->queuedpads, pads->priv->eospads, pads->priv->numpads,
1331           GST_DEBUG_FUNCPTR_NAME (func));
1332
1333       if (G_UNLIKELY (g_atomic_int_compare_and_exchange (&pads->priv->seeking,
1334                   TRUE, FALSE) == TRUE)) {
1335         GST_INFO_OBJECT (pads, "finished seeking");
1336       }
1337       flow_ret = func (pads, user_data);
1338       collected = TRUE;
1339
1340       /* break on error */
1341       if (flow_ret != GST_FLOW_OK)
1342         break;
1343       /* Don't keep looping after telling the element EOS or flushing */
1344       if (pads->priv->queuedpads == 0)
1345         break;
1346     }
1347     if (!collected)
1348       GST_DEBUG_OBJECT (pads, "Not all active pads (%d) have data, continuing",
1349           pads->priv->numpads);
1350   }
1351   return flow_ret;
1352 }
1353
1354
1355 /* General overview:
1356  * - only pad with a buffer can determine earliest_data (and earliest_time)
1357  * - only segment info determines (non-)waiting state
1358  * - ? perhaps use _stream_time for comparison
1359  *   (which muxers might have use as well ?)
1360  */
1361
1362 /*
1363  * Function to recalculate the waiting state of all pads.
1364  *
1365  * Must be called with STREAM_LOCK.
1366  *
1367  * Returns TRUE if a pad was set to waiting
1368  * (from non-waiting state).
1369  */
1370 static gboolean
1371 gst_collect_pads_recalculate_waiting (GstCollectPads * pads)
1372 {
1373   GSList *collected;
1374   gboolean result = FALSE;
1375
1376   /* If earliest time is not known, there is nothing to do. */
1377   if (pads->priv->earliest_data == NULL)
1378     return FALSE;
1379
1380   for (collected = pads->data; collected; collected = g_slist_next (collected)) {
1381     GstCollectData *data = (GstCollectData *) collected->data;
1382     int cmp_res;
1383     GstClockTime comp_time;
1384
1385     /* check if pad has a segment */
1386     if (data->segment.format == GST_FORMAT_UNDEFINED) {
1387       GST_WARNING_OBJECT (pads,
1388           "GstCollectPads has no time segment, assuming 0 based.");
1389       gst_segment_init (&data->segment, GST_FORMAT_TIME);
1390       GST_COLLECT_PADS_STATE_SET (data, GST_COLLECT_PADS_STATE_NEW_SEGMENT);
1391     }
1392
1393     /* check segment format */
1394     if (data->segment.format != GST_FORMAT_TIME) {
1395       GST_ERROR_OBJECT (pads, "GstCollectPads can handle only time segments.");
1396       continue;
1397     }
1398
1399     /* check if the waiting state should be changed */
1400     comp_time = data->segment.position;
1401     cmp_res = pads->priv->compare_func (pads, data, comp_time,
1402         pads->priv->earliest_data, pads->priv->earliest_time,
1403         pads->priv->compare_user_data);
1404     if (cmp_res > 0)
1405       /* stop waiting */
1406       gst_collect_pads_set_waiting (pads, data, FALSE);
1407     else {
1408       if (!GST_COLLECT_PADS_STATE_IS_SET (data, GST_COLLECT_PADS_STATE_WAITING)) {
1409         /* start waiting */
1410         gst_collect_pads_set_waiting (pads, data, TRUE);
1411         result = TRUE;
1412       }
1413     }
1414   }
1415
1416   return result;
1417 }
1418
1419 /**
1420  * gst_collect_pads_find_best_pad:
1421  * @pads: the collectpads to use
1422  * @data: returns the collectdata for earliest data
1423  * @time: returns the earliest available buffertime
1424  *
1425  * Find the oldest/best pad, i.e. pad holding the oldest buffer and
1426  * and return the corresponding #GstCollectData and buffertime.
1427  *
1428  * This function should be called with STREAM_LOCK held,
1429  * such as in the callback.
1430  */
1431 static void
1432 gst_collect_pads_find_best_pad (GstCollectPads * pads,
1433     GstCollectData ** data, GstClockTime * time)
1434 {
1435   GSList *collected;
1436   GstCollectData *best = NULL;
1437   GstClockTime best_time = GST_CLOCK_TIME_NONE;
1438
1439   g_return_if_fail (data != NULL);
1440   g_return_if_fail (time != NULL);
1441
1442   for (collected = pads->data; collected; collected = g_slist_next (collected)) {
1443     GstBuffer *buffer;
1444     GstCollectData *data = (GstCollectData *) collected->data;
1445     GstClockTime timestamp;
1446
1447     buffer = gst_collect_pads_peek (pads, data);
1448     /* if we have a buffer check if it is better then the current best one */
1449     if (buffer != NULL) {
1450       timestamp = GST_BUFFER_DTS (buffer);
1451       if (!GST_CLOCK_TIME_IS_VALID (timestamp)) {
1452         timestamp = GST_BUFFER_PTS (buffer);
1453       }
1454       gst_buffer_unref (buffer);
1455       if (best == NULL || pads->priv->compare_func (pads, data, timestamp,
1456               best, best_time, pads->priv->compare_user_data) < 0) {
1457         best = data;
1458         best_time = timestamp;
1459       }
1460     }
1461   }
1462
1463   /* set earliest time */
1464   *data = best;
1465   *time = best_time;
1466
1467   GST_DEBUG_OBJECT (pads, "best pad %s, best time %" GST_TIME_FORMAT,
1468       best ? GST_PAD_NAME (((GstCollectData *) best)->pad) : "(nil)",
1469       GST_TIME_ARGS (best_time));
1470 }
1471
1472 /*
1473  * Function to recalculate earliest_data and earliest_timestamp. This also calls
1474  * gst_collect_pads_recalculate_waiting
1475  *
1476  * Must be called with STREAM_LOCK.
1477  */
1478 static gboolean
1479 gst_collect_pads_recalculate_full (GstCollectPads * pads)
1480 {
1481   if (pads->priv->earliest_data)
1482     unref_data (pads->priv->earliest_data);
1483   gst_collect_pads_find_best_pad (pads, &pads->priv->earliest_data,
1484       &pads->priv->earliest_time);
1485   if (pads->priv->earliest_data)
1486     ref_data (pads->priv->earliest_data);
1487   return gst_collect_pads_recalculate_waiting (pads);
1488 }
1489
1490 /*
1491  * Default collect callback triggered when #GstCollectPads gathered all data.
1492  *
1493  * Called with STREAM_LOCK.
1494  */
1495 static GstFlowReturn
1496 gst_collect_pads_default_collected (GstCollectPads * pads, gpointer user_data)
1497 {
1498   GstCollectData *best = NULL;
1499   GstBuffer *buffer;
1500   GstFlowReturn ret = GST_FLOW_OK;
1501   GstCollectPadsBufferFunction func;
1502   gpointer buffer_user_data;
1503
1504   g_return_val_if_fail (GST_IS_COLLECT_PADS (pads), GST_FLOW_ERROR);
1505
1506   GST_OBJECT_LOCK (pads);
1507   func = pads->priv->buffer_func;
1508   buffer_user_data = pads->priv->buffer_user_data;
1509   GST_OBJECT_UNLOCK (pads);
1510
1511   g_return_val_if_fail (func != NULL, GST_FLOW_NOT_SUPPORTED);
1512
1513   /* Find the oldest pad at all cost */
1514   if (gst_collect_pads_recalculate_full (pads)) {
1515     /* waiting was switched on,
1516      * so give another thread a chance to deliver a possibly
1517      * older buffer; don't charge on yet with the current oldest */
1518     ret = GST_FLOW_OK;
1519     goto done;
1520   }
1521
1522   best = pads->priv->earliest_data;
1523
1524   /* No data collected means EOS. */
1525   if (G_UNLIKELY (best == NULL)) {
1526     ret = func (pads, best, NULL, buffer_user_data);
1527     if (ret == GST_FLOW_OK)
1528       ret = GST_FLOW_EOS;
1529     goto done;
1530   }
1531
1532   /* make sure that the pad we take a buffer from is waiting;
1533    * otherwise popping a buffer will seem not to have happened
1534    * and collectpads can get into a busy loop */
1535   gst_collect_pads_set_waiting (pads, best, TRUE);
1536
1537   /* Send buffer */
1538   buffer = gst_collect_pads_pop (pads, best);
1539   ret = func (pads, best, buffer, buffer_user_data);
1540
1541   /* maybe non-waiting was forced to waiting above due to
1542    * newsegment events coming too sparsely,
1543    * so re-check to restore state to avoid hanging/waiting */
1544   gst_collect_pads_recalculate_full (pads);
1545
1546 done:
1547   return ret;
1548 }
1549
1550 /*
1551  * Default timestamp compare function.
1552  */
1553 static gint
1554 gst_collect_pads_default_compare_func (GstCollectPads * pads,
1555     GstCollectData * data1, GstClockTime timestamp1,
1556     GstCollectData * data2, GstClockTime timestamp2, gpointer user_data)
1557 {
1558
1559   GST_LOG_OBJECT (pads, "comparing %" GST_TIME_FORMAT
1560       " and %" GST_TIME_FORMAT, GST_TIME_ARGS (timestamp1),
1561       GST_TIME_ARGS (timestamp2));
1562   /* non-valid timestamps go first as they are probably headers or so */
1563   if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (timestamp1)))
1564     return GST_CLOCK_TIME_IS_VALID (timestamp2) ? -1 : 0;
1565
1566   if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (timestamp2)))
1567     return 1;
1568
1569   /* compare timestamp */
1570   if (timestamp1 < timestamp2)
1571     return -1;
1572
1573   if (timestamp1 > timestamp2)
1574     return 1;
1575
1576   return 0;
1577 }
1578
1579 /* called with STREAM_LOCK */
1580 static void
1581 gst_collect_pads_handle_position_update (GstCollectPads * pads,
1582     GstCollectData * data, GstClockTime new_pos)
1583 {
1584   gint cmp_res;
1585
1586   /* If oldest time is not known, or current pad got newsegment;
1587    * recalculate the state */
1588   if (!pads->priv->earliest_data || pads->priv->earliest_data == data) {
1589     gst_collect_pads_recalculate_full (pads);
1590     goto exit;
1591   }
1592
1593   /* Check if the waiting state of the pad should change. */
1594   cmp_res =
1595       pads->priv->compare_func (pads, data, new_pos,
1596       pads->priv->earliest_data, pads->priv->earliest_time,
1597       pads->priv->compare_user_data);
1598
1599   if (cmp_res > 0)
1600     /* Stop waiting */
1601     gst_collect_pads_set_waiting (pads, data, FALSE);
1602
1603 exit:
1604   return;
1605
1606 }
1607
1608 static GstClockTime
1609 gst_collect_pads_clip_time (GstCollectPads * pads, GstCollectData * data,
1610     GstClockTime time)
1611 {
1612   GstClockTime otime = time;
1613   GstBuffer *in, *out = NULL;
1614
1615   if (pads->priv->clip_func) {
1616     in = gst_buffer_new ();
1617     GST_BUFFER_PTS (in) = time;
1618     GST_BUFFER_DTS (in) = time;
1619     pads->priv->clip_func (pads, data, in, &out, pads->priv->clip_user_data);
1620     if (out) {
1621       otime = GST_BUFFER_PTS (out);
1622       gst_buffer_unref (out);
1623     } else {
1624       /* FIXME should distinguish between ahead or after segment,
1625        * let's assume after segment and use some large time ... */
1626       otime = G_MAXINT64 / 2;
1627     }
1628   }
1629
1630   return otime;
1631 }
1632
1633 /**
1634  * gst_collect_pads_event_default:
1635  * @pads: the collectpads to use
1636  * @data: collect data of corresponding pad
1637  * @event: event being processed
1638  * @discard: process but do not send event downstream
1639  *
1640  * Default GstCollectPads event handling that elements should always
1641  * chain up to to ensure proper operation.  Element might however indicate
1642  * event should not be forwarded downstream.
1643  */
1644 gboolean
1645 gst_collect_pads_event_default (GstCollectPads * pads, GstCollectData * data,
1646     GstEvent * event, gboolean discard)
1647 {
1648   gboolean res = TRUE;
1649   GstCollectPadsBufferFunction buffer_func;
1650   GstObject *parent;
1651   GstPad *pad;
1652
1653   GST_OBJECT_LOCK (pads);
1654   buffer_func = pads->priv->buffer_func;
1655   GST_OBJECT_UNLOCK (pads);
1656
1657   pad = data->pad;
1658   parent = GST_OBJECT_PARENT (pad);
1659
1660   switch (GST_EVENT_TYPE (event)) {
1661     case GST_EVENT_FLUSH_START:
1662     {
1663       if (g_atomic_int_get (&pads->priv->seeking)) {
1664         /* drop all but the first FLUSH_STARTs when seeking */
1665         if (g_atomic_int_compare_and_exchange (&pads->priv->pending_flush_start,
1666                 TRUE, FALSE) == FALSE)
1667           goto eat;
1668
1669         /* unblock collect pads */
1670         gst_pad_event_default (pad, parent, event);
1671         event = NULL;
1672
1673         GST_COLLECT_PADS_STREAM_LOCK (pads);
1674         /* Start flushing. We never call gst_collect_pads_set_flushing (FALSE), we
1675          * instead wait until each pad gets its FLUSH_STOP and let that reset the pad to
1676          * non-flushing (which happens in gst_collect_pads_event_default).
1677          */
1678         gst_collect_pads_set_flushing (pads, TRUE);
1679
1680         if (pads->priv->flush_func)
1681           pads->priv->flush_func (pads, pads->priv->flush_user_data);
1682
1683         g_atomic_int_set (&pads->priv->pending_flush_stop, TRUE);
1684         GST_COLLECT_PADS_STREAM_UNLOCK (pads);
1685
1686         goto eat;
1687       } else {
1688         /* forward event to unblock check_collected */
1689         GST_DEBUG_OBJECT (pad, "forwarding flush start");
1690         res = gst_pad_event_default (pad, parent, event);
1691         event = NULL;
1692
1693         /* now unblock the chain function.
1694          * no cond per pad, so they all unblock,
1695          * non-flushing block again */
1696         GST_COLLECT_PADS_STREAM_LOCK (pads);
1697         GST_COLLECT_PADS_STATE_SET (data, GST_COLLECT_PADS_STATE_FLUSHING);
1698         gst_collect_pads_clear (pads, data);
1699
1700         /* cater for possible default muxing functionality */
1701         if (buffer_func) {
1702           /* restore to initial state */
1703           gst_collect_pads_set_waiting (pads, data, TRUE);
1704           /* if the current pad is affected, reset state, recalculate later */
1705           if (pads->priv->earliest_data == data) {
1706             unref_data (data);
1707             pads->priv->earliest_data = NULL;
1708             pads->priv->earliest_time = GST_CLOCK_TIME_NONE;
1709           }
1710         }
1711
1712         GST_COLLECT_PADS_STREAM_UNLOCK (pads);
1713
1714         goto eat;
1715       }
1716     }
1717     case GST_EVENT_FLUSH_STOP:
1718     {
1719       /* flush the 1 buffer queue */
1720       GST_COLLECT_PADS_STREAM_LOCK (pads);
1721       GST_COLLECT_PADS_STATE_UNSET (data, GST_COLLECT_PADS_STATE_FLUSHING);
1722       gst_collect_pads_clear (pads, data);
1723       /* we need new segment info after the flush */
1724       gst_segment_init (&data->segment, GST_FORMAT_UNDEFINED);
1725       GST_COLLECT_PADS_STATE_UNSET (data, GST_COLLECT_PADS_STATE_NEW_SEGMENT);
1726       /* if the pad was EOS, remove the EOS flag and
1727        * decrement the number of eospads */
1728       if (G_UNLIKELY (GST_COLLECT_PADS_STATE_IS_SET (data,
1729                   GST_COLLECT_PADS_STATE_EOS))) {
1730         if (!GST_COLLECT_PADS_STATE_IS_SET (data,
1731                 GST_COLLECT_PADS_STATE_WAITING))
1732           pads->priv->queuedpads++;
1733         pads->priv->eospads--;
1734         GST_COLLECT_PADS_STATE_UNSET (data, GST_COLLECT_PADS_STATE_EOS);
1735       }
1736       GST_COLLECT_PADS_STREAM_UNLOCK (pads);
1737
1738       if (g_atomic_int_get (&pads->priv->seeking)) {
1739         if (g_atomic_int_compare_and_exchange (&pads->priv->pending_flush_stop,
1740                 TRUE, FALSE))
1741           goto forward;
1742         else
1743           goto eat;
1744       } else {
1745         goto forward;
1746       }
1747     }
1748     case GST_EVENT_EOS:
1749     {
1750       GST_COLLECT_PADS_STREAM_LOCK (pads);
1751       /* if the pad was not EOS, make it EOS and so we
1752        * have one more eospad */
1753       if (G_LIKELY (!GST_COLLECT_PADS_STATE_IS_SET (data,
1754                   GST_COLLECT_PADS_STATE_EOS))) {
1755         GST_COLLECT_PADS_STATE_SET (data, GST_COLLECT_PADS_STATE_EOS);
1756         if (!GST_COLLECT_PADS_STATE_IS_SET (data,
1757                 GST_COLLECT_PADS_STATE_WAITING))
1758           pads->priv->queuedpads--;
1759         pads->priv->eospads++;
1760       }
1761       /* check if we need collecting anything, we ignore the result. */
1762       gst_collect_pads_check_collected (pads);
1763       GST_COLLECT_PADS_STREAM_UNLOCK (pads);
1764
1765       goto eat;
1766     }
1767     case GST_EVENT_SEGMENT:
1768     {
1769       GstSegment seg;
1770
1771       GST_COLLECT_PADS_STREAM_LOCK (pads);
1772
1773       gst_event_copy_segment (event, &seg);
1774
1775       GST_DEBUG_OBJECT (data->pad, "got segment %" GST_SEGMENT_FORMAT, &seg);
1776
1777       /* default collection can not handle other segment formats than time */
1778       if (buffer_func && seg.format != GST_FORMAT_TIME) {
1779         GST_WARNING_OBJECT (pads, "GstCollectPads default collecting "
1780             "can only handle time segments. Non time segment ignored.");
1781         goto newsegment_done;
1782       }
1783
1784       /* need to update segment first */
1785       data->segment = seg;
1786       GST_COLLECT_PADS_STATE_SET (data, GST_COLLECT_PADS_STATE_NEW_SEGMENT);
1787
1788       /* now we can use for e.g. running time */
1789       seg.position = gst_collect_pads_clip_time (pads, data, seg.start);
1790       /* update again */
1791       data->segment = seg;
1792
1793       /* default muxing functionality */
1794       if (!buffer_func)
1795         goto newsegment_done;
1796
1797       gst_collect_pads_handle_position_update (pads, data, seg.position);
1798
1799     newsegment_done:
1800       GST_COLLECT_PADS_STREAM_UNLOCK (pads);
1801       /* we must not forward this event since multiple segments will be
1802        * accumulated and this is certainly not what we want. */
1803       goto eat;
1804     }
1805     case GST_EVENT_GAP:
1806     {
1807       GstClockTime start, duration;
1808
1809       GST_COLLECT_PADS_STREAM_LOCK (pads);
1810
1811       gst_event_parse_gap (event, &start, &duration);
1812       if (GST_CLOCK_TIME_IS_VALID (duration))
1813         start += duration;
1814       /* we do not expect another buffer until after gap,
1815        * so that is our position now */
1816       data->segment.position = gst_collect_pads_clip_time (pads, data, start);
1817
1818       gst_collect_pads_handle_position_update (pads, data,
1819           data->segment.position);
1820
1821       GST_COLLECT_PADS_STREAM_UNLOCK (pads);
1822       goto eat;
1823     }
1824     case GST_EVENT_STREAM_START:
1825       /* drop stream start events, element must create its own start event,
1826        * we can't just forward the first random stream start event we get */
1827       goto eat;
1828     case GST_EVENT_CAPS:
1829       goto eat;
1830     default:
1831       /* forward other events */
1832       goto forward;
1833   }
1834
1835 eat:
1836   if (event)
1837     gst_event_unref (event);
1838   return res;
1839
1840 forward:
1841   if (discard)
1842     goto eat;
1843   else
1844     return gst_pad_event_default (pad, parent, event);
1845 }
1846
1847 typedef struct
1848 {
1849   GstEvent *event;
1850   gboolean result;
1851 } EventData;
1852
1853 static gboolean
1854 event_forward_func (GstPad * pad, EventData * data)
1855 {
1856   data->result &= gst_pad_push_event (pad, gst_event_ref (data->event));
1857
1858   /* Always send to all pads */
1859   return FALSE;
1860 }
1861
1862 static gboolean
1863 forward_event_to_all_sinkpads (GstPad * srcpad, GstEvent * event)
1864 {
1865   EventData data;
1866
1867   data.event = event;
1868   data.result = TRUE;
1869
1870   gst_pad_forward (srcpad, (GstPadForwardFunction) event_forward_func, &data);
1871
1872   gst_event_unref (event);
1873
1874   return data.result;
1875 }
1876
1877 /**
1878  * gst_collect_pads_src_event_default:
1879  * @pads: the collectpads to use
1880  * @pad: src #GstPad that received the event
1881  * @event: event being processed
1882  *
1883  * Default GstCollectPads event handling for the src pad of elements.
1884  * Elements can chain up to this to let flushing seek event handling
1885  * be done by GstCollectPads.
1886  *
1887  * Since: 1.4
1888  */
1889 gboolean
1890 gst_collect_pads_src_event_default (GstCollectPads * pads, GstPad * pad,
1891     GstEvent * event)
1892 {
1893   GstObject *parent;
1894   gboolean res = TRUE;
1895
1896   parent = GST_OBJECT_PARENT (pad);
1897
1898   switch (GST_EVENT_TYPE (event)) {
1899     case GST_EVENT_SEEK:{
1900       GstSeekFlags flags;
1901
1902       GST_INFO_OBJECT (pads, "starting seek");
1903
1904       gst_event_parse_seek (event, NULL, NULL, &flags, NULL, NULL, NULL, NULL);
1905       if (flags & GST_SEEK_FLAG_FLUSH) {
1906         g_atomic_int_set (&pads->priv->seeking, TRUE);
1907         g_atomic_int_set (&pads->priv->pending_flush_start, TRUE);
1908         /* forward the seek upstream */
1909         res = forward_event_to_all_sinkpads (pad, event);
1910         event = NULL;
1911         if (!res) {
1912           g_atomic_int_set (&pads->priv->seeking, FALSE);
1913           g_atomic_int_set (&pads->priv->pending_flush_start, FALSE);
1914         }
1915       }
1916
1917       GST_INFO_OBJECT (pads, "seek done, result: %d", res);
1918
1919       break;
1920     }
1921     default:
1922       break;
1923   }
1924
1925   if (event)
1926     res = gst_pad_event_default (pad, parent, event);
1927
1928   return res;
1929 }
1930
1931 static gboolean
1932 gst_collect_pads_event_default_internal (GstCollectPads * pads,
1933     GstCollectData * data, GstEvent * event, gpointer user_data)
1934 {
1935   return gst_collect_pads_event_default (pads, data, event, FALSE);
1936 }
1937
1938 static gboolean
1939 gst_collect_pads_event (GstPad * pad, GstObject * parent, GstEvent * event)
1940 {
1941   gboolean res = FALSE, need_unlock = FALSE;
1942   GstCollectData *data;
1943   GstCollectPads *pads;
1944   GstCollectPadsEventFunction event_func;
1945   gpointer event_user_data;
1946
1947   /* some magic to get the managing collect_pads */
1948   GST_OBJECT_LOCK (pad);
1949   data = (GstCollectData *) gst_pad_get_element_private (pad);
1950   if (G_UNLIKELY (data == NULL))
1951     goto pad_removed;
1952   ref_data (data);
1953   GST_OBJECT_UNLOCK (pad);
1954
1955   res = FALSE;
1956
1957   pads = data->collect;
1958
1959   GST_DEBUG_OBJECT (data->pad, "Got %s event on sink pad",
1960       GST_EVENT_TYPE_NAME (event));
1961
1962   GST_OBJECT_LOCK (pads);
1963   event_func = pads->priv->event_func;
1964   event_user_data = pads->priv->event_user_data;
1965   GST_OBJECT_UNLOCK (pads);
1966
1967   if (GST_EVENT_IS_SERIALIZED (event)) {
1968     GST_COLLECT_PADS_STREAM_LOCK (pads);
1969     need_unlock = TRUE;
1970   }
1971
1972   if (G_LIKELY (event_func)) {
1973     res = event_func (pads, data, event, event_user_data);
1974   }
1975
1976   if (need_unlock)
1977     GST_COLLECT_PADS_STREAM_UNLOCK (pads);
1978
1979   unref_data (data);
1980   return res;
1981
1982   /* ERRORS */
1983 pad_removed:
1984   {
1985     GST_DEBUG ("%s got removed from collectpads", GST_OBJECT_NAME (pad));
1986     GST_OBJECT_UNLOCK (pad);
1987     return FALSE;
1988   }
1989 }
1990
1991 /**
1992  * gst_collect_pads_query_default:
1993  * @pads: the collectpads to use
1994  * @data: collect data of corresponding pad
1995  * @query: query being processed
1996  * @discard: process but do not send event downstream
1997  *
1998  * Default GstCollectPads query handling that elements should always
1999  * chain up to to ensure proper operation.  Element might however indicate
2000  * query should not be forwarded downstream.
2001  */
2002 gboolean
2003 gst_collect_pads_query_default (GstCollectPads * pads, GstCollectData * data,
2004     GstQuery * query, gboolean discard)
2005 {
2006   gboolean res = TRUE;
2007   GstObject *parent;
2008   GstPad *pad;
2009
2010   pad = data->pad;
2011   parent = GST_OBJECT_PARENT (pad);
2012
2013   switch (GST_QUERY_TYPE (query)) {
2014     case GST_QUERY_SEEKING:
2015     {
2016       GstFormat format;
2017
2018       /* don't pass it along as some (file)sink might claim it does
2019        * whereas with a collectpads in between that will not likely work */
2020       gst_query_parse_seeking (query, &format, NULL, NULL, NULL);
2021       gst_query_set_seeking (query, format, FALSE, 0, -1);
2022       res = TRUE;
2023       discard = TRUE;
2024       break;
2025     }
2026     default:
2027       break;
2028   }
2029
2030   if (!discard)
2031     return gst_pad_query_default (pad, parent, query);
2032   else
2033     return res;
2034 }
2035
2036 static gboolean
2037 gst_collect_pads_query_default_internal (GstCollectPads * pads,
2038     GstCollectData * data, GstQuery * query, gpointer user_data)
2039 {
2040   return gst_collect_pads_query_default (pads, data, query, FALSE);
2041 }
2042
2043 static gboolean
2044 gst_collect_pads_query (GstPad * pad, GstObject * parent, GstQuery * query)
2045 {
2046   gboolean res = FALSE, need_unlock = FALSE;
2047   GstCollectData *data;
2048   GstCollectPads *pads;
2049   GstCollectPadsQueryFunction query_func;
2050   gpointer query_user_data;
2051
2052   GST_DEBUG_OBJECT (pad, "Got %s query on sink pad",
2053       GST_QUERY_TYPE_NAME (query));
2054
2055   /* some magic to get the managing collect_pads */
2056   GST_OBJECT_LOCK (pad);
2057   data = (GstCollectData *) gst_pad_get_element_private (pad);
2058   if (G_UNLIKELY (data == NULL))
2059     goto pad_removed;
2060   ref_data (data);
2061   GST_OBJECT_UNLOCK (pad);
2062
2063   pads = data->collect;
2064
2065   GST_OBJECT_LOCK (pads);
2066   query_func = pads->priv->query_func;
2067   query_user_data = pads->priv->query_user_data;
2068   GST_OBJECT_UNLOCK (pads);
2069
2070   if (GST_QUERY_IS_SERIALIZED (query)) {
2071     GST_COLLECT_PADS_STREAM_LOCK (pads);
2072     need_unlock = TRUE;
2073   }
2074
2075   if (G_LIKELY (query_func)) {
2076     res = query_func (pads, data, query, query_user_data);
2077   }
2078
2079   if (need_unlock)
2080     GST_COLLECT_PADS_STREAM_UNLOCK (pads);
2081
2082   unref_data (data);
2083   return res;
2084
2085   /* ERRORS */
2086 pad_removed:
2087   {
2088     GST_DEBUG ("%s got removed from collectpads", GST_OBJECT_NAME (pad));
2089     GST_OBJECT_UNLOCK (pad);
2090     return FALSE;
2091   }
2092 }
2093
2094
2095 /* For each buffer we receive we check if our collected condition is reached
2096  * and if so we call the collected function. When this is done we check if
2097  * data has been unqueued. If data is still queued we wait holding the stream
2098  * lock to make sure no EOS event can happen while we are ready to be
2099  * collected 
2100  */
2101 static GstFlowReturn
2102 gst_collect_pads_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer)
2103 {
2104   GstCollectData *data;
2105   GstCollectPads *pads;
2106   GstFlowReturn ret;
2107   GstBuffer **buffer_p;
2108   guint32 cookie;
2109
2110   GST_DEBUG ("Got buffer for pad %s:%s", GST_DEBUG_PAD_NAME (pad));
2111
2112   /* some magic to get the managing collect_pads */
2113   GST_OBJECT_LOCK (pad);
2114   data = (GstCollectData *) gst_pad_get_element_private (pad);
2115   if (G_UNLIKELY (data == NULL))
2116     goto no_data;
2117   ref_data (data);
2118   GST_OBJECT_UNLOCK (pad);
2119
2120   pads = data->collect;
2121
2122   GST_COLLECT_PADS_STREAM_LOCK (pads);
2123   /* if not started, bail out */
2124   if (G_UNLIKELY (!pads->priv->started))
2125     goto not_started;
2126   /* check if this pad is flushing */
2127   if (G_UNLIKELY (GST_COLLECT_PADS_STATE_IS_SET (data,
2128               GST_COLLECT_PADS_STATE_FLUSHING)))
2129     goto flushing;
2130   /* pad was EOS, we can refuse this data */
2131   if (G_UNLIKELY (GST_COLLECT_PADS_STATE_IS_SET (data,
2132               GST_COLLECT_PADS_STATE_EOS)))
2133     goto eos;
2134
2135   /* see if we need to clip */
2136   if (pads->priv->clip_func) {
2137     GstBuffer *outbuf = NULL;
2138     ret =
2139         pads->priv->clip_func (pads, data, buffer, &outbuf,
2140         pads->priv->clip_user_data);
2141     buffer = outbuf;
2142
2143     if (G_UNLIKELY (outbuf == NULL))
2144       goto clipped;
2145
2146     if (G_UNLIKELY (ret == GST_FLOW_EOS))
2147       goto eos;
2148     else if (G_UNLIKELY (ret != GST_FLOW_OK))
2149       goto error;
2150   }
2151
2152   GST_DEBUG_OBJECT (pads, "Queuing buffer %p for pad %s:%s", buffer,
2153       GST_DEBUG_PAD_NAME (pad));
2154
2155   /* One more pad has data queued */
2156   if (GST_COLLECT_PADS_STATE_IS_SET (data, GST_COLLECT_PADS_STATE_WAITING))
2157     pads->priv->queuedpads++;
2158   buffer_p = &data->buffer;
2159   gst_buffer_replace (buffer_p, buffer);
2160
2161   /* update segment last position if in TIME */
2162   if (G_LIKELY (data->segment.format == GST_FORMAT_TIME)) {
2163     GstClockTime timestamp;
2164
2165     timestamp = GST_BUFFER_DTS (buffer);
2166     if (!GST_CLOCK_TIME_IS_VALID (timestamp))
2167       timestamp = GST_BUFFER_PTS (buffer);
2168
2169     if (GST_CLOCK_TIME_IS_VALID (timestamp))
2170       data->segment.position = timestamp;
2171   }
2172
2173   /* While we have data queued on this pad try to collect stuff */
2174   do {
2175     /* Check if our collected condition is matched and call the collected
2176      * function if it is */
2177     ret = gst_collect_pads_check_collected (pads);
2178     /* when an error occurs, we want to report this back to the caller ASAP
2179      * without having to block if the buffer was not popped */
2180     if (G_UNLIKELY (ret != GST_FLOW_OK))
2181       goto error;
2182
2183     /* data was consumed, we can exit and accept new data */
2184     if (data->buffer == NULL)
2185       break;
2186
2187     /* Having the _INIT here means we don't care about any broadcast up to here
2188      * (most of which occur with STREAM_LOCK held, so could not have happened
2189      * anyway).  We do care about e.g. a remove initiated broadcast as of this
2190      * point.  Putting it here also makes this thread ignores any evt it raised
2191      * itself (as is a usual WAIT semantic).
2192      */
2193     GST_COLLECT_PADS_EVT_INIT (cookie);
2194
2195     /* pad could be removed and re-added */
2196     unref_data (data);
2197     GST_OBJECT_LOCK (pad);
2198     if (G_UNLIKELY ((data = gst_pad_get_element_private (pad)) == NULL))
2199       goto pad_removed;
2200     ref_data (data);
2201     GST_OBJECT_UNLOCK (pad);
2202
2203     GST_DEBUG_OBJECT (pads, "Pad %s:%s has a buffer queued, waiting",
2204         GST_DEBUG_PAD_NAME (pad));
2205
2206     /* wait to be collected, this must happen from another thread triggered
2207      * by the _chain function of another pad. We release the lock so we
2208      * can get stopped or flushed as well. We can however not get EOS
2209      * because we still hold the STREAM_LOCK.
2210      */
2211     GST_COLLECT_PADS_STREAM_UNLOCK (pads);
2212     GST_COLLECT_PADS_EVT_WAIT (pads, cookie);
2213     GST_COLLECT_PADS_STREAM_LOCK (pads);
2214
2215     GST_DEBUG_OBJECT (pads, "Pad %s:%s resuming", GST_DEBUG_PAD_NAME (pad));
2216
2217     /* after a signal, we could be stopped */
2218     if (G_UNLIKELY (!pads->priv->started))
2219       goto not_started;
2220     /* check if this pad is flushing */
2221     if (G_UNLIKELY (GST_COLLECT_PADS_STATE_IS_SET (data,
2222                 GST_COLLECT_PADS_STATE_FLUSHING)))
2223       goto flushing;
2224   }
2225   while (data->buffer != NULL);
2226
2227 unlock_done:
2228   GST_COLLECT_PADS_STREAM_UNLOCK (pads);
2229   /* data is definitely NULL if pad_removed goto was run. */
2230   if (data)
2231     unref_data (data);
2232   if (buffer)
2233     gst_buffer_unref (buffer);
2234   return ret;
2235
2236 pad_removed:
2237   {
2238     GST_WARNING ("%s got removed from collectpads", GST_OBJECT_NAME (pad));
2239     GST_OBJECT_UNLOCK (pad);
2240     ret = GST_FLOW_NOT_LINKED;
2241     goto unlock_done;
2242   }
2243   /* ERRORS */
2244 no_data:
2245   {
2246     GST_DEBUG ("%s got removed from collectpads", GST_OBJECT_NAME (pad));
2247     GST_OBJECT_UNLOCK (pad);
2248     gst_buffer_unref (buffer);
2249     return GST_FLOW_NOT_LINKED;
2250   }
2251 not_started:
2252   {
2253     GST_DEBUG ("not started");
2254     gst_collect_pads_clear (pads, data);
2255     ret = GST_FLOW_FLUSHING;
2256     goto unlock_done;
2257   }
2258 flushing:
2259   {
2260     GST_DEBUG ("pad %s:%s is flushing", GST_DEBUG_PAD_NAME (pad));
2261     gst_collect_pads_clear (pads, data);
2262     ret = GST_FLOW_FLUSHING;
2263     goto unlock_done;
2264   }
2265 eos:
2266   {
2267     /* we should not post an error for this, just inform upstream that
2268      * we don't expect anything anymore */
2269     GST_DEBUG ("pad %s:%s is eos", GST_DEBUG_PAD_NAME (pad));
2270     ret = GST_FLOW_EOS;
2271     goto unlock_done;
2272   }
2273 clipped:
2274   {
2275     GST_DEBUG ("clipped buffer on pad %s:%s", GST_DEBUG_PAD_NAME (pad));
2276     ret = GST_FLOW_OK;
2277     goto unlock_done;
2278   }
2279 error:
2280   {
2281     /* we print the error, the element should post a reasonable error
2282      * message for fatal errors */
2283     GST_DEBUG ("collect failed, reason %d (%s)", ret, gst_flow_get_name (ret));
2284     gst_collect_pads_clear (pads, data);
2285     goto unlock_done;
2286   }
2287 }