📄 gstbasetransform.c
字号:
/* GStreamer * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu> * 2000 Wim Taymans <wtay@chello.be> * 2005 Wim Taymans <wim@fluendo.com> * 2005 Andy Wingo <wingo@fluendo.com> * 2005 Thomas Vander Stichele <thomas at apestaart dot org> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. *//** * SECTION:gstbasetransform * @short_description: Base class for simple transform filters * @see_also: #GstBaseSrc, #GstBaseSink * * This base class is for filter elements that process data. * * It provides for: * <itemizedlist> * <listitem><para>one sinkpad and one srcpad</para></listitem> * <listitem><para> * Possible formats on sink and source pad implemented * with custom transform_caps function. By default uses * same format on sink and source. * </para></listitem> * <listitem><para>Handles state changes</para></listitem> * <listitem><para>Does flushing</para></listitem> * <listitem><para>Push mode</para></listitem> * <listitem><para> * Pull mode if the sub-class transform can operate on arbitrary data * </para></listitem> * </itemizedlist> * * Use Cases: * <orderedlist> * <listitem> * <itemizedlist><title>Passthrough mode</title> * <listitem><para> * Element has no interest in modifying the buffer. It may want to inspect it, * in which case the element should have a transform_ip function. If there * is no transform_ip function in passthrough mode, the buffer is pushed * intact. * </para></listitem> * <listitem><para> * On the GstBaseTransformClass is the passthrough_on_same_caps variable * which will automatically set/unset passthrough based on whether the * element negotiates the same caps on both pads. * </para></listitem> * <listitem><para> * passthrough_on_same_caps on an element that doesn't implement a * transform_caps function is useful for elements that only inspect data * (such as level) * </para></listitem> * </itemizedlist> * <itemizedlist> * <title>Example elements</title> * <listitem>Level</listitem> * <listitem>Videoscale, audioconvert, ffmpegcolorspace, audioresample in * certain modes.</listitem> * </itemizedlist> * </listitem> * <listitem> * <itemizedlist> * <title>Modifications in-place - input buffer and output buffer are the * same thing.</title> * <listitem><para> * The element must implement a transform_ip function. * </para></listitem> * <listitem><para> * Output buffer size must <= input buffer size * </para></listitem> * <listitem><para> * If the always_in_place flag is set, non-writable buffers will be copied * and passed to the transform_ip function, otherwise a new buffer will be * created and the transform function called. * </para></listitem> * <listitem><para> * Incoming writable buffers will be passed to the transform_ip function * immediately. </para></listitem> * <listitem><para> * only implementing transform_ip and not transform implies always_in_place * = TRUE * </para></listitem> * </itemizedlist> * <itemizedlist> * <title>Example elements</title> * <listitem>Volume</listitem> * <listitem>Audioconvert in certain modes (signed/unsigned * conversion)</listitem> * <listitem>ffmpegcolorspace in certain modes (endianness * swapping)</listitem> * </itemizedlist> * </listitem> * <listitem> * <itemizedlist> * <title>Modifications only to the caps/metadata of a buffer</title> * <listitem><para> * The element does not require writable data, but non-writable buffers * should be subbuffered so that the meta-information can be replaced. * </para></listitem> * <listitem><para> * Elements wishing to operate in this mode should replace the * prepare_output_buffer method to create subbuffers of the input buffer * and set always_in_place to TRUE * </para></listitem> * </itemizedlist> * <itemizedlist> * <title>Example elements</title> * <listitem>Capsfilter when setting caps on outgoing buffers that have * none.</listitem> * <listitem>identity when it is going to re-timestamp buffers by * datarate.</listitem> * </itemizedlist> * </listitem> * <listitem> * <itemizedlist><title>Normal mode</title> * <listitem><para> * always_in_place flag is not set, or there is no transform_ip function * </para></listitem> * <listitem><para> * Element will receive an input buffer and output buffer to operate on. * </para></listitem> * <listitem><para> * Output buffer is allocated by calling the prepare_output_buffer function. * </para></listitem> * </itemizedlist> * <itemizedlist> * <title>Example elements</title> * <listitem>Videoscale, ffmpegcolorspace, audioconvert when doing * scaling/conversions</listitem> * </itemizedlist> * </listitem> * <listitem> * <itemizedlist><title>Special output buffer allocations</title> * <listitem><para> * Elements which need to do special allocation of their output buffers * other than what gst_buffer_pad_alloc allows should implement a * prepare_output_buffer method, which calls the parent implementation and * passes the newly allocated buffer. * </para></listitem> * </itemizedlist> * <itemizedlist> * <title>Example elements</title> * <listitem>efence</listitem> * </itemizedlist> * </listitem> * </orderedlist> * * <itemizedlist><title>Sub-class settable flags on GstBaseTransform</title> * <listitem><para> * <itemizedlist><title>passthrough</title> * <listitem><para> * Implies that in the current configuration, the sub-class is not * interested in modifying the buffers. * </para></listitem> * <listitem><para> * Elements which are always in passthrough mode whenever the same caps * has been negotiated on both pads can set the class variable * passthrough_on_same_caps to have this behaviour automatically. * </para></listitem> * </itemizedlist> * </para></listitem> * <listitem><para> * <itemizedlist><title>always_in_place</title> * <listitem><para> * Determines whether a non-writable buffer will be copied before passing * to the transform_ip function. * </para></listitem> * <listitem><para> * Implied TRUE if no transform function is implemented. * </para></listitem> * <listitem><para> * Implied FALSE if ONLY transform function is implemented. * </para></listitem> * </itemizedlist> * </para></listitem> * </itemizedlist> **/#ifdef HAVE_CONFIG_H# include "config.h"#endif#include <stdlib.h>#include <string.h>#include "../../../gst/gst_private.h"#include "../../../gst/gst-i18n-lib.h"#include "gstbasetransform.h"#include <gst/gstmarshal.h>GST_DEBUG_CATEGORY_STATIC (gst_base_transform_debug);#define GST_CAT_DEFAULT gst_base_transform_debug/* BaseTransform signals and args */enum{ /* FILL ME */ LAST_SIGNAL};#define DEFAULT_PROP_QOS FALSEenum{ PROP_0, PROP_QOS};#define GST_BASE_TRANSFORM_GET_PRIVATE(obj) \ (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_BASE_TRANSFORM, GstBaseTransformPrivate))struct _GstBaseTransformPrivate{ /* QoS *//* with LOCK */ gboolean qos_enabled; gdouble proportion; GstClockTime earliest_time; /* previous buffer had a discont */ gboolean discont; GstActivateMode pad_mode;};static GstElementClass *parent_class = NULL;static void gst_base_transform_base_init (gpointer g_class);static void gst_base_transform_class_init (GstBaseTransformClass * klass);static void gst_base_transform_init (GstBaseTransform * trans, GstBaseTransformClass * klass);static GstFlowReturn gst_base_transform_prepare_output_buffer (GstBaseTransform * trans, GstBuffer * input, gint size, GstCaps * caps, GstBuffer ** buf);GTypegst_base_transform_get_type (void){ static GType base_transform_type = 0; if (!base_transform_type) { static const GTypeInfo base_transform_info = { sizeof (GstBaseTransformClass), (GBaseInitFunc) gst_base_transform_base_init, NULL, (GClassInitFunc) gst_base_transform_class_init, NULL, NULL, sizeof (GstBaseTransform), 0, (GInstanceInitFunc) gst_base_transform_init, }; base_transform_type = g_type_register_static (GST_TYPE_ELEMENT, "GstBaseTransform", &base_transform_info, G_TYPE_FLAG_ABSTRACT); } return base_transform_type;}static void gst_base_transform_finalize (GObject * object);static void gst_base_transform_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec);static void gst_base_transform_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec);static gboolean gst_base_transform_src_activate_pull (GstPad * pad, gboolean active);static gboolean gst_base_transform_sink_activate_push (GstPad * pad, gboolean active);static gboolean gst_base_transform_activate (GstBaseTransform * trans, gboolean active);static gboolean gst_base_transform_get_unit_size (GstBaseTransform * trans, GstCaps * caps, guint * size);static gboolean gst_base_transform_src_event (GstPad * pad, GstEvent * event);static gboolean gst_base_transform_src_eventfunc (GstBaseTransform * trans, GstEvent * event);static gboolean gst_base_transform_sink_event (GstPad * pad, GstEvent * event);static gboolean gst_base_transform_sink_eventfunc (GstBaseTransform * trans, GstEvent * event);static gboolean gst_base_transform_check_get_range (GstPad * pad);static GstFlowReturn gst_base_transform_getrange (GstPad * pad, guint64 offset, guint length, GstBuffer ** buffer);static GstFlowReturn gst_base_transform_chain (GstPad * pad, GstBuffer * buffer);static GstCaps *gst_base_transform_getcaps (GstPad * pad);static gboolean gst_base_transform_setcaps (GstPad * pad, GstCaps * caps);static GstFlowReturn gst_base_transform_buffer_alloc (GstPad * pad, guint64 offset, guint size, GstCaps * caps, GstBuffer ** buf);/* static guint gst_base_transform_signals[LAST_SIGNAL] = { 0 }; */static voidgst_base_transform_base_init (gpointer g_class){ GST_DEBUG_CATEGORY_INIT (gst_base_transform_debug, "basetransform", 0, "basetransform element");}static voidgst_base_transform_finalize (GObject * object){ GstBaseTransform *trans; trans = GST_BASE_TRANSFORM (object); g_mutex_free (trans->transform_lock); G_OBJECT_CLASS (parent_class)->finalize (object);}static voidgst_base_transform_class_init (GstBaseTransformClass * klass){ GObjectClass *gobject_class; gobject_class = G_OBJECT_CLASS (klass); g_type_class_add_private (klass, sizeof (GstBaseTransformPrivate)); parent_class = g_type_class_peek_parent (klass); gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_base_transform_set_property); gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_base_transform_get_property); g_object_class_install_property (gobject_class, PROP_QOS, g_param_spec_boolean ("qos", "QoS", "handle QoS messages", DEFAULT_PROP_QOS, G_PARAM_READWRITE)); gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_base_transform_finalize); klass->passthrough_on_same_caps = FALSE; klass->event = GST_DEBUG_FUNCPTR (gst_base_transform_sink_eventfunc); klass->src_event = GST_DEBUG_FUNCPTR (gst_base_transform_src_eventfunc);}static voidgst_base_transform_init (GstBaseTransform * trans, GstBaseTransformClass * bclass){ GstPadTemplate *pad_template; GST_DEBUG ("gst_base_transform_init"); trans->priv = GST_BASE_TRANSFORM_GET_PRIVATE (trans); pad_template = gst_element_class_get_pad_template (GST_ELEMENT_CLASS (bclass), "sink"); g_return_if_fail (pad_template != NULL); trans->sinkpad = gst_pad_new_from_template (pad_template, "sink"); gst_pad_set_getcaps_function (trans->sinkpad, GST_DEBUG_FUNCPTR (gst_base_transform_getcaps)); gst_pad_set_setcaps_function (trans->sinkpad, GST_DEBUG_FUNCPTR (gst_base_transform_setcaps)); gst_pad_set_event_function (trans->sinkpad, GST_DEBUG_FUNCPTR (gst_base_transform_sink_event)); gst_pad_set_chain_function (trans->sinkpad, GST_DEBUG_FUNCPTR (gst_base_transform_chain)); gst_pad_set_activatepush_function (trans->sinkpad, GST_DEBUG_FUNCPTR (gst_base_transform_sink_activate_push)); gst_pad_set_bufferalloc_function (trans->sinkpad, GST_DEBUG_FUNCPTR (gst_base_transform_buffer_alloc)); gst_element_add_pad (GST_ELEMENT (trans), trans->sinkpad); pad_template = gst_element_class_get_pad_template (GST_ELEMENT_CLASS (bclass), "src"); g_return_if_fail (pad_template != NULL); trans->srcpad = gst_pad_new_from_template (pad_template, "src"); gst_pad_set_getcaps_function (trans->srcpad, GST_DEBUG_FUNCPTR (gst_base_transform_getcaps)); gst_pad_set_setcaps_function (trans->srcpad, GST_DEBUG_FUNCPTR (gst_base_transform_setcaps)); gst_pad_set_event_function (trans->srcpad, GST_DEBUG_FUNCPTR (gst_base_transform_src_event)); gst_pad_set_checkgetrange_function (trans->srcpad, GST_DEBUG_FUNCPTR (gst_base_transform_check_get_range)); gst_pad_set_getrange_function (trans->srcpad, GST_DEBUG_FUNCPTR (gst_base_transform_getrange)); gst_pad_set_activatepull_function (trans->srcpad, GST_DEBUG_FUNCPTR (gst_base_transform_src_activate_pull)); gst_element_add_pad (GST_ELEMENT (trans), trans->srcpad); trans->transform_lock = g_mutex_new (); trans->delay_configure = FALSE; trans->pending_configure = FALSE; trans->priv->qos_enabled = DEFAULT_PROP_QOS; trans->cache_caps1 = NULL; trans->cache_caps2 = NULL; trans->priv->pad_mode = GST_ACTIVATE_NONE; trans->passthrough = FALSE; if (bclass->transform == NULL) { /* If no transform function, always_in_place is TRUE */ GST_DEBUG_OBJECT (trans, "setting in_place TRUE"); trans->always_in_place = TRUE; if (bclass->transform_ip == NULL) trans->passthrough = TRUE; }}/* given @caps on the src or sink pad (given by @direction) * calculate the possible caps on the other pad. * * Returns new caps, unref after usage. */static GstCaps *gst_base_transform_transform_caps (GstBaseTransform * trans, GstPadDirection direction, GstCaps * caps){ GstCaps *ret; GstBaseTransformClass *klass; klass = GST_BASE_TRANSFORM_GET_CLASS (trans); /* if there is a custom transform function, use this */ if (klass->transform_caps) { GstCaps *temp; gint i; /* start with empty caps */ ret = gst_caps_new_empty (); GST_DEBUG_OBJECT (trans, "transform caps (direction = %d)", direction); if (gst_caps_is_any (caps)) { /* for any caps we still have to call the transform function */ GST_DEBUG_OBJECT (trans, "from: ANY"); temp = klass->transform_caps (trans, direction, caps); GST_DEBUG_OBJECT (trans, " to: %" GST_PTR_FORMAT, temp); temp = gst_caps_make_writable (temp); gst_caps_append (ret, temp); } else { /* we send caps with just one structure to the transform * function as this is easier for the element */ for (i = 0; i < gst_caps_get_size (caps); i++) { GstCaps *nth; nth = gst_caps_copy_nth (caps, i); GST_DEBUG_OBJECT (trans, "from[%d]: %" GST_PTR_FORMAT, i, nth); temp = klass->transform_caps (trans, direction, nth); gst_caps_unref (nth); GST_DEBUG_OBJECT (trans, " to[%d]: %" GST_PTR_FORMAT, i, temp); temp = gst_caps_make_writable (temp); /* FIXME: here we need to only append those structures, that are not yet * in there * gst_caps_append (ret, temp); */ gst_caps_merge (ret, temp); } GST_DEBUG_OBJECT (trans, "merged: (%d)", gst_caps_get_size (ret)); /* now simplify caps gst_caps_do_simplify (ret); GST_DEBUG_OBJECT (trans, "simplified: (%d)", gst_caps_get_size (ret)); */ } } else { /* else use the identity transform */ ret = gst_caps_ref (caps); } GST_DEBUG_OBJECT (trans, "to: (%d) %" GST_PTR_FORMAT, gst_caps_get_size (ret), ret); return ret;}static gbooleangst_base_transform_transform_size (GstBaseTransform * trans, GstPadDirection direction, GstCaps * caps, guint size, GstCaps * othercaps, guint * othersize){ guint inunitsize, outunitsize, units; GstBaseTransformClass *klass;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -