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/x-amr-nb, "
30 "rate = (int) 8000, " "channels = (int) 1")
31 );
33 static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
34 GST_PAD_SRC,
35 GST_PAD_ALWAYS,
36 GST_STATIC_CAPS ("audio/x-raw-int, "
37 "width = (int) 16, "
38 "depth = (int) 16, "
39 "signed = (boolean) TRUE, "
40 "endianness = (int) BYTE_ORDER, "
41 "rate = (int) 8000," "channels = (int) 1")
42 );
44 static const gint block_size[16] = { 12, 13, 15, 17, 19, 20, 26, 31, 5,
45 0, 0, 0, 0, 0, 0, 0
46 };
48 static void gst_amrnbdec_base_init (GstAmrnbDecClass * klass);
49 static void gst_amrnbdec_class_init (GstAmrnbDecClass * klass);
50 static void gst_amrnbdec_init (GstAmrnbDec * amrnbdec);
52 static GstFlowReturn gst_amrnbdec_chain (GstPad * pad, GstBuffer * buffer);
53 static gboolean gst_amrnbdec_setcaps (GstPad * pad, GstCaps * caps);
54 static GstElementStateReturn gst_amrnbdec_state_change (GstElement * element);
56 static GstElementClass *parent_class = NULL;
58 GType
59 gst_amrnbdec_get_type (void)
60 {
61 static GType amrnbdec_type = 0;
63 if (!amrnbdec_type) {
64 static const GTypeInfo amrnbdec_info = {
65 sizeof (GstAmrnbDecClass),
66 (GBaseInitFunc) gst_amrnbdec_base_init,
67 NULL,
68 (GClassInitFunc) gst_amrnbdec_class_init,
69 NULL,
70 NULL,
71 sizeof (GstAmrnbDec),
72 0,
73 (GInstanceInitFunc) gst_amrnbdec_init,
74 };
76 amrnbdec_type = g_type_register_static (GST_TYPE_ELEMENT,
77 "GstAmrnbDec", &amrnbdec_info, 0);
78 }
80 return amrnbdec_type;
81 }
83 static void
84 gst_amrnbdec_base_init (GstAmrnbDecClass * klass)
85 {
86 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
87 GstElementDetails gst_amrnbdec_details = {
88 "AMR-NB decoder",
89 "Codec/Decoder/Audio",
90 "Adaptive Multi-Rate Narrow-Band audio decoder",
91 "Ronald Bultje <rbultje@ronald.bitfreak.net>"
92 };
94 gst_element_class_add_pad_template (element_class,
95 gst_static_pad_template_get (&sink_template));
96 gst_element_class_add_pad_template (element_class,
97 gst_static_pad_template_get (&src_template));
99 gst_element_class_set_details (element_class, &gst_amrnbdec_details);
100 }
102 static void
103 gst_amrnbdec_class_init (GstAmrnbDecClass * klass)
104 {
105 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
107 parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
109 element_class->change_state = gst_amrnbdec_state_change;
110 }
112 static void
113 gst_amrnbdec_init (GstAmrnbDec * amrnbdec)
114 {
115 /* create the sink pad */
116 amrnbdec->sinkpad =
117 gst_pad_new_from_template (gst_static_pad_template_get (&sink_template),
118 "sink");
119 gst_pad_set_setcaps_function (amrnbdec->sinkpad, gst_amrnbdec_setcaps);
120 gst_pad_set_chain_function (amrnbdec->sinkpad, gst_amrnbdec_chain);
121 gst_element_add_pad (GST_ELEMENT (amrnbdec), amrnbdec->sinkpad);
123 /* create the src pad */
124 amrnbdec->srcpad =
125 gst_pad_new_from_template (gst_static_pad_template_get (&src_template),
126 "src");
127 gst_pad_use_fixed_caps (amrnbdec->srcpad);
128 gst_element_add_pad (GST_ELEMENT (amrnbdec), amrnbdec->srcpad);
130 amrnbdec->adapter = gst_adapter_new ();
132 /* init rest */
133 amrnbdec->handle = NULL;
134 amrnbdec->channels = 0;
135 amrnbdec->rate = 0;
136 amrnbdec->ts = 0;
137 }
139 static gboolean
140 gst_amrnbdec_setcaps (GstPad * pad, GstCaps * caps)
141 {
142 GstStructure *structure;
143 GstAmrnbDec *amrnbdec;
144 GstCaps *copy;
146 amrnbdec = GST_AMRNBDEC (GST_PAD_PARENT (pad));
148 structure = gst_caps_get_structure (caps, 0);
150 /* get channel count */
151 gst_structure_get_int (structure, "channels", &amrnbdec->channels);
152 gst_structure_get_int (structure, "rate", &amrnbdec->rate);
154 /* create reverse caps */
155 copy = gst_caps_new_simple ("audio/x-raw-int",
156 "channels", G_TYPE_INT, amrnbdec->channels,
157 "width", G_TYPE_INT, 16,
158 "depth", G_TYPE_INT, 16,
159 "endianness", G_TYPE_INT, G_BYTE_ORDER,
160 "rate", G_TYPE_INT, amrnbdec->rate, "signed", G_TYPE_BOOLEAN, TRUE, NULL);
162 gst_pad_set_caps (amrnbdec->srcpad, copy);
163 gst_caps_unref (copy);
165 return TRUE;
166 }
168 static GstFlowReturn
169 gst_amrnbdec_chain (GstPad * pad, GstBuffer * buffer)
170 {
171 GstAmrnbDec *amrnbdec;
172 GstFlowReturn ret;
174 amrnbdec = GST_AMRNBDEC (GST_PAD_PARENT (pad));
176 if (amrnbdec->rate == 0 || amrnbdec->channels == 0)
177 goto not_negotiated;
179 if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer))
180 amrnbdec->ts = GST_BUFFER_TIMESTAMP (buffer);
182 gst_adapter_push (amrnbdec->adapter, buffer);
184 ret = GST_FLOW_OK;
186 while (TRUE) {
187 GstBuffer *out;
188 guint8 *data;
189 gint block, mode;
191 if (gst_adapter_available (amrnbdec->adapter) < 1)
192 break;
193 data = (guint8 *) gst_adapter_peek (amrnbdec->adapter, 1);
195 /* get size */
196 mode = (data[0] >> 3) & 0x0F;
197 block = block_size[mode] + 1;
199 if (gst_adapter_available (amrnbdec->adapter) < block)
200 break;
201 data = (guint8 *) gst_adapter_peek (amrnbdec->adapter, block);
203 /* get output */
204 out = gst_buffer_new_and_alloc (160 * 2);
205 GST_BUFFER_DURATION (out) = GST_SECOND * 160 /
206 (amrnbdec->rate * amrnbdec->channels);
207 GST_BUFFER_TIMESTAMP (out) = amrnbdec->ts;
208 amrnbdec->ts += GST_BUFFER_DURATION (out);
209 gst_buffer_set_caps (out, GST_RPAD_CAPS (amrnbdec->srcpad));
211 /* decode */
212 Decoder_Interface_Decode (amrnbdec->handle, data,
213 (short *) GST_BUFFER_DATA (out), 0);
215 gst_adapter_flush (amrnbdec->adapter, block);
217 /* play */
218 ret = gst_pad_push (amrnbdec->srcpad, out);
219 }
221 return ret;
223 not_negotiated:
224 {
225 return GST_FLOW_NOT_NEGOTIATED;
226 }
227 }
229 static GstElementStateReturn
230 gst_amrnbdec_state_change (GstElement * element)
231 {
232 GstAmrnbDec *amrnbdec;
233 GstElementStateReturn ret;
234 gint transition;
236 amrnbdec = GST_AMRNBDEC (element);
237 transition = GST_STATE_TRANSITION (element);
239 switch (transition) {
240 case GST_STATE_NULL_TO_READY:
241 if (!(amrnbdec->handle = Decoder_Interface_init ()))
242 return GST_STATE_FAILURE;
243 break;
244 case GST_STATE_READY_TO_PAUSED:
245 gst_adapter_clear (amrnbdec->adapter);
246 amrnbdec->ts = 0;
247 break;
248 default:
249 break;
250 }
252 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element);
254 switch (transition) {
255 case GST_STATE_READY_TO_NULL:
256 Decoder_Interface_exit (amrnbdec->handle);
257 break;
258 default:
259 break;
260 }
262 return ret;
263 }