gst/base/: Make basesrc negotiate.
authorWim Taymans <wim.taymans@gmail.com>
Wed, 6 Jul 2005 13:25:26 +0000 (13:25 +0000)
committerWim Taymans <wim.taymans@gmail.com>
Wed, 6 Jul 2005 13:25:26 +0000 (13:25 +0000)
Original commit message from CVS:
* gst/base/README:
* gst/base/gstbasesink.c: (gst_base_sink_preroll_queue_empty),
(gst_base_sink_handle_object), (gst_base_sink_loop),
(gst_base_sink_change_state):
* gst/base/gstbasesink.h:
* gst/base/gstbasesrc.c: (gst_base_src_class_init),
(gst_base_src_init), (gst_base_src_setcaps),
(gst_base_src_getcaps), (gst_base_src_loop),
(gst_base_src_default_negotiate), (gst_base_src_negotiate),
(gst_base_src_start), (gst_base_src_change_state):
* gst/base/gstbasesrc.h:
Make basesrc negotiate.
Handle the case where preroll fails in basesink.
Update README.

ChangeLog
gst/base/README
gst/base/gstbasesink.c
gst/base/gstbasesink.h
gst/base/gstbasesrc.c
gst/base/gstbasesrc.h
libs/gst/base/README
libs/gst/base/gstbasesink.c
libs/gst/base/gstbasesink.h
libs/gst/base/gstbasesrc.c
libs/gst/base/gstbasesrc.h

index ccf4497..3c76cd9 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,22 @@
 2005-07-06  Wim Taymans  <wim@fluendo.com>
 
+       * gst/base/README:
+       * gst/base/gstbasesink.c: (gst_base_sink_preroll_queue_empty),
+       (gst_base_sink_handle_object), (gst_base_sink_loop),
+       (gst_base_sink_change_state):
+       * gst/base/gstbasesink.h:
+       * gst/base/gstbasesrc.c: (gst_base_src_class_init),
+       (gst_base_src_init), (gst_base_src_setcaps),
+       (gst_base_src_getcaps), (gst_base_src_loop),
+       (gst_base_src_default_negotiate), (gst_base_src_negotiate),
+       (gst_base_src_start), (gst_base_src_change_state):
+       * gst/base/gstbasesrc.h:
+       Make basesrc negotiate.
+       Handle the case where preroll fails in basesink.
+       Update README.
+
+2005-07-06  Wim Taymans  <wim@fluendo.com>
+
        * gst/gstpad.c: (gst_pad_fixate_caps), (gst_pad_accept_caps):
        Implement the fixate function.
        Clean up acceptcaps.
index 2633218..8047beb 100644 (file)
@@ -20,7 +20,9 @@ GstBaseTransform
   Base class for simple tranform filters
 
   - one sinkpad and one srcpad
-  - formats the same on sink and source pad.
+  - possible formats on sink and source pad implemented
+    with custom transform_caps function. By default uses 
+    same format on sink and source.
   - handles state changes
   - does flushing
   - push mode
@@ -34,3 +36,7 @@ GstBaseSrc
   - handles state changes
   - pull/push mode
   - handles seeking/query
+
+GstPushSrc
+
+  Base class for push based source elements
index f0aa9f8..78befff 100644 (file)
@@ -447,7 +447,6 @@ gst_base_sink_handle_object (GstBaseSink * basesink, GstPad * pad,
 {
   gint length;
   gboolean have_event;
-  guint t;
 
   GST_PREROLL_LOCK (pad);
   /* push object on the queue */
@@ -484,16 +483,21 @@ gst_base_sink_handle_object (GstBaseSink * basesink, GstPad * pad,
     /* if it's a buffer, we need to call the preroll method */
     if (GST_IS_BUFFER (obj)) {
       GstBaseSinkClass *bclass;
+      GstFlowReturn pres;
 
       bclass = GST_BASESINK_GET_CLASS (basesink);
       if (bclass->preroll)
-        bclass->preroll (basesink, GST_BUFFER (obj));
+        if ((pres =
+                bclass->preroll (basesink, GST_BUFFER (obj))) != GST_FLOW_OK)
+          goto preroll_failed;
     }
   }
   length = basesink->preroll_queued;
   GST_DEBUG ("prerolled length %d", length);
 
   if (length == 1) {
+    guint t;
+
     basesink->have_preroll = TRUE;
     /* we are prerolling */
     GST_PREROLL_UNLOCK (pad);
@@ -575,6 +579,36 @@ flushing:
     GST_DEBUG ("pad is flushing");
     return GST_FLOW_WRONG_STATE;
   }
+preroll_failed:
+  {
+    guint t;
+
+    GST_DEBUG ("preroll failed");
+    basesink->have_preroll = FALSE;
+    gst_base_sink_preroll_queue_flush (basesink, pad);
+    GST_PREROLL_UNLOCK (pad);
+
+    /* have to release STREAM_LOCK as we cannot take the STATE_LOCK
+     * inside the STREAM_LOCK */
+    t = GST_STREAM_UNLOCK_FULL (pad);
+    GST_DEBUG ("released stream lock %d times", t);
+    if (t == 0) {
+      GST_WARNING ("STREAM_LOCK should have been locked !!");
+      g_warning ("STREAM_LOCK should have been locked !!");
+    }
+
+    /* now we abort our state */
+    GST_STATE_LOCK (basesink);
+    GST_DEBUG ("abort state %p >", basesink);
+    gst_element_abort_state (GST_ELEMENT (basesink));
+    GST_STATE_UNLOCK (basesink);
+
+    /* reacquire stream lock, pad could be flushing now */
+    if (t > 0)
+      GST_STREAM_LOCK_FULL (pad, t);
+
+    return GST_FLOW_ERROR;
+  }
 }
 
 static gboolean
@@ -859,8 +893,10 @@ gst_base_sink_loop (GstPad * pad)
   return;
 
 paused:
-  gst_pad_pause_task (pad);
-  return;
+  {
+    gst_pad_pause_task (pad);
+    return;
+  }
 }
 
 static gboolean
@@ -940,9 +976,15 @@ gst_base_sink_change_state (GstElement * element)
   GstElementStateReturn ret = GST_STATE_SUCCESS;
   GstBaseSink *basesink = GST_BASESINK (element);
   GstElementState transition = GST_STATE_TRANSITION (element);
+  GstBaseSinkClass *bclass;
+
+  bclass = GST_BASESINK_GET_CLASS (basesink);
 
   switch (transition) {
     case GST_STATE_NULL_TO_READY:
+      if (bclass->start)
+        if (!bclass->start (basesink))
+          goto start_failed;
       break;
     case GST_STATE_READY_TO_PAUSED:
       /* need to complete preroll before this state change completes, there
@@ -1013,10 +1055,21 @@ gst_base_sink_change_state (GstElement * element)
     case GST_STATE_PAUSED_TO_READY:
       break;
     case GST_STATE_READY_TO_NULL:
+      if (bclass->stop)
+        if (!bclass->stop (basesink)) {
+          GST_WARNING ("failed to stop");
+        }
       break;
     default:
       break;
   }
 
   return ret;
+
+  /* ERRORS */
+start_failed:
+  {
+    GST_DEBUG ("failed to start");
+    return GST_STATE_FAILURE;
+  }
 }
index e0d0f8a..336de29 100644 (file)
@@ -87,6 +87,10 @@ struct _GstBaseSinkClass {
   void         (*get_times)    (GstBaseSink *sink, GstBuffer *buffer,
                                 GstClockTime *start, GstClockTime *end);
 
+  /* start and stop processing, ideal for opening/closing the resource */
+  gboolean      (*start)        (GstBaseSink *sink);
+  gboolean      (*stop)         (GstBaseSink *sink);
+
   /* unlock any pending access to the resource. subclasses should unlock
    * any function ASAP. */
   gboolean      (*unlock)       (GstBaseSink *sink);
index 333a947..9ebb8db 100644 (file)
@@ -81,6 +81,8 @@ gst_base_src_get_type (void)
   }
   return base_src_type;
 }
+static GstCaps *gst_base_src_getcaps (GstPad * pad);
+static gboolean gst_base_src_setcaps (GstPad * pad, GstCaps * caps);
 
 static gboolean gst_base_src_activate_push (GstPad * pad, gboolean active);
 static gboolean gst_base_src_activate_pull (GstPad * pad, gboolean active);
@@ -95,6 +97,7 @@ static gboolean gst_base_src_query (GstPad * pad, GstQuery * query);
 #if 0
 static const GstEventMask *gst_base_src_get_event_mask (GstPad * pad);
 #endif
+static gboolean gst_base_src_default_negotiate (GstBaseSrc * basesrc);
 
 static gboolean gst_base_src_unlock (GstBaseSrc * basesrc);
 static gboolean gst_base_src_get_size (GstBaseSrc * basesrc, guint64 * size);
@@ -146,6 +149,8 @@ gst_base_src_class_init (GstBaseSrcClass * klass)
 
   gstelement_class->change_state =
       GST_DEBUG_FUNCPTR (gst_base_src_change_state);
+
+  klass->negotiate = gst_base_src_default_negotiate;
 }
 
 static void
@@ -154,6 +159,10 @@ gst_base_src_init (GstBaseSrc * basesrc, gpointer g_class)
   GstPad *pad;
   GstPadTemplate *pad_template;
 
+  basesrc->is_live = FALSE;
+  basesrc->live_lock = g_mutex_new ();
+  basesrc->live_cond = g_cond_new ();
+
   pad_template =
       gst_element_class_get_pad_template (GST_ELEMENT_CLASS (g_class), "src");
   g_return_if_fail (pad_template != NULL);
@@ -164,12 +173,9 @@ gst_base_src_init (GstBaseSrc * basesrc, gpointer g_class)
   gst_pad_set_activatepull_function (pad, gst_base_src_activate_pull);
   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);
-
-  basesrc->is_live = FALSE;
-  basesrc->live_lock = g_mutex_new ();
-  basesrc->live_cond = g_cond_new ();
+  gst_pad_set_getcaps_function (pad, gst_base_src_getcaps);
+  gst_pad_set_setcaps_function (pad, gst_base_src_setcaps);
 
   /* hold ref to pad */
   basesrc->srcpad = pad;
@@ -215,6 +221,46 @@ gst_base_src_set_dataflow_funcs (GstBaseSrc * this)
 }
 
 static gboolean
+gst_base_src_setcaps (GstPad * pad, GstCaps * caps)
+{
+  GstBaseSrcClass *bclass;
+  GstBaseSrc *bsrc;
+  gboolean res = TRUE;
+
+  bsrc = GST_BASE_SRC (GST_PAD_PARENT (pad));
+  bclass = GST_BASE_SRC_GET_CLASS (bsrc);
+
+  if (bclass->set_caps)
+    res = bclass->set_caps (bsrc, caps);
+
+  return res;
+}
+
+static GstCaps *
+gst_base_src_getcaps (GstPad * pad)
+{
+  GstBaseSrcClass *bclass;
+  GstBaseSrc *bsrc;
+  GstCaps *caps = NULL;
+
+  bsrc = GST_BASE_SRC (GST_PAD_PARENT (pad));
+  bclass = GST_BASE_SRC_GET_CLASS (bsrc);
+  if (bclass->get_caps)
+    caps = bclass->get_caps (bsrc);
+
+  if (caps == NULL) {
+    GstPadTemplate *pad_template;
+
+    pad_template =
+        gst_element_class_get_pad_template (GST_ELEMENT_CLASS (bclass), "src");
+    if (pad_template != NULL) {
+      caps = gst_caps_ref (gst_pad_template_get_caps (pad_template));
+    }
+  }
+  return caps;
+}
+
+static gboolean
 gst_base_src_query (GstPad * pad, GstQuery * query)
 {
   gboolean b;
@@ -565,6 +611,9 @@ gst_base_src_loop (GstPad * pad)
   if (ret != GST_FLOW_OK)
     goto eos;
 
+  if (buf == NULL)
+    goto error;
+
   src->offset += GST_BUFFER_SIZE (buf);
 
   ret = gst_pad_push (pad, buf);
@@ -586,6 +635,13 @@ pause:
     gst_pad_pause_task (pad);
     return;
   }
+error:
+  {
+    GST_DEBUG_OBJECT (src, "got error, pausing task");
+    gst_pad_pause_task (pad);
+    gst_pad_push_event (pad, gst_event_new (GST_EVENT_EOS));
+    return;
+  }
 }
 
 static gboolean
@@ -646,6 +702,74 @@ gst_base_src_is_seekable (GstBaseSrc * basesrc)
 }
 
 static gboolean
+gst_base_src_default_negotiate (GstBaseSrc * basesrc)
+{
+  GstCaps *thiscaps;
+  GstCaps *caps = NULL;
+  GstCaps *peercaps = NULL;
+  gboolean result = FALSE;
+
+  thiscaps = gst_pad_get_caps (GST_BASE_SRC_PAD (basesrc));
+  GST_DEBUG ("caps of src: %" GST_PTR_FORMAT, thiscaps);
+  if (thiscaps == NULL || gst_caps_is_any (thiscaps))
+    goto no_nego_needed;
+
+  peercaps = gst_pad_peer_get_caps (GST_BASE_SRC_PAD (basesrc));
+  GST_DEBUG ("caps of peer: %" GST_PTR_FORMAT, peercaps);
+  if (peercaps) {
+    GstCaps *icaps;
+
+    icaps = gst_caps_intersect (thiscaps, peercaps);
+    GST_DEBUG ("intersect: %" GST_PTR_FORMAT, icaps);
+    gst_caps_unref (thiscaps);
+    gst_caps_unref (peercaps);
+    if (icaps) {
+      caps = gst_caps_copy_nth (icaps, 0);
+      gst_caps_unref (icaps);
+    }
+  } else {
+    caps = thiscaps;
+  }
+  if (caps) {
+    caps = gst_caps_make_writable (caps);
+    gst_pad_fixate_caps (GST_BASE_SRC_PAD (basesrc), caps);
+    GST_DEBUG ("fixated to: %" GST_PTR_FORMAT, caps);
+
+    if (gst_caps_is_any (caps)) {
+      gst_caps_unref (caps);
+      result = TRUE;
+    } else if (gst_caps_is_fixed (caps)) {
+      gst_pad_set_caps (GST_BASE_SRC_PAD (basesrc), caps);
+      gst_caps_unref (caps);
+      result = TRUE;
+    }
+  }
+  return result;
+
+no_nego_needed:
+  {
+    GST_DEBUG ("no negotiation needed");
+    if (thiscaps)
+      gst_caps_unref (thiscaps);
+    return TRUE;
+  }
+}
+
+static gboolean
+gst_base_src_negotiate (GstBaseSrc * basesrc)
+{
+  GstBaseSrcClass *bclass;
+  gboolean result = FALSE;
+
+  bclass = GST_BASE_SRC_GET_CLASS (basesrc);
+
+  if (bclass->negotiate)
+    result = bclass->negotiate (basesrc);
+
+  return result;
+}
+
+static gboolean
 gst_base_src_start (GstBaseSrc * basesrc)
 {
   GstBaseSrcClass *bclass;
@@ -694,9 +818,13 @@ gst_base_src_start (GstBaseSrc * basesrc)
 
     caps = gst_type_find_helper (basesrc->srcpad, basesrc->size);
     gst_pad_set_caps (basesrc->srcpad, caps);
+    gst_caps_unref (caps);
   }
 #endif
 
+  if (!gst_base_src_negotiate (basesrc))
+    goto could_not_negotiate;
+
   return TRUE;
 
   /* ERROR */
@@ -705,6 +833,12 @@ could_not_start:
     GST_DEBUG_OBJECT (basesrc, "could not start");
     return FALSE;
   }
+could_not_negotiate:
+  {
+    GST_DEBUG_OBJECT (basesrc, "could not negotiate, stopping");
+    gst_base_src_stop (basesrc);
+    return FALSE;
+  }
 }
 
 static gboolean
@@ -823,8 +957,10 @@ gst_base_src_change_state (GstElement * element)
       break;
     case GST_STATE_PAUSED_TO_PLAYING:
       GST_LIVE_LOCK (element);
-      basesrc->live_running = TRUE;
-      GST_LIVE_SIGNAL (element);
+      if (basesrc->is_live) {
+        basesrc->live_running = TRUE;
+        GST_LIVE_SIGNAL (element);
+      }
       GST_LIVE_UNLOCK (element);
       break;
     default:
index 3ebb4f5..a6d641d 100644 (file)
@@ -113,6 +113,9 @@ struct _GstBaseSrcClass {
   /* notify the subclass of new caps */
   gboolean      (*set_caps)     (GstBaseSrc *src, GstCaps *caps);
 
+  /* decide on caps */
+  gboolean      (*negotiate)    (GstBaseSrc *src);
+
   /* start and stop processing, ideal for opening/closing the resource */
   gboolean      (*start)        (GstBaseSrc *src);
   gboolean      (*stop)         (GstBaseSrc *src);
index 2633218..8047beb 100644 (file)
@@ -20,7 +20,9 @@ GstBaseTransform
   Base class for simple tranform filters
 
   - one sinkpad and one srcpad
-  - formats the same on sink and source pad.
+  - possible formats on sink and source pad implemented
+    with custom transform_caps function. By default uses 
+    same format on sink and source.
   - handles state changes
   - does flushing
   - push mode
@@ -34,3 +36,7 @@ GstBaseSrc
   - handles state changes
   - pull/push mode
   - handles seeking/query
+
+GstPushSrc
+
+  Base class for push based source elements
index f0aa9f8..78befff 100644 (file)
@@ -447,7 +447,6 @@ gst_base_sink_handle_object (GstBaseSink * basesink, GstPad * pad,
 {
   gint length;
   gboolean have_event;
-  guint t;
 
   GST_PREROLL_LOCK (pad);
   /* push object on the queue */
@@ -484,16 +483,21 @@ gst_base_sink_handle_object (GstBaseSink * basesink, GstPad * pad,
     /* if it's a buffer, we need to call the preroll method */
     if (GST_IS_BUFFER (obj)) {
       GstBaseSinkClass *bclass;
+      GstFlowReturn pres;
 
       bclass = GST_BASESINK_GET_CLASS (basesink);
       if (bclass->preroll)
-        bclass->preroll (basesink, GST_BUFFER (obj));
+        if ((pres =
+                bclass->preroll (basesink, GST_BUFFER (obj))) != GST_FLOW_OK)
+          goto preroll_failed;
     }
   }
   length = basesink->preroll_queued;
   GST_DEBUG ("prerolled length %d", length);
 
   if (length == 1) {
+    guint t;
+
     basesink->have_preroll = TRUE;
     /* we are prerolling */
     GST_PREROLL_UNLOCK (pad);
@@ -575,6 +579,36 @@ flushing:
     GST_DEBUG ("pad is flushing");
     return GST_FLOW_WRONG_STATE;
   }
+preroll_failed:
+  {
+    guint t;
+
+    GST_DEBUG ("preroll failed");
+    basesink->have_preroll = FALSE;
+    gst_base_sink_preroll_queue_flush (basesink, pad);
+    GST_PREROLL_UNLOCK (pad);
+
+    /* have to release STREAM_LOCK as we cannot take the STATE_LOCK
+     * inside the STREAM_LOCK */
+    t = GST_STREAM_UNLOCK_FULL (pad);
+    GST_DEBUG ("released stream lock %d times", t);
+    if (t == 0) {
+      GST_WARNING ("STREAM_LOCK should have been locked !!");
+      g_warning ("STREAM_LOCK should have been locked !!");
+    }
+
+    /* now we abort our state */
+    GST_STATE_LOCK (basesink);
+    GST_DEBUG ("abort state %p >", basesink);
+    gst_element_abort_state (GST_ELEMENT (basesink));
+    GST_STATE_UNLOCK (basesink);
+
+    /* reacquire stream lock, pad could be flushing now */
+    if (t > 0)
+      GST_STREAM_LOCK_FULL (pad, t);
+
+    return GST_FLOW_ERROR;
+  }
 }
 
 static gboolean
@@ -859,8 +893,10 @@ gst_base_sink_loop (GstPad * pad)
   return;
 
 paused:
-  gst_pad_pause_task (pad);
-  return;
+  {
+    gst_pad_pause_task (pad);
+    return;
+  }
 }
 
 static gboolean
@@ -940,9 +976,15 @@ gst_base_sink_change_state (GstElement * element)
   GstElementStateReturn ret = GST_STATE_SUCCESS;
   GstBaseSink *basesink = GST_BASESINK (element);
   GstElementState transition = GST_STATE_TRANSITION (element);
+  GstBaseSinkClass *bclass;
+
+  bclass = GST_BASESINK_GET_CLASS (basesink);
 
   switch (transition) {
     case GST_STATE_NULL_TO_READY:
+      if (bclass->start)
+        if (!bclass->start (basesink))
+          goto start_failed;
       break;
     case GST_STATE_READY_TO_PAUSED:
       /* need to complete preroll before this state change completes, there
@@ -1013,10 +1055,21 @@ gst_base_sink_change_state (GstElement * element)
     case GST_STATE_PAUSED_TO_READY:
       break;
     case GST_STATE_READY_TO_NULL:
+      if (bclass->stop)
+        if (!bclass->stop (basesink)) {
+          GST_WARNING ("failed to stop");
+        }
       break;
     default:
       break;
   }
 
   return ret;
+
+  /* ERRORS */
+start_failed:
+  {
+    GST_DEBUG ("failed to start");
+    return GST_STATE_FAILURE;
+  }
 }
index e0d0f8a..336de29 100644 (file)
@@ -87,6 +87,10 @@ struct _GstBaseSinkClass {
   void         (*get_times)    (GstBaseSink *sink, GstBuffer *buffer,
                                 GstClockTime *start, GstClockTime *end);
 
+  /* start and stop processing, ideal for opening/closing the resource */
+  gboolean      (*start)        (GstBaseSink *sink);
+  gboolean      (*stop)         (GstBaseSink *sink);
+
   /* unlock any pending access to the resource. subclasses should unlock
    * any function ASAP. */
   gboolean      (*unlock)       (GstBaseSink *sink);
index 333a947..9ebb8db 100644 (file)
@@ -81,6 +81,8 @@ gst_base_src_get_type (void)
   }
   return base_src_type;
 }
+static GstCaps *gst_base_src_getcaps (GstPad * pad);
+static gboolean gst_base_src_setcaps (GstPad * pad, GstCaps * caps);
 
 static gboolean gst_base_src_activate_push (GstPad * pad, gboolean active);
 static gboolean gst_base_src_activate_pull (GstPad * pad, gboolean active);
@@ -95,6 +97,7 @@ static gboolean gst_base_src_query (GstPad * pad, GstQuery * query);
 #if 0
 static const GstEventMask *gst_base_src_get_event_mask (GstPad * pad);
 #endif
+static gboolean gst_base_src_default_negotiate (GstBaseSrc * basesrc);
 
 static gboolean gst_base_src_unlock (GstBaseSrc * basesrc);
 static gboolean gst_base_src_get_size (GstBaseSrc * basesrc, guint64 * size);
@@ -146,6 +149,8 @@ gst_base_src_class_init (GstBaseSrcClass * klass)
 
   gstelement_class->change_state =
       GST_DEBUG_FUNCPTR (gst_base_src_change_state);
+
+  klass->negotiate = gst_base_src_default_negotiate;
 }
 
 static void
@@ -154,6 +159,10 @@ gst_base_src_init (GstBaseSrc * basesrc, gpointer g_class)
   GstPad *pad;
   GstPadTemplate *pad_template;
 
+  basesrc->is_live = FALSE;
+  basesrc->live_lock = g_mutex_new ();
+  basesrc->live_cond = g_cond_new ();
+
   pad_template =
       gst_element_class_get_pad_template (GST_ELEMENT_CLASS (g_class), "src");
   g_return_if_fail (pad_template != NULL);
@@ -164,12 +173,9 @@ gst_base_src_init (GstBaseSrc * basesrc, gpointer g_class)
   gst_pad_set_activatepull_function (pad, gst_base_src_activate_pull);
   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);
-
-  basesrc->is_live = FALSE;
-  basesrc->live_lock = g_mutex_new ();
-  basesrc->live_cond = g_cond_new ();
+  gst_pad_set_getcaps_function (pad, gst_base_src_getcaps);
+  gst_pad_set_setcaps_function (pad, gst_base_src_setcaps);
 
   /* hold ref to pad */
   basesrc->srcpad = pad;
@@ -215,6 +221,46 @@ gst_base_src_set_dataflow_funcs (GstBaseSrc * this)
 }
 
 static gboolean
+gst_base_src_setcaps (GstPad * pad, GstCaps * caps)
+{
+  GstBaseSrcClass *bclass;
+  GstBaseSrc *bsrc;
+  gboolean res = TRUE;
+
+  bsrc = GST_BASE_SRC (GST_PAD_PARENT (pad));
+  bclass = GST_BASE_SRC_GET_CLASS (bsrc);
+
+  if (bclass->set_caps)
+    res = bclass->set_caps (bsrc, caps);
+
+  return res;
+}
+
+static GstCaps *
+gst_base_src_getcaps (GstPad * pad)
+{
+  GstBaseSrcClass *bclass;
+  GstBaseSrc *bsrc;
+  GstCaps *caps = NULL;
+
+  bsrc = GST_BASE_SRC (GST_PAD_PARENT (pad));
+  bclass = GST_BASE_SRC_GET_CLASS (bsrc);
+  if (bclass->get_caps)
+    caps = bclass->get_caps (bsrc);
+
+  if (caps == NULL) {
+    GstPadTemplate *pad_template;
+
+    pad_template =
+        gst_element_class_get_pad_template (GST_ELEMENT_CLASS (bclass), "src");
+    if (pad_template != NULL) {
+      caps = gst_caps_ref (gst_pad_template_get_caps (pad_template));
+    }
+  }
+  return caps;
+}
+
+static gboolean
 gst_base_src_query (GstPad * pad, GstQuery * query)
 {
   gboolean b;
@@ -565,6 +611,9 @@ gst_base_src_loop (GstPad * pad)
   if (ret != GST_FLOW_OK)
     goto eos;
 
+  if (buf == NULL)
+    goto error;
+
   src->offset += GST_BUFFER_SIZE (buf);
 
   ret = gst_pad_push (pad, buf);
@@ -586,6 +635,13 @@ pause:
     gst_pad_pause_task (pad);
     return;
   }
+error:
+  {
+    GST_DEBUG_OBJECT (src, "got error, pausing task");
+    gst_pad_pause_task (pad);
+    gst_pad_push_event (pad, gst_event_new (GST_EVENT_EOS));
+    return;
+  }
 }
 
 static gboolean
@@ -646,6 +702,74 @@ gst_base_src_is_seekable (GstBaseSrc * basesrc)
 }
 
 static gboolean
+gst_base_src_default_negotiate (GstBaseSrc * basesrc)
+{
+  GstCaps *thiscaps;
+  GstCaps *caps = NULL;
+  GstCaps *peercaps = NULL;
+  gboolean result = FALSE;
+
+  thiscaps = gst_pad_get_caps (GST_BASE_SRC_PAD (basesrc));
+  GST_DEBUG ("caps of src: %" GST_PTR_FORMAT, thiscaps);
+  if (thiscaps == NULL || gst_caps_is_any (thiscaps))
+    goto no_nego_needed;
+
+  peercaps = gst_pad_peer_get_caps (GST_BASE_SRC_PAD (basesrc));
+  GST_DEBUG ("caps of peer: %" GST_PTR_FORMAT, peercaps);
+  if (peercaps) {
+    GstCaps *icaps;
+
+    icaps = gst_caps_intersect (thiscaps, peercaps);
+    GST_DEBUG ("intersect: %" GST_PTR_FORMAT, icaps);
+    gst_caps_unref (thiscaps);
+    gst_caps_unref (peercaps);
+    if (icaps) {
+      caps = gst_caps_copy_nth (icaps, 0);
+      gst_caps_unref (icaps);
+    }
+  } else {
+    caps = thiscaps;
+  }
+  if (caps) {
+    caps = gst_caps_make_writable (caps);
+    gst_pad_fixate_caps (GST_BASE_SRC_PAD (basesrc), caps);
+    GST_DEBUG ("fixated to: %" GST_PTR_FORMAT, caps);
+
+    if (gst_caps_is_any (caps)) {
+      gst_caps_unref (caps);
+      result = TRUE;
+    } else if (gst_caps_is_fixed (caps)) {
+      gst_pad_set_caps (GST_BASE_SRC_PAD (basesrc), caps);
+      gst_caps_unref (caps);
+      result = TRUE;
+    }
+  }
+  return result;
+
+no_nego_needed:
+  {
+    GST_DEBUG ("no negotiation needed");
+    if (thiscaps)
+      gst_caps_unref (thiscaps);
+    return TRUE;
+  }
+}
+
+static gboolean
+gst_base_src_negotiate (GstBaseSrc * basesrc)
+{
+  GstBaseSrcClass *bclass;
+  gboolean result = FALSE;
+
+  bclass = GST_BASE_SRC_GET_CLASS (basesrc);
+
+  if (bclass->negotiate)
+    result = bclass->negotiate (basesrc);
+
+  return result;
+}
+
+static gboolean
 gst_base_src_start (GstBaseSrc * basesrc)
 {
   GstBaseSrcClass *bclass;
@@ -694,9 +818,13 @@ gst_base_src_start (GstBaseSrc * basesrc)
 
     caps = gst_type_find_helper (basesrc->srcpad, basesrc->size);
     gst_pad_set_caps (basesrc->srcpad, caps);
+    gst_caps_unref (caps);
   }
 #endif
 
+  if (!gst_base_src_negotiate (basesrc))
+    goto could_not_negotiate;
+
   return TRUE;
 
   /* ERROR */
@@ -705,6 +833,12 @@ could_not_start:
     GST_DEBUG_OBJECT (basesrc, "could not start");
     return FALSE;
   }
+could_not_negotiate:
+  {
+    GST_DEBUG_OBJECT (basesrc, "could not negotiate, stopping");
+    gst_base_src_stop (basesrc);
+    return FALSE;
+  }
 }
 
 static gboolean
@@ -823,8 +957,10 @@ gst_base_src_change_state (GstElement * element)
       break;
     case GST_STATE_PAUSED_TO_PLAYING:
       GST_LIVE_LOCK (element);
-      basesrc->live_running = TRUE;
-      GST_LIVE_SIGNAL (element);
+      if (basesrc->is_live) {
+        basesrc->live_running = TRUE;
+        GST_LIVE_SIGNAL (element);
+      }
       GST_LIVE_UNLOCK (element);
       break;
     default:
index 3ebb4f5..a6d641d 100644 (file)
@@ -113,6 +113,9 @@ struct _GstBaseSrcClass {
   /* notify the subclass of new caps */
   gboolean      (*set_caps)     (GstBaseSrc *src, GstCaps *caps);
 
+  /* decide on caps */
+  gboolean      (*negotiate)    (GstBaseSrc *src);
+
   /* start and stop processing, ideal for opening/closing the resource */
   gboolean      (*start)        (GstBaseSrc *src);
   gboolean      (*stop)         (GstBaseSrc *src);