aggregator: add simple support for caps handling

Modelled off the videoaggregator caps handling as that seems the most
mature aggregtor-using implementation that has caps handling there is.

https://bugzilla.gnome.org/show_bug.cgi?id=776931
This commit is contained in:
Matthew Waters 2017-05-20 14:24:57 +02:00 committed by Olivier Crête
parent ed8512c53e
commit 7c53043386
15 changed files with 382 additions and 379 deletions

View file

@ -108,11 +108,14 @@ gst_gl_base_mixer_pad_set_property (GObject * object, guint prop_id,
} }
static gboolean static gboolean
_negotiated_caps (GstVideoAggregator * vagg, GstCaps * caps) _negotiated_caps (GstAggregator * agg, GstCaps * caps)
{ {
GstGLBaseMixer *mix = GST_GL_BASE_MIXER (vagg); GstGLBaseMixer *mix = GST_GL_BASE_MIXER (agg);
return gst_gl_base_mixer_do_bufferpool (mix, caps); if (!gst_gl_base_mixer_do_bufferpool (mix, caps))
return FALSE;
return GST_AGGREGATOR_CLASS (parent_class)->negotiated_src_caps (agg, caps);
} }
static gboolean static gboolean
@ -324,9 +327,6 @@ gst_gl_base_mixer_class_init (GstGLBaseMixerClass * klass)
{ {
GObjectClass *gobject_class; GObjectClass *gobject_class;
GstElementClass *element_class; GstElementClass *element_class;
GstVideoAggregatorClass *videoaggregator_class =
(GstVideoAggregatorClass *) klass;
GstAggregatorClass *agg_class = (GstAggregatorClass *) klass; GstAggregatorClass *agg_class = (GstAggregatorClass *) klass;
GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "glmixer", 0, "opengl mixer"); GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "glmixer", 0, "opengl mixer");
@ -350,8 +350,7 @@ gst_gl_base_mixer_class_init (GstGLBaseMixerClass * klass)
agg_class->src_activate = gst_gl_base_mixer_src_activate_mode; agg_class->src_activate = gst_gl_base_mixer_src_activate_mode;
agg_class->stop = gst_gl_base_mixer_stop; agg_class->stop = gst_gl_base_mixer_stop;
agg_class->start = gst_gl_base_mixer_start; agg_class->start = gst_gl_base_mixer_start;
agg_class->negotiated_src_caps = _negotiated_caps;
videoaggregator_class->negotiated_caps = _negotiated_caps;
klass->propose_allocation = _default_propose_allocation; klass->propose_allocation = _default_propose_allocation;

View file

@ -96,16 +96,16 @@ gst_gl_mixer_pad_set_property (GObject * object, guint prop_id,
} }
static gboolean static gboolean
_negotiated_caps (GstVideoAggregator * vagg, GstCaps * caps) _negotiated_caps (GstAggregator * agg, GstCaps * caps)
{ {
GstGLMixer *mix = GST_GL_MIXER (vagg); GstGLMixer *mix = GST_GL_MIXER (agg);
gboolean ret; gboolean ret;
mix->priv->negotiated = TRUE; mix->priv->negotiated = TRUE;
gst_caps_replace (&mix->out_caps, caps); gst_caps_replace (&mix->out_caps, caps);
ret = GST_VIDEO_AGGREGATOR_CLASS (parent_class)->negotiated_caps (vagg, caps); ret = GST_AGGREGATOR_CLASS (parent_class)->negotiated_src_caps (agg, caps);
return ret; return ret;
} }
@ -215,29 +215,6 @@ gst_gl_mixer_pad_sink_acceptcaps (GstPad * pad, GstGLMixer * mix,
return ret; return ret;
} }
/* copies the given caps */
static GstCaps *
_update_caps (GstVideoAggregator * vagg, GstCaps * caps, GstCaps * filter)
{
GstCaps *tmp;
guint i, n;
if (filter) {
tmp = gst_caps_intersect (caps, filter);
tmp = gst_caps_make_writable (tmp);
} else {
tmp = gst_caps_copy (caps);
}
n = gst_caps_get_size (tmp);
for (i = 0; i < n; i++) {
gst_caps_set_features (tmp, i,
gst_caps_features_from_string (GST_CAPS_FEATURE_MEMORY_GL_MEMORY));
}
return tmp;
}
static GstCaps * static GstCaps *
gst_gl_mixer_pad_sink_getcaps (GstPad * pad, GstGLMixer * mix, GstCaps * filter) gst_gl_mixer_pad_sink_getcaps (GstPad * pad, GstGLMixer * mix, GstCaps * filter)
{ {
@ -391,11 +368,10 @@ gst_gl_mixer_class_init (GstGLMixerClass * klass)
agg_class->src_query = gst_gl_mixer_src_query; agg_class->src_query = gst_gl_mixer_src_query;
agg_class->stop = gst_gl_mixer_stop; agg_class->stop = gst_gl_mixer_stop;
agg_class->start = gst_gl_mixer_start; agg_class->start = gst_gl_mixer_start;
agg_class->negotiated_src_caps = _negotiated_caps;
videoaggregator_class->aggregate_frames = gst_gl_mixer_aggregate_frames; videoaggregator_class->aggregate_frames = gst_gl_mixer_aggregate_frames;
videoaggregator_class->get_output_buffer = gst_gl_mixer_get_output_buffer; videoaggregator_class->get_output_buffer = gst_gl_mixer_get_output_buffer;
videoaggregator_class->negotiated_caps = _negotiated_caps;
videoaggregator_class->update_caps = _update_caps;
videoaggregator_class->find_best_format = _find_best_format; videoaggregator_class->find_best_format = _find_best_format;
mix_class->propose_allocation = gst_gl_mixer_propose_allocation; mix_class->propose_allocation = gst_gl_mixer_propose_allocation;

View file

@ -81,10 +81,8 @@ gst_gl_stereo_mix_pad_init (GstGLStereoMixPad * pad)
#define gst_gl_stereo_mix_parent_class parent_class #define gst_gl_stereo_mix_parent_class parent_class
G_DEFINE_TYPE (GstGLStereoMix, gst_gl_stereo_mix, GST_TYPE_GL_MIXER); G_DEFINE_TYPE (GstGLStereoMix, gst_gl_stereo_mix, GST_TYPE_GL_MIXER);
static GstCaps *_update_caps (GstVideoAggregator * vagg, GstCaps * caps, static GstCaps *_update_caps (GstVideoAggregator * vagg, GstCaps * caps);
GstCaps * filter); static gboolean _negotiated_caps (GstAggregator * aggregator, GstCaps * caps);
static gboolean _negotiated_caps (GstVideoAggregator * videoaggregator,
GstCaps * caps);
gboolean gst_gl_stereo_mix_make_output (GstGLStereoMix * mix); gboolean gst_gl_stereo_mix_make_output (GstGLStereoMix * mix);
static gboolean gst_gl_stereo_mix_process_frames (GstGLStereoMix * mixer); static gboolean gst_gl_stereo_mix_process_frames (GstGLStereoMix * mixer);
@ -188,10 +186,10 @@ gst_gl_stereo_mix_class_init (GstGLStereoMixClass * klass)
agg_class->stop = gst_gl_stereo_mix_stop; agg_class->stop = gst_gl_stereo_mix_stop;
agg_class->start = gst_gl_stereo_mix_start; agg_class->start = gst_gl_stereo_mix_start;
agg_class->src_query = gst_gl_stereo_mix_src_query; agg_class->src_query = gst_gl_stereo_mix_src_query;
agg_class->negotiated_src_caps = _negotiated_caps;
videoaggregator_class->aggregate_frames = gst_gl_stereo_mix_aggregate_frames; videoaggregator_class->aggregate_frames = gst_gl_stereo_mix_aggregate_frames;
videoaggregator_class->update_caps = _update_caps; videoaggregator_class->update_caps = _update_caps;
videoaggregator_class->negotiated_caps = _negotiated_caps;
videoaggregator_class->get_output_buffer = videoaggregator_class->get_output_buffer =
gst_gl_stereo_mix_get_output_buffer; gst_gl_stereo_mix_get_output_buffer;
@ -470,7 +468,7 @@ get_converted_caps (GstGLStereoMix * mix, GstCaps * caps)
/* Return the possible output caps based on inputs and downstream prefs */ /* Return the possible output caps based on inputs and downstream prefs */
static GstCaps * static GstCaps *
_update_caps (GstVideoAggregator * vagg, GstCaps * caps, GstCaps * filter) _update_caps (GstVideoAggregator * vagg, GstCaps * caps)
{ {
GstGLStereoMix *mix = GST_GL_STEREO_MIX (vagg); GstGLStereoMix *mix = GST_GL_STEREO_MIX (vagg);
GList *l; GList *l;
@ -563,16 +561,16 @@ _update_caps (GstVideoAggregator * vagg, GstCaps * caps, GstCaps * filter)
/* Called after videoaggregator fixates our caps */ /* Called after videoaggregator fixates our caps */
static gboolean static gboolean
_negotiated_caps (GstVideoAggregator * vagg, GstCaps * caps) _negotiated_caps (GstAggregator * agg, GstCaps * caps)
{ {
GstVideoAggregator *vagg = GST_VIDEO_AGGREGATOR (agg);
GstGLStereoMix *mix = GST_GL_STEREO_MIX (vagg); GstGLStereoMix *mix = GST_GL_STEREO_MIX (vagg);
GstCaps *in_caps; GstCaps *in_caps;
GST_LOG_OBJECT (mix, "Configured output caps %" GST_PTR_FORMAT, caps); GST_LOG_OBJECT (mix, "Configured output caps %" GST_PTR_FORMAT, caps);
if (GST_VIDEO_AGGREGATOR_CLASS (parent_class)->negotiated_caps) if (GST_AGGREGATOR_CLASS (parent_class)->negotiated_src_caps)
if (!GST_VIDEO_AGGREGATOR_CLASS (parent_class)->negotiated_caps (vagg, if (!GST_AGGREGATOR_CLASS (parent_class)->negotiated_src_caps (agg, caps))
caps))
return FALSE; return FALSE;
/* Update the glview_convert output */ /* Update the glview_convert output */

View file

@ -453,9 +453,8 @@ static void gst_gl_video_mixer_set_property (GObject * object, guint prop_id,
static void gst_gl_video_mixer_get_property (GObject * object, guint prop_id, static void gst_gl_video_mixer_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec); GValue * value, GParamSpec * pspec);
static GstCaps *_update_caps (GstVideoAggregator * vagg, GstCaps * caps, static GstCaps *_update_caps (GstVideoAggregator * vagg, GstCaps * caps);
GstCaps * filter); static GstCaps *_fixate_caps (GstAggregator * agg, GstCaps * caps);
static GstCaps *_fixate_caps (GstVideoAggregator * vagg, GstCaps * caps);
static gboolean gst_gl_video_mixer_propose_allocation (GstGLBaseMixer * static gboolean gst_gl_video_mixer_propose_allocation (GstGLBaseMixer *
base_mix, GstGLBaseMixerPad * base_pad, GstQuery * decide_query, base_mix, GstGLBaseMixerPad * base_pad, GstQuery * decide_query,
GstQuery * query); GstQuery * query);
@ -874,9 +873,9 @@ gst_gl_video_mixer_class_init (GstGLVideoMixerClass * klass)
gst_gl_video_mixer_process_textures; gst_gl_video_mixer_process_textures;
vagg_class->update_caps = _update_caps; vagg_class->update_caps = _update_caps;
vagg_class->fixate_caps = _fixate_caps;
agg_class->sinkpads_type = GST_TYPE_GL_VIDEO_MIXER_PAD; agg_class->sinkpads_type = GST_TYPE_GL_VIDEO_MIXER_PAD;
agg_class->fixate_src_caps = _fixate_caps;
mix_class->propose_allocation = gst_gl_video_mixer_propose_allocation; mix_class->propose_allocation = gst_gl_video_mixer_propose_allocation;
@ -986,7 +985,7 @@ _mixer_pad_get_output_size (GstGLVideoMixer * mix,
} }
static GstCaps * static GstCaps *
_update_caps (GstVideoAggregator * vagg, GstCaps * caps, GstCaps * filter) _update_caps (GstVideoAggregator * vagg, GstCaps * caps)
{ {
GstCaps *ret; GstCaps *ret;
GList *l; GList *l;
@ -1014,18 +1013,15 @@ _update_caps (GstVideoAggregator * vagg, GstCaps * caps, GstCaps * filter)
GST_OBJECT_UNLOCK (vagg); GST_OBJECT_UNLOCK (vagg);
if (filter) {
ret = gst_caps_intersect (caps, filter);
} else {
ret = gst_caps_ref (caps); ret = gst_caps_ref (caps);
}
return ret; return ret;
} }
static GstCaps * static GstCaps *
_fixate_caps (GstVideoAggregator * vagg, GstCaps * caps) _fixate_caps (GstAggregator * agg, GstCaps * caps)
{ {
GstVideoAggregator *vagg = GST_VIDEO_AGGREGATOR (agg);
GstGLVideoMixer *mix = GST_GL_VIDEO_MIXER (vagg); GstGLVideoMixer *mix = GST_GL_VIDEO_MIXER (vagg);
gint best_width = 0, best_height = 0; gint best_width = 0, best_height = 0;
gint best_fps_n = 0, best_fps_d = 0; gint best_fps_n = 0, best_fps_d = 0;

View file

@ -144,8 +144,6 @@ struct _GstAudioAggregatorPrivate
{ {
GMutex mutex; GMutex mutex;
gboolean send_caps; /* aagg lock */
/* All three properties are unprotected, can't be modified while streaming */ /* All three properties are unprotected, can't be modified while streaming */
/* Size in frames that is output per buffer */ /* Size in frames that is output per buffer */
GstClockTime output_buffer_duration; GstClockTime output_buffer_duration;
@ -189,6 +187,8 @@ static GstFlowReturn gst_audio_aggregator_aggregate (GstAggregator * agg,
gboolean timeout); gboolean timeout);
static gboolean sync_pad_values (GstAudioAggregator * aagg, static gboolean sync_pad_values (GstAudioAggregator * aagg,
GstAudioAggregatorPad * pad); GstAudioAggregatorPad * pad);
static gboolean gst_audio_aggregator_negotiated_src_caps (GstAggregator * agg,
GstCaps * caps);
#define DEFAULT_OUTPUT_BUFFER_DURATION (10 * GST_MSECOND) #define DEFAULT_OUTPUT_BUFFER_DURATION (10 * GST_MSECOND)
#define DEFAULT_ALIGNMENT_THRESHOLD (40 * GST_MSECOND) #define DEFAULT_ALIGNMENT_THRESHOLD (40 * GST_MSECOND)
@ -251,6 +251,8 @@ gst_audio_aggregator_class_init (GstAudioAggregatorClass * klass)
GST_DEBUG_FUNCPTR (gst_audio_aggregator_aggregate); GST_DEBUG_FUNCPTR (gst_audio_aggregator_aggregate);
gstaggregator_class->clip = GST_DEBUG_FUNCPTR (gst_audio_aggregator_do_clip); gstaggregator_class->clip = GST_DEBUG_FUNCPTR (gst_audio_aggregator_do_clip);
gstaggregator_class->get_next_time = gst_audio_aggregator_get_next_time; gstaggregator_class->get_next_time = gst_audio_aggregator_get_next_time;
gstaggregator_class->negotiated_src_caps =
gst_audio_aggregator_negotiated_src_caps;
klass->create_output_buffer = gst_audio_aggregator_create_output_buffer; klass->create_output_buffer = gst_audio_aggregator_create_output_buffer;
@ -656,9 +658,10 @@ gst_audio_aggregator_set_sink_caps (GstAudioAggregator * aagg,
} }
gboolean static gboolean
gst_audio_aggregator_set_src_caps (GstAudioAggregator * aagg, GstCaps * caps) gst_audio_aggregator_negotiated_src_caps (GstAggregator * agg, GstCaps * caps)
{ {
GstAudioAggregator *aagg = GST_AUDIO_AGGREGATOR (agg);
GstAudioInfo info; GstAudioInfo info;
if (!gst_audio_info_from_caps (&info, caps)) { if (!gst_audio_info_from_caps (&info, caps)) {
@ -674,8 +677,6 @@ gst_audio_aggregator_set_src_caps (GstAudioAggregator * aagg, GstCaps * caps)
gst_caps_replace (&aagg->current_caps, caps); gst_caps_replace (&aagg->current_caps, caps);
memcpy (&aagg->info, &info, sizeof (info)); memcpy (&aagg->info, &info, sizeof (info));
aagg->priv->send_caps = TRUE;
} }
GST_OBJECT_UNLOCK (aagg); GST_OBJECT_UNLOCK (aagg);
@ -683,7 +684,9 @@ gst_audio_aggregator_set_src_caps (GstAudioAggregator * aagg, GstCaps * caps)
/* send caps event later, after stream-start event */ /* send caps event later, after stream-start event */
return TRUE; return
GST_AGGREGATOR_CLASS
(gst_audio_aggregator_parent_class)->negotiated_src_caps (agg, caps);
} }
@ -1132,21 +1135,13 @@ gst_audio_aggregator_aggregate (GstAggregator * agg, gboolean timeout)
GST_OBJECT_UNLOCK (agg); GST_OBJECT_UNLOCK (agg);
GST_AUDIO_AGGREGATOR_UNLOCK (aagg); GST_AUDIO_AGGREGATOR_UNLOCK (aagg);
return GST_FLOW_OK; return GST_AGGREGATOR_FLOW_NEED_DATA;
} else { } else {
GST_OBJECT_UNLOCK (agg); GST_OBJECT_UNLOCK (agg);
goto not_negotiated; goto not_negotiated;
} }
} }
if (aagg->priv->send_caps) {
GST_OBJECT_UNLOCK (agg);
gst_aggregator_set_src_caps (agg, aagg->current_caps);
GST_OBJECT_LOCK (agg);
aagg->priv->send_caps = FALSE;
}
rate = GST_AUDIO_INFO_RATE (&aagg->info); rate = GST_AUDIO_INFO_RATE (&aagg->info);
bpf = GST_AUDIO_INFO_BPF (&aagg->info); bpf = GST_AUDIO_INFO_BPF (&aagg->info);
@ -1296,7 +1291,7 @@ gst_audio_aggregator_aggregate (GstAggregator * agg, gboolean timeout)
/* We dropped a buffer, retry */ /* We dropped a buffer, retry */
GST_LOG_OBJECT (aagg, "A pad dropped a buffer, wait for the next one"); GST_LOG_OBJECT (aagg, "A pad dropped a buffer, wait for the next one");
GST_AUDIO_AGGREGATOR_UNLOCK (aagg); GST_AUDIO_AGGREGATOR_UNLOCK (aagg);
return GST_FLOW_OK; return GST_AGGREGATOR_FLOW_NEED_DATA;
} }
if (!is_done && !is_eos) { if (!is_done && !is_eos) {
@ -1304,7 +1299,7 @@ gst_audio_aggregator_aggregate (GstAggregator * agg, gboolean timeout)
GST_LOG_OBJECT (aagg, GST_LOG_OBJECT (aagg,
"We're not done yet for the current offset, waiting for more data"); "We're not done yet for the current offset, waiting for more data");
GST_AUDIO_AGGREGATOR_UNLOCK (aagg); GST_AUDIO_AGGREGATOR_UNLOCK (aagg);
return GST_FLOW_OK; return GST_AGGREGATOR_FLOW_NEED_DATA;
} }
if (is_eos) { if (is_eos) {

View file

@ -162,9 +162,6 @@ void
gst_audio_aggregator_set_sink_caps (GstAudioAggregator * aagg, gst_audio_aggregator_set_sink_caps (GstAudioAggregator * aagg,
GstAudioAggregatorPad * pad, GstCaps * caps); GstAudioAggregatorPad * pad, GstCaps * caps);
gboolean
gst_audio_aggregator_set_src_caps (GstAudioAggregator * aagg, GstCaps * caps);
G_END_DECLS G_END_DECLS

View file

@ -809,6 +809,116 @@ gst_aggregator_pad_set_flushing (GstAggregatorPad * aggpad,
PAD_UNLOCK (aggpad); PAD_UNLOCK (aggpad);
} }
static GstFlowReturn
gst_aggregator_default_update_src_caps (GstAggregator * agg, GstCaps * caps,
GstCaps ** ret)
{
*ret = gst_caps_ref (caps);
return GST_FLOW_OK;
}
static GstCaps *
gst_aggregator_default_fixate_src_caps (GstAggregator * agg, GstCaps * caps)
{
caps = gst_caps_fixate (caps);
return caps;
}
static gboolean
gst_aggregator_default_negotiated_src_caps (GstAggregator * agg, GstCaps * caps)
{
return TRUE;
}
/* WITH SRC_LOCK held */
static GstFlowReturn
gst_aggregator_update_src_caps (GstAggregator * self)
{
GstAggregatorClass *agg_klass = GST_AGGREGATOR_GET_CLASS (self);
GstCaps *downstream_caps, *template_caps, *caps = NULL;
GstFlowReturn ret = GST_FLOW_OK;
template_caps = gst_pad_get_pad_template_caps (self->srcpad);
downstream_caps = gst_pad_peer_query_caps (self->srcpad, template_caps);
if (gst_caps_is_empty (downstream_caps)) {
GST_INFO_OBJECT (self, "Downstream caps (%"
GST_PTR_FORMAT ") not compatible with pad template caps (%"
GST_PTR_FORMAT ")", downstream_caps, template_caps);
ret = GST_FLOW_NOT_NEGOTIATED;
goto done;
}
g_assert (agg_klass->update_src_caps);
GST_DEBUG_OBJECT (self, "updating caps from %" GST_PTR_FORMAT,
downstream_caps);
ret = agg_klass->update_src_caps (self, downstream_caps, &caps);
if (ret < GST_FLOW_OK) {
GST_WARNING_OBJECT (self, "Subclass failed to update provided caps");
goto done;
}
if ((caps == NULL || gst_caps_is_empty (caps)) && ret >= GST_FLOW_OK) {
ret = GST_FLOW_NOT_NEGOTIATED;
goto done;
}
GST_DEBUG_OBJECT (self, " to %" GST_PTR_FORMAT, caps);
#ifdef GST_ENABLE_EXTRA_CHECKS
if (!gst_caps_is_subset (caps, template_caps)) {
GstCaps *intersection;
GST_ERROR_OBJECT (self,
"update_src_caps returned caps %" GST_PTR_FORMAT
" which are not a real subset of the template caps %"
GST_PTR_FORMAT, caps, template_caps);
g_warning ("%s: update_src_caps returned caps which are not a real "
"subset of the filter caps", GST_ELEMENT_NAME (self));
intersection =
gst_caps_intersect_full (template_caps, caps, GST_CAPS_INTERSECT_FIRST);
gst_caps_unref (caps);
caps = intersection;
}
#endif
if (gst_caps_is_any (caps)) {
goto done;
}
if (!gst_caps_is_fixed (caps)) {
g_assert (agg_klass->fixate_src_caps);
GST_DEBUG_OBJECT (self, "fixate caps from %" GST_PTR_FORMAT, caps);
if (!(caps = agg_klass->fixate_src_caps (self, caps))) {
GST_WARNING_OBJECT (self, "Subclass failed to fixate provided caps");
ret = GST_FLOW_NOT_NEGOTIATED;
goto done;
}
GST_DEBUG_OBJECT (self, " to %" GST_PTR_FORMAT, caps);
}
if (agg_klass->negotiated_src_caps) {
if (!agg_klass->negotiated_src_caps (self, caps)) {
GST_WARNING_OBJECT (self, "Subclass failed to accept negotiated caps");
ret = GST_FLOW_NOT_NEGOTIATED;
goto done;
}
}
gst_aggregator_set_src_caps (self, caps);
done:
gst_caps_unref (downstream_caps);
gst_caps_unref (template_caps);
if (caps)
gst_caps_unref (caps);
return ret;
}
static void static void
gst_aggregator_aggregate_func (GstAggregator * self) gst_aggregator_aggregate_func (GstAggregator * self)
{ {
@ -823,7 +933,7 @@ gst_aggregator_aggregate_func (GstAggregator * self)
GST_LOG_OBJECT (self, "Checking aggregate"); GST_LOG_OBJECT (self, "Checking aggregate");
while (priv->send_eos && priv->running) { while (priv->send_eos && priv->running) {
GstFlowReturn flow_return; GstFlowReturn flow_return = GST_FLOW_OK;
gboolean processed_event = FALSE; gboolean processed_event = FALSE;
gst_aggregator_iterate_sinkpads (self, check_events, NULL); gst_aggregator_iterate_sinkpads (self, check_events, NULL);
@ -835,8 +945,19 @@ gst_aggregator_aggregate_func (GstAggregator * self)
if (processed_event) if (processed_event)
continue; continue;
if (gst_pad_check_reconfigure (GST_AGGREGATOR_SRC_PAD (self))) {
flow_return = gst_aggregator_update_src_caps (self);
if (flow_return != GST_FLOW_OK)
gst_pad_mark_reconfigure (GST_AGGREGATOR_SRC_PAD (self));
}
if (timeout || flow_return >= GST_FLOW_OK) {
GST_TRACE_OBJECT (self, "Actually aggregating!"); GST_TRACE_OBJECT (self, "Actually aggregating!");
flow_return = klass->aggregate (self, timeout); flow_return = klass->aggregate (self, timeout);
}
if (flow_return == GST_AGGREGATOR_FLOW_NEED_DATA)
continue;
GST_OBJECT_LOCK (self); GST_OBJECT_LOCK (self);
if (flow_return == GST_FLOW_FLUSHING && priv->flush_seeking) { if (flow_return == GST_FLOW_FLUSHING && priv->flush_seeking) {
@ -1979,6 +2100,9 @@ gst_aggregator_class_init (GstAggregatorClass * klass)
klass->src_query = gst_aggregator_default_src_query; klass->src_query = gst_aggregator_default_src_query;
klass->create_new_pad = gst_aggregator_default_create_new_pad; klass->create_new_pad = gst_aggregator_default_create_new_pad;
klass->update_src_caps = gst_aggregator_default_update_src_caps;
klass->fixate_src_caps = gst_aggregator_default_fixate_src_caps;
klass->negotiated_src_caps = gst_aggregator_default_negotiated_src_caps;
gstelement_class->request_new_pad = gstelement_class->request_new_pad =
GST_DEBUG_FUNCPTR (gst_aggregator_request_new_pad); GST_DEBUG_FUNCPTR (gst_aggregator_request_new_pad);

View file

@ -120,6 +120,7 @@ gboolean gst_aggregator_pad_is_eos (GstAggregatorPad * pad);
#define GST_IS_AGGREGATOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_AGGREGATOR)) #define GST_IS_AGGREGATOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_AGGREGATOR))
#define GST_FLOW_NOT_HANDLED GST_FLOW_CUSTOM_SUCCESS #define GST_FLOW_NOT_HANDLED GST_FLOW_CUSTOM_SUCCESS
#define GST_AGGREGATOR_FLOW_NEED_DATA GST_FLOW_CUSTOM_ERROR
/** /**
* GstAggregator: * GstAggregator:
@ -195,6 +196,18 @@ struct _GstAggregator
* based aggregation to occur. Defaults to returning * based aggregation to occur. Defaults to returning
* GST_CLOCK_TIME_NONE causing the element to wait for buffers * GST_CLOCK_TIME_NONE causing the element to wait for buffers
* on all sink pads before aggregating. * on all sink pads before aggregating.
* @update_src_caps: Lets subclasses update the #GstCaps representing
* the src pad caps before usage. The result should end up
* in @ret. Return %GST_AGGREGATOR_FLOW_NEED_DATA to indicate that the
* element needs more information (caps, a buffer, etc) to
* choose the correct caps. Should return ANY caps if the
* stream has not caps at all.
* @fixate_src_caps: Optional.
* Fixate and return the src pad caps provided. The function takes
* ownership of @caps and returns a fixated version of
* @caps. @caps is not guaranteed to be writable.
* @negotiated_src_caps: Optional.
* Notifies subclasses what caps format has been negotiated
* *
* The aggregator base class will handle in a thread-safe way all manners of * The aggregator base class will handle in a thread-safe way all manners of
* concurrent flushes, seeks, pad additions and removals, leaving to the * concurrent flushes, seeks, pad additions and removals, leaving to the
@ -250,6 +263,13 @@ struct _GstAggregatorClass {
GstPadTemplate * templ, GstPadTemplate * templ,
const gchar * req_name, const gchar * req_name,
const GstCaps * caps); const GstCaps * caps);
GstFlowReturn (*update_src_caps) (GstAggregator * self,
GstCaps * caps,
GstCaps ** ret);
GstCaps * (*fixate_src_caps) (GstAggregator * self,
GstCaps * caps);
gboolean (*negotiated_src_caps) (GstAggregator * self,
GstCaps * caps);
/*< private >*/ /*< private >*/
gpointer _gst_reserved[GST_PADDING_LARGE]; gpointer _gst_reserved[GST_PADDING_LARGE];

View file

@ -535,60 +535,11 @@ gst_video_aggregator_find_best_format (GstVideoAggregator * vagg,
g_hash_table_unref (formats_table); g_hash_table_unref (formats_table);
} }
/* WITH GST_VIDEO_AGGREGATOR_LOCK TAKEN */
static gboolean
gst_video_aggregator_src_setcaps (GstVideoAggregator * vagg, GstCaps * caps)
{
GstAggregator *agg = GST_AGGREGATOR (vagg);
gboolean ret = FALSE;
GstVideoInfo info;
GstPad *pad = GST_AGGREGATOR (vagg)->srcpad;
GST_INFO_OBJECT (pad, "set src caps: %" GST_PTR_FORMAT, caps);
if (!gst_video_info_from_caps (&info, caps))
goto done;
ret = TRUE;
if (GST_VIDEO_INFO_FPS_N (&vagg->info) != GST_VIDEO_INFO_FPS_N (&info) ||
GST_VIDEO_INFO_FPS_D (&vagg->info) != GST_VIDEO_INFO_FPS_D (&info)) {
if (agg->segment.position != -1) {
vagg->priv->nframes = 0;
/* The timestamp offset will be updated based on the
* segment position the next time we aggregate */
GST_DEBUG_OBJECT (vagg,
"Resetting frame counter because of framerate change");
}
gst_video_aggregator_reset_qos (vagg);
}
vagg->info = info;
if (vagg->priv->current_caps == NULL ||
gst_caps_is_equal (caps, vagg->priv->current_caps) == FALSE) {
GstClockTime latency;
gst_caps_replace (&vagg->priv->current_caps, caps);
GST_VIDEO_AGGREGATOR_UNLOCK (vagg);
gst_aggregator_set_src_caps (agg, caps);
latency = gst_util_uint64_scale (GST_SECOND,
GST_VIDEO_INFO_FPS_D (&info), GST_VIDEO_INFO_FPS_N (&info));
gst_aggregator_set_latency (agg, latency, latency);
GST_VIDEO_AGGREGATOR_LOCK (vagg);
}
done:
return ret;
}
static GstCaps * static GstCaps *
gst_video_aggregator_default_fixate_caps (GstVideoAggregator * vagg, gst_video_aggregator_default_fixate_src_caps (GstAggregator * agg,
GstCaps * caps) GstCaps * caps)
{ {
GstVideoAggregator *vagg = GST_VIDEO_AGGREGATOR (agg);
gint best_width = -1, best_height = -1; gint best_width = -1, best_height = -1;
gint best_fps_n = -1, best_fps_d = -1; gint best_fps_n = -1, best_fps_d = -1;
gdouble best_fps = -1.; gdouble best_fps = -1.;
@ -634,6 +585,7 @@ gst_video_aggregator_default_fixate_caps (GstVideoAggregator * vagg,
best_fps = 25.0; best_fps = 25.0;
} }
caps = gst_caps_make_writable (caps);
s = gst_caps_get_structure (caps, 0); s = gst_caps_get_structure (caps, 0);
gst_structure_fixate_field_nearest_int (s, "width", best_width); gst_structure_fixate_field_nearest_int (s, "width", best_width);
gst_structure_fixate_field_nearest_int (s, "height", best_height); gst_structure_fixate_field_nearest_int (s, "height", best_height);
@ -648,7 +600,7 @@ gst_video_aggregator_default_fixate_caps (GstVideoAggregator * vagg,
static GstCaps * static GstCaps *
gst_video_aggregator_default_update_caps (GstVideoAggregator * vagg, gst_video_aggregator_default_update_caps (GstVideoAggregator * vagg,
GstCaps * caps, GstCaps * filter) GstCaps * caps)
{ {
GstVideoAggregatorClass *vagg_klass = GST_VIDEO_AGGREGATOR_GET_CLASS (vagg); GstVideoAggregatorClass *vagg_klass = GST_VIDEO_AGGREGATOR_GET_CLASS (vagg);
GstCaps *ret, *best_format_caps; GstCaps *ret, *best_format_caps;
@ -682,38 +634,59 @@ gst_video_aggregator_default_update_caps (GstVideoAggregator * vagg,
gst_video_chroma_to_string (best_info.chroma_site), NULL); gst_video_chroma_to_string (best_info.chroma_site), NULL);
ret = gst_caps_merge (best_format_caps, gst_caps_ref (caps)); ret = gst_caps_merge (best_format_caps, gst_caps_ref (caps));
if (filter) {
GstCaps *tmp;
tmp = gst_caps_intersect (ret, filter);
gst_caps_unref (ret);
ret = tmp;
}
return ret; return ret;
} }
/* WITH GST_VIDEO_AGGREGATOR_LOCK TAKEN */ static GstFlowReturn
static gboolean gst_video_aggregator_default_update_src_caps (GstAggregator * agg,
gst_video_aggregator_update_src_caps (GstVideoAggregator * vagg) GstCaps * caps, GstCaps ** ret)
{ {
GstVideoAggregatorClass *vagg_klass = GST_VIDEO_AGGREGATOR_GET_CLASS (vagg); GstVideoAggregatorClass *vagg_klass = GST_VIDEO_AGGREGATOR_GET_CLASS (agg);
GstVideoAggregatorPadClass *vaggpad_klass = g_type_class_peek GstVideoAggregator *vagg = GST_VIDEO_AGGREGATOR (agg);
(GST_AGGREGATOR_GET_CLASS (vagg)->sinkpads_type); gboolean at_least_one_pad_configured = FALSE;
GstAggregator *agg = GST_AGGREGATOR (vagg);
gboolean ret = TRUE, at_least_one_pad_configured = FALSE;
gboolean at_least_one_alpha = FALSE;
GstCaps *downstream_caps;
GList *l; GList *l;
downstream_caps = gst_pad_get_allowed_caps (agg->srcpad); GST_OBJECT_LOCK (vagg);
for (l = GST_ELEMENT (vagg)->sinkpads; l; l = l->next) {
GstVideoAggregatorPad *mpad = l->data;
if (!downstream_caps || gst_caps_is_empty (downstream_caps)) { if (GST_VIDEO_INFO_WIDTH (&mpad->info) == 0
GST_INFO_OBJECT (vagg, "No downstream caps found %" || GST_VIDEO_INFO_HEIGHT (&mpad->info) == 0)
GST_PTR_FORMAT, downstream_caps); continue;
if (downstream_caps)
gst_caps_unref (downstream_caps); at_least_one_pad_configured = TRUE;
return FALSE;
} }
GST_OBJECT_UNLOCK (vagg);
if (!at_least_one_pad_configured) {
/* We couldn't decide the output video info because the sinkpads don't have
* all the caps yet, so we mark the pad as needing a reconfigure. This
* allows aggregate() to skip ahead a bit and try again later. */
GST_DEBUG_OBJECT (vagg, "Couldn't decide output video info");
gst_pad_mark_reconfigure (agg->srcpad);
return GST_AGGREGATOR_FLOW_NEED_DATA;
}
g_assert (vagg_klass->update_caps);
*ret = vagg_klass->update_caps (vagg, caps);
return GST_FLOW_OK;
}
static gboolean
gst_video_aggregator_default_negotiated_src_caps (GstAggregator * agg,
GstCaps * caps)
{
GstVideoAggregatorPadClass *vaggpad_klass = g_type_class_peek
(GST_AGGREGATOR_GET_CLASS (agg)->sinkpads_type);
GstVideoAggregator *vagg = GST_VIDEO_AGGREGATOR (agg);
gboolean at_least_one_alpha = FALSE;
const GstVideoFormatInfo *finfo;
GstVideoInfo info;
GList *l;
GST_INFO_OBJECT (agg->srcpad, "set src caps: %" GST_PTR_FORMAT, caps);
GST_OBJECT_LOCK (vagg); GST_OBJECT_LOCK (vagg);
for (l = GST_ELEMENT (vagg)->sinkpads; l; l = l->next) { for (l = GST_ELEMENT (vagg)->sinkpads; l; l = l->next) {
@ -725,72 +698,34 @@ gst_video_aggregator_update_src_caps (GstVideoAggregator * vagg)
if (mpad->info.finfo->flags & GST_VIDEO_FORMAT_FLAG_ALPHA) if (mpad->info.finfo->flags & GST_VIDEO_FORMAT_FLAG_ALPHA)
at_least_one_alpha = TRUE; at_least_one_alpha = TRUE;
at_least_one_pad_configured = TRUE;
} }
GST_OBJECT_UNLOCK (vagg); GST_OBJECT_UNLOCK (vagg);
if (at_least_one_pad_configured) { if (!gst_video_info_from_caps (&info, caps))
GstCaps *caps, *peercaps; return FALSE;
peercaps = gst_pad_peer_query_caps (agg->srcpad, NULL); if (GST_VIDEO_INFO_FPS_N (&vagg->info) != GST_VIDEO_INFO_FPS_N (&info) ||
GST_VIDEO_INFO_FPS_D (&vagg->info) != GST_VIDEO_INFO_FPS_D (&info)) {
g_assert (vagg_klass->update_caps); if (agg->segment.position != -1) {
GST_DEBUG_OBJECT (vagg, "updating caps from %" GST_PTR_FORMAT, vagg->priv->nframes = 0;
downstream_caps); /* The timestamp offset will be updated based on the
GST_DEBUG_OBJECT (vagg, " with filter %" GST_PTR_FORMAT, peercaps); * segment position the next time we aggregate */
if (!(caps = vagg_klass->update_caps (vagg, downstream_caps, peercaps)) || GST_DEBUG_OBJECT (vagg,
gst_caps_is_empty (caps)) { "Resetting frame counter because of framerate change");
GST_WARNING_OBJECT (vagg, "Subclass failed to update provided caps");
gst_caps_unref (downstream_caps);
if (peercaps)
gst_caps_unref (peercaps);
ret = FALSE;
goto done;
} }
GST_DEBUG_OBJECT (vagg, " to %" GST_PTR_FORMAT, caps); gst_video_aggregator_reset_qos (vagg);
gst_caps_unref (downstream_caps);
if (peercaps)
gst_caps_unref (peercaps);
if (!gst_caps_is_fixed (caps)) {
g_assert (vagg_klass->fixate_caps);
caps = gst_caps_make_writable (caps);
GST_DEBUG_OBJECT (vagg, "fixate caps from %" GST_PTR_FORMAT, caps);
if (!(caps = vagg_klass->fixate_caps (vagg, caps))) {
GST_WARNING_OBJECT (vagg, "Subclass failed to fixate provided caps");
ret = FALSE;
goto done;
}
GST_DEBUG_OBJECT (vagg, " to %" GST_PTR_FORMAT, caps);
} }
{ vagg->info = info;
const GstVideoFormatInfo *finfo;
const gchar *v_format_str;
GstVideoFormat v_format;
GstStructure *s;
s = gst_caps_get_structure (caps, 0); finfo = vagg->info.finfo;
v_format_str = gst_structure_get_string (s, "format");
g_return_val_if_fail (v_format_str != NULL, FALSE);
v_format = gst_video_format_from_string (v_format_str);
g_return_val_if_fail (v_format != GST_VIDEO_FORMAT_UNKNOWN, FALSE);
finfo = gst_video_format_get_info (v_format);
g_return_val_if_fail (finfo != NULL, FALSE);
if (at_least_one_alpha && !(finfo->flags & GST_VIDEO_FORMAT_FLAG_ALPHA)) { if (at_least_one_alpha && !(finfo->flags & GST_VIDEO_FORMAT_FLAG_ALPHA)) {
GST_ELEMENT_ERROR (vagg, CORE, NEGOTIATION, GST_ELEMENT_ERROR (vagg, CORE, NEGOTIATION,
("At least one of the input pads contains alpha, but configured caps don't support alpha."), ("At least one of the input pads contains alpha, but configured caps don't support alpha."),
("Either convert your inputs to not contain alpha or add a videoconvert after the aggregator")); ("Either convert your inputs to not contain alpha or add a videoconvert after the aggregator"));
ret = FALSE; return FALSE;
goto done;
} }
}
gst_video_info_from_caps (&vagg->info, caps);
if (vaggpad_klass->set_info) { if (vaggpad_klass->set_info) {
/* Then browse the sinks once more, setting or unsetting conversion if needed */ /* Then browse the sinks once more, setting or unsetting conversion if needed */
@ -803,23 +738,19 @@ gst_video_aggregator_update_src_caps (GstVideoAggregator * vagg)
} }
} }
if (gst_video_aggregator_src_setcaps (vagg, caps)) { if (vagg->priv->current_caps == NULL ||
if (vagg_klass->negotiated_caps) gst_caps_is_equal (caps, vagg->priv->current_caps) == FALSE) {
ret = GstClockTime latency;
GST_VIDEO_AGGREGATOR_GET_CLASS (vagg)->negotiated_caps (vagg, caps);
} gst_caps_replace (&vagg->priv->current_caps, caps);
gst_caps_unref (caps);
} else { gst_aggregator_set_src_caps (agg, caps);
/* We couldn't decide the output video info because the sinkpads don't have latency = gst_util_uint64_scale (GST_SECOND,
* all the caps yet, so we mark the pad as needing a reconfigure. This GST_VIDEO_INFO_FPS_D (&vagg->info), GST_VIDEO_INFO_FPS_N (&vagg->info));
* allows aggregate() to skip ahead a bit and try again later. */ gst_aggregator_set_latency (agg, latency, latency);
GST_DEBUG_OBJECT (vagg, "Couldn't decide output video info");
gst_pad_mark_reconfigure (agg->srcpad);
ret = FALSE;
} }
done: return TRUE;
return ret;
} }
static gboolean static gboolean
@ -1101,7 +1032,6 @@ gst_video_aggregator_reset (GstVideoAggregator * vagg)
GST_OBJECT_UNLOCK (vagg); GST_OBJECT_UNLOCK (vagg);
} }
#define GST_FLOW_NEEDS_DATA GST_FLOW_CUSTOM_ERROR
static gint static gint
gst_video_aggregator_fill_queues (GstVideoAggregator * vagg, gst_video_aggregator_fill_queues (GstVideoAggregator * vagg,
GstClockTime output_start_running_time, GstClockTime output_start_running_time,
@ -1309,7 +1239,7 @@ gst_video_aggregator_fill_queues (GstVideoAggregator * vagg,
gst_pad_mark_reconfigure (GST_AGGREGATOR_SRC_PAD (vagg)); gst_pad_mark_reconfigure (GST_AGGREGATOR_SRC_PAD (vagg));
if (need_more_data) if (need_more_data)
return GST_FLOW_NEEDS_DATA; return GST_AGGREGATOR_FLOW_NEED_DATA;
if (eos) if (eos)
return GST_FLOW_EOS; return GST_FLOW_EOS;
@ -1471,27 +1401,14 @@ gst_video_aggregator_get_next_time (GstAggregator * agg)
return next_time; return next_time;
} }
static GstFlowReturn static void
gst_video_aggregator_check_reconfigure (GstVideoAggregator * vagg, gst_video_aggregator_advance_on_timeout (GstVideoAggregator * vagg)
gboolean timeout)
{ {
GstAggregator *agg = (GstAggregator *) vagg; GstAggregator *agg = GST_AGGREGATOR (vagg);
if (GST_VIDEO_INFO_FORMAT (&vagg->info) == GST_VIDEO_FORMAT_UNKNOWN
|| gst_pad_check_reconfigure (GST_AGGREGATOR_SRC_PAD (vagg))) {
gboolean ret;
restart:
ret = gst_video_aggregator_update_src_caps (vagg);
if (!ret) {
gst_pad_mark_reconfigure (GST_AGGREGATOR_SRC_PAD (vagg));
if (timeout) {
guint64 frame_duration; guint64 frame_duration;
gint fps_d, fps_n; gint fps_d, fps_n;
GST_DEBUG_OBJECT (vagg, GST_OBJECT_LOCK (agg);
"Got timeout before receiving any caps, don't output anything");
if (agg->segment.position == -1) { if (agg->segment.position == -1) {
if (agg->segment.rate > 0.0) if (agg->segment.rate > 0.0)
agg->segment.position = agg->segment.start; agg->segment.position = agg->segment.start;
@ -1513,24 +1430,7 @@ gst_video_aggregator_check_reconfigure (GstVideoAggregator * vagg,
else else
agg->segment.position = 0; agg->segment.position = 0;
vagg->priv->nframes++; vagg->priv->nframes++;
return GST_FLOW_NEEDS_DATA; GST_OBJECT_UNLOCK (agg);
} else {
if (GST_PAD_IS_FLUSHING (GST_AGGREGATOR_SRC_PAD (vagg)))
return GST_FLOW_FLUSHING;
else
return GST_FLOW_NOT_NEGOTIATED;
}
} else {
/* It is possible that during gst_video_aggregator_update_src_caps()
* we got a caps change on one of the sink pads, in which case we need
* to redo the negotiation
* - https://bugzilla.gnome.org/show_bug.cgi?id=755782 */
if (gst_pad_check_reconfigure (GST_AGGREGATOR_SRC_PAD (vagg)))
goto restart;
}
}
return GST_FLOW_OK;
} }
static GstFlowReturn static GstFlowReturn
@ -1546,10 +1446,10 @@ gst_video_aggregator_aggregate (GstAggregator * agg, gboolean timeout)
GST_VIDEO_AGGREGATOR_LOCK (vagg); GST_VIDEO_AGGREGATOR_LOCK (vagg);
restart: restart:
flow_ret = gst_video_aggregator_check_reconfigure (vagg, timeout); if (GST_VIDEO_INFO_FORMAT (&vagg->info) == GST_VIDEO_FORMAT_UNKNOWN) {
if (flow_ret != GST_FLOW_OK) { if (timeout)
if (flow_ret == GST_FLOW_NEEDS_DATA) gst_video_aggregator_advance_on_timeout (vagg);
flow_ret = GST_FLOW_OK; flow_ret = GST_AGGREGATOR_FLOW_NEED_DATA;
goto unlock_and_return; goto unlock_and_return;
} }
@ -1591,9 +1491,8 @@ restart:
output_end_running_time); output_end_running_time);
} }
if (flow_ret == GST_FLOW_NEEDS_DATA && !timeout) { if (flow_ret == GST_AGGREGATOR_FLOW_NEED_DATA && !timeout) {
GST_DEBUG_OBJECT (vagg, "Need more data for decisions"); GST_DEBUG_OBJECT (vagg, "Need more data for decisions");
flow_ret = GST_FLOW_OK;
goto unlock_and_return; goto unlock_and_return;
} else if (flow_ret == GST_FLOW_EOS) { } else if (flow_ret == GST_FLOW_EOS) {
GST_DEBUG_OBJECT (vagg, "All sinkpads are EOS -- forwarding"); GST_DEBUG_OBJECT (vagg, "All sinkpads are EOS -- forwarding");
@ -2187,11 +2086,14 @@ gst_video_aggregator_class_init (GstVideoAggregatorClass * klass)
agg_class->src_event = gst_video_aggregator_src_event; agg_class->src_event = gst_video_aggregator_src_event;
agg_class->src_query = gst_video_aggregator_src_query; agg_class->src_query = gst_video_aggregator_src_query;
agg_class->get_next_time = gst_video_aggregator_get_next_time; agg_class->get_next_time = gst_video_aggregator_get_next_time;
agg_class->update_src_caps = gst_video_aggregator_default_update_src_caps;
agg_class->fixate_src_caps = gst_video_aggregator_default_fixate_src_caps;
agg_class->negotiated_src_caps =
gst_video_aggregator_default_negotiated_src_caps;
klass->find_best_format = gst_video_aggregator_find_best_format; klass->find_best_format = gst_video_aggregator_find_best_format;
klass->get_output_buffer = gst_video_aggregator_get_output_buffer; klass->get_output_buffer = gst_video_aggregator_get_output_buffer;
klass->update_caps = gst_video_aggregator_default_update_caps; klass->update_caps = gst_video_aggregator_default_update_caps;
klass->fixate_caps = gst_video_aggregator_default_fixate_caps;
/* Register the pad class */ /* Register the pad class */
g_type_class_ref (GST_TYPE_VIDEO_AGGREGATOR_PAD); g_type_class_ref (GST_TYPE_VIDEO_AGGREGATOR_PAD);

View file

@ -73,9 +73,6 @@ struct _GstVideoAggregator
* @update_caps: Optional. * @update_caps: Optional.
* Lets subclasses update the #GstCaps representing * Lets subclasses update the #GstCaps representing
* the src pad caps before usage. Return %NULL to indicate failure. * the src pad caps before usage. Return %NULL to indicate failure.
* @fixate_caps: Fixate and return the src pad caps provided. The function takes
* ownership of @caps and returns a fixated version of
* @caps. @caps is not guaranteed to be writable.
* @aggregate_frames: Lets subclasses aggregate frames that are ready. Subclasses * @aggregate_frames: Lets subclasses aggregate frames that are ready. Subclasses
* should iterate the GstElement.sinkpads and use the already * should iterate the GstElement.sinkpads and use the already
* mapped #GstVideoFrame from GstVideoAggregatorPad.aggregated_frame * mapped #GstVideoFrame from GstVideoAggregatorPad.aggregated_frame
@ -97,16 +94,11 @@ struct _GstVideoAggregatorClass
/*< public >*/ /*< public >*/
GstCaps * (*update_caps) (GstVideoAggregator * videoaggregator, GstCaps * (*update_caps) (GstVideoAggregator * videoaggregator,
GstCaps * caps,
GstCaps * filter_caps);
GstCaps * (*fixate_caps) (GstVideoAggregator * videoaggregator,
GstCaps * caps); GstCaps * caps);
GstFlowReturn (*aggregate_frames) (GstVideoAggregator * videoaggregator, GstFlowReturn (*aggregate_frames) (GstVideoAggregator * videoaggregator,
GstBuffer * outbuffer); GstBuffer * outbuffer);
GstFlowReturn (*get_output_buffer) (GstVideoAggregator * videoaggregator, GstFlowReturn (*get_output_buffer) (GstVideoAggregator * videoaggregator,
GstBuffer ** outbuffer); GstBuffer ** outbuffer);
gboolean (*negotiated_caps) (GstVideoAggregator * videoaggregator,
GstCaps * caps);
void (*find_best_format) (GstVideoAggregator * vagg, void (*find_best_format) (GstVideoAggregator * vagg,
GstCaps * downstream_caps, GstCaps * downstream_caps,
GstVideoInfo * best_info, GstVideoInfo * best_info,

View file

@ -432,10 +432,10 @@ gst_audio_interleave_setcaps (GstAudioInterleave * self, GstPad * pad,
GST_DEBUG_OBJECT (self, "setting sinkcaps %" GST_PTR_FORMAT, sinkcaps); GST_DEBUG_OBJECT (self, "setting sinkcaps %" GST_PTR_FORMAT, sinkcaps);
gst_caps_replace (&self->sinkcaps, sinkcaps); gst_caps_replace (&self->sinkcaps, sinkcaps);
gst_pad_mark_reconfigure (GST_AGGREGATOR_SRC_PAD (aagg));
gst_caps_unref (sinkcaps); gst_caps_unref (sinkcaps);
new = TRUE; new = TRUE;
self->new_caps = TRUE;
} }
if (self->channel_positions_from_input if (self->channel_positions_from_input
@ -504,52 +504,40 @@ gst_audio_interleave_sink_event (GstAggregator * agg, GstAggregatorPad * aggpad,
} }
static GstFlowReturn static GstFlowReturn
gst_audio_interleave_aggregate (GstAggregator * aggregator, gboolean timeout) gst_audio_interleave_update_src_caps (GstAggregator * agg, GstCaps * caps,
GstCaps ** ret)
{ {
GstAudioInterleave *self = GST_AUDIO_INTERLEAVE (aggregator); GstAudioInterleave *self = GST_AUDIO_INTERLEAVE (agg);
GstAudioAggregator *aagg = GST_AUDIO_AGGREGATOR (aggregator);
GST_OBJECT_LOCK (aggregator);
if (self->new_caps) {
GstCaps *srccaps;
GstStructure *s; GstStructure *s;
gboolean ret;
if (self->sinkcaps == NULL || self->channels == 0) { /* This means that either no caps have been set on the sink pad (if
/* In this case, let the base class handle it */ * sinkcaps is NULL) or that there is no sink pad (if channels == 0).
goto not_negotiated; */
} if (self->sinkcaps == NULL || self->channels == 0)
return GST_FLOW_NOT_NEGOTIATED;
srccaps = gst_caps_copy (self->sinkcaps); *ret = gst_caps_copy (self->sinkcaps);
s = gst_caps_get_structure (srccaps, 0); s = gst_caps_get_structure (*ret, 0);
gst_structure_set (s, "channels", G_TYPE_INT, self->channels, "layout", gst_structure_set (s, "channels", G_TYPE_INT, self->channels, "layout",
G_TYPE_STRING, "interleaved", "channel-mask", GST_TYPE_BITMASK, G_TYPE_STRING, "interleaved", "channel-mask", GST_TYPE_BITMASK,
gst_audio_interleave_get_channel_mask (self), NULL); gst_audio_interleave_get_channel_mask (self), NULL);
return GST_FLOW_OK;
}
GST_OBJECT_UNLOCK (aggregator); static gboolean
ret = gst_audio_aggregator_set_src_caps (aagg, srccaps); gst_audio_interleave_negotiated_src_caps (GstAggregator * agg, GstCaps * caps)
gst_caps_unref (srccaps); {
GstAudioInterleave *self = GST_AUDIO_INTERLEAVE (agg);
GstAudioAggregator *aagg = GST_AUDIO_AGGREGATOR (self);
if (!ret) if (!GST_AGGREGATOR_CLASS (parent_class)->negotiated_src_caps (agg, caps))
goto src_did_not_accept; return FALSE;
GST_OBJECT_LOCK (aggregator);
gst_audio_interleave_set_process_function (self, &aagg->info); gst_audio_interleave_set_process_function (self, &aagg->info);
self->new_caps = FALSE; return TRUE;
}
not_negotiated:
GST_OBJECT_UNLOCK (aggregator);
return GST_AGGREGATOR_CLASS (parent_class)->aggregate (aggregator, timeout);
src_did_not_accept:
GST_WARNING_OBJECT (self, "src did not accept setcaps()");
return GST_FLOW_NOT_NEGOTIATED;;
} }
static void static void
@ -586,7 +574,8 @@ gst_audio_interleave_class_init (GstAudioInterleaveClass * klass)
agg_class->sink_query = GST_DEBUG_FUNCPTR (gst_audio_interleave_sink_query); agg_class->sink_query = GST_DEBUG_FUNCPTR (gst_audio_interleave_sink_query);
agg_class->sink_event = GST_DEBUG_FUNCPTR (gst_audio_interleave_sink_event); agg_class->sink_event = GST_DEBUG_FUNCPTR (gst_audio_interleave_sink_event);
agg_class->stop = gst_audio_interleave_stop; agg_class->stop = gst_audio_interleave_stop;
agg_class->aggregate = gst_audio_interleave_aggregate; agg_class->update_src_caps = gst_audio_interleave_update_src_caps;
agg_class->negotiated_src_caps = gst_audio_interleave_negotiated_src_caps;
aagg_class->aggregate_one_buffer = gst_audio_interleave_aggregate_one_buffer; aagg_class->aggregate_one_buffer = gst_audio_interleave_aggregate_one_buffer;
@ -720,7 +709,6 @@ gst_audio_interleave_stop (GstAggregator * agg)
if (!GST_AGGREGATOR_CLASS (parent_class)->stop (agg)) if (!GST_AGGREGATOR_CLASS (parent_class)->stop (agg))
return FALSE; return FALSE;
self->new_caps = FALSE;
gst_caps_replace (&self->sinkcaps, NULL); gst_caps_replace (&self->sinkcaps, NULL);
return TRUE; return TRUE;
@ -765,9 +753,7 @@ gst_audio_interleave_request_new_pad (GstElement * element,
g_value_unset (&val); g_value_unset (&val);
/* Update the src caps if we already have them */ /* Update the src caps if we already have them */
GST_OBJECT_LOCK (self); gst_pad_mark_reconfigure (GST_AGGREGATOR_SRC_PAD (self));
self->new_caps = TRUE;
GST_OBJECT_UNLOCK (self);
return GST_PAD_CAST (newpad); return GST_PAD_CAST (newpad);
@ -804,7 +790,7 @@ gst_audio_interleave_release_pad (GstElement * element, GstPad * pad)
ipad->channel--; ipad->channel--;
} }
self->new_caps = TRUE; gst_pad_mark_reconfigure (GST_AGGREGATOR_SRC_PAD (self));
GST_OBJECT_UNLOCK (self); GST_OBJECT_UNLOCK (self);

View file

@ -58,7 +58,6 @@ struct _GstAudioInterleave {
gint padcounter; gint padcounter;
guint channels; guint channels;
gboolean new_caps;
GstCaps *sinkcaps; GstCaps *sinkcaps;
GValueArray *channel_positions; GValueArray *channel_positions;

View file

@ -348,7 +348,6 @@ gst_audiomixer_setcaps (GstAudioMixer * audiomixer, GstPad * pad,
GstAudioInfo info; GstAudioInfo info;
GstStructure *s; GstStructure *s;
gint channels = 0; gint channels = 0;
gboolean ret;
caps = gst_caps_copy (orig_caps); caps = gst_caps_copy (orig_caps);
@ -405,12 +404,13 @@ gst_audiomixer_setcaps (GstAudioMixer * audiomixer, GstPad * pad,
gst_caps_unref (caps); gst_caps_unref (caps);
return FALSE; return FALSE;
} }
} else {
gst_caps_replace (&aagg->current_caps, caps);
aagg->info = info;
gst_pad_mark_reconfigure (GST_AGGREGATOR_SRC_PAD (agg));
} }
GST_OBJECT_UNLOCK (audiomixer); GST_OBJECT_UNLOCK (audiomixer);
ret = gst_audio_aggregator_set_src_caps (aagg, caps);
if (ret)
gst_audio_aggregator_set_sink_caps (aagg, GST_AUDIO_AGGREGATOR_PAD (pad), gst_audio_aggregator_set_sink_caps (aagg, GST_AUDIO_AGGREGATOR_PAD (pad),
orig_caps); orig_caps);
@ -418,7 +418,7 @@ gst_audiomixer_setcaps (GstAudioMixer * audiomixer, GstPad * pad,
gst_caps_unref (caps); gst_caps_unref (caps);
return ret; return TRUE;
/* ERRORS */ /* ERRORS */
invalid_format: invalid_format:
@ -429,6 +429,20 @@ invalid_format:
} }
} }
static GstFlowReturn
gst_audiomixer_update_src_caps (GstAggregator * agg, GstCaps * caps,
GstCaps ** ret)
{
GstAudioAggregator *aagg = GST_AUDIO_AGGREGATOR (agg);
if (aagg->current_caps == NULL)
return GST_AGGREGATOR_FLOW_NEED_DATA;
*ret = gst_caps_ref (aagg->current_caps);
return GST_FLOW_OK;
}
static gboolean static gboolean
gst_audiomixer_sink_event (GstAggregator * agg, GstAggregatorPad * aggpad, gst_audiomixer_sink_event (GstAggregator * agg, GstAggregatorPad * aggpad,
GstEvent * event) GstEvent * event)
@ -495,6 +509,8 @@ gst_audiomixer_class_init (GstAudioMixerClass * klass)
agg_class->sink_query = GST_DEBUG_FUNCPTR (gst_audiomixer_sink_query); agg_class->sink_query = GST_DEBUG_FUNCPTR (gst_audiomixer_sink_query);
agg_class->sink_event = GST_DEBUG_FUNCPTR (gst_audiomixer_sink_event); agg_class->sink_event = GST_DEBUG_FUNCPTR (gst_audiomixer_sink_event);
agg_class->update_src_caps =
GST_DEBUG_FUNCPTR (gst_audiomixer_update_src_caps);
aagg_class->aggregate_one_buffer = gst_audiomixer_aggregate_one_buffer; aagg_class->aggregate_one_buffer = gst_audiomixer_aggregate_one_buffer;
} }

View file

@ -870,8 +870,9 @@ set_functions (GstCompositor * self, GstVideoInfo * info)
} }
static GstCaps * static GstCaps *
_fixate_caps (GstVideoAggregator * vagg, GstCaps * caps) _fixate_caps (GstAggregator * agg, GstCaps * caps)
{ {
GstVideoAggregator *vagg = GST_VIDEO_AGGREGATOR (agg);
GList *l; GList *l;
gint best_width = -1, best_height = -1; gint best_width = -1, best_height = -1;
gint best_fps_n = -1, best_fps_d = -1; gint best_fps_n = -1, best_fps_d = -1;
@ -945,21 +946,21 @@ _fixate_caps (GstVideoAggregator * vagg, GstCaps * caps)
} }
static gboolean static gboolean
_negotiated_caps (GstVideoAggregator * vagg, GstCaps * caps) _negotiated_caps (GstAggregator * agg, GstCaps * caps)
{ {
GstVideoInfo v_info; GstVideoInfo v_info;
GST_DEBUG_OBJECT (vagg, "Negotiated caps %" GST_PTR_FORMAT, caps); GST_DEBUG_OBJECT (agg, "Negotiated caps %" GST_PTR_FORMAT, caps);
if (!gst_video_info_from_caps (&v_info, caps)) if (!gst_video_info_from_caps (&v_info, caps))
return FALSE; return FALSE;
if (!set_functions (GST_COMPOSITOR (vagg), &v_info)) { if (!set_functions (GST_COMPOSITOR (agg), &v_info)) {
GST_ERROR_OBJECT (vagg, "Failed to setup vfuncs"); GST_ERROR_OBJECT (agg, "Failed to setup vfuncs");
return FALSE; return FALSE;
} }
return TRUE; return GST_AGGREGATOR_CLASS (parent_class)->negotiated_src_caps (agg, caps);
} }
static GstFlowReturn static GstFlowReturn
@ -1090,8 +1091,8 @@ gst_compositor_class_init (GstCompositorClass * klass)
agg_class->sinkpads_type = GST_TYPE_COMPOSITOR_PAD; agg_class->sinkpads_type = GST_TYPE_COMPOSITOR_PAD;
agg_class->sink_query = _sink_query; agg_class->sink_query = _sink_query;
videoaggregator_class->fixate_caps = _fixate_caps; agg_class->fixate_src_caps = _fixate_caps;
videoaggregator_class->negotiated_caps = _negotiated_caps; agg_class->negotiated_src_caps = _negotiated_caps;
videoaggregator_class->aggregate_frames = gst_compositor_aggregate_frames; videoaggregator_class->aggregate_frames = gst_compositor_aggregate_frames;
g_object_class_install_property (gobject_class, PROP_BACKGROUND, g_object_class_install_property (gobject_class, PROP_BACKGROUND,

View file

@ -1043,7 +1043,9 @@ GST_START_TEST (test_audiointerleave_2ch_smallbuf)
gst_caps_unref (caps); gst_caps_unref (caps);
gst_event_unref (ev); gst_event_unref (ev);
for (i = 0; i < 24; i++) /* eat the caps processing */
gst_harness_crank_single_clock_wait (h);
for (i = 0; i < 23; i++)
gst_harness_crank_single_clock_wait (h); gst_harness_crank_single_clock_wait (h);
fail_unless_equals_uint64 (gst_clock_get_time (GST_ELEMENT_CLOCK fail_unless_equals_uint64 (gst_clock_get_time (GST_ELEMENT_CLOCK
(h->element)), 750 * GST_MSECOND); (h->element)), 750 * GST_MSECOND);