3145f79f4c19524ee3b67a00104e89191d062eb6
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 = gst_pad_new_from_static_template (&sink_template, "sink");
118 gst_pad_set_setcaps_function (amrnbenc->sinkpad, gst_amrnbenc_setcaps);
119 gst_pad_set_chain_function (amrnbenc->sinkpad, gst_amrnbenc_chain);
120 gst_element_add_pad (GST_ELEMENT (amrnbenc), amrnbenc->sinkpad);
122 /* create the src pad */
123 amrnbenc->srcpad = gst_pad_new_from_static_template (&src_template, "src");
124 gst_pad_use_fixed_caps (amrnbenc->srcpad);
125 gst_element_add_pad (GST_ELEMENT (amrnbenc), amrnbenc->srcpad);
127 amrnbenc->adapter = gst_adapter_new ();
129 /* init rest */
130 amrnbenc->handle = NULL;
131 }
133 static void
134 gst_amrnbenc_finalize (GObject * object)
135 {
136 GstAmrnbEnc *amrnbenc;
138 amrnbenc = GST_AMRNBENC (object);
140 g_object_unref (G_OBJECT (amrnbenc->adapter));
141 amrnbenc->adapter = NULL;
143 G_OBJECT_CLASS (parent_class)->finalize (object);
144 }
146 static gboolean
147 gst_amrnbenc_setcaps (GstPad * pad, GstCaps * caps)
148 {
149 GstStructure *structure;
150 GstAmrnbEnc *amrnbenc;
151 GstCaps *copy;
153 amrnbenc = GST_AMRNBENC (GST_PAD_PARENT (pad));
155 structure = gst_caps_get_structure (caps, 0);
157 /* get channel count */
158 gst_structure_get_int (structure, "channels", &amrnbenc->channels);
159 gst_structure_get_int (structure, "rate", &amrnbenc->rate);
161 /* this is not wrong but will sound bad */
162 if (amrnbenc->channels != 1) {
163 g_warning ("amrnbdec is only optimized for mono channels");
164 }
165 if (amrnbenc->rate != 8000) {
166 g_warning ("amrnbdec is only optimized for 8000 Hz samplerate");
167 }
169 /* create reverse caps */
170 copy = gst_caps_new_simple ("audio/AMR",
171 "channels", G_TYPE_INT, amrnbenc->channels,
172 "rate", G_TYPE_INT, amrnbenc->rate, NULL);
174 /* precalc duration as it's constant now */
175 amrnbenc->duration = gst_util_uint64_scale_int (160, GST_SECOND,
176 amrnbenc->rate * amrnbenc->channels);
178 gst_pad_set_caps (amrnbenc->srcpad, copy);
179 gst_caps_unref (copy);
181 return TRUE;
182 }
184 static GstFlowReturn
185 gst_amrnbenc_chain (GstPad * pad, GstBuffer * buffer)
186 {
187 GstAmrnbEnc *amrnbenc;
188 GstFlowReturn ret;
190 amrnbenc = GST_AMRNBENC (GST_PAD_PARENT (pad));
192 g_return_val_if_fail (amrnbenc->handle, GST_FLOW_WRONG_STATE);
194 if (amrnbenc->rate == 0 || amrnbenc->channels == 0)
195 goto not_negotiated;
197 /* discontinuity clears adapter, FIXME, maybe we can set some
198 * encoder flag to mask the discont. */
199 if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT)) {
200 gst_adapter_clear (amrnbenc->adapter);
201 amrnbenc->ts = 0;
202 }
204 /* take latest timestamp, FIXME timestamp is the one of the
205 * first buffer in the adapter. */
206 if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer))
207 amrnbenc->ts = GST_BUFFER_TIMESTAMP (buffer);
209 ret = GST_FLOW_OK;
210 gst_adapter_push (amrnbenc->adapter, buffer);
212 /* Collect samples until we have enough for an output frame */
213 while (gst_adapter_available (amrnbenc->adapter) >= 320) {
214 GstBuffer *out;
215 guint8 *data;
216 gint outsize;
218 /* get output, max size is 32 */
219 out = gst_buffer_new_and_alloc (32);
220 GST_BUFFER_DURATION (out) = amrnbenc->duration;
221 GST_BUFFER_TIMESTAMP (out) = amrnbenc->ts;
222 if (amrnbenc->ts != -1)
223 amrnbenc->ts += amrnbenc->duration;
224 gst_buffer_set_caps (out, GST_PAD_CAPS (amrnbenc->srcpad));
226 /* The AMR encoder actually writes into the source data buffers it gets */
227 data = gst_adapter_take (amrnbenc->adapter, 320);
229 /* encode */
230 outsize = Encoder_Interface_Encode (amrnbenc->handle, MR122, (short *) data,
231 (guint8 *) GST_BUFFER_DATA (out), 0);
233 g_free (data);
235 GST_BUFFER_SIZE (out) = outsize;
237 /* play */
238 if ((ret = gst_pad_push (amrnbenc->srcpad, out)) != GST_FLOW_OK)
239 break;
240 }
241 return ret;
243 /* ERRORS */
244 not_negotiated:
245 {
246 GST_ELEMENT_ERROR (amrnbenc, STREAM, TYPE_NOT_FOUND,
247 (NULL), ("unknown type"));
248 return GST_FLOW_NOT_NEGOTIATED;
249 }
250 }
252 static GstStateChangeReturn
253 gst_amrnbenc_state_change (GstElement * element, GstStateChange transition)
254 {
255 GstAmrnbEnc *amrnbenc;
256 GstStateChangeReturn ret;
258 amrnbenc = GST_AMRNBENC (element);
260 switch (transition) {
261 case GST_STATE_CHANGE_NULL_TO_READY:
262 if (!(amrnbenc->handle = Encoder_Interface_init (0)))
263 return GST_STATE_CHANGE_FAILURE;
264 break;
265 case GST_STATE_CHANGE_READY_TO_PAUSED:
266 amrnbenc->rate = 0;
267 amrnbenc->channels = 0;
268 amrnbenc->ts = 0;
269 gst_adapter_clear (amrnbenc->adapter);
270 break;
271 default:
272 break;
273 }
275 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
277 switch (transition) {
278 case GST_STATE_CHANGE_READY_TO_NULL:
279 Encoder_Interface_exit (amrnbenc->handle);
280 break;
281 default:
282 break;
283 }
285 return ret;
286 }