3145f79f4c19524ee3b67a00104e89191d062eb6
[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 = 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;
133 static void
134 gst_amrnbenc_finalize (GObject * object)
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);
146 static gboolean
147 gst_amrnbenc_setcaps (GstPad * pad, GstCaps * caps)
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;
184 static GstFlowReturn
185 gst_amrnbenc_chain (GstPad * pad, GstBuffer * buffer)
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   }
252 static GstStateChangeReturn
253 gst_amrnbenc_state_change (GstElement * element, GstStateChange transition)
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;