From 3ec9673dfcd539f57808f20460d3eabbb16b7895 Mon Sep 17 00:00:00 2001 From: Alexander Schrab Date: Thu, 25 Apr 2013 21:50:33 +0200 Subject: [PATCH] mulawdec: change base class to GstAudioDecoder https://bugzilla.gnome.org/show_bug.cgi?id=698894 --- gst/law/mulaw-decode.c | 286 +++++++------------------------- gst/law/mulaw-decode.h | 20 +-- tests/check/Makefile.am | 1 + tests/check/elements/mulawdec.c | 124 ++++++++++++++ 4 files changed, 194 insertions(+), 237 deletions(-) create mode 100644 tests/check/elements/mulawdec.c diff --git a/gst/law/mulaw-decode.c b/gst/law/mulaw-decode.c index 0ae94b6124..80c21e6ca3 100644 --- a/gst/law/mulaw-decode.c +++ b/gst/law/mulaw-decode.c @@ -33,6 +33,11 @@ extern GstStaticPadTemplate mulaw_dec_src_factory; extern GstStaticPadTemplate mulaw_dec_sink_factory; +static gboolean gst_mulawdec_set_format (GstAudioDecoder * dec, GstCaps * caps); +static GstFlowReturn gst_mulawdec_handle_frame (GstAudioDecoder * dec, + GstBuffer * buffer); + + /* Stereo signals and args */ enum { @@ -45,278 +50,109 @@ enum ARG_0 }; -static GstStateChangeReturn -gst_mulawdec_change_state (GstElement * element, GstStateChange transition); - -static gboolean gst_mulawdec_event (GstPad * pad, GstObject * parent, - GstEvent * event); -static GstFlowReturn gst_mulawdec_chain (GstPad * pad, GstObject * parent, - GstBuffer * buffer); - #define gst_mulawdec_parent_class parent_class -G_DEFINE_TYPE (GstMuLawDec, gst_mulawdec, GST_TYPE_ELEMENT); +G_DEFINE_TYPE (GstMuLawDec, gst_mulawdec, GST_TYPE_AUDIO_DECODER); static gboolean -mulawdec_setcaps (GstMuLawDec * mulawdec, GstCaps * caps) +gst_mulawdec_set_format (GstAudioDecoder * dec, GstCaps * caps) { + GstMuLawDec *mulawdec = GST_MULAWDEC (dec); GstStructure *structure; int rate, channels; - gboolean ret; - GstCaps *outcaps; GstAudioInfo info; structure = gst_caps_get_structure (caps, 0); - ret = gst_structure_get_int (structure, "rate", &rate); - ret = ret && gst_structure_get_int (structure, "channels", &channels); - if (!ret) - return FALSE; + if (!structure) { + GST_ERROR ("failed to get structure from caps"); + goto error_failed_get_structure; + } + + if (!gst_structure_get_int (structure, "rate", &rate)) { + GST_ERROR ("failed to find field rate in input caps"); + goto error_failed_find_rate; + } + + if (!gst_structure_get_int (structure, "channels", &channels)) { + GST_ERROR ("failed to find field channels in input caps"); + goto error_failed_find_channel; + } gst_audio_info_init (&info); gst_audio_info_set_format (&info, GST_AUDIO_FORMAT_S16, rate, channels, NULL); - outcaps = gst_audio_info_to_caps (&info); - ret = gst_pad_set_caps (mulawdec->srcpad, outcaps); - gst_caps_unref (outcaps); + GST_DEBUG_OBJECT (mulawdec, "rate=%d, channels=%d", rate, channels); - if (ret) { - GST_DEBUG_OBJECT (mulawdec, "rate=%d, channels=%d", rate, channels); - mulawdec->info = info; - } - return ret; + return gst_audio_decoder_set_output_format (dec, &info); + +error_failed_find_channel: +error_failed_find_rate: +error_failed_get_structure: + return FALSE; } -static GstCaps * -mulawdec_getcaps (GstPad * pad, GstCaps * filter) +static GstFlowReturn +gst_mulawdec_handle_frame (GstAudioDecoder * dec, GstBuffer * buffer) { - GstMuLawDec *mulawdec; - GstPad *otherpad; - GstCaps *othercaps, *result; - GstCaps *templ; - const gchar *name; - gint i; + GstMapInfo inmap, outmap; + gint16 *linear_data; + guint8 *mulaw_data; + gsize mulaw_size, linear_size; + GstBuffer *outbuf; - mulawdec = GST_MULAWDEC (GST_PAD_PARENT (pad)); - - /* figure out the name of the caps we are going to return */ - if (pad == mulawdec->srcpad) { - name = "audio/x-raw"; - otherpad = mulawdec->sinkpad; - } else { - name = "audio/x-mulaw"; - otherpad = mulawdec->srcpad; + if (!gst_buffer_map (buffer, &inmap, GST_MAP_READ)) { + GST_ERROR ("failed to map input buffer"); + goto error_failed_map_input_buffer; } - /* get caps from the peer, this can return NULL when there is no peer */ - othercaps = gst_pad_peer_query_caps (otherpad, NULL); - /* get the template caps to make sure we return something acceptable */ - templ = gst_pad_get_pad_template_caps (pad); + mulaw_data = inmap.data; + mulaw_size = inmap.size; - if (othercaps) { - /* there was a peer */ - othercaps = gst_caps_make_writable (othercaps); + linear_size = mulaw_size * 2; - /* go through the caps and remove the fields we don't want */ - for (i = 0; i < gst_caps_get_size (othercaps); i++) { - GstStructure *structure; - - structure = gst_caps_get_structure (othercaps, i); - - /* adjust the name */ - gst_structure_set_name (structure, name); - - if (pad == mulawdec->sinkpad) { - /* remove the fields we don't want */ - gst_structure_remove_fields (structure, "format", "layout", NULL); - } else { - /* add fixed fields */ - gst_structure_set (structure, "format", G_TYPE_STRING, - GST_AUDIO_NE (S16), "layout", G_TYPE_STRING, "interleaved", NULL); - } - } - /* filter against the allowed caps of the pad to return our result */ - result = gst_caps_intersect (othercaps, templ); - gst_caps_unref (othercaps); - gst_caps_unref (templ); - } else { - /* there was no peer, return the template caps */ - result = templ; + outbuf = gst_audio_decoder_allocate_output_buffer (dec, linear_size); + if (!gst_buffer_map (outbuf, &outmap, GST_MAP_WRITE)) { + GST_ERROR ("failed to map input buffer"); + goto error_failed_map_output_buffer; } - if (filter && result) { - GstCaps *temp; - temp = gst_caps_intersect (result, filter); - gst_caps_unref (result); - result = temp; - } - return result; -} + linear_data = (gint16 *) outmap.data; -static gboolean -gst_mulawdec_query (GstPad * pad, GstObject * parent, GstQuery * query) -{ - gboolean res; + mulaw_decode (mulaw_data, linear_data, mulaw_size); - switch (GST_QUERY_TYPE (query)) { - case GST_QUERY_CAPS: - { - GstCaps *filter, *caps; + gst_buffer_unmap (outbuf, &outmap); + gst_buffer_unmap (buffer, &inmap); - gst_query_parse_caps (query, &filter); - caps = mulawdec_getcaps (pad, filter); - gst_query_set_caps_result (query, caps); - gst_caps_unref (caps); + return gst_audio_decoder_finish_frame (dec, outbuf, -1); - res = TRUE; - break; - } - default: - res = gst_pad_query_default (pad, parent, query); - break; - } - return res; +error_failed_map_output_buffer: + gst_buffer_unref (outbuf); + +error_failed_map_input_buffer: + return FALSE; } static void gst_mulawdec_class_init (GstMuLawDecClass * klass) { GstElementClass *element_class = (GstElementClass *) klass; + GstAudioDecoderClass *audiodec_class = GST_AUDIO_DECODER_CLASS (klass); gst_element_class_add_pad_template (element_class, gst_static_pad_template_get (&mulaw_dec_src_factory)); gst_element_class_add_pad_template (element_class, gst_static_pad_template_get (&mulaw_dec_sink_factory)); + + audiodec_class->set_format = GST_DEBUG_FUNCPTR (gst_mulawdec_set_format); + audiodec_class->handle_frame = GST_DEBUG_FUNCPTR (gst_mulawdec_handle_frame); + gst_element_class_set_static_metadata (element_class, "Mu Law audio decoder", "Codec/Decoder/Audio", "Convert 8bit mu law to 16bit PCM", "Zaheer Abbas Merali "); - - element_class->change_state = GST_DEBUG_FUNCPTR (gst_mulawdec_change_state); } static void gst_mulawdec_init (GstMuLawDec * mulawdec) { - mulawdec->sinkpad = - gst_pad_new_from_static_template (&mulaw_dec_sink_factory, "sink"); - gst_pad_set_query_function (mulawdec->sinkpad, gst_mulawdec_query); - gst_pad_set_event_function (mulawdec->sinkpad, gst_mulawdec_event); - gst_pad_set_chain_function (mulawdec->sinkpad, gst_mulawdec_chain); - gst_element_add_pad (GST_ELEMENT (mulawdec), mulawdec->sinkpad); - - mulawdec->srcpad = - gst_pad_new_from_static_template (&mulaw_dec_src_factory, "src"); - gst_pad_set_query_function (mulawdec->srcpad, gst_mulawdec_query); - gst_element_add_pad (GST_ELEMENT (mulawdec), mulawdec->srcpad); -} - -static gboolean -gst_mulawdec_event (GstPad * pad, GstObject * parent, GstEvent * event) -{ - GstMuLawDec *mulawdec; - gboolean res; - - mulawdec = GST_MULAWDEC (parent); - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_CAPS: - { - GstCaps *caps; - - gst_event_parse_caps (event, &caps); - mulawdec_setcaps (mulawdec, caps); - gst_event_unref (event); - - res = TRUE; - break; - } - default: - res = gst_pad_event_default (pad, parent, event); - break; - } - return res; -} - -static GstFlowReturn -gst_mulawdec_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer) -{ - GstMuLawDec *mulawdec; - GstMapInfo inmap, outmap; - gint16 *linear_data; - guint8 *mulaw_data; - gsize mulaw_size, linear_size; - GstBuffer *outbuf; - GstFlowReturn ret; - - mulawdec = GST_MULAWDEC (parent); - - if (G_UNLIKELY (!GST_AUDIO_INFO_IS_VALID (&mulawdec->info))) - goto not_negotiated; - - gst_buffer_map (buffer, &inmap, GST_MAP_READ); - mulaw_data = inmap.data; - mulaw_size = inmap.size; - - linear_size = mulaw_size * 2; - - outbuf = gst_buffer_new_allocate (NULL, linear_size, NULL); - gst_buffer_map (outbuf, &outmap, GST_MAP_WRITE); - linear_data = (gint16 *) outmap.data; - - /* copy discont flag */ - if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT)) - GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT); - - GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buffer); - if (GST_BUFFER_DURATION_IS_VALID (buffer)) { - GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (buffer); - } else { - GST_BUFFER_DURATION (outbuf) = gst_util_uint64_scale_int (GST_SECOND, - linear_size, GST_AUDIO_INFO_RATE (&mulawdec->info) * - GST_AUDIO_INFO_BPF (&mulawdec->info)); - } - - mulaw_decode (mulaw_data, linear_data, mulaw_size); - - gst_buffer_unmap (outbuf, &outmap); - gst_buffer_unmap (buffer, &inmap); - gst_buffer_unref (buffer); - - ret = gst_pad_push (mulawdec->srcpad, outbuf); - - return ret; - - /* ERRORS */ -not_negotiated: - { - GST_WARNING_OBJECT (mulawdec, "no input format set: not-negotiated"); - gst_buffer_unref (buffer); - return GST_FLOW_NOT_NEGOTIATED; - } -} - -static GstStateChangeReturn -gst_mulawdec_change_state (GstElement * element, GstStateChange transition) -{ - GstStateChangeReturn ret; - GstMuLawDec *dec = GST_MULAWDEC (element); - - switch (transition) { - default: - break; - } - - ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); - if (ret != GST_STATE_CHANGE_SUCCESS) - return ret; - - switch (transition) { - case GST_STATE_CHANGE_PAUSED_TO_READY: - gst_audio_info_init (&dec->info); - break; - default: - break; - } - - return ret; } diff --git a/gst/law/mulaw-decode.h b/gst/law/mulaw-decode.h index ff18f9e6bc..bed62fa097 100644 --- a/gst/law/mulaw-decode.h +++ b/gst/law/mulaw-decode.h @@ -22,9 +22,9 @@ #include #include +#include G_BEGIN_DECLS - #define GST_TYPE_MULAWDEC \ (gst_mulawdec_get_type()) #define GST_MULAWDEC(obj) \ @@ -35,24 +35,20 @@ G_BEGIN_DECLS (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_MULAWDEC)) #define GST_IS_MULAWDEC_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_MULAWDEC)) - typedef struct _GstMuLawDec GstMuLawDec; typedef struct _GstMuLawDecClass GstMuLawDecClass; -struct _GstMuLawDec { - GstElement element; - - GstPad *sinkpad,*srcpad; - - GstAudioInfo info; +struct _GstMuLawDec +{ + GstAudioDecoder element; }; -struct _GstMuLawDecClass { - GstElementClass parent_class; +struct _GstMuLawDecClass +{ + GstAudioDecoderClass parent_class; }; -GType gst_mulawdec_get_type(void); +GType gst_mulawdec_get_type (void); G_END_DECLS - #endif /* __GST_STEREO_H__ */ diff --git a/tests/check/Makefile.am b/tests/check/Makefile.am index 8f1e811043..a3a0ca0c4d 100644 --- a/tests/check/Makefile.am +++ b/tests/check/Makefile.am @@ -134,6 +134,7 @@ check_PROGRAMS = \ elements/matroskamux \ elements/matroskaparse \ elements/mpegaudioparse \ + elements/mulawdec \ elements/mulawenc \ elements/multifile \ elements/qtmux \ diff --git a/tests/check/elements/mulawdec.c b/tests/check/elements/mulawdec.c new file mode 100644 index 0000000000..e9a01c2e4c --- /dev/null +++ b/tests/check/elements/mulawdec.c @@ -0,0 +1,124 @@ +/* GStreamer MulawDec unit tests + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +static GstPad *mysrcpad, *mysinkpad; +static GstElement *mulawdec = NULL; + +static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("audio/x-raw," + "format = (string) S16LE, " + "rate = (int) 8000, " + "channels = (int) 1, " "layout = (string)interleaved") + ); + +static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("audio/x-mulaw," "rate = (int) 8000," "channels = (int) 1") + ); + +static void +mulawdec_setup (void) +{ + GstCaps *src_caps; + + src_caps = + gst_caps_from_string ("audio/x-mulaw," "rate = (int) 8000," + "channels = (int) 1"); + + GST_DEBUG ("%s", __FUNCTION__); + + mulawdec = gst_check_setup_element ("mulawdec"); + + mysrcpad = gst_check_setup_src_pad (mulawdec, &srctemplate); + mysinkpad = gst_check_setup_sink_pad (mulawdec, &sinktemplate); + + gst_pad_set_active (mysrcpad, TRUE); + gst_pad_set_active (mysinkpad, TRUE); + + gst_pad_set_caps (mysrcpad, src_caps); + gst_caps_unref (src_caps); +} + +static void +buffer_unref (void *buffer, void *user_data) +{ + gst_buffer_unref (GST_BUFFER (buffer)); +} + +static void +mulawdec_teardown (void) +{ + /* free decoded buffers */ + g_list_foreach (buffers, buffer_unref, NULL); + g_list_free (buffers); + buffers = NULL; + + gst_pad_set_active (mysrcpad, FALSE); + gst_pad_set_active (mysinkpad, FALSE); + gst_check_teardown_src_pad (mulawdec); + gst_check_teardown_sink_pad (mulawdec); + gst_check_teardown_element (mulawdec); + mulawdec = NULL; +} + +GST_START_TEST (test_one_buffer) +{ + GstBuffer *buffer; + gint buf_size = 4096; + guint8 *dp; + + fail_unless (gst_element_set_state (mulawdec, GST_STATE_PLAYING) == + GST_STATE_CHANGE_SUCCESS, "could not change state to playing"); + + buffer = gst_buffer_new (); + dp = g_malloc0 (buf_size); + gst_buffer_append_memory (buffer, + gst_memory_new_wrapped (0, dp, buf_size, 0, buf_size, dp, g_free)); + ASSERT_BUFFER_REFCOUNT (buffer, "buffer", 1); + + fail_unless (gst_pad_push (mysrcpad, buffer) == GST_FLOW_OK); + + fail_unless (g_list_length (buffers) == 1); + fail_unless (gst_buffer_get_size (GST_BUFFER (g_list_first (buffers)->data))); +} + +GST_END_TEST; + +static Suite * +mulawdec_suite (void) +{ + Suite *s = suite_create ("mulawdec"); + TCase *tc_chain = tcase_create ("mulawdec"); + + tcase_add_checked_fixture (tc_chain, mulawdec_setup, mulawdec_teardown); + + suite_add_tcase (s, tc_chain); + tcase_add_test (tc_chain, test_one_buffer); + return s; +} + +GST_CHECK_MAIN (mulawdec)