pbutils: add codec-specific utility functions for AAC
authorArun Raghavan <arun.raghavan@collabora.co.uk>
Fri, 30 Apr 2010 08:11:17 +0000 (13:41 +0530)
committerTim-Philipp Müller <tim.muller@collabora.co.uk>
Thu, 30 Sep 2010 12:09:28 +0000 (13:09 +0100)
This allows us to add generic codec-specific functionality, like
extracting profile/level data from headers, without having to duplicate
code across demuxers and typefindfunctions.

As a starting point, this moves over AAC level extraction code from
typefindfunctions, so it can be reused in qtdemux, etc.

https://bugzilla.gnome.org/show_bug.cgi?id=617314

API: gst_codec_utils_aac_get_sample_rate_from_index()
API: gst_codec_utils_aac_get_level()

gst-libs/gst/pbutils/Makefile.am
gst-libs/gst/pbutils/codec-utils.c [new file with mode: 0644]
gst-libs/gst/pbutils/codec-utils.h [moved from gst/typefind/gstaacutil.h with 53% similarity]
gst-libs/gst/pbutils/pbutils.h
gst/typefind/Makefile.am
gst/typefind/gstaacutil.c [deleted file]
gst/typefind/gsttypefindfunctions.c
win32/common/libgstpbutils.def

index 60ab464..1d3d092 100644 (file)
@@ -2,6 +2,7 @@ lib_LTLIBRARIES = libgstpbutils-@GST_MAJORMINOR@.la
 
 headers_pbutils = \
        pbutils.h         \
+       codec-utils.h     \
        descriptions.h    \
        install-plugins.h \
        missing-plugins.h \
@@ -27,6 +28,7 @@ built_headers_configure = \
 libgstpbutils_@GST_MAJORMINOR@_la_SOURCES = \
        gstpluginsbaseversion.c \
        pbutils.c         \
+       codec-utils.c     \
        descriptions.c    \
        install-plugins.c \
        missing-plugins.c \
diff --git a/gst-libs/gst/pbutils/codec-utils.c b/gst-libs/gst/pbutils/codec-utils.c
new file mode 100644 (file)
index 0000000..18d91b6
--- /dev/null
@@ -0,0 +1,278 @@
+/* GStreamer base utils library codec-specific utility functions
+ * Copyright (C) 2010 Arun Raghavan <arun.raghavan@collabora.co.uk>
+ *               2010 Collabora Multimedia
+ *               2010 Nokia Corporation
+ *
+ * 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.
+ */
+
+/**
+ * SECTION:gstpbutilscodecutils
+ * @short_description: Miscellaneous codec-specific utility functions
+ *
+ * <refsect2>
+ * <para>
+ * Provides numerous codec-specific ulility functions such as functions to
+ * provide the codec profile and level in human-readable string form from
+ * header data.
+ * </para>
+ * </refsect2>
+ */
+
+#include "pbutils.h"
+
+/**
+ * gst_codec_utils_aac_get_sample_rate_from_index:
+ * @sr_idx: Sample rate index as from the AudioSpecificConfig (MPEG-4
+ *          container) or ADTS frame header
+ *
+ * Translates the sample rate index found in AAC headers to the actual sample
+ * rate.
+ *
+ * Returns: The sample rate if @sr_idx is valid, 0 otherwise.
+ */
+guint
+gst_codec_utils_aac_get_sample_rate_from_index (guint sr_idx)
+{
+  static const guint aac_sample_rates[] = { 96000, 88200, 64000, 48000, 44100,
+    32000, 24000, 22050, 16000, 12000, 11025, 8000
+  };
+
+  if (G_LIKELY (sr_idx < G_N_ELEMENTS (aac_sample_rates)))
+    return aac_sample_rates[sr_idx];
+
+  GST_WARNING ("Invalid sample rate index %u", sr_idx);
+  return 0;
+}
+
+/**
+ * gst_codec_utils_aac_get_level:
+ * @audio_config: a pointer to the AudioSpecificConfig as specified in the
+ *                Elementary Stream Descriptor (esds) in ISO/IEC 14496-1 (see
+ *                below for a more detailed description).
+ * @len: Length of @audio_config in bytes
+ *
+ * Determines the level of a stream as defined in ISO/IEC 14496-3. For AAC LC
+ * streams, the constraints from the AAC audio profile are applied. For AAC
+ * Main, LTP, SSR and others, the Main profile is used.
+ *
+ * The @audio_config parameter follows the following format, starting from the
+ * most significant bit of the first byte:
+ *
+ * Bit 0:4 contains the AudioObjectType
+ * Bit 5:8 contains the sample frequency index (if this is 0xf, then the next
+ *         24 bits define the actual sample frequency, and subsequent fields
+ *         are appropriately shifted).
+ * Bit 9:12 contains the channel configuration
+ *
+ * <note>
+ * HE-AAC support has not yet been implemented.
+ * </note>
+ *
+ * Returns: The level as a const string and NULL if the level could not be
+ * determined.
+ */
+const gchar *
+gst_codec_utils_aac_get_level (const guint8 * audio_config, guint len)
+{
+  int profile, sr_idx, channel_config, rate;
+  /* Number of single channel elements, channel pair elements, low frequency
+   * elements, independently switched coupling channel elements, and
+   * dependently switched coupling channel elements.
+   *
+   * Note: The 2 CCE types are ignored for now as they require us to actually
+   * parse the first frame, and they are rarely found in actual streams.
+   */
+  int num_sce = 0, num_cpe = 0, num_lfe = 0, num_cce_indep = 0, num_cce_dep = 0;
+  int num_channels;
+  /* Processor and RAM Complexity Units (calculated and "reference" for single
+   * channel) */
+  int pcu, rcu, pcu_ref, rcu_ref;
+  int ret = -1;
+
+  g_return_val_if_fail (audio_config != NULL, NULL);
+
+  if (len < 2)
+    return NULL;
+
+  profile = audio_config[0] >> 3;
+  /* FIXME: add support for sr_idx = 0xf */
+  sr_idx = ((audio_config[0] & 0x7) << 1) | ((audio_config[1] & 0x80) >> 7);
+  rate = gst_codec_utils_aac_get_sample_rate_from_index (sr_idx);
+  channel_config = (audio_config[1] & 0x7f) >> 3;
+
+  if (rate == 0)
+    return NULL;
+
+  switch (channel_config) {
+    case 0:
+      /* Channel config is defined in the AudioObjectType's SpecificConfig,
+       * which requires some amount of digging through the headers. I only see
+       * this done in the MPEG conformance streams - FIXME */
+      GST_WARNING ("Found a stream with channel configuration in the "
+          "AudioSpecificConfig. Please file a bug with a link to the media if "
+          "possible.");
+      return NULL;
+    case 1:
+      /* front center */
+      num_sce = 1;
+      break;
+    case 2:
+      /* front left and right */
+      num_cpe = 1;
+      break;
+    case 3:
+      /* front left, right, and center */
+      num_sce = 1;
+      num_cpe = 1;
+      break;
+    case 4:
+      /* front left, right, and center; rear surround */
+      num_sce = 2;
+      num_cpe = 1;
+      break;
+    case 5:
+      /* front left, right, and center; rear left and right surround */
+      num_sce = 1;
+      num_cpe = 2;
+      break;
+    case 6:
+      /* front left, right, center and LFE; rear left and right surround */
+      num_sce = 1;
+      num_cpe = 2;
+      break;
+    case 7:
+      /* front left, right, center and LFE; outside front left and right;
+       * rear left and right surround */
+      num_sce = 1;
+      num_cpe = 3;
+      num_lfe = 1;
+      break;
+    default:
+      GST_WARNING ("Unknown channel config in header: %d", channel_config);
+      return NULL;
+  }
+
+  switch (profile) {
+    case 0:                    /* NULL */
+      GST_WARNING ("profile 0 is not a valid profile");
+      return NULL;
+    case 2:                    /* LC */
+      pcu_ref = 3;
+      rcu_ref = 3;
+      break;
+    case 3:                    /* SSR */
+      pcu_ref = 4;
+      rcu_ref = 3;
+      break;
+    case 4:                    /* LTP */
+      pcu_ref = 4;
+      rcu_ref = 4;
+      break;
+    case 1:                    /* Main */
+    default:
+      /* Other than a couple of ER profiles, Main is the worst-case */
+      pcu_ref = 5;
+      rcu_ref = 5;
+      break;
+  }
+
+  /* "fs_ref" is 48000 Hz for AAC Main/LC/SSR/LTP. SBR's fs_ref is defined as
+   * 24000/48000 (in/out), for SBR streams. Actual support is a FIXME */
+
+  pcu = ((float) rate / 48000) * pcu_ref *
+      ((2 * num_cpe) + num_sce + num_lfe + num_cce_indep + (0.3 * num_cce_dep));
+
+  rcu = ((float) rcu_ref) * (num_sce + (0.5 * num_lfe) + (0.5 * num_cce_indep) +
+      (0.4 * num_cce_dep));
+
+  if (num_cpe < 2)
+    rcu += (rcu_ref + (rcu_ref - 1)) * num_cpe;
+  else
+    rcu += (rcu_ref + (rcu_ref - 1) * ((2 * num_cpe) - 1));
+
+  num_channels = num_sce + (2 * num_cpe) + num_lfe;
+
+  if (profile == 2) {
+    /* AAC LC => return the level as per the 'AAC Profile' */
+    if (num_channels <= 2 && rate <= 24000 && pcu <= 3 && rcu <= 5)
+      ret = 1;
+    else if (num_channels <= 2 && rate <= 48000 && pcu <= 6 && rcu <= 5)
+      ret = 2;
+    /* There is no level 3 for the AAC Profile */
+    else if (num_channels <= 5 && rate <= 48000 && pcu <= 19 && rcu <= 15)
+      ret = 4;
+    else if (num_channels <= 5 && rate <= 96000 && pcu <= 38 && rcu <= 15)
+      ret = 5;
+  } else {
+    /* Return the level as per the 'Main Profile' */
+    if (pcu < 40 && rcu < 20)
+      ret = 1;
+    else if (pcu < 80 && rcu < 64)
+      ret = 2;
+    else if (pcu < 160 && rcu < 128)
+      ret = 3;
+    else if (pcu < 320 && rcu < 256)
+      ret = 4;
+  }
+
+  if (ret == -1) {
+    GST_WARNING ("couldn't determine level: profile=%u, rate=%u, "
+        "channel_config=%u, pcu=%d,rcu=%d", profile, rate, channel_config, pcu,
+        rcu);
+    return NULL;
+  } else {
+    /* For fast and convenient int -> string conversion */
+    static const char itoa[][2] = {
+      "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"
+    };
+
+    g_assert (ret < G_N_ELEMENTS (itoa));
+    return itoa[ret];
+  }
+}
+
+/**
+ * gst_codec_utils_aac_caps_set_level:
+ * @caps: the #GstCaps to which the level is to be added
+ * @audio_config: a pointer to the AudioSpecificConfig as specified in the
+ *                Elementary Stream Descriptor (esds) in ISO/IEC 14496-1 (see
+ *                below for a more details).
+ * @len: Length of @audio_config in bytes
+ *
+ * Sets the level in @caps if it can be determined from @audio_config. See
+ * #gst_codec_utils_aac_get_level() for more details on the parameters.
+ *
+ * Returns: TRUE if the level could be set, FALSE otherwise.
+ */
+gboolean
+gst_codec_utils_aac_caps_set_level (GstCaps * caps,
+    const guint8 * audio_config, guint len)
+{
+  const gchar *level;
+
+  g_return_val_if_fail (GST_IS_CAPS (caps), FALSE);
+  g_return_val_if_fail (audio_config != NULL, FALSE);
+
+  level = gst_codec_utils_aac_get_level (audio_config, len);
+
+  if (!level)
+    return FALSE;
+
+  gst_caps_set_simple (caps, "level", G_TYPE_STRING, level, NULL);
+
+  return TRUE;
+}
similarity index 53%
rename from gst/typefind/gstaacutil.h
rename to gst-libs/gst/pbutils/codec-utils.h
index 4fe5a58..0b54da2 100644 (file)
@@ -1,9 +1,7 @@
-/* GStreamer
- * Copyright (C) 2010 Nokia Corporation
- * Copyright (C) 2010 Collabora Multimedia
+/* GStreamer base utils library codec-specific utility functions
  * Copyright (C) 2010 Arun Raghavan <arun.raghavan@collabora.co.uk>
- *
- * gstaacutil.h: collection of AAC helper utilities
+ *               2010 Collabora Multimedia
+ *               2010 Nokia Corporation
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
  * Boston, MA 02111-1307, USA.
  */
 
-#ifndef __GST_AAC_UTIL_H__
-#define __GST_AAC_UTIL_H__
-
-#include <glib.h>
+#ifndef __GST_PB_UTILS_CODEC_UTILS_H__
+#define __GST_PB_UTILS_CODEC_UTILS_H__
 
-/* FIXME: This file is duplicated in gst-plugins-* wherever needed, so if you
- * update this file, please find all other instances and update them as well.
- * This less-than-optimal setup is being used till there is a standard location
- * for such common functionality.
- */
+#include <gst/gst.h>
 
 G_BEGIN_DECLS
 
-gint    gst_aac_level_from_header (guint profile,
-                                   guint sample_freq_idx,
-                                   guint channel_config);
+/* AAC */
+
+guint         gst_codec_utils_aac_get_sample_rate_from_index (guint sr_idx);
+
+const gchar * gst_codec_utils_aac_get_level      (const guint8 * audio_config,
+                                                  guint          len);
+
+gboolean      gst_codec_utils_aac_caps_set_level (GstCaps      * caps,
+                                                  const guint8 * audio_config,
+                                                  guint          len);
 
 G_END_DECLS
 
-#endif /* __GST_AAC_UTIL_H__*/
+#endif /* __GST_PB_UTILS_CODEC_UTILS_H__ */
index 1e401b5..5fabf01 100644 (file)
@@ -26,6 +26,7 @@
 #include <gst/pbutils/descriptions.h>
 #include <gst/pbutils/missing-plugins.h>
 #include <gst/pbutils/install-plugins.h>
+#include <gst/pbutils/codec-utils.h>
 #include <gst/pbutils/pbutils-enumtypes.h>
 #include <gst/pbutils/pbutils-marshal.h>
 #include <gst/pbutils/gstdiscoverer.h>
index b5d5766..cf9e59e 100644 (file)
@@ -1,9 +1,12 @@
 plugin_LTLIBRARIES = libgsttypefindfunctions.la
 
-libgsttypefindfunctions_la_SOURCES = gsttypefindfunctions.c gstaacutil.c
-libgsttypefindfunctions_la_CFLAGS = $(GST_CFLAGS) $(GIO_CFLAGS)
+libgsttypefindfunctions_la_SOURCES = gsttypefindfunctions.c
+libgsttypefindfunctions_la_CFLAGS = \
+       $(GST_PLUGINS_BASE_CFLAGS) \
+       $(GST_CFLAGS) $(GIO_CFLAGS)
 libgsttypefindfunctions_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
-libgsttypefindfunctions_la_LIBADD = $(GST_LIBS) $(GIO_LIBS)
-libgsttypefindfunctions_la_LIBTOOLFLAGS = --tag=disable-static
+libgsttypefindfunctions_la_LIBADD = \
+       $(top_builddir)/gst-libs/gst/pbutils/libgstpbutils-@GST_MAJORMINOR@.la \
+       $(GST_LIBS) $(GIO_LIBS)
 
-noinst_HEADERS = gstaacutil.h
+libgsttypefindfunctions_la_LIBTOOLFLAGS = --tag=disable-static
diff --git a/gst/typefind/gstaacutil.c b/gst/typefind/gstaacutil.c
deleted file mode 100644 (file)
index 229b078..0000000
+++ /dev/null
@@ -1,176 +0,0 @@
-/* GStreamer
- * Copyright (C) 2010 Nokia Corporation
- * Copyright (C) 2010 Collabora Multimedia
- * Copyright (C) 2010 Arun Raghavan <arun.raghavan@collabora.co.uk>
- *
- * gstaacutil.c: collection of AAC helper utilities
- *
- * 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.
- */
-
-#include <gst/gst.h>
-
-#include "gstaacutil.h"
-
-/* FIXME: This file is duplicated in gst-plugins-* wherever needed, so if you
- * update this file, please find all other instances and update them as well.
- * This less-than-optimal setup is being used till there is a standard location
- * for such common functionality.
- */
-
-/* Determines the level of a stream as defined in ISO/IEC 14496-3. The
- * sample_frequency_index and channel_configuration must be got from the ESDS
- * for MP4 files and the ADTS header for ADTS streams.
- *
- * For AAC LC streams, we assume that apply the constraints from the AAC audio
- * profile. For AAC Main/LTP/SSR/..., we use the Main profile.
- *
- * FIXME: HE-AAC support is TBD.
- *
- * Returns -1 if the level could not be determined.
- */
-gint
-gst_aac_level_from_header (guint profile, guint rate, guint channel_config)
-{
-  /* Number of single channel elements, channel pair elements, low frequency
-   * elements, independently switched coupling channel elements, and
-   * dependently switched coupling channel elements.
-   *
-   * Note: The 2 CCE types are ignored for now as they require us to actually
-   * parse the first frame, and they are rarely found in actual streams.
-   */
-  int num_sce = 0, num_cpe = 0, num_lfe = 0, num_cce_indep = 0, num_cce_dep = 0;
-  int num_channels;
-  /* Processor and RAM Complexity Units (calculated and "reference" for single
-   * channel) */
-  int pcu, rcu, pcu_ref, rcu_ref;
-
-  switch (channel_config) {
-    case 0:
-      /* Channel config is defined in the AudioObjectType's SpecificConfig,
-       * which requires some amount of digging through the headers. I only see
-       * this done in the MPEG conformance streams - FIXME */
-      GST_WARNING ("Found a stream with channel configuration in the "
-          "AudioSpecificConfig. Please file a bug with a link to the media if "
-          "possible.");
-      return -1;
-    case 1:
-      /* front center */
-      num_sce = 1;
-      break;
-    case 2:
-      /* front left and right */
-      num_cpe = 1;
-      break;
-    case 3:
-      /* front left, right, and center */
-      num_sce = 1;
-      num_cpe = 1;
-      break;
-    case 4:
-      /* front left, right, and center; rear surround */
-      num_sce = 2;
-      num_cpe = 1;
-      break;
-    case 5:
-      /* front left, right, and center; rear left and right surround */
-      num_sce = 1;
-      num_cpe = 2;
-      break;
-    case 6:
-      /* front left, right, center and LFE; rear left and right surround */
-      num_sce = 1;
-      num_cpe = 2;
-      break;
-    case 7:
-      /* front left, right, center and LFE; outside front left and right;
-       * rear left and right surround */
-      num_sce = 1;
-      num_cpe = 3;
-      num_lfe = 1;
-      break;
-    default:
-      GST_WARNING ("Unknown channel config in header: %d", channel_config);
-      return -1;
-  }
-
-  switch (profile) {
-    case 0:                    /* NULL */
-      GST_WARNING ("profile 0 is not a valid profile");
-      return -1;
-    case 2:                    /* LC */
-      pcu_ref = 3;
-      rcu_ref = 3;
-      break;
-    case 3:                    /* SSR */
-      pcu_ref = 4;
-      rcu_ref = 3;
-      break;
-    case 4:                    /* LTP */
-      pcu_ref = 4;
-      rcu_ref = 4;
-      break;
-    case 1:                    /* Main */
-    default:
-      /* Other than a couple of ER profiles, Main is the worst-case */
-      pcu_ref = 5;
-      rcu_ref = 5;
-      break;
-  }
-
-  /* "fs_ref" is 48000 Hz for AAC Main/LC/SSR/LTP. SBR's fs_ref is defined as
-   * 24000/48000 (in/out), for SBR streams. Actual support is a FIXME */
-
-  pcu = ((float) rate / 48000) * pcu_ref *
-      ((2 * num_cpe) + num_sce + num_lfe + num_cce_indep + (0.3 * num_cce_dep));
-
-  rcu = ((float) rcu_ref) * (num_sce + (0.5 * num_lfe) + (0.5 * num_cce_indep) +
-      (0.4 * num_cce_dep));
-
-  if (num_cpe < 2)
-    rcu += (rcu_ref + (rcu_ref - 1)) * num_cpe;
-  else
-    rcu += (rcu_ref + (rcu_ref - 1) * ((2 * num_cpe) - 1));
-
-  num_channels = num_sce + (2 * num_cpe) + num_lfe;
-
-  if (profile == 2) {
-    /* AAC LC => return the level as per the 'AAC Profile' */
-    if (num_channels <= 2 && rate <= 24000 && pcu <= 3 && rcu <= 5)
-      return 1;
-    if (num_channels <= 2 && rate <= 48000 && pcu <= 6 && rcu <= 5)
-      return 2;
-    /* There is no level 3 for the AAC Profile */
-    if (num_channels <= 5 && rate <= 48000 && pcu <= 19 && rcu <= 15)
-      return 4;
-    if (num_channels <= 5 && rate <= 96000 && pcu <= 38 && rcu <= 15)
-      return 5;
-  } else {
-    /* Return the level as per the 'Main Profile' */
-    if (pcu < 40 && rcu < 20)
-      return 1;
-    if (pcu < 80 && rcu < 64)
-      return 2;
-    if (pcu < 160 && rcu < 128)
-      return 3;
-    if (pcu < 320 && rcu < 256)
-      return 4;
-  }
-
-  GST_WARNING ("couldn't determine level: profile=%u,rate=%u,channel_config=%u,"
-      "pcu=%d,rcu=%d", profile, rate, channel_config, pcu, rcu);
-  return -1;
-}
index 05f8c84..d9a011e 100644 (file)
@@ -40,7 +40,7 @@
 #include <string.h>
 #include <ctype.h>
 
-#include "gstaacutil.h"
+#include <gst/pbutils/pbutils.h>
 
 GST_DEBUG_CATEGORY_STATIC (type_find_debug);
 #define GST_CAT_DEFAULT type_find_debug
@@ -661,9 +661,6 @@ aac_type_find (GstTypeFind * tf, gpointer unused)
 {
   /* LUT to convert the AudioObjectType from the ADTS header to a string */
   static const gchar profile_to_string[][5] = { "main", "lc", "ssr", "ltp" };
-  static const guint sample_freq[] = { 96000, 88200, 64000, 48000, 44100,
-    32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350
-  };
   DataScanCtx c = { 0, NULL, 0 };
 
   while (c.offset < AAC_AMOUNT) {
@@ -697,7 +694,7 @@ aac_type_find (GstTypeFind * tf, gpointer unused)
       if ((snc & 0xfff6) == 0xfff0) {
         GstCaps *caps;
         guint mpegversion, sample_freq_idx, channel_config, profile, rate;
-        gint level;
+        guint8 audio_config[2];
 
         mpegversion = (c.data[1] & 0x08) ? 2 : 4;
         profile = c.data[2] >> 6;
@@ -715,11 +712,17 @@ aac_type_find (GstTypeFind * tf, gpointer unused)
           goto next;
         }
 
-        rate = sample_freq[sample_freq_idx];
+        rate = gst_codec_utils_aac_get_sample_rate_from_index (sample_freq_idx);
         GST_LOG ("ADTS: profile=%u, rate=%u", profile, rate);
 
+        /* The ADTS frame header is slightly different from the
+         * AudioSpecificConfig defined for the MPEG-4 container, so we just
+         * construct enough of it for getting the level here. */
         /* ADTS counts profiles from 0 instead of 1 to save bits */
-        level = gst_aac_level_from_header (profile + 1, rate, channel_config);
+        audio_config[0] = (profile + 1) << 3;
+        audio_config[0] |= (sample_freq_idx >> 1) & 0x7;
+        audio_config[1] = (sample_freq_idx & 0x1) << 7;
+        audio_config[1] |= (channel_config & 0xf) << 3;
 
         caps = gst_caps_new_simple ("audio/mpeg",
             "framed", G_TYPE_BOOLEAN, FALSE,
@@ -728,15 +731,7 @@ aac_type_find (GstTypeFind * tf, gpointer unused)
             "base-profile", G_TYPE_STRING, profile_to_string[profile],
             "profile", G_TYPE_STRING, profile_to_string[profile], NULL);
 
-        if (level != -1) {
-          gchar level_str[16];
-
-          /* we use a string here because h.264 levels are also strings and
-           * there aren't a lot of levels, so it's not too awkward to not use
-           * and integer here and keep the field type consistent with h.264 */
-          g_snprintf (level_str, sizeof (level_str), "%d", level);
-          gst_caps_set_simple (caps, "level", G_TYPE_STRING, level_str, NULL);
-        }
+        gst_codec_utils_aac_caps_set_level (caps, audio_config, 2);
 
         /* add rate and number of channels if we can */
         if (channel_config != 0 && channel_config <= 7) {
index c3435f4..87ce127 100644 (file)
@@ -1,4 +1,7 @@
 EXPORTS
+       gst_codec_utils_aac_caps_set_level
+       gst_codec_utils_aac_get_level
+       gst_codec_utils_aac_get_sample_rate_from_index
        gst_discoverer_audio_info_get_bitrate
        gst_discoverer_audio_info_get_channels
        gst_discoverer_audio_info_get_depth