mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-13 02:45:35 +00:00
aggregator: Add property to select how to decide on a start time
Before aggregator based elements always started at running time 0, now it's possible to select the first input buffer running time or explicitly set a start-time value. https://bugzilla.gnome.org/show_bug.cgi?id=749966
This commit is contained in:
parent
9ab98e9b22
commit
3030d1b501
1 changed files with 125 additions and 4 deletions
|
@ -71,6 +71,33 @@
|
|||
|
||||
#include "gstaggregator.h"
|
||||
|
||||
typedef enum
|
||||
{
|
||||
GST_AGGREGATOR_START_TIME_SELECTION_ZERO,
|
||||
GST_AGGREGATOR_START_TIME_SELECTION_FIRST,
|
||||
GST_AGGREGATOR_START_TIME_SELECTION_SET
|
||||
} GstAggregatorStartTimeSelection;
|
||||
|
||||
static GType
|
||||
gst_aggregator_start_time_selection_get_type (void)
|
||||
{
|
||||
static GType gtype = 0;
|
||||
|
||||
if (gtype == 0) {
|
||||
static const GEnumValue values[] = {
|
||||
{GST_AGGREGATOR_START_TIME_SELECTION_ZERO,
|
||||
"Start at 0 running time (default)", "zero"},
|
||||
{GST_AGGREGATOR_START_TIME_SELECTION_FIRST,
|
||||
"Start at first observed input running time", "first"},
|
||||
{GST_AGGREGATOR_START_TIME_SELECTION_SET,
|
||||
"Set start time with start-time property", "set"},
|
||||
{0, NULL, NULL}
|
||||
};
|
||||
|
||||
gtype = g_enum_register_static ("GstAggregatorStartTimeSelection", values);
|
||||
}
|
||||
return gtype;
|
||||
}
|
||||
|
||||
/* Might become API */
|
||||
static void gst_aggregator_merge_tags (GstAggregator * aggregator,
|
||||
|
@ -255,6 +282,10 @@ struct _GstAggregatorPrivate
|
|||
GMutex src_lock;
|
||||
GCond src_cond;
|
||||
|
||||
gboolean first_buffer;
|
||||
GstAggregatorStartTimeSelection start_time_selection;
|
||||
GstClockTime start_time;
|
||||
|
||||
/* properties */
|
||||
gint64 latency;
|
||||
};
|
||||
|
@ -268,12 +299,16 @@ typedef struct
|
|||
gboolean one_actually_seeked;
|
||||
} EventData;
|
||||
|
||||
#define DEFAULT_LATENCY 0
|
||||
#define DEFAULT_LATENCY 0
|
||||
#define DEFAULT_START_TIME_SELECTION GST_AGGREGATOR_START_TIME_SELECTION_FIRST
|
||||
#define DEFAULT_START_TIME (-1)
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_LATENCY,
|
||||
PROP_START_TIME_SELECTION,
|
||||
PROP_START_TIME,
|
||||
PROP_LAST
|
||||
};
|
||||
|
||||
|
@ -374,6 +409,14 @@ gst_aggregator_check_pads_ready (GstAggregator * self)
|
|||
pad = l->data;
|
||||
|
||||
PAD_LOCK (pad);
|
||||
|
||||
/* In live mode, having a single pad with buffers is enough to
|
||||
* generate a start time from it. In non-live mode all pads need
|
||||
* to have a buffer
|
||||
*/
|
||||
if (self->priv->peer_latency_live && pad->priv->buffer)
|
||||
self->priv->first_buffer = FALSE;
|
||||
|
||||
if (pad->priv->buffer == NULL && !pad->priv->eos) {
|
||||
PAD_UNLOCK (pad);
|
||||
goto pad_not_ready;
|
||||
|
@ -382,6 +425,8 @@ gst_aggregator_check_pads_ready (GstAggregator * self)
|
|||
|
||||
}
|
||||
|
||||
self->priv->first_buffer = FALSE;
|
||||
|
||||
GST_OBJECT_UNLOCK (self);
|
||||
GST_LOG_OBJECT (self, "pads are ready");
|
||||
return TRUE;
|
||||
|
@ -407,6 +452,7 @@ gst_aggregator_reset_flow_values (GstAggregator * self)
|
|||
self->priv->send_stream_start = TRUE;
|
||||
self->priv->send_segment = TRUE;
|
||||
gst_segment_init (&self->segment, GST_FORMAT_TIME);
|
||||
self->priv->first_buffer = TRUE;
|
||||
GST_OBJECT_UNLOCK (self);
|
||||
}
|
||||
|
||||
|
@ -567,9 +613,19 @@ gst_aggregator_wait_and_check (GstAggregator * self, gboolean * timeout)
|
|||
|
||||
start = gst_aggregator_get_next_time (self);
|
||||
|
||||
/* If we're not live, or if we use the running time
|
||||
* of the first buffer as start time, we wait until
|
||||
* all pads have buffers.
|
||||
* Otherwise (i.e. if we are live!), we wait on the clock
|
||||
* and if a pad does not have a buffer in time we ignore
|
||||
* that pad.
|
||||
*/
|
||||
if (!GST_CLOCK_TIME_IS_VALID (latency) ||
|
||||
!GST_IS_CLOCK (GST_ELEMENT_CLOCK (self)) ||
|
||||
!GST_CLOCK_TIME_IS_VALID (start)) {
|
||||
!GST_CLOCK_TIME_IS_VALID (start) ||
|
||||
(self->priv->first_buffer
|
||||
&& self->priv->start_time_selection ==
|
||||
GST_AGGREGATOR_START_TIME_SELECTION_FIRST)) {
|
||||
/* We wake up here when something happened, and below
|
||||
* then check if we're ready now. If we return FALSE,
|
||||
* we will be directly called again.
|
||||
|
@ -602,7 +658,6 @@ gst_aggregator_wait_and_check (GstAggregator * self, gboolean * timeout)
|
|||
GST_TIME_ARGS (start), GST_TIME_ARGS (latency),
|
||||
GST_TIME_ARGS (gst_clock_get_time (clock)));
|
||||
|
||||
|
||||
self->priv->aggregate_id = gst_clock_new_single_shot_id (clock, time);
|
||||
gst_object_unref (clock);
|
||||
SRC_UNLOCK (self);
|
||||
|
@ -669,7 +724,6 @@ gst_aggregator_aggregate_func (GstAggregator * self)
|
|||
continue;
|
||||
|
||||
GST_TRACE_OBJECT (self, "Actually aggregating!");
|
||||
|
||||
flow_return = klass->aggregate (self, timeout);
|
||||
|
||||
GST_OBJECT_LOCK (self);
|
||||
|
@ -1463,6 +1517,9 @@ gst_aggregator_do_seek (GstAggregator * self, GstEvent * event)
|
|||
|
||||
gst_segment_do_seek (&self->segment, rate, fmt, flags, start_type, start,
|
||||
stop_type, stop, NULL);
|
||||
|
||||
/* Seeking sets a position */
|
||||
self->priv->first_buffer = FALSE;
|
||||
GST_OBJECT_UNLOCK (self);
|
||||
|
||||
/* forward the seek upstream */
|
||||
|
@ -1680,6 +1737,12 @@ gst_aggregator_set_property (GObject * object, guint prop_id,
|
|||
case PROP_LATENCY:
|
||||
gst_aggregator_set_latency_property (agg, g_value_get_int64 (value));
|
||||
break;
|
||||
case PROP_START_TIME_SELECTION:
|
||||
agg->priv->start_time_selection = g_value_get_enum (value);
|
||||
break;
|
||||
case PROP_START_TIME:
|
||||
agg->priv->start_time = g_value_get_uint64 (value);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
|
@ -1696,6 +1759,12 @@ gst_aggregator_get_property (GObject * object, guint prop_id,
|
|||
case PROP_LATENCY:
|
||||
g_value_set_int64 (value, gst_aggregator_get_latency_property (agg));
|
||||
break;
|
||||
case PROP_START_TIME_SELECTION:
|
||||
g_value_set_enum (value, agg->priv->start_time_selection);
|
||||
break;
|
||||
case PROP_START_TIME:
|
||||
g_value_set_uint64 (value, agg->priv->start_time);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
|
@ -1743,6 +1812,19 @@ gst_aggregator_class_init (GstAggregatorClass * klass)
|
|||
(G_MAXLONG == G_MAXINT64) ? G_MAXINT64 : (G_MAXLONG * GST_SECOND - 1),
|
||||
DEFAULT_LATENCY, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_property (gobject_class, PROP_START_TIME_SELECTION,
|
||||
g_param_spec_enum ("start-time-selection", "Start Time Selection",
|
||||
"Decides which start time is output",
|
||||
gst_aggregator_start_time_selection_get_type (),
|
||||
DEFAULT_START_TIME_SELECTION,
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_property (gobject_class, PROP_START_TIME,
|
||||
g_param_spec_uint64 ("start-time", "Start Time",
|
||||
"Start time to use if start-time-selection=set", 0,
|
||||
G_MAXUINT64,
|
||||
DEFAULT_START_TIME, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
GST_DEBUG_REGISTER_FUNCPTR (gst_aggregator_stop_pad);
|
||||
}
|
||||
|
||||
|
@ -1785,6 +1867,8 @@ gst_aggregator_init (GstAggregator * self, GstAggregatorClass * klass)
|
|||
gst_element_add_pad (GST_ELEMENT (self), self->srcpad);
|
||||
|
||||
self->priv->latency = DEFAULT_LATENCY;
|
||||
self->priv->start_time_selection = DEFAULT_START_TIME_SELECTION;
|
||||
self->priv->start_time = DEFAULT_START_TIME;
|
||||
|
||||
g_mutex_init (&self->priv->src_lock);
|
||||
g_cond_init (&self->priv->src_cond);
|
||||
|
@ -1860,6 +1944,43 @@ gst_aggregator_pad_chain (GstPad * pad, GstObject * object, GstBuffer * buffer)
|
|||
|
||||
flow_return = aggpad->priv->flow_return;
|
||||
|
||||
if (self->priv->first_buffer) {
|
||||
GstClockTime start_time;
|
||||
|
||||
switch (self->priv->start_time_selection) {
|
||||
case GST_AGGREGATOR_START_TIME_SELECTION_ZERO:
|
||||
default:
|
||||
start_time = 0;
|
||||
break;
|
||||
case GST_AGGREGATOR_START_TIME_SELECTION_FIRST:
|
||||
start_time = GST_BUFFER_PTS (actual_buf);
|
||||
if (start_time != -1) {
|
||||
start_time = MAX (start_time, aggpad->segment.start);
|
||||
start_time =
|
||||
gst_segment_to_running_time (&aggpad->segment, GST_FORMAT_TIME,
|
||||
start_time);
|
||||
}
|
||||
break;
|
||||
case GST_AGGREGATOR_START_TIME_SELECTION_SET:
|
||||
start_time = self->priv->start_time;
|
||||
if (start_time == -1)
|
||||
start_time = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (start_time != -1) {
|
||||
if (self->segment.position == -1)
|
||||
self->segment.position = start_time;
|
||||
else
|
||||
self->segment.position = MIN (start_time, self->segment.position);
|
||||
self->segment.start = MIN (start_time, self->segment.start);
|
||||
self->segment.time = MIN (start_time, self->segment.time);
|
||||
|
||||
GST_DEBUG_OBJECT (self, "Selecting start time %" GST_TIME_FORMAT,
|
||||
GST_TIME_ARGS (start_time));
|
||||
}
|
||||
}
|
||||
|
||||
PAD_UNLOCK (aggpad);
|
||||
PAD_FLUSH_UNLOCK (aggpad);
|
||||
|
||||
|
|
Loading…
Reference in a new issue