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>
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.
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.
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.
22 * SECTION:element-faac
25 * faac encodes raw audio to AAC (MPEG-4 part 3) streams.
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.
33 * <title>Example launch line</title>
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.
46 #include <gst/audio/multichannel.h>
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 ] "
59 /* these don't seem to work? */
62 "endianness = (int) BYTE_ORDER, "
63 "signed = (boolean) true, "
65 "depth = (int) { 24, 32 }, "
66 "rate = (int) [ 8000, 96000], "
67 "channels = (int) [ 1, 6]; "
69 "endianness = (int) BYTE_ORDER, "
71 "rate = (int) [ 8000, 96000], " "channels = (int) [ 1, 6]"
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",
82 GST_STATIC_CAPS (SRC_CAPS));
84 static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
87 GST_STATIC_CAPS (SINK_CAPS));
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);
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);
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);
119 static GstElementClass *parent_class = NULL;
121 GST_DEBUG_CATEGORY_STATIC (faac_debug);
122 #define GST_CAT_DEFAULT faac_debug
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
133 gst_faac_get_type (void)
135 static GType gst_faac_type = 0;
137 if (!gst_faac_type) {
138 static const GTypeInfo gst_faac_info = {
139 sizeof (GstFaacClass),
140 (GBaseInitFunc) gst_faac_base_init,
142 (GClassInitFunc) gst_faac_class_init,
147 (GInstanceInitFunc) gst_faac_init,
149 const GInterfaceInfo preset_interface_info = {
150 NULL, /* interface_init */
151 NULL, /* interface_finalize */
152 NULL /* interface_data */
155 gst_faac_type = g_type_register_static (GST_TYPE_ELEMENT,
156 "GstFaac", &gst_faac_info, 0);
158 g_type_add_interface_static (gst_faac_type, GST_TYPE_PRESET,
159 &preset_interface_info);
162 return gst_faac_type;
166 gst_faac_base_init (GstFaacClass * klass)
168 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
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));
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>");
180 GST_DEBUG_CATEGORY_INIT (faac_debug, "faac", 0, "AAC encoding");
183 #define GST_TYPE_FAAC_PROFILE (gst_faac_profile_get_type ())
185 gst_faac_profile_get_type (void)
187 static GType gst_faac_profile_type = 0;
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"},
198 gst_faac_profile_type = g_enum_register_static ("GstFaacProfile",
202 return gst_faac_profile_type;
205 #define GST_TYPE_FAAC_SHORTCTL (gst_faac_shortctl_get_type ())
207 gst_faac_shortctl_get_type (void)
209 static GType gst_faac_shortctl_type = 0;
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"},
219 gst_faac_shortctl_type = g_enum_register_static ("GstFaacShortCtl",
223 return gst_faac_shortctl_type;
227 gst_faac_class_init (GstFaacClass * klass)
229 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
230 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
232 parent_class = g_type_class_peek_parent (klass);
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);
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));
259 /* virtual functions */
260 gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_faac_change_state);
264 gst_faac_init (GstFaac * faac)
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);
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);
281 faac->adapter = gst_adapter_new ();
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;
291 gst_faac_reset (faac);
295 gst_faac_reset (GstFaac * faac)
298 faac->samplerate = -1;
301 gst_adapter_clear (faac->adapter);
305 gst_faac_finalize (GObject * object)
307 GstFaac *faac = (GstFaac *) object;
309 g_object_unref (faac->adapter);
311 G_OBJECT_CLASS (parent_class)->finalize (object);
315 gst_faac_close_encoder (GstFaac * faac)
318 faacEncClose (faac->handle);
320 gst_adapter_clear (faac->adapter);
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},
329 GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
330 GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
331 GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
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},
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},
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}
354 gst_faac_sink_getcaps (GstPad * pad)
356 static volatile gsize sinkcaps = 0;
358 if (g_once_init_enter (&sinkcaps)) {
359 GstCaps *tmp = gst_caps_new_empty ();
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);
369 for (i = 1; i <= 6; i++) {
370 GValue chanpos = { 0 };
373 t = gst_structure_copy (s);
375 gst_structure_set (t, "channels", G_TYPE_INT, i, NULL);
377 g_value_init (&chanpos, GST_TYPE_ARRAY);
378 g_value_init (&pos, GST_TYPE_AUDIO_CHANNEL_POSITION);
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);
384 g_value_unset (&pos);
386 gst_structure_set_value (t, "channel-positions", &chanpos);
387 g_value_unset (&chanpos);
388 gst_caps_append_structure (tmp, t);
390 gst_structure_free (s);
392 GST_DEBUG_OBJECT (pad, "Generated sinkcaps: %" GST_PTR_FORMAT, tmp);
394 g_once_init_leave (&sinkcaps, (gsize) tmp);
397 return gst_caps_ref ((GstCaps *) sinkcaps);
400 /* check downstream caps to configure format */
402 gst_faac_negotiate (GstFaac * faac)
406 caps = gst_pad_get_allowed_caps (faac->srcpad);
408 GST_DEBUG_OBJECT (faac, "allowed caps: %" GST_PTR_FORMAT, caps);
410 if (caps && gst_caps_get_size (caps) > 0) {
411 GstStructure *s = gst_caps_get_structure (caps, 0);
412 const gchar *str = NULL;
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;
422 GST_DEBUG_OBJECT (faac, "unknown stream-format: %s", str);
423 faac->outputformat = 0;
429 gst_caps_unref (caps);
434 gst_faac_sink_setcaps (GstPad * pad, GstCaps * caps)
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;
443 if (!gst_caps_is_fixed (caps))
446 if (!gst_structure_get_int (structure, "channels", &channels) ||
447 !gst_structure_get_int (structure, "rate", &samplerate)) {
451 if (gst_structure_has_name (structure, "audio/x-raw-int")) {
452 gst_structure_get_int (structure, "width", &width);
455 fmt = FAAC_INPUT_16BIT;
460 fmt = FAAC_INPUT_32BIT;
464 g_return_val_if_reached (FALSE);
466 } else if (gst_structure_has_name (structure, "audio/x-raw-float")) {
467 fmt = FAAC_INPUT_FLOAT;
474 /* If the encoder is initialized, do not
475 reinitialize it again if not necessary */
477 if (samplerate == faac->samplerate && channels == faac->channels &&
481 /* clear out pending frames */
482 gst_faac_push_buffers (faac, TRUE);
484 gst_faac_close_encoder (faac);
487 if (!(handle = faacEncOpen (samplerate, channels, &samples, &bytes)))
490 /* ok, record and set up */
493 faac->handle = handle;
495 faac->samples = samples;
496 faac->channels = channels;
497 faac->samplerate = samplerate;
499 gst_faac_negotiate (faac);
502 result = gst_faac_configure_source_pad (faac);
505 gst_object_unref (faac);
511 GST_ELEMENT_ERROR (faac, LIBRARY, SETTINGS, (NULL), (NULL));
516 GST_WARNING_OBJECT (faac, "refused caps %" GST_PTR_FORMAT, caps);
522 gst_faac_configure_source_pad (GstFaac * faac)
524 GstCaps *allowed_caps;
526 gboolean ret = FALSE;
527 gint n, ver, mpegversion = 2;
528 faacEncConfiguration *conf;
531 mpegversion = FAAC_DEFAULT_MPEGVERSION;
533 allowed_caps = gst_pad_get_allowed_caps (faac->srcpad);
534 GST_DEBUG_OBJECT (faac, "allowed caps: %" GST_PTR_FORMAT, allowed_caps);
537 if (gst_caps_is_empty (allowed_caps))
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);
544 if (gst_structure_get_int (s, "mpegversion", &ver) &&
545 (ver == 4 || ver == 2)) {
551 gst_caps_unref (allowed_caps);
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;
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;
566 /* check, warn and correct if the max bitrate for the given samplerate is
567 * exceeded. Maximum of 6144 bit for a channel */
569 (unsigned int) (6144.0 * (double) faac->samplerate / (double) 1024.0 +
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;
579 /* default 0 to start with, libfaac chooses based on bitrate */
582 if (!faacEncSetConfiguration (faac->handle, conf))
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);
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"),
600 if (!faac->outputformat) {
601 GstBuffer *codec_data;
602 guint8 *config = NULL;
603 gulong config_len = 0;
605 /* get the config string */
606 GST_DEBUG_OBJECT (faac, "retrieving decoder info");
607 faacEncGetDecoderSpecificInfo (faac->handle, &config, &config_len);
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);
615 gst_caps_set_simple (srccaps,
616 "codec_data", GST_TYPE_BUFFER, codec_data, NULL);
618 gst_buffer_unref (codec_data);
621 GST_DEBUG_OBJECT (faac, "src pad caps: %" GST_PTR_FORMAT, srccaps);
623 ret = gst_pad_set_caps (faac->srcpad, srccaps);
624 gst_caps_unref (srccaps);
631 gst_caps_unref (allowed_caps);
636 GST_WARNING_OBJECT (faac, "Faac doesn't support the current configuration");
642 gst_faac_push_buffers (GstFaac * faac, gboolean force)
644 GstFlowReturn ret = GST_FLOW_OK;
645 gint av, frame_size, size, ret_size;
647 guint64 timestamp, distance;
650 /* samples already considers channel count */
651 frame_size = faac->samples * faac->bps;
653 while (G_LIKELY (ret == GST_FLOW_OK)) {
655 av = gst_adapter_available (faac->adapter);
657 GST_LOG_OBJECT (faac, "pushing: force: %d, frame_size: %d, av: %d, "
658 "offset: %d", force, frame_size, av, faac->offset);
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) */
667 /* not enough data for one frame and no flush forcing */
668 if (!force && (av < frame_size + faac->offset))
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;
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;
682 GST_LOG_OBJECT (faac, "emptying encoder");
687 outbuf = gst_buffer_new_and_alloc (faac->bytes);
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);
696 GST_LOG_OBJECT (faac, "encoder return: %d", ret_size);
698 /* consumed, advanced view */
699 faac->offset += size;
700 g_assert (faac->offset <= av);
702 if (G_UNLIKELY (!ret_size)) {
703 gst_buffer_unref (outbuf);
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;
716 /* after some caching, finally some data */
717 /* adapter gives time */
718 timestamp = gst_adapter_prev_timestamp (faac->adapter, &distance);
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;
727 /* otherwise leftover */
728 gst_adapter_clear (faac->adapter);
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,
738 GST_BUFFER_DURATION (outbuf) =
739 GST_FRAMES_TO_CLOCK_TIME (size / faac->channels / faac->bps,
742 GST_BUFFER_TIMESTAMP (outbuf) + GST_BUFFER_DURATION (outbuf);
744 /* perhaps check/set DISCONT based on timestamps ? */
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)));
751 gst_buffer_set_caps (outbuf, GST_PAD_CAPS (faac->srcpad));
752 ret = gst_pad_push (faac->srcpad, outbuf);
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);
761 gst_adapter_clear (faac->adapter);
770 GST_ELEMENT_ERROR (faac, LIBRARY, ENCODE, (NULL), (NULL));
771 return GST_FLOW_ERROR;
776 gst_faac_sink_event (GstPad * pad, GstEvent * event)
781 faac = GST_FAAC (gst_pad_get_parent (pad));
783 GST_LOG_OBJECT (faac, "received %s", GST_EVENT_TYPE_NAME (event));
785 switch (GST_EVENT_TYPE (event)) {
790 GST_DEBUG_OBJECT (faac, "Pushing out remaining buffers because of EOS");
791 gst_faac_push_buffers (faac, TRUE);
794 ret = gst_pad_event_default (pad, event);
798 ret = gst_pad_event_default (pad, event);
802 gst_object_unref (faac);
807 gst_faac_chain (GstPad * pad, GstBuffer * inbuf)
809 GstFlowReturn result = GST_FLOW_OK;
812 faac = GST_FAAC (gst_pad_get_parent (pad));
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)));
821 gst_adapter_push (faac->adapter, inbuf);
823 result = gst_faac_push_buffers (faac, FALSE);
826 gst_object_unref (faac);
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;
842 gst_faac_set_property (GObject * object,
843 guint prop_id, const GValue * value, GParamSpec * pspec)
845 GstFaac *faac = GST_FAAC (object);
847 GST_OBJECT_LOCK (faac);
851 faac->bitrate = g_value_get_int (value);
854 faac->profile = g_value_get_enum (value);
857 faac->tns = g_value_get_boolean (value);
860 faac->midside = g_value_get_boolean (value);
863 faac->shortctl = g_value_get_enum (value);
866 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
870 GST_OBJECT_UNLOCK (faac);
874 gst_faac_get_property (GObject * object,
875 guint prop_id, GValue * value, GParamSpec * pspec)
877 GstFaac *faac = GST_FAAC (object);
879 GST_OBJECT_LOCK (faac);
883 g_value_set_int (value, faac->bitrate);
886 g_value_set_enum (value, faac->profile);
889 g_value_set_boolean (value, faac->tns);
892 g_value_set_boolean (value, faac->midside);
895 g_value_set_enum (value, faac->shortctl);
898 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
902 GST_OBJECT_UNLOCK (faac);
905 static GstStateChangeReturn
906 gst_faac_change_state (GstElement * element, GstStateChange transition)
908 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
909 GstFaac *faac = GST_FAAC (element);
911 /* upwards state changes */
912 switch (transition) {
917 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
919 /* downwards state changes */
920 switch (transition) {
921 case GST_STATE_CHANGE_PAUSED_TO_READY:
923 gst_faac_close_encoder (faac);
924 gst_faac_reset (faac);
935 plugin_init (GstPlugin * plugin)
937 return gst_element_register (plugin, "faac", GST_RANK_SECONDARY,
941 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
944 "Free AAC Encoder (FAAC)",
945 plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)