mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-25 17:50:36 +00:00
audiointerleave: Set src caps in aggregate
This prevents races between the setcaps of the sink pads https://bugzilla.gnome.org/show_bug.cgi?id=740236
This commit is contained in:
parent
fb8339de40
commit
edde3c326e
2 changed files with 79 additions and 105 deletions
|
@ -322,14 +322,14 @@ gst_audio_interleave_channel_positions_to_mask (GValueArray * positions,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_audio_interleave_set_channel_positions (GstAudioInterleave * self,
|
||||
GstStructure * s)
|
||||
|
||||
/* Must be called with the object lock held */
|
||||
|
||||
static guint64
|
||||
gst_audio_interleave_get_channel_mask (GstAudioInterleave * self)
|
||||
{
|
||||
guint64 channel_mask = 0;
|
||||
|
||||
GST_OBJECT_LOCK (self);
|
||||
|
||||
if (self->channel_positions != NULL &&
|
||||
self->channels == self->channel_positions->n_values) {
|
||||
if (!gst_audio_interleave_channel_positions_to_mask
|
||||
|
@ -341,9 +341,8 @@ gst_audio_interleave_set_channel_positions (GstAudioInterleave * self,
|
|||
} else {
|
||||
GST_WARNING_OBJECT (self, "Using NONE channel positions");
|
||||
}
|
||||
gst_structure_set (s, "channel-mask", GST_TYPE_BITMASK, channel_mask, NULL);
|
||||
|
||||
GST_OBJECT_UNLOCK (self);
|
||||
return channel_mask;
|
||||
}
|
||||
|
||||
|
||||
|
@ -377,11 +376,10 @@ interleave_24 (guint8 * out, guint8 * in, guint stride, guint nframes)
|
|||
}
|
||||
|
||||
static void
|
||||
gst_audio_interleave_set_process_function (GstAudioInterleave * self)
|
||||
gst_audio_interleave_set_process_function (GstAudioInterleave * self,
|
||||
GstAudioInfo * info)
|
||||
{
|
||||
GstAudioAggregator *aagg = GST_AUDIO_AGGREGATOR (self);
|
||||
|
||||
switch (GST_AUDIO_INFO_WIDTH (&aagg->info)) {
|
||||
switch (GST_AUDIO_INFO_WIDTH (info)) {
|
||||
case 8:
|
||||
self->func = (GstInterleaveFunc) interleave_8;
|
||||
break;
|
||||
|
@ -412,56 +410,17 @@ gst_audio_interleave_setcaps (GstAudioInterleave * self, GstPad * pad,
|
|||
GstCaps * caps)
|
||||
{
|
||||
GstAudioAggregator *aagg = GST_AUDIO_AGGREGATOR (self);
|
||||
GstAudioAggregatorPad *aaggpad = GST_AUDIO_AGGREGATOR_PAD (pad);
|
||||
GstAudioInfo info;
|
||||
GValue *val;
|
||||
guint channel;
|
||||
GstCaps *srccaps;
|
||||
GstStructure *s;
|
||||
gboolean ret;
|
||||
|
||||
if (self->sinkcaps && !gst_caps_is_subset (caps, self->sinkcaps))
|
||||
goto cannot_change_caps;
|
||||
gboolean new = FALSE;
|
||||
|
||||
if (!gst_audio_info_from_caps (&info, caps))
|
||||
goto invalid_format;
|
||||
|
||||
if (aaggpad->info.finfo->format == GST_AUDIO_FORMAT_UNKNOWN)
|
||||
g_atomic_int_add (&self->configured_sinkpads_counter, 1);
|
||||
|
||||
gst_audio_aggregator_set_sink_caps (aagg, GST_AUDIO_AGGREGATOR_PAD (pad),
|
||||
caps);
|
||||
|
||||
if (self->channel_positions_from_input
|
||||
&& GST_AUDIO_INFO_CHANNELS (&info) == 1) {
|
||||
channel = GST_AUDIO_INTERLEAVE_PAD (pad)->channel;
|
||||
val = g_value_array_get_nth (self->input_channel_positions, channel);
|
||||
g_value_set_enum (val, GST_AUDIO_INFO_POSITION (&info, 0));
|
||||
}
|
||||
|
||||
if (g_atomic_int_get (&self->configured_sinkpads_counter) < self->channels)
|
||||
return TRUE;
|
||||
|
||||
srccaps = gst_caps_copy (caps);
|
||||
s = gst_caps_get_structure (srccaps, 0);
|
||||
|
||||
gst_structure_remove_field (s, "channel-mask");
|
||||
|
||||
gst_structure_set (s, "channels", G_TYPE_INT, self->channels, "layout",
|
||||
G_TYPE_STRING, "interleaved", NULL);
|
||||
gst_audio_interleave_set_channel_positions (self, s);
|
||||
|
||||
ret = gst_audio_aggregator_set_src_caps (aagg, srccaps);
|
||||
|
||||
gst_caps_unref (srccaps);
|
||||
|
||||
if (!ret)
|
||||
goto src_did_not_accept;
|
||||
|
||||
gst_audio_aggregator_set_sink_caps (aagg, GST_AUDIO_AGGREGATOR_PAD (pad),
|
||||
caps);
|
||||
|
||||
gst_audio_interleave_set_process_function (self);
|
||||
GST_OBJECT_LOCK (self);
|
||||
if (self->sinkcaps && !gst_caps_is_subset (caps, self->sinkcaps))
|
||||
goto cannot_change_caps;
|
||||
|
||||
if (!self->sinkcaps) {
|
||||
GstCaps *sinkcaps = gst_caps_copy (caps);
|
||||
|
@ -474,8 +433,23 @@ gst_audio_interleave_setcaps (GstAudioInterleave * self, GstPad * pad,
|
|||
gst_caps_replace (&self->sinkcaps, sinkcaps);
|
||||
|
||||
gst_caps_unref (sinkcaps);
|
||||
new = TRUE;
|
||||
self->new_caps = TRUE;
|
||||
}
|
||||
|
||||
if (self->channel_positions_from_input
|
||||
&& GST_AUDIO_INFO_CHANNELS (&info) == 1) {
|
||||
channel = GST_AUDIO_INTERLEAVE_PAD (pad)->channel;
|
||||
val = g_value_array_get_nth (self->input_channel_positions, channel);
|
||||
g_value_set_enum (val, GST_AUDIO_INFO_POSITION (&info, 0));
|
||||
}
|
||||
GST_OBJECT_UNLOCK (self);
|
||||
|
||||
gst_audio_aggregator_set_sink_caps (aagg, GST_AUDIO_AGGREGATOR_PAD (pad),
|
||||
caps);
|
||||
|
||||
if (!new)
|
||||
return TRUE;
|
||||
|
||||
GST_INFO_OBJECT (pad, "handle caps change to %" GST_PTR_FORMAT, caps);
|
||||
|
||||
|
@ -490,15 +464,11 @@ invalid_format:
|
|||
}
|
||||
cannot_change_caps:
|
||||
{
|
||||
GST_OBJECT_UNLOCK (self);
|
||||
GST_WARNING_OBJECT (self, "caps of %" GST_PTR_FORMAT " already set, can't "
|
||||
"change", self->sinkcaps);
|
||||
return FALSE;
|
||||
}
|
||||
src_did_not_accept:
|
||||
{
|
||||
GST_WARNING_OBJECT (self, "src did not accept setcaps()");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
|
@ -532,6 +502,48 @@ gst_audio_interleave_sink_event (GstAggregator * agg, GstAggregatorPad * aggpad,
|
|||
return res;
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_audio_interleave_aggregate (GstAggregator * aggregator, gboolean timeout)
|
||||
{
|
||||
GstAudioInterleave *self = GST_AUDIO_INTERLEAVE (aggregator);
|
||||
GstAudioAggregator *aagg = GST_AUDIO_AGGREGATOR (aggregator);
|
||||
|
||||
GST_OBJECT_LOCK (aggregator);
|
||||
if (self->new_caps) {
|
||||
GstCaps *srccaps;
|
||||
GstStructure *s;
|
||||
gboolean ret;
|
||||
|
||||
srccaps = gst_caps_copy (self->sinkcaps);
|
||||
s = gst_caps_get_structure (srccaps, 0);
|
||||
|
||||
gst_structure_set (s, "channels", G_TYPE_INT, self->channels, "layout",
|
||||
G_TYPE_STRING, "interleaved", "channel-mask", GST_TYPE_BITMASK,
|
||||
gst_audio_interleave_get_channel_mask (self), NULL);
|
||||
|
||||
|
||||
GST_OBJECT_UNLOCK (aggregator);
|
||||
ret = gst_audio_aggregator_set_src_caps (aagg, srccaps);
|
||||
gst_caps_unref (srccaps);
|
||||
|
||||
if (!ret)
|
||||
goto src_did_not_accept;
|
||||
|
||||
GST_OBJECT_LOCK (aggregator);
|
||||
|
||||
gst_audio_interleave_set_process_function (self, &aagg->info);
|
||||
|
||||
self->new_caps = FALSE;
|
||||
}
|
||||
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
|
||||
gst_audio_interleave_class_init (GstAudioInterleaveClass * klass)
|
||||
{
|
||||
|
@ -567,6 +579,7 @@ gst_audio_interleave_class_init (GstAudioInterleaveClass * klass)
|
|||
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->stop = gst_audio_interleave_stop;
|
||||
agg_class->aggregate = gst_audio_interleave_aggregate;
|
||||
|
||||
aagg_class->aggregate_one_buffer = gst_audio_interleave_aggregate_one_buffer;
|
||||
|
||||
|
@ -701,6 +714,7 @@ gst_audio_interleave_stop (GstAggregator * agg)
|
|||
if (!GST_AGGREGATOR_CLASS (parent_class)->stop (agg))
|
||||
return FALSE;
|
||||
|
||||
self->new_caps = FALSE;
|
||||
gst_caps_replace (&self->sinkcaps, NULL);
|
||||
|
||||
return TRUE;
|
||||
|
@ -746,22 +760,9 @@ gst_audio_interleave_request_new_pad (GstElement * element,
|
|||
g_value_unset (&val);
|
||||
|
||||
/* Update the src caps if we already have them */
|
||||
if (self->sinkcaps) {
|
||||
GstCaps *srccaps;
|
||||
GstStructure *s;
|
||||
|
||||
/* Take lock to make sure processing finishes first */
|
||||
|
||||
srccaps = gst_caps_copy (self->sinkcaps);
|
||||
s = gst_caps_get_structure (srccaps, 0);
|
||||
|
||||
gst_structure_set (s, "channels", G_TYPE_INT, self->channels, NULL);
|
||||
|
||||
gst_audio_interleave_set_channel_positions (self, s);
|
||||
|
||||
gst_audio_aggregator_set_src_caps (GST_AUDIO_AGGREGATOR (self), srccaps);
|
||||
gst_caps_unref (srccaps);
|
||||
}
|
||||
GST_OBJECT_LOCK (self);
|
||||
self->new_caps = TRUE;
|
||||
GST_OBJECT_UNLOCK (self);
|
||||
|
||||
return GST_PAD_CAST (newpad);
|
||||
|
||||
|
@ -786,9 +787,6 @@ gst_audio_interleave_release_pad (GstElement * element, GstPad * pad)
|
|||
|
||||
g_atomic_int_add (&self->channels, -1);
|
||||
|
||||
if (gst_pad_has_current_caps (pad))
|
||||
g_atomic_int_add (&self->configured_sinkpads_counter, -1);
|
||||
|
||||
position = GST_AUDIO_INTERLEAVE_PAD (pad)->channel;
|
||||
g_value_array_remove (self->input_channel_positions, position);
|
||||
|
||||
|
@ -801,33 +799,9 @@ gst_audio_interleave_release_pad (GstElement * element, GstPad * pad)
|
|||
ipad->channel--;
|
||||
}
|
||||
|
||||
|
||||
/* Update the src caps if we already have them */
|
||||
if (self->sinkcaps) {
|
||||
if (self->channels > 0) {
|
||||
GstCaps *srccaps;
|
||||
GstStructure *s;
|
||||
|
||||
srccaps = gst_caps_copy (self->sinkcaps);
|
||||
s = gst_caps_get_structure (srccaps, 0);
|
||||
|
||||
gst_structure_set (s, "channels", G_TYPE_INT, self->channels, NULL);
|
||||
gst_audio_interleave_set_channel_positions (self, s);
|
||||
|
||||
self->new_caps = TRUE;
|
||||
GST_OBJECT_UNLOCK (self);
|
||||
|
||||
gst_audio_aggregator_set_src_caps (GST_AUDIO_AGGREGATOR (self), srccaps);
|
||||
gst_caps_unref (srccaps);
|
||||
} else {
|
||||
gst_caps_replace (&self->sinkcaps, NULL);
|
||||
GST_OBJECT_UNLOCK (self);
|
||||
}
|
||||
} else {
|
||||
GST_OBJECT_UNLOCK (self);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
GST_DEBUG_OBJECT (self, "release pad %s:%s", GST_DEBUG_PAD_NAME (pad));
|
||||
|
||||
|
|
|
@ -58,8 +58,8 @@ struct _GstAudioInterleave {
|
|||
gint padcounter;
|
||||
guint channels;
|
||||
|
||||
gboolean new_caps;
|
||||
GstCaps *sinkcaps;
|
||||
gint configured_sinkpads_counter;
|
||||
|
||||
GValueArray *channel_positions;
|
||||
GValueArray *input_channel_positions;
|
||||
|
|
Loading…
Reference in a new issue