dvdreadsrc: fix off by one in cell calculation for the last chapter
[glsdk/gst-plugins-ugly0-10.git] / ext / amrnb / amrnbdec.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-amrnbdec
22  * @see_also: #GstAmrnbEnc, #GstAmrParse
23  *
24  * AMR narrowband 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 ! amrnbdec ! audioresample ! audioconvert ! alsasink
31  * ]|
32  * </refsect2>
33  */
35 #ifdef HAVE_CONFIG_H
36 #include "config.h"
37 #endif
39 #include "amrnbdec.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, " "rate = (int) 8000, " "channels = (int) 1")
45     );
47 static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
48     GST_PAD_SRC,
49     GST_PAD_ALWAYS,
50     GST_STATIC_CAPS ("audio/x-raw-int, "
51         "width = (int) 16, "
52         "depth = (int) 16, "
53         "signed = (boolean) TRUE, "
54         "endianness = (int) BYTE_ORDER, "
55         "rate = (int) 8000," "channels = (int) 1")
56     );
58 GST_DEBUG_CATEGORY_STATIC (gst_amrnbdec_debug);
59 #define GST_CAT_DEFAULT gst_amrnbdec_debug
61 static const gint block_size_if1[16] = { 12, 13, 15, 17, 19, 20, 26, 31, 5,
62   0, 0, 0, 0, 0, 0, 0
63 };
65 static const gint block_size_if2[16] = { 12, 13, 15, 17, 18, 20, 25, 30, 5,
66   0, 0, 0, 0, 0, 0, 0
67 };
69 static GType
70 gst_amrnb_variant_get_type (void)
71 {
72   static GType gst_amrnb_variant_type = 0;
73   static const GEnumValue gst_amrnb_variant[] = {
74     {GST_AMRNB_VARIANT_IF1, "IF1", "IF1"},
75     {GST_AMRNB_VARIANT_IF2, "IF2", "IF2"},
76     {0, NULL, NULL},
77   };
78   if (!gst_amrnb_variant_type) {
79     gst_amrnb_variant_type =
80         g_enum_register_static ("GstAmrnbVariant", gst_amrnb_variant);
81   }
82   return gst_amrnb_variant_type;
83 }
85 #define GST_AMRNB_VARIANT_TYPE (gst_amrnb_variant_get_type())
87 #define VARIANT_DEFAULT GST_AMRNB_VARIANT_IF1
88 enum
89 {
90   PROP_0,
91   PROP_VARIANT
92 };
94 static void gst_amrnbdec_set_property (GObject * object, guint prop_id,
95     const GValue * value, GParamSpec * pspec);
96 static void gst_amrnbdec_get_property (GObject * object, guint prop_id,
97     GValue * value, GParamSpec * pspec);
99 static gboolean gst_amrnbdec_start (GstAudioDecoder * dec);
100 static gboolean gst_amrnbdec_stop (GstAudioDecoder * dec);
101 static gboolean gst_amrnbdec_set_format (GstAudioDecoder * dec, GstCaps * caps);
102 static gboolean gst_amrnbdec_parse (GstAudioDecoder * dec, GstAdapter * adapter,
103     gint * offset, gint * length);
104 static GstFlowReturn gst_amrnbdec_handle_frame (GstAudioDecoder * dec,
105     GstBuffer * buffer);
107 #define _do_init(bla) \
108     GST_DEBUG_CATEGORY_INIT (gst_amrnbdec_debug, "amrnbdec", 0, "AMR-NB audio decoder");
110 GST_BOILERPLATE_FULL (GstAmrnbDec, gst_amrnbdec, GstAudioDecoder,
111     GST_TYPE_AUDIO_DECODER, _do_init);
113 static void
114 gst_amrnbdec_base_init (gpointer klass)
116   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
118   gst_element_class_add_static_pad_template (element_class,
119       &sink_template);
120   gst_element_class_add_static_pad_template (element_class, &src_template);
122   gst_element_class_set_details_simple (element_class, "AMR-NB audio decoder",
123       "Codec/Decoder/Audio",
124       "Adaptive Multi-Rate Narrow-Band audio decoder",
125       "GStreamer maintainers <gstreamer-devel@lists.sourceforge.net>");
128 static void
129 gst_amrnbdec_class_init (GstAmrnbDecClass * klass)
131   GObjectClass *object_class = G_OBJECT_CLASS (klass);
132   GstAudioDecoderClass *base_class = GST_AUDIO_DECODER_CLASS (klass);
134   object_class->set_property = gst_amrnbdec_set_property;
135   object_class->get_property = gst_amrnbdec_get_property;
137   base_class->start = GST_DEBUG_FUNCPTR (gst_amrnbdec_start);
138   base_class->stop = GST_DEBUG_FUNCPTR (gst_amrnbdec_stop);
139   base_class->set_format = GST_DEBUG_FUNCPTR (gst_amrnbdec_set_format);
140   base_class->parse = GST_DEBUG_FUNCPTR (gst_amrnbdec_parse);
141   base_class->handle_frame = GST_DEBUG_FUNCPTR (gst_amrnbdec_handle_frame);
143   g_object_class_install_property (object_class, PROP_VARIANT,
144       g_param_spec_enum ("variant", "Variant",
145           "The decoder variant", GST_AMRNB_VARIANT_TYPE,
146           VARIANT_DEFAULT,
147           G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
150 static void
151 gst_amrnbdec_init (GstAmrnbDec * amrnbdec, GstAmrnbDecClass * klass)
155 static gboolean
156 gst_amrnbdec_start (GstAudioDecoder * dec)
158   GstAmrnbDec *amrnbdec = GST_AMRNBDEC (dec);
160   GST_DEBUG_OBJECT (dec, "start");
161   if (!(amrnbdec->handle = Decoder_Interface_init ()))
162     return FALSE;
164   amrnbdec->rate = 0;
165   amrnbdec->channels = 0;
167   return TRUE;
170 static gboolean
171 gst_amrnbdec_stop (GstAudioDecoder * dec)
173   GstAmrnbDec *amrnbdec = GST_AMRNBDEC (dec);
175   GST_DEBUG_OBJECT (dec, "stop");
176   Decoder_Interface_exit (amrnbdec->handle);
178   return TRUE;
181 static void
182 gst_amrnbdec_set_property (GObject * object, guint prop_id,
183     const GValue * value, GParamSpec * pspec)
185   GstAmrnbDec *self = GST_AMRNBDEC (object);
187   switch (prop_id) {
188     case PROP_VARIANT:
189       self->variant = g_value_get_enum (value);
190       break;
191     default:
192       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
193       break;
194   }
195   return;
198 static void
199 gst_amrnbdec_get_property (GObject * object, guint prop_id,
200     GValue * value, GParamSpec * pspec)
202   GstAmrnbDec *self = GST_AMRNBDEC (object);
204   switch (prop_id) {
205     case PROP_VARIANT:
206       g_value_set_enum (value, self->variant);
207       break;
208     default:
209       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
210       break;
211   }
212   return;
215 static gboolean
216 gst_amrnbdec_set_format (GstAudioDecoder * dec, GstCaps * caps)
218   GstStructure *structure;
219   GstAmrnbDec *amrnbdec;
220   GstCaps *copy;
222   amrnbdec = GST_AMRNBDEC (dec);
224   structure = gst_caps_get_structure (caps, 0);
226   /* get channel count */
227   gst_structure_get_int (structure, "channels", &amrnbdec->channels);
228   gst_structure_get_int (structure, "rate", &amrnbdec->rate);
230   /* create reverse caps */
231   copy = gst_caps_new_simple ("audio/x-raw-int",
232       "channels", G_TYPE_INT, amrnbdec->channels,
233       "width", G_TYPE_INT, 16,
234       "depth", G_TYPE_INT, 16,
235       "endianness", G_TYPE_INT, G_BYTE_ORDER,
236       "rate", G_TYPE_INT, amrnbdec->rate, "signed", G_TYPE_BOOLEAN, TRUE, NULL);
238   gst_pad_set_caps (GST_AUDIO_DECODER_SRC_PAD (dec), copy);
239   gst_caps_unref (copy);
241   return TRUE;
244 static GstFlowReturn
245 gst_amrnbdec_parse (GstAudioDecoder * dec, GstAdapter * adapter,
246     gint * offset, gint * length)
248   GstAmrnbDec *amrnbdec = GST_AMRNBDEC (dec);
249   const guint8 *data;
250   guint size;
251   gboolean sync, eos;
252   gint block, mode;
254   size = gst_adapter_available (adapter);
255   g_return_val_if_fail (size > 0, GST_FLOW_ERROR);
257   gst_audio_decoder_get_parse_state (dec, &sync, &eos);
259   /* need to peek data to get the size */
260   if (gst_adapter_available (adapter) < 1)
261     return GST_FLOW_ERROR;
263   data = gst_adapter_peek (adapter, 1);
265   /* get size */
266   switch (amrnbdec->variant) {
267     case GST_AMRNB_VARIANT_IF1:
268       mode = (data[0] >> 3) & 0x0F;
269       block = block_size_if1[mode] + 1;
270       break;
271     case GST_AMRNB_VARIANT_IF2:
272       mode = data[0] & 0x0F;
273       block = block_size_if2[mode] + 1;
274       break;
275     default:
276       g_assert_not_reached ();
277       return GST_FLOW_ERROR;
278       break;
279   }
281   GST_DEBUG_OBJECT (amrnbdec, "mode %d, block %d", mode, block);
283   *offset = 0;
284   *length = block;
286   return GST_FLOW_OK;
289 static GstFlowReturn
290 gst_amrnbdec_handle_frame (GstAudioDecoder * dec, GstBuffer * buffer)
292   GstAmrnbDec *amrnbdec;
293   guint8 *data;
294   GstBuffer *out;
296   amrnbdec = GST_AMRNBDEC (dec);
298   /* no fancy flushing */
299   if (!buffer || !GST_BUFFER_SIZE (buffer))
300     return GST_FLOW_OK;
302   if (amrnbdec->rate == 0 || amrnbdec->channels == 0)
303     goto not_negotiated;
305   /* the library seems to write into the source data, hence
306    * the copy. */
307   /* should not be a problem though */
308   data = GST_BUFFER_DATA (buffer);
310   /* get output */
311   out = gst_buffer_new_and_alloc (160 * 2);
313   /* decode */
314   Decoder_Interface_Decode (amrnbdec->handle, data,
315       (short *) GST_BUFFER_DATA (out), 0);
317   return gst_audio_decoder_finish_frame (dec, out, 1);
319   /* ERRORS */
320 not_negotiated:
321   {
322     GST_ELEMENT_ERROR (amrnbdec, STREAM, TYPE_NOT_FOUND, (NULL),
323         ("Decoder is not initialized"));
324     return GST_FLOW_NOT_NEGOTIATED;
325   }