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);
101 }
103 static void
104 gst_amrnbdec_class_init (GstAmrnbDecClass * klass)
105 {
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;
111 }
113 static void
114 gst_amrnbdec_init (GstAmrnbDec * amrnbdec)
115 {
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;
136 }
138 static gboolean
139 gst_amrnbdec_setcaps (GstPad * pad, GstCaps * caps)
140 {
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;
170 }
172 static gboolean
173 gst_amrnbdec_event (GstPad * pad, GstEvent * event)
174 {
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;
200 }
202 static GstFlowReturn
203 gst_amrnbdec_chain (GstPad * pad, GstBuffer * buffer)
204 {
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 }
276 }
278 static GstStateChangeReturn
279 gst_amrnbdec_state_change (GstElement * element, GstStateChange transition)
280 {
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 }
320 }