check/pipelines/simple_launch_lines.c (run_pipeline): Check element_set_state's retur...
authorAndy Wingo <wingo@pobox.com>
Fri, 26 Aug 2005 14:21:43 +0000 (14:21 +0000)
committerAndy Wingo <wingo@pobox.com>
Fri, 26 Aug 2005 14:21:43 +0000 (14:21 +0000)
Original commit message from CVS:
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.

17 files changed:
ChangeLog
check/pipelines/simple_launch_lines.c
gst/base/gstbasesink.c
gst/base/gstbasesink.h
gst/base/gstbasesrc.c
gst/base/gstbasesrc.h
gst/elements/gstfakesink.c
gst/elements/gstfakesrc.c
gst/elements/gstfakesrc.h
libs/gst/base/gstbasesink.c
libs/gst/base/gstbasesink.h
libs/gst/base/gstbasesrc.c
libs/gst/base/gstbasesrc.h
plugins/elements/gstfakesink.c
plugins/elements/gstfakesrc.c
plugins/elements/gstfakesrc.h
tests/check/pipelines/simple-launch-lines.c

index aabd60e..5e11bc9 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,38 @@
+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:
index 618d3a5..19726fd 100644 (file)
@@ -45,7 +45,10 @@ run_pipeline (GstElement * pipe, gchar * descr,
 
   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);
@@ -67,6 +70,7 @@ run_pipeline (GstElement * pipe, gchar * descr,
         revent, tevent, descr);
   }
 
+done:
   gst_element_set_state (pipe, GST_STATE_NULL);
   gst_object_unref (pipe);
 }
@@ -75,29 +79,25 @@ GST_START_TEST (test_2_elements)
 {
   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)
index 1dd5d6c..78dc662 100644 (file)
@@ -54,16 +54,13 @@ enum
   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
 };
 
@@ -116,7 +113,7 @@ static GstElementStateReturn gst_base_sink_change_state (GstElement * element);
 
 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);
@@ -147,14 +144,6 @@ gst_base_sink_class_init (GstBaseSinkClass * klass)
   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),
@@ -255,12 +244,25 @@ gst_base_sink_init (GstBaseSink * basesink, gpointer g_class)
       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);
 }
 
@@ -277,30 +279,6 @@ gst_base_sink_finalize (GObject * object)
 }
 
 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;
@@ -314,23 +292,9 @@ static void
 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);
@@ -347,18 +311,10 @@ static void
 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;
@@ -1037,15 +993,23 @@ gst_base_sink_chain (GstPad * pad, GstBuffer * buf)
 
   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)
 {
@@ -1061,7 +1025,7 @@ 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;
 
@@ -1072,6 +1036,7 @@ gst_base_sink_loop (GstPad * pad)
 
 paused:
   {
+    gst_base_sink_event (pad, gst_event_new_eos ());
     gst_object_unref (basesink);
     gst_pad_pause_task (pad);
     return;
@@ -1111,23 +1076,62 @@ gst_base_sink_deactivate (GstBaseSink * basesink, GstPad * pad)
 }
 
 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;
@@ -1143,15 +1147,42 @@ gst_base_sink_activate_pull (GstPad * pad, gboolean active)
   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;
@@ -1216,7 +1247,14 @@ gst_base_sink_change_state (GstElement * element)
       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:
@@ -1270,4 +1308,9 @@ start_failed:
     GST_DEBUG ("failed to start");
     return GST_STATE_FAILURE;
   }
+activate_failed:
+  {
+    GST_DEBUG ("element failed to change states -- activation problem?");
+    return GST_STATE_FAILURE;
+  }
 }
index 1364d3c..6b677b3 100644 (file)
@@ -56,35 +56,37 @@ typedef struct _GstBaseSinkClass GstBaseSinkClass;
 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];
index b1abb15..fb94452 100644 (file)
@@ -68,8 +68,6 @@ enum
 {
   PROP_0,
   PROP_BLOCKSIZE,
-  PROP_HAS_LOOP,
-  PROP_HAS_GETRANGE,
   PROP_NUM_BUFFERS,
 };
 
@@ -129,7 +127,6 @@ static gboolean gst_base_src_stop (GstBaseSrc * basesrc);
 
 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,
@@ -161,16 +158,6 @@ gst_base_src_class_init (GstBaseSrcClass * klass)
           "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,
@@ -194,6 +181,9 @@ gst_base_src_init (GstBaseSrc * basesrc, gpointer g_class)
   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);
@@ -205,6 +195,7 @@ gst_base_src_init (GstBaseSrc * basesrc, gpointer g_class)
   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);
 
@@ -270,17 +261,6 @@ gst_base_src_is_live (GstBaseSrc * src)
   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)
 {
@@ -540,14 +520,6 @@ gst_base_src_set_property (GObject * object, guint prop_id,
     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;
@@ -569,12 +541,6 @@ gst_base_src_get_property (GObject * object, guint prop_id, GValue * value,
     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;
@@ -1008,6 +974,10 @@ gst_base_src_activate_push (GstPad * pad, gboolean active)
   /* 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;
 
@@ -1017,6 +987,11 @@ gst_base_src_activate_push (GstPad * pad, gboolean active)
     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);
index af12dbf..b26e345 100644 (file)
@@ -78,8 +78,8 @@ struct _GstBaseSrc {
 
   /* 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;
 
index 4262d8a..30e046a 100644 (file)
@@ -64,16 +64,21 @@ enum
 #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())
@@ -152,28 +157,38 @@ gst_fake_sink_class_init (GstFakeSinkClass * klass)
   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:
@@ -218,21 +233,27 @@ gst_fake_sink_set_property (GObject * object, guint prop_id,
   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;
@@ -248,24 +269,30 @@ gst_fake_sink_get_property (GObject * object, guint prop_id, GValue * value,
   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;
index bb939d3..c0e5edf 100644 (file)
@@ -74,6 +74,8 @@ enum
 #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
 {
@@ -93,8 +95,8 @@ 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
 };
 
@@ -196,6 +198,7 @@ static void gst_fake_src_get_property (GObject * object, guint prop_id,
 
 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,
@@ -280,13 +283,15 @@ gst_fake_src_class_init (GstFakeSrcClass * klass)
   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",
@@ -307,7 +312,7 @@ gst_fake_src_class_init (GstFakeSrcClass * klass)
       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);
@@ -430,13 +435,13 @@ gst_fake_src_set_property (GObject * object, guint prop_id,
     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));
@@ -502,11 +507,11 @@ gst_fake_src_get_property (GObject * object, guint prop_id, GValue * 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));
@@ -744,3 +749,11 @@ gst_fake_src_stop (GstBaseSrc * basesrc)
 
   return TRUE;
 }
+
+static gboolean
+gst_fake_src_is_seekable (GstBaseSrc * basesrc)
+{
+  GstFakeSrc *src = GST_FAKE_SRC (basesrc);
+
+  return src->can_activate_pull;
+}
index 71fc7bc..84fb0cc 100644 (file)
@@ -105,6 +105,7 @@ struct _GstFakeSrc {
   gboolean      silent;
   gboolean      signal_handoffs;
   gboolean      dump;
+  gboolean      can_activate_pull;
 
   guint64        bytes_sent;
 
index 1dd5d6c..78dc662 100644 (file)
@@ -54,16 +54,13 @@ enum
   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
 };
 
@@ -116,7 +113,7 @@ static GstElementStateReturn gst_base_sink_change_state (GstElement * element);
 
 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);
@@ -147,14 +144,6 @@ gst_base_sink_class_init (GstBaseSinkClass * klass)
   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),
@@ -255,12 +244,25 @@ gst_base_sink_init (GstBaseSink * basesink, gpointer g_class)
       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);
 }
 
@@ -277,30 +279,6 @@ gst_base_sink_finalize (GObject * object)
 }
 
 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;
@@ -314,23 +292,9 @@ static void
 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);
@@ -347,18 +311,10 @@ static void
 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;
@@ -1037,15 +993,23 @@ gst_base_sink_chain (GstPad * pad, GstBuffer * buf)
 
   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)
 {
@@ -1061,7 +1025,7 @@ 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;
 
@@ -1072,6 +1036,7 @@ gst_base_sink_loop (GstPad * pad)
 
 paused:
   {
+    gst_base_sink_event (pad, gst_event_new_eos ());
     gst_object_unref (basesink);
     gst_pad_pause_task (pad);
     return;
@@ -1111,23 +1076,62 @@ gst_base_sink_deactivate (GstBaseSink * basesink, GstPad * pad)
 }
 
 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;
@@ -1143,15 +1147,42 @@ gst_base_sink_activate_pull (GstPad * pad, gboolean active)
   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;
@@ -1216,7 +1247,14 @@ gst_base_sink_change_state (GstElement * element)
       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:
@@ -1270,4 +1308,9 @@ start_failed:
     GST_DEBUG ("failed to start");
     return GST_STATE_FAILURE;
   }
+activate_failed:
+  {
+    GST_DEBUG ("element failed to change states -- activation problem?");
+    return GST_STATE_FAILURE;
+  }
 }
index 1364d3c..6b677b3 100644 (file)
@@ -56,35 +56,37 @@ typedef struct _GstBaseSinkClass GstBaseSinkClass;
 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];
index b1abb15..fb94452 100644 (file)
@@ -68,8 +68,6 @@ enum
 {
   PROP_0,
   PROP_BLOCKSIZE,
-  PROP_HAS_LOOP,
-  PROP_HAS_GETRANGE,
   PROP_NUM_BUFFERS,
 };
 
@@ -129,7 +127,6 @@ static gboolean gst_base_src_stop (GstBaseSrc * basesrc);
 
 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,
@@ -161,16 +158,6 @@ gst_base_src_class_init (GstBaseSrcClass * klass)
           "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,
@@ -194,6 +181,9 @@ gst_base_src_init (GstBaseSrc * basesrc, gpointer g_class)
   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);
@@ -205,6 +195,7 @@ gst_base_src_init (GstBaseSrc * basesrc, gpointer g_class)
   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);
 
@@ -270,17 +261,6 @@ gst_base_src_is_live (GstBaseSrc * src)
   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)
 {
@@ -540,14 +520,6 @@ gst_base_src_set_property (GObject * object, guint prop_id,
     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;
@@ -569,12 +541,6 @@ gst_base_src_get_property (GObject * object, guint prop_id, GValue * value,
     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;
@@ -1008,6 +974,10 @@ gst_base_src_activate_push (GstPad * pad, gboolean active)
   /* 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;
 
@@ -1017,6 +987,11 @@ gst_base_src_activate_push (GstPad * pad, gboolean active)
     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);
index af12dbf..b26e345 100644 (file)
@@ -78,8 +78,8 @@ struct _GstBaseSrc {
 
   /* 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;
 
index 4262d8a..30e046a 100644 (file)
@@ -64,16 +64,21 @@ enum
 #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())
@@ -152,28 +157,38 @@ gst_fake_sink_class_init (GstFakeSinkClass * klass)
   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:
@@ -218,21 +233,27 @@ gst_fake_sink_set_property (GObject * object, guint prop_id,
   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;
@@ -248,24 +269,30 @@ gst_fake_sink_get_property (GObject * object, guint prop_id, GValue * value,
   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;
index bb939d3..c0e5edf 100644 (file)
@@ -74,6 +74,8 @@ enum
 #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
 {
@@ -93,8 +95,8 @@ 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
 };
 
@@ -196,6 +198,7 @@ static void gst_fake_src_get_property (GObject * object, guint prop_id,
 
 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,
@@ -280,13 +283,15 @@ gst_fake_src_class_init (GstFakeSrcClass * klass)
   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",
@@ -307,7 +312,7 @@ gst_fake_src_class_init (GstFakeSrcClass * klass)
       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);
@@ -430,13 +435,13 @@ gst_fake_src_set_property (GObject * object, guint prop_id,
     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));
@@ -502,11 +507,11 @@ gst_fake_src_get_property (GObject * object, guint prop_id, GValue * 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));
@@ -744,3 +749,11 @@ gst_fake_src_stop (GstBaseSrc * basesrc)
 
   return TRUE;
 }
+
+static gboolean
+gst_fake_src_is_seekable (GstBaseSrc * basesrc)
+{
+  GstFakeSrc *src = GST_FAKE_SRC (basesrc);
+
+  return src->can_activate_pull;
+}
index 71fc7bc..84fb0cc 100644 (file)
@@ -105,6 +105,7 @@ struct _GstFakeSrc {
   gboolean      silent;
   gboolean      signal_handoffs;
   gboolean      dump;
+  gboolean      can_activate_pull;
 
   guint64        bytes_sent;
 
index 618d3a5..19726fd 100644 (file)
@@ -45,7 +45,10 @@ run_pipeline (GstElement * pipe, gchar * descr,
 
   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);
@@ -67,6 +70,7 @@ run_pipeline (GstElement * pipe, gchar * descr,
         revent, tevent, descr);
   }
 
+done:
   gst_element_set_state (pipe, GST_STATE_NULL);
   gst_object_unref (pipe);
 }
@@ -75,29 +79,25 @@ GST_START_TEST (test_2_elements)
 {
   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)