- Optimize negotiation. We currently do a get_caps() call when we link pads,
which could potentially generate a huge list of caps and all their
combinations, we need to avoid generating these huge lists by generating them
- incrementaly when needed. We can do this with a gst_pad_iterate_caps() call.
+ We also need to incrementally return intersections etc, for this. somewhat
+ incrementally when needed. We can do this with a gst_pad_iterate_caps() call.
+ We also need to incrementally return intersections etc, for this.
+ FIXED in 0.11 with a filter on getcaps functions.
- Elements in a bin have no clue about the final state of the parent element
since the bin sets the target state on its children in small steps. This
The same flow works as well for any chain of multiple elements and might
be implemented with a helper function in the future.
-
-Issues
-~~~~~~
-
-When an EOS event has passed a pad and the pad is set to blocked, the block will
-never happen because no data is going to flow anymore. One possibility is to
-keep track of the pad's EOS state and make the block succeed immediately. This is
-not yet implemenented.
-
-When dynamically reconnecting pads, some events (like NEWSEGMENT, EOS,
-TAGS, ...) are not yet retransmitted to the newly connected element. It's
-unclear if this can be done by core automatically by caching those events and
-resending them on a relink. It might also be possible that this needs a
-GstFlowReturn value from the event function, in which case the implementation
-must be delayed for after 0.11, when we can break API/ABI.
-
+
This function describes the possible types that the pad can handle or
produce (see part-pads.txt and part-negotiation.txt).
- Various methods exist to work with the media types such as substracting
-Caps are also attached to buffers to describe to content of the data
-pointed to be the buffer.
-
+ Various methods exist to work with the media types such as subtracting
or intersecting.
input buffer is transformed into the output buffer. The flow is exactly
the same as the case with the same-caps negotiation. (DCC)
- We can immeditatly observe that the copy transform states will need to
+ We can immediately observe that the copy transform states will need to
-allocate a buffer from a downstream element using pad-alloc. When the transform
-element is receiving a non-writable buffer in the in-place state, it will also
-need to perform a pad-alloc. There is no reason why the passthrough state would
-perform a pad-alloc. This is important because upstream re-negotiation can only
-happen when the transform uses pad-alloc for all outgoing buffers.
+allocate a new buffer from the bufferpool. When the transform element is
+receiving a non-writable buffer in the in-place state, it will also
+need to perform an allocation. There is no reason why the passthrough state would
+perform an allocation.
This steady state changes when one of the following actions occur:
Since the stream time is always set to 0 at start and after a seek, a 0
point for all next buffer's timestamps has to be propagated through the
-pipeline using the NEWSEGMENT event.
+pipeline using the SEGMENT event.
-Before sending buffers, an element must send a NEWSEGMENT event. An element is
-free to refuse buffers if they were not preceeded by a NEWSEGMENT event.
+Before sending buffers, an element must send a SEGMENT event. An element is
+free to refuse buffers if they were not preceeded by a SEGMENT event.
-Elements that sync to the clock should store the NEWSEGMENT start and end values
+Elements that sync to the clock should store the SEGMENT start and end values
- and substract the start value from the buffer timestamp before comparing
+ and subtract the start value from the buffer timestamp before comparing
it against the stream time (see part-clocks.txt).
-An element is allowed to send out buffers with the NEWSEGMENT start time already
+An element is allowed to send out buffers with the SEGMENT start time already
- substracted from the timestamp. If it does so, it needs to send a corrected
+ subtracted from the timestamp. If it does so, it needs to send a corrected
-NEWSEGMENT downstream, ie, one with start time 0.
+SEGMENT downstream, ie, one with start time 0.
-A NEWSEGMENT event should be generated as soon as possible in the pipeline and
+A SEGMENT event should be generated as soon as possible in the pipeline and
is usually generated by a demuxer or source. The event is generated before
pushing the first buffer and after a seek, right before pushing the new buffer.
if (caps == existing || gst_caps_is_equal (caps, existing))
goto is_same_caps;
}
- acceptfunc = GST_PAD_ACCEPTCAPSFUNC (pad);
GST_OBJECT_UNLOCK (pad);
+#endif
+ acceptfunc = GST_PAD_ACCEPTCAPSFUNC (pad);
- if (G_LIKELY (acceptfunc)) {
- /* we can call the function */
- result = acceptfunc (pad, caps);
- GST_DEBUG_OBJECT (pad, "acceptfunc returned %d", result);
- } else {
- /* Only null if the element explicitly unset it */
- result = gst_pad_acceptcaps_default (pad, caps);
- GST_DEBUG_OBJECT (pad, "default acceptcaps returned %d", result);
- }
+ /* Only null if the element explicitly unset it */
+ if (G_UNLIKELY (acceptfunc == NULL))
+ goto no_func;
+
+ /* we can call the function */
+ result = acceptfunc (pad, caps);
+ GST_DEBUG_OBJECT (pad, "acceptfunc returned %d", result);
+ #ifndef G_DISABLE_ASSERT
+ {
+ GstCaps *padcaps;
+
+ padcaps = gst_pad_get_caps_reffed (pad);
+ if (!gst_caps_is_subset (caps, padcaps)) {
+ gchar *padcaps_str, *caps_str;
+
+ padcaps_str = gst_caps_to_string (padcaps);
+ caps_str = gst_caps_to_string (caps);
+ g_warning ("pad %s:%s accepted caps %s although "
+ "they are not a subset of its caps %s",
+ GST_DEBUG_PAD_NAME (pad), caps_str, padcaps_str);
+ g_free (padcaps_str);
+ g_free (caps_str);
+ }
+ gst_caps_unref (padcaps);
+ }
+ #endif
+
return result;
+#if 0
is_same_caps:
{
GST_DEBUG_OBJECT (pad, "pad had same caps");
gboolean
gst_pad_set_caps (GstPad * pad, GstCaps * caps)
{
- GstPadSetCapsFunction setcaps;
- GstCaps *existing;
+ GstEvent *event;
+ gboolean res = TRUE;
g_return_val_if_fail (GST_IS_PAD (pad), FALSE);
- g_return_val_if_fail (caps == NULL || gst_caps_is_fixed (caps), FALSE);
+ g_return_val_if_fail (caps != NULL && gst_caps_is_fixed (caps), FALSE);
- GST_OBJECT_LOCK (pad);
- existing = GST_PAD_CAPS (pad);
- if (existing == caps)
- goto was_ok;
+ event = gst_event_new_caps (caps);
- if (gst_caps_is_equal (caps, existing))
- goto setting_same_caps;
+ if (GST_PAD_IS_SRC (pad))
+ res = gst_pad_push_event (pad, event);
+ else
+ res = gst_pad_send_event (pad, event);
- setcaps = GST_PAD_SETCAPSFUNC (pad);
+ return res;
+}
- /* call setcaps function to configure the pad only if the
- * caps is not NULL */
- if (setcaps != NULL && caps) {
- if (!GST_PAD_IS_IN_SETCAPS (pad)) {
- GST_OBJECT_FLAG_SET (pad, GST_PAD_IN_SETCAPS);
- GST_OBJECT_UNLOCK (pad);
- if (!setcaps (pad, caps))
- goto could_not_set;
- GST_OBJECT_LOCK (pad);
- GST_OBJECT_FLAG_UNSET (pad, GST_PAD_IN_SETCAPS);
- } else {
- GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad, "pad was dispatching");
+static gboolean
+do_event_function (GstPad * pad, GstEvent * event,
+ GstPadEventFunction eventfunc, gboolean * caps_notify)
+{
+ gboolean result = TRUE, call_event = TRUE;
- GstCaps *caps, *templ, *old;
++ GstCaps *caps, *old, *templ;
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_CAPS:
+ {
+ /* backwards compatibility mode for caps */
+ gst_event_parse_caps (event, &caps);
+
+ /* See if pad accepts the caps */
+ templ = gst_pad_get_pad_template_caps (pad);
+ if (!gst_caps_can_intersect (caps, templ))
+ goto not_accepted;
+
+ /* check if it changed */
+ if ((old = gst_pad_get_current_caps (pad))) {
+ call_event = !gst_caps_is_equal (caps, old);
+ gst_caps_unref (old);
+ }
+ if (call_event)
+ *caps_notify = TRUE;
-
+ gst_caps_unref (templ);
+ break;
}
+ default:
+ break;
}
- gst_caps_replace (&GST_PAD_CAPS (pad), caps);
- GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad, "caps %p %" GST_PTR_FORMAT, caps,
- caps);
- GST_OBJECT_UNLOCK (pad);
-
-#if GLIB_CHECK_VERSION(2,26,0)
- g_object_notify_by_pspec ((GObject *) pad, pspec_caps);
-#else
- g_object_notify ((GObject *) pad, "caps");
-#endif
-
- return TRUE;
-
-was_ok:
- {
- GST_OBJECT_UNLOCK (pad);
- return TRUE;
- }
-setting_same_caps:
- {
- gst_caps_replace (&GST_PAD_CAPS (pad), caps);
- GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad,
- "caps %p %" GST_PTR_FORMAT " same as existing, updating ptr only", caps,
- caps);
- GST_OBJECT_UNLOCK (pad);
- return TRUE;
+ if (call_event) {
+ GST_DEBUG_OBJECT (pad, "calling event function with event %p", event);
+ result = eventfunc (pad, event);
+ } else {
+ gst_event_unref (event);
}
+ return result;
/* ERRORS */
-could_not_set:
+not_accepted:
{
- GST_OBJECT_LOCK (pad);
- GST_OBJECT_FLAG_UNSET (pad, GST_PAD_IN_SETCAPS);
+ gst_caps_unref (templ);
+ gst_event_unref (event);
GST_CAT_DEBUG_OBJECT (GST_CAT_CAPS, pad,
- "caps %" GST_PTR_FORMAT " could not be set", caps);
- GST_OBJECT_UNLOCK (pad);
-
+ "caps %" GST_PTR_FORMAT " not accepted", caps);
return FALSE;
}
}
* @pad: a #GstPad to call the default event handler on.
* @event: (transfer full): the #GstEvent to handle.
*
- * Invokes the default event handler for the given pad. End-of-stream and
- * discontinuity events are handled specially, and then the event is sent to all
- * pads internally linked to @pad. Note that if there are many possible sink
- * pads that are internally linked to @pad, only one will be sent an event.
- * Multi-sinkpad elements should implement custom event handlers.
+ * Invokes the default event handler for the given pad.
+ *
+ * The EOS event will pause the task associated with @pad before it is forwarded
+ * to all internally linked pads,
+ *
+ * The CAPS event will never be forwarded.
+ *
+ * The the event is sent to all pads internally linked to @pad. This function
+ * takes ownership of @event.
*
- * Returns: TRUE if the event was sent succesfully.
+ * Returns: TRUE if the event was sent successfully.
*/
gboolean
gst_pad_event_default (GstPad * pad, GstEvent * event)
typedef struct _GstSegment GstSegment;
- * continue playback. With this seek method it is possible to perform seemless
+/**
+ * GstSeekType:
+ * @GST_SEEK_TYPE_NONE: no change in position is required
+ * @GST_SEEK_TYPE_CUR: change relative to currently configured segment. This
+ * can't be used to seek relative to the current playback position - do a
+ * position query, calculate the desired position and then do an absolute
+ * position seek instead if that's what you want to do.
+ * @GST_SEEK_TYPE_SET: absolute position is requested
+ * @GST_SEEK_TYPE_END: relative position to duration is requested
+ *
+ * The different types of seek events. When constructing a seek event with
+ * gst_event_new_seek() or when doing gst_segment_do_seek ().
+ */
+typedef enum {
+ /* one of these */
+ GST_SEEK_TYPE_NONE = 0,
+ GST_SEEK_TYPE_CUR = 1,
+ GST_SEEK_TYPE_SET = 2,
+ GST_SEEK_TYPE_END = 3
+} GstSeekType;
+
+/**
+ * GstSeekFlags:
+ * @GST_SEEK_FLAG_NONE: no flag
+ * @GST_SEEK_FLAG_FLUSH: flush pipeline
+ * @GST_SEEK_FLAG_ACCURATE: accurate position is requested, this might
+ * be considerably slower for some formats.
+ * @GST_SEEK_FLAG_KEY_UNIT: seek to the nearest keyframe. This might be
+ * faster but less accurate.
+ * @GST_SEEK_FLAG_SEGMENT: perform a segment seek.
+ * @GST_SEEK_FLAG_SKIP: when doing fast foward or fast reverse playback, allow
+ * elements to skip frames instead of generating all
+ * frames. Since 0.10.22.
+ *
+ * Flags to be used with gst_element_seek() or gst_event_new_seek(). All flags
+ * can be used together.
+ *
+ * A non flushing seek might take some time to perform as the currently
+ * playing data in the pipeline will not be cleared.
+ *
+ * An accurate seek might be slower for formats that don't have any indexes
+ * or timestamp markers in the stream. Specifying this flag might require a
+ * complete scan of the file in those cases.
+ *
+ * When performing a segment seek: after the playback of the segment completes,
+ * no EOS will be emmited by the element that performed the seek, but a
+ * #GST_MESSAGE_SEGMENT_DONE message will be posted on the bus by the element.
+ * When this message is posted, it is possible to send a new seek event to
++ * continue playback. With this seek method it is possible to perform seamless
+ * looping or simple linear editing.
+ *
+ * When doing fast forward (rate > 1.0) or fast reverse (rate < -1.0) trickmode
+ * playback, the @GST_SEEK_FLAG_SKIP flag can be used to instruct decoders
+ * and demuxers to adjust the playback rate by skipping frames. This can improve
+ * performance and decrease CPU usage because not all frames need to be decoded.
+ *
+ * Also see part-seeking.txt in the GStreamer design documentation for more
+ * details on the meaning of these flags and the behaviour expected of
+ * elements that handle them.
+ */
+typedef enum {
+ GST_SEEK_FLAG_NONE = 0,
+ GST_SEEK_FLAG_FLUSH = (1 << 0),
+ GST_SEEK_FLAG_ACCURATE = (1 << 1),
+ GST_SEEK_FLAG_KEY_UNIT = (1 << 2),
+ GST_SEEK_FLAG_SEGMENT = (1 << 3),
+ GST_SEEK_FLAG_SKIP = (1 << 4)
+} GstSeekFlags;
+
+/**
+ * GstSegmentFlags:
+ * @GST_SEGMENT_FLAG_NONE: no flags
+ * @GST_SEGMENT_FLAG_RESET: reset the pipeline running_time to the segment
+ * running_time
+ * @GST_SEGMENT_FLAG_SKIP: perform skip playback
+ *
+ * Flags for the GstSegment structure. Currently mapped to the corresponding
+ * values of the seek flags.
+ */
+typedef enum {
+ GST_SEGMENT_FLAG_NONE = GST_SEEK_FLAG_NONE,
+ GST_SEGMENT_FLAG_RESET = GST_SEEK_FLAG_FLUSH,
+ GST_SEGMENT_FLAG_SKIP = GST_SEEK_FLAG_SKIP
+} GstSegmentFlags;
+
/**
* GstSegment:
+ * @flags: flags for this segment
* @rate: the rate of the segment
- * @abs_rate: absolute value of @rate
+ * @applied_rate: the already applied rate to the segment
* @format: the format of the segment values
- * @flags: flags for this segment
+ * @base: the base time of the segment
* @start: the start of the segment
* @stop: the stop of the segment
* @time: the stream time of the segment
res = FALSE;
}
- /* if successfull seek, we update our real segment and push
+ /* if successful seek, we update our real segment and push
* out the new segment. */
if (res) {
- memcpy (&sink->segment, &seeksegment, sizeof (GstSegment));
+ gst_segment_copy_into (&seeksegment, &sink->segment);
if (sink->segment.flags & GST_SEEK_FLAG_SEGMENT) {
gst_element_post_message (GST_ELEMENT (sink),
GST_DEBUG_OBJECT (basesink, "allowed caps: %" GST_PTR_FORMAT, caps);
caps = gst_caps_make_writable (caps);
- /* get the first (prefered) format */
+ /* get the first (preferred) format */
gst_caps_truncate (caps);
- /* try to fixate */
- gst_pad_fixate_caps (GST_BASE_SINK_PAD (basesink), caps);
- GST_DEBUG_OBJECT (basesink, "fixated to: %" GST_PTR_FORMAT, caps);
+ GST_DEBUG_OBJECT (basesink, "have caps: %" GST_PTR_FORMAT, caps);
if (gst_caps_is_any (caps)) {
GST_DEBUG_OBJECT (basesink, "caps were ANY after fixating, "
", dropped: %" G_GUINT64_FORMAT, priv->rendered, priv->dropped);
gst_base_sink_reset_qos (basesink);
- GST_PAD_PREROLL_UNLOCK (basesink->sinkpad);
+ GST_BASE_SINK_PREROLL_UNLOCK (basesink);
break;
case GST_STATE_CHANGE_PAUSED_TO_READY:
- GST_PAD_PREROLL_LOCK (basesink->sinkpad);
+ GST_BASE_SINK_PREROLL_LOCK (basesink);
- /* start by reseting our position state with the object lock so that the
+ /* start by resetting our position state with the object lock so that the
* position query gets the right idea. We do this before we post the
* messages so that the message handlers pick this up. */
GST_OBJECT_LOCK (basesink);
{
GstBaseTransform *trans;
GstPad *otherpad;
- GstCaps *peercaps, *caps, *peerfilter = NULL;
- const GstCaps *templ;
- GstCaps *peercaps, *caps, *temp;
++ GstCaps *peercaps, *caps, *temp, *peerfilter = NULL;
++ GstCaps *templ;
trans = GST_BASE_TRANSFORM (gst_pad_get_parent (pad));
otherpad = (pad == trans->srcpad) ? trans->sinkpad : trans->srcpad;
/* we can do what the peer can */
- peercaps = gst_pad_peer_get_caps_reffed (otherpad);
+ if (filter) {
- GstCaps *temp, *templ;
+
+ GST_DEBUG_OBJECT (pad, "filter caps %" GST_PTR_FORMAT, filter);
+
+ /* filtered against our padtemplate on the other side */
+ templ = gst_pad_get_pad_template_caps (pad);
+ GST_DEBUG_OBJECT (pad, "our template %" GST_PTR_FORMAT, templ);
+ temp = gst_caps_intersect_full (filter, templ, GST_CAPS_INTERSECT_FIRST);
+ GST_DEBUG_OBJECT (pad, "intersected %" GST_PTR_FORMAT, temp);
+ gst_caps_unref (templ);
+
+ /* then see what we can transform this to */
+ peerfilter = gst_base_transform_transform_caps (trans,
+ GST_PAD_DIRECTION (pad), temp, NULL);
+ GST_DEBUG_OBJECT (pad, "transformed %" GST_PTR_FORMAT, peerfilter);
+ gst_caps_unref (temp);
+
+ /* and filter against the template of this pad */
+ templ = gst_pad_get_pad_template_caps (otherpad);
+ GST_DEBUG_OBJECT (pad, "our template %" GST_PTR_FORMAT, templ);
+ /* We keep the caps sorted like the returned caps */
+ temp =
+ gst_caps_intersect_full (peerfilter, templ, GST_CAPS_INTERSECT_FIRST);
+ GST_DEBUG_OBJECT (pad, "intersected %" GST_PTR_FORMAT, temp);
+ gst_caps_unref (peerfilter);
+ gst_caps_unref (templ);
+ peerfilter = temp;
+ }
+
+ peercaps = gst_pad_peer_get_caps (otherpad, peerfilter);
+
+ if (peerfilter)
+ gst_caps_unref (peerfilter);
+
if (peercaps) {
- GstCaps *temp, *templ;
-
GST_DEBUG_OBJECT (pad, "peer caps %" GST_PTR_FORMAT, peercaps);
/* filtered against our padtemplate on the other side */
GST_DEBUG_OBJECT (pad, "our template %" GST_PTR_FORMAT, templ);
temp = gst_caps_intersect_full (peercaps, templ, GST_CAPS_INTERSECT_FIRST);
GST_DEBUG_OBJECT (pad, "intersected %" GST_PTR_FORMAT, temp);
- GST_DEBUG_OBJECT (pad, "no peer, using our template caps %" GST_PTR_FORMAT,
- temp);
+ gst_caps_unref (templ);
+ } else {
+ temp = gst_caps_copy (gst_pad_get_pad_template_caps (otherpad));
+ }
- /* then see what we can transform this to */
- caps = gst_base_transform_transform_caps (trans,
- GST_PAD_DIRECTION (otherpad), temp, filter);
- GST_DEBUG_OBJECT (pad, "transformed %" GST_PTR_FORMAT, caps);
- gst_caps_unref (temp);
- if (caps == NULL)
- goto done;
-
- /* and filter against the template of this pad */
- templ = gst_pad_get_pad_template_caps (pad);
- GST_DEBUG_OBJECT (pad, "our template %" GST_PTR_FORMAT, templ);
- /* We keep the caps sorted like the returned caps */
- temp = gst_caps_intersect_full (caps, templ, GST_CAPS_INTERSECT_FIRST);
- GST_DEBUG_OBJECT (pad, "intersected %" GST_PTR_FORMAT, temp);
- gst_caps_unref (caps);
- gst_caps_unref (templ);
- caps = temp;
+ /* then see what we can transform this to */
+ caps = gst_base_transform_transform_caps (trans,
- GST_PAD_DIRECTION (otherpad), temp);
++ GST_PAD_DIRECTION (otherpad), temp, filter);
+ GST_DEBUG_OBJECT (pad, "transformed %" GST_PTR_FORMAT, caps);
+ gst_caps_unref (temp);
+ if (caps == NULL)
+ goto done;
+
+ /* and filter against the template of this pad */
+ templ = gst_pad_get_pad_template_caps (pad);
+ GST_DEBUG_OBJECT (pad, "our template %" GST_PTR_FORMAT, templ);
+ /* We keep the caps sorted like the returned caps */
+ temp = gst_caps_intersect_full (caps, templ, GST_CAPS_INTERSECT_FIRST);
+ GST_DEBUG_OBJECT (pad, "intersected %" GST_PTR_FORMAT, temp);
+ gst_caps_unref (caps);
++ gst_caps_unref (templ);
+ caps = temp;
+ if (peercaps) {
/* Now try if we can put the untransformed downstream caps first */
temp = gst_caps_intersect_full (peercaps, caps, GST_CAPS_INTERSECT_FIRST);
if (!gst_caps_is_empty (temp)) {
/* getrange might silently return shortened buffers at the end of a file,
* we must, however, always return either the full requested data or NULL */
buf_offset = GST_BUFFER_OFFSET (buffer);
- buf_size = GST_BUFFER_SIZE (buffer);
+ buf_size = gst_buffer_get_size (buffer);
if ((buf_offset != -1 && buf_offset != offset) || buf_size < size) {
- GST_DEBUG ("droping short buffer: %" G_GUINT64_FORMAT "-%" G_GUINT64_FORMAT
+ GST_DEBUG ("dropping short buffer: %" G_GUINT64_FORMAT "-%" G_GUINT64_FORMAT
" instead of %" G_GUINT64_FORMAT "-%" G_GUINT64_FORMAT,
buf_offset, buf_offset + buf_size - 1, offset, offset + size - 1);
gst_buffer_unref (buffer);
GstTypeFindHelper *helper = (GstTypeFindHelper *) data;
GST_LOG_OBJECT (helper->obj,
- "'%s' called called suggest (%u, %" GST_PTR_FORMAT ")",
+ "'%s' called suggest (%u, %" GST_PTR_FORMAT ")",
- GST_PLUGIN_FEATURE_NAME (helper->factory), probability, caps);
+ GST_OBJECT_NAME (helper->factory), probability, caps);
if (probability > helper->best_probability) {
GstCaps *copy = gst_caps_copy (caps);
{
GstTypeFindHelper *helper = (GstTypeFindHelper *) data;
- GST_LOG_OBJECT (helper->obj, "'%s' called called get_length, returning %"
+ GST_LOG_OBJECT (helper->obj, "'%s' called get_length, returning %"
- G_GUINT64_FORMAT, GST_PLUGIN_FEATURE_NAME (helper->factory),
- helper->size);
+ G_GUINT64_FORMAT, GST_OBJECT_NAME (helper->factory), helper->size);
return helper->size;
}
GstTypeFindBufHelper *helper = (GstTypeFindBufHelper *) data;
GST_LOG_OBJECT (helper->obj,
- "'%s' called called suggest (%u, %" GST_PTR_FORMAT ")",
+ "'%s' called suggest (%u, %" GST_PTR_FORMAT ")",
- GST_PLUGIN_FEATURE_NAME (helper->factory), probability, caps);
+ GST_OBJECT_NAME (helper->factory), probability, caps);
/* Note: not >= as we call typefinders in order of rank, highest first */
if (probability > helper->best_probability) {
GST_OBJECT_UNLOCK (tee);
}
-/* we have no previous source pad we can use to proxy the pad alloc. Loop over
- * the source pads, try to alloc a buffer on each one of them. Keep a reference
- * to the first pad that succeeds, we will be using it to alloc more buffers
- * later. must be called with the OBJECT_LOCK on tee. */
-static GstFlowReturn
-gst_tee_find_buffer_alloc (GstTee * tee, guint64 offset, guint size,
- GstCaps * caps, GstBuffer ** buf)
+static gboolean
+gst_tee_sink_event (GstPad * pad, GstEvent * event)
{
- GstFlowReturn res;
- GList *pads;
- guint32 cookie;
-
- res = GST_FLOW_NOT_LINKED;
-
-retry:
- pads = GST_ELEMENT_CAST (tee)->srcpads;
- cookie = GST_ELEMENT_CAST (tee)->pads_cookie;
-
- while (pads) {
- GstPad *pad;
- PushData *data;
-
- pad = GST_PAD_CAST (pads->data);
- gst_object_ref (pad);
- GST_DEBUG_OBJECT (tee, "try alloc on pad %s:%s", GST_DEBUG_PAD_NAME (pad));
- GST_OBJECT_UNLOCK (tee);
-
- GST_TEE_DYN_LOCK (tee);
- data = g_object_get_qdata ((GObject *) pad, push_data);
- if (!data->removed)
- res = gst_pad_alloc_buffer (pad, offset, size, caps, buf);
- else
- res = GST_FLOW_NOT_LINKED;
- GST_TEE_DYN_UNLOCK (tee);
-
- GST_DEBUG_OBJECT (tee, "got return value %d", res);
-
- gst_object_unref (pad);
+ gboolean res;
- GST_OBJECT_LOCK (tee);
- if (GST_ELEMENT_CAST (tee)->pads_cookie != cookie) {
- GST_DEBUG_OBJECT (tee, "pad list changed, restart");
- /* pad list changed, restart. If the pad alloc function returned OK we
- * need to unref the buffer */
- if (res == GST_FLOW_OK)
- gst_buffer_unref (*buf);
- *buf = NULL;
- goto retry;
- }
- if (!data->removed && res == GST_FLOW_OK) {
- GST_DEBUG_OBJECT (tee, "we have a buffer on pad %s:%s",
- GST_DEBUG_PAD_NAME (pad));
- /* we have a buffer, keep the pad for later and exit the loop. */
- tee->allocpad = pad;
- GST_OBJECT_UNLOCK (tee);
- gst_tee_notify_alloc_pad (tee);
- GST_OBJECT_LOCK (tee);
+ switch (GST_EVENT_TYPE (event)) {
+ default:
+ res = gst_pad_event_default (pad, event);
break;
- }
- /* no valid buffer, try another pad */
- pads = g_list_next (pads);
}
+
return res;
}
PUSH_BYTES (8800);
CHECK_QUERY_POSITION (filesink, GST_FORMAT_BYTES, 8900);
- if (gst_pad_push_event (mysrcpad,
- gst_event_new_new_segment (TRUE, 1.0, GST_FORMAT_BYTES, 8800, -1,
- 0))) {
+ segment.start = 8800;
+ if (gst_pad_push_event (mysrcpad, gst_event_new_segment (&segment))) {
GST_LOG ("seek ok");
- /* make sure that that new position is reported immediately */
+ /* make sure that new position is reported immediately */
CHECK_QUERY_POSITION (filesink, GST_FORMAT_BYTES, 8800);
PUSH_BYTES (1);
CHECK_QUERY_POSITION (filesink, GST_FORMAT_BYTES, 8801);
fail_unless (qret == TRUE, "position wrong");
fail_unless (position == 10 * GST_SECOND, "position is wrong");
+ /* Since we are paused and the preroll queue has a length of 1, this function
+ * will return immediately. The EOS will complete the preroll and the
+ * position should now be 10 seconds. */
GST_DEBUG ("pushing EOS");
- event = gst_event_new_eos ();
- res = gst_pad_send_event (sinkpad, event);
- fail_unless (res == TRUE, "no TRUE return");
+ GST_DEBUG ("starting thread");
+ thread = g_thread_create ((GThreadFunc) send_eos, sinkpad, TRUE, NULL);
+ fail_if (thread == NULL, "no thread");
+
+ /* wait for preroll */
+ gst_element_get_state (sink, NULL, NULL, -1);
/* check if position is still 10 seconds */
- format = GST_FORMAT_TIME;
- gst_element_query_position (sink, &format, &position);
+ gst_element_query_position (sink, GST_FORMAT_TIME, &position);
GST_DEBUG ("EOS position %" GST_TIME_FORMAT, GST_TIME_ARGS (position));
fail_unless (position == 10 * GST_SECOND, "position is wrong");