}
}
-/* called when elements link. The sticky events from the srcpad are
- * copied to the sinkpad (when different) and the inactive flag is set,
- * this will make sure that we send the event to the sinkpad event
- * function when the next buffer of event arrives. */
+/* The sticky event with @idx from the srcpad is copied to the
+ * sinkpad (when different) and the inactive flag is set.
+ * This function applies the pad offsets in case of segment events.
+ * This will make sure that we send the event to the sinkpad event
+ * function when the next buffer of event arrives.
+ * Should be called with the OBJECT lock of both pads */
static gboolean
-replace_events (PadEvent srcev[], PadEvent sinkev[])
+replace_event (GstPad * srcpad, GstPad * sinkpad, guint idx)
{
- guint i;
+ PadEvent *srcev, *sinkev;
+ GstEvent *event;
gboolean inactive = FALSE;
- for (i = 0; i < GST_EVENT_MAX_STICKY; i++) {
- if (srcev[i].event != sinkev[i].event) {
- gst_event_replace (&sinkev[i].event, srcev[i].event);
- sinkev[i].active = FALSE;
+ srcev = &srcpad->priv->events[idx];
+
+ if ((event = srcev->event)) {
+ sinkev = &sinkpad->priv->events[idx];
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_SEGMENT:
+ {
+ GstSegment segment;
+ gint64 offset;
+
+ offset = srcpad->offset + sinkpad->offset;
+ if (offset != 0) {
+ gst_event_copy_segment (event, &segment);
+ /* adjust the base time. FIXME, check negative times, try to tweak the
+ * start to do clipping on negative times */
+ segment.base += offset;
+ /* make a new event from the updated segment */
+ event = gst_event_new_segment (&segment);
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ if (sinkev->event != event) {
+ /* replace when different */
+ gst_event_replace (&sinkev->event, event);
+ sinkev->active = FALSE;
inactive = TRUE;
}
}
return inactive;
}
+/* should be called with the OBJECT_LOCK */
static GstCaps *
get_pad_caps (GstPad * pad)
{
{
GstPadLinkReturn result;
GstElement *parent;
+ guint i;
+ gboolean inactive;
g_return_val_if_fail (GST_IS_PAD (srcpad), GST_PAD_LINK_REFUSED);
g_return_val_if_fail (GST_PAD_IS_SRC (srcpad), GST_PAD_LINK_WRONG_DIRECTION);
/* make sure we push the events from the source to this new peer, for this we
* copy the events on the sinkpad and mark EVENTS_PENDING */
- if (replace_events (srcpad->priv->events, sinkpad->priv->events))
+ inactive = FALSE;
+ for (i = 0; i < GST_EVENT_MAX_STICKY; i++)
+ inactive |= replace_event (srcpad, sinkpad, i);
+
+ /* we had some new inactive events, set our flag */
+ if (inactive)
GST_OBJECT_FLAG_SET (sinkpad, GST_PAD_NEED_EVENTS);
GST_OBJECT_UNLOCK (sinkpad);
* gst_pad_get_offset:
* @pad: a #GstPad
*
- * Get the offset applied to the running time of @pad.
+ * Get the offset applied to the running time of @pad. @pad has to be a source
+ * pad.
*
* Returns: the offset.
*/
void
gst_pad_set_offset (GstPad * pad, gint64 offset)
{
+ guint idx;
+ GstPad *peer;
+ GstPad *tmp = NULL;
+
g_return_if_fail (GST_IS_PAD (pad));
GST_OBJECT_LOCK (pad);
+ /* if nothing changed, do nothing */
+ if (pad->offset == offset)
+ goto done;
+
pad->offset = offset;
+
+ /* if no peer, we just updated the offset */
+ if ((peer = GST_PAD_PEER (pad)) == NULL)
+ goto done;
+
+ /* switch pads around when dealing with a sinkpad */
+ if (GST_PAD_IS_SINK (pad)) {
+ /* ref the peer so it doesn't go away when we release the lock */
+ tmp = gst_object_ref (peer);
+ /* make sure we get the peer (the srcpad) */
+ GST_OBJECT_UNLOCK (pad);
+
+ /* swap pads */
+ peer = pad;
+ pad = tmp;
+
+ GST_OBJECT_LOCK (pad);
+ /* check if the pad didn't get relinked */
+ if (GST_PAD_PEER (pad) != peer)
+ goto done;
+
+ /* we can release the ref now */
+ gst_object_unref (peer);
+ }
+
+ /* the index of the segment event in the array */
+ idx = GST_EVENT_STICKY_IDX_TYPE (GST_EVENT_SEGMENT);
+
+ /* lock order is srcpad >> sinkpad */
+ GST_OBJECT_LOCK (peer);
+ /* take the current segment event, adjust it and then place
+ * it on the sinkpad. events on the srcpad are always active. */
+ if (replace_event (pad, peer, idx))
+ GST_OBJECT_FLAG_SET (peer, GST_PAD_NEED_EVENTS);
+
+ GST_OBJECT_UNLOCK (peer);
+
+done:
GST_OBJECT_UNLOCK (pad);
}
{
GstPad *peerpad;
gboolean result;
+ gint64 offset;
g_return_val_if_fail (GST_IS_PAD (pad), FALSE);
g_return_val_if_fail (event != NULL, FALSE);
if ((peerpad = GST_PAD_PEER (pad)))
gst_object_ref (peerpad);
+
+ offset = pad->offset;
GST_OBJECT_UNLOCK (pad);
/* backwards compatibility mode for caps */
- if (GST_EVENT_TYPE (event) == GST_EVENT_CAPS) {
- GstCaps *caps;
- gst_event_parse_caps (event, &caps);
- /* FIXME, this is awkward because we don't check flushing here which means
- * that we can call the setcaps functions on flushing pads, this is not
- * quite what we want */
- gst_pad_call_setcaps (pad, caps);
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_CAPS:
+ {
+ GstCaps *caps;
+
+ gst_event_parse_caps (event, &caps);
+ /* FIXME, this is awkward because we don't check flushing here which means
+ * that we can call the setcaps functions on flushing pads, this is not
+ * quite what we want, otoh, this code should just go away and elements
+ * that set caps on their sinkpad should just setup stuff themselves. */
+ gst_pad_call_setcaps (pad, caps);
+ break;
+ }
+ case GST_EVENT_SEGMENT:
+ {
+ /* check if we need to adjust the segment */
+ if (offset != 0 && peerpad != NULL) {
+ GstSegment segment;
+
+ /* copy segment values */
+ gst_event_copy_segment (event, &segment);
+ gst_event_unref (event);
+
+ /* adjust and make a new event with the offset applied */
+ segment.base += offset;
+ event = gst_event_new_segment (&segment);
+ }
+ break;
+ }
+ default:
+ break;
}
/* now check the peer pad */