e056a7a9df2bb747c53e1bd1fdad83163bb32010
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)
100 {
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);
108 }
110 static void
111 gst_amrwbdec_init (GstAmrwbDec * amrwbdec, GstAmrwbDecClass * klass)
112 {
113 }
115 static gboolean
116 gst_amrwbdec_start (GstAudioDecoder * dec)
117 {
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;
128 }
130 static gboolean
131 gst_amrwbdec_stop (GstAudioDecoder * dec)
132 {
133 GstAmrwbDec *amrwbdec = GST_AMRWBDEC (dec);
135 GST_DEBUG_OBJECT (dec, "stop");
136 D_IF_exit (amrwbdec->handle);
138 return TRUE;
139 }
141 static gboolean
142 gst_amrwbdec_set_format (GstAudioDecoder * dec, GstCaps * caps)
143 {
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;
168 }
170 static GstFlowReturn
171 gst_amrwbdec_parse (GstAudioDecoder * dec, GstAdapter * adapter,
172 gint * offset, gint * length)
173 {
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;
206 }
208 static GstFlowReturn
209 gst_amrwbdec_handle_frame (GstAudioDecoder * dec, GstBuffer * buffer)
210 {
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 }
245 }