Tizen 2.0 Release
[framework/multimedia/gst-plugins-bad0.10.git] / ext / voaacenc / gstvoaacenc.c
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., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /**
21  * SECTION:element-voaacenc
22  *
23  * AAC audio encoder based on vo-aacenc library 
24  * <ulink url="http://sourceforge.net/projects/opencore-amr/files/vo-aacenc/">vo-aacenc library source file</ulink>.
25  * 
26  * <refsect2>
27  * <title>Example launch line</title>
28  * |[
29  * gst-launch filesrc location=abc.wav ! wavparse ! audioresample ! audioconvert ! voaacenc ! filesink location=abc.aac
30  * ]|
31  * </refsect2>
32  */
33
34 #ifdef HAVE_CONFIG_H
35 #include "config.h"
36 #endif
37
38 #include <string.h>
39
40 #include <gst/audio/multichannel.h>
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 static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
71     GST_PAD_SINK,
72     GST_PAD_ALWAYS,
73     GST_STATIC_CAPS ("audio/x-raw-int, "
74         "width = (int) 16, "
75         "depth = (int) 16, "
76         "signed = (boolean) TRUE, "
77         "endianness = (int) BYTE_ORDER, "
78         "rate = (int) { " SAMPLE_RATES " }, " "channels = (int) [1, 2]")
79     );
80
81 static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
82     GST_PAD_SRC,
83     GST_PAD_ALWAYS,
84     GST_STATIC_CAPS ("audio/mpeg, "
85         "mpegversion = (int) 4, "
86         "rate = (int) { " SAMPLE_RATES " }, "
87         "channels = (int) [1, 2], "
88         "stream-format = (string) { adts, raw }, " "base-profile = (string) lc")
89     );
90
91 GST_DEBUG_CATEGORY_STATIC (gst_voaacenc_debug);
92 #define GST_CAT_DEFAULT gst_voaacenc_debug
93
94 static gboolean voaacenc_core_init (GstVoAacEnc * voaacenc);
95 static gboolean voaacenc_core_set_parameter (GstVoAacEnc * voaacenc);
96 static void voaacenc_core_uninit (GstVoAacEnc * voaacenc);
97
98 static gboolean gst_voaacenc_start (GstAudioEncoder * enc);
99 static gboolean gst_voaacenc_stop (GstAudioEncoder * enc);
100 static gboolean gst_voaacenc_set_format (GstAudioEncoder * enc,
101     GstAudioInfo * info);
102 static GstFlowReturn gst_voaacenc_handle_frame (GstAudioEncoder * enc,
103     GstBuffer * in_buf);
104 static GstCaps *gst_voaacenc_getcaps (GstAudioEncoder * enc);
105
106 GST_BOILERPLATE (GstVoAacEnc, gst_voaacenc, GstAudioEncoder,
107     GST_TYPE_AUDIO_ENCODER);
108
109 static void
110 gst_voaacenc_set_property (GObject * object, guint prop_id,
111     const GValue * value, GParamSpec * pspec)
112 {
113   GstVoAacEnc *self = GST_VOAACENC (object);
114
115   switch (prop_id) {
116     case PROP_BITRATE:
117       self->bitrate = g_value_get_int (value);
118       break;
119     default:
120       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
121       break;
122   }
123   return;
124 }
125
126 static void
127 gst_voaacenc_get_property (GObject * object, guint prop_id,
128     GValue * value, GParamSpec * pspec)
129 {
130   GstVoAacEnc *self = GST_VOAACENC (object);
131
132   switch (prop_id) {
133     case PROP_BITRATE:
134       g_value_set_int (value, self->bitrate);
135       break;
136     default:
137       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
138       break;
139   }
140   return;
141 }
142
143 static void
144 gst_voaacenc_base_init (gpointer klass)
145 {
146   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
147
148   gst_element_class_add_pad_template (element_class,
149       gst_static_pad_template_get (&sink_template));
150   gst_element_class_add_pad_template (element_class,
151       gst_static_pad_template_get (&src_template));
152
153   gst_element_class_set_details_simple (element_class, "AAC audio encoder",
154       "Codec/Encoder/Audio", "AAC audio encoder", "Kan Hu <kan.hu@linaro.org>");
155 }
156
157 static void
158 gst_voaacenc_class_init (GstVoAacEncClass * klass)
159 {
160   GObjectClass *object_class = G_OBJECT_CLASS (klass);
161   GstAudioEncoderClass *base_class = GST_AUDIO_ENCODER_CLASS (klass);
162
163   object_class->set_property = GST_DEBUG_FUNCPTR (gst_voaacenc_set_property);
164   object_class->get_property = GST_DEBUG_FUNCPTR (gst_voaacenc_get_property);
165
166   base_class->start = GST_DEBUG_FUNCPTR (gst_voaacenc_start);
167   base_class->stop = GST_DEBUG_FUNCPTR (gst_voaacenc_stop);
168   base_class->set_format = GST_DEBUG_FUNCPTR (gst_voaacenc_set_format);
169   base_class->handle_frame = GST_DEBUG_FUNCPTR (gst_voaacenc_handle_frame);
170   base_class->getcaps = GST_DEBUG_FUNCPTR (gst_voaacenc_getcaps);
171
172   g_object_class_install_property (object_class, PROP_BITRATE,
173       g_param_spec_int ("bitrate",
174           "Bitrate",
175           "Target Audio Bitrate",
176           0, G_MAXINT, VOAAC_ENC_DEFAULT_BITRATE,
177           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
178
179   GST_DEBUG_CATEGORY_INIT (gst_voaacenc_debug, "voaacenc", 0, "voaac encoder");
180 }
181
182 static void
183 gst_voaacenc_init (GstVoAacEnc * voaacenc, GstVoAacEncClass * klass)
184 {
185   voaacenc->bitrate = VOAAC_ENC_DEFAULT_BITRATE;
186   voaacenc->output_format = VOAAC_ENC_DEFAULT_OUTPUTFORMAT;
187
188   /* init rest */
189   voaacenc->handle = NULL;
190 }
191
192 static gboolean
193 gst_voaacenc_start (GstAudioEncoder * enc)
194 {
195   GstVoAacEnc *voaacenc = GST_VOAACENC (enc);
196
197   GST_DEBUG_OBJECT (enc, "start");
198
199   if (voaacenc_core_init (voaacenc) == FALSE)
200     return FALSE;
201
202   voaacenc->rate = 0;
203   voaacenc->channels = 0;
204
205   return TRUE;
206 }
207
208 static gboolean
209 gst_voaacenc_stop (GstAudioEncoder * enc)
210 {
211   GstVoAacEnc *voaacenc = GST_VOAACENC (enc);
212
213   GST_DEBUG_OBJECT (enc, "stop");
214   voaacenc_core_uninit (voaacenc);
215
216   return TRUE;
217 }
218
219 static gpointer
220 gst_voaacenc_generate_sink_caps (gpointer data)
221 {
222 #define VOAAC_ENC_MAX_CHANNELS 6
223 /* describe the channels position */
224   static const GstAudioChannelPosition
225       gst_voaacenc_channel_position[][VOAAC_ENC_MAX_CHANNELS] = {
226     {                           /* 1 ch: Mono */
227         GST_AUDIO_CHANNEL_POSITION_FRONT_MONO},
228     {                           /* 2 ch: front left + front right (front stereo) */
229           GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
230         GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT},
231     {                           /* 3 ch: front center + front stereo */
232           GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
233           GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
234         GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT},
235     {                           /* 4 ch: front center + front stereo + back center */
236           GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
237           GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
238           GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
239         GST_AUDIO_CHANNEL_POSITION_REAR_CENTER},
240     {                           /* 5 ch: front center + front stereo + back stereo */
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     {                           /* 6ch: front center + front stereo + back stereo + LFE */
247           GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
248           GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
249           GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
250           GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
251           GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
252         GST_AUDIO_CHANNEL_POSITION_LFE}
253   };
254   GstCaps *caps = gst_caps_new_empty ();
255   gint i, c;
256   static const int rates[] = {
257     8000, 11025, 12000, 16000, 22050, 24000,
258     32000, 44100, 48000, 64000, 88200, 96000
259   };
260   GValue rates_arr = { 0, };
261   GValue tmp = { 0, };
262
263   g_value_init (&rates_arr, GST_TYPE_LIST);
264   g_value_init (&tmp, G_TYPE_INT);
265   for (i = 0; i < G_N_ELEMENTS (rates); i++) {
266     g_value_set_int (&tmp, rates[i]);
267     gst_value_list_append_value (&rates_arr, &tmp);
268   }
269   g_value_unset (&tmp);
270
271   for (i = 0; i < 2 /*VOAAC_ENC_MAX_CHANNELS */ ; i++) {
272     GValue chanpos = { 0 };
273     GValue pos = { 0 };
274     GstStructure *structure;
275
276     g_value_init (&chanpos, GST_TYPE_ARRAY);
277     g_value_init (&pos, GST_TYPE_AUDIO_CHANNEL_POSITION);
278
279     for (c = 0; c <= i; c++) {
280       g_value_set_enum (&pos, gst_voaacenc_channel_position[i][c]);
281       gst_value_array_append_value (&chanpos, &pos);
282     }
283
284     g_value_unset (&pos);
285
286     structure = gst_structure_new ("audio/x-raw-int",
287         "width", G_TYPE_INT, 16,
288         "depth", G_TYPE_INT, 16,
289         "signed", G_TYPE_BOOLEAN, TRUE,
290         "endianness", G_TYPE_INT, G_BYTE_ORDER,
291         "channels", G_TYPE_INT, i + 1, NULL);
292
293     gst_structure_set_value (structure, "rate", &rates_arr);
294     gst_structure_set_value (structure, "channel-positions", &chanpos);
295     g_value_unset (&chanpos);
296
297     gst_caps_append_structure (caps, structure);
298   }
299
300   g_value_unset (&rates_arr);
301
302   GST_DEBUG ("generated sink caps: %" GST_PTR_FORMAT, caps);
303   return caps;
304 }
305
306 static GstCaps *
307 gst_voaacenc_get_sink_caps (void)
308 {
309   static GOnce g_once = G_ONCE_INIT;
310   GstCaps *caps;
311
312   g_once (&g_once, gst_voaacenc_generate_sink_caps, NULL);
313   caps = g_once.retval;
314
315   return caps;
316 }
317
318 static GstCaps *
319 gst_voaacenc_getcaps (GstAudioEncoder * benc)
320 {
321   return gst_audio_encoder_proxy_getcaps (benc, gst_voaacenc_get_sink_caps ());
322 }
323
324 /* check downstream caps to configure format */
325 static void
326 gst_voaacenc_negotiate (GstVoAacEnc * voaacenc)
327 {
328   GstCaps *caps;
329
330   caps = gst_pad_get_allowed_caps (GST_AUDIO_ENCODER_SRC_PAD (voaacenc));
331
332   GST_DEBUG_OBJECT (voaacenc, "allowed caps: %" GST_PTR_FORMAT, caps);
333
334   if (caps && gst_caps_get_size (caps) > 0) {
335     GstStructure *s = gst_caps_get_structure (caps, 0);
336     const gchar *str = NULL;
337
338     if ((str = gst_structure_get_string (s, "stream-format"))) {
339       if (strcmp (str, "adts") == 0) {
340         GST_DEBUG_OBJECT (voaacenc, "use ADTS format for output");
341         voaacenc->output_format = 1;
342       } else if (strcmp (str, "raw") == 0) {
343         GST_DEBUG_OBJECT (voaacenc, "use RAW format for output");
344         voaacenc->output_format = 0;
345       } else {
346         GST_DEBUG_OBJECT (voaacenc, "unknown stream-format: %s", str);
347         voaacenc->output_format = VOAAC_ENC_DEFAULT_OUTPUTFORMAT;
348       }
349     }
350   }
351
352   if (caps)
353     gst_caps_unref (caps);
354 }
355
356 static gint
357 gst_voaacenc_get_rate_index (gint rate)
358 {
359   static const gint rate_table[] = {
360     96000, 88200, 64000, 48000, 44100, 32000,
361     24000, 22050, 16000, 12000, 11025, 8000
362   };
363   gint i;
364   for (i = 0; i < G_N_ELEMENTS (rate_table); ++i) {
365     if (rate == rate_table[i]) {
366       return i;
367     }
368   }
369   return -1;
370 }
371
372 static GstCaps *
373 gst_voaacenc_create_source_pad_caps (GstVoAacEnc * voaacenc)
374 {
375   GstCaps *caps = NULL;
376   GstBuffer *codec_data;
377   gint index;
378   guint8 data[VOAAC_ENC_CODECDATA_LEN];
379
380   if ((index = gst_voaacenc_get_rate_index (voaacenc->rate)) >= 0) {
381     /* LC profile only */
382     data[0] = ((0x02 << 3) | (index >> 1));
383     data[1] = ((index & 0x01) << 7) | (voaacenc->channels << 3);
384
385     caps = gst_caps_new_simple ("audio/mpeg",
386         "mpegversion", G_TYPE_INT, VOAAC_ENC_MPEGVERSION,
387         "channels", G_TYPE_INT, voaacenc->channels,
388         "rate", G_TYPE_INT, voaacenc->rate,
389         "stream-format", G_TYPE_STRING,
390         (voaacenc->output_format ? "adts" : "raw")
391         , NULL);
392
393     gst_codec_utils_aac_caps_set_level_and_profile (caps, data, sizeof (data));
394
395     if (!voaacenc->output_format) {
396       codec_data = gst_buffer_new_and_alloc (VOAAC_ENC_CODECDATA_LEN);
397
398       memcpy (GST_BUFFER_DATA (codec_data), data, sizeof (data));
399
400       gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER, codec_data,
401           NULL);
402
403       gst_buffer_unref (codec_data);
404     }
405   }
406
407   return caps;
408 }
409
410 static gboolean
411 gst_voaacenc_set_format (GstAudioEncoder * benc, GstAudioInfo * info)
412 {
413   gboolean ret = FALSE;
414   GstVoAacEnc *voaacenc;
415   GstCaps *src_caps;
416
417   voaacenc = GST_VOAACENC (benc);
418
419   /* get channel count */
420   voaacenc->channels = GST_AUDIO_INFO_CHANNELS (info);
421   voaacenc->rate = GST_AUDIO_INFO_RATE (info);
422
423   /* precalc buffer size as it's constant now */
424   voaacenc->inbuf_size = voaacenc->channels * 2 * 1024;
425
426   gst_voaacenc_negotiate (voaacenc);
427
428   /* create reverse caps */
429   src_caps = gst_voaacenc_create_source_pad_caps (voaacenc);
430
431   if (src_caps) {
432     gst_pad_set_caps (GST_AUDIO_ENCODER_SRC_PAD (voaacenc), src_caps);
433     gst_caps_unref (src_caps);
434     ret = voaacenc_core_set_parameter (voaacenc);
435   }
436
437   /* report needs to base class */
438   gst_audio_encoder_set_frame_samples_min (benc, 1024);
439   gst_audio_encoder_set_frame_samples_max (benc, 1024);
440   gst_audio_encoder_set_frame_max (benc, 1);
441
442   return ret;
443 }
444
445 static GstFlowReturn
446 gst_voaacenc_handle_frame (GstAudioEncoder * benc, GstBuffer * buf)
447 {
448   GstVoAacEnc *voaacenc;
449   GstFlowReturn ret = GST_FLOW_OK;
450   GstBuffer *out;
451   VO_AUDIO_OUTPUTINFO output_info = { {0} };
452   VO_CODECBUFFER input = { 0 };
453   VO_CODECBUFFER output = { 0 };
454
455   voaacenc = GST_VOAACENC (benc);
456
457   g_return_val_if_fail (voaacenc->handle, GST_FLOW_NOT_NEGOTIATED);
458
459   if (voaacenc->rate == 0 || voaacenc->channels == 0)
460     goto not_negotiated;
461
462   /* we don't deal with squeezing remnants, so simply discard those */
463   if (G_UNLIKELY (buf == NULL)) {
464     GST_DEBUG_OBJECT (benc, "no data");
465     goto exit;
466   }
467
468   if (G_UNLIKELY (GST_BUFFER_SIZE (buf) < voaacenc->inbuf_size)) {
469     GST_DEBUG_OBJECT (voaacenc, "discarding trailing data %d",
470         buf ? GST_BUFFER_SIZE (buf) : 0);
471     ret = gst_audio_encoder_finish_frame (benc, NULL, -1);
472     goto exit;
473   }
474
475   /* max size */
476   if ((ret =
477           gst_pad_alloc_buffer_and_set_caps (GST_AUDIO_ENCODER_SRC_PAD
478               (voaacenc), 0, voaacenc->inbuf_size,
479               GST_PAD_CAPS (GST_AUDIO_ENCODER_SRC_PAD (voaacenc)),
480               &out)) != GST_FLOW_OK) {
481     goto exit;
482   }
483
484   output.Buffer = GST_BUFFER_DATA (out);
485   output.Length = voaacenc->inbuf_size;
486
487   g_assert (GST_BUFFER_SIZE (buf) == voaacenc->inbuf_size);
488   input.Buffer = GST_BUFFER_DATA (buf);
489   input.Length = voaacenc->inbuf_size;
490   voaacenc->codec_api.SetInputData (voaacenc->handle, &input);
491
492   /* encode */
493   if (voaacenc->codec_api.GetOutputData (voaacenc->handle, &output,
494           &output_info) != VO_ERR_NONE) {
495     gst_buffer_unref (out);
496     goto encode_failed;
497   }
498
499   GST_LOG_OBJECT (voaacenc, "encoded to %d bytes", output.Length);
500   GST_BUFFER_SIZE (out) = output.Length;
501
502   GST_LOG_OBJECT (voaacenc, "Pushing out buffer time: %" GST_TIME_FORMAT
503       " duration: %" GST_TIME_FORMAT,
504       GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (out)),
505       GST_TIME_ARGS (GST_BUFFER_DURATION (out)));
506
507   ret = gst_audio_encoder_finish_frame (benc, out, 1024);
508
509 exit:
510   return ret;
511
512   /* ERRORS */
513 not_negotiated:
514   {
515     GST_ELEMENT_ERROR (voaacenc, STREAM, TYPE_NOT_FOUND,
516         (NULL), ("unknown type"));
517     ret = GST_FLOW_NOT_NEGOTIATED;
518     goto exit;
519   }
520 encode_failed:
521   {
522     GST_ELEMENT_ERROR (voaacenc, STREAM, ENCODE, (NULL), ("encode failed"));
523     ret = GST_FLOW_ERROR;
524     goto exit;
525   }
526 }
527
528 static VO_U32
529 voaacenc_core_mem_alloc (VO_S32 uID, VO_MEM_INFO * pMemInfo)
530 {
531   if (!pMemInfo)
532     return VO_ERR_INVALID_ARG;
533
534   pMemInfo->VBuffer = g_malloc (pMemInfo->Size);
535   return 0;
536 }
537
538 static VO_U32
539 voaacenc_core_mem_free (VO_S32 uID, VO_PTR pMem)
540 {
541   g_free (pMem);
542   return 0;
543 }
544
545 static VO_U32
546 voaacenc_core_mem_set (VO_S32 uID, VO_PTR pBuff, VO_U8 uValue, VO_U32 uSize)
547 {
548   memset (pBuff, uValue, uSize);
549   return 0;
550 }
551
552 static VO_U32
553 voaacenc_core_mem_copy (VO_S32 uID, VO_PTR pDest, VO_PTR pSource, VO_U32 uSize)
554 {
555   memcpy (pDest, pSource, uSize);
556   return 0;
557 }
558
559 static VO_U32
560 voaacenc_core_mem_check (VO_S32 uID, VO_PTR pBuffer, VO_U32 uSize)
561 {
562   return 0;
563 }
564
565 static gboolean
566 voaacenc_core_init (GstVoAacEnc * voaacenc)
567 {
568   VO_CODEC_INIT_USERDATA user_data = { 0 };
569   voGetAACEncAPI (&voaacenc->codec_api);
570
571   voaacenc->mem_operator.Alloc = voaacenc_core_mem_alloc;
572   voaacenc->mem_operator.Copy = voaacenc_core_mem_copy;
573   voaacenc->mem_operator.Free = voaacenc_core_mem_free;
574   voaacenc->mem_operator.Set = voaacenc_core_mem_set;
575   voaacenc->mem_operator.Check = voaacenc_core_mem_check;
576   user_data.memflag = VO_IMF_USERMEMOPERATOR;
577   user_data.memData = &voaacenc->mem_operator;
578   voaacenc->codec_api.Init (&voaacenc->handle, VO_AUDIO_CodingAAC, &user_data);
579
580   if (voaacenc->handle == NULL) {
581     return FALSE;
582   }
583   return TRUE;
584
585 }
586
587 static gboolean
588 voaacenc_core_set_parameter (GstVoAacEnc * voaacenc)
589 {
590   AACENC_PARAM params = { 0 };
591   guint32 ret;
592
593   params.sampleRate = voaacenc->rate;
594   params.bitRate = voaacenc->bitrate;
595   params.nChannels = voaacenc->channels;
596   if (voaacenc->output_format) {
597     params.adtsUsed = 1;
598   } else {
599     params.adtsUsed = 0;
600   }
601
602   ret =
603       voaacenc->codec_api.SetParam (voaacenc->handle, VO_PID_AAC_ENCPARAM,
604       &params);
605   if (ret != VO_ERR_NONE) {
606     GST_ERROR_OBJECT (voaacenc, "Failed to set encoder parameters");
607     return FALSE;
608   }
609   return TRUE;
610 }
611
612 static void
613 voaacenc_core_uninit (GstVoAacEnc * voaacenc)
614 {
615   if (voaacenc->handle) {
616     voaacenc->codec_api.Uninit (voaacenc->handle);
617     voaacenc->handle = NULL;
618   }
619 }