GST_PAD_ALWAYS,
GST_STATIC_CAPS_ANY);
+static void gst_app_sink_uri_handler_init (gpointer g_iface,
+ gpointer iface_data);
+
static void gst_app_sink_dispose (GObject * object);
static void gst_app_sink_finalize (GObject * object);
static guint gst_app_sink_signals[LAST_SIGNAL] = { 0 };
-GST_BOILERPLATE (GstAppSink, gst_app_sink, GstBaseSink, GST_TYPE_BASE_SINK);
+static void
+_do_init (GType filesrc_type)
+{
+ static const GInterfaceInfo urihandler_info = {
+ gst_app_sink_uri_handler_init,
+ NULL,
+ NULL
+ };
+ g_type_add_interface_static (filesrc_type, GST_TYPE_URI_HANDLER,
+ &urihandler_info);
+}
+
+GST_BOILERPLATE_FULL (GstAppSink, gst_app_sink, GstBaseSink, GST_TYPE_BASE_SINK,
+ _do_init);
/* Can't use glib-genmarshal for this, as it doesn't know how to handle
* GstMiniObject-based types, which are a new fundamental type */
g_mutex_unlock (appsink->priv->mutex);
/* emit EOS now */
- g_signal_emit (appsink, gst_app_sink_signals[SIGNAL_EOS], 0);
-
if (appsink->priv->callbacks.eos)
appsink->priv->callbacks.eos (appsink, appsink->priv->user_data);
+ else
+ g_signal_emit (appsink, gst_app_sink_signals[SIGNAL_EOS], 0);
+
break;
case GST_EVENT_FLUSH_START:
/* we don't have to do anything here, the base class will call unlock
emit = appsink->priv->emit_signals;
g_mutex_unlock (appsink->priv->mutex);
- if (emit)
- g_signal_emit (appsink, gst_app_sink_signals[SIGNAL_NEW_PREROLL], 0);
-
if (appsink->priv->callbacks.new_preroll)
appsink->priv->callbacks.new_preroll (appsink, appsink->priv->user_data);
+ else if (emit)
+ g_signal_emit (appsink, gst_app_sink_signals[SIGNAL_NEW_PREROLL], 0);
return GST_FLOW_OK;
emit = appsink->priv->emit_signals;
g_mutex_unlock (appsink->priv->mutex);
- if (emit)
- g_signal_emit (appsink, gst_app_sink_signals[SIGNAL_NEW_BUFFER], 0);
-
if (appsink->priv->callbacks.new_buffer)
appsink->priv->callbacks.new_buffer (appsink, appsink->priv->user_data);
+ else if (emit)
+ g_signal_emit (appsink, gst_app_sink_signals[SIGNAL_NEW_BUFFER], 0);
return GST_FLOW_OK;
* This is an alternative to using the signals, it has lower overhead and is thus
* less expensive, but also less flexible.
*
+ * If callbacks are installed, no signals will be emited for performance
+ * reasons.
+ *
* Since: 0.10.23
*/
void
appsink->priv->notify = notify;
GST_OBJECT_UNLOCK (appsink);
}
+
+/*** GSTURIHANDLER INTERFACE *************************************************/
+
+static GstURIType
+gst_app_sink_uri_get_type (void)
+{
+ return GST_URI_SINK;
+}
+
+static gchar **
+gst_app_sink_uri_get_protocols (void)
+{
+ static gchar *protocols[] = { "appsink", NULL };
+
+ return protocols;
+}
+
+static const gchar *
+gst_app_sink_uri_get_uri (GstURIHandler * handler)
+{
+ return "appsink";
+}
+
+static gboolean
+gst_app_sink_uri_set_uri (GstURIHandler * handler, const gchar * uri)
+{
+ gchar *protocol;
+ gboolean ret;
+
+ protocol = gst_uri_get_protocol (uri);
+ ret = !strcmp (protocol, "appsink");
+ g_free (protocol);
+
+ return ret;
+}
+
+static void
+gst_app_sink_uri_handler_init (gpointer g_iface, gpointer iface_data)
+{
+ GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface;
+
+ iface->get_type = gst_app_sink_uri_get_type;
+ iface->get_protocols = gst_app_sink_uri_get_protocols;
+ iface->get_uri = gst_app_sink_uri_get_uri;
+ iface->set_uri = gst_app_sink_uri_set_uri;
+}
guint64 min_latency;
guint64 max_latency;
+ gboolean emit_signals;
+
+ GstAppSrcCallbacks callbacks;
+ gpointer user_data;
+ GDestroyNotify notify;
};
GST_DEBUG_CATEGORY_STATIC (app_src_debug);
#define DEFAULT_PROP_IS_LIVE FALSE
#define DEFAULT_PROP_MIN_LATENCY -1
#define DEFAULT_PROP_MAX_LATENCY -1
+#define DEFAULT_PROP_EMIT_SIGNALS TRUE
enum
{
PROP_IS_LIVE,
PROP_MIN_LATENCY,
PROP_MAX_LATENCY,
+ PROP_EMIT_SIGNALS,
PROP_LAST
};
-1, G_MAXINT64, DEFAULT_PROP_MAX_LATENCY,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ /**
+ * GstAppSrc::emit-signals
+ *
+ * Make appsrc emit the "need-data", "enough-data" and "seek-data" signals.
+ * This option is by default enabled for backwards compatibility reasons but
+ * can disabled when needed because signal emission is expensive.
+ *
+ * Since: 0.10.23
+ */
+ g_object_class_install_property (gobject_class, PROP_EMIT_SIGNALS,
+ g_param_spec_boolean ("emit-signals", "Emit signals",
+ "Emit new-preroll and new-buffer signals", DEFAULT_PROP_EMIT_SIGNALS,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
/**
* GstAppSrc::need-data:
* @appsrc: the appsrc element that emited the signal
appsrc->priv->block = DEFAULT_PROP_BLOCK;
appsrc->priv->min_latency = DEFAULT_PROP_MIN_LATENCY;
appsrc->priv->max_latency = DEFAULT_PROP_MAX_LATENCY;
+ appsrc->priv->emit_signals = DEFAULT_PROP_EMIT_SIGNALS;
gst_base_src_set_live (GST_BASE_SRC (appsrc), DEFAULT_PROP_IS_LIVE);
}
gst_app_src_set_latencies (appsrc, FALSE, -1, TRUE,
g_value_get_int64 (value));
break;
+ case PROP_EMIT_SIGNALS:
+ gst_app_src_set_emit_signals (appsrc, g_value_get_boolean (value));
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
g_value_set_int64 (value, max);
break;
}
+ case PROP_EMIT_SIGNALS:
+ g_value_set_boolean (value, gst_app_src_get_emit_signals (appsrc));
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
if (appsrc->priv->stream_type == GST_APP_STREAM_TYPE_STREAM)
return TRUE;
- g_signal_emit (appsrc, gst_app_src_signals[SIGNAL_SEEK_DATA], 0,
- desired_position, &res);
+ if (appsrc->priv->callbacks.seek_data)
+ res = appsrc->priv->callbacks.seek_data (appsrc, desired_position,
+ appsrc->priv->user_data);
+ else {
+ gboolean emit;
+
+ g_mutex_lock (appsrc->priv->mutex);
+ emit = appsrc->priv->emit_signals;
+ g_mutex_unlock (appsrc->priv->mutex);
+
+ if (emit)
+ g_signal_emit (appsrc, gst_app_src_signals[SIGNAL_SEEK_DATA], 0,
+ desired_position, &res);
+ }
if (res) {
GST_DEBUG_OBJECT (appsrc, "flushing queue");
* changed. */
if (G_UNLIKELY (appsrc->priv->offset != offset)) {
gboolean res;
+ gboolean emit;
+ emit = appsrc->priv->emit_signals;
g_mutex_unlock (appsrc->priv->mutex);
GST_DEBUG_OBJECT (appsrc,
"we are at %" G_GINT64_FORMAT ", seek to %" G_GINT64_FORMAT,
appsrc->priv->offset, offset);
- g_signal_emit (appsrc, gst_app_src_signals[SIGNAL_SEEK_DATA], 0,
- offset, &res);
+ if (appsrc->priv->callbacks.seek_data)
+ res = appsrc->priv->callbacks.seek_data (appsrc, offset,
+ appsrc->priv->user_data);
+ else if (emit)
+ g_signal_emit (appsrc, gst_app_src_signals[SIGNAL_SEEK_DATA], 0,
+ offset, &res);
if (G_UNLIKELY (!res))
/* failing to seek is fatal */
ret = GST_FLOW_OK;
break;
} else {
+ gboolean emit;
+
+ emit = appsrc->priv->emit_signals;
g_mutex_unlock (appsrc->priv->mutex);
/* we have no data, we need some. We fire the signal with the size hint. */
- g_signal_emit (appsrc, gst_app_src_signals[SIGNAL_NEED_DATA], 0, size,
- NULL);
+ if (appsrc->priv->callbacks.need_data)
+ appsrc->priv->callbacks.need_data (appsrc, size,
+ appsrc->priv->user_data);
+ else if (emit)
+ g_signal_emit (appsrc, gst_app_src_signals[SIGNAL_NEED_DATA], 0, size,
+ NULL);
g_mutex_lock (appsrc->priv->mutex);
/* we can be flushing now because we released the lock */
g_mutex_unlock (appsrc->priv->mutex);
}
+/**
+ * gst_app_src_set_emit_signals:
+ * @appsrc: a #GstAppSrc
+ * @emit: the new state
+ *
+ * Make appsrc emit the "new-preroll" and "new-buffer" signals. This option is
+ * by default disabled because signal emission is expensive and unneeded when
+ * the application prefers to operate in pull mode.
+ *
+ * Since: 0.10.23
+ */
+void
+gst_app_src_set_emit_signals (GstAppSrc * appsrc, gboolean emit)
+{
+ g_return_if_fail (GST_IS_APP_SRC (appsrc));
+
+ g_mutex_lock (appsrc->priv->mutex);
+ appsrc->priv->emit_signals = emit;
+ g_mutex_unlock (appsrc->priv->mutex);
+}
+
+/**
+ * gst_app_src_get_emit_signals:
+ * @appsrc: a #GstAppSrc
+ *
+ * Check if appsrc will emit the "new-preroll" and "new-buffer" signals.
+ *
+ * Returns: %TRUE if @appsrc is emiting the "new-preroll" and "new-buffer"
+ * signals.
+ *
+ * Since: 0.10.23
+ */
+gboolean
+gst_app_src_get_emit_signals (GstAppSrc * appsrc)
+{
+ gboolean result;
+
+ g_return_val_if_fail (GST_IS_APP_SRC (appsrc), FALSE);
+
+ g_mutex_lock (appsrc->priv->mutex);
+ result = appsrc->priv->emit_signals;
+ g_mutex_unlock (appsrc->priv->mutex);
+
+ return result;
+}
+
static GstFlowReturn
gst_app_src_push_buffer_full (GstAppSrc * appsrc, GstBuffer * buffer,
gboolean steal_ref)
appsrc->priv->queued_bytes, appsrc->priv->max_bytes);
if (first) {
+ gboolean emit;
+
+ emit = appsrc->priv->emit_signals;
/* only signal on the first push */
g_mutex_unlock (appsrc->priv->mutex);
- g_signal_emit (appsrc, gst_app_src_signals[SIGNAL_ENOUGH_DATA], 0,
- NULL);
+ if (appsrc->priv->callbacks.enough_data)
+ appsrc->priv->callbacks.enough_data (appsrc, appsrc->priv->user_data);
+ else if (emit)
+ g_signal_emit (appsrc, gst_app_src_signals[SIGNAL_ENOUGH_DATA], 0,
+ NULL);
g_mutex_lock (appsrc->priv->mutex);
/* continue to check for flushing/eos after releasing the lock */
* Adds a buffer to the queue of buffers that the appsrc element will
* push to its source pad. This function takes ownership of the buffer.
*
+ * When the block property is TRUE, this function can block until free
+ * space becomes available in the queue.
+ *
* Returns: #GST_FLOW_OK when the buffer was successfuly queued.
* #GST_FLOW_WRONG_STATE when @appsrc is not PAUSED or PLAYING.
* #GST_FLOW_UNEXPECTED when EOS occured.
}
}
+/**
+ * gst_app_src_set_callbacks:
+ * @appsrc: a #GstAppSrc
+ * @callbacks: the callbacks
+ * @user_data: a user_data argument for the callbacks
+ * @notify: a destroy notify function
+ *
+ * Set callbacks which will be executed when data is needed, enough data has
+ * been collected or when a seek should be performed.
+ * This is an alternative to using the signals, it has lower overhead and is thus
+ * less expensive, but also less flexible.
+ *
+ * If callbacks are installed, no signals will be emited for performance
+ * reasons.
+ *
+ * Since: 0.10.23
+ */
+void
+gst_app_src_set_callbacks (GstAppSrc * appsrc,
+ GstAppSrcCallbacks * callbacks, gpointer user_data, GDestroyNotify notify)
+{
+ GDestroyNotify old_notify;
+
+ g_return_if_fail (appsrc != NULL);
+ g_return_if_fail (GST_IS_APP_SRC (appsrc));
+ g_return_if_fail (callbacks != NULL);
+
+ GST_OBJECT_LOCK (appsrc);
+ old_notify = appsrc->priv->notify;
+
+ if (old_notify) {
+ gpointer old_data;
+
+ old_data = appsrc->priv->user_data;
+
+ appsrc->priv->user_data = NULL;
+ appsrc->priv->notify = NULL;
+ GST_OBJECT_UNLOCK (appsrc);
+
+ old_notify (old_data);
+
+ GST_OBJECT_LOCK (appsrc);
+ }
+ appsrc->priv->callbacks = *callbacks;
+ appsrc->priv->user_data = user_data;
+ appsrc->priv->notify = notify;
+ GST_OBJECT_UNLOCK (appsrc);
+}
+
/*** GSTURIHANDLER INTERFACE *************************************************/
static GstURIType
typedef struct _GstAppSrcClass GstAppSrcClass;
typedef struct _GstAppSrcPrivate GstAppSrcPrivate;
+/**
+ * GstAppSrcCallbacks:
+ * @need_data: Called when the appsrc needs more data. A buffer or EOS should be
+ * pushed to appsrc from this thread or another thread. @length is just a hint
+ * and when it is set to -1, any number of bytes can be pushed into @appsrc.
+ * @enough_data: Called when appsrc has enough data. It is recommended that the
+ * application stops calling push-buffer until the need_data callback is
+ * emited again to avoid excessive buffer queueing.
+ * @seek_data: Called when a seek should be performed to the offset.
+ * The next push-buffer should produce buffers from the new @offset.
+ * This callback is only called for seekable stream types.
+ *
+ * A set of callbacks that can be installed on the appsrc with
+ * gst_app_src_set_callbacks().
+ *
+ * Since: 0.10.23
+ */
+typedef struct {
+ void (*need_data) (GstAppSrc *src, guint length, gpointer user_data);
+ void (*enough_data) (GstAppSrc *src, gpointer user_data);
+ gboolean (*seek_data) (GstAppSrc *src, guint64 offset, gpointer user_data);
+
+ /*< private >*/
+ gpointer _gst_reserved[GST_PADDING];
+} GstAppSrcCallbacks;
+
/**
* GstAppStreamType:
* @GST_APP_STREAM_TYPE_STREAM: No seeking is supported in the stream, such as a
void gst_app_src_set_latency (GstAppSrc *appsrc, guint64 min, guint64 max);
void gst_app_src_get_latency (GstAppSrc *appsrc, guint64 *min, guint64 *max);
+void gst_app_src_set_emit_signals (GstAppSrc *appsrc, gboolean emit);
+gboolean gst_app_src_get_emit_signals (GstAppSrc *appsrc);
+
GstFlowReturn gst_app_src_push_buffer (GstAppSrc *appsrc, GstBuffer *buffer);
GstFlowReturn gst_app_src_end_of_stream (GstAppSrc *appsrc);
+void gst_app_src_set_callbacks (GstAppSrc * appsrc,
+ GstAppSrcCallbacks *callbacks,
+ gpointer user_data,
+ GDestroyNotify notify);
+
G_END_DECLS
#endif