f25fdfe87d764f63811c3e70c8925da6c62db859
[glsdk/gst-plugins-ugly0-10.git] / ext / amrnb / amrnbenc.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 "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)
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;
113 static void
114 gst_amrnbenc_init (GstAmrnbEnc * amrnbenc)
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;
137 static void
138 gst_amrnbenc_finalize (GObject * object)
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);
150 static gboolean
151 gst_amrnbenc_setcaps (GstPad * pad, GstCaps * caps)
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;
188 static GstFlowReturn
189 gst_amrnbenc_chain (GstPad * pad, GstBuffer * buffer)
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   }
256 static GstStateChangeReturn
257 gst_amrnbenc_state_change (GstElement * element, GstStateChange transition)
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;