1 /* GStreamer AAC encoder plugin
2 * Copyright (C) 2011 Kan Hu <kan.hu@linaro.org>
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., 51 Franklin St, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18 */
19
20 /**
21 * SECTION:element-voaacenc
22 * @title: voaacenc
23 *
24 * AAC audio encoder based on vo-aacenc library.
25 *
26 * [vo-aacenc library source file](http://sourceforge.net/projects/opencore-amr/files/vo-aacenc/)
27 *
28 * ## Example launch line
29 * |[
30 * gst-launch-1.0 filesrc location=abc.wav ! wavparse ! audioresample ! audioconvert ! voaacenc ! filesink location=abc.aac
31 * ]|
32 *
33 */
34
35 #ifdef HAVE_CONFIG_H
36 #include "config.h"
37 #endif
38
39 #include <string.h>
40
41 #include <gst/pbutils/codec-utils.h>
42
43 #include "gstvoaacenc.h"
44
45 #define VOAAC_ENC_DEFAULT_BITRATE (128000)
46 #define VOAAC_ENC_DEFAULT_OUTPUTFORMAT (0) /* RAW */
47 #define VOAAC_ENC_MPEGVERSION (4)
48 #define VOAAC_ENC_CODECDATA_LEN (2)
49 #define VOAAC_ENC_BITS_PER_SAMPLE (16)
50
51 enum
52 {
53 PROP_0,
54 PROP_BITRATE
55 };
56
57 #define SAMPLE_RATES " 8000, " \
58 "11025, " \
59 "12000, " \
60 "16000, " \
61 "22050, " \
62 "24000, " \
63 "32000, " \
64 "44100, " \
65 "48000, " \
66 "64000, " \
67 "88200, " \
68 "96000"
69
70 /* voaacenc only supports 1 or 2 channels */
71 static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
72 GST_PAD_SINK,
73 GST_PAD_ALWAYS,
74 GST_STATIC_CAPS ("audio/x-raw, "
75 "format = (string) " GST_AUDIO_NE (S16) ", "
76 "layout = (string) interleaved, "
77 "rate = (int) { " SAMPLE_RATES " }, " "channels = (int) 1;"
78 "audio/x-raw, "
79 "format = (string) " GST_AUDIO_NE (S16) ", "
80 "layout = (string) interleaved, "
81 "rate = (int) { " SAMPLE_RATES " }, " "channels = (int) 2, "
82 "channel-mask=(bitmask)0x3")
83 );
84
85 static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
86 GST_PAD_SRC,
87 GST_PAD_ALWAYS,
88 GST_STATIC_CAPS ("audio/mpeg, "
89 "mpegversion = (int) 4, "
90 "rate = (int) { " SAMPLE_RATES " }, "
91 "channels = (int) [1, 2], "
92 "stream-format = (string) { adts, raw }, " "base-profile = (string) lc")
93 );
94
95 GST_DEBUG_CATEGORY_STATIC (gst_voaacenc_debug);
96 #define GST_CAT_DEFAULT gst_voaacenc_debug
97
98 static gboolean voaacenc_core_init (GstVoAacEnc * voaacenc);
99 static gboolean voaacenc_core_set_parameter (GstVoAacEnc * voaacenc);
100 static void voaacenc_core_uninit (GstVoAacEnc * voaacenc);
101
102 static gboolean gst_voaacenc_start (GstAudioEncoder * enc);
103 static gboolean gst_voaacenc_stop (GstAudioEncoder * enc);
104 static gboolean gst_voaacenc_set_format (GstAudioEncoder * enc,
105 GstAudioInfo * info);
106 static GstFlowReturn gst_voaacenc_handle_frame (GstAudioEncoder * enc,
107 GstBuffer * in_buf);
108
109 G_DEFINE_TYPE (GstVoAacEnc, gst_voaacenc, GST_TYPE_AUDIO_ENCODER);
110 GST_ELEMENT_REGISTER_DEFINE (voaacenc, "voaacenc",
111 GST_RANK_SECONDARY, GST_TYPE_VOAACENC);
112
113 static void
gst_voaacenc_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)114 gst_voaacenc_set_property (GObject * object, guint prop_id,
115 const GValue * value, GParamSpec * pspec)
116 {
117 GstVoAacEnc *self = GST_VOAACENC (object);
118
119 switch (prop_id) {
120 case PROP_BITRATE:
121 self->bitrate = g_value_get_int (value);
122 break;
123 default:
124 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
125 break;
126 }
127 return;
128 }
129
130 static void
gst_voaacenc_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)131 gst_voaacenc_get_property (GObject * object, guint prop_id,
132 GValue * value, GParamSpec * pspec)
133 {
134 GstVoAacEnc *self = GST_VOAACENC (object);
135
136 switch (prop_id) {
137 case PROP_BITRATE:
138 g_value_set_int (value, self->bitrate);
139 break;
140 default:
141 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
142 break;
143 }
144 return;
145 }
146
147 static void
gst_voaacenc_class_init(GstVoAacEncClass * klass)148 gst_voaacenc_class_init (GstVoAacEncClass * klass)
149 {
150 GObjectClass *object_class = G_OBJECT_CLASS (klass);
151 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
152 GstAudioEncoderClass *base_class = GST_AUDIO_ENCODER_CLASS (klass);
153
154 object_class->set_property = GST_DEBUG_FUNCPTR (gst_voaacenc_set_property);
155 object_class->get_property = GST_DEBUG_FUNCPTR (gst_voaacenc_get_property);
156
157 base_class->start = GST_DEBUG_FUNCPTR (gst_voaacenc_start);
158 base_class->stop = GST_DEBUG_FUNCPTR (gst_voaacenc_stop);
159 base_class->set_format = GST_DEBUG_FUNCPTR (gst_voaacenc_set_format);
160 base_class->handle_frame = GST_DEBUG_FUNCPTR (gst_voaacenc_handle_frame);
161
162 g_object_class_install_property (object_class, PROP_BITRATE,
163 g_param_spec_int ("bitrate",
164 "Bitrate",
165 "Target Audio Bitrate (bits per second)",
166 0, 320000, VOAAC_ENC_DEFAULT_BITRATE,
167 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
168
169 gst_element_class_add_static_pad_template (element_class, &sink_template);
170 gst_element_class_add_static_pad_template (element_class, &src_template);
171
172 gst_element_class_set_static_metadata (element_class, "AAC audio encoder",
173 "Codec/Encoder/Audio", "AAC audio encoder", "Kan Hu <kan.hu@linaro.org>");
174
175 GST_DEBUG_CATEGORY_INIT (gst_voaacenc_debug, "voaacenc", 0, "voaac encoder");
176 }
177
178 static void
gst_voaacenc_init(GstVoAacEnc * voaacenc)179 gst_voaacenc_init (GstVoAacEnc * voaacenc)
180 {
181 GST_PAD_SET_ACCEPT_TEMPLATE (GST_AUDIO_ENCODER_SINK_PAD (voaacenc));
182 voaacenc->bitrate = VOAAC_ENC_DEFAULT_BITRATE;
183 voaacenc->output_format = VOAAC_ENC_DEFAULT_OUTPUTFORMAT;
184
185 /* init rest */
186 voaacenc->handle = NULL;
187 }
188
189 static gboolean
gst_voaacenc_start(GstAudioEncoder * enc)190 gst_voaacenc_start (GstAudioEncoder * enc)
191 {
192 GstVoAacEnc *voaacenc = GST_VOAACENC (enc);
193
194 GST_DEBUG_OBJECT (enc, "start");
195
196 if (voaacenc_core_init (voaacenc) == FALSE)
197 return FALSE;
198
199 voaacenc->rate = 0;
200 voaacenc->channels = 0;
201
202 return TRUE;
203 }
204
205 static gboolean
gst_voaacenc_stop(GstAudioEncoder * enc)206 gst_voaacenc_stop (GstAudioEncoder * enc)
207 {
208 GstVoAacEnc *voaacenc = GST_VOAACENC (enc);
209
210 GST_DEBUG_OBJECT (enc, "stop");
211 voaacenc_core_uninit (voaacenc);
212
213 return TRUE;
214 }
215
216 #define VOAAC_ENC_MAX_CHANNELS 6
217 /* describe the channels position */
218 static const GstAudioChannelPosition
219 aac_channel_positions[][VOAAC_ENC_MAX_CHANNELS] = {
220 { /* 1 ch: Mono */
221 GST_AUDIO_CHANNEL_POSITION_MONO},
222 { /* 2 ch: front left + front right (front stereo) */
223 GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
224 GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT},
225 { /* 3 ch: front center + front stereo */
226 GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
227 GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
228 GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT},
229 { /* 4 ch: front center + front stereo + back center */
230 GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
231 GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
232 GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
233 GST_AUDIO_CHANNEL_POSITION_REAR_CENTER},
234 { /* 5 ch: front center + front stereo + back stereo */
235 GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
236 GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
237 GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
238 GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
239 GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT},
240 { /* 6ch: front center + front stereo + back stereo + LFE */
241 GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
242 GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
243 GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
244 GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
245 GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
246 GST_AUDIO_CHANNEL_POSITION_LFE1}
247 };
248
249 /* check downstream caps to configure format */
250 static void
gst_voaacenc_negotiate(GstVoAacEnc * voaacenc)251 gst_voaacenc_negotiate (GstVoAacEnc * voaacenc)
252 {
253 GstCaps *caps;
254
255 caps = gst_pad_get_allowed_caps (GST_AUDIO_ENCODER_SRC_PAD (voaacenc));
256
257 GST_DEBUG_OBJECT (voaacenc, "allowed caps: %" GST_PTR_FORMAT, caps);
258
259 if (caps && gst_caps_get_size (caps) > 0) {
260 GstStructure *s = gst_caps_get_structure (caps, 0);
261 const gchar *str = NULL;
262
263 if ((str = gst_structure_get_string (s, "stream-format"))) {
264 if (strcmp (str, "adts") == 0) {
265 GST_DEBUG_OBJECT (voaacenc, "use ADTS format for output");
266 voaacenc->output_format = 1;
267 } else if (strcmp (str, "raw") == 0) {
268 GST_DEBUG_OBJECT (voaacenc, "use RAW format for output");
269 voaacenc->output_format = 0;
270 } else {
271 GST_DEBUG_OBJECT (voaacenc, "unknown stream-format: %s", str);
272 voaacenc->output_format = VOAAC_ENC_DEFAULT_OUTPUTFORMAT;
273 }
274 }
275 }
276
277 if (caps)
278 gst_caps_unref (caps);
279 }
280
281 static gint
gst_voaacenc_get_rate_index(gint rate)282 gst_voaacenc_get_rate_index (gint rate)
283 {
284 static const gint rate_table[] = {
285 96000, 88200, 64000, 48000, 44100, 32000,
286 24000, 22050, 16000, 12000, 11025, 8000
287 };
288 gint i;
289 for (i = 0; i < G_N_ELEMENTS (rate_table); ++i) {
290 if (rate == rate_table[i]) {
291 return i;
292 }
293 }
294 return -1;
295 }
296
297 static GstCaps *
gst_voaacenc_create_source_pad_caps(GstVoAacEnc * voaacenc)298 gst_voaacenc_create_source_pad_caps (GstVoAacEnc * voaacenc)
299 {
300 GstCaps *caps = NULL;
301 gint index;
302 GstBuffer *codec_data;
303 GstMapInfo map;
304
305 if ((index = gst_voaacenc_get_rate_index (voaacenc->rate)) >= 0) {
306 codec_data = gst_buffer_new_and_alloc (VOAAC_ENC_CODECDATA_LEN);
307 gst_buffer_map (codec_data, &map, GST_MAP_WRITE);
308 /* LC profile only */
309 map.data[0] = ((0x02 << 3) | (index >> 1));
310 map.data[1] = ((index & 0x01) << 7) | (voaacenc->channels << 3);
311
312 caps = gst_caps_new_simple ("audio/mpeg",
313 "mpegversion", G_TYPE_INT, VOAAC_ENC_MPEGVERSION,
314 "channels", G_TYPE_INT, voaacenc->channels,
315 "rate", G_TYPE_INT, voaacenc->rate, NULL);
316
317 gst_codec_utils_aac_caps_set_level_and_profile (caps, map.data,
318 VOAAC_ENC_CODECDATA_LEN);
319 gst_buffer_unmap (codec_data, &map);
320
321 if (!voaacenc->output_format) {
322 gst_caps_set_simple (caps,
323 "stream-format", G_TYPE_STRING, "raw",
324 "codec_data", GST_TYPE_BUFFER, codec_data, NULL);
325 } else {
326 gst_caps_set_simple (caps,
327 "stream-format", G_TYPE_STRING, "adts",
328 "framed", G_TYPE_BOOLEAN, TRUE, NULL);
329 }
330 gst_buffer_unref (codec_data);
331 }
332
333 return caps;
334 }
335
336 static gboolean
gst_voaacenc_set_format(GstAudioEncoder * benc,GstAudioInfo * info)337 gst_voaacenc_set_format (GstAudioEncoder * benc, GstAudioInfo * info)
338 {
339 gboolean ret = FALSE;
340 GstVoAacEnc *voaacenc;
341 GstCaps *src_caps;
342
343 voaacenc = GST_VOAACENC (benc);
344
345 /* get channel count */
346 voaacenc->channels = GST_AUDIO_INFO_CHANNELS (info);
347 voaacenc->rate = GST_AUDIO_INFO_RATE (info);
348
349 /* precalc buffer size as it's constant now */
350 voaacenc->inbuf_size = voaacenc->channels * 2 * 1024;
351
352 gst_voaacenc_negotiate (voaacenc);
353
354 /* create reverse caps */
355 src_caps = gst_voaacenc_create_source_pad_caps (voaacenc);
356
357 if (src_caps) {
358 gst_audio_encoder_set_output_format (GST_AUDIO_ENCODER (voaacenc),
359 src_caps);
360 gst_caps_unref (src_caps);
361 ret = voaacenc_core_set_parameter (voaacenc);
362 }
363
364 /* report needs to base class */
365 gst_audio_encoder_set_frame_samples_min (benc, 1024);
366 gst_audio_encoder_set_frame_samples_max (benc, 1024);
367 gst_audio_encoder_set_frame_max (benc, 1);
368
369 return ret;
370 }
371
372 static GstFlowReturn
gst_voaacenc_handle_frame(GstAudioEncoder * benc,GstBuffer * buf)373 gst_voaacenc_handle_frame (GstAudioEncoder * benc, GstBuffer * buf)
374 {
375 GstVoAacEnc *voaacenc;
376 GstFlowReturn ret = GST_FLOW_OK;
377 GstBuffer *out;
378 VO_AUDIO_OUTPUTINFO output_info = { {0} };
379 VO_CODECBUFFER input = { 0 };
380 VO_CODECBUFFER output = { 0 };
381 GstMapInfo map, omap;
382 GstAudioInfo *info = gst_audio_encoder_get_audio_info (benc);
383
384 voaacenc = GST_VOAACENC (benc);
385
386 g_return_val_if_fail (voaacenc->handle, GST_FLOW_NOT_NEGOTIATED);
387
388 /* we don't deal with squeezing remnants, so simply discard those */
389 if (G_UNLIKELY (buf == NULL)) {
390 GST_DEBUG_OBJECT (benc, "no data");
391 goto exit;
392 }
393
394 if (memcmp (info->position, aac_channel_positions[info->channels - 1],
395 sizeof (GstAudioChannelPosition) * info->channels) != 0) {
396 buf = gst_buffer_make_writable (buf);
397 gst_audio_buffer_reorder_channels (buf, info->finfo->format,
398 info->channels, info->position,
399 aac_channel_positions[info->channels - 1]);
400 }
401
402 gst_buffer_map (buf, &map, GST_MAP_READ);
403
404 if (G_UNLIKELY (map.size < voaacenc->inbuf_size)) {
405 gst_buffer_unmap (buf, &map);
406 GST_DEBUG_OBJECT (voaacenc, "discarding trailing data %d", (gint) map.size);
407 ret = gst_audio_encoder_finish_frame (benc, NULL, -1);
408 goto exit;
409 }
410
411 /* max size */
412 out = gst_buffer_new_and_alloc (voaacenc->inbuf_size);
413 gst_buffer_map (out, &omap, GST_MAP_WRITE);
414
415 output.Buffer = omap.data;
416 output.Length = voaacenc->inbuf_size;
417
418 g_assert (map.size == voaacenc->inbuf_size);
419 input.Buffer = map.data;
420 input.Length = voaacenc->inbuf_size;
421 voaacenc->codec_api.SetInputData (voaacenc->handle, &input);
422
423 /* encode */
424 if (voaacenc->codec_api.GetOutputData (voaacenc->handle, &output,
425 &output_info) != VO_ERR_NONE) {
426 gst_buffer_unmap (buf, &map);
427 gst_buffer_unmap (out, &omap);
428 gst_buffer_unref (out);
429 goto encode_failed;
430 }
431
432 GST_LOG_OBJECT (voaacenc, "encoded to %lu bytes", output.Length);
433 gst_buffer_unmap (buf, &map);
434 gst_buffer_unmap (out, &omap);
435 gst_buffer_resize (out, 0, output.Length);
436
437 ret = gst_audio_encoder_finish_frame (benc, out, 1024);
438
439 exit:
440 return ret;
441
442 /* ERRORS */
443 encode_failed:
444 {
445 GST_ELEMENT_ERROR (voaacenc, STREAM, ENCODE, (NULL), ("encode failed"));
446 ret = GST_FLOW_ERROR;
447 goto exit;
448 }
449 }
450
451 static VO_U32
voaacenc_core_mem_alloc(VO_S32 uID,VO_MEM_INFO * pMemInfo)452 voaacenc_core_mem_alloc (VO_S32 uID, VO_MEM_INFO * pMemInfo)
453 {
454 if (!pMemInfo)
455 return VO_ERR_INVALID_ARG;
456
457 pMemInfo->VBuffer = g_malloc (pMemInfo->Size);
458 return 0;
459 }
460
461 static VO_U32
voaacenc_core_mem_free(VO_S32 uID,VO_PTR pMem)462 voaacenc_core_mem_free (VO_S32 uID, VO_PTR pMem)
463 {
464 g_free (pMem);
465 return 0;
466 }
467
468 static VO_U32
voaacenc_core_mem_set(VO_S32 uID,VO_PTR pBuff,VO_U8 uValue,VO_U32 uSize)469 voaacenc_core_mem_set (VO_S32 uID, VO_PTR pBuff, VO_U8 uValue, VO_U32 uSize)
470 {
471 memset (pBuff, uValue, uSize);
472 return 0;
473 }
474
475 static VO_U32
voaacenc_core_mem_copy(VO_S32 uID,VO_PTR pDest,VO_PTR pSource,VO_U32 uSize)476 voaacenc_core_mem_copy (VO_S32 uID, VO_PTR pDest, VO_PTR pSource, VO_U32 uSize)
477 {
478 memcpy (pDest, pSource, uSize);
479 return 0;
480 }
481
482 static VO_U32
voaacenc_core_mem_check(VO_S32 uID,VO_PTR pBuffer,VO_U32 uSize)483 voaacenc_core_mem_check (VO_S32 uID, VO_PTR pBuffer, VO_U32 uSize)
484 {
485 return 0;
486 }
487
488 static gboolean
voaacenc_core_init(GstVoAacEnc * voaacenc)489 voaacenc_core_init (GstVoAacEnc * voaacenc)
490 {
491 VO_CODEC_INIT_USERDATA user_data = { 0 };
492 voGetAACEncAPI (&voaacenc->codec_api);
493
494 voaacenc->mem_operator.Alloc = voaacenc_core_mem_alloc;
495 voaacenc->mem_operator.Copy = voaacenc_core_mem_copy;
496 voaacenc->mem_operator.Free = voaacenc_core_mem_free;
497 voaacenc->mem_operator.Set = voaacenc_core_mem_set;
498 voaacenc->mem_operator.Check = voaacenc_core_mem_check;
499 user_data.memflag = VO_IMF_USERMEMOPERATOR;
500 user_data.memData = &voaacenc->mem_operator;
501 voaacenc->codec_api.Init (&voaacenc->handle, VO_AUDIO_CodingAAC, &user_data);
502
503 if (voaacenc->handle == NULL) {
504 return FALSE;
505 }
506 return TRUE;
507
508 }
509
510 static gboolean
voaacenc_core_set_parameter(GstVoAacEnc * voaacenc)511 voaacenc_core_set_parameter (GstVoAacEnc * voaacenc)
512 {
513 AACENC_PARAM params = { 0 };
514 guint32 ret;
515
516 params.sampleRate = voaacenc->rate;
517 params.bitRate = voaacenc->bitrate;
518 params.nChannels = voaacenc->channels;
519 if (voaacenc->output_format) {
520 params.adtsUsed = 1;
521 } else {
522 params.adtsUsed = 0;
523 }
524
525 ret =
526 voaacenc->codec_api.SetParam (voaacenc->handle, VO_PID_AAC_ENCPARAM,
527 ¶ms);
528 if (ret != VO_ERR_NONE) {
529 GST_ERROR_OBJECT (voaacenc, "Failed to set encoder parameters");
530 return FALSE;
531 }
532 return TRUE;
533 }
534
535 static void
voaacenc_core_uninit(GstVoAacEnc * voaacenc)536 voaacenc_core_uninit (GstVoAacEnc * voaacenc)
537 {
538 if (voaacenc->handle) {
539 voaacenc->codec_api.Uninit (voaacenc->handle);
540 voaacenc->handle = NULL;
541 }
542 }
543