📄 gstbasesrc.c
字号:
/* GStreamer * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu> * 2000,2005 Wim Taymans <wim@fluendo.com> * * gstbasesrc.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:gstbasesrc * @short_description: Base class for getrange based source elements * @see_also: #GstPushSrc, #GstBaseTransform, #GstBaseSink * * This is a generice base class for source elements. The following * types of sources are supported: * <itemizedlist> * <listitem><para>random access sources like files</para></listitem> * <listitem><para>seekable sources</para></listitem> * <listitem><para>live sources</para></listitem> * </itemizedlist> * * <refsect2> * <para> * The source can be configured to operate in any #GstFormat with the * gst_base_src_set_format() method. The currently set format determines * the format of the internal #GstSegment and any #GST_EVENT_NEWSEGMENT * events. The default format for #GstBaseSrc is #GST_FORMAT_BYTES. * </para> * <para> * #GstBaseSrc always supports push mode scheduling. If the following * conditions are met, it also supports pull mode scheduling: * <itemizedlist> * <listitem><para>The format is set to #GST_FORMAT_BYTES (default).</para> * </listitem> * <listitem><para>#GstBaseSrc::is_seekable returns %TRUE.</para> * </listitem> * </itemizedlist> * </para> * <para> * Since 0.10.9, any #GstBaseSrc can enable pull based scheduling at any * time by overriding #GstBaseSrc::check_get_range so that it returns %TRUE. * </para> * <para> * If all the conditions are met for operating in pull mode, #GstBaseSrc is * automatically seekable in push mode as well. The following conditions must * be met to make the element seekable in push mode when the format is not * #GST_FORMAT_BYTES: * <itemizedlist> * <listitem><para> * #GstBaseSrc::is_seekable returns %TRUE. * </para></listitem> * <listitem><para> * #GstBaseSrc::query can convert all supported seek formats to the * internal format as set with gst_base_src_set_format(). * </para></listitem> * <listitem><para> * #GstBaseSrc::do_seek is implemented, performs the seek and returns %TRUE. * </para></listitem> * </itemizedlist> * </para> * <para> * When the element does not meet the requirements to operate in pull mode, * the offset and length in the #GstBaseSrc::create method should be ignored. * It is recommended to subclass #GstPushSrc instead, in this situation. If the * element can operate in pull mode but only with specific offsets and * lengths, it is allowed to generate an error when the wrong values are passed * to the #GstBaseSrc::create function. * </para> * <para> * #GstBaseSrc has support for live sources. Live sources are sources that * produce data at a fixed rate, such as audio or video capture devices. A * typical live source also provides a clock to publish the rate at which * they produce data. * Use gst_base_src_set_live() to activate the live source mode. * </para> * <para> * A live source does not produce data in the PAUSED state. This means that the * #GstBaseSrc::create method will not be called in PAUSED but only in PLAYING. * To signal the pipeline that the element will not produce data, the return * value from the READY to PAUSED state will be #GST_STATE_CHANGE_NO_PREROLL. * </para> * <para> * A typical live source will timestamp the buffers it creates with the * current stream time of the pipeline. This is one reason why a live source * can only produce data in the PLAYING state, when the clock is actually * distributed and running. * </para> * <para> * Live sources that synchronize and block on the clock (and audio source, for * example) can since 0.10.12 use gst_base_src_wait_playing() when the ::create * function was interrupted by a state change to PAUSED. * </para> * <para> * The #GstBaseSrc::get_times method can be used to implement pseudo-live * sources. The base source will wait for the specified stream time returned in * #GstBaseSrc::get_times before pushing out the buffer. * It only makes sense to implement the ::get_times function if the source is * a live source. * </para> * <para> * There is only support in #GstBaseSrc for exactly one source pad, which * should be named "src". A source implementation (subclass of #GstBaseSrc) * should install a pad template in its base_init function, like so: * </para> * <para> * <programlisting> * static void * my_element_base_init (gpointer g_class) * { * GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class); * // srctemplate should be a #GstStaticPadTemplate with direction * // #GST_PAD_SRC and name "src" * gst_element_class_add_pad_template (gstelement_class, * gst_static_pad_template_get (&srctemplate)); * // see #GstElementDetails * gst_element_class_set_details (gstelement_class, &details); * } * </programlisting> * </para> * <title>Controlled shutdown of live sources in applications</title> * <para> * Applications that record from a live source may want to stop recording * in a controlled way, so that the recording is stopped, but the data * already in the pipeline is processed to the end (remember that many live * sources would go on recording forever otherwise). For that to happen the * application needs to make the source stop recording and send an EOS * event down the pipeline. The application would then wait for an * EOS message posted on the pipeline's bus to know when all data has * been processed and the pipeline can safely be stopped. * </para> * <para> * Since GStreamer 0.10.3 an application may simply set the source * element to NULL or READY state to make it send an EOS event downstream. * The application should lock the state of the source afterwards, so that * shutting down the pipeline from PLAYING doesn't temporarily start up the * source element for a second time: * <programlisting> * ... * // stop recording * gst_element_set_state (audio_source, #GST_STATE_NULL); * gst_element_set_locked_state (audio_source, %TRUE); * ... * </programlisting> * Now the application should wait for an EOS message * to be posted on the pipeline's bus. Once it has received * an EOS message, it may safely shut down the entire pipeline: * <programlisting> * ... * // everything done - shut down pipeline * gst_element_set_state (pipeline, #GST_STATE_NULL); * gst_element_set_locked_state (audio_source, %FALSE); * ... * </programlisting> * </para> * <para> * Note that setting the source element to NULL or READY when the * pipeline is in the PAUSED state may cause a deadlock since the streaming * thread might be blocked in PREROLL. * </para> * <para> * Last reviewed on 2006-09-27 (0.10.11) * </para> * </refsect2> */#ifdef HAVE_CONFIG_H# include "config.h"#endif#include <stdlib.h>#include <string.h>#include "gstbasesrc.h"#include "gsttypefindhelper.h"#include <gst/gstmarshal.h>#include <gst/gst-i18n-lib.h>GST_DEBUG_CATEGORY_STATIC (gst_base_src_debug);#define GST_CAT_DEFAULT gst_base_src_debug#define GST_LIVE_GET_LOCK(elem) (GST_BASE_SRC_CAST(elem)->live_lock)#define GST_LIVE_LOCK(elem) g_mutex_lock(GST_LIVE_GET_LOCK(elem))#define GST_LIVE_TRYLOCK(elem) g_mutex_trylock(GST_LIVE_GET_LOCK(elem))#define GST_LIVE_UNLOCK(elem) g_mutex_unlock(GST_LIVE_GET_LOCK(elem))#define GST_LIVE_GET_COND(elem) (GST_BASE_SRC_CAST(elem)->live_cond)#define GST_LIVE_WAIT(elem) g_cond_wait (GST_LIVE_GET_COND (elem), GST_LIVE_GET_LOCK (elem))#define GST_LIVE_TIMED_WAIT(elem, timeval) g_cond_timed_wait (GST_LIVE_GET_COND (elem), GST_LIVE_GET_LOCK (elem),\ timeval)#define GST_LIVE_SIGNAL(elem) g_cond_signal (GST_LIVE_GET_COND (elem));#define GST_LIVE_BROADCAST(elem) g_cond_broadcast (GST_LIVE_GET_COND (elem));/* BaseSrc signals and args */enum{ /* FILL ME */ LAST_SIGNAL};#define DEFAULT_BLOCKSIZE 4096#define DEFAULT_NUM_BUFFERS -1#define DEFAULT_TYPEFIND FALSEenum{ PROP_0, PROP_BLOCKSIZE, PROP_NUM_BUFFERS, PROP_TYPEFIND,};#define GST_BASE_SRC_GET_PRIVATE(obj) \ (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_BASE_SRC, GstBaseSrcPrivate))struct _GstBaseSrcPrivate{ gboolean last_sent_eos; /* last thing we did was send an EOS (we set this * to avoid the sending of two EOS in some cases) */ gboolean discont; /* two segments to be sent in the streaming thread with STREAM_LOCK */ GstEvent *close_segment; GstEvent *start_segment;};static GstElementClass *parent_class = NULL;static void gst_base_src_base_init (gpointer g_class);static void gst_base_src_class_init (GstBaseSrcClass * klass);static void gst_base_src_init (GstBaseSrc * src, gpointer g_class);static void gst_base_src_finalize (GObject * object);GTypegst_base_src_get_type (void){ static GType base_src_type = 0; if (G_UNLIKELY (base_src_type == 0)) { static const GTypeInfo base_src_info = { sizeof (GstBaseSrcClass), (GBaseInitFunc) gst_base_src_base_init, NULL, (GClassInitFunc) gst_base_src_class_init, NULL, NULL, sizeof (GstBaseSrc), 0, (GInstanceInitFunc) gst_base_src_init, }; base_src_type = g_type_register_static (GST_TYPE_ELEMENT, "GstBaseSrc", &base_src_info, G_TYPE_FLAG_ABSTRACT); } return base_src_type;}static GstCaps *gst_base_src_getcaps (GstPad * pad);static gboolean gst_base_src_setcaps (GstPad * pad, GstCaps * caps);static void gst_base_src_fixate (GstPad * pad, GstCaps * caps);static gboolean gst_base_src_activate_push (GstPad * pad, gboolean active);static gboolean gst_base_src_activate_pull (GstPad * pad, gboolean active);static void gst_base_src_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec);static void gst_base_src_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec);static gboolean gst_base_src_event_handler (GstPad * pad, GstEvent * event);static gboolean gst_base_src_send_event (GstElement * elem, GstEvent * event);static gboolean gst_base_src_default_event (GstBaseSrc * src, GstEvent * event);static const GstQueryType *gst_base_src_get_query_types (GstElement * element);static gboolean gst_base_src_query (GstPad * pad, GstQuery * query);static gboolean gst_base_src_default_negotiate (GstBaseSrc * basesrc);static gboolean gst_base_src_default_do_seek (GstBaseSrc * src, GstSegment * segment);static gboolean gst_base_src_default_query (GstBaseSrc * src, GstQuery * query);static gboolean gst_base_src_default_prepare_seek_segment (GstBaseSrc * src, GstEvent * event, GstSegment * segment);static gboolean gst_base_src_unlock (GstBaseSrc * basesrc);static gboolean gst_base_src_unlock_stop (GstBaseSrc * basesrc);static gboolean gst_base_src_start (GstBaseSrc * basesrc);static gboolean gst_base_src_stop (GstBaseSrc * basesrc);static GstStateChangeReturn gst_base_src_change_state (GstElement * element, GstStateChange transition);static void gst_base_src_loop (GstPad * pad);static gboolean gst_base_src_pad_check_get_range (GstPad * pad);static gboolean gst_base_src_default_check_get_range (GstBaseSrc * bsrc);static GstFlowReturn gst_base_src_pad_get_range (GstPad * pad, guint64 offset, guint length, GstBuffer ** buf);static GstFlowReturn gst_base_src_get_range (GstBaseSrc * src, guint64 offset, guint length, GstBuffer ** buf);static voidgst_base_src_base_init (gpointer g_class){ GST_DEBUG_CATEGORY_INIT (gst_base_src_debug, "basesrc", 0, "basesrc element");}static voidgst_base_src_class_init (GstBaseSrcClass * klass){ GObjectClass *gobject_class; GstElementClass *gstelement_class; gobject_class = G_OBJECT_CLASS (klass); gstelement_class = GST_ELEMENT_CLASS (klass); g_type_class_add_private (klass, sizeof (GstBaseSrcPrivate)); parent_class = g_type_class_peek_parent (klass); gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_base_src_finalize); gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_base_src_set_property); gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_base_src_get_property); g_object_class_install_property (gobject_class, PROP_BLOCKSIZE, g_param_spec_ulong ("blocksize", "Block size", "Size in bytes to read per buffer (0 = default)", 0, G_MAXULONG, DEFAULT_BLOCKSIZE, G_PARAM_READWRITE)); g_object_class_install_property (gobject_class, PROP_NUM_BUFFERS, g_param_spec_int ("num-buffers", "num-buffers", "Number of buffers to output before sending EOS", -1, G_MAXINT, DEFAULT_NUM_BUFFERS, G_PARAM_READWRITE)); g_object_class_install_property (gobject_class, PROP_TYPEFIND, g_param_spec_boolean ("typefind", "Typefind", "Run typefind before negotiating", DEFAULT_TYPEFIND, G_PARAM_READWRITE)); gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_base_src_change_state); gstelement_class->send_event = GST_DEBUG_FUNCPTR (gst_base_src_send_event); gstelement_class->get_query_types = GST_DEBUG_FUNCPTR (gst_base_src_get_query_types); klass->negotiate = GST_DEBUG_FUNCPTR (gst_base_src_default_negotiate); klass->event = GST_DEBUG_FUNCPTR (gst_base_src_default_event); klass->do_seek = GST_DEBUG_FUNCPTR (gst_base_src_default_do_seek); klass->query = GST_DEBUG_FUNCPTR (gst_base_src_default_query); klass->check_get_range = GST_DEBUG_FUNCPTR (gst_base_src_default_check_get_range); klass->prepare_seek_segment = GST_DEBUG_FUNCPTR (gst_base_src_default_prepare_seek_segment);}static voidgst_base_src_init (GstBaseSrc * basesrc, gpointer g_class){ GstPad *pad; GstPadTemplate *pad_template; basesrc->priv = GST_BASE_SRC_GET_PRIVATE (basesrc); basesrc->is_live = FALSE; basesrc->live_lock = g_mutex_new (); basesrc->live_cond = g_cond_new (); basesrc->num_buffers = DEFAULT_NUM_BUFFERS; basesrc->num_buffers_left = -1; basesrc->can_activate_push = TRUE; basesrc->pad_mode = GST_ACTIVATE_NONE; pad_template = gst_element_class_get_pad_template (GST_ELEMENT_CLASS (g_class), "src"); g_return_if_fail (pad_template != NULL); GST_DEBUG_OBJECT (basesrc, "creating src pad"); pad = gst_pad_new_from_template (pad_template, "src"); GST_DEBUG_OBJECT (basesrc, "setting functions on src pad"); gst_pad_set_activatepush_function (pad, GST_DEBUG_FUNCPTR (gst_base_src_activate_push)); gst_pad_set_activatepull_function (pad, GST_DEBUG_FUNCPTR (gst_base_src_activate_pull)); gst_pad_set_event_function (pad, GST_DEBUG_FUNCPTR (gst_base_src_event_handler)); gst_pad_set_query_function (pad, GST_DEBUG_FUNCPTR (gst_base_src_query)); gst_pad_set_checkgetrange_function (pad, GST_DEBUG_FUNCPTR (gst_base_src_pad_check_get_range)); gst_pad_set_getrange_function (pad, GST_DEBUG_FUNCPTR (gst_base_src_pad_get_range)); gst_pad_set_getcaps_function (pad, GST_DEBUG_FUNCPTR (gst_base_src_getcaps)); gst_pad_set_setcaps_function (pad, GST_DEBUG_FUNCPTR (gst_base_src_setcaps)); gst_pad_set_fixatecaps_function (pad, GST_DEBUG_FUNCPTR (gst_base_src_fixate)); /* hold pointer to pad */ basesrc->srcpad = pad; GST_DEBUG_OBJECT (basesrc, "adding src pad"); gst_element_add_pad (GST_ELEMENT (basesrc), pad); basesrc->blocksize = DEFAULT_BLOCKSIZE; basesrc->clock_id = NULL; /* we operate in BYTES by default */ gst_base_src_set_format (basesrc, GST_FORMAT_BYTES); basesrc->data.ABI.typefind = DEFAULT_TYPEFIND; GST_OBJECT_FLAG_UNSET (basesrc, GST_BASE_SRC_STARTED); GST_DEBUG_OBJECT (basesrc, "init done");}static voidgst_base_src_finalize (GObject * object){ GstBaseSrc *basesrc; GstEvent **event_p; basesrc = GST_BASE_SRC (object); g_mutex_free (basesrc->live_lock); g_cond_free (basesrc->live_cond); event_p = &basesrc->data.ABI.pending_seek; gst_event_replace ((GstEvent **) event_p, NULL); G_OBJECT_CLASS (parent_class)->finalize (object);}/** * gst_base_src_wait_playing: * @src: the src * * If the #GstBaseSrcClass::create method performs its own synchronisation against
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -