*
* #GstBaseSink provides support for exactly one sink pad, which should be
* named "sink". A sink implementation (subclass of #GstBaseSink) should
- * install a pad template in its base_init function, like so:
+ * install a pad template in its class_init function, like so:
* |[
* static void
- * my_element_base_init (gpointer g_class)
+ * my_element_class_init (GstMyElementClass *klass)
* {
- * GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
+ * GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
*
* // sinktemplate should be a #GstStaticPadTemplate with direction
* // #GST_PAD_SINK and name "sink"
* very specific elements (such as file sinks) which need to handle the
* newsegment event specially.
*
- * #GstBaseSink provides an overridable #GstBaseSinkClass.buffer_alloc()
- * function that can be used by sinks that want to do reverse negotiation or to
- * provide custom buffers (hardware buffers for example) to upstream elements.
- *
* The #GstBaseSinkClass.unlock() method is called when the elements should
* unblock any blocking operations they perform in the
* #GstBaseSinkClass.render() method. This is mostly useful when the
# include "config.h"
#endif
-/* FIXME 0.11: suppress warnings for deprecated API such as GStaticRecMutex
- * with newer GLib versions (>= 2.31.0) */
-#define GLIB_DISABLE_DEPRECATION_WARNINGS
#include <gst/gst_private.h>
#include "gstbasesink.h"
-#include <gst/gstmarshal.h>
#include <gst/gst-i18n-lib.h>
GST_DEBUG_CATEGORY_STATIC (gst_base_sink_debug);
gboolean need_preroll; /* if we need preroll after this step */
} GstStepInfo;
-/* FIXME, some stuff in ABI.data and other in Private...
- * Make up your mind please.
- */
struct _GstBaseSinkPrivate
{
gint qos_enabled; /* ATOMIC */
gboolean have_latency;
/* the last buffer we prerolled or rendered. Useful for making snapshots */
- gint enable_last_buffer; /* atomic */
+ gint enable_last_sample; /* atomic */
GstBuffer *last_buffer;
+ GstCaps *last_caps;
- /* caps for pull based scheduling */
- GstCaps *pull_caps;
+ /* negotiated caps */
+ GstCaps *caps;
/* blocksize for pulling */
guint blocksize;
#define UPDATE_RUNNING_AVG_P(avg,val) DO_RUNNING_AVG(avg,val,16)
#define UPDATE_RUNNING_AVG_N(avg,val) DO_RUNNING_AVG(avg,val,4)
-enum
-{
- _PR_IS_NOTHING = 1 << 0,
- _PR_IS_BUFFER = 1 << 1,
- _PR_IS_BUFFERLIST = 1 << 2,
- _PR_IS_EVENT = 1 << 3
-} PrivateObjectType;
-
-#define OBJ_IS_BUFFER(a) ((a) & _PR_IS_BUFFER)
-#define OBJ_IS_BUFFERLIST(a) ((a) & _PR_IS_BUFFERLIST)
-#define OBJ_IS_EVENT(a) ((a) & _PR_IS_EVENT)
-#define OBJ_IS_BUFFERFULL(a) ((a) & (_PR_IS_BUFFER | _PR_IS_BUFFERLIST))
-
/* BaseSink properties */
#define DEFAULT_CAN_ACTIVATE_PULL FALSE /* fixme: enable me */
#define DEFAULT_CAN_ACTIVATE_PUSH TRUE
-#define DEFAULT_PREROLL_QUEUE_LEN 0
#define DEFAULT_SYNC TRUE
#define DEFAULT_MAX_LATENESS -1
#define DEFAULT_QOS FALSE
#define DEFAULT_TS_OFFSET 0
#define DEFAULT_BLOCKSIZE 4096
#define DEFAULT_RENDER_DELAY 0
-#define DEFAULT_ENABLE_LAST_BUFFER TRUE
+#define DEFAULT_ENABLE_LAST_SAMPLE TRUE
#define DEFAULT_THROTTLE_TIME 0
enum
{
PROP_0,
- PROP_PREROLL_QUEUE_LEN,
PROP_SYNC,
PROP_MAX_LATENESS,
PROP_QOS,
PROP_ASYNC,
PROP_TS_OFFSET,
- PROP_ENABLE_LAST_BUFFER,
- PROP_LAST_BUFFER,
+ PROP_ENABLE_LAST_SAMPLE,
+ PROP_LAST_SAMPLE,
PROP_BLOCKSIZE,
PROP_RENDER_DELAY,
PROP_THROTTLE_TIME,
static gboolean gst_base_sink_send_event (GstElement * element,
GstEvent * event);
static gboolean default_element_query (GstElement * element, GstQuery * query);
-static const GstQueryType *gst_base_sink_get_query_types (GstElement * element);
-
-static GstCaps *gst_base_sink_get_caps (GstBaseSink * sink);
-static gboolean gst_base_sink_set_caps (GstBaseSink * sink, GstCaps * caps);
-static GstFlowReturn gst_base_sink_buffer_alloc (GstBaseSink * sink,
- guint64 offset, guint size, GstCaps * caps, GstBuffer ** buf);
-static void gst_base_sink_get_times (GstBaseSink * basesink, GstBuffer * buffer,
- GstClockTime * start, GstClockTime * end);
+
+static GstCaps *gst_base_sink_default_get_caps (GstBaseSink * sink,
+ GstCaps * caps);
+static gboolean gst_base_sink_default_set_caps (GstBaseSink * sink,
+ GstCaps * caps);
+static void gst_base_sink_default_get_times (GstBaseSink * basesink,
+ GstBuffer * buffer, GstClockTime * start, GstClockTime * end);
static gboolean gst_base_sink_set_flushing (GstBaseSink * basesink,
GstPad * pad, gboolean flushing);
static gboolean gst_base_sink_default_activate_pull (GstBaseSink * basesink,
static GstStateChangeReturn gst_base_sink_change_state (GstElement * element,
GstStateChange transition);
-static gboolean gst_base_sink_sink_query (GstPad * pad, GstQuery * query);
-static GstFlowReturn gst_base_sink_chain (GstPad * pad, GstBuffer * buffer);
-static GstFlowReturn gst_base_sink_chain_list (GstPad * pad,
+static gboolean gst_base_sink_sink_query (GstPad * pad, GstObject * parent,
+ GstQuery * query);
+static GstFlowReturn gst_base_sink_chain (GstPad * pad, GstObject * parent,
+ GstBuffer * buffer);
+static GstFlowReturn gst_base_sink_chain_list (GstPad * pad, GstObject * parent,
GstBufferList * list);
static void gst_base_sink_loop (GstPad * pad);
-static gboolean gst_base_sink_pad_activate (GstPad * pad);
-static gboolean gst_base_sink_pad_activate_push (GstPad * pad, gboolean active);
-static gboolean gst_base_sink_pad_activate_pull (GstPad * pad, gboolean active);
-static gboolean gst_base_sink_event (GstPad * pad, GstEvent * event);
+static gboolean gst_base_sink_pad_activate (GstPad * pad, GstObject * parent);
+static gboolean gst_base_sink_pad_activate_mode (GstPad * pad,
+ GstObject * parent, GstPadMode mode, gboolean active);
+static gboolean gst_base_sink_default_event (GstBaseSink * basesink,
+ GstEvent * event);
+static GstFlowReturn gst_base_sink_default_wait_eos (GstBaseSink * basesink,
+ GstEvent * event);
+static gboolean gst_base_sink_event (GstPad * pad, GstObject * parent,
+ GstEvent * event);
-static gboolean default_sink_query (GstBaseSink * sink, GstQuery * query);
+static gboolean gst_base_sink_default_query (GstBaseSink * sink,
+ GstQuery * query);
static gboolean gst_base_sink_negotiate_pull (GstBaseSink * basesink);
-static GstCaps *gst_base_sink_pad_getcaps (GstPad * pad);
-static gboolean gst_base_sink_pad_setcaps (GstPad * pad, GstCaps * caps);
-static void gst_base_sink_pad_fixate (GstPad * pad, GstCaps * caps);
-static GstFlowReturn gst_base_sink_pad_buffer_alloc (GstPad * pad,
- guint64 offset, guint size, GstCaps * caps, GstBuffer ** buf);
-
+static GstCaps *gst_base_sink_default_fixate (GstBaseSink * bsink,
+ GstCaps * caps);
+static GstCaps *gst_base_sink_fixate (GstBaseSink * bsink, GstCaps * caps);
/* check if an object was too late */
static gboolean gst_base_sink_is_too_late (GstBaseSink * basesink,
GstMiniObject * obj, GstClockTime rstart, GstClockTime rstop,
GstClockReturn status, GstClockTimeDiff jitter);
-static GstFlowReturn gst_base_sink_preroll_object (GstBaseSink * basesink,
- guint8 obj_type, GstMiniObject * obj);
static void
gst_base_sink_class_init (GstBaseSinkClass * klass)
gobject_class->set_property = gst_base_sink_set_property;
gobject_class->get_property = gst_base_sink_get_property;
- /* FIXME, this next value should be configured using an event from the
- * upstream element, ie, the BUFFER_SIZE event. */
- g_object_class_install_property (gobject_class, PROP_PREROLL_QUEUE_LEN,
- g_param_spec_uint ("preroll-queue-len", "Preroll queue length",
- "Number of buffers to queue during preroll", 0, G_MAXUINT,
- DEFAULT_PREROLL_QUEUE_LEN,
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
-
g_object_class_install_property (gobject_class, PROP_SYNC,
g_param_spec_boolean ("sync", "Sync", "Sync on the clock", DEFAULT_SYNC,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
DEFAULT_TS_OFFSET, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/**
- * GstBaseSink:enable-last-buffer
+ * GstBaseSink:enable-last-sample
*
- * Enable the last-buffer property. If FALSE, basesink doesn't keep a
- * reference to the last buffer arrived and the last-buffer property is always
+ * Enable the last-sample property. If FALSE, basesink doesn't keep a
+ * reference to the last buffer arrived and the last-sample property is always
* set to NULL. This can be useful if you need buffers to be released as soon
* as possible, eg. if you're using a buffer pool.
*
* Since: 0.10.30
*/
- g_object_class_install_property (gobject_class, PROP_ENABLE_LAST_BUFFER,
- g_param_spec_boolean ("enable-last-buffer", "Enable Last Buffer",
- "Enable the last-buffer property", DEFAULT_ENABLE_LAST_BUFFER,
+ g_object_class_install_property (gobject_class, PROP_ENABLE_LAST_SAMPLE,
+ g_param_spec_boolean ("enable-last-sample", "Enable Last Buffer",
+ "Enable the last-sample property", DEFAULT_ENABLE_LAST_SAMPLE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/**
- * GstBaseSink:last-buffer
+ * GstBaseSink:last-sample
*
* The last buffer that arrived in the sink and was used for preroll or for
* rendering. This property can be used to generate thumbnails. This property
*
* Since: 0.10.15
*/
- g_object_class_install_property (gobject_class, PROP_LAST_BUFFER,
- gst_param_spec_mini_object ("last-buffer", "Last Buffer",
- "The last buffer received in the sink", GST_TYPE_BUFFER,
+ g_object_class_install_property (gobject_class, PROP_LAST_SAMPLE,
+ g_param_spec_boxed ("last-sample", "Last Sample",
+ "The last sample received in the sink", GST_TYPE_SAMPLE,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
/**
* GstBaseSink:blocksize
*/
g_object_class_install_property (gobject_class, PROP_THROTTLE_TIME,
g_param_spec_uint64 ("throttle-time", "Throttle time",
- "The time to keep between rendered buffers (unused)", 0, G_MAXUINT64,
+ "The time to keep between rendered buffers", 0, G_MAXUINT64,
DEFAULT_THROTTLE_TIME, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
gstelement_class->change_state =
GST_DEBUG_FUNCPTR (gst_base_sink_change_state);
gstelement_class->send_event = GST_DEBUG_FUNCPTR (gst_base_sink_send_event);
gstelement_class->query = GST_DEBUG_FUNCPTR (default_element_query);
- gstelement_class->get_query_types =
- GST_DEBUG_FUNCPTR (gst_base_sink_get_query_types);
- klass->get_caps = GST_DEBUG_FUNCPTR (gst_base_sink_get_caps);
- klass->set_caps = GST_DEBUG_FUNCPTR (gst_base_sink_set_caps);
- klass->buffer_alloc = GST_DEBUG_FUNCPTR (gst_base_sink_buffer_alloc);
- klass->get_times = GST_DEBUG_FUNCPTR (gst_base_sink_get_times);
+ klass->get_caps = GST_DEBUG_FUNCPTR (gst_base_sink_default_get_caps);
+ klass->set_caps = GST_DEBUG_FUNCPTR (gst_base_sink_default_set_caps);
+ klass->fixate = GST_DEBUG_FUNCPTR (gst_base_sink_default_fixate);
klass->activate_pull =
GST_DEBUG_FUNCPTR (gst_base_sink_default_activate_pull);
- klass->query = GST_DEBUG_FUNCPTR (default_sink_query);
+ klass->get_times = GST_DEBUG_FUNCPTR (gst_base_sink_default_get_times);
+ klass->query = GST_DEBUG_FUNCPTR (gst_base_sink_default_query);
+ klass->event = GST_DEBUG_FUNCPTR (gst_base_sink_default_event);
+ klass->wait_eos = GST_DEBUG_FUNCPTR (gst_base_sink_default_wait_eos);
/* Registering debug symbols for function pointers */
- GST_DEBUG_REGISTER_FUNCPTR (gst_base_sink_pad_getcaps);
- GST_DEBUG_REGISTER_FUNCPTR (gst_base_sink_pad_setcaps);
- GST_DEBUG_REGISTER_FUNCPTR (gst_base_sink_pad_fixate);
- GST_DEBUG_REGISTER_FUNCPTR (gst_base_sink_pad_buffer_alloc);
+ GST_DEBUG_REGISTER_FUNCPTR (gst_base_sink_fixate);
GST_DEBUG_REGISTER_FUNCPTR (gst_base_sink_pad_activate);
- GST_DEBUG_REGISTER_FUNCPTR (gst_base_sink_pad_activate_push);
- GST_DEBUG_REGISTER_FUNCPTR (gst_base_sink_pad_activate_pull);
+ GST_DEBUG_REGISTER_FUNCPTR (gst_base_sink_pad_activate_mode);
GST_DEBUG_REGISTER_FUNCPTR (gst_base_sink_event);
GST_DEBUG_REGISTER_FUNCPTR (gst_base_sink_chain);
GST_DEBUG_REGISTER_FUNCPTR (gst_base_sink_chain_list);
}
static GstCaps *
-gst_base_sink_pad_getcaps (GstPad * pad)
+gst_base_sink_query_caps (GstBaseSink * bsink, GstPad * pad, GstCaps * filter)
{
GstBaseSinkClass *bclass;
- GstBaseSink *bsink;
GstCaps *caps = NULL;
+ gboolean fixed;
- bsink = GST_BASE_SINK (gst_pad_get_parent (pad));
bclass = GST_BASE_SINK_GET_CLASS (bsink);
+ fixed = GST_PAD_IS_FIXED_CAPS (pad);
- if (bsink->pad_mode == GST_ACTIVATE_PULL) {
- /* if we are operating in pull mode we only accept the negotiated caps */
- GST_OBJECT_LOCK (pad);
- if ((caps = GST_PAD_CAPS (pad)))
- gst_caps_ref (caps);
- GST_OBJECT_UNLOCK (pad);
+ if (fixed || bsink->pad_mode == GST_PAD_MODE_PULL) {
+ /* if we are operating in pull mode or fixed caps, we only accept the
+ * currently negotiated caps */
+ caps = gst_pad_get_current_caps (pad);
}
if (caps == NULL) {
if (bclass->get_caps)
- caps = bclass->get_caps (bsink);
+ caps = bclass->get_caps (bsink, filter);
if (caps == NULL) {
GstPadTemplate *pad_template;
gst_element_class_get_pad_template (GST_ELEMENT_CLASS (bclass),
"sink");
if (pad_template != NULL) {
- caps = gst_caps_ref (gst_pad_template_get_caps (pad_template));
+ caps = gst_pad_template_get_caps (pad_template);
+
+ if (filter) {
+ GstCaps *intersection;
+
+ intersection =
+ gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
+ gst_caps_unref (caps);
+ caps = intersection;
+ }
}
}
}
- gst_object_unref (bsink);
return caps;
}
-static gboolean
-gst_base_sink_pad_setcaps (GstPad * pad, GstCaps * caps)
+static GstCaps *
+gst_base_sink_default_fixate (GstBaseSink * bsink, GstCaps * caps)
{
- GstBaseSinkClass *bclass;
- GstBaseSink *bsink;
- gboolean res = TRUE;
-
- bsink = GST_BASE_SINK (gst_pad_get_parent (pad));
- bclass = GST_BASE_SINK_GET_CLASS (bsink);
-
- if (res && bclass->set_caps)
- res = bclass->set_caps (bsink, caps);
-
- gst_object_unref (bsink);
-
- return res;
+ GST_DEBUG_OBJECT (bsink, "using default caps fixate function");
+ return gst_caps_fixate (caps);
}
-static void
-gst_base_sink_pad_fixate (GstPad * pad, GstCaps * caps)
+static GstCaps *
+gst_base_sink_fixate (GstBaseSink * bsink, GstCaps * caps)
{
GstBaseSinkClass *bclass;
- GstBaseSink *bsink;
- bsink = GST_BASE_SINK (gst_pad_get_parent (pad));
bclass = GST_BASE_SINK_GET_CLASS (bsink);
if (bclass->fixate)
- bclass->fixate (bsink, caps);
-
- gst_object_unref (bsink);
-}
+ caps = bclass->fixate (bsink, caps);
-static GstFlowReturn
-gst_base_sink_pad_buffer_alloc (GstPad * pad, guint64 offset, guint size,
- GstCaps * caps, GstBuffer ** buf)
-{
- GstBaseSinkClass *bclass;
- GstBaseSink *bsink;
- GstFlowReturn result = GST_FLOW_OK;
-
- bsink = GST_BASE_SINK (gst_pad_get_parent (pad));
- if (G_UNLIKELY (bsink == NULL))
- return GST_FLOW_WRONG_STATE;
- bclass = GST_BASE_SINK_GET_CLASS (bsink);
-
- if (bclass->buffer_alloc)
- result = bclass->buffer_alloc (bsink, offset, size, caps, buf);
- else
- *buf = NULL; /* fallback in gstpad.c will allocate generic buffer */
-
- gst_object_unref (bsink);
-
- return result;
+ return caps;
}
static void
basesink->sinkpad = gst_pad_new_from_template (pad_template, "sink");
- gst_pad_set_getcaps_function (basesink->sinkpad, gst_base_sink_pad_getcaps);
- gst_pad_set_setcaps_function (basesink->sinkpad, gst_base_sink_pad_setcaps);
- gst_pad_set_fixatecaps_function (basesink->sinkpad, gst_base_sink_pad_fixate);
- gst_pad_set_bufferalloc_function (basesink->sinkpad,
- gst_base_sink_pad_buffer_alloc);
gst_pad_set_activate_function (basesink->sinkpad, gst_base_sink_pad_activate);
- gst_pad_set_activatepush_function (basesink->sinkpad,
- gst_base_sink_pad_activate_push);
- gst_pad_set_activatepull_function (basesink->sinkpad,
- gst_base_sink_pad_activate_pull);
+ gst_pad_set_activatemode_function (basesink->sinkpad,
+ gst_base_sink_pad_activate_mode);
gst_pad_set_query_function (basesink->sinkpad, gst_base_sink_sink_query);
gst_pad_set_event_function (basesink->sinkpad, gst_base_sink_event);
gst_pad_set_chain_function (basesink->sinkpad, gst_base_sink_chain);
gst_pad_set_chain_list_function (basesink->sinkpad, gst_base_sink_chain_list);
gst_element_add_pad (GST_ELEMENT_CAST (basesink), basesink->sinkpad);
- basesink->pad_mode = GST_ACTIVATE_NONE;
- basesink->preroll_queue = g_queue_new ();
- basesink->abidata.ABI.clip_segment = gst_segment_new ();
+ basesink->pad_mode = GST_PAD_MODE_NONE;
+ g_mutex_init (&basesink->preroll_lock);
+ g_cond_init (&basesink->preroll_cond);
priv->have_latency = FALSE;
basesink->can_activate_push = DEFAULT_CAN_ACTIVATE_PUSH;
basesink->can_activate_pull = DEFAULT_CAN_ACTIVATE_PULL;
basesink->sync = DEFAULT_SYNC;
- basesink->abidata.ABI.max_lateness = DEFAULT_MAX_LATENESS;
+ basesink->max_lateness = DEFAULT_MAX_LATENESS;
g_atomic_int_set (&priv->qos_enabled, DEFAULT_QOS);
priv->async_enabled = DEFAULT_ASYNC;
priv->ts_offset = DEFAULT_TS_OFFSET;
priv->render_delay = DEFAULT_RENDER_DELAY;
priv->blocksize = DEFAULT_BLOCKSIZE;
priv->cached_clock_id = NULL;
- g_atomic_int_set (&priv->enable_last_buffer, DEFAULT_ENABLE_LAST_BUFFER);
+ g_atomic_int_set (&priv->enable_last_sample, DEFAULT_ENABLE_LAST_SAMPLE);
priv->throttle_time = DEFAULT_THROTTLE_TIME;
- GST_OBJECT_FLAG_SET (basesink, GST_ELEMENT_IS_SINK);
+ GST_OBJECT_FLAG_SET (basesink, GST_ELEMENT_FLAG_SINK);
}
static void
basesink = GST_BASE_SINK (object);
- g_queue_free (basesink->preroll_queue);
- gst_segment_free (basesink->abidata.ABI.clip_segment);
+ g_mutex_clear (&basesink->preroll_lock);
+ g_cond_clear (&basesink->preroll_cond);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
g_return_if_fail (GST_IS_BASE_SINK (sink));
GST_OBJECT_LOCK (sink);
- sink->abidata.ABI.max_lateness = max_lateness;
+ sink->max_lateness = max_lateness;
GST_OBJECT_UNLOCK (sink);
}
g_return_val_if_fail (GST_IS_BASE_SINK (sink), -1);
GST_OBJECT_LOCK (sink);
- res = sink->abidata.ABI.max_lateness;
+ res = sink->max_lateness;
GST_OBJECT_UNLOCK (sink);
return res;
{
g_return_if_fail (GST_IS_BASE_SINK (sink));
- GST_PAD_PREROLL_LOCK (sink->sinkpad);
+ GST_BASE_SINK_PREROLL_LOCK (sink);
g_atomic_int_set (&sink->priv->async_enabled, enabled);
GST_LOG_OBJECT (sink, "set async enabled to %d", enabled);
- GST_PAD_PREROLL_UNLOCK (sink->sinkpad);
+ GST_BASE_SINK_PREROLL_UNLOCK (sink);
}
/**
}
/**
- * gst_base_sink_get_last_buffer:
+ * gst_base_sink_get_last_sample:
* @sink: the sink
*
- * Get the last buffer that arrived in the sink and was used for preroll or for
+ * Get the last sample that arrived in the sink and was used for preroll or for
* rendering. This property can be used to generate thumbnails.
*
- * The #GstCaps on the buffer can be used to determine the type of the buffer.
+ * The #GstCaps on the sample can be used to determine the type of the buffer.
*
- * Free-function: gst_buffer_unref
+ * Free-function: gst_sample_unref
*
- * Returns: (transfer full): a #GstBuffer. gst_buffer_unref() after usage.
+ * Returns: (transfer full): a #GstSample. gst_sample_unref() after usage.
* This function returns NULL when no buffer has arrived in the sink yet
* or when the sink is not in PAUSED or PLAYING.
*
* Since: 0.10.15
*/
-GstBuffer *
-gst_base_sink_get_last_buffer (GstBaseSink * sink)
+GstSample *
+gst_base_sink_get_last_sample (GstBaseSink * sink)
{
- GstBuffer *res;
+ GstSample *res = NULL;
g_return_val_if_fail (GST_IS_BASE_SINK (sink), NULL);
GST_OBJECT_LOCK (sink);
- if ((res = sink->priv->last_buffer))
- gst_buffer_ref (res);
+ if (sink->priv->last_buffer) {
+ res = gst_sample_new (sink->priv->last_buffer,
+ sink->priv->last_caps, &sink->segment, NULL);
+ }
GST_OBJECT_UNLOCK (sink);
return res;
if (G_LIKELY (buffer))
gst_buffer_ref (buffer);
sink->priv->last_buffer = buffer;
+ if (buffer)
+ /* copy over the caps */
+ gst_caps_replace (&sink->priv->last_caps, sink->priv->caps);
+ else
+ gst_caps_replace (&sink->priv->last_caps, NULL);
} else {
old = NULL;
}
static void
gst_base_sink_set_last_buffer (GstBaseSink * sink, GstBuffer * buffer)
{
- if (!g_atomic_int_get (&sink->priv->enable_last_buffer))
+ if (!g_atomic_int_get (&sink->priv->enable_last_sample))
return;
GST_OBJECT_LOCK (sink);
}
/**
- * gst_base_sink_set_last_buffer_enabled:
+ * gst_base_sink_set_last_sample_enabled:
* @sink: the sink
- * @enabled: the new enable-last-buffer value.
+ * @enabled: the new enable-last-sample value.
*
- * Configures @sink to store the last received buffer in the last-buffer
+ * Configures @sink to store the last received sample in the last-sample
* property.
*
* Since: 0.10.30
*/
void
-gst_base_sink_set_last_buffer_enabled (GstBaseSink * sink, gboolean enabled)
+gst_base_sink_set_last_sample_enabled (GstBaseSink * sink, gboolean enabled)
{
g_return_if_fail (GST_IS_BASE_SINK (sink));
/* Only take lock if we change the value */
- if (g_atomic_int_compare_and_exchange (&sink->priv->enable_last_buffer,
+ if (g_atomic_int_compare_and_exchange (&sink->priv->enable_last_sample,
!enabled, enabled) && !enabled) {
GST_OBJECT_LOCK (sink);
gst_base_sink_set_last_buffer_unlocked (sink, NULL);
}
/**
- * gst_base_sink_is_last_buffer_enabled:
+ * gst_base_sink_is_last_sample_enabled:
* @sink: the sink
*
- * Checks if @sink is currently configured to store the last received buffer in
- * the last-buffer property.
+ * Checks if @sink is currently configured to store the last received sample in
+ * the last-sample property.
*
- * Returns: TRUE if the sink is configured to store the last received buffer.
+ * Returns: TRUE if the sink is configured to store the last received sample.
*
* Since: 0.10.30
*/
gboolean
-gst_base_sink_is_last_buffer_enabled (GstBaseSink * sink)
+gst_base_sink_is_last_sample_enabled (GstBaseSink * sink)
{
g_return_val_if_fail (GST_IS_BASE_SINK (sink), FALSE);
- return g_atomic_int_get (&sink->priv->enable_last_buffer);
+ return g_atomic_int_get (&sink->priv->enable_last_sample);
}
/**
GstBaseSink *sink = GST_BASE_SINK (object);
switch (prop_id) {
- case PROP_PREROLL_QUEUE_LEN:
- /* preroll lock necessary to serialize with finish_preroll */
- GST_PAD_PREROLL_LOCK (sink->sinkpad);
- g_atomic_int_set (&sink->preroll_queue_max_len, g_value_get_uint (value));
- GST_PAD_PREROLL_UNLOCK (sink->sinkpad);
- break;
case PROP_SYNC:
gst_base_sink_set_sync (sink, g_value_get_boolean (value));
break;
case PROP_RENDER_DELAY:
gst_base_sink_set_render_delay (sink, g_value_get_uint64 (value));
break;
- case PROP_ENABLE_LAST_BUFFER:
- gst_base_sink_set_last_buffer_enabled (sink, g_value_get_boolean (value));
+ case PROP_ENABLE_LAST_SAMPLE:
+ gst_base_sink_set_last_sample_enabled (sink, g_value_get_boolean (value));
break;
case PROP_THROTTLE_TIME:
gst_base_sink_set_throttle_time (sink, g_value_get_uint64 (value));
GstBaseSink *sink = GST_BASE_SINK (object);
switch (prop_id) {
- case PROP_PREROLL_QUEUE_LEN:
- g_value_set_uint (value, g_atomic_int_get (&sink->preroll_queue_max_len));
- break;
case PROP_SYNC:
g_value_set_boolean (value, gst_base_sink_get_sync (sink));
break;
case PROP_TS_OFFSET:
g_value_set_int64 (value, gst_base_sink_get_ts_offset (sink));
break;
- case PROP_LAST_BUFFER:
- gst_value_take_buffer (value, gst_base_sink_get_last_buffer (sink));
+ case PROP_LAST_SAMPLE:
+ gst_value_take_buffer (value, gst_base_sink_get_last_sample (sink));
break;
- case PROP_ENABLE_LAST_BUFFER:
- g_value_set_boolean (value, gst_base_sink_is_last_buffer_enabled (sink));
+ case PROP_ENABLE_LAST_SAMPLE:
+ g_value_set_boolean (value, gst_base_sink_is_last_sample_enabled (sink));
break;
case PROP_BLOCKSIZE:
g_value_set_uint (value, gst_base_sink_get_blocksize (sink));
static GstCaps *
-gst_base_sink_get_caps (GstBaseSink * sink)
+gst_base_sink_default_get_caps (GstBaseSink * sink, GstCaps * filter)
{
return NULL;
}
static gboolean
-gst_base_sink_set_caps (GstBaseSink * sink, GstCaps * caps)
+gst_base_sink_default_set_caps (GstBaseSink * sink, GstCaps * caps)
{
return TRUE;
}
-static GstFlowReturn
-gst_base_sink_buffer_alloc (GstBaseSink * sink, guint64 offset, guint size,
- GstCaps * caps, GstBuffer ** buf)
-{
- *buf = NULL;
- return GST_FLOW_OK;
-}
-
-/* with PREROLL_LOCK, STREAM_LOCK */
-static void
-gst_base_sink_preroll_queue_flush (GstBaseSink * basesink, GstPad * pad)
-{
- GstMiniObject *obj;
-
- GST_DEBUG_OBJECT (basesink, "flushing queue %p", basesink);
- while ((obj = g_queue_pop_head (basesink->preroll_queue))) {
- GST_DEBUG_OBJECT (basesink, "popped %p", obj);
- gst_mini_object_unref (obj);
- }
- /* we can't have EOS anymore now */
- basesink->eos = FALSE;
- basesink->priv->received_eos = FALSE;
- basesink->have_preroll = FALSE;
- basesink->priv->step_unlock = FALSE;
- basesink->eos_queued = FALSE;
- basesink->preroll_queued = 0;
- basesink->buffers_queued = 0;
- basesink->events_queued = 0;
- /* can't report latency anymore until we preroll again */
- if (basesink->priv->async_enabled) {
- GST_OBJECT_LOCK (basesink);
- basesink->priv->have_latency = FALSE;
- GST_OBJECT_UNLOCK (basesink);
- }
- /* and signal any waiters now */
- GST_PAD_PREROLL_SIGNAL (pad);
-}
-
-/* with STREAM_LOCK, configures given segment with the event information. */
-static void
-gst_base_sink_configure_segment (GstBaseSink * basesink, GstPad * pad,
- GstEvent * event, GstSegment * segment)
-{
- gboolean update;
- gdouble rate, arate;
- GstFormat format;
- gint64 start;
- gint64 stop;
- gint64 time;
-
- /* the newsegment event is needed to bring the buffer timestamps to the
- * stream time and to drop samples outside of the playback segment. */
- gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format,
- &start, &stop, &time);
-
- /* The segment is protected with both the STREAM_LOCK and the OBJECT_LOCK.
- * We protect with the OBJECT_LOCK so that we can use the values to
- * safely answer a POSITION query. */
- GST_OBJECT_LOCK (basesink);
- gst_segment_set_newsegment_full (segment, update, rate, arate, format, start,
- stop, time);
-
- if (format == GST_FORMAT_TIME) {
- GST_DEBUG_OBJECT (basesink,
- "configured NEWSEGMENT update %d, rate %lf, applied rate %lf, "
- "format GST_FORMAT_TIME, "
- "%" GST_TIME_FORMAT " -- %" GST_TIME_FORMAT
- ", time %" GST_TIME_FORMAT ", accum %" GST_TIME_FORMAT,
- update, rate, arate, GST_TIME_ARGS (segment->start),
- GST_TIME_ARGS (segment->stop), GST_TIME_ARGS (segment->time),
- GST_TIME_ARGS (segment->accum));
- } else {
- GST_DEBUG_OBJECT (basesink,
- "configured NEWSEGMENT update %d, rate %lf, applied rate %lf, "
- "format %d, "
- "%" G_GINT64_FORMAT " -- %" G_GINT64_FORMAT ", time %"
- G_GINT64_FORMAT ", accum %" G_GINT64_FORMAT, update, rate, arate,
- segment->format, segment->start, segment->stop, segment->time,
- segment->accum);
- }
- GST_OBJECT_UNLOCK (basesink);
-}
-
/* with PREROLL_LOCK, STREAM_LOCK */
static gboolean
gst_base_sink_commit_state (GstBaseSink * basesink)
switch (pending) {
case GST_STATE_PLAYING:
{
- GstBaseSinkClass *bclass;
- GstStateChangeReturn ret;
-
- bclass = GST_BASE_SINK_GET_CLASS (basesink);
-
GST_DEBUG_OBJECT (basesink, "commiting state to PLAYING");
basesink->need_preroll = FALSE;
if (current == GST_STATE_READY) {
post_paused = TRUE;
}
-
- /* make sure we notify the subclass of async playing */
- if (bclass->async_play) {
- GST_WARNING_OBJECT (basesink, "deprecated async_play");
- ret = bclass->async_play (basesink);
- if (ret == GST_STATE_CHANGE_FAILURE)
- goto async_failed;
- }
break;
}
case GST_STATE_PAUSED:
if (post_async_done) {
GST_DEBUG_OBJECT (basesink, "posting async-done message");
gst_element_post_message (GST_ELEMENT_CAST (basesink),
- gst_message_new_async_done (GST_OBJECT_CAST (basesink)));
+ gst_message_new_async_done (GST_OBJECT_CAST (basesink), FALSE));
}
if (post_playing) {
GST_DEBUG_OBJECT (basesink, "posting PLAYING state change message");
GST_OBJECT_UNLOCK (basesink);
return FALSE;
}
-async_failed:
- {
- GST_DEBUG_OBJECT (basesink, "async commit failed");
- GST_STATE_RETURN (basesink) = GST_STATE_CHANGE_FAILURE;
- GST_OBJECT_UNLOCK (basesink);
- return FALSE;
- }
}
static void
/* set the new rate for the remainder of the segment */
current->start_rate = segment->rate;
segment->rate *= current->rate;
- segment->abs_rate = ABS (segment->rate);
/* save values */
if (segment->rate > 0.0)
/* update the segment clipping regions for non-flushing seeks */
if (segment->rate > 0.0) {
segment->stop = gst_segment_to_position (segment, GST_FORMAT_TIME, end);
- segment->last_stop = segment->stop;
+ segment->position = segment->stop;
} else {
gint64 position;
position = gst_segment_to_position (segment, GST_FORMAT_TIME, end);
segment->time = position;
segment->start = position;
- segment->last_stop = position;
+ segment->position = position;
}
}
}
- GST_DEBUG_OBJECT (sink,
- "segment now rate %lf, applied rate %lf, "
- "format GST_FORMAT_TIME, "
- "%" GST_TIME_FORMAT " -- %" GST_TIME_FORMAT
- ", time %" GST_TIME_FORMAT ", accum %" GST_TIME_FORMAT,
- segment->rate, segment->applied_rate, GST_TIME_ARGS (segment->start),
- GST_TIME_ARGS (segment->stop), GST_TIME_ARGS (segment->time),
- GST_TIME_ARGS (segment->accum));
-
+ GST_DEBUG_OBJECT (sink, "segment now %" GST_SEGMENT_FORMAT, segment);
GST_DEBUG_OBJECT (sink, "step started at running_time %" GST_TIME_FORMAT,
GST_TIME_ARGS (current->start));
gst_segment_set_running_time (segment, GST_FORMAT_TIME, position);
if (current->flush) {
- /* and remove the accumulated time we flushed, start time did not change */
- segment->accum = current->start;
+ /* and remove the time we flushed, start time did not change */
+ segment->base = current->start;
} else {
/* start time is now the stepped position */
gst_element_set_start_time (GST_ELEMENT_CAST (sink), position);
/* restore the previous rate */
segment->rate = current->start_rate;
- segment->abs_rate = ABS (segment->rate);
if (segment->rate > 0.0)
segment->stop = current->start_stop;
else
segment->start = current->start_start;
- /* the clip segment is used for position report in paused... */
- memcpy (sink->abidata.ABI.clip_segment, segment, sizeof (GstSegment));
-
/* post the step done when we know the stepped duration in TIME */
message =
gst_message_new_step_done (GST_OBJECT_CAST (sink), current->format,
static gboolean
handle_stepping (GstBaseSink * sink, GstSegment * segment,
- GstStepInfo * current, gint64 * cstart, gint64 * cstop, gint64 * rstart,
- gint64 * rstop)
+ GstStepInfo * current, guint64 * cstart, guint64 * cstop, guint64 * rstart,
+ guint64 * rstop)
{
gboolean step_end = FALSE;
case GST_FORMAT_TIME:
{
guint64 end;
- gint64 first, last;
+ guint64 first, last;
+ gdouble abs_rate;
if (segment->rate > 0.0) {
if (segment->stop == *cstop)
end = current->start + current->amount;
current->position = first - current->start;
- if (G_UNLIKELY (segment->abs_rate != 1.0))
- current->position /= segment->abs_rate;
+ abs_rate = ABS (segment->rate);
+ if (G_UNLIKELY (abs_rate != 1.0))
+ current->position /= abs_rate;
GST_DEBUG_OBJECT (sink,
"buffer: %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
gst_base_sink_get_sync_times (GstBaseSink * basesink, GstMiniObject * obj,
GstClockTime * rsstart, GstClockTime * rsstop,
GstClockTime * rrstart, GstClockTime * rrstop, gboolean * do_sync,
- gboolean * stepped, GstSegment * segment, GstStepInfo * step,
- gboolean * step_end, guint8 obj_type)
+ gboolean * stepped, GstStepInfo * step, gboolean * step_end)
{
GstBaseSinkClass *bclass;
GstBuffer *buffer;
GstClockTime start, stop; /* raw start/stop timestamps */
- gint64 cstart, cstop; /* clipped raw timestamps */
- gint64 rstart, rstop; /* clipped timestamps converted to running time */
+ guint64 cstart, cstop; /* clipped raw timestamps */
+ guint64 rstart, rstop; /* clipped timestamps converted to running time */
GstClockTime sstart, sstop; /* clipped timestamps converted to stream time */
GstFormat format;
GstBaseSinkPrivate *priv;
+ GstSegment *segment;
gboolean eos;
priv = basesink->priv;
+ segment = &basesink->segment;
/* start with nothing */
start = stop = GST_CLOCK_TIME_NONE;
- if (G_UNLIKELY (OBJ_IS_EVENT (obj_type))) {
+ if (G_UNLIKELY (GST_IS_EVENT (obj))) {
GstEvent *event = GST_EVENT_CAST (obj);
switch (GST_EVENT_TYPE (event)) {
/* EOS event needs syncing */
case GST_EVENT_EOS:
{
- if (basesink->segment.rate >= 0.0) {
+ if (segment->rate >= 0.0) {
sstart = sstop = priv->current_sstop;
if (!GST_CLOCK_TIME_IS_VALID (sstart)) {
/* we have not seen a buffer yet, use the segment values */
- sstart = sstop = gst_segment_to_stream_time (&basesink->segment,
- basesink->segment.format, basesink->segment.stop);
+ sstart = sstop = gst_segment_to_stream_time (segment,
+ segment->format, segment->stop);
}
} else {
sstart = sstop = priv->current_sstart;
if (!GST_CLOCK_TIME_IS_VALID (sstart)) {
/* we have not seen a buffer yet, use the segment values */
- sstart = sstop = gst_segment_to_stream_time (&basesink->segment,
- basesink->segment.format, basesink->segment.start);
+ sstart = sstop = gst_segment_to_stream_time (segment,
+ segment->format, segment->start);
}
}
}
default:
/* other events do not need syncing */
- /* FIXME, maybe NEWSEGMENT might need synchronisation
- * since the POSITION query depends on accumulated times and
- * we cannot accumulate the current segment before the previous
- * one completed.
- */
return FALSE;
}
}
if (!GST_CLOCK_TIME_IS_VALID (start)) {
/* we don't need to sync but we still want to get the timestamps for
* tracking the position */
- gst_base_sink_get_times (basesink, buffer, &start, &stop);
+ gst_base_sink_default_get_times (basesink, buffer, &start, &stop);
*do_sync = FALSE;
} else {
*do_sync = TRUE;
/* collect segment and format for code clarity */
format = segment->format;
- /* no timestamp clipping if we did not get a TIME segment format */
- if (G_UNLIKELY (format != GST_FORMAT_TIME)) {
- cstart = start;
- cstop = stop;
- /* do running and stream time in TIME format */
- format = GST_FORMAT_TIME;
- GST_LOG_OBJECT (basesink, "not time format, don't clip");
- goto do_times;
- }
-
- /* clip, only when we know about time */
- if (G_UNLIKELY (!gst_segment_clip (segment, GST_FORMAT_TIME,
- (gint64) start, (gint64) stop, &cstart, &cstop))) {
+ /* clip */
+ if (G_UNLIKELY (!gst_segment_clip (segment, format,
+ start, stop, &cstart, &cstop))) {
if (step->valid) {
GST_DEBUG_OBJECT (basesink, "step out of segment");
/* when we are stepping, pretend we're at the end of the segment */
/* set last stop position */
if (G_LIKELY (stop != GST_CLOCK_TIME_NONE && cstop != GST_CLOCK_TIME_NONE))
- gst_segment_set_last_stop (segment, GST_FORMAT_TIME, cstop);
+ segment->position = cstop;
else
- gst_segment_set_last_stop (segment, GST_FORMAT_TIME, cstart);
+ segment->position = cstart;
do_times:
rstart = gst_segment_to_running_time (segment, format, cstart);
* entry. */
sink->clock_id = sink->priv->cached_clock_id;
/* release the preroll lock while waiting */
- GST_PAD_PREROLL_UNLOCK (sink->sinkpad);
+ GST_BASE_SINK_PREROLL_UNLOCK (sink);
ret = gst_clock_id_wait (sink->priv->cached_clock_id, jitter);
- GST_PAD_PREROLL_LOCK (sink->sinkpad);
+ GST_BASE_SINK_PREROLL_LOCK (sink);
sink->clock_id = NULL;
return ret;
* This function will block until a state change to PLAYING happens (in which
* case this function returns #GST_FLOW_OK) or the processing must be stopped due
* to a state change to READY or a FLUSH event (in which case this function
- * returns #GST_FLOW_WRONG_STATE).
+ * returns #GST_FLOW_FLUSHING).
*
* This function should only be called with the PREROLL_LOCK held, like in the
* render function.
sink->have_preroll = TRUE;
GST_DEBUG_OBJECT (sink, "waiting in preroll for flush or PLAYING");
/* block until the state changes, or we get a flush, or something */
- GST_PAD_PREROLL_WAIT (sink->sinkpad);
+ GST_BASE_SINK_PREROLL_WAIT (sink);
sink->have_preroll = FALSE;
if (G_UNLIKELY (sink->flushing))
goto stopping;
stopping:
{
GST_DEBUG_OBJECT (sink, "preroll interrupted because of flush");
- return GST_FLOW_WRONG_STATE;
+ return GST_FLOW_FLUSHING;
}
step_unlocked:
{
}
}
-static inline guint8
-get_object_type (GstMiniObject * obj)
-{
- guint8 obj_type;
-
- if (G_LIKELY (GST_IS_BUFFER (obj)))
- obj_type = _PR_IS_BUFFER;
- else if (GST_IS_EVENT (obj))
- obj_type = _PR_IS_EVENT;
- else if (GST_IS_BUFFER_LIST (obj))
- obj_type = _PR_IS_BUFFERLIST;
- else
- obj_type = _PR_IS_NOTHING;
-
- return obj_type;
-}
-
/**
* gst_base_sink_do_preroll:
* @sink: the sink
GstFlowReturn ret;
while (G_UNLIKELY (sink->need_preroll)) {
- guint8 obj_type;
GST_DEBUG_OBJECT (sink, "prerolling object %p", obj);
- obj_type = get_object_type (obj);
+ /* if it's a buffer, we need to call the preroll method */
+ if (sink->priv->call_preroll) {
+ GstBaseSinkClass *bclass;
+ GstBuffer *buf;
+
+ if (GST_IS_BUFFER_LIST (obj)) {
+ buf = gst_buffer_list_get (GST_BUFFER_LIST_CAST (obj), 0);
+ g_assert (NULL != buf);
+ } else if (GST_IS_BUFFER (obj)) {
+ buf = GST_BUFFER_CAST (obj);
+ /* For buffer lists do not set last buffer for now */
+ gst_base_sink_set_last_buffer (sink, buf);
+ } else
+ buf = NULL;
+
+ if (buf) {
+ GST_DEBUG_OBJECT (sink, "preroll buffer %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));
+
+ bclass = GST_BASE_SINK_GET_CLASS (sink);
+
+ if (bclass->prepare)
+ if ((ret = bclass->prepare (sink, buf)) != GST_FLOW_OK)
+ goto prepare_canceled;
+
+ if (bclass->preroll)
+ if ((ret = bclass->preroll (sink, buf)) != GST_FLOW_OK)
+ goto preroll_canceled;
+
+ sink->priv->call_preroll = FALSE;
+ }
+ }
- ret = gst_base_sink_preroll_object (sink, obj_type, obj);
- if (ret != GST_FLOW_OK)
- goto preroll_failed;
+ /* commit state */
+ if (G_LIKELY (sink->playing_async)) {
+ if (G_UNLIKELY (!gst_base_sink_commit_state (sink)))
+ goto stopping;
+ }
/* need to recheck here because the commit state could have
* made us not need the preroll anymore */
return GST_FLOW_OK;
/* ERRORS */
+prepare_canceled:
+ {
+ GST_DEBUG_OBJECT (sink, "prepare failed, abort state");
+ gst_element_abort_state (GST_ELEMENT_CAST (sink));
+ return ret;
+ }
+preroll_canceled:
+ {
+ GST_DEBUG_OBJECT (sink, "preroll failed, abort state");
+ gst_element_abort_state (GST_ELEMENT_CAST (sink));
+ return ret;
+ }
+stopping:
+ {
+ GST_DEBUG_OBJECT (sink, "stopping while commiting state");
+ return GST_FLOW_FLUSHING;
+ }
preroll_failed:
{
GST_DEBUG_OBJECT (sink, "preroll failed: %s", gst_flow_get_name (ret));
GST_DEBUG_OBJECT (sink, "possibly waiting for clock to reach %"
GST_TIME_FORMAT, GST_TIME_ARGS (time));
- /* compensate for latency and ts_offset. We don't adjust for render delay
- * because we don't interact with the device on EOS normally. */
+ /* compensate for latency, ts_offset and render delay */
stime = gst_base_sink_adjust_time (sink, time);
/* wait for the clock, this can be interrupted because we got shut down or
flushing:
{
GST_DEBUG_OBJECT (sink, "we are flushing");
- return GST_FLOW_WRONG_STATE;
+ return GST_FLOW_FLUSHING;
}
}
* does not take ownership of obj.
*/
static GstFlowReturn
-gst_base_sink_do_sync (GstBaseSink * basesink, GstPad * pad,
- GstMiniObject * obj, gboolean * late, gboolean * step_end, guint8 obj_type)
+gst_base_sink_do_sync (GstBaseSink * basesink,
+ GstMiniObject * obj, gboolean * late, gboolean * step_end)
{
GstClockTimeDiff jitter = 0;
gboolean syncable;
/* get timing information for this object against the render segment */
syncable = gst_base_sink_get_sync_times (basesink, obj,
- &sstart, &sstop, &rstart, &rstop, &do_sync, &stepped, &basesink->segment,
- current, step_end, obj_type);
+ &sstart, &sstop, &rstart, &rstop, &do_sync, &stepped, current, step_end);
if (G_UNLIKELY (stepped))
goto step_skipped;
/* adjust for latency */
stime = gst_base_sink_adjust_time (basesink, rstart);
- /* adjust for render-delay, avoid underflows */
- if (GST_CLOCK_TIME_IS_VALID (stime)) {
- if (stime > priv->render_delay)
- stime -= priv->render_delay;
- else
- stime = 0;
- }
-
/* preroll done, we can sync since we are in PLAYING now. */
GST_DEBUG_OBJECT (basesink, "possibly waiting for clock to reach %"
GST_TIME_FORMAT ", adjusted %" GST_TIME_FORMAT,
flushing:
{
GST_DEBUG_OBJECT (basesink, "we are flushing");
- return GST_FLOW_WRONG_STATE;
+ return GST_FLOW_FLUSHING;
}
preroll_failed:
{
"qos: type %d, proportion: %lf, diff %" G_GINT64_FORMAT ", timestamp %"
GST_TIME_FORMAT, type, proportion, diff, GST_TIME_ARGS (time));
- event = gst_event_new_qos_full (type, proportion, diff, time);
+ event = gst_event_new_qos (type, proportion, diff, time);
/* send upstream */
res = gst_pad_push_event (basesink->sinkpad, event);
GstClockReturn status, GstClockTimeDiff jitter)
{
gboolean late;
- gint64 max_lateness;
+ guint64 max_lateness;
GstBaseSinkPrivate *priv;
priv = basesink->priv;
if (G_LIKELY (status != GST_CLOCK_EARLY))
goto in_time;
- max_lateness = basesink->abidata.ABI.max_lateness;
+ max_lateness = basesink->max_lateness;
/* check if frame dropping is enabled */
if (max_lateness == -1)
}
}
-/* with STREAM_LOCK, PREROLL_LOCK,
- *
- * Synchronize the object on the clock and then render it.
- *
- * takes ownership of obj.
- */
-static GstFlowReturn
-gst_base_sink_render_object (GstBaseSink * basesink, GstPad * pad,
- guint8 obj_type, gpointer obj)
+static void
+gst_base_sink_flush_start (GstBaseSink * basesink, GstPad * pad)
{
- GstFlowReturn ret;
- GstBaseSinkClass *bclass;
- gboolean late, step_end;
- gpointer sync_obj;
- GstBaseSinkPrivate *priv;
-
- priv = basesink->priv;
+ /* make sure we are not blocked on the clock also clear any pending
+ * eos state. */
+ gst_base_sink_set_flushing (basesink, pad, TRUE);
- if (OBJ_IS_BUFFERLIST (obj_type)) {
- /*
- * If buffer list, use the first group buffer within the list
- * for syncing
- */
- sync_obj = gst_buffer_list_get (GST_BUFFER_LIST_CAST (obj), 0, 0);
- g_assert (NULL != sync_obj);
+ /* we grab the stream lock but that is not needed since setting the
+ * sink to flushing would make sure no state commit is being done
+ * anymore */
+ GST_PAD_STREAM_LOCK (pad);
+ gst_base_sink_reset_qos (basesink);
+ /* and we need to commit our state again on the next
+ * prerolled buffer */
+ basesink->playing_async = TRUE;
+ if (basesink->priv->async_enabled) {
+ gst_element_lost_state (GST_ELEMENT_CAST (basesink));
} else {
- sync_obj = obj;
+ /* start time reset in above case as well;
+ * arranges for a.o. proper position reporting when flushing in PAUSED */
+ gst_element_set_start_time (GST_ELEMENT_CAST (basesink), 0);
+ basesink->priv->have_latency = TRUE;
}
+ gst_base_sink_set_last_buffer (basesink, NULL);
+ GST_PAD_STREAM_UNLOCK (pad);
+}
-again:
- late = FALSE;
- step_end = FALSE;
+static void
+gst_base_sink_flush_stop (GstBaseSink * basesink, GstPad * pad,
+ gboolean reset_time)
+{
+ /* unset flushing so we can accept new data, this also flushes out any EOS
+ * event. */
+ gst_base_sink_set_flushing (basesink, pad, FALSE);
- /* synchronize this object, non syncable objects return OK
- * immediately. */
- ret =
- gst_base_sink_do_sync (basesink, pad, sync_obj, &late, &step_end,
- obj_type);
- if (G_UNLIKELY (ret != GST_FLOW_OK))
- goto sync_failed;
+ /* for position reporting */
+ GST_OBJECT_LOCK (basesink);
+ basesink->priv->current_sstart = GST_CLOCK_TIME_NONE;
+ basesink->priv->current_sstop = GST_CLOCK_TIME_NONE;
+ basesink->priv->eos_rtime = GST_CLOCK_TIME_NONE;
+ basesink->priv->call_preroll = TRUE;
+ basesink->priv->current_step.valid = FALSE;
+ basesink->priv->pending_step.valid = FALSE;
+ if (basesink->pad_mode == GST_PAD_MODE_PUSH) {
+ /* we need new segment info after the flush. */
+ basesink->have_newsegment = FALSE;
+ if (reset_time) {
+ gst_segment_init (&basesink->segment, GST_FORMAT_UNDEFINED);
+ }
+ }
+ GST_OBJECT_UNLOCK (basesink);
- /* and now render, event or buffer/buffer list. */
- if (G_LIKELY (OBJ_IS_BUFFERFULL (obj_type))) {
- /* drop late buffers unconditionally, let's hope it's unlikely */
- if (G_UNLIKELY (late))
- goto dropped;
+ if (reset_time) {
+ GST_DEBUG_OBJECT (basesink, "posting reset-time message");
+ gst_element_post_message (GST_ELEMENT_CAST (basesink),
+ gst_message_new_reset_time (GST_OBJECT_CAST (basesink), 0));
+ }
+}
- bclass = GST_BASE_SINK_GET_CLASS (basesink);
+static GstFlowReturn
+gst_base_sink_default_wait_eos (GstBaseSink * basesink, GstEvent * event)
+{
+ GstFlowReturn ret;
+ gboolean late, step_end;
- if (G_LIKELY ((OBJ_IS_BUFFERLIST (obj_type) && bclass->render_list) ||
- (!OBJ_IS_BUFFERLIST (obj_type) && bclass->render))) {
- gint do_qos;
+ ret = gst_base_sink_do_sync (basesink, GST_MINI_OBJECT_CAST (event),
+ &late, &step_end);
- /* read once, to get same value before and after */
- do_qos = g_atomic_int_get (&priv->qos_enabled);
+ return ret;
+}
- GST_DEBUG_OBJECT (basesink, "rendering object %p", obj);
+static gboolean
+gst_base_sink_default_event (GstBaseSink * basesink, GstEvent * event)
+{
+ gboolean result = TRUE;
+ GstBaseSinkClass *bclass;
- /* record rendering time for QoS and stats */
- if (do_qos)
- gst_base_sink_do_render_stats (basesink, TRUE);
+ bclass = GST_BASE_SINK_GET_CLASS (basesink);
- if (!OBJ_IS_BUFFERLIST (obj_type)) {
- GstBuffer *buf;
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_FLUSH_START:
+ {
+ GST_DEBUG_OBJECT (basesink, "flush-start %p", event);
+ gst_base_sink_flush_start (basesink, basesink->sinkpad);
+ break;
+ }
+ case GST_EVENT_FLUSH_STOP:
+ {
+ gboolean reset_time;
- /* For buffer lists do not set last buffer. Creating buffer
- * with meaningful data can be done only with memcpy which will
- * significantly affect performance */
- buf = GST_BUFFER_CAST (obj);
- gst_base_sink_set_last_buffer (basesink, buf);
+ gst_event_parse_flush_stop (event, &reset_time);
+ GST_DEBUG_OBJECT (basesink, "flush-stop %p, reset_time: %d", event,
+ reset_time);
+ gst_base_sink_flush_stop (basesink, basesink->sinkpad, reset_time);
+ break;
+ }
+ case GST_EVENT_EOS:
+ {
+ GstMessage *message;
+ guint32 seqnum;
- ret = bclass->render (basesink, buf);
- } else {
- GstBufferList *buflist;
+ /* we set the received EOS flag here so that we can use it when testing if
+ * we are prerolled and to refuse more buffers. */
+ basesink->priv->received_eos = TRUE;
- buflist = GST_BUFFER_LIST_CAST (obj);
+ /* wait for EOS */
+ if (G_LIKELY (bclass->wait_eos)) {
+ GstFlowReturn ret;
- ret = bclass->render_list (basesink, buflist);
+ ret = bclass->wait_eos (basesink, event);
+ if (G_UNLIKELY (ret != GST_FLOW_OK)) {
+ result = FALSE;
+ goto done;
+ }
}
- if (do_qos)
- gst_base_sink_do_render_stats (basesink, FALSE);
+ /* the EOS event is completely handled so we mark
+ * ourselves as being in the EOS state. eos is also
+ * protected by the object lock so we can read it when
+ * answering the POSITION query. */
+ GST_OBJECT_LOCK (basesink);
+ basesink->eos = TRUE;
+ GST_OBJECT_UNLOCK (basesink);
- if (ret == GST_FLOW_STEP)
- goto again;
+ /* ok, now we can post the message */
+ GST_DEBUG_OBJECT (basesink, "Now posting EOS");
- if (G_UNLIKELY (basesink->flushing))
- goto flushing;
+ seqnum = basesink->priv->seqnum = gst_event_get_seqnum (event);
+ GST_DEBUG_OBJECT (basesink, "Got seqnum #%" G_GUINT32_FORMAT, seqnum);
- priv->rendered++;
+ message = gst_message_new_eos (GST_OBJECT_CAST (basesink));
+ gst_message_set_seqnum (message, seqnum);
+ gst_element_post_message (GST_ELEMENT_CAST (basesink), message);
+ break;
}
- } else if (G_LIKELY (OBJ_IS_EVENT (obj_type))) {
- GstEvent *event = GST_EVENT_CAST (obj);
- gboolean event_res = TRUE;
- GstEventType type;
-
- bclass = GST_BASE_SINK_GET_CLASS (basesink);
-
- type = GST_EVENT_TYPE (event);
-
- GST_DEBUG_OBJECT (basesink, "rendering event %p, type %s", obj,
- gst_event_type_get_name (type));
-
- if (bclass->event)
- event_res = bclass->event (basesink, event);
-
- /* when we get here we could be flushing again when the event handler calls
- * _wait_eos(). We have to ignore this object in that case. */
- if (G_UNLIKELY (basesink->flushing))
- goto flushing;
+ case GST_EVENT_CAPS:
+ {
+ GstCaps *caps;
- if (G_LIKELY (event_res)) {
- guint32 seqnum;
+ GST_DEBUG_OBJECT (basesink, "caps %p", event);
- seqnum = basesink->priv->seqnum = gst_event_get_seqnum (event);
- GST_DEBUG_OBJECT (basesink, "Got seqnum #%" G_GUINT32_FORMAT, seqnum);
+ gst_event_parse_caps (event, &caps);
+ if (bclass->set_caps)
+ result = bclass->set_caps (basesink, caps);
- switch (type) {
- case GST_EVENT_EOS:
- {
- GstMessage *message;
+ if (result) {
+ GST_OBJECT_LOCK (basesink);
+ gst_caps_replace (&basesink->priv->caps, caps);
+ GST_OBJECT_UNLOCK (basesink);
+ }
+ break;
+ }
+ case GST_EVENT_SEGMENT:
+ /* configure the segment */
+ /* The segment is protected with both the STREAM_LOCK and the OBJECT_LOCK.
+ * We protect with the OBJECT_LOCK so that we can use the values to
+ * safely answer a POSITION query. */
+ GST_OBJECT_LOCK (basesink);
+ /* the newsegment event is needed to bring the buffer timestamps to the
+ * stream time and to drop samples outside of the playback segment. */
+ gst_event_copy_segment (event, &basesink->segment);
+ GST_DEBUG_OBJECT (basesink, "configured SEGMENT %" GST_SEGMENT_FORMAT,
+ &basesink->segment);
+ basesink->have_newsegment = TRUE;
+ GST_OBJECT_UNLOCK (basesink);
+ break;
+ case GST_EVENT_TAG:
+ {
+ GstTagList *taglist;
- /* the EOS event is completely handled so we mark
- * ourselves as being in the EOS state. eos is also
- * protected by the object lock so we can read it when
- * answering the POSITION query. */
- GST_OBJECT_LOCK (basesink);
- basesink->eos = TRUE;
- GST_OBJECT_UNLOCK (basesink);
+ gst_event_parse_tag (event, &taglist);
- /* ok, now we can post the message */
- GST_DEBUG_OBJECT (basesink, "Now posting EOS");
+ gst_element_post_message (GST_ELEMENT_CAST (basesink),
+ gst_message_new_tag (GST_OBJECT_CAST (basesink),
+ gst_tag_list_copy (taglist)));
+ break;
+ }
+ case GST_EVENT_SINK_MESSAGE:
+ {
+ GstMessage *msg = NULL;
- message = gst_message_new_eos (GST_OBJECT_CAST (basesink));
- gst_message_set_seqnum (message, seqnum);
- gst_element_post_message (GST_ELEMENT_CAST (basesink), message);
- break;
- }
- case GST_EVENT_NEWSEGMENT:
- /* configure the segment */
- gst_base_sink_configure_segment (basesink, pad, event,
- &basesink->segment);
- break;
- case GST_EVENT_SINK_MESSAGE:{
- GstMessage *msg = NULL;
-
- gst_event_parse_sink_message (event, &msg);
-
- if (msg)
- gst_element_post_message (GST_ELEMENT_CAST (basesink), msg);
- }
- default:
- break;
- }
+ gst_event_parse_sink_message (event, &msg);
+ if (msg)
+ gst_element_post_message (GST_ELEMENT_CAST (basesink), msg);
+ break;
}
- } else {
- g_return_val_if_reached (GST_FLOW_ERROR);
+ default:
+ break;
}
-
done:
- if (step_end) {
- /* the step ended, check if we need to activate a new step */
- GST_DEBUG_OBJECT (basesink, "step ended");
- stop_stepping (basesink, &basesink->segment, &priv->current_step,
- priv->current_rstart, priv->current_rstop, basesink->eos);
- goto again;
- }
+ gst_event_unref (event);
- gst_base_sink_perform_qos (basesink, late);
-
- GST_DEBUG_OBJECT (basesink, "object unref after render %p", obj);
- gst_mini_object_unref (GST_MINI_OBJECT_CAST (obj));
- return ret;
-
- /* ERRORS */
-sync_failed:
- {
- GST_DEBUG_OBJECT (basesink, "do_sync returned %s", gst_flow_get_name (ret));
- goto done;
- }
-dropped:
- {
- priv->dropped++;
- GST_DEBUG_OBJECT (basesink, "buffer late, dropping");
-
- if (g_atomic_int_get (&priv->qos_enabled)) {
- GstMessage *qos_msg;
- GstClockTime timestamp, duration;
-
- timestamp = GST_BUFFER_TIMESTAMP (GST_BUFFER_CAST (sync_obj));
- duration = GST_BUFFER_DURATION (GST_BUFFER_CAST (sync_obj));
-
- GST_CAT_DEBUG_OBJECT (GST_CAT_QOS, basesink,
- "qos: dropped buffer rt %" GST_TIME_FORMAT ", st %" GST_TIME_FORMAT
- ", ts %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT,
- GST_TIME_ARGS (priv->current_rstart),
- GST_TIME_ARGS (priv->current_sstart), GST_TIME_ARGS (timestamp),
- GST_TIME_ARGS (duration));
- GST_CAT_DEBUG_OBJECT (GST_CAT_QOS, basesink,
- "qos: rendered %" G_GUINT64_FORMAT ", dropped %" G_GUINT64_FORMAT,
- priv->rendered, priv->dropped);
-
- qos_msg =
- gst_message_new_qos (GST_OBJECT_CAST (basesink), basesink->sync,
- priv->current_rstart, priv->current_sstart, timestamp, duration);
- gst_message_set_qos_values (qos_msg, priv->current_jitter, priv->avg_rate,
- 1000000);
- gst_message_set_qos_stats (qos_msg, GST_FORMAT_BUFFERS, priv->rendered,
- priv->dropped);
- gst_element_post_message (GST_ELEMENT_CAST (basesink), qos_msg);
- }
- goto done;
- }
-flushing:
- {
- GST_DEBUG_OBJECT (basesink, "we are flushing, ignore object");
- gst_mini_object_unref (obj);
- return GST_FLOW_WRONG_STATE;
- }
-}
-
-/* with STREAM_LOCK, PREROLL_LOCK
- *
- * Perform preroll on the given object. For buffers this means
- * calling the preroll subclass method.
- * If that succeeds, the state will be commited.
- *
- * function does not take ownership of obj.
- */
-static GstFlowReturn
-gst_base_sink_preroll_object (GstBaseSink * basesink, guint8 obj_type,
- GstMiniObject * obj)
-{
- GstFlowReturn ret;
-
- GST_DEBUG_OBJECT (basesink, "prerolling object %p", obj);
-
- /* if it's a buffer, we need to call the preroll method */
- if (G_LIKELY (OBJ_IS_BUFFERFULL (obj_type) && basesink->priv->call_preroll)) {
- GstBaseSinkClass *bclass;
- GstBuffer *buf;
- GstClockTime timestamp;
-
- if (OBJ_IS_BUFFERLIST (obj_type)) {
- buf = gst_buffer_list_get (GST_BUFFER_LIST_CAST (obj), 0, 0);
- g_assert (NULL != buf);
- } else {
- buf = GST_BUFFER_CAST (obj);
- }
-
- timestamp = GST_BUFFER_TIMESTAMP (buf);
-
- GST_DEBUG_OBJECT (basesink, "preroll buffer %" GST_TIME_FORMAT,
- GST_TIME_ARGS (timestamp));
-
- /*
- * For buffer lists do not set last buffer. Creating buffer
- * with meaningful data can be done only with memcpy which will
- * significantly affect performance
- */
- if (!OBJ_IS_BUFFERLIST (obj_type)) {
- gst_base_sink_set_last_buffer (basesink, buf);
- }
-
- bclass = GST_BASE_SINK_GET_CLASS (basesink);
- if (bclass->preroll)
- if ((ret = bclass->preroll (basesink, buf)) != GST_FLOW_OK)
- goto preroll_failed;
-
- basesink->priv->call_preroll = FALSE;
- }
-
- /* commit state */
- if (G_LIKELY (basesink->playing_async)) {
- if (G_UNLIKELY (!gst_base_sink_commit_state (basesink)))
- goto stopping;
- }
-
- return GST_FLOW_OK;
-
- /* ERRORS */
-preroll_failed:
- {
- GST_DEBUG_OBJECT (basesink, "preroll failed, abort state");
- gst_element_abort_state (GST_ELEMENT_CAST (basesink));
- return ret;
- }
-stopping:
- {
- GST_DEBUG_OBJECT (basesink, "stopping while commiting state");
- return GST_FLOW_WRONG_STATE;
- }
-}
-
-/* with STREAM_LOCK, PREROLL_LOCK
- *
- * Queue an object for rendering.
- * The first prerollable object queued will complete the preroll. If the
- * preroll queue is filled, we render all the objects in the queue.
- *
- * This function takes ownership of the object.
- */
-static GstFlowReturn
-gst_base_sink_queue_object_unlocked (GstBaseSink * basesink, GstPad * pad,
- guint8 obj_type, gpointer obj, gboolean prerollable)
-{
- GstFlowReturn ret = GST_FLOW_OK;
- gint length;
- GQueue *q;
-
- if (G_UNLIKELY (basesink->need_preroll)) {
- if (G_LIKELY (prerollable))
- basesink->preroll_queued++;
-
- length = basesink->preroll_queued;
-
- GST_DEBUG_OBJECT (basesink, "now %d prerolled items", length);
-
- /* first prerollable item needs to finish the preroll */
- if (length == 1) {
- ret = gst_base_sink_preroll_object (basesink, obj_type, obj);
- if (G_UNLIKELY (ret != GST_FLOW_OK))
- goto preroll_failed;
- }
- /* need to recheck if we need preroll, commit state during preroll
- * could have made us not need more preroll. */
- if (G_UNLIKELY (basesink->need_preroll)) {
- /* see if we can render now, if we can't add the object to the preroll
- * queue. */
- if (G_UNLIKELY (length <= basesink->preroll_queue_max_len))
- goto more_preroll;
- }
- }
- /* we can start rendering (or blocking) the queued object
- * if any. */
- q = basesink->preroll_queue;
- while (G_UNLIKELY (!g_queue_is_empty (q))) {
- GstMiniObject *o;
- guint8 ot;
-
- o = g_queue_pop_head (q);
- GST_DEBUG_OBJECT (basesink, "rendering queued object %p", o);
-
- ot = get_object_type (o);
-
- /* do something with the return value */
- ret = gst_base_sink_render_object (basesink, pad, ot, o);
- if (ret != GST_FLOW_OK)
- goto dequeue_failed;
- }
-
- /* now render the object */
- ret = gst_base_sink_render_object (basesink, pad, obj_type, obj);
- basesink->preroll_queued = 0;
-
- return ret;
-
- /* special cases */
-preroll_failed:
- {
- GST_DEBUG_OBJECT (basesink, "preroll failed, reason %s",
- gst_flow_get_name (ret));
- gst_mini_object_unref (GST_MINI_OBJECT_CAST (obj));
- return ret;
- }
-more_preroll:
- {
- /* add object to the queue and return */
- GST_DEBUG_OBJECT (basesink, "need more preroll data %d <= %d",
- length, basesink->preroll_queue_max_len);
- g_queue_push_tail (basesink->preroll_queue, obj);
- return GST_FLOW_OK;
- }
-dequeue_failed:
- {
- GST_DEBUG_OBJECT (basesink, "rendering queued objects failed, reason %s",
- gst_flow_get_name (ret));
- gst_mini_object_unref (GST_MINI_OBJECT_CAST (obj));
- return ret;
- }
-}
-
-/* with STREAM_LOCK
- *
- * This function grabs the PREROLL_LOCK and adds the object to
- * the queue.
- *
- * This function takes ownership of obj.
- *
- * Note: Only GstEvent seem to be passed to this private method
- */
-static GstFlowReturn
-gst_base_sink_queue_object (GstBaseSink * basesink, GstPad * pad,
- GstMiniObject * obj, gboolean prerollable)
-{
- GstFlowReturn ret;
-
- GST_PAD_PREROLL_LOCK (pad);
- if (G_UNLIKELY (basesink->flushing))
- goto flushing;
-
- if (G_UNLIKELY (basesink->priv->received_eos))
- goto was_eos;
-
- ret =
- gst_base_sink_queue_object_unlocked (basesink, pad, _PR_IS_EVENT, obj,
- prerollable);
- GST_PAD_PREROLL_UNLOCK (pad);
-
- return ret;
-
- /* ERRORS */
-flushing:
- {
- GST_DEBUG_OBJECT (basesink, "sink is flushing");
- GST_PAD_PREROLL_UNLOCK (pad);
- gst_mini_object_unref (obj);
- return GST_FLOW_WRONG_STATE;
- }
-was_eos:
- {
- GST_DEBUG_OBJECT (basesink,
- "we are EOS, dropping object, return UNEXPECTED");
- GST_PAD_PREROLL_UNLOCK (pad);
- gst_mini_object_unref (obj);
- return GST_FLOW_UNEXPECTED;
- }
-}
-
-static void
-gst_base_sink_flush_start (GstBaseSink * basesink, GstPad * pad)
-{
- /* make sure we are not blocked on the clock also clear any pending
- * eos state. */
- gst_base_sink_set_flushing (basesink, pad, TRUE);
-
- /* we grab the stream lock but that is not needed since setting the
- * sink to flushing would make sure no state commit is being done
- * anymore */
- GST_PAD_STREAM_LOCK (pad);
- gst_base_sink_reset_qos (basesink);
- /* and we need to commit our state again on the next
- * prerolled buffer */
- basesink->playing_async = TRUE;
- if (basesink->priv->async_enabled) {
- gst_element_lost_state (GST_ELEMENT_CAST (basesink));
- } else {
- /* start time reset in above case as well;
- * arranges for a.o. proper position reporting when flushing in PAUSED */
- gst_element_set_start_time (GST_ELEMENT_CAST (basesink), 0);
- basesink->priv->have_latency = TRUE;
- }
- gst_base_sink_set_last_buffer (basesink, NULL);
- GST_PAD_STREAM_UNLOCK (pad);
-}
-
-static void
-gst_base_sink_flush_stop (GstBaseSink * basesink, GstPad * pad)
-{
- /* unset flushing so we can accept new data, this also flushes out any EOS
- * event. */
- gst_base_sink_set_flushing (basesink, pad, FALSE);
-
- /* for position reporting */
- GST_OBJECT_LOCK (basesink);
- basesink->priv->current_sstart = GST_CLOCK_TIME_NONE;
- basesink->priv->current_sstop = GST_CLOCK_TIME_NONE;
- basesink->priv->eos_rtime = GST_CLOCK_TIME_NONE;
- basesink->priv->call_preroll = TRUE;
- basesink->priv->current_step.valid = FALSE;
- basesink->priv->pending_step.valid = FALSE;
- if (basesink->pad_mode == GST_ACTIVATE_PUSH) {
- /* we need new segment info after the flush. */
- basesink->have_newsegment = FALSE;
- gst_segment_init (&basesink->segment, GST_FORMAT_UNDEFINED);
- gst_segment_init (basesink->abidata.ABI.clip_segment, GST_FORMAT_UNDEFINED);
- }
- GST_OBJECT_UNLOCK (basesink);
-}
+ return result;
+}
static gboolean
-gst_base_sink_event (GstPad * pad, GstEvent * event)
+gst_base_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
{
GstBaseSink *basesink;
gboolean result = TRUE;
GstBaseSinkClass *bclass;
- basesink = GST_BASE_SINK (gst_pad_get_parent (pad));
- if (G_UNLIKELY (basesink == NULL)) {
- gst_event_unref (event);
- return FALSE;
- }
-
+ basesink = GST_BASE_SINK_CAST (parent);
bclass = GST_BASE_SINK_GET_CLASS (basesink);
GST_DEBUG_OBJECT (basesink, "received event %p %" GST_PTR_FORMAT, event,
event);
switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_EOS:
- {
- GstFlowReturn ret;
-
- GST_PAD_PREROLL_LOCK (pad);
- if (G_UNLIKELY (basesink->flushing))
- goto flushing;
-
- if (G_UNLIKELY (basesink->priv->received_eos)) {
- /* we can't accept anything when we are EOS */
- result = FALSE;
- gst_event_unref (event);
- } else {
- /* we set the received EOS flag here so that we can use it when testing if
- * we are prerolled and to refuse more buffers. */
- basesink->priv->received_eos = TRUE;
-
- /* EOS is a prerollable object, we call the unlocked version because it
- * does not check the received_eos flag. */
- ret = gst_base_sink_queue_object_unlocked (basesink, pad,
- _PR_IS_EVENT, GST_MINI_OBJECT_CAST (event), TRUE);
- if (G_UNLIKELY (ret != GST_FLOW_OK))
- result = FALSE;
- }
- GST_PAD_PREROLL_UNLOCK (pad);
- break;
- }
- case GST_EVENT_NEWSEGMENT:
- {
- GstFlowReturn ret;
- gboolean update;
-
- GST_DEBUG_OBJECT (basesink, "newsegment %p", event);
-
- GST_PAD_PREROLL_LOCK (pad);
- if (G_UNLIKELY (basesink->flushing))
- goto flushing;
-
- gst_event_parse_new_segment_full (event, &update, NULL, NULL, NULL, NULL,
- NULL, NULL);
-
- if (G_UNLIKELY (basesink->priv->received_eos && !update)) {
- /* we can't accept anything when we are EOS */
- result = FALSE;
- gst_event_unref (event);
- } else {
- /* the new segment is a non prerollable item and does not block anything,
- * we need to configure the current clipping segment and insert the event
- * in the queue to serialize it with the buffers for rendering. */
- gst_base_sink_configure_segment (basesink, pad, event,
- basesink->abidata.ABI.clip_segment);
-
- ret =
- gst_base_sink_queue_object_unlocked (basesink, pad,
- _PR_IS_EVENT, GST_MINI_OBJECT_CAST (event), FALSE);
- if (G_UNLIKELY (ret != GST_FLOW_OK))
- result = FALSE;
- else {
- GST_OBJECT_LOCK (basesink);
- basesink->have_newsegment = TRUE;
- GST_OBJECT_UNLOCK (basesink);
- }
- }
- GST_PAD_PREROLL_UNLOCK (pad);
- break;
- }
- case GST_EVENT_FLUSH_START:
- if (bclass->event)
- bclass->event (basesink, event);
-
- GST_DEBUG_OBJECT (basesink, "flush-start %p", event);
-
- gst_base_sink_flush_start (basesink, pad);
-
- gst_event_unref (event);
- break;
case GST_EVENT_FLUSH_STOP:
+ /* special case for this serialized event because we don't want to grab
+ * the PREROLL lock or check if we were flushing */
if (bclass->event)
- bclass->event (basesink, event);
-
- GST_DEBUG_OBJECT (basesink, "flush-stop %p", event);
-
- gst_base_sink_flush_stop (basesink, pad);
-
- gst_event_unref (event);
+ result = bclass->event (basesink, event);
break;
default:
- /* other events are sent to queue or subclass depending on if they
- * are serialized. */
if (GST_EVENT_IS_SERIALIZED (event)) {
- gst_base_sink_queue_object (basesink, pad,
- GST_MINI_OBJECT_CAST (event), FALSE);
+ GST_BASE_SINK_PREROLL_LOCK (basesink);
+ if (G_UNLIKELY (basesink->flushing))
+ goto flushing;
+
+ if (G_UNLIKELY (basesink->priv->received_eos))
+ goto after_eos;
+
+ if (bclass->event)
+ result = bclass->event (basesink, event);
+
+ GST_BASE_SINK_PREROLL_UNLOCK (basesink);
} else {
if (bclass->event)
- bclass->event (basesink, event);
- gst_event_unref (event);
+ result = bclass->event (basesink, event);
}
break;
}
done:
- gst_object_unref (basesink);
-
return result;
/* ERRORS */
flushing:
{
GST_DEBUG_OBJECT (basesink, "we are flushing");
- GST_PAD_PREROLL_UNLOCK (pad);
+ GST_BASE_SINK_PREROLL_UNLOCK (basesink);
+ gst_event_unref (event);
result = FALSE;
+ goto done;
+ }
+
+after_eos:
+ {
+ GST_DEBUG_OBJECT (basesink, "Event received after EOS, dropping");
+ GST_BASE_SINK_PREROLL_UNLOCK (basesink);
gst_event_unref (event);
+ result = FALSE;
goto done;
}
}
* timestamps on a buffer, subclasses can override
*/
static void
-gst_base_sink_get_times (GstBaseSink * basesink, GstBuffer * buffer,
+gst_base_sink_default_get_times (GstBaseSink * basesink, GstBuffer * buffer,
GstClockTime * start, GstClockTime * end)
{
GstClockTime timestamp, duration;
- timestamp = GST_BUFFER_TIMESTAMP (buffer);
- if (GST_CLOCK_TIME_IS_VALID (timestamp)) {
+ /* first sync on DTS, else use PTS */
+ timestamp = GST_BUFFER_DTS (buffer);
+ if (!GST_CLOCK_TIME_IS_VALID (timestamp))
+ timestamp = GST_BUFFER_PTS (buffer);
+ if (GST_CLOCK_TIME_IS_VALID (timestamp)) {
/* get duration to calculate end time */
duration = GST_BUFFER_DURATION (buffer);
if (GST_CLOCK_TIME_IS_VALID (duration)) {
*
* Takes a buffer and compare the timestamps with the last segment.
* If the buffer falls outside of the segment boundaries, drop it.
- * Else queue the buffer for preroll and rendering.
+ * Else send the buffer for preroll and rendering.
*
* This function takes ownership of the buffer.
*/
static GstFlowReturn
gst_base_sink_chain_unlocked (GstBaseSink * basesink, GstPad * pad,
- guint8 obj_type, gpointer obj)
+ gpointer obj, gboolean is_list)
{
GstBaseSinkClass *bclass;
- GstFlowReturn result;
+ GstBaseSinkPrivate *priv = basesink->priv;
+ GstFlowReturn ret;
GstClockTime start = GST_CLOCK_TIME_NONE, end = GST_CLOCK_TIME_NONE;
- GstSegment *clip_segment;
- GstBuffer *time_buf;
+ GstSegment *segment;
+ GstBuffer *sync_buf;
+ gint do_qos;
+ gboolean late, step_end;
if (G_UNLIKELY (basesink->flushing))
goto flushing;
- if (G_UNLIKELY (basesink->priv->received_eos))
+ if (G_UNLIKELY (priv->received_eos))
goto was_eos;
- if (OBJ_IS_BUFFERLIST (obj_type)) {
- time_buf = gst_buffer_list_get (GST_BUFFER_LIST_CAST (obj), 0, 0);
- g_assert (NULL != time_buf);
+ if (is_list) {
+ sync_buf = gst_buffer_list_get (GST_BUFFER_LIST_CAST (obj), 0);
+ g_assert (NULL != sync_buf);
} else {
- time_buf = GST_BUFFER_CAST (obj);
+ sync_buf = GST_BUFFER_CAST (obj);
}
/* for code clarity */
- clip_segment = basesink->abidata.ABI.clip_segment;
+ segment = &basesink->segment;
if (G_UNLIKELY (!basesink->have_newsegment)) {
gboolean sync;
/* this means this sink will assume timestamps start from 0 */
GST_OBJECT_LOCK (basesink);
- clip_segment->start = 0;
- clip_segment->stop = -1;
+ segment->start = 0;
+ segment->stop = -1;
basesink->segment.start = 0;
basesink->segment.stop = -1;
basesink->have_newsegment = TRUE;
/* check if the buffer needs to be dropped, we first ask the subclass for the
* start and end */
if (bclass->get_times)
- bclass->get_times (basesink, time_buf, &start, &end);
+ bclass->get_times (basesink, sync_buf, &start, &end);
if (!GST_CLOCK_TIME_IS_VALID (start)) {
/* if the subclass does not want sync, we use our own values so that we at
* least clip the buffer to the segment */
- gst_base_sink_get_times (basesink, time_buf, &start, &end);
+ gst_base_sink_default_get_times (basesink, sync_buf, &start, &end);
}
GST_DEBUG_OBJECT (basesink, "got times start: %" GST_TIME_FORMAT
", end: %" GST_TIME_FORMAT, GST_TIME_ARGS (start), GST_TIME_ARGS (end));
/* a dropped buffer does not participate in anything */
- if (GST_CLOCK_TIME_IS_VALID (start) &&
- (clip_segment->format == GST_FORMAT_TIME)) {
- if (G_UNLIKELY (!gst_segment_clip (clip_segment,
- GST_FORMAT_TIME, (gint64) start, (gint64) end, NULL, NULL)))
+ if (GST_CLOCK_TIME_IS_VALID (start) && (segment->format == GST_FORMAT_TIME)) {
+ if (G_UNLIKELY (!gst_segment_clip (segment,
+ GST_FORMAT_TIME, start, end, NULL, NULL)))
goto out_of_segment;
}
- /* now we can process the buffer in the queue, this function takes ownership
- * of the buffer */
- result = gst_base_sink_queue_object_unlocked (basesink, pad,
- obj_type, obj, TRUE);
- return result;
+ if (!is_list) {
+ if (bclass->prepare) {
+ ret = bclass->prepare (basesink, GST_BUFFER_CAST (obj));
+ if (G_UNLIKELY (ret != GST_FLOW_OK))
+ goto prepare_failed;
+ }
+ } else {
+ if (bclass->prepare_list) {
+ ret = bclass->prepare_list (basesink, GST_BUFFER_LIST_CAST (obj));
+ if (G_UNLIKELY (ret != GST_FLOW_OK))
+ goto prepare_failed;
+ }
+ }
+
+again:
+ late = FALSE;
+ step_end = FALSE;
+
+ /* synchronize this object, non syncable objects return OK
+ * immediately. */
+ ret = gst_base_sink_do_sync (basesink, GST_MINI_OBJECT_CAST (sync_buf),
+ &late, &step_end);
+ if (G_UNLIKELY (ret != GST_FLOW_OK))
+ goto sync_failed;
+
+ /* drop late buffers unconditionally, let's hope it's unlikely */
+ if (G_UNLIKELY (late))
+ goto dropped;
+
+ /* read once, to get same value before and after */
+ do_qos = g_atomic_int_get (&priv->qos_enabled);
+
+ GST_DEBUG_OBJECT (basesink, "rendering object %p", obj);
+
+ /* record rendering time for QoS and stats */
+ if (do_qos)
+ gst_base_sink_do_render_stats (basesink, TRUE);
+
+ if (!is_list) {
+ /* For buffer lists do not set last buffer for now. */
+ gst_base_sink_set_last_buffer (basesink, GST_BUFFER_CAST (obj));
+
+ if (bclass->render)
+ ret = bclass->render (basesink, GST_BUFFER_CAST (obj));
+ } else {
+ if (bclass->render_list)
+ ret = bclass->render_list (basesink, GST_BUFFER_LIST_CAST (obj));
+ }
+
+ if (do_qos)
+ gst_base_sink_do_render_stats (basesink, FALSE);
+
+ if (ret == GST_FLOW_STEP)
+ goto again;
+
+ if (G_UNLIKELY (basesink->flushing))
+ goto flushing;
+
+ priv->rendered++;
+
+done:
+ if (step_end) {
+ /* the step ended, check if we need to activate a new step */
+ GST_DEBUG_OBJECT (basesink, "step ended");
+ stop_stepping (basesink, &basesink->segment, &priv->current_step,
+ priv->current_rstart, priv->current_rstop, basesink->eos);
+ goto again;
+ }
+
+ gst_base_sink_perform_qos (basesink, late);
+
+ GST_DEBUG_OBJECT (basesink, "object unref after render %p", obj);
+ gst_mini_object_unref (GST_MINI_OBJECT_CAST (obj));
+
+ return ret;
/* ERRORS */
flushing:
{
GST_DEBUG_OBJECT (basesink, "sink is flushing");
gst_mini_object_unref (GST_MINI_OBJECT_CAST (obj));
- return GST_FLOW_WRONG_STATE;
+ return GST_FLOW_FLUSHING;
}
was_eos:
{
- GST_DEBUG_OBJECT (basesink,
- "we are EOS, dropping object, return UNEXPECTED");
+ GST_DEBUG_OBJECT (basesink, "we are EOS, dropping object, return EOS");
gst_mini_object_unref (GST_MINI_OBJECT_CAST (obj));
- return GST_FLOW_UNEXPECTED;
+ return GST_FLOW_EOS;
}
out_of_segment:
{
gst_mini_object_unref (GST_MINI_OBJECT_CAST (obj));
return GST_FLOW_OK;
}
+prepare_failed:
+ {
+ GST_DEBUG_OBJECT (basesink, "prepare buffer failed %s",
+ gst_flow_get_name (ret));
+ gst_mini_object_unref (GST_MINI_OBJECT_CAST (obj));
+ return ret;
+ }
+sync_failed:
+ {
+ GST_DEBUG_OBJECT (basesink, "do_sync returned %s", gst_flow_get_name (ret));
+ goto done;
+ }
+dropped:
+ {
+ priv->dropped++;
+ GST_DEBUG_OBJECT (basesink, "buffer late, dropping");
+
+ if (g_atomic_int_get (&priv->qos_enabled)) {
+ GstMessage *qos_msg;
+ GstClockTime timestamp, duration;
+
+ timestamp = GST_BUFFER_TIMESTAMP (GST_BUFFER_CAST (sync_buf));
+ duration = GST_BUFFER_DURATION (GST_BUFFER_CAST (sync_buf));
+
+ GST_CAT_DEBUG_OBJECT (GST_CAT_QOS, basesink,
+ "qos: dropped buffer rt %" GST_TIME_FORMAT ", st %" GST_TIME_FORMAT
+ ", ts %" GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (priv->current_rstart),
+ GST_TIME_ARGS (priv->current_sstart), GST_TIME_ARGS (timestamp),
+ GST_TIME_ARGS (duration));
+ GST_CAT_DEBUG_OBJECT (GST_CAT_QOS, basesink,
+ "qos: rendered %" G_GUINT64_FORMAT ", dropped %" G_GUINT64_FORMAT,
+ priv->rendered, priv->dropped);
+
+ qos_msg =
+ gst_message_new_qos (GST_OBJECT_CAST (basesink), basesink->sync,
+ priv->current_rstart, priv->current_sstart, timestamp, duration);
+ gst_message_set_qos_values (qos_msg, priv->current_jitter, priv->avg_rate,
+ 1000000);
+ gst_message_set_qos_stats (qos_msg, GST_FORMAT_BUFFERS, priv->rendered,
+ priv->dropped);
+ gst_element_post_message (GST_ELEMENT_CAST (basesink), qos_msg);
+ }
+ goto done;
+ }
}
/* with STREAM_LOCK
*/
static GstFlowReturn
-gst_base_sink_chain_main (GstBaseSink * basesink, GstPad * pad,
- guint8 obj_type, gpointer obj)
+gst_base_sink_chain_main (GstBaseSink * basesink, GstPad * pad, gpointer obj,
+ gboolean is_list)
{
GstFlowReturn result;
- if (G_UNLIKELY (basesink->pad_mode != GST_ACTIVATE_PUSH))
+ if (G_UNLIKELY (basesink->pad_mode != GST_PAD_MODE_PUSH))
goto wrong_mode;
- GST_PAD_PREROLL_LOCK (pad);
- result = gst_base_sink_chain_unlocked (basesink, pad, obj_type, obj);
- GST_PAD_PREROLL_UNLOCK (pad);
+ GST_BASE_SINK_PREROLL_LOCK (basesink);
+ result = gst_base_sink_chain_unlocked (basesink, pad, obj, is_list);
+ GST_BASE_SINK_PREROLL_UNLOCK (basesink);
done:
return result;
gst_mini_object_unref (GST_MINI_OBJECT_CAST (obj));
/* we don't post an error message this will signal to the peer
* pushing that EOS is reached. */
- result = GST_FLOW_UNEXPECTED;
+ result = GST_FLOW_EOS;
goto done;
}
}
static GstFlowReturn
-gst_base_sink_chain (GstPad * pad, GstBuffer * buf)
+gst_base_sink_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
{
GstBaseSink *basesink;
- basesink = GST_BASE_SINK (GST_OBJECT_PARENT (pad));
+ basesink = GST_BASE_SINK (parent);
- return gst_base_sink_chain_main (basesink, pad, _PR_IS_BUFFER, buf);
+ return gst_base_sink_chain_main (basesink, pad, buf, FALSE);
}
static GstFlowReturn
-gst_base_sink_chain_list (GstPad * pad, GstBufferList * list)
+gst_base_sink_chain_list (GstPad * pad, GstObject * parent,
+ GstBufferList * list)
{
GstBaseSink *basesink;
GstBaseSinkClass *bclass;
GstFlowReturn result;
- basesink = GST_BASE_SINK (GST_OBJECT_PARENT (pad));
+ basesink = GST_BASE_SINK (parent);
bclass = GST_BASE_SINK_GET_CLASS (basesink);
if (G_LIKELY (bclass->render_list)) {
- result = gst_base_sink_chain_main (basesink, pad, _PR_IS_BUFFERLIST, list);
+ result = gst_base_sink_chain_main (basesink, pad, list, TRUE);
} else {
- GstBufferListIterator *it;
- GstBuffer *group;
+ guint i, len;
+ GstBuffer *buffer;
GST_INFO_OBJECT (pad, "chaining each group in list as a merged buffer");
- it = gst_buffer_list_iterate (list);
+ len = gst_buffer_list_length (list);
- if (gst_buffer_list_iterator_next_group (it)) {
- do {
- group = gst_buffer_list_iterator_merge_group (it);
- if (group == NULL) {
- group = gst_buffer_new ();
- GST_CAT_INFO_OBJECT (GST_CAT_SCHEDULING, pad, "chaining empty group");
- } else {
- GST_CAT_INFO_OBJECT (GST_CAT_SCHEDULING, pad, "chaining group");
- }
- result = gst_base_sink_chain_main (basesink, pad, _PR_IS_BUFFER, group);
- } while (result == GST_FLOW_OK
- && gst_buffer_list_iterator_next_group (it));
- } else {
- GST_CAT_INFO_OBJECT (GST_CAT_SCHEDULING, pad, "chaining empty group");
- result =
- gst_base_sink_chain_main (basesink, pad, _PR_IS_BUFFER,
- gst_buffer_new ());
+ result = GST_FLOW_OK;
+ for (i = 0; i < len; i++) {
+ buffer = gst_buffer_list_get (list, i);
+ result = gst_base_sink_chain_main (basesink, pad,
+ gst_buffer_ref (buffer), FALSE);
+ if (result != GST_FLOW_OK)
+ break;
}
- gst_buffer_list_iterator_free (it);
gst_buffer_list_unref (list);
}
return result;
GstSeekType cur_type, stop_type;
gint64 cur, stop;
GstSeekFlags flags;
- GstFormat seek_format, dest_format;
+ GstFormat seek_format;
gdouble rate;
gboolean update;
gboolean res = TRUE;
gst_event_parse_seek (event, &rate, &seek_format, &flags,
&cur_type, &cur, &stop_type, &stop);
- dest_format = segment->format;
- if (seek_format == dest_format) {
- gst_segment_set_seek (segment, rate, seek_format, flags,
+ if (seek_format == segment->format) {
+ gst_segment_do_seek (segment, rate, seek_format, flags,
cur_type, cur, stop_type, stop, &update);
return TRUE;
}
if (cur_type != GST_SEEK_TYPE_NONE) {
/* FIXME: Handle seek_cur & seek_end by converting the input segment vals */
res =
- gst_pad_query_convert (sink->sinkpad, seek_format, cur, &dest_format,
+ gst_pad_query_convert (sink->sinkpad, seek_format, cur, segment->format,
&cur);
cur_type = GST_SEEK_TYPE_SET;
}
if (res && stop_type != GST_SEEK_TYPE_NONE) {
/* FIXME: Handle seek_cur & seek_end by converting the input segment vals */
res =
- gst_pad_query_convert (sink->sinkpad, seek_format, stop, &dest_format,
- &stop);
+ gst_pad_query_convert (sink->sinkpad, seek_format, stop,
+ segment->format, &stop);
stop_type = GST_SEEK_TYPE_SET;
}
/* And finally, configure our output segment in the desired format */
- gst_segment_set_seek (segment, rate, dest_format, flags, cur_type, cur,
+ gst_segment_do_seek (segment, rate, segment->format, flags, cur_type, cur,
stop_type, stop, &update);
if (!res)
} else {
/* The seek format matches our processing format, no need to ask the
* the subclass to configure the segment. */
- gst_segment_set_seek (&seeksegment, rate, seek_format, flags,
+ gst_segment_do_seek (&seeksegment, rate, seek_format, flags,
cur_type, cur, stop_type, stop, &update);
}
}
if (res) {
GST_DEBUG_OBJECT (sink, "segment configured from %" G_GINT64_FORMAT
" to %" G_GINT64_FORMAT ", position %" G_GINT64_FORMAT,
- seeksegment.start, seeksegment.stop, seeksegment.last_stop);
+ seeksegment.start, seeksegment.stop, seeksegment.position);
- /* do the seek, segment.last_stop contains the new position. */
+ /* do the seek, segment.position contains the new position. */
res = gst_base_sink_default_do_seek (sink, &seeksegment);
}
if (flush) {
GST_DEBUG_OBJECT (sink, "stop flushing upstream");
- gst_pad_push_event (pad, gst_event_new_flush_stop ());
- gst_base_sink_flush_stop (sink, pad);
- } else if (res && sink->abidata.ABI.running) {
+ gst_pad_push_event (pad, gst_event_new_flush_stop (TRUE));
+ gst_base_sink_flush_stop (sink, pad, TRUE);
+ } else if (res && sink->running) {
/* we are running the current segment and doing a non-flushing seek,
- * close the segment first based on the last_stop. */
+ * close the segment first based on the position. */
GST_DEBUG_OBJECT (sink, "closing running segment %" G_GINT64_FORMAT
- " to %" G_GINT64_FORMAT, sink->segment.start, sink->segment.last_stop);
+ " to %" G_GINT64_FORMAT, sink->segment.start, sink->segment.position);
}
/* The subclass must have converted the segment to the processing format
/* if successful seek, we update our real segment and push
* out the new segment. */
if (res) {
- memcpy (&sink->segment, &seeksegment, sizeof (GstSegment));
+ gst_segment_copy_into (&seeksegment, &sink->segment);
if (sink->segment.flags & GST_SEEK_FLAG_SEGMENT) {
gst_element_post_message (GST_ELEMENT (sink),
gst_message_new_segment_start (GST_OBJECT (sink),
- sink->segment.format, sink->segment.last_stop));
+ sink->segment.format, sink->segment.position));
}
}
sink->priv->discont = TRUE;
- sink->abidata.ABI.running = TRUE;
+ sink->running = TRUE;
GST_PAD_STREAM_UNLOCK (pad);
if (bclass->unlock)
bclass->unlock (sink);
- GST_PAD_PREROLL_LOCK (sink->sinkpad);
+ GST_BASE_SINK_PREROLL_LOCK (sink);
/* now that we have the PREROLL lock, clear our unlock request */
if (bclass->unlock_stop)
bclass->unlock_stop (sink);
sink->playing_async = TRUE;
priv->pending_step.need_preroll = TRUE;
sink->need_preroll = FALSE;
- gst_element_lost_state_full (GST_ELEMENT_CAST (sink), FALSE);
+ gst_element_lost_state (GST_ELEMENT_CAST (sink));
} else {
sink->priv->have_latency = TRUE;
sink->need_preroll = FALSE;
if (sink->have_preroll) {
GST_DEBUG_OBJECT (sink, "signal waiter");
priv->step_unlock = TRUE;
- GST_PAD_PREROLL_SIGNAL (sink->sinkpad);
+ GST_BASE_SINK_PREROLL_SIGNAL (sink);
}
- GST_PAD_PREROLL_UNLOCK (sink->sinkpad);
+ GST_BASE_SINK_PREROLL_UNLOCK (sink);
} else {
/* update the stepinfo and make it valid */
set_step_info (sink, current, pending, seqnum, format, amount, rate, flush,
static void
gst_base_sink_loop (GstPad * pad)
{
+ GstObject *parent;
GstBaseSink *basesink;
GstBuffer *buf = NULL;
GstFlowReturn result;
guint blocksize;
guint64 offset;
- basesink = GST_BASE_SINK (GST_OBJECT_PARENT (pad));
+ parent = GST_OBJECT_PARENT (pad);
+ basesink = GST_BASE_SINK (parent);
- g_assert (basesink->pad_mode == GST_ACTIVATE_PULL);
+ g_assert (basesink->pad_mode == GST_PAD_MODE_PULL);
if ((blocksize = basesink->priv->blocksize) == 0)
blocksize = -1;
- offset = basesink->segment.last_stop;
+ offset = basesink->segment.position;
GST_DEBUG_OBJECT (basesink, "pulling %" G_GUINT64_FORMAT ", %u",
offset, blocksize);
if (G_UNLIKELY (buf == NULL))
goto no_buffer;
- offset += GST_BUFFER_SIZE (buf);
+ offset += gst_buffer_get_size (buf);
- gst_segment_set_last_stop (&basesink->segment, GST_FORMAT_BYTES, offset);
+ basesink->segment.position = offset;
- GST_PAD_PREROLL_LOCK (pad);
- result = gst_base_sink_chain_unlocked (basesink, pad, _PR_IS_BUFFER, buf);
- GST_PAD_PREROLL_UNLOCK (pad);
+ GST_BASE_SINK_PREROLL_LOCK (basesink);
+ result = gst_base_sink_chain_unlocked (basesink, pad, buf, FALSE);
+ GST_BASE_SINK_PREROLL_UNLOCK (basesink);
if (G_UNLIKELY (result != GST_FLOW_OK))
goto paused;
GST_LOG_OBJECT (basesink, "pausing task, reason %s",
gst_flow_get_name (result));
gst_pad_pause_task (pad);
- if (result == GST_FLOW_UNEXPECTED) {
+ if (result == GST_FLOW_EOS) {
/* perform EOS logic */
if (basesink->segment.flags & GST_SEEK_FLAG_SEGMENT) {
gst_element_post_message (GST_ELEMENT_CAST (basesink),
gst_message_new_segment_done (GST_OBJECT_CAST (basesink),
- basesink->segment.format, basesink->segment.last_stop));
+ basesink->segment.format, basesink->segment.position));
} else {
- gst_base_sink_event (pad, gst_event_new_eos ());
+ gst_base_sink_event (pad, parent, gst_event_new_eos ());
}
- } else if (result == GST_FLOW_NOT_LINKED || result <= GST_FLOW_UNEXPECTED) {
+ } else if (result == GST_FLOW_NOT_LINKED || result <= GST_FLOW_EOS) {
/* for fatal errors we post an error message, post the error
* first so the app knows about the error first.
* wrong-state is not a fatal error because it happens due to
GST_ELEMENT_ERROR (basesink, STREAM, FAILED,
(_("Internal data stream error.")),
("stream stopped, reason %s", gst_flow_get_name (result)));
- gst_base_sink_event (pad, gst_event_new_eos ());
+ gst_base_sink_event (pad, parent, gst_event_new_eos ());
}
return;
}
bclass->unlock (basesink);
}
- GST_PAD_PREROLL_LOCK (pad);
+ GST_BASE_SINK_PREROLL_LOCK (basesink);
basesink->flushing = flushing;
if (flushing) {
/* step 1, now that we have the PREROLL lock, clear our unlock request */
* also flush out the EOS state */
GST_DEBUG_OBJECT (basesink,
"flushing out data thread, need preroll to TRUE");
- gst_base_sink_preroll_queue_flush (basesink, pad);
+
+ /* we can't have EOS anymore now */
+ basesink->eos = FALSE;
+ basesink->priv->received_eos = FALSE;
+ basesink->have_preroll = FALSE;
+ basesink->priv->step_unlock = FALSE;
+ /* can't report latency anymore until we preroll again */
+ if (basesink->priv->async_enabled) {
+ GST_OBJECT_LOCK (basesink);
+ basesink->priv->have_latency = FALSE;
+ GST_OBJECT_UNLOCK (basesink);
+ }
+ /* and signal any waiters now */
+ GST_BASE_SINK_PREROLL_SIGNAL (basesink);
}
- GST_PAD_PREROLL_UNLOCK (pad);
+ GST_BASE_SINK_PREROLL_UNLOCK (basesink);
return TRUE;
}
}
static gboolean
-gst_base_sink_pad_activate (GstPad * pad)
+gst_base_sink_pad_activate (GstPad * pad, GstObject * parent)
{
gboolean result = FALSE;
GstBaseSink *basesink;
+ GstQuery *query;
+ gboolean pull_mode;
- basesink = GST_BASE_SINK (gst_pad_get_parent (pad));
+ basesink = GST_BASE_SINK (parent);
GST_DEBUG_OBJECT (basesink, "Trying pull mode first");
}
/* check if downstreams supports pull mode at all */
- if (!gst_pad_check_pull_range (pad)) {
+ query = gst_query_new_scheduling ();
+
+ if (!gst_pad_peer_query (pad, query)) {
+ gst_query_unref (query);
+ GST_DEBUG_OBJECT (basesink, "peer query faild, no pull mode");
+ goto fallback;
+ }
+
+ /* parse result of the query */
+ pull_mode = gst_query_has_scheduling_mode (query, GST_PAD_MODE_PULL);
+ gst_query_unref (query);
+
+ if (!pull_mode) {
GST_DEBUG_OBJECT (basesink, "pull mode not supported");
goto fallback;
}
/* set the pad mode before starting the task so that it's in the
* correct state for the new thread. also the sink set_caps and get_caps
* function checks this */
- basesink->pad_mode = GST_ACTIVATE_PULL;
+ basesink->pad_mode = GST_PAD_MODE_PULL;
/* we first try to negotiate a format so that when we try to activate
* downstream, it knows about our format */
}
/* ok activate now */
- if (!gst_pad_activate_pull (pad, TRUE)) {
+ if (!gst_pad_activate_mode (pad, GST_PAD_MODE_PULL, TRUE)) {
/* clear any pending caps */
GST_OBJECT_LOCK (basesink);
- gst_caps_replace (&basesink->priv->pull_caps, NULL);
+ gst_caps_replace (&basesink->priv->caps, NULL);
GST_OBJECT_UNLOCK (basesink);
GST_DEBUG_OBJECT (basesink, "failed to activate in pull mode");
goto fallback;
/* push mode fallback */
fallback:
GST_DEBUG_OBJECT (basesink, "Falling back to push mode");
- if ((result = gst_pad_activate_push (pad, TRUE))) {
+ if ((result = gst_pad_activate_mode (pad, GST_PAD_MODE_PUSH, TRUE))) {
GST_DEBUG_OBJECT (basesink, "Success activating push mode");
}
gst_base_sink_set_flushing (basesink, pad, TRUE);
}
- gst_object_unref (basesink);
-
return result;
}
static gboolean
-gst_base_sink_pad_activate_push (GstPad * pad, gboolean active)
+gst_base_sink_pad_activate_push (GstPad * pad, GstObject * parent,
+ gboolean active)
{
gboolean result;
GstBaseSink *basesink;
- basesink = GST_BASE_SINK (gst_pad_get_parent (pad));
+ basesink = GST_BASE_SINK (parent);
if (active) {
if (!basesink->can_activate_push) {
result = FALSE;
- basesink->pad_mode = GST_ACTIVATE_NONE;
+ basesink->pad_mode = GST_PAD_MODE_NONE;
} else {
result = TRUE;
- basesink->pad_mode = GST_ACTIVATE_PUSH;
+ basesink->pad_mode = GST_PAD_MODE_PUSH;
}
} else {
- if (G_UNLIKELY (basesink->pad_mode != GST_ACTIVATE_PUSH)) {
+ if (G_UNLIKELY (basesink->pad_mode != GST_PAD_MODE_PUSH)) {
g_warning ("Internal GStreamer activation error!!!");
result = FALSE;
} else {
gst_base_sink_set_flushing (basesink, pad, TRUE);
result = TRUE;
- basesink->pad_mode = GST_ACTIVATE_NONE;
+ basesink->pad_mode = GST_PAD_MODE_NONE;
}
}
- gst_object_unref (basesink);
-
return result;
}
GST_DEBUG_OBJECT (basesink, "allowed caps: %" GST_PTR_FORMAT, caps);
- caps = gst_caps_make_writable (caps);
- /* get the first (preferred) format */
- gst_caps_truncate (caps);
- /* try to fixate */
- gst_pad_fixate_caps (GST_BASE_SINK_PAD (basesink), caps);
-
- GST_DEBUG_OBJECT (basesink, "fixated to: %" GST_PTR_FORMAT, caps);
-
if (gst_caps_is_any (caps)) {
GST_DEBUG_OBJECT (basesink, "caps were ANY after fixating, "
"allowing pull()");
/* neither side has template caps in this case, so they are prepared for
pull() without setcaps() */
result = TRUE;
- } else if (gst_caps_is_fixed (caps)) {
- if (!gst_pad_set_caps (GST_BASE_SINK_PAD (basesink), caps))
- goto could_not_set_caps;
+ } else {
+ /* try to fixate */
+ caps = gst_base_sink_fixate (basesink, caps);
+ GST_DEBUG_OBJECT (basesink, "fixated to: %" GST_PTR_FORMAT, caps);
- GST_OBJECT_LOCK (basesink);
- gst_caps_replace (&basesink->priv->pull_caps, caps);
- GST_OBJECT_UNLOCK (basesink);
+ if (gst_caps_is_fixed (caps)) {
+ if (!gst_pad_set_caps (GST_BASE_SINK_PAD (basesink), caps))
+ goto could_not_set_caps;
- result = TRUE;
+ result = TRUE;
+ }
}
gst_caps_unref (caps);
/* this won't get called until we implement an activate function */
static gboolean
-gst_base_sink_pad_activate_pull (GstPad * pad, gboolean active)
+gst_base_sink_pad_activate_pull (GstPad * pad, GstObject * parent,
+ gboolean active)
{
gboolean result = FALSE;
GstBaseSink *basesink;
GstBaseSinkClass *bclass;
- basesink = GST_BASE_SINK (gst_pad_get_parent (pad));
+ basesink = GST_BASE_SINK (parent);
bclass = GST_BASE_SINK_GET_CLASS (basesink);
if (active) {
- GstFormat format;
gint64 duration;
/* we mark we have a newsegment here because pull based
* mode works just fine without having a newsegment before the
* first buffer */
- format = GST_FORMAT_BYTES;
-
- gst_segment_init (&basesink->segment, format);
- gst_segment_init (basesink->abidata.ABI.clip_segment, format);
+ gst_segment_init (&basesink->segment, GST_FORMAT_BYTES);
GST_OBJECT_LOCK (basesink);
basesink->have_newsegment = TRUE;
GST_OBJECT_UNLOCK (basesink);
/* get the peer duration in bytes */
- result = gst_pad_query_peer_duration (pad, &format, &duration);
+ result = gst_pad_peer_query_duration (pad, GST_FORMAT_BYTES, &duration);
if (result) {
GST_DEBUG_OBJECT (basesink,
"setting duration in bytes to %" G_GINT64_FORMAT, duration);
- gst_segment_set_duration (basesink->abidata.ABI.clip_segment, format,
- duration);
- gst_segment_set_duration (&basesink->segment, format, duration);
+ basesink->segment.duration = duration;
} else {
GST_DEBUG_OBJECT (basesink, "unknown duration");
}
goto activate_failed;
} else {
- if (G_UNLIKELY (basesink->pad_mode != GST_ACTIVATE_PULL)) {
+ if (G_UNLIKELY (basesink->pad_mode != GST_PAD_MODE_PULL)) {
g_warning ("Internal GStreamer activation error!!!");
result = FALSE;
} else {
result = gst_base_sink_set_flushing (basesink, pad, TRUE);
if (bclass->activate_pull)
result &= bclass->activate_pull (basesink, FALSE);
- basesink->pad_mode = GST_ACTIVATE_NONE;
- /* clear any pending caps */
- GST_OBJECT_LOCK (basesink);
- gst_caps_replace (&basesink->priv->pull_caps, NULL);
- GST_OBJECT_UNLOCK (basesink);
+ basesink->pad_mode = GST_PAD_MODE_NONE;
}
}
- gst_object_unref (basesink);
return result;
activate_failed:
{
/* reset, as starting the thread failed */
- basesink->pad_mode = GST_ACTIVATE_NONE;
+ basesink->pad_mode = GST_PAD_MODE_NONE;
GST_ERROR_OBJECT (basesink, "subclass failed to activate in pull mode");
return FALSE;
}
}
+static gboolean
+gst_base_sink_pad_activate_mode (GstPad * pad, GstObject * parent,
+ GstPadMode mode, gboolean active)
+{
+ gboolean res;
+
+ switch (mode) {
+ case GST_PAD_MODE_PULL:
+ res = gst_base_sink_pad_activate_pull (pad, parent, active);
+ break;
+ case GST_PAD_MODE_PUSH:
+ res = gst_base_sink_pad_activate_push (pad, parent, active);
+ break;
+ default:
+ GST_LOG_OBJECT (pad, "unknown activation mode %d", mode);
+ res = FALSE;
+ break;
+ }
+ return res;
+}
+
/* send an event to our sinkpad peer. */
static gboolean
gst_base_sink_send_event (GstElement * element, GstEvent * event)
GstPad *pad;
GstBaseSink *basesink = GST_BASE_SINK (element);
gboolean forward, result = TRUE;
- GstActivateMode mode;
+ GstPadMode mode;
GST_OBJECT_LOCK (element);
/* get the pad and the scheduling mode */
}
case GST_EVENT_SEEK:
/* in pull mode we will execute the seek */
- if (mode == GST_ACTIVATE_PULL)
+ if (mode == GST_PAD_MODE_PULL)
result = gst_base_sink_perform_seek (basesink, pad, event);
break;
case GST_EVENT_STEP:
{
GstClock *clock = NULL;
gboolean res = FALSE;
- GstFormat oformat, tformat;
+ GstFormat oformat;
GstSegment *segment;
GstClockTime now, latency;
- GstClockTimeDiff base;
- gint64 time, accum, duration;
+ GstClockTimeDiff base_time;
+ gint64 time, base, duration;
gdouble rate;
gint64 last;
gboolean last_seen, with_clock, in_paused;
in_paused = TRUE;
}
- /* we don't use the clip segment in pull mode, when seeking we update the
- * main segment directly with the new segment values without it having to be
- * activated by the rendering after preroll */
- if (basesink->pad_mode == GST_ACTIVATE_PUSH)
- segment = basesink->abidata.ABI.clip_segment;
- else
- segment = &basesink->segment;
+ segment = &basesink->segment;
- /* our intermediate time format */
- tformat = GST_FORMAT_TIME;
/* get the format in the segment */
oformat = segment->format;
else
duration = 0;
- accum = segment->accum;
+ base = segment->base;
rate = segment->rate * segment->applied_rate;
latency = basesink->priv->latency;
}
} else {
/* convert last stop to stream time */
- last = gst_segment_to_stream_time (segment, oformat, segment->last_stop);
+ last = gst_segment_to_stream_time (segment, oformat, segment->position);
}
if (in_paused) {
/* in paused, use start_time */
- base = GST_ELEMENT_START_TIME (basesink);
+ base_time = GST_ELEMENT_START_TIME (basesink);
GST_DEBUG_OBJECT (basesink, "in paused, using start time %" GST_TIME_FORMAT,
- GST_TIME_ARGS (base));
+ GST_TIME_ARGS (base_time));
} else if (with_clock) {
/* else use clock when needed */
- base = GST_ELEMENT_CAST (basesink)->base_time;
+ base_time = GST_ELEMENT_CAST (basesink)->base_time;
GST_DEBUG_OBJECT (basesink, "using clock and base time %" GST_TIME_FORMAT,
- GST_TIME_ARGS (base));
+ GST_TIME_ARGS (base_time));
} else {
/* else, no sync or clock -> no base time */
GST_DEBUG_OBJECT (basesink, "no sync or no clock");
- base = -1;
+ base_time = -1;
}
- /* no base, we can't calculate running_time, use last seem timestamp to report
+ /* no base_time, we can't calculate running_time, use last seem timestamp to report
* time */
- if (base == -1)
+ if (base_time == -1)
last_seen = TRUE;
/* need to release the object lock before we can get the time,
GST_TIME_ARGS (last));
*cur = last;
} else {
- if (oformat != tformat) {
- /* convert accum, time and duration to time */
- if (!gst_pad_query_convert (basesink->sinkpad, oformat, accum, &tformat,
- &accum))
+ if (oformat != GST_FORMAT_TIME) {
+ /* convert base, time and duration to time */
+ if (!gst_pad_query_convert (basesink->sinkpad, oformat, base,
+ GST_FORMAT_TIME, &base))
goto convert_failed;
if (!gst_pad_query_convert (basesink->sinkpad, oformat, duration,
- &tformat, &duration))
+ GST_FORMAT_TIME, &duration))
goto convert_failed;
- if (!gst_pad_query_convert (basesink->sinkpad, oformat, time, &tformat,
- &time))
+ if (!gst_pad_query_convert (basesink->sinkpad, oformat, time,
+ GST_FORMAT_TIME, &time))
goto convert_failed;
- if (!gst_pad_query_convert (basesink->sinkpad, oformat, last, &tformat,
- &last))
+ if (!gst_pad_query_convert (basesink->sinkpad, oformat, last,
+ GST_FORMAT_TIME, &last))
goto convert_failed;
/* assume time format from now on */
- oformat = tformat;
+ oformat = GST_FORMAT_TIME;
}
if (!in_paused && with_clock) {
now = gst_clock_get_time (clock);
} else {
- now = base;
- base = 0;
+ now = base_time;
+ base_time = 0;
}
- /* subtract base time and accumulated time from the clock time.
+ /* subtract base time and base time from the clock time.
* Make sure we don't go negative. This is the current time in
* the segment which we need to scale with the combined
* rate and applied rate. */
- base += accum;
- base += latency;
- if (GST_CLOCK_DIFF (base, now) < 0)
- base = now;
+ base_time += base;
+ base_time += latency;
+ if (GST_CLOCK_DIFF (base_time, now) < 0)
+ base_time = now;
/* for negative rates we need to count back from the segment
* duration. */
if (rate < 0.0)
time += duration;
- *cur = time + gst_guint64_to_gdouble (now - base) * rate;
+ *cur = time + gst_guint64_to_gdouble (now - base_time) * rate;
if (in_paused) {
/* never report less than segment values in paused */
}
GST_DEBUG_OBJECT (basesink,
- "now %" GST_TIME_FORMAT " - base %" GST_TIME_FORMAT " - accum %"
+ "now %" GST_TIME_FORMAT " - base_time %" GST_TIME_FORMAT " - base %"
GST_TIME_FORMAT " + time %" GST_TIME_FORMAT " last %" GST_TIME_FORMAT,
- GST_TIME_ARGS (now), GST_TIME_ARGS (base), GST_TIME_ARGS (accum),
+ GST_TIME_ARGS (now), GST_TIME_ARGS (base_time), GST_TIME_ARGS (base),
GST_TIME_ARGS (time), GST_TIME_ARGS (last));
}
if (oformat != format) {
/* convert to final format */
- if (!gst_pad_query_convert (basesink->sinkpad, oformat, *cur, &format, cur))
+ if (!gst_pad_query_convert (basesink->sinkpad, oformat, *cur, format, cur))
goto convert_failed;
}
{
gboolean res = FALSE;
- if (basesink->pad_mode == GST_ACTIVATE_PULL) {
- GstFormat uformat = GST_FORMAT_BYTES;
+ if (basesink->pad_mode == GST_PAD_MODE_PULL) {
gint64 uduration;
/* get the duration in bytes, in pull mode that's all we are sure to
* know. We have to explicitly get this value from upstream instead of
* using our cached value because it might change. Duration caching
* should be done at a higher level. */
- res = gst_pad_query_peer_duration (basesink->sinkpad, &uformat, &uduration);
+ res =
+ gst_pad_peer_query_duration (basesink->sinkpad, GST_FORMAT_BYTES,
+ &uduration);
if (res) {
- gst_segment_set_duration (&basesink->segment, uformat, uduration);
- if (format != uformat) {
+ basesink->segment.duration = uduration;
+ if (format != GST_FORMAT_BYTES) {
/* convert to the requested format */
- res = gst_pad_query_convert (basesink->sinkpad, uformat, uduration,
- &format, dur);
+ res =
+ gst_pad_query_convert (basesink->sinkpad, GST_FORMAT_BYTES,
+ uduration, format, dur);
} else {
*dur = uduration;
}
return res;
}
-static const GstQueryType *
-gst_base_sink_get_query_types (GstElement * element)
-{
- static const GstQueryType query_types[] = {
- GST_QUERY_DURATION,
- GST_QUERY_POSITION,
- GST_QUERY_SEGMENT,
- GST_QUERY_LATENCY,
- 0
- };
-
- return query_types;
-}
-
static gboolean
default_element_query (GstElement * element, GstQuery * query)
{
/* we can handle a few things if upstream failed */
if (format == GST_FORMAT_PERCENT) {
gint64 dur = 0;
- GstFormat uformat = GST_FORMAT_TIME;
res = gst_base_sink_get_position (basesink, GST_FORMAT_TIME, &cur,
&upstream);
if (!res && upstream) {
- res = gst_pad_query_peer_position (basesink->sinkpad, &uformat,
+ res =
+ gst_pad_peer_query_position (basesink->sinkpad, GST_FORMAT_TIME,
&cur);
}
if (res) {
res = gst_base_sink_get_duration (basesink, GST_FORMAT_TIME, &dur,
&upstream);
if (!res && upstream) {
- res = gst_pad_query_peer_duration (basesink->sinkpad, &uformat,
- &dur);
+ res =
+ gst_pad_peer_query_duration (basesink->sinkpad,
+ GST_FORMAT_TIME, &dur);
}
}
if (res) {
break;
case GST_QUERY_SEGMENT:
{
- if (basesink->pad_mode == GST_ACTIVATE_PULL) {
+ if (basesink->pad_mode == GST_PAD_MODE_PULL) {
gst_query_set_segment (query, basesink->segment.rate,
GST_FORMAT_TIME, basesink->segment.start, basesink->segment.stop);
res = TRUE;
return res;
}
+
static gboolean
-default_sink_query (GstBaseSink * basesink, GstQuery * query)
+gst_base_sink_default_query (GstBaseSink * basesink, GstQuery * query)
{
- return gst_pad_query_default (basesink->sinkpad, query);
+ gboolean res;
+ GstBaseSinkClass *bclass;
+
+ bclass = GST_BASE_SINK_GET_CLASS (basesink);
+
+ switch (GST_QUERY_TYPE (query)) {
+ case GST_QUERY_ALLOCATION:
+ {
+ if (bclass->propose_allocation)
+ res = bclass->propose_allocation (basesink, query);
+ else
+ res = FALSE;
+ break;
+ }
+ case GST_QUERY_CAPS:
+ {
+ GstCaps *caps, *filter;
+
+ gst_query_parse_caps (query, &filter);
+ caps = gst_base_sink_query_caps (basesink, basesink->sinkpad, filter);
+ gst_query_set_caps_result (query, caps);
+ gst_caps_unref (caps);
+ res = TRUE;
+ break;
+ }
+ case GST_QUERY_ACCEPT_CAPS:
+ {
+ GstCaps *caps, *allowed;
+ gboolean subset;
+
+ /* slightly faster than the default implementation */
+ gst_query_parse_accept_caps (query, &caps);
+ allowed = gst_base_sink_query_caps (basesink, basesink->sinkpad, NULL);
+ subset = gst_caps_is_subset (caps, allowed);
+ gst_caps_unref (allowed);
+ gst_query_set_accept_caps_result (query, subset);
+ res = TRUE;
+ break;
+ }
+ case GST_QUERY_DRAIN:
+ res = TRUE;
+ break;
+ default:
+ res =
+ gst_pad_query_default (basesink->sinkpad, GST_OBJECT_CAST (basesink),
+ query);
+ break;
+ }
+ return res;
}
static gboolean
-gst_base_sink_sink_query (GstPad * pad, GstQuery * query)
+gst_base_sink_sink_query (GstPad * pad, GstObject * parent, GstQuery * query)
{
GstBaseSink *basesink;
GstBaseSinkClass *bclass;
gboolean res;
- basesink = GST_BASE_SINK_CAST (gst_pad_get_parent (pad));
- if (G_UNLIKELY (basesink == NULL)) {
- gst_query_unref (query);
- return FALSE;
- }
-
+ basesink = GST_BASE_SINK_CAST (parent);
bclass = GST_BASE_SINK_GET_CLASS (basesink);
if (bclass->query)
else
res = FALSE;
- gst_object_unref (basesink);
-
return res;
}
case GST_STATE_CHANGE_READY_TO_PAUSED:
/* need to complete preroll before this state change completes, there
* is no data flow in READY so we can safely assume we need to preroll. */
- GST_PAD_PREROLL_LOCK (basesink->sinkpad);
+ GST_BASE_SINK_PREROLL_LOCK (basesink);
GST_DEBUG_OBJECT (basesink, "READY to PAUSED");
basesink->have_newsegment = FALSE;
gst_segment_init (&basesink->segment, GST_FORMAT_UNDEFINED);
- gst_segment_init (basesink->abidata.ABI.clip_segment,
- GST_FORMAT_UNDEFINED);
basesink->offset = 0;
basesink->have_preroll = FALSE;
priv->step_unlock = FALSE;
* the state change function */
ret = GST_STATE_CHANGE_ASYNC;
gst_element_post_message (GST_ELEMENT_CAST (basesink),
- gst_message_new_async_start (GST_OBJECT_CAST (basesink), FALSE));
+ gst_message_new_async_start (GST_OBJECT_CAST (basesink)));
} else {
priv->have_latency = TRUE;
}
- GST_PAD_PREROLL_UNLOCK (basesink->sinkpad);
+ GST_BASE_SINK_PREROLL_UNLOCK (basesink);
break;
case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
- GST_PAD_PREROLL_LOCK (basesink->sinkpad);
+ GST_BASE_SINK_PREROLL_LOCK (basesink);
g_atomic_int_set (&basesink->priv->to_playing, TRUE);
if (!gst_base_sink_needs_preroll (basesink)) {
GST_DEBUG_OBJECT (basesink, "PAUSED to PLAYING, don't need preroll");
gst_element_post_message (GST_ELEMENT_CAST (basesink), message);
} else {
GST_DEBUG_OBJECT (basesink, "signal preroll");
- GST_PAD_PREROLL_SIGNAL (basesink->sinkpad);
+ GST_BASE_SINK_PREROLL_SIGNAL (basesink);
}
} else {
GST_DEBUG_OBJECT (basesink, "PAUSED to PLAYING, we are not prerolled");
GST_DEBUG_OBJECT (basesink, "doing async state change");
ret = GST_STATE_CHANGE_ASYNC;
gst_element_post_message (GST_ELEMENT_CAST (basesink),
- gst_message_new_async_start (GST_OBJECT_CAST (basesink), FALSE));
+ gst_message_new_async_start (GST_OBJECT_CAST (basesink)));
}
}
- GST_PAD_PREROLL_UNLOCK (basesink->sinkpad);
+ GST_BASE_SINK_PREROLL_UNLOCK (basesink);
break;
default:
break;
if (bclass->unlock)
bclass->unlock (basesink);
- GST_PAD_PREROLL_LOCK (basesink->sinkpad);
+ GST_BASE_SINK_PREROLL_LOCK (basesink);
GST_DEBUG_OBJECT (basesink, "got preroll lock");
/* now that we have the PREROLL lock, clear our unlock request */
if (bclass->unlock_stop)
GST_DEBUG_OBJECT (basesink, "doing async state change");
ret = GST_STATE_CHANGE_ASYNC;
gst_element_post_message (GST_ELEMENT_CAST (basesink),
- gst_message_new_async_start (GST_OBJECT_CAST (basesink),
- FALSE));
+ gst_message_new_async_start (GST_OBJECT_CAST (basesink)));
}
}
}
", dropped: %" G_GUINT64_FORMAT, priv->rendered, priv->dropped);
gst_base_sink_reset_qos (basesink);
- GST_PAD_PREROLL_UNLOCK (basesink->sinkpad);
+ GST_BASE_SINK_PREROLL_UNLOCK (basesink);
break;
case GST_STATE_CHANGE_PAUSED_TO_READY:
- GST_PAD_PREROLL_LOCK (basesink->sinkpad);
+ GST_BASE_SINK_PREROLL_LOCK (basesink);
/* start by resetting our position state with the object lock so that the
* position query gets the right idea. We do this before we post the
* messages so that the message handlers pick this up. */
gst_clock_id_unref (priv->cached_clock_id);
priv->cached_clock_id = NULL;
}
+ gst_caps_replace (&basesink->priv->caps, NULL);
GST_OBJECT_UNLOCK (basesink);
gst_base_sink_set_last_buffer (basesink, NULL);
GST_STATE_PLAYING, GST_STATE_PAUSED, GST_STATE_READY));
gst_element_post_message (GST_ELEMENT_CAST (basesink),
- gst_message_new_async_done (GST_OBJECT_CAST (basesink)));
+ gst_message_new_async_done (GST_OBJECT_CAST (basesink), FALSE));
}
priv->commited = TRUE;
} else {
GST_DEBUG_OBJECT (basesink, "PAUSED to READY, don't need_preroll");
}
- GST_PAD_PREROLL_UNLOCK (basesink->sinkpad);
+ GST_BASE_SINK_PREROLL_UNLOCK (basesink);
break;
case GST_STATE_CHANGE_READY_TO_NULL:
if (bclass->stop) {