f25fdfe87d764f63811c3e70c8925da6c62db859
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 "amrnbenc.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-raw-int, "
30 "width = (int) 16, "
31 "depth = (int) 16, "
32 "signed = (boolean) TRUE, "
33 "endianness = (int) BYTE_ORDER, "
34 "rate = (int) 8000," "channels = (int) 1")
35 );
37 static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
38 GST_PAD_SRC,
39 GST_PAD_ALWAYS,
40 GST_STATIC_CAPS ("audio/AMR, " "rate = (int) 8000, " "channels = (int) 1")
41 );
43 static void gst_amrnbenc_base_init (GstAmrnbEncClass * klass);
44 static void gst_amrnbenc_class_init (GstAmrnbEncClass * klass);
45 static void gst_amrnbenc_init (GstAmrnbEnc * amrnbenc);
46 static void gst_amrnbenc_finalize (GObject * object);
48 static GstFlowReturn gst_amrnbenc_chain (GstPad * pad, GstBuffer * buffer);
49 static gboolean gst_amrnbenc_setcaps (GstPad * pad, GstCaps * caps);
50 static GstStateChangeReturn gst_amrnbenc_state_change (GstElement * element,
51 GstStateChange transition);
53 static GstElementClass *parent_class = NULL;
55 GType
56 gst_amrnbenc_get_type (void)
57 {
58 static GType amrnbenc_type = 0;
60 if (!amrnbenc_type) {
61 static const GTypeInfo amrnbenc_info = {
62 sizeof (GstAmrnbEncClass),
63 (GBaseInitFunc) gst_amrnbenc_base_init,
64 NULL,
65 (GClassInitFunc) gst_amrnbenc_class_init,
66 NULL,
67 NULL,
68 sizeof (GstAmrnbEnc),
69 0,
70 (GInstanceInitFunc) gst_amrnbenc_init,
71 };
73 amrnbenc_type = g_type_register_static (GST_TYPE_ELEMENT,
74 "GstAmrnbEnc", &amrnbenc_info, 0);
75 }
77 return amrnbenc_type;
78 }
80 static void
81 gst_amrnbenc_base_init (GstAmrnbEncClass * klass)
82 {
83 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
84 GstElementDetails gst_amrnbenc_details = {
85 "AMR-NB encoder",
86 "Codec/Encoder/Audio",
87 "Adaptive Multi-Rate Narrow-Band audio encoder",
88 "Ronald Bultje <rbultje@ronald.bitfreak.net>, "
89 "Wim Taymans <wim@fluendo.com>"
90 };
92 gst_element_class_add_pad_template (element_class,
93 gst_static_pad_template_get (&sink_template));
94 gst_element_class_add_pad_template (element_class,
95 gst_static_pad_template_get (&src_template));
97 gst_element_class_set_details (element_class, &gst_amrnbenc_details);
98 }
100 static void
101 gst_amrnbenc_class_init (GstAmrnbEncClass * klass)
102 {
103 GObjectClass *object_class = G_OBJECT_CLASS (klass);
104 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
106 parent_class = g_type_class_peek_parent (klass);
108 object_class->finalize = gst_amrnbenc_finalize;
110 element_class->change_state = gst_amrnbenc_state_change;
111 }
113 static void
114 gst_amrnbenc_init (GstAmrnbEnc * amrnbenc)
115 {
116 /* create the sink pad */
117 amrnbenc->sinkpad =
118 gst_pad_new_from_template (gst_static_pad_template_get (&sink_template),
119 "sink");
120 gst_pad_set_setcaps_function (amrnbenc->sinkpad, gst_amrnbenc_setcaps);
121 gst_pad_set_chain_function (amrnbenc->sinkpad, gst_amrnbenc_chain);
122 gst_element_add_pad (GST_ELEMENT (amrnbenc), amrnbenc->sinkpad);
124 /* create the src pad */
125 amrnbenc->srcpad =
126 gst_pad_new_from_template (gst_static_pad_template_get (&src_template),
127 "src");
128 gst_pad_use_fixed_caps (amrnbenc->srcpad);
129 gst_element_add_pad (GST_ELEMENT (amrnbenc), amrnbenc->srcpad);
131 amrnbenc->adapter = gst_adapter_new ();
133 /* init rest */
134 amrnbenc->handle = NULL;
135 }
137 static void
138 gst_amrnbenc_finalize (GObject * object)
139 {
140 GstAmrnbEnc *amrnbenc;
142 amrnbenc = GST_AMRNBENC (object);
144 g_object_unref (G_OBJECT (amrnbenc->adapter));
145 amrnbenc->adapter = NULL;
147 G_OBJECT_CLASS (parent_class)->finalize (object);
148 }
150 static gboolean
151 gst_amrnbenc_setcaps (GstPad * pad, GstCaps * caps)
152 {
153 GstStructure *structure;
154 GstAmrnbEnc *amrnbenc;
155 GstCaps *copy;
157 amrnbenc = GST_AMRNBENC (GST_PAD_PARENT (pad));
159 structure = gst_caps_get_structure (caps, 0);
161 /* get channel count */
162 gst_structure_get_int (structure, "channels", &amrnbenc->channels);
163 gst_structure_get_int (structure, "rate", &amrnbenc->rate);
165 /* this is not wrong but will sound bad */
166 if (amrnbenc->channels != 1) {
167 g_warning ("amrnbdec is only optimized for mono channels");
168 }
169 if (amrnbenc->rate != 8000) {
170 g_warning ("amrnbdec is only optimized for 8000 Hz samplerate");
171 }
173 /* create reverse caps */
174 copy = gst_caps_new_simple ("audio/AMR",
175 "channels", G_TYPE_INT, amrnbenc->channels,
176 "rate", G_TYPE_INT, amrnbenc->rate, NULL);
178 /* precalc duration as it's constant now */
179 amrnbenc->duration = gst_util_uint64_scale_int (160, GST_SECOND,
180 amrnbenc->rate * amrnbenc->channels);
182 gst_pad_set_caps (amrnbenc->srcpad, copy);
183 gst_caps_unref (copy);
185 return TRUE;
186 }
188 static GstFlowReturn
189 gst_amrnbenc_chain (GstPad * pad, GstBuffer * buffer)
190 {
191 GstAmrnbEnc *amrnbenc;
192 GstFlowReturn ret;
194 amrnbenc = GST_AMRNBENC (GST_PAD_PARENT (pad));
196 g_return_val_if_fail (amrnbenc->handle, GST_FLOW_WRONG_STATE);
198 if (amrnbenc->rate == 0 || amrnbenc->channels == 0)
199 goto not_negotiated;
201 /* discontinuity clears adapter, FIXME, maybe we can set some
202 * encoder flag to mask the discont. */
203 if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT)) {
204 gst_adapter_clear (amrnbenc->adapter);
205 amrnbenc->ts = 0;
206 }
208 /* take latest timestamp, FIXME timestamp is the one of the
209 * first buffer in the adapter. */
210 if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer))
211 amrnbenc->ts = GST_BUFFER_TIMESTAMP (buffer);
213 ret = GST_FLOW_OK;
214 gst_adapter_push (amrnbenc->adapter, buffer);
216 /* Collect samples until we have enough for an output frame */
217 while (gst_adapter_available (amrnbenc->adapter) >= 320) {
218 GstBuffer *out;
219 guint8 *data;
220 gint outsize;
222 /* get output, max size is 32 */
223 out = gst_buffer_new_and_alloc (32);
224 GST_BUFFER_DURATION (out) = amrnbenc->duration;
225 GST_BUFFER_TIMESTAMP (out) = amrnbenc->ts;
226 if (amrnbenc->ts != -1)
227 amrnbenc->ts += amrnbenc->duration;
228 gst_buffer_set_caps (out, GST_PAD_CAPS (amrnbenc->srcpad));
230 /* The AMR encoder actually writes into the source data buffers it gets */
231 data = gst_adapter_take (amrnbenc->adapter, 320);
233 /* encode */
234 outsize = Encoder_Interface_Encode (amrnbenc->handle, MR122, (short *) data,
235 (guint8 *) GST_BUFFER_DATA (out), 0);
237 g_free (data);
239 GST_BUFFER_SIZE (out) = outsize;
241 /* play */
242 if ((ret = gst_pad_push (amrnbenc->srcpad, out)) != GST_FLOW_OK)
243 break;
244 }
245 return ret;
247 /* ERRORS */
248 not_negotiated:
249 {
250 GST_ELEMENT_ERROR (amrnbenc, STREAM, TYPE_NOT_FOUND,
251 (NULL), ("unknown type"));
252 return GST_FLOW_NOT_NEGOTIATED;
253 }
254 }
256 static GstStateChangeReturn
257 gst_amrnbenc_state_change (GstElement * element, GstStateChange transition)
258 {
259 GstAmrnbEnc *amrnbenc;
260 GstStateChangeReturn ret;
262 amrnbenc = GST_AMRNBENC (element);
264 switch (transition) {
265 case GST_STATE_CHANGE_NULL_TO_READY:
266 if (!(amrnbenc->handle = Encoder_Interface_init (0)))
267 return GST_STATE_CHANGE_FAILURE;
268 break;
269 case GST_STATE_CHANGE_READY_TO_PAUSED:
270 amrnbenc->rate = 0;
271 amrnbenc->channels = 0;
272 amrnbenc->ts = 0;
273 gst_adapter_clear (amrnbenc->adapter);
274 break;
275 default:
276 break;
277 }
279 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
281 switch (transition) {
282 case GST_STATE_CHANGE_READY_TO_NULL:
283 Encoder_Interface_exit (amrnbenc->handle);
284 break;
285 default:
286 break;
287 }
289 return ret;
290 }