diff options
author | Olivier CrĂȘte <olivier.crete@collabora.com> | 2015-03-06 13:49:48 -0500 |
---|---|---|
committer | Olivier CrĂȘte <olivier.crete@collabora.com> | 2015-03-16 16:44:03 -0400 |
commit | 224f14a299ed5cae77354c41dc16d3f2d9234f6d (patch) | |
tree | 3218499d6bd173df9cf97dc3bbdbd548d7ddea2b /gst/audiomixer | |
parent | b08b01895fc0606fec7477084332130f12345996 (diff) | |
download | gstreamer-plugins-bad-224f14a299ed5cae77354c41dc16d3f2d9234f6d.tar.gz |
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
Diffstat (limited to 'gst/audiomixer')
-rw-r--r-- | gst/audiomixer/gstaudiointerleave.c | 182 | ||||
-rw-r--r-- | gst/audiomixer/gstaudiointerleave.h | 2 |
2 files changed, 79 insertions, 105 deletions
diff --git a/gst/audiomixer/gstaudiointerleave.c b/gst/audiomixer/gstaudiointerleave.c index f06ea2824..fc984298e 100644 --- a/gst/audiomixer/gstaudiointerleave.c +++ b/gst/audiomixer/gstaudiointerleave.c @@ -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,32 +799,8 @@ 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); - - 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); - } - - + self->new_caps = TRUE; + GST_OBJECT_UNLOCK (self); GST_DEBUG_OBJECT (self, "release pad %s:%s", GST_DEBUG_PAD_NAME (pad)); diff --git a/gst/audiomixer/gstaudiointerleave.h b/gst/audiomixer/gstaudiointerleave.h index 87f6385e3..0473b45e0 100644 --- a/gst/audiomixer/gstaudiointerleave.h +++ b/gst/audiomixer/gstaudiointerleave.h @@ -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; |