static GstFlowReturn _chain (GstPad * pad, GstObject * object, GstBuffer * buffer) { GstBuffer *actual_buf = buffer; GstAggregator *self = GST_AGGREGATOR (object); GstAggregatorPrivate *priv = self->priv; GstAggregatorPad *aggpad = GST_AGGREGATOR_PAD (pad); GstAggregatorClass *aggclass = GST_AGGREGATOR_GET_CLASS (object); GST_DEBUG_OBJECT (aggpad, "Start chaining a buffer %" GST_PTR_FORMAT, buffer); if (g_atomic_int_get (&aggpad->priv->flushing) == TRUE) goto flushing; if (g_atomic_int_get (&aggpad->priv->pending_eos) == TRUE) goto eos; PAD_LOCK_EVENT (aggpad); if (aggpad->buffer) { GST_DEBUG_OBJECT (aggpad, "Waiting for buffer to be consumed"); PAD_WAIT_EVENT (aggpad); } PAD_UNLOCK_EVENT (aggpad); if (g_atomic_int_get (&aggpad->priv->flushing) == TRUE) goto flushing; if (aggclass->clip) { aggclass->clip (self, aggpad, buffer, &actual_buf); } PAD_LOCK_EVENT (aggpad); if (aggpad->buffer) gst_buffer_unref (aggpad->buffer); aggpad->buffer = actual_buf; PAD_UNLOCK_EVENT (aggpad); _add_aggregate_gsource (self); GST_DEBUG_OBJECT (aggpad, "Done chaining"); return priv->flow_return; flushing: gst_buffer_unref (buffer); GST_DEBUG_OBJECT (aggpad, "We are flushing"); return GST_FLOW_FLUSHING; eos: gst_buffer_unref (buffer); GST_DEBUG_OBJECT (pad, "We are EOS already..."); return GST_FLOW_EOS; }
static gboolean _unresponsive_timeout (GstClock * clock, GstClockTime time, GstClockID id, gpointer user_data) { GstAggregatorPad *aggpad; GstAggregator *self; if (user_data == NULL) return FALSE; aggpad = GST_AGGREGATOR_PAD (user_data); /* avoid holding the last reference to the parent element here */ PAD_LOCK_EVENT (aggpad); self = GST_AGGREGATOR (gst_pad_get_parent (GST_PAD (aggpad))); GST_DEBUG_OBJECT (aggpad, "marked unresponsive"); g_atomic_int_set (&aggpad->unresponsive, TRUE); if (self) { QUEUE_PUSH (self); gst_object_unref (self); } PAD_UNLOCK_EVENT (aggpad); return TRUE; }
/** * gst_aggregator_pad_get_buffer: * @pad: the pad to get buffer from * * Returns: (transfer full): A reference to the buffer in @pad or * NULL if no buffer was queued. You should unref the buffer after * usage. */ GstBuffer * gst_aggregator_pad_get_buffer (GstAggregatorPad * pad) { GstBuffer *buffer = NULL; PAD_LOCK_EVENT (pad); if (pad->buffer) buffer = gst_buffer_ref (pad->buffer); PAD_UNLOCK_EVENT (pad); return buffer; }
static gboolean pad_activate_mode_func (GstPad * pad, GstObject * parent, GstPadMode mode, gboolean active) { GstAggregatorPad *aggpad = GST_AGGREGATOR_PAD (pad); if (active == FALSE) { PAD_LOCK_EVENT (aggpad); g_atomic_int_set (&aggpad->priv->flushing, TRUE); gst_buffer_replace (&aggpad->buffer, NULL); PAD_BROADCAST_EVENT (aggpad); PAD_UNLOCK_EVENT (aggpad); } else { g_atomic_int_set (&aggpad->priv->flushing, FALSE); PAD_LOCK_EVENT (aggpad); PAD_BROADCAST_EVENT (aggpad); PAD_UNLOCK_EVENT (aggpad); } return TRUE; }
static gboolean _stop_pad (GstAggregator * self, GstAggregatorPad * pad, gpointer unused_udata) { _aggpad_flush (pad, self); PAD_LOCK_EVENT (pad); /* remove the timeouts */ if (pad->priv->timeout_id) { gst_clock_id_unschedule (pad->priv->timeout_id); gst_clock_id_unref (pad->priv->timeout_id); pad->priv->timeout_id = NULL; } PAD_UNLOCK_EVENT (pad); return TRUE; }
/** * gst_aggregator_pad_steal_buffer: * @pad: the pad to get buffer from * * Steal the ref to the buffer currently queued in @pad. * * Returns: (transfer full): The buffer in @pad or NULL if no buffer was * queued. You should unref the buffer after usage. */ GstBuffer * gst_aggregator_pad_steal_buffer (GstAggregatorPad * pad) { GstBuffer *buffer = NULL; PAD_LOCK_EVENT (pad); if (pad->buffer) { GST_TRACE_OBJECT (pad, "Consuming buffer"); buffer = pad->buffer; pad->buffer = NULL; if (pad->priv->pending_eos) { pad->priv->pending_eos = FALSE; pad->eos = TRUE; } PAD_BROADCAST_EVENT (pad); GST_DEBUG_OBJECT (pad, "Consummed: %" GST_PTR_FORMAT, buffer); } PAD_UNLOCK_EVENT (pad); return buffer; }
/* GstAggregator vmethods default implementations */ static gboolean _sink_event (GstAggregator * self, GstAggregatorPad * aggpad, GstEvent * event) { gboolean res = TRUE; GstPad *pad = GST_PAD (aggpad); GstAggregatorPrivate *priv = self->priv; GstAggregatorPadPrivate *padpriv = aggpad->priv; switch (GST_EVENT_TYPE (event)) { case GST_EVENT_FLUSH_START: { GstBuffer *tmpbuf; g_atomic_int_set (&aggpad->priv->flushing, TRUE); /* Remove pad buffer and wake up the streaming thread */ tmpbuf = gst_aggregator_pad_steal_buffer (aggpad); gst_buffer_replace (&tmpbuf, NULL); if (g_atomic_int_compare_and_exchange (&padpriv->pending_flush_start, TRUE, FALSE) == TRUE) { GST_DEBUG_OBJECT (aggpad, "Expecting FLUSH_STOP now"); g_atomic_int_set (&padpriv->pending_flush_stop, TRUE); } if (g_atomic_int_get (&priv->flush_seeking)) { /* If flush_seeking we forward the first FLUSH_START */ if (g_atomic_int_compare_and_exchange (&priv->pending_flush_start, TRUE, FALSE) == TRUE) { GST_DEBUG_OBJECT (self, "Flushing, pausing srcpad task"); _stop_srcpad_task (self, event); priv->flow_return = GST_FLOW_OK; GST_INFO_OBJECT (self, "Getting STREAM_LOCK while seeking"); GST_PAD_STREAM_LOCK (self->srcpad); GST_LOG_OBJECT (self, "GOT STREAM_LOCK"); event = NULL; goto eat; } } /* We forward only in one case: right after flush_seeking */ goto eat; } case GST_EVENT_FLUSH_STOP: { GST_DEBUG_OBJECT (aggpad, "Got FLUSH_STOP"); _aggpad_flush (aggpad, self); if (g_atomic_int_get (&priv->flush_seeking)) { g_atomic_int_set (&aggpad->priv->pending_flush_stop, FALSE); if (g_atomic_int_get (&priv->flush_seeking)) { if (_all_flush_stop_received (self)) { /* That means we received FLUSH_STOP/FLUSH_STOP on * all sinkpads -- Seeking is Done... sending FLUSH_STOP */ _flush (self); gst_pad_push_event (self->srcpad, event); priv->send_eos = TRUE; event = NULL; _add_aggregate_gsource (self); GST_INFO_OBJECT (self, "Releasing source pad STREAM_LOCK"); GST_PAD_STREAM_UNLOCK (self->srcpad); _start_srcpad_task (self); } } } /* We never forward the event */ goto eat; } case GST_EVENT_EOS: { GST_DEBUG_OBJECT (aggpad, "EOS"); /* We still have a buffer, and we don't want the subclass to have to * check for it. Mark pending_eos, eos will be set when steal_buffer is * called */ PAD_LOCK_EVENT (aggpad); if (!aggpad->buffer) { aggpad->eos = TRUE; } else { aggpad->priv->pending_eos = TRUE; } PAD_UNLOCK_EVENT (aggpad); _add_aggregate_gsource (self); goto eat; } case GST_EVENT_SEGMENT: { PAD_LOCK_EVENT (aggpad); gst_event_copy_segment (event, &aggpad->segment); PAD_UNLOCK_EVENT (aggpad); goto eat; } case GST_EVENT_STREAM_START: { goto eat; } case GST_EVENT_TAG: { GstTagList *tags; gst_event_parse_tag (event, &tags); if (gst_tag_list_get_scope (tags) == GST_TAG_SCOPE_STREAM) { gst_aggregator_merge_tags (self, tags, GST_TAG_MERGE_REPLACE); gst_event_unref (event); event = NULL; goto eat; } break; } default: { break; } } GST_DEBUG_OBJECT (pad, "Forwarding event: %" GST_PTR_FORMAT, event); return gst_pad_event_default (pad, GST_OBJECT (self), event); eat: GST_DEBUG_OBJECT (pad, "Eating event: %" GST_PTR_FORMAT, event); if (event) gst_event_unref (event); return res; }
/* GstAggregator vmethods default implementations */ static gboolean _sink_event (GstAggregator * self, GstAggregatorPad * aggpad, GstEvent * event) { gboolean res = TRUE; GstPad *pad = GST_PAD (aggpad); GstAggregatorPrivate *priv = self->priv; switch (GST_EVENT_TYPE (event)) { case GST_EVENT_FLUSH_START: { _flush_start (self, aggpad, event); /* We forward only in one case: right after flush_seeking */ event = NULL; goto eat; } case GST_EVENT_FLUSH_STOP: { GST_DEBUG_OBJECT (aggpad, "Got FLUSH_STOP"); _aggpad_flush (aggpad, self); if (g_atomic_int_get (&priv->flush_seeking)) { g_atomic_int_set (&aggpad->priv->pending_flush_stop, FALSE); if (g_atomic_int_get (&priv->flush_seeking)) { if (_all_flush_stop_received (self)) { /* That means we received FLUSH_STOP/FLUSH_STOP on * all sinkpads -- Seeking is Done... sending FLUSH_STOP */ _flush (self); gst_pad_push_event (self->srcpad, event); priv->send_eos = TRUE; event = NULL; QUEUE_PUSH (self); GST_INFO_OBJECT (self, "Releasing source pad STREAM_LOCK"); GST_PAD_STREAM_UNLOCK (self->srcpad); _start_srcpad_task (self); } } } /* We never forward the event */ goto eat; } case GST_EVENT_EOS: { GST_DEBUG_OBJECT (aggpad, "EOS"); /* We still have a buffer, and we don't want the subclass to have to * check for it. Mark pending_eos, eos will be set when steal_buffer is * called */ PAD_LOCK_EVENT (aggpad); if (!aggpad->buffer) { aggpad->eos = TRUE; } else { aggpad->priv->pending_eos = TRUE; } PAD_UNLOCK_EVENT (aggpad); QUEUE_PUSH (self); goto eat; } case GST_EVENT_SEGMENT: { PAD_LOCK_EVENT (aggpad); gst_event_copy_segment (event, &aggpad->segment); self->priv->seqnum = gst_event_get_seqnum (event); PAD_UNLOCK_EVENT (aggpad); goto eat; } case GST_EVENT_STREAM_START: { goto eat; } case GST_EVENT_TAG: { GstTagList *tags; gst_event_parse_tag (event, &tags); if (gst_tag_list_get_scope (tags) == GST_TAG_SCOPE_STREAM) { gst_aggregator_merge_tags (self, tags, GST_TAG_MERGE_REPLACE); gst_event_unref (event); event = NULL; goto eat; } break; } default: { break; } } GST_DEBUG_OBJECT (pad, "Forwarding event: %" GST_PTR_FORMAT, event); return gst_pad_event_default (pad, GST_OBJECT (self), event); eat: GST_DEBUG_OBJECT (pad, "Eating event: %" GST_PTR_FORMAT, event); if (event) gst_event_unref (event); return res; }
static GstFlowReturn _chain (GstPad * pad, GstObject * object, GstBuffer * buffer) { GstBuffer *actual_buf = buffer; GstAggregator *self = GST_AGGREGATOR (object); GstAggregatorPrivate *priv = self->priv; GstAggregatorPad *aggpad = GST_AGGREGATOR_PAD (pad); GstAggregatorClass *aggclass = GST_AGGREGATOR_GET_CLASS (object); GstClockTime timeout = gst_aggregator_get_timeout (self); GstClockTime now; GST_DEBUG_OBJECT (aggpad, "Start chaining a buffer %" GST_PTR_FORMAT, buffer); if (aggpad->priv->timeout_id) { gst_clock_id_unschedule (aggpad->priv->timeout_id); gst_clock_id_unref (aggpad->priv->timeout_id); aggpad->priv->timeout_id = NULL; } g_atomic_int_set (&aggpad->unresponsive, FALSE); PAD_STREAM_LOCK (aggpad); if (g_atomic_int_get (&aggpad->priv->flushing) == TRUE) goto flushing; if (g_atomic_int_get (&aggpad->priv->pending_eos) == TRUE) goto eos; PAD_LOCK_EVENT (aggpad); if (aggpad->buffer) { GST_DEBUG_OBJECT (aggpad, "Waiting for buffer to be consumed"); PAD_WAIT_EVENT (aggpad); } PAD_UNLOCK_EVENT (aggpad); if (g_atomic_int_get (&aggpad->priv->flushing) == TRUE) goto flushing; if (aggclass->clip) { aggclass->clip (self, aggpad, buffer, &actual_buf); } PAD_LOCK_EVENT (aggpad); if (aggpad->buffer) gst_buffer_unref (aggpad->buffer); aggpad->buffer = actual_buf; PAD_UNLOCK_EVENT (aggpad); PAD_STREAM_UNLOCK (aggpad); QUEUE_PUSH (self); if (GST_CLOCK_TIME_IS_VALID (timeout)) { now = gst_clock_get_time (self->clock); aggpad->priv->timeout_id = gst_clock_new_single_shot_id (self->clock, now + timeout); gst_clock_id_wait_async (aggpad->priv->timeout_id, _unresponsive_timeout, gst_object_ref (aggpad), gst_object_unref); } GST_DEBUG_OBJECT (aggpad, "Done chaining"); return priv->flow_return; flushing: PAD_STREAM_UNLOCK (aggpad); gst_buffer_unref (buffer); GST_DEBUG_OBJECT (aggpad, "We are flushing"); return GST_FLOW_FLUSHING; eos: PAD_STREAM_UNLOCK (aggpad); gst_buffer_unref (buffer); GST_DEBUG_OBJECT (pad, "We are EOS already..."); return GST_FLOW_EOS; }