blob: ae09f06153a23a57697c7776b45d5eb453ee41dd [file] [log] [blame]
Renato Araujo Oliveira Filho599af072006-03-29 16:50:08 +00001/* GStreamer Adaptive Multi-Rate Wide-Band (AMR-WB) plugin
2 * Copyright (C) 2006 Edgard Lima <edgard.lima@indt.org.br>
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
Tim-Philipp Müller9e1b75f2012-11-03 20:38:00 +000016 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
Renato Araujo Oliveira Filho599af072006-03-29 16:50:08 +000018 */
19
Stefan Kost59a213c2007-07-05 08:45:32 +000020/**
Sebastian Drögef085fa82011-04-19 10:07:23 +020021 * SECTION:element-voamrwbenc
22 * @see_also: #GstAmrWbDec, #GstAmrWbParse
Stefan Kost2aa5ce32007-07-03 09:18:22 +000023 *
Stefan Kost2affd3d2008-06-13 11:59:23 +000024 * AMR wideband encoder based on the
Stefan Kost2aa5ce32007-07-03 09:18:22 +000025 * <ulink url="http://www.penguin.cz/~utx/amr">reference codec implementation</ulink>.
Stefan Kost2affd3d2008-06-13 11:59:23 +000026 *
27 * <refsect2>
Stefan Kost2aa5ce32007-07-03 09:18:22 +000028 * <title>Example launch line</title>
Stefan Kost2affd3d2008-06-13 11:59:23 +000029 * |[
Sebastian Drögef085fa82011-04-19 10:07:23 +020030 * gst-launch filesrc location=abc.wav ! wavparse ! audioresample ! audioconvert ! voamrwbenc ! filesink location=abc.amr
Stefan Kost2affd3d2008-06-13 11:59:23 +000031 * ]|
Sebastian Drögef085fa82011-04-19 10:07:23 +020032 * Please note that the above stream misses the header, that is needed to play
Stefan Kost2aa5ce32007-07-03 09:18:22 +000033 * the stream.
34 * </refsect2>
35 */
36
Renato Araujo Oliveira Filho599af072006-03-29 16:50:08 +000037#ifdef HAVE_CONFIG_H
38#include "config.h"
39#endif
40
Sebastian Drögef085fa82011-04-19 10:07:23 +020041#include "gstvoamrwbenc.h"
Renato Araujo Oliveira Filho599af072006-03-29 16:50:08 +000042
Daniel Charles51990d62007-09-16 07:28:18 +000043#define MR660 0
44#define MR885 1
45#define MR1265 2
46#define MR1425 2
47#define MR1585 3
48#define MR1825 4
49#define MR1985 5
50#define MR2305 6
51#define MR2385 7
52#define MRDTX 8
Sebastian Drögef085fa82011-04-19 10:07:23 +020053
54#define L_FRAME16k 320 /* Frame size at 16kHz */
Daniel Charles51990d62007-09-16 07:28:18 +000055
56static GType
Sebastian Drögef085fa82011-04-19 10:07:23 +020057gst_voamrwbenc_bandmode_get_type (void)
Daniel Charles51990d62007-09-16 07:28:18 +000058{
Sebastian Drögef085fa82011-04-19 10:07:23 +020059 static GType gst_voamrwbenc_bandmode_type = 0;
Sebastian Dröge80e02cb2015-01-21 10:17:04 +010060 static const GEnumValue gst_voamrwbenc_bandmode[] = {
Daniel Charles51990d62007-09-16 07:28:18 +000061 {MR660, "MR660", "MR660"},
62 {MR885, "MR885", "MR885"},
63 {MR1265, "MR1265", "MR1265"},
64 {MR1425, "MR1425", "MR1425"},
65 {MR1585, "MR1585", "MR1585"},
66 {MR1825, "MR1825", "MR1825"},
67 {MR1985, "MR1985", "MR1985"},
68 {MR2305, "MR2305", "MR2305"},
69 {MR2385, "MR2385", "MR2385"},
70 {MRDTX, "MRDTX", "MRDTX"},
71 {0, NULL, NULL},
72 };
Sebastian Drögef085fa82011-04-19 10:07:23 +020073 if (!gst_voamrwbenc_bandmode_type) {
74 gst_voamrwbenc_bandmode_type =
75 g_enum_register_static ("GstVoAmrWbEncBandMode",
76 gst_voamrwbenc_bandmode);
Daniel Charles51990d62007-09-16 07:28:18 +000077 }
Sebastian Drögef085fa82011-04-19 10:07:23 +020078 return gst_voamrwbenc_bandmode_type;
Daniel Charles51990d62007-09-16 07:28:18 +000079}
80
Sebastian Drögef085fa82011-04-19 10:07:23 +020081#define GST_VOAMRWBENC_BANDMODE_TYPE (gst_voamrwbenc_bandmode_get_type())
Daniel Charles51990d62007-09-16 07:28:18 +000082
83#define BANDMODE_DEFAULT MR660
84
85enum
86{
87 PROP_0,
88 PROP_BANDMODE
89};
90
Renato Araujo Oliveira Filho599af072006-03-29 16:50:08 +000091static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
92 GST_PAD_SINK,
93 GST_PAD_ALWAYS,
Mark Nauwelaerts76811c22012-01-11 12:24:15 +010094 GST_STATIC_CAPS ("audio/x-raw, "
Mark Nauwelaerts849a83b2012-01-11 12:39:01 +010095 "format = (string) " GST_AUDIO_NE (S16) ", "
Mark Nauwelaerts76811c22012-01-11 12:24:15 +010096 "layout = (string) interleaved, "
Renato Araujo Oliveira Filho599af072006-03-29 16:50:08 +000097 "rate = (int) 16000, " "channels = (int) 1")
98 );
99
100static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
101 GST_PAD_SRC,
102 GST_PAD_ALWAYS,
103 GST_STATIC_CAPS ("audio/AMR-WB, "
104 "rate = (int) 16000, " "channels = (int) 1")
105 );
106
Sebastian Drögef085fa82011-04-19 10:07:23 +0200107GST_DEBUG_CATEGORY_STATIC (gst_voamrwbenc_debug);
108#define GST_CAT_DEFAULT gst_voamrwbenc_debug
Stefan Kostd337dda2007-05-18 09:35:28 +0000109
Mark Nauwelaerts97279f12011-11-17 23:03:05 +0100110static gboolean gst_voamrwbenc_start (GstAudioEncoder * enc);
111static gboolean gst_voamrwbenc_stop (GstAudioEncoder * enc);
112static gboolean gst_voamrwbenc_set_format (GstAudioEncoder * enc,
113 GstAudioInfo * info);
114static GstFlowReturn gst_voamrwbenc_handle_frame (GstAudioEncoder * enc,
115 GstBuffer * in_buf);
Renato Araujo Oliveira Filho599af072006-03-29 16:50:08 +0000116
Mark Nauwelaerts76811c22012-01-11 12:24:15 +0100117G_DEFINE_TYPE (GstVoAmrWbEnc, gst_voamrwbenc, GST_TYPE_AUDIO_ENCODER);
Renato Araujo Oliveira Filho599af072006-03-29 16:50:08 +0000118
Maciej Katafiasz9c905082006-05-06 00:15:59 +0000119static void
Sebastian Drögef085fa82011-04-19 10:07:23 +0200120gst_voamrwbenc_set_property (GObject * object, guint prop_id,
Daniel Charles51990d62007-09-16 07:28:18 +0000121 const GValue * value, GParamSpec * pspec)
122{
Sebastian Drögef085fa82011-04-19 10:07:23 +0200123 GstVoAmrWbEnc *self = GST_VOAMRWBENC (object);
Daniel Charles51990d62007-09-16 07:28:18 +0000124
125 switch (prop_id) {
126 case PROP_BANDMODE:
127 self->bandmode = g_value_get_enum (value);
128 break;
129 default:
130 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
131 break;
132 }
133
134 return;
135}
136
137static void
Sebastian Drögef085fa82011-04-19 10:07:23 +0200138gst_voamrwbenc_get_property (GObject * object, guint prop_id,
Daniel Charles51990d62007-09-16 07:28:18 +0000139 GValue * value, GParamSpec * pspec)
140{
Sebastian Drögef085fa82011-04-19 10:07:23 +0200141 GstVoAmrWbEnc *self = GST_VOAMRWBENC (object);
Daniel Charles51990d62007-09-16 07:28:18 +0000142
143 switch (prop_id) {
144 case PROP_BANDMODE:
145 g_value_set_enum (value, self->bandmode);
146 break;
147 default:
148 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
149 break;
150 }
151
152 return;
153}
154
155static void
Mark Nauwelaerts76811c22012-01-11 12:24:15 +0100156gst_voamrwbenc_class_init (GstVoAmrWbEncClass * klass)
Renato Araujo Oliveira Filho599af072006-03-29 16:50:08 +0000157{
Mark Nauwelaerts76811c22012-01-11 12:24:15 +0100158 GObjectClass *object_class = G_OBJECT_CLASS (klass);
Renato Araujo Oliveira Filho599af072006-03-29 16:50:08 +0000159 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
Mark Nauwelaerts76811c22012-01-11 12:24:15 +0100160 GstAudioEncoderClass *base_class = GST_AUDIO_ENCODER_CLASS (klass);
161
162 object_class->set_property = gst_voamrwbenc_set_property;
163 object_class->get_property = gst_voamrwbenc_get_property;
Renato Araujo Oliveira Filho599af072006-03-29 16:50:08 +0000164
165 gst_element_class_add_pad_template (element_class,
166 gst_static_pad_template_get (&sink_template));
167 gst_element_class_add_pad_template (element_class,
168 gst_static_pad_template_get (&src_template));
169
Tim-Philipp Müller32ba17c2012-10-17 17:34:26 +0100170 gst_element_class_set_static_metadata (element_class, "AMR-WB audio encoder",
Benjamin Otte775c7582010-03-18 17:30:26 +0100171 "Codec/Encoder/Audio",
172 "Adaptive Multi-Rate Wideband audio encoder",
173 "Renato Araujo <renato.filho@indt.org.br>");
Daniel Charles51990d62007-09-16 07:28:18 +0000174
Mark Nauwelaerts97279f12011-11-17 23:03:05 +0100175 base_class->start = GST_DEBUG_FUNCPTR (gst_voamrwbenc_start);
176 base_class->stop = GST_DEBUG_FUNCPTR (gst_voamrwbenc_stop);
177 base_class->set_format = GST_DEBUG_FUNCPTR (gst_voamrwbenc_set_format);
178 base_class->handle_frame = GST_DEBUG_FUNCPTR (gst_voamrwbenc_handle_frame);
179
Daniel Charles51990d62007-09-16 07:28:18 +0000180 g_object_class_install_property (object_class, PROP_BANDMODE,
181 g_param_spec_enum ("band-mode", "Band Mode",
Sebastian Drögef085fa82011-04-19 10:07:23 +0200182 "Encoding Band Mode (Kbps)", GST_VOAMRWBENC_BANDMODE_TYPE,
Stefan Kost0387a892010-10-19 16:23:23 +0300183 BANDMODE_DEFAULT,
184 G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
Mark Nauwelaertsdcc13e32012-01-28 20:01:35 +0100185
186 GST_DEBUG_CATEGORY_INIT (gst_voamrwbenc_debug, "voamrwbenc", 0,
187 "voamrwb encoder");
Renato Araujo Oliveira Filho599af072006-03-29 16:50:08 +0000188}
189
190static void
Mark Nauwelaerts76811c22012-01-11 12:24:15 +0100191gst_voamrwbenc_init (GstVoAmrWbEnc * amrwbenc)
Renato Araujo Oliveira Filho599af072006-03-29 16:50:08 +0000192{
Thiago Santos65172822015-08-16 07:18:34 -0300193 GST_PAD_SET_ACCEPT_TEMPLATE (GST_AUDIO_ENCODER_SINK_PAD (amrwbenc));
194
Renato Araujo Oliveira Filho599af072006-03-29 16:50:08 +0000195 /* init rest */
196 amrwbenc->handle = NULL;
197 amrwbenc->channels = 0;
198 amrwbenc->rate = 0;
Renato Araujo Oliveira Filho599af072006-03-29 16:50:08 +0000199}
200
201static gboolean
Mark Nauwelaerts97279f12011-11-17 23:03:05 +0100202gst_voamrwbenc_start (GstAudioEncoder * enc)
Renato Araujo Oliveira Filho599af072006-03-29 16:50:08 +0000203{
Mark Nauwelaerts97279f12011-11-17 23:03:05 +0100204 GstVoAmrWbEnc *voamrwbenc = GST_VOAMRWBENC (enc);
205
206 GST_DEBUG_OBJECT (enc, "start");
207
208 if (!(voamrwbenc->handle = E_IF_init ()))
209 return FALSE;
210
211 voamrwbenc->rate = 0;
212 voamrwbenc->channels = 0;
213
214 return TRUE;
215}
216
217static gboolean
218gst_voamrwbenc_stop (GstAudioEncoder * enc)
219{
220 GstVoAmrWbEnc *voamrwbenc = GST_VOAMRWBENC (enc);
221
222 GST_DEBUG_OBJECT (enc, "stop");
223
224 if (voamrwbenc->handle) {
225 E_IF_exit (voamrwbenc->handle);
226 voamrwbenc->handle = NULL;
227 }
228
229 return TRUE;
230}
231
232static gboolean
233gst_voamrwbenc_set_format (GstAudioEncoder * benc, GstAudioInfo * info)
234{
Sebastian Drögef085fa82011-04-19 10:07:23 +0200235 GstVoAmrWbEnc *amrwbenc;
Renato Araujo Oliveira Filho599af072006-03-29 16:50:08 +0000236 GstCaps *copy;
237
Mark Nauwelaerts97279f12011-11-17 23:03:05 +0100238 amrwbenc = GST_VOAMRWBENC (benc);
Renato Araujo Oliveira Filho599af072006-03-29 16:50:08 +0000239
240 /* get channel count */
Mark Nauwelaerts97279f12011-11-17 23:03:05 +0100241 amrwbenc->channels = GST_AUDIO_INFO_CHANNELS (info);
242 amrwbenc->rate = GST_AUDIO_INFO_RATE (info);
Renato Araujo Oliveira Filho599af072006-03-29 16:50:08 +0000243
244 /* this is not wrong but will sound bad */
245 if (amrwbenc->channels != 1) {
246 GST_WARNING ("amrwbdec is only optimized for mono channels");
247 }
248 if (amrwbenc->rate != 16000) {
249 GST_WARNING ("amrwbdec is only optimized for 16000 Hz samplerate");
250 }
251
252 /* create reverse caps */
253 copy = gst_caps_new_simple ("audio/AMR-WB",
254 "channels", G_TYPE_INT, amrwbenc->channels,
255 "rate", G_TYPE_INT, amrwbenc->rate, NULL);
256
Sebastian Dröge43da3e62012-02-01 16:27:22 +0100257 gst_audio_encoder_set_output_format (GST_AUDIO_ENCODER (amrwbenc), copy);
Renato Araujo Oliveira Filho599af072006-03-29 16:50:08 +0000258 gst_caps_unref (copy);
259
Mark Nauwelaerts97279f12011-11-17 23:03:05 +0100260 /* report needs to base class: one frame at a time */
261 gst_audio_encoder_set_frame_samples_min (benc, L_FRAME16k);
262 gst_audio_encoder_set_frame_samples_max (benc, L_FRAME16k);
263 gst_audio_encoder_set_frame_max (benc, 1);
264
Renato Araujo Oliveira Filho599af072006-03-29 16:50:08 +0000265 return TRUE;
266}
267
268static GstFlowReturn
Mark Nauwelaerts97279f12011-11-17 23:03:05 +0100269gst_voamrwbenc_handle_frame (GstAudioEncoder * benc, GstBuffer * buffer)
Renato Araujo Oliveira Filho599af072006-03-29 16:50:08 +0000270{
Sebastian Drögef085fa82011-04-19 10:07:23 +0200271 GstVoAmrWbEnc *amrwbenc;
Renato Araujo Oliveira Filho599af072006-03-29 16:50:08 +0000272 GstFlowReturn ret = GST_FLOW_OK;
Sebastian Drögef085fa82011-04-19 10:07:23 +0200273 const int buffer_size = sizeof (short) * L_FRAME16k;
Mark Nauwelaerts97279f12011-11-17 23:03:05 +0100274 GstBuffer *out;
275 gint outsize;
Mark Nauwelaerts12ee4182012-01-25 18:49:58 +0100276 GstMapInfo map, omap;
Renato Araujo Oliveira Filho599af072006-03-29 16:50:08 +0000277
Mark Nauwelaerts97279f12011-11-17 23:03:05 +0100278 amrwbenc = GST_VOAMRWBENC (benc);
Renato Araujo Oliveira Filho599af072006-03-29 16:50:08 +0000279
Mark Nauwelaerts97279f12011-11-17 23:03:05 +0100280 g_return_val_if_fail (amrwbenc->handle, GST_FLOW_NOT_NEGOTIATED);
Renato Araujo Oliveira Filho599af072006-03-29 16:50:08 +0000281
Mark Nauwelaerts97279f12011-11-17 23:03:05 +0100282 /* we don't deal with squeezing remnants, so simply discard those */
283 if (G_UNLIKELY (buffer == NULL)) {
284 GST_DEBUG_OBJECT (amrwbenc, "no data");
285 goto done;
Stefan Kostf92e6bd2008-10-09 10:01:37 +0000286 }
287
Mark Nauwelaerts12ee4182012-01-25 18:49:58 +0100288 gst_buffer_map (buffer, &map, GST_MAP_READ);
Mark Nauwelaerts76811c22012-01-11 12:24:15 +0100289
Mark Nauwelaerts12ee4182012-01-25 18:49:58 +0100290 if (G_UNLIKELY (map.size < buffer_size)) {
291 GST_DEBUG_OBJECT (amrwbenc, "discarding trailing data %d", (gint) map.size);
292 gst_buffer_unmap (buffer, &map);
Mark Nauwelaerts97279f12011-11-17 23:03:05 +0100293 ret = gst_audio_encoder_finish_frame (benc, NULL, -1);
294 goto done;
Renato Araujo Oliveira Filho599af072006-03-29 16:50:08 +0000295 }
296
Mark Nauwelaerts97279f12011-11-17 23:03:05 +0100297 out = gst_buffer_new_and_alloc (buffer_size);
Mark Nauwelaerts12ee4182012-01-25 18:49:58 +0100298 gst_buffer_map (out, &omap, GST_MAP_WRITE);
Mark Nauwelaerts97279f12011-11-17 23:03:05 +0100299 /* encode */
300 outsize = E_IF_encode (amrwbenc->handle, amrwbenc->bandmode,
Mark Nauwelaerts12ee4182012-01-25 18:49:58 +0100301 (const short *) map.data, (unsigned char *) omap.data, 0);
Mark Nauwelaerts97279f12011-11-17 23:03:05 +0100302
303 GST_LOG_OBJECT (amrwbenc, "encoded to %d bytes", outsize);
Mark Nauwelaerts12ee4182012-01-25 18:49:58 +0100304 gst_buffer_unmap (out, &omap);
305 gst_buffer_unmap (buffer, &map);
306 gst_buffer_resize (out, 0, outsize);
Mark Nauwelaerts97279f12011-11-17 23:03:05 +0100307
308 ret = gst_audio_encoder_finish_frame (benc, out, L_FRAME16k);
309
Renato Araujo Oliveira Filho599af072006-03-29 16:50:08 +0000310done:
Renato Araujo Oliveira Filho599af072006-03-29 16:50:08 +0000311 return ret;
312}