faac: Detect output format from downstream caps change unit test
[platform/upstream/gstreamer.git] / ext / faac / gstfaac.c
1 /* GStreamer FAAC (Free AAC Encoder) plugin
2  * Copyright (C) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net>
3  * Copyright (C) 2009 Mark Nauwelaerts <mnauw@users.sourceforge.net>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20
21 /**
22  * SECTION:element-faac
23  * @see_also: faad
24  *
25  * faac encodes raw audio to AAC (MPEG-4 part 3) streams.
26  *
27  *
28  * The #GstFaac:profile property determines the AAC profile, where the default
29  * LC (Low Complexity) profile is most widely used, supported and suitable for
30  * general use. The other profiles are very rarely used and often not supported.
31  *
32  * <refsect2>
33  * <title>Example launch line</title>
34  * |[
35  * gst-launch audiotestsrc wave=sine num-buffers=100 ! audioconvert ! faac ! matroskamux ! filesink location=sine.mkv
36  * ]| Encode a sine beep as aac and write to matroska container.
37  * </refsect2>
38  */
39
40 #ifdef HAVE_CONFIG_H
41 #include "config.h"
42 #endif
43 #include <stdlib.h>
44 #include <string.h>
45
46 #include <gst/audio/multichannel.h>
47
48 #include "gstfaac.h"
49
50 #define SINK_CAPS \
51     "audio/x-raw-int, "                \
52     "endianness = (int) BYTE_ORDER, "  \
53     "signed = (boolean) true, "        \
54     "width = (int) 16, "               \
55     "depth = (int) 16, "               \
56     "rate = (int) [ 8000, 96000 ], "   \
57     "channels = (int) [ 1, 6 ] "
58
59 /* these don't seem to work? */
60 #if 0
61 "audio/x-raw-int, "
62     "endianness = (int) BYTE_ORDER, "
63     "signed = (boolean) true, "
64     "width = (int) 32, "
65     "depth = (int) { 24, 32 }, "
66     "rate = (int) [ 8000, 96000], "
67     "channels = (int) [ 1, 6]; "
68     "audio/x-raw-float, "
69     "endianness = (int) BYTE_ORDER, "
70     "width = (int) 32, "
71     "rate = (int) [ 8000, 96000], " "channels = (int) [ 1, 6]"
72 #endif
73 #define SRC_CAPS \
74     "audio/mpeg, "                     \
75     "mpegversion = (int) { 4, 2 }, "   \
76     "channels = (int) [ 1, 6 ], "      \
77     "rate = (int) [ 8000, 96000 ], "   \
78     "stream-format = (string) { adts, raw } "
79 static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
80     GST_PAD_SRC,
81     GST_PAD_ALWAYS,
82     GST_STATIC_CAPS (SRC_CAPS));
83
84 static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
85     GST_PAD_SINK,
86     GST_PAD_ALWAYS,
87     GST_STATIC_CAPS (SINK_CAPS));
88
89 enum
90 {
91   ARG_0,
92   ARG_BITRATE,
93   ARG_PROFILE,
94   ARG_TNS,
95   ARG_MIDSIDE,
96   ARG_SHORTCTL
97 };
98
99 static void gst_faac_base_init (GstFaacClass * klass);
100 static void gst_faac_class_init (GstFaacClass * klass);
101 static void gst_faac_init (GstFaac * faac);
102 static void gst_faac_finalize (GObject * object);
103 static void gst_faac_reset (GstFaac * faac);
104
105 static void gst_faac_set_property (GObject * object,
106     guint prop_id, const GValue * value, GParamSpec * pspec);
107 static void gst_faac_get_property (GObject * object,
108     guint prop_id, GValue * value, GParamSpec * pspec);
109
110 static gboolean gst_faac_sink_event (GstPad * pad, GstEvent * event);
111 static gboolean gst_faac_configure_source_pad (GstFaac * faac);
112 static gboolean gst_faac_sink_setcaps (GstPad * pad, GstCaps * caps);
113 static GstCaps *gst_faac_sink_getcaps (GstPad * pad);
114 static GstFlowReturn gst_faac_push_buffers (GstFaac * faac, gboolean force);
115 static GstFlowReturn gst_faac_chain (GstPad * pad, GstBuffer * data);
116 static GstStateChangeReturn gst_faac_change_state (GstElement * element,
117     GstStateChange transition);
118
119 static GstElementClass *parent_class = NULL;
120
121 GST_DEBUG_CATEGORY_STATIC (faac_debug);
122 #define GST_CAT_DEFAULT faac_debug
123
124 #define FAAC_DEFAULT_MPEGVERSION 4
125 #define FAAC_DEFAULT_OUTPUTFORMAT 0     /* RAW */
126 #define FAAC_DEFAULT_BITRATE      128 * 1000
127 #define FAAC_DEFAULT_PROFILE      LOW
128 #define FAAC_DEFAULT_TNS          FALSE
129 #define FAAC_DEFAULT_MIDSIDE      TRUE
130 #define FAAC_DEFAULT_SHORTCTL     SHORTCTL_NORMAL
131
132 GType
133 gst_faac_get_type (void)
134 {
135   static GType gst_faac_type = 0;
136
137   if (!gst_faac_type) {
138     static const GTypeInfo gst_faac_info = {
139       sizeof (GstFaacClass),
140       (GBaseInitFunc) gst_faac_base_init,
141       NULL,
142       (GClassInitFunc) gst_faac_class_init,
143       NULL,
144       NULL,
145       sizeof (GstFaac),
146       0,
147       (GInstanceInitFunc) gst_faac_init,
148     };
149     const GInterfaceInfo preset_interface_info = {
150       NULL,                     /* interface_init */
151       NULL,                     /* interface_finalize */
152       NULL                      /* interface_data */
153     };
154
155     gst_faac_type = g_type_register_static (GST_TYPE_ELEMENT,
156         "GstFaac", &gst_faac_info, 0);
157
158     g_type_add_interface_static (gst_faac_type, GST_TYPE_PRESET,
159         &preset_interface_info);
160   }
161
162   return gst_faac_type;
163 }
164
165 static void
166 gst_faac_base_init (GstFaacClass * klass)
167 {
168   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
169
170   gst_element_class_add_pad_template (element_class,
171       gst_static_pad_template_get (&src_template));
172   gst_element_class_add_pad_template (element_class,
173       gst_static_pad_template_get (&sink_template));
174
175   gst_element_class_set_details_simple (element_class, "AAC audio encoder",
176       "Codec/Encoder/Audio",
177       "Free MPEG-2/4 AAC encoder",
178       "Ronald Bultje <rbultje@ronald.bitfreak.net>");
179
180   GST_DEBUG_CATEGORY_INIT (faac_debug, "faac", 0, "AAC encoding");
181 }
182
183 #define GST_TYPE_FAAC_PROFILE (gst_faac_profile_get_type ())
184 static GType
185 gst_faac_profile_get_type (void)
186 {
187   static GType gst_faac_profile_type = 0;
188
189   if (!gst_faac_profile_type) {
190     static GEnumValue gst_faac_profile[] = {
191       {MAIN, "MAIN", "Main profile"},
192       {LOW, "LC", "Low complexity profile"},
193       {SSR, "SSR", "Scalable sampling rate profile"},
194       {LTP, "LTP", "Long term prediction profile"},
195       {0, NULL, NULL},
196     };
197
198     gst_faac_profile_type = g_enum_register_static ("GstFaacProfile",
199         gst_faac_profile);
200   }
201
202   return gst_faac_profile_type;
203 }
204
205 #define GST_TYPE_FAAC_SHORTCTL (gst_faac_shortctl_get_type ())
206 static GType
207 gst_faac_shortctl_get_type (void)
208 {
209   static GType gst_faac_shortctl_type = 0;
210
211   if (!gst_faac_shortctl_type) {
212     static GEnumValue gst_faac_shortctl[] = {
213       {SHORTCTL_NORMAL, "SHORTCTL_NORMAL", "Normal block type"},
214       {SHORTCTL_NOSHORT, "SHORTCTL_NOSHORT", "No short blocks"},
215       {SHORTCTL_NOLONG, "SHORTCTL_NOLONG", "No long blocks"},
216       {0, NULL, NULL},
217     };
218
219     gst_faac_shortctl_type = g_enum_register_static ("GstFaacShortCtl",
220         gst_faac_shortctl);
221   }
222
223   return gst_faac_shortctl_type;
224 }
225
226 static void
227 gst_faac_class_init (GstFaacClass * klass)
228 {
229   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
230   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
231
232   parent_class = g_type_class_peek_parent (klass);
233
234   gobject_class->set_property = gst_faac_set_property;
235   gobject_class->get_property = gst_faac_get_property;
236   gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_faac_finalize);
237
238   /* properties */
239   g_object_class_install_property (gobject_class, ARG_BITRATE,
240       g_param_spec_int ("bitrate", "Bitrate (bps)", "Bitrate in bits/sec",
241           8 * 1000, 320 * 1000, FAAC_DEFAULT_BITRATE,
242           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
243   g_object_class_install_property (gobject_class, ARG_PROFILE,
244       g_param_spec_enum ("profile", "Profile", "MPEG/AAC encoding profile",
245           GST_TYPE_FAAC_PROFILE, FAAC_DEFAULT_PROFILE,
246           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
247   g_object_class_install_property (gobject_class, ARG_TNS,
248       g_param_spec_boolean ("tns", "TNS", "Use temporal noise shaping",
249           FAAC_DEFAULT_TNS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
250   g_object_class_install_property (gobject_class, ARG_MIDSIDE,
251       g_param_spec_boolean ("midside", "Midside", "Allow mid/side encoding",
252           FAAC_DEFAULT_MIDSIDE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
253   g_object_class_install_property (gobject_class, ARG_SHORTCTL,
254       g_param_spec_enum ("shortctl", "Block type",
255           "Block type encorcing",
256           GST_TYPE_FAAC_SHORTCTL, FAAC_DEFAULT_SHORTCTL,
257           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
258
259   /* virtual functions */
260   gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_faac_change_state);
261 }
262
263 static void
264 gst_faac_init (GstFaac * faac)
265 {
266   faac->sinkpad = gst_pad_new_from_static_template (&sink_template, "sink");
267   gst_pad_set_chain_function (faac->sinkpad,
268       GST_DEBUG_FUNCPTR (gst_faac_chain));
269   gst_pad_set_setcaps_function (faac->sinkpad,
270       GST_DEBUG_FUNCPTR (gst_faac_sink_setcaps));
271   gst_pad_set_getcaps_function (faac->sinkpad,
272       GST_DEBUG_FUNCPTR (gst_faac_sink_getcaps));
273   gst_pad_set_event_function (faac->sinkpad,
274       GST_DEBUG_FUNCPTR (gst_faac_sink_event));
275   gst_element_add_pad (GST_ELEMENT (faac), faac->sinkpad);
276
277   faac->srcpad = gst_pad_new_from_static_template (&src_template, "src");
278   gst_pad_use_fixed_caps (faac->srcpad);
279   gst_element_add_pad (GST_ELEMENT (faac), faac->srcpad);
280
281   faac->adapter = gst_adapter_new ();
282
283   /* default properties */
284   faac->bitrate = FAAC_DEFAULT_BITRATE;
285   faac->profile = FAAC_DEFAULT_PROFILE;
286   faac->shortctl = FAAC_DEFAULT_SHORTCTL;
287   faac->outputformat = FAAC_DEFAULT_OUTPUTFORMAT;
288   faac->tns = FAAC_DEFAULT_TNS;
289   faac->midside = FAAC_DEFAULT_MIDSIDE;
290
291   gst_faac_reset (faac);
292 }
293
294 static void
295 gst_faac_reset (GstFaac * faac)
296 {
297   faac->handle = NULL;
298   faac->samplerate = -1;
299   faac->channels = -1;
300   faac->offset = 0;
301   gst_adapter_clear (faac->adapter);
302 }
303
304 static void
305 gst_faac_finalize (GObject * object)
306 {
307   GstFaac *faac = (GstFaac *) object;
308
309   g_object_unref (faac->adapter);
310
311   G_OBJECT_CLASS (parent_class)->finalize (object);
312 }
313
314 static void
315 gst_faac_close_encoder (GstFaac * faac)
316 {
317   if (faac->handle)
318     faacEncClose (faac->handle);
319   faac->handle = NULL;
320   gst_adapter_clear (faac->adapter);
321   faac->offset = 0;
322 }
323
324 static const GstAudioChannelPosition aac_channel_positions[][8] = {
325   {GST_AUDIO_CHANNEL_POSITION_FRONT_MONO},
326   {GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
327       GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT},
328   {
329         GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
330         GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
331         GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
332       },
333   {
334         GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
335         GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
336         GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
337       GST_AUDIO_CHANNEL_POSITION_REAR_CENTER},
338   {
339         GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
340         GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
341         GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
342         GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
343       GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT},
344   {
345         GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
346         GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
347         GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
348         GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
349         GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
350       GST_AUDIO_CHANNEL_POSITION_LFE}
351 };
352
353 static GstCaps *
354 gst_faac_sink_getcaps (GstPad * pad)
355 {
356   static volatile gsize sinkcaps = 0;
357
358   if (g_once_init_enter (&sinkcaps)) {
359     GstCaps *tmp = gst_caps_new_empty ();
360     GstStructure *s, *t;
361     gint i, c;
362
363     s = gst_structure_new ("audio/x-raw-int",
364         "endianness", G_TYPE_INT, G_BYTE_ORDER,
365         "signed", G_TYPE_BOOLEAN, TRUE,
366         "width", G_TYPE_INT, 16,
367         "depth", G_TYPE_INT, 16, "rate", GST_TYPE_INT_RANGE, 8000, 96000, NULL);
368
369     for (i = 1; i <= 6; i++) {
370       GValue chanpos = { 0 };
371       GValue pos = { 0 };
372
373       t = gst_structure_copy (s);
374
375       gst_structure_set (t, "channels", G_TYPE_INT, i, NULL);
376
377       g_value_init (&chanpos, GST_TYPE_ARRAY);
378       g_value_init (&pos, GST_TYPE_AUDIO_CHANNEL_POSITION);
379
380       for (c = 0; c < i; c++) {
381         g_value_set_enum (&pos, aac_channel_positions[i - 1][c]);
382         gst_value_array_append_value (&chanpos, &pos);
383       }
384       g_value_unset (&pos);
385
386       gst_structure_set_value (t, "channel-positions", &chanpos);
387       g_value_unset (&chanpos);
388       gst_caps_append_structure (tmp, t);
389     }
390     gst_structure_free (s);
391
392     GST_DEBUG_OBJECT (pad, "Generated sinkcaps: %" GST_PTR_FORMAT, tmp);
393
394     g_once_init_leave (&sinkcaps, (gsize) tmp);
395   }
396
397   return gst_caps_ref ((GstCaps *) sinkcaps);
398 }
399
400 /* check downstream caps to configure format */
401 static void
402 gst_faac_negotiate (GstFaac * faac)
403 {
404   GstCaps *caps;
405
406   caps = gst_pad_get_allowed_caps (faac->srcpad);
407
408   GST_DEBUG_OBJECT (faac, "allowed caps: %" GST_PTR_FORMAT, caps);
409
410   if (caps && gst_caps_get_size (caps) > 0) {
411     GstStructure *s = gst_caps_get_structure (caps, 0);
412     const gchar *str = NULL;
413
414     if ((str = gst_structure_get_string (s, "stream-format"))) {
415       if (strcmp (str, "adts") == 0) {
416         GST_DEBUG_OBJECT (faac, "use ADTS format for output");
417         faac->outputformat = 1;
418       } else if (strcmp (str, "raw") == 0) {
419         GST_DEBUG_OBJECT (faac, "use RAW format for output");
420         faac->outputformat = 0;
421       } else {
422         GST_DEBUG_OBJECT (faac, "unknown stream-format: %s", str);
423         faac->outputformat = 0;
424       }
425     }
426   }
427
428   if (caps)
429     gst_caps_unref (caps);
430
431 }
432
433 static gboolean
434 gst_faac_sink_setcaps (GstPad * pad, GstCaps * caps)
435 {
436   GstFaac *faac = GST_FAAC (gst_pad_get_parent (pad));
437   GstStructure *structure = gst_caps_get_structure (caps, 0);
438   faacEncHandle *handle;
439   gint channels, samplerate, width;
440   gulong samples, bytes, fmt = 0, bps = 0;
441   gboolean result = FALSE;
442
443   if (!gst_caps_is_fixed (caps))
444     goto refuse_caps;
445
446   if (!gst_structure_get_int (structure, "channels", &channels) ||
447       !gst_structure_get_int (structure, "rate", &samplerate)) {
448     goto refuse_caps;
449   }
450
451   if (gst_structure_has_name (structure, "audio/x-raw-int")) {
452     gst_structure_get_int (structure, "width", &width);
453     switch (width) {
454       case 16:
455         fmt = FAAC_INPUT_16BIT;
456         bps = 2;
457         break;
458       case 24:
459       case 32:
460         fmt = FAAC_INPUT_32BIT;
461         bps = 4;
462         break;
463       default:
464         g_return_val_if_reached (FALSE);
465     }
466   } else if (gst_structure_has_name (structure, "audio/x-raw-float")) {
467     fmt = FAAC_INPUT_FLOAT;
468     bps = 4;
469   }
470
471   if (!fmt)
472     goto refuse_caps;
473
474   /* If the encoder is initialized, do not
475      reinitialize it again if not necessary */
476   if (faac->handle) {
477     if (samplerate == faac->samplerate && channels == faac->channels &&
478         fmt == faac->format)
479       return TRUE;
480
481     /* clear out pending frames */
482     gst_faac_push_buffers (faac, TRUE);
483
484     gst_faac_close_encoder (faac);
485   }
486
487   if (!(handle = faacEncOpen (samplerate, channels, &samples, &bytes)))
488     goto setup_failed;
489
490   /* ok, record and set up */
491   faac->format = fmt;
492   faac->bps = bps;
493   faac->handle = handle;
494   faac->bytes = bytes;
495   faac->samples = samples;
496   faac->channels = channels;
497   faac->samplerate = samplerate;
498
499   gst_faac_negotiate (faac);
500
501   /* finish up */
502   result = gst_faac_configure_source_pad (faac);
503
504 done:
505   gst_object_unref (faac);
506   return result;
507
508   /* ERRORS */
509 setup_failed:
510   {
511     GST_ELEMENT_ERROR (faac, LIBRARY, SETTINGS, (NULL), (NULL));
512     goto done;
513   }
514 refuse_caps:
515   {
516     GST_WARNING_OBJECT (faac, "refused caps %" GST_PTR_FORMAT, caps);
517     goto done;
518   }
519 }
520
521 static gboolean
522 gst_faac_configure_source_pad (GstFaac * faac)
523 {
524   GstCaps *allowed_caps;
525   GstCaps *srccaps;
526   gboolean ret = FALSE;
527   gint n, ver, mpegversion = 2;
528   faacEncConfiguration *conf;
529   guint maxbitrate;
530
531   mpegversion = FAAC_DEFAULT_MPEGVERSION;
532
533   allowed_caps = gst_pad_get_allowed_caps (faac->srcpad);
534   GST_DEBUG_OBJECT (faac, "allowed caps: %" GST_PTR_FORMAT, allowed_caps);
535
536   if (allowed_caps) {
537     if (gst_caps_is_empty (allowed_caps))
538       goto empty_caps;
539
540     if (!gst_caps_is_any (allowed_caps)) {
541       for (n = 0; n < gst_caps_get_size (allowed_caps); n++) {
542         GstStructure *s = gst_caps_get_structure (allowed_caps, n);
543
544         if (gst_structure_get_int (s, "mpegversion", &ver) &&
545             (ver == 4 || ver == 2)) {
546           mpegversion = ver;
547           break;
548         }
549       }
550     }
551     gst_caps_unref (allowed_caps);
552   }
553
554   /* we negotiated caps update current configuration */
555   conf = faacEncGetCurrentConfiguration (faac->handle);
556   conf->mpegVersion = (mpegversion == 4) ? MPEG4 : MPEG2;
557   conf->aacObjectType = faac->profile;
558   conf->allowMidside = faac->midside;
559   conf->useLfe = 0;
560   conf->useTns = faac->tns;
561   conf->bitRate = faac->bitrate / faac->channels;
562   conf->inputFormat = faac->format;
563   conf->outputFormat = faac->outputformat;
564   conf->shortctl = faac->shortctl;
565
566   /* check, warn and correct if the max bitrate for the given samplerate is
567    * exceeded. Maximum of 6144 bit for a channel */
568   maxbitrate =
569       (unsigned int) (6144.0 * (double) faac->samplerate / (double) 1024.0 +
570       .5);
571   if (conf->bitRate > maxbitrate) {
572     GST_ELEMENT_WARNING (faac, RESOURCE, SETTINGS, (NULL),
573         ("bitrate %lu exceeds maximum allowed bitrate of %u for samplerate %d. "
574             "Setting bitrate to %u", conf->bitRate, maxbitrate,
575             faac->samplerate, maxbitrate));
576     conf->bitRate = maxbitrate;
577   }
578
579   /* default 0 to start with, libfaac chooses based on bitrate */
580   conf->bandWidth = 0;
581
582   if (!faacEncSetConfiguration (faac->handle, conf))
583     goto set_failed;
584
585   /* let's see what really happened,
586    * note that this may not really match desired rate */
587   GST_DEBUG_OBJECT (faac, "average bitrate: %lu kbps",
588       (conf->bitRate + 500) / 1000 * faac->channels);
589   GST_DEBUG_OBJECT (faac, "quantization quality: %ld", conf->quantqual);
590   GST_DEBUG_OBJECT (faac, "bandwidth: %d Hz", conf->bandWidth);
591
592   /* now create a caps for it all */
593   srccaps = gst_caps_new_simple ("audio/mpeg",
594       "mpegversion", G_TYPE_INT, mpegversion,
595       "channels", G_TYPE_INT, faac->channels,
596       "rate", G_TYPE_INT, faac->samplerate,
597       "stream-format", G_TYPE_STRING, (faac->outputformat ? "adts" : "raw"),
598       NULL);
599
600   if (!faac->outputformat) {
601     GstBuffer *codec_data;
602     guint8 *config = NULL;
603     gulong config_len = 0;
604
605     /* get the config string */
606     GST_DEBUG_OBJECT (faac, "retrieving decoder info");
607     faacEncGetDecoderSpecificInfo (faac->handle, &config, &config_len);
608
609     /* copy it into a buffer */
610     codec_data = gst_buffer_new_and_alloc (config_len);
611     memcpy (GST_BUFFER_DATA (codec_data), config, config_len);
612     free (config);
613
614     /* add to caps */
615     gst_caps_set_simple (srccaps,
616         "codec_data", GST_TYPE_BUFFER, codec_data, NULL);
617
618     gst_buffer_unref (codec_data);
619   }
620
621   GST_DEBUG_OBJECT (faac, "src pad caps: %" GST_PTR_FORMAT, srccaps);
622
623   ret = gst_pad_set_caps (faac->srcpad, srccaps);
624   gst_caps_unref (srccaps);
625
626   return ret;
627
628   /* ERROR */
629 empty_caps:
630   {
631     gst_caps_unref (allowed_caps);
632     return FALSE;
633   }
634 set_failed:
635   {
636     GST_WARNING_OBJECT (faac, "Faac doesn't support the current configuration");
637     return FALSE;
638   }
639 }
640
641 static GstFlowReturn
642 gst_faac_push_buffers (GstFaac * faac, gboolean force)
643 {
644   GstFlowReturn ret = GST_FLOW_OK;
645   gint av, frame_size, size, ret_size;
646   GstBuffer *outbuf;
647   guint64 timestamp, distance;
648   const guint8 *data;
649
650   /* samples already considers channel count */
651   frame_size = faac->samples * faac->bps;
652
653   while (G_LIKELY (ret == GST_FLOW_OK)) {
654
655     av = gst_adapter_available (faac->adapter);
656
657     GST_LOG_OBJECT (faac, "pushing: force: %d, frame_size: %d, av: %d, "
658         "offset: %d", force, frame_size, av, faac->offset);
659
660     /* idea:
661      * - start of adapter corresponds with what has already been encoded
662      * (i.e. really returned by faac)
663      * - start + offset is what needs to be fed to faac next
664      * That way we can timestamp the output based
665      * on adapter provided timestamp (and duration is a fixed frame duration) */
666
667     /* not enough data for one frame and no flush forcing */
668     if (!force && (av < frame_size + faac->offset))
669       break;
670
671     if (G_LIKELY (av - faac->offset >= frame_size)) {
672       GST_LOG_OBJECT (faac, "encoding a frame");
673       data = gst_adapter_peek (faac->adapter, faac->offset + frame_size);
674       data += faac->offset;
675       size = frame_size;
676     } else if (av - faac->offset > 0) {
677       GST_LOG_OBJECT (faac, "encoding leftover");
678       data = gst_adapter_peek (faac->adapter, av);
679       data += faac->offset;
680       size = av - faac->offset;
681     } else {
682       GST_LOG_OBJECT (faac, "emptying encoder");
683       data = NULL;
684       size = 0;
685     }
686
687     outbuf = gst_buffer_new_and_alloc (faac->bytes);
688
689     if (G_UNLIKELY ((ret_size = faacEncEncode (faac->handle, (gint32 *) data,
690                     size / faac->bps, GST_BUFFER_DATA (outbuf),
691                     faac->bytes)) < 0)) {
692       gst_buffer_unref (outbuf);
693       goto encode_failed;
694     }
695
696     GST_LOG_OBJECT (faac, "encoder return: %d", ret_size);
697
698     /* consumed, advanced view */
699     faac->offset += size;
700     g_assert (faac->offset <= av);
701
702     if (G_UNLIKELY (!ret_size)) {
703       gst_buffer_unref (outbuf);
704       if (size)
705         continue;
706       else
707         break;
708     }
709
710     /* deal with encoder lead-out */
711     if (G_UNLIKELY (av == 0 && faac->offset == 0)) {
712       GST_DEBUG_OBJECT (faac, "encoder returned additional data");
713       /* continuous with previous output, ok to have 0 duration */
714       timestamp = faac->next_ts;
715     } else {
716       /* after some caching, finally some data */
717       /* adapter gives time */
718       timestamp = gst_adapter_prev_timestamp (faac->adapter, &distance);
719     }
720
721     if (G_LIKELY ((av = gst_adapter_available (faac->adapter)) >= frame_size)) {
722       /* must have then come from a complete frame */
723       gst_adapter_flush (faac->adapter, frame_size);
724       faac->offset -= frame_size;
725       size = frame_size;
726     } else {
727       /* otherwise leftover */
728       gst_adapter_clear (faac->adapter);
729       faac->offset = 0;
730       size = av;
731     }
732
733     GST_BUFFER_SIZE (outbuf) = ret_size;
734     if (G_LIKELY (GST_CLOCK_TIME_IS_VALID (timestamp)))
735       GST_BUFFER_TIMESTAMP (outbuf) = timestamp +
736           GST_FRAMES_TO_CLOCK_TIME (distance / faac->channels / faac->bps,
737           faac->samplerate);
738     GST_BUFFER_DURATION (outbuf) =
739         GST_FRAMES_TO_CLOCK_TIME (size / faac->channels / faac->bps,
740         faac->samplerate);
741     faac->next_ts =
742         GST_BUFFER_TIMESTAMP (outbuf) + GST_BUFFER_DURATION (outbuf);
743
744     /* perhaps check/set DISCONT based on timestamps ? */
745
746     GST_LOG_OBJECT (faac, "Pushing out buffer time: %" GST_TIME_FORMAT
747         " duration: %" GST_TIME_FORMAT,
748         GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
749         GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)));
750
751     gst_buffer_set_caps (outbuf, GST_PAD_CAPS (faac->srcpad));
752     ret = gst_pad_push (faac->srcpad, outbuf);
753   }
754
755   /* in case encoder returns less than expected, clear our view as well */
756   if (G_UNLIKELY (force)) {
757 #ifndef GST_DISABLE_GST_DEBUG
758     if ((av = gst_adapter_available (faac->adapter)))
759       GST_WARNING_OBJECT (faac, "encoder left %d bytes; discarding", av);
760 #endif
761     gst_adapter_clear (faac->adapter);
762     faac->offset = 0;
763   }
764
765   return ret;
766
767   /* ERRORS */
768 encode_failed:
769   {
770     GST_ELEMENT_ERROR (faac, LIBRARY, ENCODE, (NULL), (NULL));
771     return GST_FLOW_ERROR;
772   }
773 }
774
775 static gboolean
776 gst_faac_sink_event (GstPad * pad, GstEvent * event)
777 {
778   GstFaac *faac;
779   gboolean ret;
780
781   faac = GST_FAAC (gst_pad_get_parent (pad));
782
783   GST_LOG_OBJECT (faac, "received %s", GST_EVENT_TYPE_NAME (event));
784
785   switch (GST_EVENT_TYPE (event)) {
786     case GST_EVENT_EOS:
787     {
788       if (faac->handle) {
789         /* flush first */
790         GST_DEBUG_OBJECT (faac, "Pushing out remaining buffers because of EOS");
791         gst_faac_push_buffers (faac, TRUE);
792       }
793
794       ret = gst_pad_event_default (pad, event);
795       break;
796     }
797     default:
798       ret = gst_pad_event_default (pad, event);
799       break;
800
801   }
802   gst_object_unref (faac);
803   return ret;
804 }
805
806 static GstFlowReturn
807 gst_faac_chain (GstPad * pad, GstBuffer * inbuf)
808 {
809   GstFlowReturn result = GST_FLOW_OK;
810   GstFaac *faac;
811
812   faac = GST_FAAC (gst_pad_get_parent (pad));
813
814   if (!faac->handle)
815     goto no_handle;
816
817   GST_LOG_OBJECT (faac, "Got buffer time: %" GST_TIME_FORMAT " duration: %"
818       GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (inbuf)),
819       GST_TIME_ARGS (GST_BUFFER_DURATION (inbuf)));
820
821   gst_adapter_push (faac->adapter, inbuf);
822
823   result = gst_faac_push_buffers (faac, FALSE);
824
825 done:
826   gst_object_unref (faac);
827
828   return result;
829
830   /* ERRORS */
831 no_handle:
832   {
833     GST_ELEMENT_ERROR (faac, CORE, NEGOTIATION, (NULL),
834         ("format wasn't negotiated before chain function"));
835     gst_buffer_unref (inbuf);
836     result = GST_FLOW_ERROR;
837     goto done;
838   }
839 }
840
841 static void
842 gst_faac_set_property (GObject * object,
843     guint prop_id, const GValue * value, GParamSpec * pspec)
844 {
845   GstFaac *faac = GST_FAAC (object);
846
847   GST_OBJECT_LOCK (faac);
848
849   switch (prop_id) {
850     case ARG_BITRATE:
851       faac->bitrate = g_value_get_int (value);
852       break;
853     case ARG_PROFILE:
854       faac->profile = g_value_get_enum (value);
855       break;
856     case ARG_TNS:
857       faac->tns = g_value_get_boolean (value);
858       break;
859     case ARG_MIDSIDE:
860       faac->midside = g_value_get_boolean (value);
861       break;
862     case ARG_SHORTCTL:
863       faac->shortctl = g_value_get_enum (value);
864       break;
865     default:
866       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
867       break;
868   }
869
870   GST_OBJECT_UNLOCK (faac);
871 }
872
873 static void
874 gst_faac_get_property (GObject * object,
875     guint prop_id, GValue * value, GParamSpec * pspec)
876 {
877   GstFaac *faac = GST_FAAC (object);
878
879   GST_OBJECT_LOCK (faac);
880
881   switch (prop_id) {
882     case ARG_BITRATE:
883       g_value_set_int (value, faac->bitrate);
884       break;
885     case ARG_PROFILE:
886       g_value_set_enum (value, faac->profile);
887       break;
888     case ARG_TNS:
889       g_value_set_boolean (value, faac->tns);
890       break;
891     case ARG_MIDSIDE:
892       g_value_set_boolean (value, faac->midside);
893       break;
894     case ARG_SHORTCTL:
895       g_value_set_enum (value, faac->shortctl);
896       break;
897     default:
898       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
899       break;
900   }
901
902   GST_OBJECT_UNLOCK (faac);
903 }
904
905 static GstStateChangeReturn
906 gst_faac_change_state (GstElement * element, GstStateChange transition)
907 {
908   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
909   GstFaac *faac = GST_FAAC (element);
910
911   /* upwards state changes */
912   switch (transition) {
913     default:
914       break;
915   }
916
917   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
918
919   /* downwards state changes */
920   switch (transition) {
921     case GST_STATE_CHANGE_PAUSED_TO_READY:
922     {
923       gst_faac_close_encoder (faac);
924       gst_faac_reset (faac);
925       break;
926     }
927     default:
928       break;
929   }
930
931   return ret;
932 }
933
934 static gboolean
935 plugin_init (GstPlugin * plugin)
936 {
937   return gst_element_register (plugin, "faac", GST_RANK_SECONDARY,
938       GST_TYPE_FAAC);
939 }
940
941 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
942     GST_VERSION_MINOR,
943     "faac",
944     "Free AAC Encoder (FAAC)",
945     plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)