+2005-08-26 Andy Wingo <wingo@pobox.com>
+
+ * check/pipelines/simple_launch_lines.c (run_pipeline): Check
+ element_set_state's return val.
+ (test_2_elements): Add test that's been disabled for months.
+
+ * gst/elements/gstfakesink.c: Cleanups. Add can-activate-push and
+ can-activate-pull properties.
+
+ * gst/elements/gstfakesrc.c: Cleanups. Add can-activate-push and
+ can-activate-pull properties. Implement is_seekable so fakesrc can
+ operate in pull mode.
+
+ * gst/base/gstbasesink.c (GstBaseSink): Remove has-loop, has-chain
+ properties.
+ (gst_base_sink_activate, gst_base_sink_activate_pull)
+ (gst_base_sink_activate_push): Make activation mode choosing work.
+ Cleanups.
+ (gst_base_sink_chain, gst_base_sink_loop): Assert activation mode
+ is right. Make pull mode work. Post an eos before pausing in pull
+ mode.
+ (gst_base_sink_change_state): Pay attention to the core's
+ change_state() return val.
+
+ * gst/base/gstbasesrc.c (GstBaseSrc): Remove has-loop,
+ has-getrange properties. Cleanups.
+
+ * gst/base/gstbasesrc.h (GstBaseSrc): Remove has_loop,
+ has_getrange and replace with can_activate_pull and
+ can_activate_push.
+
+ * gst/base/gstbasesink.h (GstBaseSink): Rearrange fields, add
+ locking comments. Remove has_loop, has_chain and replace with
+ can_activate_pull and can_activate_push.
+
2005-08-26 Jan Schmidt <thaytan@mad.scientist.com>
* configure.ac:
bus = gst_element_get_bus (pipe);
g_assert (bus);
- gst_element_set_state (pipe, GST_STATE_PLAYING);
+ if (gst_element_set_state (pipe, GST_STATE_PLAYING) != GST_STATE_SUCCESS) {
+ g_critical ("Couldn't set pipeline to PLAYING");
+ goto done;
+ }
while (1) {
revent = gst_bus_poll (bus, GST_MESSAGE_ANY, GST_SECOND / 2);
revent, tevent, descr);
}
+done:
gst_element_set_state (pipe, GST_STATE_NULL);
gst_object_unref (pipe);
}
{
gchar *s;
- /* has-loop got unimplemented at some point, so these aren't actually testing
- * what they're supposed to -- a big ol' FIXME */
-
- s = "fakesrc has-loop=false ! fakesink has-loop=true";
+ s = "fakesrc can-activate-push=false ! fakesink can-activate-pull=true";
run_pipeline (setup_pipeline (s), s,
GST_MESSAGE_STATE_CHANGED, GST_MESSAGE_UNKNOWN);
- s = "fakesrc has-loop=true ! fakesink has-loop=false";
+ s = "fakesrc can-activate-push=true ! fakesink can-activate-pull=false";
run_pipeline (setup_pipeline (s), s,
GST_MESSAGE_STATE_CHANGED, GST_MESSAGE_UNKNOWN);
- s = "fakesrc has-loop=false num-buffers=10 ! fakesink has-loop=true";
+ s = "fakesrc can-activate-push=false num-buffers=10 ! fakesink can-activate-pull=true";
run_pipeline (setup_pipeline (s), s,
GST_MESSAGE_STATE_CHANGED, GST_MESSAGE_EOS);
- s = "fakesrc has-loop=true num-buffers=10 ! fakesink has-loop=false";
+ s = "fakesrc can-activate-push=true num-buffers=10 ! fakesink can-activate-pull=false";
run_pipeline (setup_pipeline (s), s,
GST_MESSAGE_STATE_CHANGED, GST_MESSAGE_EOS);
- /* Should raise a critical, but doesn't with has-loop not working
- s = "fakesrc has-loop=false ! fakesink has-loop=false";
- ASSERT_CRITICAL (run_pipeline (setup_pipeline (s), s,
- GST_MESSAGE_STATE_CHANGED, GST_MESSAGE_UNKNOWN)); */
+ s = "fakesrc can-activate-push=false ! fakesink can-activate-pull=false";
+ ASSERT_CRITICAL (run_pipeline (setup_pipeline (s), s,
+ GST_MESSAGE_STATE_CHANGED, GST_MESSAGE_UNKNOWN));
}
GST_END_TEST static void
got_handoff (GstElement * sink, GstBuffer * buf, GstPad * pad, gpointer unused)
LAST_SIGNAL
};
-/* FIXME, need to figure out a better way to handle the pull mode */
#define DEFAULT_SIZE 1024
-#define DEFAULT_HAS_LOOP FALSE
-#define DEFAULT_HAS_CHAIN TRUE
+#define DEFAULT_CAN_ACTIVATE_PULL FALSE /* fixme: enable me */
+#define DEFAULT_CAN_ACTIVATE_PUSH TRUE
enum
{
PROP_0,
- PROP_HAS_LOOP,
- PROP_HAS_CHAIN,
PROP_PREROLL_QUEUE_LEN
};
static GstFlowReturn gst_base_sink_chain (GstPad * pad, GstBuffer * buffer);
static void gst_base_sink_loop (GstPad * pad);
-static GstFlowReturn gst_base_sink_chain (GstPad * pad, GstBuffer * buffer);
+static gboolean gst_base_sink_activate (GstPad * pad);
static gboolean gst_base_sink_activate_push (GstPad * pad, gboolean active);
static gboolean gst_base_sink_activate_pull (GstPad * pad, gboolean active);
static gboolean gst_base_sink_event (GstPad * pad, GstEvent * event);
gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_base_sink_set_property);
gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_base_sink_get_property);
- g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_HAS_LOOP,
- g_param_spec_boolean ("has-loop", "has-loop",
- "Enable loop-based operation", DEFAULT_HAS_LOOP,
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
- g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_HAS_CHAIN,
- g_param_spec_boolean ("has-chain", "has-chain",
- "Enable chain-based operation", DEFAULT_HAS_CHAIN,
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
/* FIXME, this next value should be configured using an event from the
* upstream element */
g_object_class_install_property (G_OBJECT_CLASS (klass),
GST_DEBUG_FUNCPTR (gst_base_sink_pad_setcaps));
gst_pad_set_bufferalloc_function (basesink->sinkpad,
GST_DEBUG_FUNCPTR (gst_base_sink_pad_buffer_alloc));
+ gst_pad_set_activate_function (basesink->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_base_sink_activate));
+ gst_pad_set_activatepush_function (basesink->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_base_sink_activate_push));
+ gst_pad_set_activatepull_function (basesink->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_base_sink_activate_pull));
+ gst_pad_set_event_function (basesink->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_base_sink_event));
+ gst_pad_set_chain_function (basesink->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_base_sink_chain));
gst_element_add_pad (GST_ELEMENT (basesink), basesink->sinkpad);
basesink->pad_mode = GST_ACTIVATE_NONE;
GST_PAD_TASK (basesink->sinkpad) = NULL;
basesink->preroll_queue = g_queue_new ();
+ basesink->can_activate_push = DEFAULT_CAN_ACTIVATE_PUSH;
+ basesink->can_activate_pull = DEFAULT_CAN_ACTIVATE_PULL;
+
GST_FLAG_SET (basesink, GST_ELEMENT_IS_SINK);
}
}
static void
-gst_base_sink_set_pad_functions (GstBaseSink * this, GstPad * pad)
-{
- gst_pad_set_activatepush_function (pad,
- GST_DEBUG_FUNCPTR (gst_base_sink_activate_push));
- gst_pad_set_activatepull_function (pad,
- GST_DEBUG_FUNCPTR (gst_base_sink_activate_pull));
- gst_pad_set_event_function (pad, GST_DEBUG_FUNCPTR (gst_base_sink_event));
-
- if (this->has_chain)
- gst_pad_set_chain_function (pad, GST_DEBUG_FUNCPTR (gst_base_sink_chain));
- else
- gst_pad_set_chain_function (pad, NULL);
-}
-
-static void
-gst_base_sink_set_all_pad_functions (GstBaseSink * this)
-{
- GList *l;
-
- for (l = GST_ELEMENT_PADS (this); l; l = l->next)
- gst_base_sink_set_pad_functions (this, (GstPad *) l->data);
-}
-
-static void
gst_base_sink_set_clock (GstElement * element, GstClock * clock)
{
GstBaseSink *sink;
gst_base_sink_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
- GstBaseSink *sink;
-
- sink = GST_BASE_SINK (object);
+ GstBaseSink *sink = GST_BASE_SINK (object);
switch (prop_id) {
- case PROP_HAS_LOOP:
- GST_LOCK (sink);
- sink->has_loop = g_value_get_boolean (value);
- gst_base_sink_set_all_pad_functions (sink);
- GST_UNLOCK (sink);
- break;
- case PROP_HAS_CHAIN:
- GST_LOCK (sink);
- sink->has_chain = g_value_get_boolean (value);
- gst_base_sink_set_all_pad_functions (sink);
- GST_UNLOCK (sink);
- break;
case PROP_PREROLL_QUEUE_LEN:
/* preroll lock necessary to serialize with finish_preroll */
GST_PREROLL_LOCK (sink->sinkpad);
gst_base_sink_get_property (GObject * object, guint prop_id, GValue * value,
GParamSpec * pspec)
{
- GstBaseSink *sink;
-
- sink = GST_BASE_SINK (object);
+ GstBaseSink *sink = GST_BASE_SINK (object);
GST_LOCK (sink);
switch (prop_id) {
- case PROP_HAS_LOOP:
- g_value_set_boolean (value, sink->has_loop);
- break;
- case PROP_HAS_CHAIN:
- g_value_set_boolean (value, sink->has_chain);
- break;
case PROP_PREROLL_QUEUE_LEN:
g_value_set_uint (value, sink->preroll_queue_max_len);
break;
basesink = GST_BASE_SINK (gst_pad_get_parent (pad));
+ if (!(basesink->pad_mode == GST_ACTIVATE_PUSH)) {
+ GST_LOCK (pad);
+ g_warning ("Push on pad %s:%s, but it was not activated in push mode",
+ GST_DEBUG_PAD_NAME (pad));
+ GST_UNLOCK (pad);
+ result = GST_FLOW_UNEXPECTED;
+ goto done;
+ }
+
result = gst_base_sink_handle_object (basesink, pad, GST_MINI_OBJECT (buf));
+done:
gst_object_unref (basesink);
return result;
}
-/* FIXME, not all sinks can operate in pull mode
- */
static void
gst_base_sink_loop (GstPad * pad)
{
if (result != GST_FLOW_OK)
goto paused;
- result = gst_base_sink_chain (pad, buf);
+ result = gst_base_sink_handle_object (basesink, pad, GST_MINI_OBJECT (buf));
if (result != GST_FLOW_OK)
goto paused;
paused:
{
+ gst_base_sink_event (pad, gst_event_new_eos ());
gst_object_unref (basesink);
gst_pad_pause_task (pad);
return;
}
static gboolean
-gst_base_sink_activate_push (GstPad * pad, gboolean active)
+gst_base_sink_activate (GstPad * pad)
{
gboolean result = FALSE;
GstBaseSink *basesink;
basesink = GST_BASE_SINK (gst_pad_get_parent (pad));
- if (active) {
- if (!basesink->has_chain)
- goto done;
+ GST_DEBUG_OBJECT (basesink, "Trying pull mode first");
+
+ if (basesink->can_activate_pull && gst_pad_check_pull_range (pad)
+ && gst_pad_activate_pull (pad, TRUE)) {
+ GST_DEBUG_OBJECT (basesink, "Success activating pull mode");
result = TRUE;
} else {
- result = gst_base_sink_deactivate (basesink, pad);
+ GST_DEBUG_OBJECT (basesink, "Falling back to push mode");
+ if (gst_pad_activate_push (pad, TRUE)) {
+ GST_DEBUG_OBJECT (basesink, "Success activating push mode");
+ result = TRUE;
+ }
+ }
+
+ if (!result) {
+ GST_WARNING_OBJECT (basesink, "Could not activate pad in either mode");
+ }
+
+ gst_object_unref (basesink);
+
+ return result;
+}
+
+static gboolean
+gst_base_sink_activate_push (GstPad * pad, gboolean active)
+{
+ gboolean result;
+ GstBaseSink *basesink;
+
+ basesink = GST_BASE_SINK (gst_pad_get_parent (pad));
+
+ if (active) {
+ if (!basesink->can_activate_push) {
+ result = FALSE;
+ basesink->pad_mode = GST_ACTIVATE_NONE;
+ } else {
+ result = TRUE;
+ basesink->pad_mode = GST_ACTIVATE_PUSH;
+ }
+ } else {
+ if (G_UNLIKELY (basesink->pad_mode != GST_ACTIVATE_PUSH)) {
+ g_warning ("Internal GStreamer activation error!!!");
+ result = FALSE;
+ } else {
+ result = gst_base_sink_deactivate (basesink, pad);
+ basesink->pad_mode = GST_ACTIVATE_NONE;
+ }
}
- basesink->pad_mode = GST_ACTIVATE_PUSH;
-done:
gst_object_unref (basesink);
return result;
basesink = GST_BASE_SINK (gst_pad_get_parent (pad));
if (active) {
- /* if we have a scheduler we can start the task */
- if (!basesink->has_loop)
- goto done;
- result =
- gst_pad_start_task (pad, (GstTaskFunction) gst_base_sink_loop, pad);
+ if (!basesink->can_activate_pull) {
+ result = FALSE;
+ basesink->pad_mode = GST_ACTIVATE_NONE;
+ } else {
+ GstPad *peer = gst_pad_get_peer (pad);
+
+ if (G_UNLIKELY (peer == NULL)) {
+ g_warning ("Trying to activate pad in pull mode, but no peer");
+ result = FALSE;
+ } else {
+ if (gst_pad_activate_pull (peer, TRUE)) {
+ basesink->have_newsegment = TRUE;
+ basesink->segment_start = basesink->segment_stop = 0;
+ result =
+ gst_pad_start_task (pad, (GstTaskFunction) gst_base_sink_loop,
+ pad);
+ } else {
+ GST_DEBUG_OBJECT (pad, "Failed to activate peer in pull mode");
+ result = FALSE;
+ }
+ gst_object_unref (peer);
+ }
+
+ basesink->pad_mode = result ? GST_ACTIVATE_PULL : GST_ACTIVATE_NONE;
+ }
} else {
- result = gst_base_sink_deactivate (basesink, pad);
+ if (G_UNLIKELY (basesink->pad_mode != GST_ACTIVATE_PULL)) {
+ g_warning ("Internal GStreamer activation error!!!");
+ result = FALSE;
+ } else {
+ basesink->have_newsegment = FALSE;
+ result = gst_base_sink_deactivate (basesink, pad);
+ basesink->pad_mode = GST_ACTIVATE_NONE;
+ }
}
-done:
+
gst_object_unref (basesink);
return result;
break;
}
- GST_ELEMENT_CLASS (parent_class)->change_state (element);
+ {
+ GstElementStateReturn bret;
+
+ bret = GST_ELEMENT_CLASS (parent_class)->change_state (element);
+
+ if (bret != GST_STATE_SUCCESS)
+ goto activate_failed;
+ }
switch (transition) {
case GST_STATE_PLAYING_TO_PAUSED:
GST_DEBUG ("failed to start");
return GST_STATE_FAILURE;
}
+activate_failed:
+ {
+ GST_DEBUG ("element failed to change states -- activation problem?");
+ return GST_STATE_FAILURE;
+ }
}
struct _GstBaseSink {
GstElement element;
+ /*< protected >*/
GstPad *sinkpad;
GstActivateMode pad_mode;
+ /*< protected >*/ /* with LOCK */
+ guint64 offset;
+ gboolean can_activate_pull;
+ gboolean can_activate_push;
+
/*< protected >*/ /* with PREROLL_LOCK */
GQueue *preroll_queue;
gint preroll_queue_max_len;
gint preroll_queued;
gint buffers_queued;
gint events_queued;
+ gboolean eos;
+ gboolean need_preroll;
+ gboolean have_preroll;
+ gboolean playing_async;
- guint64 offset;
- gboolean has_loop;
- gboolean has_chain;
-
- GstClock *clock;
- GstClockID clock_id;
- GstClockTime end_time;
-
+ /*< protected >*/ /* with STREAM_LOCK */
gboolean have_newsegment;
-
gdouble segment_rate;
gint64 segment_start;
gint64 segment_stop;
gint64 segment_base;
- gboolean eos;
- gboolean need_preroll;
- gboolean have_preroll;
- gboolean playing_async;
+ /*< private >*/ /* with LOCK */
+ GstClock *clock;
+ GstClockID clock_id;
+ GstClockTime end_time;
/*< private >*/
gpointer _gst_reserved[GST_PADDING];
{
PROP_0,
PROP_BLOCKSIZE,
- PROP_HAS_LOOP,
- PROP_HAS_GETRANGE,
PROP_NUM_BUFFERS,
};
static GstElementStateReturn gst_base_src_change_state (GstElement * element);
-static void gst_base_src_set_dataflow_funcs (GstBaseSrc * this);
static void gst_base_src_loop (GstPad * pad);
static gboolean gst_base_src_check_get_range (GstPad * pad);
static GstFlowReturn gst_base_src_get_range (GstPad * pad, guint64 offset,
"Size in bytes to read per buffer", 1, G_MAXULONG, DEFAULT_BLOCKSIZE,
G_PARAM_READWRITE));
- g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_HAS_LOOP,
- g_param_spec_boolean ("has-loop", "Has loop function",
- "True if the element should expose a loop function", TRUE,
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
-
- g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_HAS_GETRANGE,
- g_param_spec_boolean ("has-getrange", "Has getrange function",
- "True if the element should expose a getrange function", TRUE,
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
-
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_NUM_BUFFERS,
g_param_spec_int ("num-buffers", "num-buffers",
"Number of buffers to output before sending EOS", -1, G_MAXINT,
basesrc->num_buffers = DEFAULT_NUM_BUFFERS;
basesrc->num_buffers_left = -1;
+ basesrc->can_activate_push = TRUE;
+ basesrc->pad_mode = GST_ACTIVATE_NONE;
+
pad_template =
gst_element_class_get_pad_template (GST_ELEMENT_CLASS (g_class), "src");
g_return_if_fail (pad_template != NULL);
gst_pad_set_event_function (pad, gst_base_src_event_handler);
gst_pad_set_query_function (pad, gst_base_src_query);
gst_pad_set_checkgetrange_function (pad, gst_base_src_check_get_range);
+ gst_pad_set_getrange_function (pad, gst_base_src_get_range);
gst_pad_set_getcaps_function (pad, gst_base_src_getcaps);
gst_pad_set_setcaps_function (pad, gst_base_src_setcaps);
return result;
}
-static void
-gst_base_src_set_dataflow_funcs (GstBaseSrc * this)
-{
- GST_DEBUG ("updating dataflow functions");
-
- if (this->has_getrange)
- gst_pad_set_getrange_function (this->srcpad, gst_base_src_get_range);
- else
- gst_pad_set_getrange_function (this->srcpad, NULL);
-}
-
static gboolean
gst_base_src_setcaps (GstPad * pad, GstCaps * caps)
{
case PROP_BLOCKSIZE:
src->blocksize = g_value_get_ulong (value);
break;
- case PROP_HAS_LOOP:
- src->has_loop = g_value_get_boolean (value);
- gst_base_src_set_dataflow_funcs (src);
- break;
- case PROP_HAS_GETRANGE:
- src->has_getrange = g_value_get_boolean (value);
- gst_base_src_set_dataflow_funcs (src);
- break;
case PROP_NUM_BUFFERS:
src->num_buffers = g_value_get_int (value);
break;
case PROP_BLOCKSIZE:
g_value_set_ulong (value, src->blocksize);
break;
- case PROP_HAS_LOOP:
- g_value_set_boolean (value, src->has_loop);
- break;
- case PROP_HAS_GETRANGE:
- g_value_set_boolean (value, src->has_getrange);
- break;
case PROP_NUM_BUFFERS:
g_value_set_int (value, src->num_buffers);
break;
/* prepare subclass first */
if (active) {
GST_DEBUG_OBJECT (basesrc, "Activating in push mode");
+
+ if (!basesrc->can_activate_push)
+ goto no_push_activation;
+
if (!gst_base_src_start (basesrc))
goto error_start;
return gst_base_src_deactivate (basesrc, pad);
}
+no_push_activation:
+ {
+ GST_DEBUG_OBJECT (basesrc, "Subclass disabled push-mode activation");
+ return FALSE;
+ }
error_start:
{
gst_base_src_stop (basesrc);
/* MT-protected (with LOCK) */
gint blocksize; /* size of buffers when operating push based */
- gboolean has_loop; /* some scheduling properties */
- gboolean has_getrange;
+ gboolean can_activate_push; /* some scheduling properties */
+ GstActivateMode pad_mode;
gboolean seekable;
gboolean random_access;
#define DEFAULT_SYNC FALSE
#define DEFAULT_SIGNAL_HANDOFFS FALSE
#define DEFAULT_LAST_MESSAGE NULL
+#define DEFAULT_LAST_MESSAGE NULL
+#define DEFAULT_CAN_ACTIVATE_PUSH TRUE
+#define DEFAULT_CAN_ACTIVATE_PULL FALSE
enum
{
- ARG_0,
- ARG_STATE_ERROR,
- ARG_SILENT,
- ARG_DUMP,
- ARG_SYNC,
- ARG_SIGNAL_HANDOFFS,
- ARG_LAST_MESSAGE,
+ PROP_0,
+ PROP_STATE_ERROR,
+ PROP_SILENT,
+ PROP_DUMP,
+ PROP_SYNC,
+ PROP_SIGNAL_HANDOFFS,
+ PROP_LAST_MESSAGE,
+ PROP_CAN_ACTIVATE_PUSH,
+ PROP_CAN_ACTIVATE_PULL
};
#define GST_TYPE_FAKE_SINK_STATE_ERROR (gst_fake_sink_state_error_get_type())
gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_fake_sink_set_property);
gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_fake_sink_get_property);
- g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_STATE_ERROR,
+ g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_STATE_ERROR,
g_param_spec_enum ("state_error", "State Error",
"Generate a state change error", GST_TYPE_FAKE_SINK_STATE_ERROR,
DEFAULT_STATE_ERROR, G_PARAM_READWRITE));
- g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LAST_MESSAGE,
+ g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_LAST_MESSAGE,
g_param_spec_string ("last_message", "Last Message",
"The message describing current status", DEFAULT_LAST_MESSAGE,
G_PARAM_READABLE));
- g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SYNC,
+ g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SYNC,
g_param_spec_boolean ("sync", "Sync", "Sync on the clock", DEFAULT_SYNC,
G_PARAM_READWRITE));
- g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SIGNAL_HANDOFFS,
+ g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SIGNAL_HANDOFFS,
g_param_spec_boolean ("signal-handoffs", "Signal handoffs",
"Send a signal before unreffing the buffer", DEFAULT_SIGNAL_HANDOFFS,
G_PARAM_READWRITE));
- g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SILENT,
+ g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SILENT,
g_param_spec_boolean ("silent", "Silent",
"Don't produce last_message events", DEFAULT_SILENT,
G_PARAM_READWRITE));
- g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_DUMP,
+ g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_DUMP,
g_param_spec_boolean ("dump", "Dump", "Dump received bytes to stdout",
DEFAULT_DUMP, G_PARAM_READWRITE));
+ g_object_class_install_property (G_OBJECT_CLASS (klass),
+ PROP_CAN_ACTIVATE_PUSH,
+ g_param_spec_boolean ("can-activate-push", "Can activate push",
+ "Can activate in push mode", DEFAULT_CAN_ACTIVATE_PUSH,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (G_OBJECT_CLASS (klass),
+ PROP_CAN_ACTIVATE_PULL,
+ g_param_spec_boolean ("can-activate-pull", "Can activate pull",
+ "Can activate in pull mode", DEFAULT_CAN_ACTIVATE_PULL,
+ G_PARAM_READWRITE));
/**
* GstFakeSink::handoff:
sink = GST_FAKE_SINK (object);
switch (prop_id) {
- case ARG_SILENT:
+ case PROP_SILENT:
sink->silent = g_value_get_boolean (value);
break;
- case ARG_STATE_ERROR:
+ case PROP_STATE_ERROR:
sink->state_error = g_value_get_enum (value);
break;
- case ARG_DUMP:
+ case PROP_DUMP:
sink->dump = g_value_get_boolean (value);
break;
- case ARG_SYNC:
+ case PROP_SYNC:
sink->sync = g_value_get_boolean (value);
break;
- case ARG_SIGNAL_HANDOFFS:
+ case PROP_SIGNAL_HANDOFFS:
sink->signal_handoffs = g_value_get_boolean (value);
break;
+ case PROP_CAN_ACTIVATE_PUSH:
+ GST_BASE_SINK (sink)->can_activate_push = g_value_get_boolean (value);
+ break;
+ case PROP_CAN_ACTIVATE_PULL:
+ GST_BASE_SINK (sink)->can_activate_pull = g_value_get_boolean (value);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
sink = GST_FAKE_SINK (object);
switch (prop_id) {
- case ARG_STATE_ERROR:
+ case PROP_STATE_ERROR:
g_value_set_enum (value, sink->state_error);
break;
- case ARG_SILENT:
+ case PROP_SILENT:
g_value_set_boolean (value, sink->silent);
break;
- case ARG_DUMP:
+ case PROP_DUMP:
g_value_set_boolean (value, sink->dump);
break;
- case ARG_SYNC:
+ case PROP_SYNC:
g_value_set_boolean (value, sink->sync);
break;
- case ARG_SIGNAL_HANDOFFS:
+ case PROP_SIGNAL_HANDOFFS:
g_value_set_boolean (value, sink->signal_handoffs);
break;
- case ARG_LAST_MESSAGE:
+ case PROP_LAST_MESSAGE:
g_value_set_string (value, sink->last_message);
break;
+ case PROP_CAN_ACTIVATE_PUSH:
+ g_value_set_boolean (value, GST_BASE_SINK (sink)->can_activate_push);
+ break;
+ case PROP_CAN_ACTIVATE_PULL:
+ g_value_set_boolean (value, GST_BASE_SINK (sink)->can_activate_pull);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
#define DEFAULT_SILENT FALSE
#define DEFAULT_DUMP FALSE
#define DEFAULT_PARENTSIZE 4096*10
+#define DEFAULT_CAN_ACTIVATE_PULL TRUE
+#define DEFAULT_CAN_ACTIVATE_PUSH TRUE
enum
{
PROP_DUMP,
PROP_PARENTSIZE,
PROP_LAST_MESSAGE,
- PROP_HAS_LOOP,
- PROP_HAS_GETRANGE,
+ PROP_CAN_ACTIVATE_PULL,
+ PROP_CAN_ACTIVATE_PUSH,
PROP_IS_LIVE
};
static gboolean gst_fake_src_start (GstBaseSrc * basesrc);
static gboolean gst_fake_src_stop (GstBaseSrc * basesrc);
+static gboolean gst_fake_src_is_seekable (GstBaseSrc * basesrc);
static gboolean gst_fake_src_event_handler (GstBaseSrc * src, GstEvent * event);
static GstFlowReturn gst_fake_src_create (GstBaseSrc * src, guint64 offset,
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_DUMP,
g_param_spec_boolean ("dump", "Dump", "Dump produced bytes to stdout",
DEFAULT_DUMP, G_PARAM_READWRITE));
- g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_HAS_LOOP,
- g_param_spec_boolean ("has-loop", "Has loop function",
- "True if the element exposes a loop function", TRUE,
+ g_object_class_install_property (G_OBJECT_CLASS (klass),
+ PROP_CAN_ACTIVATE_PUSH,
+ g_param_spec_boolean ("can-activate-push", "Can activate push",
+ "Can activate in push mode", DEFAULT_CAN_ACTIVATE_PUSH,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
- g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_HAS_GETRANGE,
- g_param_spec_boolean ("has-getrange", "Has getrange function",
- "True if the element exposes a getrange function", TRUE,
+ g_object_class_install_property (G_OBJECT_CLASS (klass),
+ PROP_CAN_ACTIVATE_PULL,
+ g_param_spec_boolean ("can-activate-pull", "Can activate pull",
+ "Can activate in pull mode", DEFAULT_CAN_ACTIVATE_PULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_IS_LIVE,
g_param_spec_boolean ("is-live", "Is this a live source",
gst_marshal_VOID__OBJECT_OBJECT, G_TYPE_NONE, 2, GST_TYPE_BUFFER,
GST_TYPE_PAD);
- /*gstbase_src_class->is_seekable = GST_DEBUG_FUNCPTR (gst_fake_src_is_seekable); */
+ gstbase_src_class->is_seekable = GST_DEBUG_FUNCPTR (gst_fake_src_is_seekable);
gstbase_src_class->start = GST_DEBUG_FUNCPTR (gst_fake_src_start);
gstbase_src_class->stop = GST_DEBUG_FUNCPTR (gst_fake_src_stop);
gstbase_src_class->event = GST_DEBUG_FUNCPTR (gst_fake_src_event_handler);
case PROP_DUMP:
src->dump = g_value_get_boolean (value);
break;
- case PROP_HAS_LOOP:
+ case PROP_CAN_ACTIVATE_PUSH:
g_return_if_fail (!GST_FLAG_IS_SET (object, GST_BASE_SRC_STARTED));
- src->has_loop = g_value_get_boolean (value);
+ GST_BASE_SRC (src)->can_activate_push = g_value_get_boolean (value);
break;
- case PROP_HAS_GETRANGE:
+ case PROP_CAN_ACTIVATE_PULL:
g_return_if_fail (!GST_FLAG_IS_SET (object, GST_BASE_SRC_STARTED));
- src->has_getrange = g_value_get_boolean (value);
+ src->can_activate_pull = g_value_get_boolean (value);
break;
case PROP_IS_LIVE:
gst_base_src_set_live (basesrc, g_value_get_boolean (value));
case PROP_LAST_MESSAGE:
g_value_set_string (value, src->last_message);
break;
- case PROP_HAS_LOOP:
- g_value_set_boolean (value, src->has_loop);
+ case PROP_CAN_ACTIVATE_PUSH:
+ g_value_set_boolean (value, GST_BASE_SRC (src)->can_activate_push);
break;
- case PROP_HAS_GETRANGE:
- g_value_set_boolean (value, src->has_getrange);
+ case PROP_CAN_ACTIVATE_PULL:
+ g_value_set_boolean (value, src->can_activate_pull);
break;
case PROP_IS_LIVE:
g_value_set_boolean (value, gst_base_src_is_live (basesrc));
return TRUE;
}
+
+static gboolean
+gst_fake_src_is_seekable (GstBaseSrc * basesrc)
+{
+ GstFakeSrc *src = GST_FAKE_SRC (basesrc);
+
+ return src->can_activate_pull;
+}
gboolean silent;
gboolean signal_handoffs;
gboolean dump;
+ gboolean can_activate_pull;
guint64 bytes_sent;
LAST_SIGNAL
};
-/* FIXME, need to figure out a better way to handle the pull mode */
#define DEFAULT_SIZE 1024
-#define DEFAULT_HAS_LOOP FALSE
-#define DEFAULT_HAS_CHAIN TRUE
+#define DEFAULT_CAN_ACTIVATE_PULL FALSE /* fixme: enable me */
+#define DEFAULT_CAN_ACTIVATE_PUSH TRUE
enum
{
PROP_0,
- PROP_HAS_LOOP,
- PROP_HAS_CHAIN,
PROP_PREROLL_QUEUE_LEN
};
static GstFlowReturn gst_base_sink_chain (GstPad * pad, GstBuffer * buffer);
static void gst_base_sink_loop (GstPad * pad);
-static GstFlowReturn gst_base_sink_chain (GstPad * pad, GstBuffer * buffer);
+static gboolean gst_base_sink_activate (GstPad * pad);
static gboolean gst_base_sink_activate_push (GstPad * pad, gboolean active);
static gboolean gst_base_sink_activate_pull (GstPad * pad, gboolean active);
static gboolean gst_base_sink_event (GstPad * pad, GstEvent * event);
gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_base_sink_set_property);
gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_base_sink_get_property);
- g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_HAS_LOOP,
- g_param_spec_boolean ("has-loop", "has-loop",
- "Enable loop-based operation", DEFAULT_HAS_LOOP,
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
- g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_HAS_CHAIN,
- g_param_spec_boolean ("has-chain", "has-chain",
- "Enable chain-based operation", DEFAULT_HAS_CHAIN,
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
/* FIXME, this next value should be configured using an event from the
* upstream element */
g_object_class_install_property (G_OBJECT_CLASS (klass),
GST_DEBUG_FUNCPTR (gst_base_sink_pad_setcaps));
gst_pad_set_bufferalloc_function (basesink->sinkpad,
GST_DEBUG_FUNCPTR (gst_base_sink_pad_buffer_alloc));
+ gst_pad_set_activate_function (basesink->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_base_sink_activate));
+ gst_pad_set_activatepush_function (basesink->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_base_sink_activate_push));
+ gst_pad_set_activatepull_function (basesink->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_base_sink_activate_pull));
+ gst_pad_set_event_function (basesink->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_base_sink_event));
+ gst_pad_set_chain_function (basesink->sinkpad,
+ GST_DEBUG_FUNCPTR (gst_base_sink_chain));
gst_element_add_pad (GST_ELEMENT (basesink), basesink->sinkpad);
basesink->pad_mode = GST_ACTIVATE_NONE;
GST_PAD_TASK (basesink->sinkpad) = NULL;
basesink->preroll_queue = g_queue_new ();
+ basesink->can_activate_push = DEFAULT_CAN_ACTIVATE_PUSH;
+ basesink->can_activate_pull = DEFAULT_CAN_ACTIVATE_PULL;
+
GST_FLAG_SET (basesink, GST_ELEMENT_IS_SINK);
}
}
static void
-gst_base_sink_set_pad_functions (GstBaseSink * this, GstPad * pad)
-{
- gst_pad_set_activatepush_function (pad,
- GST_DEBUG_FUNCPTR (gst_base_sink_activate_push));
- gst_pad_set_activatepull_function (pad,
- GST_DEBUG_FUNCPTR (gst_base_sink_activate_pull));
- gst_pad_set_event_function (pad, GST_DEBUG_FUNCPTR (gst_base_sink_event));
-
- if (this->has_chain)
- gst_pad_set_chain_function (pad, GST_DEBUG_FUNCPTR (gst_base_sink_chain));
- else
- gst_pad_set_chain_function (pad, NULL);
-}
-
-static void
-gst_base_sink_set_all_pad_functions (GstBaseSink * this)
-{
- GList *l;
-
- for (l = GST_ELEMENT_PADS (this); l; l = l->next)
- gst_base_sink_set_pad_functions (this, (GstPad *) l->data);
-}
-
-static void
gst_base_sink_set_clock (GstElement * element, GstClock * clock)
{
GstBaseSink *sink;
gst_base_sink_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
- GstBaseSink *sink;
-
- sink = GST_BASE_SINK (object);
+ GstBaseSink *sink = GST_BASE_SINK (object);
switch (prop_id) {
- case PROP_HAS_LOOP:
- GST_LOCK (sink);
- sink->has_loop = g_value_get_boolean (value);
- gst_base_sink_set_all_pad_functions (sink);
- GST_UNLOCK (sink);
- break;
- case PROP_HAS_CHAIN:
- GST_LOCK (sink);
- sink->has_chain = g_value_get_boolean (value);
- gst_base_sink_set_all_pad_functions (sink);
- GST_UNLOCK (sink);
- break;
case PROP_PREROLL_QUEUE_LEN:
/* preroll lock necessary to serialize with finish_preroll */
GST_PREROLL_LOCK (sink->sinkpad);
gst_base_sink_get_property (GObject * object, guint prop_id, GValue * value,
GParamSpec * pspec)
{
- GstBaseSink *sink;
-
- sink = GST_BASE_SINK (object);
+ GstBaseSink *sink = GST_BASE_SINK (object);
GST_LOCK (sink);
switch (prop_id) {
- case PROP_HAS_LOOP:
- g_value_set_boolean (value, sink->has_loop);
- break;
- case PROP_HAS_CHAIN:
- g_value_set_boolean (value, sink->has_chain);
- break;
case PROP_PREROLL_QUEUE_LEN:
g_value_set_uint (value, sink->preroll_queue_max_len);
break;
basesink = GST_BASE_SINK (gst_pad_get_parent (pad));
+ if (!(basesink->pad_mode == GST_ACTIVATE_PUSH)) {
+ GST_LOCK (pad);
+ g_warning ("Push on pad %s:%s, but it was not activated in push mode",
+ GST_DEBUG_PAD_NAME (pad));
+ GST_UNLOCK (pad);
+ result = GST_FLOW_UNEXPECTED;
+ goto done;
+ }
+
result = gst_base_sink_handle_object (basesink, pad, GST_MINI_OBJECT (buf));
+done:
gst_object_unref (basesink);
return result;
}
-/* FIXME, not all sinks can operate in pull mode
- */
static void
gst_base_sink_loop (GstPad * pad)
{
if (result != GST_FLOW_OK)
goto paused;
- result = gst_base_sink_chain (pad, buf);
+ result = gst_base_sink_handle_object (basesink, pad, GST_MINI_OBJECT (buf));
if (result != GST_FLOW_OK)
goto paused;
paused:
{
+ gst_base_sink_event (pad, gst_event_new_eos ());
gst_object_unref (basesink);
gst_pad_pause_task (pad);
return;
}
static gboolean
-gst_base_sink_activate_push (GstPad * pad, gboolean active)
+gst_base_sink_activate (GstPad * pad)
{
gboolean result = FALSE;
GstBaseSink *basesink;
basesink = GST_BASE_SINK (gst_pad_get_parent (pad));
- if (active) {
- if (!basesink->has_chain)
- goto done;
+ GST_DEBUG_OBJECT (basesink, "Trying pull mode first");
+
+ if (basesink->can_activate_pull && gst_pad_check_pull_range (pad)
+ && gst_pad_activate_pull (pad, TRUE)) {
+ GST_DEBUG_OBJECT (basesink, "Success activating pull mode");
result = TRUE;
} else {
- result = gst_base_sink_deactivate (basesink, pad);
+ GST_DEBUG_OBJECT (basesink, "Falling back to push mode");
+ if (gst_pad_activate_push (pad, TRUE)) {
+ GST_DEBUG_OBJECT (basesink, "Success activating push mode");
+ result = TRUE;
+ }
+ }
+
+ if (!result) {
+ GST_WARNING_OBJECT (basesink, "Could not activate pad in either mode");
+ }
+
+ gst_object_unref (basesink);
+
+ return result;
+}
+
+static gboolean
+gst_base_sink_activate_push (GstPad * pad, gboolean active)
+{
+ gboolean result;
+ GstBaseSink *basesink;
+
+ basesink = GST_BASE_SINK (gst_pad_get_parent (pad));
+
+ if (active) {
+ if (!basesink->can_activate_push) {
+ result = FALSE;
+ basesink->pad_mode = GST_ACTIVATE_NONE;
+ } else {
+ result = TRUE;
+ basesink->pad_mode = GST_ACTIVATE_PUSH;
+ }
+ } else {
+ if (G_UNLIKELY (basesink->pad_mode != GST_ACTIVATE_PUSH)) {
+ g_warning ("Internal GStreamer activation error!!!");
+ result = FALSE;
+ } else {
+ result = gst_base_sink_deactivate (basesink, pad);
+ basesink->pad_mode = GST_ACTIVATE_NONE;
+ }
}
- basesink->pad_mode = GST_ACTIVATE_PUSH;
-done:
gst_object_unref (basesink);
return result;
basesink = GST_BASE_SINK (gst_pad_get_parent (pad));
if (active) {
- /* if we have a scheduler we can start the task */
- if (!basesink->has_loop)
- goto done;
- result =
- gst_pad_start_task (pad, (GstTaskFunction) gst_base_sink_loop, pad);
+ if (!basesink->can_activate_pull) {
+ result = FALSE;
+ basesink->pad_mode = GST_ACTIVATE_NONE;
+ } else {
+ GstPad *peer = gst_pad_get_peer (pad);
+
+ if (G_UNLIKELY (peer == NULL)) {
+ g_warning ("Trying to activate pad in pull mode, but no peer");
+ result = FALSE;
+ } else {
+ if (gst_pad_activate_pull (peer, TRUE)) {
+ basesink->have_newsegment = TRUE;
+ basesink->segment_start = basesink->segment_stop = 0;
+ result =
+ gst_pad_start_task (pad, (GstTaskFunction) gst_base_sink_loop,
+ pad);
+ } else {
+ GST_DEBUG_OBJECT (pad, "Failed to activate peer in pull mode");
+ result = FALSE;
+ }
+ gst_object_unref (peer);
+ }
+
+ basesink->pad_mode = result ? GST_ACTIVATE_PULL : GST_ACTIVATE_NONE;
+ }
} else {
- result = gst_base_sink_deactivate (basesink, pad);
+ if (G_UNLIKELY (basesink->pad_mode != GST_ACTIVATE_PULL)) {
+ g_warning ("Internal GStreamer activation error!!!");
+ result = FALSE;
+ } else {
+ basesink->have_newsegment = FALSE;
+ result = gst_base_sink_deactivate (basesink, pad);
+ basesink->pad_mode = GST_ACTIVATE_NONE;
+ }
}
-done:
+
gst_object_unref (basesink);
return result;
break;
}
- GST_ELEMENT_CLASS (parent_class)->change_state (element);
+ {
+ GstElementStateReturn bret;
+
+ bret = GST_ELEMENT_CLASS (parent_class)->change_state (element);
+
+ if (bret != GST_STATE_SUCCESS)
+ goto activate_failed;
+ }
switch (transition) {
case GST_STATE_PLAYING_TO_PAUSED:
GST_DEBUG ("failed to start");
return GST_STATE_FAILURE;
}
+activate_failed:
+ {
+ GST_DEBUG ("element failed to change states -- activation problem?");
+ return GST_STATE_FAILURE;
+ }
}
struct _GstBaseSink {
GstElement element;
+ /*< protected >*/
GstPad *sinkpad;
GstActivateMode pad_mode;
+ /*< protected >*/ /* with LOCK */
+ guint64 offset;
+ gboolean can_activate_pull;
+ gboolean can_activate_push;
+
/*< protected >*/ /* with PREROLL_LOCK */
GQueue *preroll_queue;
gint preroll_queue_max_len;
gint preroll_queued;
gint buffers_queued;
gint events_queued;
+ gboolean eos;
+ gboolean need_preroll;
+ gboolean have_preroll;
+ gboolean playing_async;
- guint64 offset;
- gboolean has_loop;
- gboolean has_chain;
-
- GstClock *clock;
- GstClockID clock_id;
- GstClockTime end_time;
-
+ /*< protected >*/ /* with STREAM_LOCK */
gboolean have_newsegment;
-
gdouble segment_rate;
gint64 segment_start;
gint64 segment_stop;
gint64 segment_base;
- gboolean eos;
- gboolean need_preroll;
- gboolean have_preroll;
- gboolean playing_async;
+ /*< private >*/ /* with LOCK */
+ GstClock *clock;
+ GstClockID clock_id;
+ GstClockTime end_time;
/*< private >*/
gpointer _gst_reserved[GST_PADDING];
{
PROP_0,
PROP_BLOCKSIZE,
- PROP_HAS_LOOP,
- PROP_HAS_GETRANGE,
PROP_NUM_BUFFERS,
};
static GstElementStateReturn gst_base_src_change_state (GstElement * element);
-static void gst_base_src_set_dataflow_funcs (GstBaseSrc * this);
static void gst_base_src_loop (GstPad * pad);
static gboolean gst_base_src_check_get_range (GstPad * pad);
static GstFlowReturn gst_base_src_get_range (GstPad * pad, guint64 offset,
"Size in bytes to read per buffer", 1, G_MAXULONG, DEFAULT_BLOCKSIZE,
G_PARAM_READWRITE));
- g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_HAS_LOOP,
- g_param_spec_boolean ("has-loop", "Has loop function",
- "True if the element should expose a loop function", TRUE,
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
-
- g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_HAS_GETRANGE,
- g_param_spec_boolean ("has-getrange", "Has getrange function",
- "True if the element should expose a getrange function", TRUE,
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
-
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_NUM_BUFFERS,
g_param_spec_int ("num-buffers", "num-buffers",
"Number of buffers to output before sending EOS", -1, G_MAXINT,
basesrc->num_buffers = DEFAULT_NUM_BUFFERS;
basesrc->num_buffers_left = -1;
+ basesrc->can_activate_push = TRUE;
+ basesrc->pad_mode = GST_ACTIVATE_NONE;
+
pad_template =
gst_element_class_get_pad_template (GST_ELEMENT_CLASS (g_class), "src");
g_return_if_fail (pad_template != NULL);
gst_pad_set_event_function (pad, gst_base_src_event_handler);
gst_pad_set_query_function (pad, gst_base_src_query);
gst_pad_set_checkgetrange_function (pad, gst_base_src_check_get_range);
+ gst_pad_set_getrange_function (pad, gst_base_src_get_range);
gst_pad_set_getcaps_function (pad, gst_base_src_getcaps);
gst_pad_set_setcaps_function (pad, gst_base_src_setcaps);
return result;
}
-static void
-gst_base_src_set_dataflow_funcs (GstBaseSrc * this)
-{
- GST_DEBUG ("updating dataflow functions");
-
- if (this->has_getrange)
- gst_pad_set_getrange_function (this->srcpad, gst_base_src_get_range);
- else
- gst_pad_set_getrange_function (this->srcpad, NULL);
-}
-
static gboolean
gst_base_src_setcaps (GstPad * pad, GstCaps * caps)
{
case PROP_BLOCKSIZE:
src->blocksize = g_value_get_ulong (value);
break;
- case PROP_HAS_LOOP:
- src->has_loop = g_value_get_boolean (value);
- gst_base_src_set_dataflow_funcs (src);
- break;
- case PROP_HAS_GETRANGE:
- src->has_getrange = g_value_get_boolean (value);
- gst_base_src_set_dataflow_funcs (src);
- break;
case PROP_NUM_BUFFERS:
src->num_buffers = g_value_get_int (value);
break;
case PROP_BLOCKSIZE:
g_value_set_ulong (value, src->blocksize);
break;
- case PROP_HAS_LOOP:
- g_value_set_boolean (value, src->has_loop);
- break;
- case PROP_HAS_GETRANGE:
- g_value_set_boolean (value, src->has_getrange);
- break;
case PROP_NUM_BUFFERS:
g_value_set_int (value, src->num_buffers);
break;
/* prepare subclass first */
if (active) {
GST_DEBUG_OBJECT (basesrc, "Activating in push mode");
+
+ if (!basesrc->can_activate_push)
+ goto no_push_activation;
+
if (!gst_base_src_start (basesrc))
goto error_start;
return gst_base_src_deactivate (basesrc, pad);
}
+no_push_activation:
+ {
+ GST_DEBUG_OBJECT (basesrc, "Subclass disabled push-mode activation");
+ return FALSE;
+ }
error_start:
{
gst_base_src_stop (basesrc);
/* MT-protected (with LOCK) */
gint blocksize; /* size of buffers when operating push based */
- gboolean has_loop; /* some scheduling properties */
- gboolean has_getrange;
+ gboolean can_activate_push; /* some scheduling properties */
+ GstActivateMode pad_mode;
gboolean seekable;
gboolean random_access;
#define DEFAULT_SYNC FALSE
#define DEFAULT_SIGNAL_HANDOFFS FALSE
#define DEFAULT_LAST_MESSAGE NULL
+#define DEFAULT_LAST_MESSAGE NULL
+#define DEFAULT_CAN_ACTIVATE_PUSH TRUE
+#define DEFAULT_CAN_ACTIVATE_PULL FALSE
enum
{
- ARG_0,
- ARG_STATE_ERROR,
- ARG_SILENT,
- ARG_DUMP,
- ARG_SYNC,
- ARG_SIGNAL_HANDOFFS,
- ARG_LAST_MESSAGE,
+ PROP_0,
+ PROP_STATE_ERROR,
+ PROP_SILENT,
+ PROP_DUMP,
+ PROP_SYNC,
+ PROP_SIGNAL_HANDOFFS,
+ PROP_LAST_MESSAGE,
+ PROP_CAN_ACTIVATE_PUSH,
+ PROP_CAN_ACTIVATE_PULL
};
#define GST_TYPE_FAKE_SINK_STATE_ERROR (gst_fake_sink_state_error_get_type())
gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_fake_sink_set_property);
gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_fake_sink_get_property);
- g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_STATE_ERROR,
+ g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_STATE_ERROR,
g_param_spec_enum ("state_error", "State Error",
"Generate a state change error", GST_TYPE_FAKE_SINK_STATE_ERROR,
DEFAULT_STATE_ERROR, G_PARAM_READWRITE));
- g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LAST_MESSAGE,
+ g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_LAST_MESSAGE,
g_param_spec_string ("last_message", "Last Message",
"The message describing current status", DEFAULT_LAST_MESSAGE,
G_PARAM_READABLE));
- g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SYNC,
+ g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SYNC,
g_param_spec_boolean ("sync", "Sync", "Sync on the clock", DEFAULT_SYNC,
G_PARAM_READWRITE));
- g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SIGNAL_HANDOFFS,
+ g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SIGNAL_HANDOFFS,
g_param_spec_boolean ("signal-handoffs", "Signal handoffs",
"Send a signal before unreffing the buffer", DEFAULT_SIGNAL_HANDOFFS,
G_PARAM_READWRITE));
- g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SILENT,
+ g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SILENT,
g_param_spec_boolean ("silent", "Silent",
"Don't produce last_message events", DEFAULT_SILENT,
G_PARAM_READWRITE));
- g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_DUMP,
+ g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_DUMP,
g_param_spec_boolean ("dump", "Dump", "Dump received bytes to stdout",
DEFAULT_DUMP, G_PARAM_READWRITE));
+ g_object_class_install_property (G_OBJECT_CLASS (klass),
+ PROP_CAN_ACTIVATE_PUSH,
+ g_param_spec_boolean ("can-activate-push", "Can activate push",
+ "Can activate in push mode", DEFAULT_CAN_ACTIVATE_PUSH,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (G_OBJECT_CLASS (klass),
+ PROP_CAN_ACTIVATE_PULL,
+ g_param_spec_boolean ("can-activate-pull", "Can activate pull",
+ "Can activate in pull mode", DEFAULT_CAN_ACTIVATE_PULL,
+ G_PARAM_READWRITE));
/**
* GstFakeSink::handoff:
sink = GST_FAKE_SINK (object);
switch (prop_id) {
- case ARG_SILENT:
+ case PROP_SILENT:
sink->silent = g_value_get_boolean (value);
break;
- case ARG_STATE_ERROR:
+ case PROP_STATE_ERROR:
sink->state_error = g_value_get_enum (value);
break;
- case ARG_DUMP:
+ case PROP_DUMP:
sink->dump = g_value_get_boolean (value);
break;
- case ARG_SYNC:
+ case PROP_SYNC:
sink->sync = g_value_get_boolean (value);
break;
- case ARG_SIGNAL_HANDOFFS:
+ case PROP_SIGNAL_HANDOFFS:
sink->signal_handoffs = g_value_get_boolean (value);
break;
+ case PROP_CAN_ACTIVATE_PUSH:
+ GST_BASE_SINK (sink)->can_activate_push = g_value_get_boolean (value);
+ break;
+ case PROP_CAN_ACTIVATE_PULL:
+ GST_BASE_SINK (sink)->can_activate_pull = g_value_get_boolean (value);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
sink = GST_FAKE_SINK (object);
switch (prop_id) {
- case ARG_STATE_ERROR:
+ case PROP_STATE_ERROR:
g_value_set_enum (value, sink->state_error);
break;
- case ARG_SILENT:
+ case PROP_SILENT:
g_value_set_boolean (value, sink->silent);
break;
- case ARG_DUMP:
+ case PROP_DUMP:
g_value_set_boolean (value, sink->dump);
break;
- case ARG_SYNC:
+ case PROP_SYNC:
g_value_set_boolean (value, sink->sync);
break;
- case ARG_SIGNAL_HANDOFFS:
+ case PROP_SIGNAL_HANDOFFS:
g_value_set_boolean (value, sink->signal_handoffs);
break;
- case ARG_LAST_MESSAGE:
+ case PROP_LAST_MESSAGE:
g_value_set_string (value, sink->last_message);
break;
+ case PROP_CAN_ACTIVATE_PUSH:
+ g_value_set_boolean (value, GST_BASE_SINK (sink)->can_activate_push);
+ break;
+ case PROP_CAN_ACTIVATE_PULL:
+ g_value_set_boolean (value, GST_BASE_SINK (sink)->can_activate_pull);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
#define DEFAULT_SILENT FALSE
#define DEFAULT_DUMP FALSE
#define DEFAULT_PARENTSIZE 4096*10
+#define DEFAULT_CAN_ACTIVATE_PULL TRUE
+#define DEFAULT_CAN_ACTIVATE_PUSH TRUE
enum
{
PROP_DUMP,
PROP_PARENTSIZE,
PROP_LAST_MESSAGE,
- PROP_HAS_LOOP,
- PROP_HAS_GETRANGE,
+ PROP_CAN_ACTIVATE_PULL,
+ PROP_CAN_ACTIVATE_PUSH,
PROP_IS_LIVE
};
static gboolean gst_fake_src_start (GstBaseSrc * basesrc);
static gboolean gst_fake_src_stop (GstBaseSrc * basesrc);
+static gboolean gst_fake_src_is_seekable (GstBaseSrc * basesrc);
static gboolean gst_fake_src_event_handler (GstBaseSrc * src, GstEvent * event);
static GstFlowReturn gst_fake_src_create (GstBaseSrc * src, guint64 offset,
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_DUMP,
g_param_spec_boolean ("dump", "Dump", "Dump produced bytes to stdout",
DEFAULT_DUMP, G_PARAM_READWRITE));
- g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_HAS_LOOP,
- g_param_spec_boolean ("has-loop", "Has loop function",
- "True if the element exposes a loop function", TRUE,
+ g_object_class_install_property (G_OBJECT_CLASS (klass),
+ PROP_CAN_ACTIVATE_PUSH,
+ g_param_spec_boolean ("can-activate-push", "Can activate push",
+ "Can activate in push mode", DEFAULT_CAN_ACTIVATE_PUSH,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
- g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_HAS_GETRANGE,
- g_param_spec_boolean ("has-getrange", "Has getrange function",
- "True if the element exposes a getrange function", TRUE,
+ g_object_class_install_property (G_OBJECT_CLASS (klass),
+ PROP_CAN_ACTIVATE_PULL,
+ g_param_spec_boolean ("can-activate-pull", "Can activate pull",
+ "Can activate in pull mode", DEFAULT_CAN_ACTIVATE_PULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_IS_LIVE,
g_param_spec_boolean ("is-live", "Is this a live source",
gst_marshal_VOID__OBJECT_OBJECT, G_TYPE_NONE, 2, GST_TYPE_BUFFER,
GST_TYPE_PAD);
- /*gstbase_src_class->is_seekable = GST_DEBUG_FUNCPTR (gst_fake_src_is_seekable); */
+ gstbase_src_class->is_seekable = GST_DEBUG_FUNCPTR (gst_fake_src_is_seekable);
gstbase_src_class->start = GST_DEBUG_FUNCPTR (gst_fake_src_start);
gstbase_src_class->stop = GST_DEBUG_FUNCPTR (gst_fake_src_stop);
gstbase_src_class->event = GST_DEBUG_FUNCPTR (gst_fake_src_event_handler);
case PROP_DUMP:
src->dump = g_value_get_boolean (value);
break;
- case PROP_HAS_LOOP:
+ case PROP_CAN_ACTIVATE_PUSH:
g_return_if_fail (!GST_FLAG_IS_SET (object, GST_BASE_SRC_STARTED));
- src->has_loop = g_value_get_boolean (value);
+ GST_BASE_SRC (src)->can_activate_push = g_value_get_boolean (value);
break;
- case PROP_HAS_GETRANGE:
+ case PROP_CAN_ACTIVATE_PULL:
g_return_if_fail (!GST_FLAG_IS_SET (object, GST_BASE_SRC_STARTED));
- src->has_getrange = g_value_get_boolean (value);
+ src->can_activate_pull = g_value_get_boolean (value);
break;
case PROP_IS_LIVE:
gst_base_src_set_live (basesrc, g_value_get_boolean (value));
case PROP_LAST_MESSAGE:
g_value_set_string (value, src->last_message);
break;
- case PROP_HAS_LOOP:
- g_value_set_boolean (value, src->has_loop);
+ case PROP_CAN_ACTIVATE_PUSH:
+ g_value_set_boolean (value, GST_BASE_SRC (src)->can_activate_push);
break;
- case PROP_HAS_GETRANGE:
- g_value_set_boolean (value, src->has_getrange);
+ case PROP_CAN_ACTIVATE_PULL:
+ g_value_set_boolean (value, src->can_activate_pull);
break;
case PROP_IS_LIVE:
g_value_set_boolean (value, gst_base_src_is_live (basesrc));
return TRUE;
}
+
+static gboolean
+gst_fake_src_is_seekable (GstBaseSrc * basesrc)
+{
+ GstFakeSrc *src = GST_FAKE_SRC (basesrc);
+
+ return src->can_activate_pull;
+}
gboolean silent;
gboolean signal_handoffs;
gboolean dump;
+ gboolean can_activate_pull;
guint64 bytes_sent;
bus = gst_element_get_bus (pipe);
g_assert (bus);
- gst_element_set_state (pipe, GST_STATE_PLAYING);
+ if (gst_element_set_state (pipe, GST_STATE_PLAYING) != GST_STATE_SUCCESS) {
+ g_critical ("Couldn't set pipeline to PLAYING");
+ goto done;
+ }
while (1) {
revent = gst_bus_poll (bus, GST_MESSAGE_ANY, GST_SECOND / 2);
revent, tevent, descr);
}
+done:
gst_element_set_state (pipe, GST_STATE_NULL);
gst_object_unref (pipe);
}
{
gchar *s;
- /* has-loop got unimplemented at some point, so these aren't actually testing
- * what they're supposed to -- a big ol' FIXME */
-
- s = "fakesrc has-loop=false ! fakesink has-loop=true";
+ s = "fakesrc can-activate-push=false ! fakesink can-activate-pull=true";
run_pipeline (setup_pipeline (s), s,
GST_MESSAGE_STATE_CHANGED, GST_MESSAGE_UNKNOWN);
- s = "fakesrc has-loop=true ! fakesink has-loop=false";
+ s = "fakesrc can-activate-push=true ! fakesink can-activate-pull=false";
run_pipeline (setup_pipeline (s), s,
GST_MESSAGE_STATE_CHANGED, GST_MESSAGE_UNKNOWN);
- s = "fakesrc has-loop=false num-buffers=10 ! fakesink has-loop=true";
+ s = "fakesrc can-activate-push=false num-buffers=10 ! fakesink can-activate-pull=true";
run_pipeline (setup_pipeline (s), s,
GST_MESSAGE_STATE_CHANGED, GST_MESSAGE_EOS);
- s = "fakesrc has-loop=true num-buffers=10 ! fakesink has-loop=false";
+ s = "fakesrc can-activate-push=true num-buffers=10 ! fakesink can-activate-pull=false";
run_pipeline (setup_pipeline (s), s,
GST_MESSAGE_STATE_CHANGED, GST_MESSAGE_EOS);
- /* Should raise a critical, but doesn't with has-loop not working
- s = "fakesrc has-loop=false ! fakesink has-loop=false";
- ASSERT_CRITICAL (run_pipeline (setup_pipeline (s), s,
- GST_MESSAGE_STATE_CHANGED, GST_MESSAGE_UNKNOWN)); */
+ s = "fakesrc can-activate-push=false ! fakesink can-activate-pull=false";
+ ASSERT_CRITICAL (run_pipeline (setup_pipeline (s), s,
+ GST_MESSAGE_STATE_CHANGED, GST_MESSAGE_UNKNOWN));
}
GST_END_TEST static void
got_handoff (GstElement * sink, GstBuffer * buf, GstPad * pad, gpointer unused)