add test for amrnbenc, enable test infrastructure, and fix a leak
[glsdk/gst-plugins-ugly0-10.git] / ext / amrnb / amrnbdec.c
1 /* GStreamer Adaptive Multi-Rate Narrow-Band (AMR-NB) plugin
2  * Copyright (C) 2004 Ronald Bultje <rbultje@ronald.bitfreak.net>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
24 #include "amrnbdec.h"
26 static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
27     GST_PAD_SINK,
28     GST_PAD_ALWAYS,
29     GST_STATIC_CAPS ("audio/AMR, " "rate = (int) 8000, " "channels = (int) 1")
30     );
32 static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
33     GST_PAD_SRC,
34     GST_PAD_ALWAYS,
35     GST_STATIC_CAPS ("audio/x-raw-int, "
36         "width = (int) 16, "
37         "depth = (int) 16, "
38         "signed = (boolean) TRUE, "
39         "endianness = (int) BYTE_ORDER, "
40         "rate = (int) 8000," "channels = (int) 1")
41     );
43 static const gint block_size[16] = { 12, 13, 15, 17, 19, 20, 26, 31, 5,
44   -1, -1, -1, -1, -1, -1, 0
45 };
47 static void gst_amrnbdec_base_init (GstAmrnbDecClass * klass);
48 static void gst_amrnbdec_class_init (GstAmrnbDecClass * klass);
49 static void gst_amrnbdec_init (GstAmrnbDec * amrnbdec);
51 static gboolean gst_amrnbdec_event (GstPad * pad, GstEvent * event);
52 static GstFlowReturn gst_amrnbdec_chain (GstPad * pad, GstBuffer * buffer);
53 static gboolean gst_amrnbdec_setcaps (GstPad * pad, GstCaps * caps);
54 static GstStateChangeReturn gst_amrnbdec_state_change (GstElement * element,
55     GstStateChange transition);
57 static GstElementClass *parent_class = NULL;
59 GType
60 gst_amrnbdec_get_type (void)
61 {
62   static GType amrnbdec_type = 0;
64   if (!amrnbdec_type) {
65     static const GTypeInfo amrnbdec_info = {
66       sizeof (GstAmrnbDecClass),
67       (GBaseInitFunc) gst_amrnbdec_base_init,
68       NULL,
69       (GClassInitFunc) gst_amrnbdec_class_init,
70       NULL,
71       NULL,
72       sizeof (GstAmrnbDec),
73       0,
74       (GInstanceInitFunc) gst_amrnbdec_init,
75     };
77     amrnbdec_type = g_type_register_static (GST_TYPE_ELEMENT,
78         "GstAmrnbDec", &amrnbdec_info, 0);
79   }
81   return amrnbdec_type;
82 }
84 static void
85 gst_amrnbdec_base_init (GstAmrnbDecClass * klass)
86 {
87   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
88   GstElementDetails gst_amrnbdec_details = {
89     "AMR-NB decoder",
90     "Codec/Decoder/Audio",
91     "Adaptive Multi-Rate Narrow-Band audio decoder",
92     "Ronald Bultje <rbultje@ronald.bitfreak.net>"
93   };
95   gst_element_class_add_pad_template (element_class,
96       gst_static_pad_template_get (&sink_template));
97   gst_element_class_add_pad_template (element_class,
98       gst_static_pad_template_get (&src_template));
100   gst_element_class_set_details (element_class, &gst_amrnbdec_details);
103 static void
104 gst_amrnbdec_class_init (GstAmrnbDecClass * klass)
106   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
108   parent_class = g_type_class_peek_parent (klass);
110   element_class->change_state = gst_amrnbdec_state_change;
113 static void
114 gst_amrnbdec_init (GstAmrnbDec * amrnbdec)
116   /* create the sink pad */
117   amrnbdec->sinkpad =
118       gst_pad_new_from_template (gst_static_pad_template_get (&sink_template),
119       "sink");
120   gst_pad_set_setcaps_function (amrnbdec->sinkpad, gst_amrnbdec_setcaps);
121   gst_pad_set_event_function (amrnbdec->sinkpad, gst_amrnbdec_event);
122   gst_pad_set_chain_function (amrnbdec->sinkpad, gst_amrnbdec_chain);
123   gst_element_add_pad (GST_ELEMENT (amrnbdec), amrnbdec->sinkpad);
125   /* create the src pad */
126   amrnbdec->srcpad =
127       gst_pad_new_from_template (gst_static_pad_template_get (&src_template),
128       "src");
129   gst_pad_use_fixed_caps (amrnbdec->srcpad);
130   gst_element_add_pad (GST_ELEMENT (amrnbdec), amrnbdec->srcpad);
132   amrnbdec->adapter = gst_adapter_new ();
134   /* init rest */
135   amrnbdec->handle = NULL;
138 static gboolean
139 gst_amrnbdec_setcaps (GstPad * pad, GstCaps * caps)
141   GstStructure *structure;
142   GstAmrnbDec *amrnbdec;
143   GstCaps *copy;
145   amrnbdec = GST_AMRNBDEC (gst_pad_get_parent (pad));
147   structure = gst_caps_get_structure (caps, 0);
149   /* get channel count */
150   gst_structure_get_int (structure, "channels", &amrnbdec->channels);
151   gst_structure_get_int (structure, "rate", &amrnbdec->rate);
153   /* create reverse caps */
154   copy = gst_caps_new_simple ("audio/x-raw-int",
155       "channels", G_TYPE_INT, amrnbdec->channels,
156       "width", G_TYPE_INT, 16,
157       "depth", G_TYPE_INT, 16,
158       "endianness", G_TYPE_INT, G_BYTE_ORDER,
159       "rate", G_TYPE_INT, amrnbdec->rate, "signed", G_TYPE_BOOLEAN, TRUE, NULL);
161   amrnbdec->duration = gst_util_uint64_scale_int (GST_SECOND, 160,
162       amrnbdec->rate * amrnbdec->channels);
164   gst_pad_set_caps (amrnbdec->srcpad, copy);
165   gst_caps_unref (copy);
167   gst_object_unref (amrnbdec);
169   return TRUE;
172 static gboolean
173 gst_amrnbdec_event (GstPad * pad, GstEvent * event)
175   GstAmrnbDec *amrnbdec;
176   gboolean ret = TRUE;
178   amrnbdec = GST_AMRNBDEC (gst_pad_get_parent (pad));
180   switch (GST_EVENT_TYPE (event)) {
181     case GST_EVENT_FLUSH_START:
182       ret = gst_pad_push_event (amrnbdec->srcpad, event);
183       break;
184     case GST_EVENT_FLUSH_STOP:
185       ret = gst_pad_push_event (amrnbdec->srcpad, event);
186       gst_adapter_clear (amrnbdec->adapter);
187       amrnbdec->ts = -1;
188       break;
189     case GST_EVENT_EOS:
190       gst_adapter_clear (amrnbdec->adapter);
191       ret = gst_pad_push_event (amrnbdec->srcpad, event);
192       break;
193     default:
194       ret = gst_pad_push_event (amrnbdec->srcpad, event);
195       break;
196   }
197   gst_object_unref (amrnbdec);
199   return ret;
202 static GstFlowReturn
203 gst_amrnbdec_chain (GstPad * pad, GstBuffer * buffer)
205   GstAmrnbDec *amrnbdec;
206   GstFlowReturn ret;
208   amrnbdec = GST_AMRNBDEC (gst_pad_get_parent (pad));
210   if (amrnbdec->rate == 0 || amrnbdec->channels == 0)
211     goto not_negotiated;
213   /* discontinuity, don't combine samples before and after the
214    * DISCONT */
215   if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT)) {
216     gst_adapter_clear (amrnbdec->adapter);
217     amrnbdec->ts = -1;
218   }
220   /* take latest timestamp, FIXME timestamp is the one of the
221    * first buffer in the adapter. */
222   if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer))
223     amrnbdec->ts = GST_BUFFER_TIMESTAMP (buffer);
225   gst_adapter_push (amrnbdec->adapter, buffer);
227   ret = GST_FLOW_OK;
229   while (TRUE) {
230     GstBuffer *out;
231     guint8 *data;
232     gint block, mode;
234     if (gst_adapter_available (amrnbdec->adapter) < 1)
235       break;
236     data = (guint8 *) gst_adapter_peek (amrnbdec->adapter, 1);
238     /* get size */
239     mode = (data[0] >> 3) & 0x0F;
240     block = block_size[mode] + 1;
242     if (gst_adapter_available (amrnbdec->adapter) < block)
243       break;
244     /* the library seems to write into the source data, hence
245      * the copy. */
246     data = gst_adapter_take (amrnbdec->adapter, block);
248     /* get output */
249     out = gst_buffer_new_and_alloc (160 * 2);
250     GST_BUFFER_DURATION (out) = amrnbdec->duration;
251     GST_BUFFER_TIMESTAMP (out) = amrnbdec->ts;
252     if (amrnbdec->ts != -1)
253       amrnbdec->ts += amrnbdec->duration;
254     gst_buffer_set_caps (out, GST_PAD_CAPS (amrnbdec->srcpad));
256     /* decode */
257     Decoder_Interface_Decode (amrnbdec->handle, data,
258         (short *) GST_BUFFER_DATA (out), 0);
259     g_free (data);
261     /* play */
262     ret = gst_pad_push (amrnbdec->srcpad, out);
263   }
264   gst_object_unref (amrnbdec);
266   return ret;
268   /* ERRORS */
269 not_negotiated:
270   {
271     GST_ELEMENT_ERROR (amrnbdec, STREAM, TYPE_NOT_FOUND, (NULL),
272         ("Decoder is not initialized"));
273     gst_object_unref (amrnbdec);
274     return GST_FLOW_NOT_NEGOTIATED;
275   }
278 static GstStateChangeReturn
279 gst_amrnbdec_state_change (GstElement * element, GstStateChange transition)
281   GstAmrnbDec *amrnbdec;
282   GstStateChangeReturn ret;
284   amrnbdec = GST_AMRNBDEC (element);
286   switch (transition) {
287     case GST_STATE_CHANGE_NULL_TO_READY:
288       if (!(amrnbdec->handle = Decoder_Interface_init ()))
289         goto init_failed;
290       break;
291     case GST_STATE_CHANGE_READY_TO_PAUSED:
292       gst_adapter_clear (amrnbdec->adapter);
293       amrnbdec->rate = 0;
294       amrnbdec->channels = 0;
295       amrnbdec->ts = -1;
296       break;
297     default:
298       break;
299   }
301   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
303   switch (transition) {
304     case GST_STATE_CHANGE_READY_TO_NULL:
305       Decoder_Interface_exit (amrnbdec->handle);
306       break;
307     default:
308       break;
309   }
311   return ret;
313   /* ERRORS */
314 init_failed:
315   {
316     GST_ELEMENT_ERROR (amrnbdec, LIBRARY, INIT, (NULL),
317         ("Failed to open AMR Decoder"));
318     return GST_STATE_CHANGE_FAILURE;
319   }