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.
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
- handles state changes
- pull/push mode
- handles seeking/query
+
+GstPushSrc
+
+ Base class for push based source elements
{
gint length;
gboolean have_event;
- guint t;
GST_PREROLL_LOCK (pad);
/* push object on the queue */
/* 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);
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
return;
paused:
- gst_pad_pause_task (pad);
- return;
+ {
+ gst_pad_pause_task (pad);
+ return;
+ }
}
static gboolean
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
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;
+ }
}
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);
}
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);
#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);
gstelement_class->change_state =
GST_DEBUG_FUNCPTR (gst_base_src_change_state);
+
+ klass->negotiate = gst_base_src_default_negotiate;
}
static void
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);
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;
}
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;
if (ret != GST_FLOW_OK)
goto eos;
+ if (buf == NULL)
+ goto error;
+
src->offset += GST_BUFFER_SIZE (buf);
ret = gst_pad_push (pad, buf);
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
}
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;
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 */
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
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:
/* 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);
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
- handles state changes
- pull/push mode
- handles seeking/query
+
+GstPushSrc
+
+ Base class for push based source elements
{
gint length;
gboolean have_event;
- guint t;
GST_PREROLL_LOCK (pad);
/* push object on the queue */
/* 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);
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
return;
paused:
- gst_pad_pause_task (pad);
- return;
+ {
+ gst_pad_pause_task (pad);
+ return;
+ }
}
static gboolean
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
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;
+ }
}
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);
}
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);
#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);
gstelement_class->change_state =
GST_DEBUG_FUNCPTR (gst_base_src_change_state);
+
+ klass->negotiate = gst_base_src_default_negotiate;
}
static void
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);
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;
}
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;
if (ret != GST_FLOW_OK)
goto eos;
+ if (buf == NULL)
+ goto error;
+
src->offset += GST_BUFFER_SIZE (buf);
ret = gst_pad_push (pad, buf);
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
}
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;
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 */
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
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:
/* 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);