From 4945af5eff456defc0073a38982e0e92a0a4305b Mon Sep 17 00:00:00 2001 From: Philippe Normand Date: Tue, 14 Feb 2012 11:56:00 +0100 Subject: [PATCH] interleave: port to 0.11 Port of the interleave element and its unittests. https://bugzilla.gnome.org/show_bug.cgi?id=669643 --- gst/interleave/Makefile.am | 4 +- gst/interleave/interleave.c | 348 ++++++++++++++++++-------------------- gst/interleave/interleave.h | 4 +- gst/interleave/plugin.c | 20 +-- gst/interleave/plugin.h | 2 - tests/check/elements/interleave.c | 57 +++++-- 6 files changed, 222 insertions(+), 213 deletions(-) diff --git a/gst/interleave/Makefile.am b/gst/interleave/Makefile.am index eb7f434..0a2d2d8 100644 --- a/gst/interleave/Makefile.am +++ b/gst/interleave/Makefile.am @@ -1,13 +1,13 @@ plugin_LTLIBRARIES = libgstinterleave.la -libgstinterleave_la_SOURCES = plugin.c deinterleave.c +libgstinterleave_la_SOURCES = plugin.c interleave.c deinterleave.c libgstinterleave_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS) libgstinterleave_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) -lgstaudio-$(GST_MAJORMINOR) $(GST_BASE_LIBS) $(GST_LIBS) libgstinterleave_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) libgstinterleave_la_LIBTOOLFLAGS = --tag=disable-static -noinst_HEADERS = plugin.h deinterleave.h +noinst_HEADERS = plugin.h interleave.h deinterleave.h Android.mk: Makefile.am $(BUILT_SOURCES) androgenizer \ diff --git a/gst/interleave/interleave.c b/gst/interleave/interleave.c index 97d81e4..6a0758d 100644 --- a/gst/interleave/interleave.c +++ b/gst/interleave/interleave.c @@ -47,12 +47,12 @@ * * Example launch line * |[ - * gst-launch filesrc location=file.mp3 ! decodebin ! audioconvert ! "audio/x-raw-int,channels=2" ! deinterleave name=d interleave name=i ! audioconvert ! wavenc ! filesink location=test.wav d.src0 ! queue ! audioconvert ! i.sink1 d.src1 ! queue ! audioconvert ! i.sink0 + * gst-launch filesrc location=file.mp3 ! decodebin ! audioconvert ! "audio/x-raw,channels=2" ! deinterleave name=d interleave name=i ! audioconvert ! wavenc ! filesink location=test.wav d.src_0 ! queue ! audioconvert ! i.sink_1 d.src_1 ! queue ! audioconvert ! i.sink_0 * ]| Decodes and deinterleaves a Stereo MP3 file into separate channels and * then interleaves the channels again to a WAV file with the channel with the * channels exchanged. * |[ - * gst-launch interleave name=i ! audioconvert ! wavenc ! filesink location=file.wav filesrc location=file1.wav ! decodebin ! audioconvert ! "audio/x-raw-int,channels=1" ! queue ! i.sink0 filesrc location=file2.wav ! decodebin ! audioconvert ! "audio/x-raw-int,channels=1" ! queue ! i.sink1 + * gst-launch interleave name=i ! audioconvert ! wavenc ! filesink location=file.wav filesrc location=file1.wav ! decodebin ! audioconvert ! "audio/x-raw,channels=1" ! queue ! i.sink_0 filesrc location=file2.wav ! decodebin ! audioconvert ! "audio/x-raw,channels=1" ! queue ! i.sink_1 * ]| Interleaves two Mono WAV files to a single Stereo WAV file. * */ @@ -65,7 +65,8 @@ #include #include "interleave.h" -#include +#include +#include GST_DEBUG_CATEGORY_STATIC (gst_interleave_debug); #define GST_CAT_DEFAULT gst_interleave_debug @@ -73,35 +74,21 @@ GST_DEBUG_CATEGORY_STATIC (gst_interleave_debug); static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink_%u", GST_PAD_SINK, GST_PAD_REQUEST, - GST_STATIC_CAPS ("audio/x-raw-int, " + GST_STATIC_CAPS ("audio/x-raw, " "rate = (int) [ 1, MAX ], " "channels = (int) 1, " - "endianness = (int) { LITTLE_ENDIAN, BIG_ENDIAN }, " - "width = (int) { 8, 16, 24, 32 }, " - "depth = (int) [ 1, 32 ], " - "signed = (boolean) true; " - "audio/x-raw-float, " - "rate = (int) [ 1, MAX ], " - "channels = (int) 1, " - "endianness = (int) { LITTLE_ENDIAN , BIG_ENDIAN }, " - "width = (int) { 32, 64 }") + "format = (string) " GST_AUDIO_FORMATS_ALL ", " + "layout = (string) {non-interleaved, interleaved}") ); static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS, - GST_STATIC_CAPS ("audio/x-raw-int, " - "rate = (int) [ 1, MAX ], " - "channels = (int) [ 1, MAX ], " - "endianness = (int) { LITTLE_ENDIAN, BIG_ENDIAN }, " - "width = (int) { 8, 16, 24, 32 }, " - "depth = (int) [ 1, 32 ], " - "signed = (boolean) true; " - "audio/x-raw-float, " + GST_STATIC_CAPS ("audio/x-raw, " "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, MAX ], " - "endianness = (int) { LITTLE_ENDIAN , BIG_ENDIAN }, " - "width = (int) { 32, 64 }") + "format = (string) " GST_AUDIO_FORMATS_ALL ", " + "layout = (string) interleaved") ); #define MAKE_FUNC(type) \ @@ -196,7 +183,8 @@ gst_interleave_pad_class_init (GstPadClass * klass) G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); } -GST_BOILERPLATE (GstInterleave, gst_interleave, GstElement, GST_TYPE_ELEMENT); +#define gst_interleave_parent_class parent_class +G_DEFINE_TYPE (GstInterleave, gst_interleave, GST_TYPE_ELEMENT); enum { @@ -211,21 +199,26 @@ static void gst_interleave_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec); static GstPad *gst_interleave_request_new_pad (GstElement * element, - GstPadTemplate * templ, const gchar * name); + GstPadTemplate * templ, const gchar * name, const GstCaps * caps); static void gst_interleave_release_pad (GstElement * element, GstPad * pad); static GstStateChangeReturn gst_interleave_change_state (GstElement * element, GstStateChange transition); -static gboolean gst_interleave_src_query (GstPad * pad, GstQuery * query); +static gboolean gst_interleave_src_query (GstPad * pad, GstObject * parent, + GstQuery * query); -static gboolean gst_interleave_src_event (GstPad * pad, GstEvent * event); +static gboolean gst_interleave_src_event (GstPad * pad, GstObject * parent, + GstEvent * event); -static gboolean gst_interleave_sink_event (GstPad * pad, GstEvent * event); +static gboolean gst_interleave_sink_event (GstCollectPads2 * pads, + GstCollectData2 * data, GstEvent * event, gpointer user_data); -static gboolean gst_interleave_sink_setcaps (GstPad * pad, GstCaps * caps); +static gboolean gst_interleave_sink_setcaps (GstInterleave * self, + GstPad * pad, const GstCaps * caps); -static GstCaps *gst_interleave_sink_getcaps (GstPad * pad); +static GstCaps *gst_interleave_sink_getcaps (GstPad * pad, GstObject * parent, + GstCaps * filter); static GstFlowReturn gst_interleave_collected (GstCollectPads2 * pads, GstInterleave * self); @@ -242,12 +235,12 @@ gst_interleave_finalize (GObject * object) if (self->channel_positions && self->channel_positions != self->input_channel_positions) { - g_value_array_free (self->channel_positions); + g_array_free (self->channel_positions, TRUE); self->channel_positions = NULL; } if (self->input_channel_positions) { - g_value_array_free (self->input_channel_positions); + g_array_free (self->input_channel_positions, TRUE); self->input_channel_positions = NULL; } @@ -257,23 +250,24 @@ gst_interleave_finalize (GObject * object) } static gboolean -gst_interleave_check_channel_positions (GValueArray * positions) +gst_interleave_check_channel_positions (GArray * positions) { gint i; guint channels; GstAudioChannelPosition *pos; gboolean ret; + GValue val; - channels = positions->n_values; - pos = g_new (GstAudioChannelPosition, positions->n_values); + channels = positions->len; + pos = g_new (GstAudioChannelPosition, channels); for (i = 0; i < channels; i++) { - GValue *v = g_value_array_get_nth (positions, i); - - pos[i] = g_value_get_enum (v); + val = g_array_index (positions, GValue, i); + pos[i] = g_value_get_enum (&val); + g_value_reset (&val); } - ret = gst_audio_check_channel_positions (pos, channels); + ret = gst_audio_check_valid_channel_positions (pos, channels, FALSE); g_free (pos); return ret; @@ -282,48 +276,22 @@ gst_interleave_check_channel_positions (GValueArray * positions) static void gst_interleave_set_channel_positions (GstInterleave * self, GstStructure * s) { - GValue pos_array = { 0, }; gint i; + guint64 channel_mask = 0; + GValue val; - g_value_init (&pos_array, GST_TYPE_ARRAY); - - if (self->channel_positions - && self->channels == self->channel_positions->n_values + if (self->channel_positions && self->channels == self->channel_positions->len && gst_interleave_check_channel_positions (self->channel_positions)) { GST_DEBUG_OBJECT (self, "Using provided channel positions"); - for (i = 0; i < self->channels; i++) - gst_value_array_append_value (&pos_array, - g_value_array_get_nth (self->channel_positions, i)); + for (i = 0; i < self->channels; i++) { + val = g_array_index (self->channel_positions, GValue, i); + channel_mask |= G_GUINT64_CONSTANT (1) << g_value_get_enum (&val); + g_value_reset (&val); + } } else { - GValue pos_none = { 0, }; - GST_WARNING_OBJECT (self, "Using NONE channel positions"); - - g_value_init (&pos_none, GST_TYPE_AUDIO_CHANNEL_POSITION); - g_value_set_enum (&pos_none, GST_AUDIO_CHANNEL_POSITION_NONE); - - for (i = 0; i < self->channels; i++) - gst_value_array_append_value (&pos_array, &pos_none); - - g_value_unset (&pos_none); } - gst_structure_set_value (s, "channel-positions", &pos_array); - g_value_unset (&pos_array); -} - -static void -gst_interleave_base_init (gpointer g_class) -{ - gst_element_class_set_details_simple (g_class, "Audio interleaver", - "Filter/Converter/Audio", - "Folds many mono channels into one interleaved audio stream", - "Andy Wingo , " - "Sebastian Dröge "); - - gst_element_class_add_pad_template (g_class, - gst_static_pad_template_get (&sink_template)); - gst_element_class_add_pad_template (g_class, - gst_static_pad_template_get (&src_template)); + gst_structure_set (s, "channel-mask", GST_TYPE_BITMASK, channel_mask, NULL); } static void @@ -338,6 +306,17 @@ gst_interleave_class_init (GstInterleaveClass * klass) GST_DEBUG_CATEGORY_INIT (gst_interleave_debug, "interleave", 0, "interleave element"); + gst_element_class_set_details_simple (gstelement_class, "Audio interleaver", + "Filter/Converter/Audio", + "Folds many mono channels into one interleaved audio stream", + "Andy Wingo , " + "Sebastian Dröge "); + + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&sink_template)); + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&src_template)); + /* Reference GstInterleavePad class to have the type registered from * a threadsafe context */ @@ -362,13 +341,8 @@ gst_interleave_class_init (GstInterleaveClass * klass) * */ g_object_class_install_property (gobject_class, PROP_CHANNEL_POSITIONS, - g_param_spec_value_array ("channel-positions", "Channel positions", - "Channel positions used on the output", - g_param_spec_enum ("channel-position", "Channel position", - "Channel position of the n-th input", - GST_TYPE_AUDIO_CHANNEL_POSITION, - GST_AUDIO_CHANNEL_POSITION_NONE, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS), + g_param_spec_boxed ("channel-positions", "Channel positions", + "Channel position of the n-th output", G_TYPE_ARRAY, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); /** @@ -396,7 +370,7 @@ gst_interleave_class_init (GstInterleaveClass * klass) } static void -gst_interleave_init (GstInterleave * self, GstInterleaveClass * klass) +gst_interleave_init (GstInterleave * self) { self->src = gst_pad_new_from_static_template (&src_template, "src"); @@ -405,13 +379,14 @@ gst_interleave_init (GstInterleave * self, GstInterleaveClass * klass) gst_pad_set_event_function (self->src, GST_DEBUG_FUNCPTR (gst_interleave_src_event)); + gst_pad_set_active (self->src, TRUE); gst_element_add_pad (GST_ELEMENT (self), self->src); self->collect = gst_collect_pads2_new (); gst_collect_pads2_set_function (self->collect, (GstCollectPads2Function) gst_interleave_collected, self); - self->input_channel_positions = g_value_array_new (0); + self->input_channel_positions = g_array_new (FALSE, TRUE, sizeof (GValue)); self->channel_positions_from_input = TRUE; self->channel_positions = self->input_channel_positions; } @@ -421,15 +396,22 @@ gst_interleave_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) { GstInterleave *self = GST_INTERLEAVE (object); + int i; + GArray *arr; switch (prop_id) { case PROP_CHANNEL_POSITIONS: if (self->channel_positions && self->channel_positions != self->input_channel_positions) - g_value_array_free (self->channel_positions); + g_array_free (self->channel_positions, TRUE); - self->channel_positions = g_value_dup_boxed (value); + arr = g_value_get_boxed (value); + self->channel_positions = g_array_new (FALSE, TRUE, sizeof (GValue)); + for (i = 0; i < arr->len; i++) + g_array_append_val (self->channel_positions, g_array_index (arr, GValue, + i)); self->channel_positions_from_input = FALSE; + self->channels = self->channel_positions->len; break; case PROP_CHANNEL_POSITIONS_FROM_INPUT: self->channel_positions_from_input = g_value_get_boolean (value); @@ -437,7 +419,7 @@ gst_interleave_set_property (GObject * object, guint prop_id, if (self->channel_positions_from_input) { if (self->channel_positions && self->channel_positions != self->input_channel_positions) - g_value_array_free (self->channel_positions); + g_array_free (self->channel_positions, TRUE); self->channel_positions = self->input_channel_positions; } break; @@ -468,7 +450,7 @@ gst_interleave_get_property (GObject * object, guint prop_id, static GstPad * gst_interleave_request_new_pad (GstElement * element, GstPadTemplate * templ, - const gchar * req_name) + const gchar * req_name, const GstCaps * caps) { GstInterleave *self = GST_INTERLEAVE (element); GstPad *new_pad; @@ -479,8 +461,11 @@ gst_interleave_request_new_pad (GstElement * element, GstPadTemplate * templ, if (templ->direction != GST_PAD_SINK) goto not_sink_pad; - channels = g_atomic_int_add (&self->channels, 1); padnumber = g_atomic_int_add (&self->padcounter, 1); + if (self->channel_positions_from_input) + channels = g_atomic_int_add (&self->channels, 1); + else + channels = padnumber; pad_name = g_strdup_printf ("sink_%u", padnumber); new_pad = GST_PAD_CAST (g_object_new (GST_TYPE_INTERLEAVE_PAD, @@ -490,19 +475,13 @@ gst_interleave_request_new_pad (GstElement * element, GstPadTemplate * templ, GST_DEBUG_OBJECT (self, "requested new pad %s", pad_name); g_free (pad_name); - gst_pad_set_setcaps_function (new_pad, - GST_DEBUG_FUNCPTR (gst_interleave_sink_setcaps)); - gst_pad_set_getcaps_function (new_pad, - GST_DEBUG_FUNCPTR (gst_interleave_sink_getcaps)); + gst_pad_use_fixed_caps (new_pad); gst_collect_pads2_add_pad (self->collect, new_pad, sizeof (GstCollectData2)); - /* FIXME: hacked way to override/extend the event function of - * GstCollectPads2; because it sets its own event function giving the - * element no access to events */ - self->collect_event = (GstPadEventFunction) GST_PAD_EVENTFUNC (new_pad); - gst_pad_set_event_function (new_pad, - GST_DEBUG_FUNCPTR (gst_interleave_sink_event)); + gst_collect_pads2_set_event_function (self->collect, + (GstCollectPads2EventFunction) + GST_DEBUG_FUNCPTR (gst_interleave_sink_event), self); if (!gst_element_add_pad (element, new_pad)) goto could_not_add; @@ -510,7 +489,7 @@ gst_interleave_request_new_pad (GstElement * element, GstPadTemplate * templ, g_value_init (&val, GST_TYPE_AUDIO_CHANNEL_POSITION); g_value_set_enum (&val, GST_AUDIO_CHANNEL_POSITION_NONE); self->input_channel_positions = - g_value_array_append (self->input_channel_positions, &val); + g_array_append_val (self->input_channel_positions, val); g_value_unset (&val); /* Update the src caps if we already have them */ @@ -527,6 +506,7 @@ gst_interleave_request_new_pad (GstElement * element, GstPadTemplate * templ, gst_structure_set (s, "channels", G_TYPE_INT, self->channels, NULL); gst_interleave_set_channel_positions (self, s); + gst_pad_set_active (self->src, TRUE); gst_pad_set_caps (self->src, srccaps); gst_caps_unref (srccaps); @@ -555,6 +535,7 @@ gst_interleave_release_pad (GstElement * element, GstPad * pad) { GstInterleave *self = GST_INTERLEAVE (element); GList *l; + GstAudioChannelPosition position; g_return_if_fail (GST_IS_INTERLEAVE_PAD (pad)); @@ -563,8 +544,8 @@ gst_interleave_release_pad (GstElement * element, GstPad * pad) g_atomic_int_add (&self->channels, -1); - g_value_array_remove (self->input_channel_positions, - GST_INTERLEAVE_PAD_CAST (pad)->channel); + position = GST_INTERLEAVE_PAD_CAST (pad)->channel; + g_array_remove_index (self->input_channel_positions, position); /* Update channel numbers */ GST_OBJECT_LOCK (self); @@ -588,11 +569,11 @@ gst_interleave_release_pad (GstElement * element, GstPad * pad) gst_structure_set (s, "channels", G_TYPE_INT, self->channels, NULL); gst_interleave_set_channel_positions (self, s); + gst_pad_set_active (self->src, TRUE); gst_pad_set_caps (self->src, srccaps); gst_caps_unref (srccaps); } else { gst_caps_replace (&self->sinkcaps, NULL); - gst_pad_set_caps (self->src, NULL); } } @@ -641,7 +622,6 @@ gst_interleave_change_state (GstElement * element, GstStateChange transition) case GST_STATE_CHANGE_PLAYING_TO_PAUSED: break; case GST_STATE_CHANGE_PAUSED_TO_READY: - gst_pad_set_caps (self->src, NULL); gst_caps_replace (&self->sinkcaps, NULL); break; case GST_STATE_CHANGE_READY_TO_NULL: @@ -662,7 +642,7 @@ __remove_channels (GstCaps * caps) size = gst_caps_get_size (caps); for (i = 0; i < size; i++) { s = gst_caps_get_structure (caps, i); - gst_structure_remove_field (s, "channel-positions"); + gst_structure_remove_field (s, "channel-mask"); gst_structure_remove_field (s, "channels"); } } @@ -685,9 +665,9 @@ __set_channels (GstCaps * caps, gint channels) /* we can only accept caps that we and downstream can handle. */ static GstCaps * -gst_interleave_sink_getcaps (GstPad * pad) +gst_interleave_sink_getcaps (GstPad * pad, GstObject * parent, GstCaps * filter) { - GstInterleave *self = GST_INTERLEAVE (gst_pad_get_parent (pad)); + GstInterleave *self = GST_INTERLEAVE (parent); GstCaps *result, *peercaps, *sinkcaps; GST_OBJECT_LOCK (self); @@ -697,7 +677,8 @@ gst_interleave_sink_getcaps (GstPad * pad) result = gst_caps_copy (self->sinkcaps); } else { /* get the downstream possible caps */ - peercaps = gst_pad_peer_get_caps (self->src); + peercaps = gst_pad_peer_query_caps (self->src, NULL); + /* get the allowed caps on this sinkpad */ sinkcaps = gst_caps_copy (gst_pad_get_pad_template_caps (pad)); __remove_channels (sinkcaps); @@ -719,8 +700,6 @@ gst_interleave_sink_getcaps (GstPad * pad) GST_OBJECT_UNLOCK (self); - gst_object_unref (self); - GST_DEBUG_OBJECT (pad, "Returning caps %" GST_PTR_FORMAT, result); return result; @@ -752,14 +731,11 @@ gst_interleave_set_process_function (GstInterleave * self) } static gboolean -gst_interleave_sink_setcaps (GstPad * pad, GstCaps * caps) +gst_interleave_sink_setcaps (GstInterleave * self, GstPad * pad, + const GstCaps * caps) { - GstInterleave *self; - g_return_val_if_fail (GST_IS_INTERLEAVE_PAD (pad), FALSE); - self = GST_INTERLEAVE (gst_pad_get_parent (pad)); - /* First caps that are set on a sink pad are used as output caps */ /* TODO: handle caps changes */ if (self->sinkcaps && !gst_caps_is_subset (caps, self->sinkcaps)) { @@ -768,38 +744,35 @@ gst_interleave_sink_setcaps (GstPad * pad, GstCaps * caps) GstCaps *srccaps; GstStructure *s; gboolean res; + GstAudioInfo info; + GValue *val; + guint channel; - s = gst_caps_get_structure (caps, 0); + if (!gst_audio_info_from_caps (&info, caps)) + goto invalid_caps; - if (!gst_structure_get_int (s, "width", &self->width)) - goto no_width; + self->width = GST_AUDIO_INFO_WIDTH (&info); + self->rate = GST_AUDIO_INFO_RATE (&info); - if (!gst_structure_get_int (s, "rate", &self->rate)) - goto no_rate; gst_interleave_set_process_function (self); + channel = GST_INTERLEAVE_PAD_CAST (pad)->channel; - if (gst_structure_has_field (s, "channel-positions")) { - const GValue *pos_array; - - pos_array = gst_structure_get_value (s, "channel-positions"); - if (GST_VALUE_HOLDS_ARRAY (pos_array) - && gst_value_array_get_size (pos_array) == 1) { - const GValue *pos = gst_value_array_get_value (pos_array, 0); - - GValue *apos = g_value_array_get_nth (self->input_channel_positions, - GST_INTERLEAVE_PAD_CAST (pad)->channel); - - g_value_set_enum (apos, g_value_get_enum (pos)); - } + if (self->channel_positions_from_input + && GST_AUDIO_INFO_CHANNELS (&info) == 1) { + val = &g_array_index (self->input_channel_positions, GValue, channel); + g_value_set_enum (val, GST_AUDIO_INFO_POSITION (&info, 0)); } 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, NULL); gst_interleave_set_channel_positions (self, s); + gst_pad_set_active (self->src, TRUE); res = gst_pad_set_caps (self->src, srccaps); gst_caps_unref (srccaps); @@ -811,53 +784,42 @@ gst_interleave_sink_setcaps (GstPad * pad, GstCaps * caps) GstCaps *sinkcaps = gst_caps_copy (caps); GstStructure *s = gst_caps_get_structure (sinkcaps, 0); - gst_structure_remove_field (s, "channel-positions"); + gst_structure_remove_field (s, "channel-mask"); gst_caps_replace (&self->sinkcaps, sinkcaps); gst_caps_unref (sinkcaps); } - gst_object_unref (self); - return TRUE; cannot_change_caps: { GST_WARNING_OBJECT (self, "caps of %" GST_PTR_FORMAT " already set, can't " "change", self->sinkcaps); - gst_object_unref (self); return FALSE; } src_did_not_accept: { GST_WARNING_OBJECT (self, "src did not accept setcaps()"); - gst_object_unref (self); return FALSE; } -no_width: +invalid_caps: { - GST_WARNING_OBJECT (self, "caps did not have width: %" GST_PTR_FORMAT, - caps); - gst_object_unref (self); - return FALSE; - } -no_rate: - { - GST_WARNING_OBJECT (self, "caps did not have rate: %" GST_PTR_FORMAT, caps); - gst_object_unref (self); + GST_WARNING_OBJECT (self, "invalid sink caps"); return FALSE; } } static gboolean -gst_interleave_sink_event (GstPad * pad, GstEvent * event) +gst_interleave_sink_event (GstCollectPads2 * pads, GstCollectData2 * data, + GstEvent * event, gpointer user_data) { - GstInterleave *self = GST_INTERLEAVE (gst_pad_get_parent (pad)); - gboolean ret; + GstInterleave *self = GST_INTERLEAVE (user_data); + gboolean ret = FALSE; GST_DEBUG ("Got %s event on pad %s:%s", GST_EVENT_TYPE_NAME (event), - GST_DEBUG_PAD_NAME (pad)); + GST_DEBUG_PAD_NAME (data->pad)); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_FLUSH_STOP: @@ -869,14 +831,21 @@ gst_interleave_sink_event (GstPad * pad, GstEvent * event) */ self->segment_pending = TRUE; break; + case GST_EVENT_CAPS: + { + GstCaps *caps; + + gst_event_parse_caps (event, &caps); + ret = gst_interleave_sink_setcaps (self, data->pad, caps); + gst_event_unref (event); + break; + } default: + ret = gst_pad_event_default (data->pad, GST_OBJECT (self), event); break; } /* now GstCollectPads2 can take care of the rest, e.g. EOS */ - ret = self->collect_event (pad, event); - - gst_object_unref (self); return ret; } @@ -901,7 +870,7 @@ gst_interleave_src_query_duration (GstInterleave * self, GstQuery * query) while (!done) { GstIteratorResult ires; - gpointer item; + GValue item = { 0, }; ires = gst_iterator_next (it, &item); switch (ires) { @@ -910,12 +879,12 @@ gst_interleave_src_query_duration (GstInterleave * self, GstQuery * query) break; case GST_ITERATOR_OK: { - GstPad *pad = GST_PAD_CAST (item); + GstPad *pad = GST_PAD_CAST (g_value_dup_object (&item)); gint64 duration; /* ask sink peer for duration */ - res &= gst_pad_query_peer_duration (pad, &format, &duration); + res &= gst_pad_peer_query_duration (pad, format, &duration); /* take max from all valid return values */ if (res) { /* valid unknown length, stop searching */ @@ -928,6 +897,7 @@ gst_interleave_src_query_duration (GstInterleave * self, GstQuery * query) max = duration; } gst_object_unref (pad); + g_value_unset (&item); break; } case GST_ITERATOR_RESYNC: @@ -978,7 +948,7 @@ gst_interleave_src_query_latency (GstInterleave * self, GstQuery * query) it = gst_element_iterate_sink_pads (GST_ELEMENT_CAST (self)); while (!done) { GstIteratorResult ires; - gpointer item; + GValue item = { 0, }; ires = gst_iterator_next (it, &item); switch (ires) { @@ -987,7 +957,7 @@ gst_interleave_src_query_latency (GstInterleave * self, GstQuery * query) break; case GST_ITERATOR_OK: { - GstPad *pad = GST_PAD_CAST (item); + GstPad *pad = GST_PAD_CAST (g_value_dup_object (&item)); GstQuery *peerquery; GstClockTime min_cur, max_cur; gboolean live_cur; @@ -1014,6 +984,7 @@ gst_interleave_src_query_latency (GstInterleave * self, GstQuery * query) gst_query_unref (peerquery); gst_object_unref (pad); + g_value_unset (&item); break; } case GST_ITERATOR_RESYNC: @@ -1043,9 +1014,9 @@ gst_interleave_src_query_latency (GstInterleave * self, GstQuery * query) } static gboolean -gst_interleave_src_query (GstPad * pad, GstQuery * query) +gst_interleave_src_query (GstPad * pad, GstObject * parent, GstQuery * query) { - GstInterleave *self = GST_INTERLEAVE (gst_pad_get_parent (pad)); + GstInterleave *self = GST_INTERLEAVE (parent); gboolean res = FALSE; switch (GST_QUERY_TYPE (query)) { @@ -1081,20 +1052,30 @@ gst_interleave_src_query (GstPad * pad, GstQuery * query) case GST_QUERY_LATENCY: res = gst_interleave_src_query_latency (self, query); break; + case GST_QUERY_CAPS: + { + GstCaps *filter, *caps; + + gst_query_parse_caps (query, &filter); + caps = gst_interleave_sink_getcaps (pad, parent, filter); + gst_query_set_caps_result (query, caps); + gst_caps_unref (caps); + res = TRUE; + } default: /* FIXME, needs a custom query handler because we have multiple * sinkpads */ - res = gst_pad_query_default (pad, query); + res = gst_pad_query_default (pad, parent, query); break; } - gst_object_unref (self); return res; } static gboolean -forward_event_func (GstPad * pad, GValue * ret, GstEvent * event) +forward_event_func (const GValue * item, GValue * ret, GstEvent * event) { + GstPad *pad = GST_PAD_CAST (g_value_dup_object (item)); gst_event_ref (event); GST_LOG_OBJECT (pad, "About to send event %s", GST_EVENT_TYPE_NAME (event)); if (!gst_pad_push_event (pad, event)) { @@ -1131,9 +1112,9 @@ forward_event (GstInterleave * self, GstEvent * event) static gboolean -gst_interleave_src_event (GstPad * pad, GstEvent * event) +gst_interleave_src_event (GstPad * pad, GstObject * parent, GstEvent * event) { - GstInterleave *self = GST_INTERLEAVE (gst_pad_get_parent (pad)); + GstInterleave *self = GST_INTERLEAVE (parent); gboolean result; switch (GST_EVENT_TYPE (event)) { @@ -1183,7 +1164,6 @@ gst_interleave_src_event (GstPad * pad, GstEvent * event) result = forward_event (self, event); break; } - gst_object_unref (self); return result; } @@ -1199,6 +1179,7 @@ gst_interleave_collected (GstCollectPads2 * pads, GstInterleave * self) guint ncollected = 0; gboolean empty = TRUE; gint width = self->width / 8; + GstMapInfo write_info; g_return_val_if_fail (self->func != NULL, GST_FLOW_NOT_NEGOTIATED); g_return_val_if_fail (self->width > 0, GST_FLOW_NOT_NEGOTIATED); @@ -1214,27 +1195,21 @@ gst_interleave_collected (GstCollectPads2 * pads, GstInterleave * self) nsamples = size / width; - ret = - gst_pad_alloc_buffer (self->src, GST_BUFFER_OFFSET_NONE, - size * self->channels, GST_PAD_CAPS (self->src), &outbuf); + outbuf = gst_buffer_new_allocate (NULL, size * self->channels, 0); - if (ret != GST_FLOW_OK) { - return ret; - } else if (outbuf == NULL || GST_BUFFER_SIZE (outbuf) < size * self->channels) { - gst_buffer_unref (outbuf); - return GST_FLOW_NOT_NEGOTIATED; - } else if (!gst_caps_is_equal (GST_BUFFER_CAPS (outbuf), - GST_PAD_CAPS (self->src))) { + if (outbuf == NULL || gst_buffer_get_size (outbuf) < size * self->channels) { gst_buffer_unref (outbuf); return GST_FLOW_NOT_NEGOTIATED; } - memset (GST_BUFFER_DATA (outbuf), 0, size * self->channels); + gst_buffer_map (outbuf, &write_info, GST_MAP_WRITE); + memset (write_info.data, 0, size * self->channels); for (collected = pads->data; collected != NULL; collected = collected->next) { GstCollectData2 *cdata; GstBuffer *inbuf; guint8 *outdata; + GstMapInfo input_info; cdata = (GstCollectData2 *) collected->data; @@ -1244,30 +1219,33 @@ gst_interleave_collected (GstCollectPads2 * pads, GstInterleave * self) goto next; } ncollected++; + gst_buffer_map (inbuf, &input_info, GST_MAP_READ); if (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_GAP)) goto next; empty = FALSE; outdata = - GST_BUFFER_DATA (outbuf) + - width * GST_INTERLEAVE_PAD_CAST (cdata->pad)->channel; + write_info.data + width * GST_INTERLEAVE_PAD_CAST (cdata->pad)->channel; - self->func (outdata, GST_BUFFER_DATA (inbuf), self->channels, nsamples); + self->func (outdata, input_info.data, self->channels, nsamples); + gst_buffer_unmap (inbuf, &input_info); next: if (inbuf) gst_buffer_unref (inbuf); } - if (ncollected == 0) + if (ncollected == 0) { + gst_buffer_unmap (outbuf, &write_info); goto eos; + } if (self->segment_pending) { GstEvent *event; - event = gst_event_new_new_segment_full (FALSE, self->segment_rate, - 1.0, GST_FORMAT_TIME, self->timestamp, -1, self->segment_position); + self->segment.format = GST_FORMAT_TIME; + event = gst_event_new_segment (&self->segment); gst_pad_push_event (self->src, event); self->segment_pending = FALSE; @@ -1287,6 +1265,8 @@ gst_interleave_collected (GstCollectPads2 * pads, GstInterleave * self) if (empty) GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_GAP); + gst_buffer_unmap (outbuf, &write_info); + GST_LOG_OBJECT (self, "pushing outbuf, timestamp %" GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf))); ret = gst_pad_push (self->src, outbuf); diff --git a/gst/interleave/interleave.h b/gst/interleave/interleave.h index abe3439..5ce8ecd 100644 --- a/gst/interleave/interleave.h +++ b/gst/interleave/interleave.h @@ -56,8 +56,8 @@ struct _GstInterleave gint rate; gint width; - GValueArray *channel_positions; - GValueArray *input_channel_positions; + GArray* channel_positions; + GArray* input_channel_positions; gboolean channel_positions_from_input; GstCaps *sinkcaps; diff --git a/gst/interleave/plugin.c b/gst/interleave/plugin.c index 000e172..abce929 100644 --- a/gst/interleave/plugin.c +++ b/gst/interleave/plugin.c @@ -28,16 +28,16 @@ static gboolean plugin_init (GstPlugin * plugin) { -#if 0 if (!gst_element_register (plugin, "interleave", GST_RANK_NONE, gst_interleave_get_type ()) || -#endif - if (!gst_element_register (plugin, "deinterleave", - GST_RANK_NONE, gst_deinterleave_get_type ())) - return FALSE; return TRUE;} + !gst_element_register (plugin, "deinterleave", + GST_RANK_NONE, gst_deinterleave_get_type ())) + return FALSE; + return TRUE; +} - GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, - GST_VERSION_MINOR, - "interleave", - "Audio interleaver/deinterleaver", - plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN); +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, + GST_VERSION_MINOR, + "interleave", + "Audio interleaver/deinterleaver", + plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN); diff --git a/gst/interleave/plugin.h b/gst/interleave/plugin.h index abe8989..3e96a7e 100644 --- a/gst/interleave/plugin.h +++ b/gst/interleave/plugin.h @@ -25,9 +25,7 @@ #include -#if 0 #include "interleave.h" -#endif #include "deinterleave.h" #endif /* __GST_PLUGIN_INTERLEAVE_H__ */ diff --git a/tests/check/elements/interleave.c b/tests/check/elements/interleave.c index 075afcc..ed83db9 100644 --- a/tests/check/elements/interleave.c +++ b/tests/check/elements/interleave.c @@ -18,10 +18,6 @@ * Boston, MA 02111-1307, USA. */ -/* FIXME 0.11: suppress warnings for deprecated API such as GValueArray - * with newer GLib versions (>= 2.31.0) */ -#define GLIB_DISABLE_DEPRECATION_WARNINGS - #ifdef HAVE_CONFIG_H # include "config.h" #endif @@ -81,19 +77,19 @@ static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_ALWAYS, GST_STATIC_CAPS ("audio/x-raw, " "format = (string) " GST_AUDIO_NE (F32) ", " - "channels = (int) 2, " "rate = (int) 48000")); + "channels = (int) 2, layout = (string) {interleaved, non-interleaved}, rate = (int) 48000")); static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS, GST_STATIC_CAPS ("audio/x-raw, " "format = (string) " GST_AUDIO_NE (F32) ", " - "channels = (int) 1, " "rate = (int) 48000")); + "channels = (int) 1, layout = (string) interleaved, rate = (int) 48000")); #define CAPS_48khz \ "audio/x-raw, " \ "format = (string) " GST_AUDIO_NE (F32) ", " \ - "channels = (int) 1, " \ + "channels = (int) 1, layout = (string) non-interleaved," \ "rate = (int) 48000" static GstFlowReturn @@ -153,12 +149,14 @@ GST_START_TEST (test_interleave_2ch) fail_unless (mysrcpads[0] != NULL); caps = gst_caps_from_string (CAPS_48khz); + gst_pad_set_active (mysrcpads[0], TRUE); fail_unless (gst_pad_set_caps (mysrcpads[0], caps)); gst_pad_use_fixed_caps (mysrcpads[0]); mysrcpads[1] = gst_pad_new_from_static_template (&srctemplate, "src1"); fail_unless (mysrcpads[1] != NULL); + gst_pad_set_active (mysrcpads[1], TRUE); fail_unless (gst_pad_set_caps (mysrcpads[1], caps)); gst_pad_use_fixed_caps (mysrcpads[1]); @@ -281,12 +279,14 @@ GST_START_TEST (test_interleave_2ch_1eos) fail_unless (mysrcpads[0] != NULL); caps = gst_caps_from_string (CAPS_48khz); + gst_pad_set_active (mysrcpads[0], TRUE); fail_unless (gst_pad_set_caps (mysrcpads[0], caps)); gst_pad_use_fixed_caps (mysrcpads[0]); mysrcpads[1] = gst_pad_new_from_static_template (&srctemplate, "src1"); fail_unless (mysrcpads[1] != NULL); + gst_pad_set_active (mysrcpads[1], TRUE); fail_unless (gst_pad_set_caps (mysrcpads[1], caps)); gst_pad_use_fixed_caps (mysrcpads[1]); @@ -381,6 +381,34 @@ src_handoff_float32 (GstElement * element, GstBuffer * buffer, GstPad * pad, gfloat *data; gint i; gsize size; + GstCaps *caps; + guint64 mask; + GstAudioChannelPosition pos; + + switch (n) { + case 0: + case 1: + case 2: + pos = GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT; + break; + case 3: + pos = GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT; + break; + default: + pos = GST_AUDIO_CHANNEL_POSITION_INVALID; + break; + } + + mask = G_GUINT64_CONSTANT (1) << pos; + + caps = gst_caps_new_simple ("audio/x-raw", + "format", G_TYPE_STRING, GST_AUDIO_NE (F32), + "channels", G_TYPE_INT, 1, + "layout", G_TYPE_STRING, "interleaved", + "channel-mask", GST_TYPE_BITMASK, mask, "rate", G_TYPE_INT, 48000, NULL); + + gst_pad_set_caps (pad, caps); + gst_caps_unref (caps); size = 48000 * sizeof (gfloat); data = g_malloc (size); @@ -433,7 +461,8 @@ sink_handoff_float32 (GstElement * element, GstBuffer * buffer, GstPad * pad, caps = gst_caps_new_simple ("audio/x-raw", "format", G_TYPE_STRING, GST_AUDIO_NE (F32), "channels", G_TYPE_INT, 2, "rate", G_TYPE_INT, 48000, - "channel-mask", GST_TYPE_BITMASK, &mask, NULL); + "layout", G_TYPE_STRING, "interleaved", + "channel-mask", GST_TYPE_BITMASK, mask, NULL); ccaps = gst_pad_get_current_caps (pad); fail_unless (gst_caps_is_equal (caps, ccaps)); @@ -619,7 +648,7 @@ GST_START_TEST (test_interleave_2ch_pipeline_custom_chanpos) GstElement *pipeline, *queue, *src1, *src2, *interleave, *sink; GstPad *sinkpad0, *sinkpad1, *tmp, *tmp2; GstMessage *msg; - GValueArray *arr; + GArray *arr; GValue val = { 0, }; have_data = 0; @@ -650,16 +679,18 @@ GST_START_TEST (test_interleave_2ch_pipeline_custom_chanpos) interleave = gst_element_factory_make ("interleave", "interleave"); fail_unless (interleave != NULL); g_object_set (interleave, "channel-positions-from-input", FALSE, NULL); - arr = g_value_array_new (2); + arr = g_array_new (FALSE, TRUE, sizeof (GValue)); + g_value_init (&val, GST_TYPE_AUDIO_CHANNEL_POSITION); g_value_set_enum (&val, GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER); - g_value_array_append (arr, &val); + g_array_append_val (arr, val); g_value_reset (&val); g_value_set_enum (&val, GST_AUDIO_CHANNEL_POSITION_REAR_CENTER); - g_value_array_append (arr, &val); + g_array_append_val (arr, val); g_value_unset (&val); + g_object_set (interleave, "channel-positions", arr, NULL); - g_value_array_free (arr); + g_array_free (arr, TRUE); gst_bin_add (GST_BIN (pipeline), gst_object_ref (interleave)); sinkpad0 = gst_element_get_request_pad (interleave, "sink_%u"); -- 2.7.4