📄 gstcollectpads.c
字号:
/* GStreamer * Copyright (C) 2005 Wim Taymans <wim@fluendo.com> * * gstcollectpads.c: * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. *//** * SECTION:gstcollectpads * @short_description: manages a set of pads that operate in collect mode * @see_also: * * Manages a set of pads that operate in collect mode. This means that control * is given to the manager of this object when all pads have data. * <itemizedlist> * <listitem><para> * Collectpads are created with gst_collect_pads_new(). A callback should then * be installed with gst_collect_pads_set_function (). * </para></listitem> * <listitem><para> * Pads are added to the collection with gst_collect_pads_add_pad()/ * gst_collect_pads_remove_pad(). The pad * has to be a sinkpad. The chain and event functions of the pad are * overridden. The element_private of the pad is used to store * private information for the collectpads. * </para></listitem> * <listitem><para> * For each pad, data is queued in the _chain function or by * performing a pull_range. * </para></listitem> * <listitem><para> * When data is queued on all pads, the callback function is called. * </para></listitem> * <listitem><para> * Data can be dequeued from the pad with the gst_collect_pads_pop() method. * One can peek at the data with the gst_collect_pads_peek() function. * These functions will return NULL if the pad received an EOS event. When all * pads return NULL from a gst_collect_pads_peek(), the element can emit an EOS * event itself. * </para></listitem> * <listitem><para> * Data can also be dequeued in byte units using the gst_collect_pads_available(), * gst_collect_pads_read() and gst_collect_pads_flush() calls. * </para></listitem> * <listitem><para> * Elements should call gst_collect_pads_start() and gst_collect_pads_stop() in * their state change functions to start and stop the processing of the collecpads. * The gst_collect_pads_stop() call should be called before calling the parent * element state change function in the PAUSED_TO_READY state change to ensure * no pad is blocked and the element can finish streaming. * </para></listitem> * <listitem><para> * gst_collect_pads_collect() and gst_collect_pads_collect_range() can be used by * elements that start a #GstTask to drive the collect_pads. This feature is however * not yet implemented. * </para></listitem> * </itemizedlist> * * Last reviewed on 2006-05-10 (0.10.6) */#include "gstcollectpads.h"GST_DEBUG_CATEGORY_STATIC (collect_pads_debug);#define GST_CAT_DEFAULT collect_pads_debugGST_BOILERPLATE (GstCollectPads, gst_collect_pads, GstObject, GST_TYPE_OBJECT);static void gst_collect_pads_clear (GstCollectPads * pads, GstCollectData * data);static GstFlowReturn gst_collect_pads_chain (GstPad * pad, GstBuffer * buffer);static gboolean gst_collect_pads_event (GstPad * pad, GstEvent * event);static void gst_collect_pads_finalize (GObject * object);static void gst_collect_pads_init (GstCollectPads * pads, GstCollectPadsClass * g_class);static void ref_data (GstCollectData * data);static void unref_data (GstCollectData * data);static voidgst_collect_pads_base_init (gpointer g_class){ GST_DEBUG_CATEGORY_INIT (collect_pads_debug, "collectpads", 0, "GstCollectPads");}static voidgst_collect_pads_class_init (GstCollectPadsClass * klass){ GObjectClass *gobject_class = (GObjectClass *) klass; gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_collect_pads_finalize);}static voidgst_collect_pads_init (GstCollectPads * pads, GstCollectPadsClass * g_class){ pads->cond = g_cond_new (); pads->data = NULL; pads->cookie = 0; pads->numpads = 0; pads->queuedpads = 0; pads->eospads = 0; pads->started = FALSE; /* members to manage the pad list */ pads->abidata.ABI.pad_lock = g_mutex_new (); pads->abidata.ABI.pad_cookie = 0; pads->abidata.ABI.pad_list = NULL;}static voidgst_collect_pads_finalize (GObject * object){ GSList *collected; GstCollectPads *pads = GST_COLLECT_PADS (object); GST_DEBUG ("finalize"); g_cond_free (pads->cond); g_mutex_free (pads->abidata.ABI.pad_lock); /* Remove pads */ collected = pads->abidata.ABI.pad_list; for (; collected; collected = g_slist_next (collected)) { GstCollectData *pdata = (GstCollectData *) collected->data; unref_data (pdata); } /* Free pads list */ g_slist_foreach (pads->data, (GFunc) unref_data, NULL); g_slist_free (pads->data); g_slist_free (pads->abidata.ABI.pad_list); G_OBJECT_CLASS (parent_class)->finalize (object);}/** * gst_collect_pads_new: * * Create a new instance of #GstCollectsPads. * * Returns: a new #GstCollectPads, or NULL in case of an error. * * MT safe. */GstCollectPads *gst_collect_pads_new (void){ GstCollectPads *newcoll; newcoll = g_object_new (GST_TYPE_COLLECT_PADS, NULL); return newcoll;}/** * gst_collect_pads_set_function: * @pads: the collectspads to use * @func: the function to set * @user_data: user data passed to the function * * Set the callback function and user data that will be called when * all the pads added to the collection have buffers queued. * * MT safe. */voidgst_collect_pads_set_function (GstCollectPads * pads, GstCollectPadsFunction func, gpointer user_data){ g_return_if_fail (pads != NULL); g_return_if_fail (GST_IS_COLLECT_PADS (pads)); GST_OBJECT_LOCK (pads); pads->func = func; pads->user_data = user_data; GST_OBJECT_UNLOCK (pads);}static voidref_data (GstCollectData * data){ g_assert (data != NULL); g_atomic_int_inc (&(data->abidata.ABI.refcount));}static voidunref_data (GstCollectData * data){ GstCollectDataDestroyNotify destroy_notify; g_assert (data != NULL); g_assert (data->abidata.ABI.refcount > 0); if (!g_atomic_int_dec_and_test (&(data->abidata.ABI.refcount))) return; /* FIXME: Ugly hack as we can't add more fields to GstCollectData */ destroy_notify = (GstCollectDataDestroyNotify) g_object_get_data (G_OBJECT (data->pad), "gst-collect-data-destroy-notify"); if (destroy_notify) destroy_notify (data); g_object_unref (data->pad); if (data->buffer) { gst_buffer_unref (data->buffer); } g_free (data);}/** * gst_collect_pads_add_pad: * @pads: the collectspads to use * @pad: the pad to add * @size: the size of the returned #GstCollectData structure * * Add a pad to the collection of collect pads. The pad has to be * a sinkpad. The refcount of the pad is incremented. Use * gst_collect_pads_remove_pad() to remove the pad from the collection * again. * * You specify a size for the returned #GstCollectData structure * so that you can use it to store additional information. * * The pad will be automatically activated in push mode when @pads is * started. * * This function calls gst_collect_pads_add_pad() passing a value of NULL * for destroy_notify. * * Returns: a new #GstCollectData to identify the new pad. Or NULL * if wrong parameters are supplied. * * MT safe. */GstCollectData *gst_collect_pads_add_pad (GstCollectPads * pads, GstPad * pad, guint size){ return gst_collect_pads_add_pad_full (pads, pad, size, NULL);}/** * gst_collect_pads_add_pad_full: * @pads: the collectspads to use * @pad: the pad to add * @size: the size of the returned #GstCollectData structure * @destroy_notify: function to be called before the returned #GstCollectData * structure is freed * * Add a pad to the collection of collect pads. The pad has to be * a sinkpad. The refcount of the pad is incremented. Use * gst_collect_pads_remove_pad() to remove the pad from the collection * again. * * You specify a size for the returned #GstCollectData structure * so that you can use it to store additional information. * * You can also specify a #GstCollectDataDestroyNotify that will be called * just before the #GstCollectData structure is freed. It is passed the * pointer to the structure and should free any custom memory and resources * allocated for it. * * The pad will be automatically activated in push mode when @pads is * started. * * Since: 0.10.12 * * Returns: a new #GstCollectData to identify the new pad. Or NULL * if wrong parameters are supplied. * * MT safe. */GstCollectData *gst_collect_pads_add_pad_full (GstCollectPads * pads, GstPad * pad, guint size, GstCollectDataDestroyNotify destroy_notify){ GstCollectData *data; g_return_val_if_fail (pads != NULL, NULL); g_return_val_if_fail (GST_IS_COLLECT_PADS (pads), NULL); g_return_val_if_fail (pad != NULL, NULL); g_return_val_if_fail (GST_PAD_IS_SINK (pad), NULL); g_return_val_if_fail (size >= sizeof (GstCollectData), NULL); GST_DEBUG ("adding pad %s:%s", GST_DEBUG_PAD_NAME (pad)); data = g_malloc0 (size); data->collect = pads; data->pad = gst_object_ref (pad); data->buffer = NULL; data->pos = 0; gst_segment_init (&data->segment, GST_FORMAT_UNDEFINED); data->abidata.ABI.flushing = FALSE; data->abidata.ABI.new_segment = FALSE; data->abidata.ABI.eos = FALSE; data->abidata.ABI.refcount = 1; /* FIXME: Ugly hack as we can't add more fields to GstCollectData */ g_object_set_data (G_OBJECT (pad), "gst-collect-data-destroy-notify", (void *) destroy_notify); GST_COLLECT_PADS_PAD_LOCK (pads); GST_OBJECT_LOCK (pad); gst_pad_set_element_private (pad, data); GST_OBJECT_UNLOCK (pad); pads->abidata.ABI.pad_list = g_slist_append (pads->abidata.ABI.pad_list, data); gst_pad_set_chain_function (pad, GST_DEBUG_FUNCPTR (gst_collect_pads_chain)); gst_pad_set_event_function (pad, GST_DEBUG_FUNCPTR (gst_collect_pads_event)); /* activate the pad when needed */ if (pads->started) gst_pad_set_active (pad, TRUE); pads->abidata.ABI.pad_cookie++; GST_COLLECT_PADS_PAD_UNLOCK (pads); return data;}static gintfind_pad (GstCollectData * data, GstPad * pad){ if (data->pad == pad) return 0; return 1;}/** * gst_collect_pads_remove_pad: * @pads: the collectspads to use * @pad: the pad to remove * * Remove a pad from the collection of collect pads. This function will also * free the #GstCollectData and all the resources that were allocated with * gst_collect_pads_add_pad(). * * The pad will be deactivated automatically when @pads is stopped. * * Returns: %TRUE if the pad could be removed. * * MT safe. */gbooleangst_collect_pads_remove_pad (GstCollectPads * pads, GstPad * pad){ GstCollectData *data; GSList *list; g_return_val_if_fail (pads != NULL, FALSE); g_return_val_if_fail (GST_IS_COLLECT_PADS (pads), FALSE); g_return_val_if_fail (pad != NULL, FALSE); g_return_val_if_fail (GST_IS_PAD (pad), FALSE); GST_DEBUG ("removing pad %s:%s", GST_DEBUG_PAD_NAME (pad)); GST_COLLECT_PADS_PAD_LOCK (pads); list = g_slist_find_custom (pads->abidata.ABI.pad_list, pad, (GCompareFunc) find_pad); if (!list) goto unknown_pad; data = (GstCollectData *) list->data; GST_DEBUG ("found pad %s:%s at %p", GST_DEBUG_PAD_NAME (pad), data); /* clear the stuff we configured */ gst_pad_set_chain_function (pad, NULL); gst_pad_set_event_function (pad, NULL); GST_OBJECT_LOCK (pad); gst_pad_set_element_private (pad, NULL); GST_OBJECT_UNLOCK (pad); /* backward compat, also remove from data if stopped, note that this function * can only be called when we are stopped because we don't take the LOCK to * protect the pads->data list. */ if (!pads->started) { GSList *dlist; dlist = g_slist_find_custom (pads->data, pad, (GCompareFunc) find_pad); if (dlist) { GstCollectData *pdata = dlist->data; pads->data = g_slist_delete_link (pads->data, dlist); unref_data (pdata); } } /* remove from the pad list */ pads->abidata.ABI.pad_list = g_slist_delete_link (pads->abidata.ABI.pad_list, list); pads->abidata.ABI.pad_cookie++; /* signal waiters because something changed */ GST_COLLECT_PADS_BROADCAST (pads); /* deactivate the pad when needed */ if (!pads->started) gst_pad_set_active (pad, FALSE); /* clean and free the collect data */ unref_data (data); GST_COLLECT_PADS_PAD_UNLOCK (pads); return TRUE;unknown_pad: {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -