summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRonald S. Bultje <rbultje@ronald.bitfreak.net>2003-11-22 12:25:48 +0000
committerRonald S. Bultje <rbultje@ronald.bitfreak.net>2003-11-22 12:25:48 +0000
commit839f6e752596016a737802629e1043253270a5c4 (patch)
tree44f8c2043f89e0df24c7eda1808618ad65405c9e
parent8d529948e60c12bfb824a529555255ff9f6698c5 (diff)
downloadgstreamer-plugins-bad-839f6e752596016a737802629e1043253270a5c4.tar.gz
Actually, FAAC is LGPL, not GPL (like FAAD)
Original commit message from CVS: Actually, FAAC is LGPL, not GPL (like FAAD)
-rw-r--r--ext/faac/gstfaac.c680
1 files changed, 680 insertions, 0 deletions
diff --git a/ext/faac/gstfaac.c b/ext/faac/gstfaac.c
new file mode 100644
index 000000000..e5dddc17a
--- /dev/null
+++ b/ext/faac/gstfaac.c
@@ -0,0 +1,680 @@
+/* GStreamer FAAC (Free AAC Encoder) plugin
+ * Copyright (C) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstfaac.h"
+
+GST_PAD_TEMPLATE_FACTORY (src_template,
+ "src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_CAPS_NEW (
+ "faac_mpeg_templ",
+ "audio/mpeg",
+ "systemstream", GST_PROPS_BOOLEAN (FALSE),
+ "mpegversion", GST_PROPS_LIST (
+ GST_PROPS_INT (4), /* we prefer 4 */
+ GST_PROPS_INT (2)
+ ),
+ "channels", GST_PROPS_INT_RANGE (1, 6),
+ "samplerate", GST_PROPS_INT_RANGE (8000, 96000)
+ )
+);
+
+GST_PAD_TEMPLATE_FACTORY (sink_template,
+ "sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_CAPS_NEW (
+ "faac_int16_templ",
+ "audio/x-raw-int",
+ "endianness", GST_PROPS_INT (G_BYTE_ORDER),
+ "signed", GST_PROPS_BOOLEAN (TRUE),
+ "width", GST_PROPS_INT (16),
+ "depth", GST_PROPS_INT (16),
+ "rate", GST_PROPS_INT_RANGE (8000, 96000),
+ "channels", GST_PROPS_INT_RANGE (1, 6)
+ ),
+ GST_CAPS_NEW (
+ "faac_int24_templ",
+ "audio/x-raw-int",
+ "endianness", GST_PROPS_INT (G_BYTE_ORDER),
+ "signed", GST_PROPS_BOOLEAN (TRUE),
+ "width", GST_PROPS_INT (32),
+ "depth", GST_PROPS_INT (24),
+ "rate", GST_PROPS_INT_RANGE (8000, 96000),
+ "channels", GST_PROPS_INT_RANGE (1, 6)
+ ),
+ GST_CAPS_NEW (
+ "faac_float_templ",
+ "audio/x-raw-float",
+ "endianness", GST_PROPS_INT (G_BYTE_ORDER),
+ "depth", GST_PROPS_INT (32), /* float */
+ "rate", GST_PROPS_INT_RANGE (8000, 96000),
+ "channels", GST_PROPS_INT_RANGE (1, 6)
+ )
+);
+
+enum {
+ ARG_0,
+ ARG_BITRATE,
+ ARG_PROFILE,
+ ARG_TNS,
+ ARG_MIDSIDE,
+ ARG_SHORTCTL
+ /* FILL ME */
+};
+
+static void gst_faac_base_init (GstFaacClass *klass);
+static void gst_faac_class_init (GstFaacClass *klass);
+static void gst_faac_init (GstFaac *faac);
+
+static void gst_faac_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void gst_faac_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec);
+
+static GstPadLinkReturn
+ gst_faac_sinkconnect (GstPad *pad,
+ GstCaps *caps);
+static GstPadLinkReturn
+ gst_faac_srcconnect (GstPad *pad,
+ GstCaps *caps);
+static void gst_faac_chain (GstPad *pad,
+ GstData *data);
+static GstElementStateReturn
+ gst_faac_change_state (GstElement *element);
+
+static GstElementClass *parent_class = NULL;
+/* static guint gst_faac_signals[LAST_SIGNAL] = { 0 }; */
+
+GType
+gst_faac_get_type (void)
+{
+ static GType gst_faac_type = 0;
+
+ if (!gst_faac_type) {
+ static const GTypeInfo gst_faac_info = {
+ sizeof (GstFaacClass),
+ (GBaseInitFunc) gst_faac_base_init,
+ NULL,
+ (GClassInitFunc) gst_faac_class_init,
+ NULL,
+ NULL,
+ sizeof(GstFaac),
+ 0,
+ (GInstanceInitFunc) gst_faac_init,
+ };
+
+ gst_faac_type = g_type_register_static (GST_TYPE_ELEMENT,
+ "GstFaac",
+ &gst_faac_info, 0);
+ }
+
+ return gst_faac_type;
+}
+
+static void
+gst_faac_base_init (GstFaacClass *klass)
+{
+ GstElementDetails gst_faac_details = {
+ "Free AAC Encoder (FAAC)",
+ "Codec/Audio/Encoder",
+ "Free MPEG-2/4 AAC encoder",
+ "Ronald Bultje <rbultje@ronald.bitfreak.net>",
+ };
+ GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
+
+ gst_element_class_add_pad_template (element_class,
+ GST_PAD_TEMPLATE_GET (src_template));
+ gst_element_class_add_pad_template (element_class,
+ GST_PAD_TEMPLATE_GET (sink_template));
+
+ gst_element_class_set_details (element_class, &gst_faac_details);
+}
+
+#define GST_TYPE_FAAC_PROFILE (gst_faac_profile_get_type ())
+static GType
+gst_faac_profile_get_type (void)
+{
+ static GType gst_faac_profile_type = 0;
+
+ if (!gst_faac_profile_type) {
+ static GEnumValue gst_faac_profile[] = {
+ { MAIN, "MAIN", "Main profile" },
+ { LOW, "LOW", "Low complexity profile" },
+ { SSR, "SSR", "Scalable sampling rate profile" },
+ { LTP, "LTP", "Long term prediction profile" },
+ { 0, NULL, NULL },
+ };
+
+ gst_faac_profile_type = g_enum_register_static ("GstFaacProfile",
+ gst_faac_profile);
+ }
+
+ return gst_faac_profile_type;
+}
+
+#define GST_TYPE_FAAC_SHORTCTL (gst_faac_shortctl_get_type ())
+static GType
+gst_faac_shortctl_get_type (void)
+{
+ static GType gst_faac_shortctl_type = 0;
+
+ if (!gst_faac_shortctl_type) {
+ static GEnumValue gst_faac_shortctl[] = {
+ { SHORTCTL_NORMAL, "SHORTCTL_NORMAL", "Normal block type" },
+ { SHORTCTL_NOSHORT, "SHORTCTL_NOSHORT", "No short blocks" },
+ { SHORTCTL_NOLONG, "SHORTCTL_NOLONG", "No long blocks" },
+ { 0, NULL, NULL },
+ };
+
+ gst_faac_shortctl_type = g_enum_register_static ("GstFaacShortCtl",
+ gst_faac_shortctl);
+ }
+
+ return gst_faac_shortctl_type;
+}
+
+static void
+gst_faac_class_init (GstFaacClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
+
+ parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
+
+ /* properties */
+ g_object_class_install_property (gobject_class, ARG_BITRATE,
+ g_param_spec_int ("bitrate", "Bitrate (bps)", "Bitrate in bits/sec",
+ 8 * 1024, 320 * 1024, 128 * 1024, G_PARAM_READWRITE));
+ g_object_class_install_property (gobject_class, ARG_PROFILE,
+ g_param_spec_enum ("profile", "Profile", "MPEG/AAC encoding profile",
+ GST_TYPE_FAAC_PROFILE, MAIN, G_PARAM_READWRITE));
+ g_object_class_install_property (gobject_class, ARG_TNS,
+ g_param_spec_boolean ("tns", "TNS", "Use temporal noise shaping",
+ FALSE, G_PARAM_READWRITE));
+ g_object_class_install_property (gobject_class, ARG_MIDSIDE,
+ g_param_spec_boolean ("midside", "Midside", "Allow mid/side encoding",
+ TRUE, G_PARAM_READWRITE));
+ g_object_class_install_property (gobject_class, ARG_SHORTCTL,
+ g_param_spec_enum ("shortctl", "Block type",
+ "Block type encorcing",
+ GST_TYPE_FAAC_SHORTCTL, MAIN, G_PARAM_READWRITE));
+
+ /* virtual functions */
+ gstelement_class->change_state = gst_faac_change_state;
+
+ gobject_class->set_property = gst_faac_set_property;
+ gobject_class->get_property = gst_faac_get_property;
+}
+
+static void
+gst_faac_init (GstFaac *faac)
+{
+ faac->handle = NULL;
+ faac->samplerate = -1;
+ faac->channels = -1;
+ faac->cache = NULL;
+ faac->cache_time = GST_CLOCK_TIME_NONE;
+ faac->cache_duration = 0;
+
+ GST_FLAG_SET (faac, GST_ELEMENT_EVENT_AWARE);
+
+ faac->sinkpad = gst_pad_new_from_template (
+ GST_PAD_TEMPLATE_GET (sink_template), "sink");
+ gst_element_add_pad (GST_ELEMENT (faac), faac->sinkpad);
+ gst_pad_set_chain_function (faac->sinkpad, gst_faac_chain);
+ gst_pad_set_link_function (faac->sinkpad, gst_faac_sinkconnect);
+
+ faac->srcpad = gst_pad_new_from_template (
+ GST_PAD_TEMPLATE_GET (src_template), "src");
+ gst_element_add_pad (GST_ELEMENT (faac), faac->srcpad);
+ gst_pad_set_link_function (faac->srcpad, gst_faac_srcconnect);
+
+ /* default properties */
+ faac->bitrate = 1024 * 128;
+ faac->profile = MAIN;
+ faac->shortctl = SHORTCTL_NORMAL;
+ faac->tns = FALSE;
+ faac->midside = TRUE;
+}
+
+static GstPadLinkReturn
+gst_faac_sinkconnect (GstPad *pad,
+ GstCaps *caps)
+{
+ GstFaac *faac = GST_FAAC (gst_pad_get_parent (pad));
+
+ if (!GST_CAPS_IS_FIXED (caps))
+ return GST_PAD_LINK_DELAYED;
+
+ if (faac->handle) {
+ faacEncClose (faac->handle);
+ faac->handle = NULL;
+ }
+ if (faac->cache) {
+ gst_buffer_unref (faac->cache);
+ faac->cache = NULL;
+ }
+
+ for (; caps != NULL; caps = caps->next) {
+ faacEncHandle *handle;
+ gint channels, samplerate, depth;
+ gulong samples, bytes, fmt = 0, bps = 0;
+
+ gst_caps_get (caps, "channels", &channels,
+ "rate", &samplerate,
+ "depth", &depth, NULL);
+
+ /* open a new handle to the encoder */
+ if (!(handle = faacEncOpen (samplerate, channels,
+ &samples, &bytes)))
+ continue;
+
+ switch (depth) {
+ case 16:
+ fmt = FAAC_INPUT_16BIT;
+ bps = 2;
+ break;
+ case 24:
+ fmt = FAAC_INPUT_32BIT; /* 24-in-32, actually */
+ bps = 4;
+ break;
+ case 32:
+ fmt = FAAC_INPUT_FLOAT; /* see template, this is right */
+ bps = 4;
+ break;
+ }
+
+ if (!fmt) {
+ faacEncClose (handle);
+ continue;
+ }
+
+ faac->format = fmt;
+ faac->bps = bps;
+ faac->handle = handle;
+ faac->bytes = bytes;
+ faac->samples = samples;
+ faac->channels = channels;
+ faac->samplerate = samplerate;
+
+ /* if the other side was already set-up, redo that */
+ if (GST_PAD_CAPS (faac->srcpad))
+ return gst_faac_srcconnect (faac->srcpad,
+ gst_pad_get_allowed_caps (faac->srcpad));
+
+ /* else, that'll be done later */
+ return GST_PAD_LINK_OK;
+ }
+
+ return GST_PAD_LINK_REFUSED;
+}
+
+static GstPadLinkReturn
+gst_faac_srcconnect (GstPad *pad,
+ GstCaps *caps)
+{
+ GstFaac *faac = GST_FAAC (gst_pad_get_parent (pad));
+ GstCaps *t;
+
+ if (!faac->handle ||
+ (faac->samplerate == -1 || faac->channels == -1)) {
+ return GST_PAD_LINK_DELAYED;
+ }
+
+ /* we do samplerate/channels ourselves */
+ for (t = caps; t != NULL; t = t->next) {
+ gst_props_remove_entry_by_name (t->properties, "rate");
+ gst_props_remove_entry_by_name (t->properties, "channels");
+ }
+
+ /* go through list */
+ caps = gst_caps_normalize (caps);
+ for ( ; caps != NULL; caps = caps->next) {
+ faacEncConfiguration *conf;
+ gint mpegversion = 0;
+ GstCaps *newcaps;
+ GstPadLinkReturn ret;
+
+ gst_caps_get_int (caps, "mpegversion", &mpegversion);
+
+ /* new conf */
+ conf = faacEncGetCurrentConfiguration (faac->handle);
+ conf->mpegVersion = (mpegversion == 4) ? MPEG4 : MPEG2;
+ conf->aacObjectType = faac->profile;
+ conf->allowMidside = faac->midside;
+ conf->useLfe = 0;
+ conf->useTns = faac->tns;
+ conf->bitRate = faac->bitrate;
+ conf->inputFormat = faac->format;
+
+ /* FIXME: this one here means that we do not support direct
+ * "MPEG audio file" output (like mp3). This means we can
+ * only mux this into mov/qt (mp4a) or matroska or so. If
+ * we want to support direct AAC file output, we need ADTS
+ * headers, and we need to find a way in the caps to detect
+ * that (that the next element is filesink or any element
+ * that does want ADTS headers). */
+
+ conf->outputFormat = 0; /* raw, no ADTS headers */
+ conf->shortctl = faac->shortctl;
+ if (!faacEncSetConfiguration (faac->handle, conf)) {
+ GST_WARNING ("Faac doesn't support the current conf");
+ continue;
+ }
+
+ newcaps = GST_CAPS_NEW ("faac_mpeg_caps",
+ "audio/mpeg",
+ "systemstream", GST_PROPS_BOOLEAN (FALSE),
+ "mpegversion", GST_PROPS_INT (mpegversion),
+ "channels", GST_PROPS_INT (faac->channels),
+ "rate", GST_PROPS_INT (faac->samplerate));
+ ret = gst_pad_try_set_caps (faac->srcpad, newcaps);
+
+ switch (ret) {
+ case GST_PAD_LINK_OK:
+ case GST_PAD_LINK_DONE:
+ return GST_PAD_LINK_DONE;
+ case GST_PAD_LINK_DELAYED:
+ return GST_PAD_LINK_DELAYED;
+ default:
+ break;
+ }
+ }
+
+ return GST_PAD_LINK_REFUSED;
+}
+
+static void
+gst_faac_chain (GstPad *pad,
+ GstData *data)
+{
+ GstFaac *faac = GST_FAAC (gst_pad_get_parent (pad));
+ GstBuffer *inbuf, *outbuf, *subbuf;
+ guint size, ret_size, in_size, frame_size;
+
+ if (GST_IS_EVENT (data)) {
+ GstEvent *event = GST_EVENT (data);
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_EOS:
+ /* flush first */
+ while (1) {
+ outbuf = gst_buffer_new_and_alloc (faac->bytes);
+ if ((ret_size = faacEncEncode (faac->handle,
+ NULL, 0,
+ GST_BUFFER_DATA (outbuf),
+ faac->bytes)) < 0) {
+ gst_element_error (GST_ELEMENT (faac), "Error during AAC encoding");
+ gst_event_unref (event);
+ gst_buffer_unref (outbuf);
+ return;
+ }
+
+ if (ret_size > 0) {
+ GST_BUFFER_SIZE (outbuf) = ret_size;
+ GST_BUFFER_TIMESTAMP (outbuf) = 0;
+ GST_BUFFER_DURATION (outbuf) = 0;
+ gst_pad_push (faac->srcpad, GST_DATA (outbuf));
+ } else {
+ break;
+ }
+ }
+
+ gst_element_set_eos (GST_ELEMENT (faac));
+ gst_pad_push (faac->srcpad, data);
+ return;
+ default:
+ gst_pad_event_default (pad, event);
+ return;
+ }
+ }
+
+ inbuf = GST_BUFFER (data);
+
+ if (!faac->handle) {
+ gst_element_error (GST_ELEMENT (faac),
+ "No input format negotiated");
+ gst_buffer_unref (inbuf);
+ return;
+ }
+
+ if (!GST_PAD_CAPS (faac->srcpad)) {
+ if (gst_faac_srcconnect (faac->srcpad,
+ gst_pad_get_allowed_caps (faac->srcpad)) <= 0) {
+ gst_element_error (GST_ELEMENT (faac),
+ "Failed to negotiate MPEG/AAC format with next element");
+ gst_buffer_unref (inbuf);
+ return;
+ }
+ }
+
+ size = GST_BUFFER_SIZE (inbuf);
+ in_size = size;
+ if (faac->cache)
+ in_size += GST_BUFFER_SIZE (faac->cache);
+ frame_size = faac->samples * faac->bps;
+
+ while (1) {
+ /* do we have enough data for one frame? */
+ if (in_size / faac->bps < faac->samples) {
+ if (in_size > size) {
+ /* this is panic! we got a buffer, but still don't have enough
+ * data. Merge them and retry in the next cycle... */
+ faac->cache = gst_buffer_merge (faac->cache, inbuf);
+ } else if (in_size == size) {
+ /* this shouldn't happen, but still... */
+ faac->cache = inbuf;
+ } else if (in_size > 0) {
+ faac->cache = gst_buffer_create_sub (inbuf, size - in_size,
+ in_size);
+ GST_BUFFER_DURATION (faac->cache) =
+ GST_BUFFER_DURATION (inbuf) * GST_BUFFER_SIZE (faac->cache) / size;
+ GST_BUFFER_TIMESTAMP (faac->cache) =
+ GST_BUFFER_TIMESTAMP (inbuf) + (GST_BUFFER_DURATION (inbuf) *
+ (size - in_size) / size);
+ gst_buffer_unref (inbuf);
+ } else {
+ gst_buffer_unref (inbuf);
+ }
+
+ return;
+ }
+
+ /* create the frame */
+ if (in_size > size) {
+ /* merge */
+ subbuf = gst_buffer_create_sub (inbuf, 0, frame_size - (in_size - size));
+ GST_BUFFER_DURATION (subbuf) =
+ GST_BUFFER_DURATION (inbuf) * GST_BUFFER_SIZE (subbuf) / size;
+ subbuf = gst_buffer_merge (faac->cache, subbuf);
+ faac->cache = NULL;
+ } else {
+ subbuf = gst_buffer_create_sub (inbuf, size - in_size, frame_size);
+ GST_BUFFER_DURATION (subbuf) =
+ GST_BUFFER_DURATION (inbuf) * GST_BUFFER_SIZE (subbuf) / size;
+ GST_BUFFER_TIMESTAMP (subbuf) =
+ GST_BUFFER_TIMESTAMP (inbuf) + (GST_BUFFER_DURATION (inbuf) *
+ (size - in_size) / size);
+ }
+
+ outbuf = gst_buffer_new_and_alloc (faac->bytes);
+ if ((ret_size = faacEncEncode (faac->handle,
+ (gint32 *) GST_BUFFER_DATA (subbuf),
+ GST_BUFFER_SIZE (subbuf) / faac->bps,
+ GST_BUFFER_DATA (outbuf),
+ faac->bytes)) < 0) {
+ gst_element_error (GST_ELEMENT (faac), "Error during AAC encoding");
+ gst_buffer_unref (inbuf);
+ gst_buffer_unref (subbuf);
+ return;
+ }
+
+ if (ret_size > 0) {
+ GST_BUFFER_SIZE (outbuf) = ret_size;
+ if (faac->cache_time != GST_CLOCK_TIME_NONE) {
+ GST_BUFFER_TIMESTAMP (outbuf) = faac->cache_time;
+ faac->cache_time = GST_CLOCK_TIME_NONE;
+ } else
+ GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (subbuf);
+ GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (subbuf);
+ if (faac->cache_duration) {
+ GST_BUFFER_DURATION (outbuf) += faac->cache_duration;
+ faac->cache_duration = 0;
+ }
+ gst_pad_push (faac->srcpad, GST_DATA (outbuf));
+ } else {
+ /* FIXME: what I'm doing here isn't fully correct, but there
+ * really isn't a better way yet.
+ * Problem is that libfaac caches buffers (for encoding
+ * purposes), so the timestamp of the outgoing buffer isn't
+ * the same as the timestamp of the data that I pushed in.
+ * However, I don't know the delay between those two so I
+ * cannot really say aything about it. This is a bad guess. */
+
+ gst_buffer_unref (outbuf);
+ if (faac->cache_time != GST_CLOCK_TIME_NONE)
+ faac->cache_time = GST_BUFFER_TIMESTAMP (subbuf);
+ faac->cache_duration += GST_BUFFER_DURATION (subbuf);
+ }
+
+ in_size -= frame_size;
+ gst_buffer_unref (subbuf);
+ }
+}
+
+static void
+gst_faac_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GstFaac *faac = GST_FAAC (object);
+
+ switch (prop_id) {
+ case ARG_BITRATE:
+ faac->bitrate = g_value_get_int (value);
+ break;
+ case ARG_PROFILE:
+ faac->profile = g_value_get_enum (value);
+ break;
+ case ARG_TNS:
+ faac->tns = g_value_get_boolean (value);
+ break;
+ case ARG_MIDSIDE:
+ faac->midside = g_value_get_boolean (value);
+ break;
+ case ARG_SHORTCTL:
+ faac->shortctl = g_value_get_enum (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gst_faac_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GstFaac *faac = GST_FAAC (object);
+
+ switch (prop_id) {
+ case ARG_BITRATE:
+ g_value_set_int (value, faac->bitrate);
+ break;
+ case ARG_PROFILE:
+ g_value_set_enum (value, faac->profile);
+ break;
+ case ARG_TNS:
+ g_value_set_boolean (value, faac->tns);
+ break;
+ case ARG_MIDSIDE:
+ g_value_set_boolean (value, faac->midside);
+ break;
+ case ARG_SHORTCTL:
+ g_value_set_enum (value, faac->shortctl);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static GstElementStateReturn
+gst_faac_change_state (GstElement *element)
+{
+ GstFaac *faac = GST_FAAC (element);
+
+ switch (GST_STATE_TRANSITION (element)) {
+ case GST_STATE_PAUSED_TO_READY:
+ if (faac->handle) {
+ faacEncClose (faac->handle);
+ faac->handle = NULL;
+ }
+ if (faac->cache) {
+ gst_buffer_unref (faac->cache);
+ faac->cache = NULL;
+ }
+ faac->cache_time = GST_CLOCK_TIME_NONE;
+ faac->cache_duration = 0;
+ faac->samplerate = -1;
+ faac->channels = -1;
+ break;
+ default:
+ break;
+ }
+
+ if (GST_ELEMENT_CLASS (parent_class)->change_state)
+ return GST_ELEMENT_CLASS (parent_class)->change_state (element);
+
+ return GST_STATE_SUCCESS;
+}
+
+static gboolean
+plugin_init (GstPlugin *plugin)
+{
+ return gst_element_register (plugin, "faac",
+ GST_RANK_NONE,
+ GST_TYPE_FAAC);
+}
+
+GST_PLUGIN_DEFINE (
+ GST_VERSION_MAJOR,
+ GST_VERSION_MINOR,
+ "faac",
+ "Free AAC Encoder (FAAC)",
+ plugin_init,
+ VERSION,
+ "LGPL",
+ GST_COPYRIGHT,
+ GST_PACKAGE,
+ GST_ORIGIN
+)