e056a7a9df2bb747c53e1bd1fdad83163bb32010
[glsdk/gst-plugins-ugly0-10.git] / ext / amrwbdec / amrwbdec.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 /**
21  * SECTION:element-amrwbdec
22  * @see_also: #GstAmrwbEnc
23  *
24  * AMR wideband decoder based on the 
25  * <ulink url="http://sourceforge.net/projects/opencore-amr">opencore codec implementation</ulink>.
26  *
27  * <refsect2>
28  * <title>Example launch line</title>
29  * |[
30  * gst-launch filesrc location=abc.amr ! amrparse ! amrwbdec ! audioresample ! audioconvert ! alsasink
31  * ]|
32  * </refsect2>
33  */
35 #ifdef HAVE_CONFIG_H
36 #include "config.h"
37 #endif
39 #include "amrwbdec.h"
41 static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
42     GST_PAD_SINK,
43     GST_PAD_ALWAYS,
44     GST_STATIC_CAPS ("audio/AMR-WB, "
45         "rate = (int) 16000, " "channels = (int) 1")
46     );
48 static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
49     GST_PAD_SRC,
50     GST_PAD_ALWAYS,
51     GST_STATIC_CAPS ("audio/x-raw-int, "
52         "width = (int) 16, "
53         "depth = (int) 16, "
54         "signed = (boolean) TRUE, "
55         "endianness = (int) BYTE_ORDER, "
56         "rate = (int) 16000, " "channels = (int) 1")
57     );
59 GST_DEBUG_CATEGORY_STATIC (gst_amrwbdec_debug);
60 #define GST_CAT_DEFAULT gst_amrwbdec_debug
62 #define L_FRAME16k      320     /* Frame size at 16kHz  */
64 static const unsigned char block_size[16] =
65     { 18, 24, 33, 37, 41, 47, 51, 59, 61,
66   6, 0, 0, 0, 0, 1, 1
67 };
69 static gboolean gst_amrwbdec_start (GstAudioDecoder * dec);
70 static gboolean gst_amrwbdec_stop (GstAudioDecoder * dec);
71 static gboolean gst_amrwbdec_set_format (GstAudioDecoder * dec, GstCaps * caps);
72 static gboolean gst_amrwbdec_parse (GstAudioDecoder * dec, GstAdapter * adapter,
73     gint * offset, gint * length);
74 static GstFlowReturn gst_amrwbdec_handle_frame (GstAudioDecoder * dec,
75     GstBuffer * buffer);
77 #define _do_init(bla) \
78     GST_DEBUG_CATEGORY_INIT (gst_amrwbdec_debug, "amrwbdec", 0, "AMR-WB audio decoder");
80 GST_BOILERPLATE_FULL (GstAmrwbDec, gst_amrwbdec, GstAudioDecoder,
81     GST_TYPE_AUDIO_DECODER, _do_init);
83 static void
84 gst_amrwbdec_base_init (gpointer klass)
85 {
86   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
88   gst_element_class_add_static_pad_template (element_class,
89       &sink_template);
90   gst_element_class_add_static_pad_template (element_class, &src_template);
92   gst_element_class_set_details_simple (element_class, "AMR-WB audio decoder",
93       "Codec/Decoder/Audio",
94       "Adaptive Multi-Rate Wideband audio decoder",
95       "Renato Araujo <renato.filho@indt.org.br>");
96 }
98 static void
99 gst_amrwbdec_class_init (GstAmrwbDecClass * klass)
101   GstAudioDecoderClass *base_class = GST_AUDIO_DECODER_CLASS (klass);
103   base_class->start = GST_DEBUG_FUNCPTR (gst_amrwbdec_start);
104   base_class->stop = GST_DEBUG_FUNCPTR (gst_amrwbdec_stop);
105   base_class->set_format = GST_DEBUG_FUNCPTR (gst_amrwbdec_set_format);
106   base_class->parse = GST_DEBUG_FUNCPTR (gst_amrwbdec_parse);
107   base_class->handle_frame = GST_DEBUG_FUNCPTR (gst_amrwbdec_handle_frame);
110 static void
111 gst_amrwbdec_init (GstAmrwbDec * amrwbdec, GstAmrwbDecClass * klass)
115 static gboolean
116 gst_amrwbdec_start (GstAudioDecoder * dec)
118   GstAmrwbDec *amrwbdec = GST_AMRWBDEC (dec);
120   GST_DEBUG_OBJECT (dec, "start");
121   if (!(amrwbdec->handle = D_IF_init ()))
122     return FALSE;
124   amrwbdec->rate = 0;
125   amrwbdec->channels = 0;
127   return TRUE;
130 static gboolean
131 gst_amrwbdec_stop (GstAudioDecoder * dec)
133   GstAmrwbDec *amrwbdec = GST_AMRWBDEC (dec);
135   GST_DEBUG_OBJECT (dec, "stop");
136   D_IF_exit (amrwbdec->handle);
138   return TRUE;
141 static gboolean
142 gst_amrwbdec_set_format (GstAudioDecoder * dec, GstCaps * caps)
144   GstStructure *structure;
145   GstAmrwbDec *amrwbdec;
146   GstCaps *copy;
148   amrwbdec = GST_AMRWBDEC (dec);
150   structure = gst_caps_get_structure (caps, 0);
152   /* get channel count */
153   gst_structure_get_int (structure, "channels", &amrwbdec->channels);
154   gst_structure_get_int (structure, "rate", &amrwbdec->rate);
156   /* create reverse caps */
157   copy = gst_caps_new_simple ("audio/x-raw-int",
158       "channels", G_TYPE_INT, amrwbdec->channels,
159       "width", G_TYPE_INT, 16,
160       "depth", G_TYPE_INT, 16,
161       "endianness", G_TYPE_INT, G_BYTE_ORDER,
162       "rate", G_TYPE_INT, amrwbdec->rate, "signed", G_TYPE_BOOLEAN, TRUE, NULL);
164   gst_pad_set_caps (GST_AUDIO_DECODER_SRC_PAD (amrwbdec), copy);
165   gst_caps_unref (copy);
167   return TRUE;
170 static GstFlowReturn
171 gst_amrwbdec_parse (GstAudioDecoder * dec, GstAdapter * adapter,
172     gint * offset, gint * length)
174   GstAmrwbDec *amrwbdec = GST_AMRWBDEC (dec);
175   const guint8 *data;
176   guint size;
177   gboolean sync, eos;
178   gint block, mode;
180   size = gst_adapter_available (adapter);
181   g_return_val_if_fail (size > 0, GST_FLOW_ERROR);
183   gst_audio_decoder_get_parse_state (dec, &sync, &eos);
185   /* need to peek data to get the size */
186   if (gst_adapter_available (adapter) < 1)
187     return GST_FLOW_ERROR;
189   data = gst_adapter_peek (adapter, 1);
190   mode = (data[0] >> 3) & 0x0F;
191   block = block_size[mode];
193   GST_DEBUG_OBJECT (amrwbdec, "mode %d, block %d", mode, block);
195   if (block) {
196     *offset = 0;
197     *length = block;
198   } else {
199     /* no frame yet, skip one byte */
200     GST_LOG_OBJECT (amrwbdec, "skipping byte");
201     *offset = 1;
202     return GST_FLOW_UNEXPECTED;
203   }
205   return GST_FLOW_OK;
208 static GstFlowReturn
209 gst_amrwbdec_handle_frame (GstAudioDecoder * dec, GstBuffer * buffer)
211   GstAmrwbDec *amrwbdec;
212   GstBuffer *out;
213   const guint8 *data;
215   amrwbdec = GST_AMRWBDEC (dec);
217   /* no fancy flushing */
218   if (!buffer || !GST_BUFFER_SIZE (buffer))
219     return GST_FLOW_OK;
221   if (amrwbdec->rate == 0 || amrwbdec->channels == 0)
222     goto not_negotiated;
224   /* the library seems to write into the source data, hence the copy. */
225   /* should be no problem */
226   data = GST_BUFFER_DATA (buffer);
228   /* get output */
229   out = gst_buffer_new_and_alloc (sizeof (gint16) * L_FRAME16k);
231   /* decode */
232   D_IF_decode (amrwbdec->handle, (unsigned char *) data,
233       (Word16 *) GST_BUFFER_DATA (out), _good_frame);
235   /* send out */
236   return gst_audio_decoder_finish_frame (dec, out, 1);
238   /* ERRORS */
239 not_negotiated:
240   {
241     GST_ELEMENT_ERROR (amrwbdec, STREAM, TYPE_NOT_FOUND, (NULL),
242         ("Decoder is not initialized"));
243     return GST_FLOW_NOT_NEGOTIATED;
244   }