pbutils: add AAC profile detection to codec utils
authorArun Raghavan <arun.raghavan@collabora.co.uk>
Fri, 30 Apr 2010 09:42:04 +0000 (15:12 +0530)
committerTim-Philipp Müller <tim.muller@collabora.co.uk>
Thu, 30 Sep 2010 12:09:29 +0000 (13:09 +0100)
This moves AAC profile detection to pbutils, and uses this in
typefindfunctions. This will also be used in qtdemux.

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

API: gst_codec_utils_aac_get_profile()
API: codec_utils_aac_caps_set_level_and_profile()

gst-libs/gst/pbutils/codec-utils.c
gst-libs/gst/pbutils/codec-utils.h
gst/typefind/gsttypefindfunctions.c
win32/common/libgstpbutils.def

index 18d91b6..412ca65 100644 (file)
 
 #include "pbutils.h"
 
 
 #include "pbutils.h"
 
+#define GST_SIMPLE_CAPS_HAS_NAME(caps,name) \
+    gst_structure_has_name(gst_caps_get_structure((caps),0),(name))
+
+#define GST_SIMPLE_CAPS_HAS_FIELD(caps,field) \
+    gst_structure_has_field(gst_caps_get_structure((caps),0),(field))
+
 /**
  * gst_codec_utils_aac_get_sample_rate_from_index:
  * @sr_idx: Sample rate index as from the AudioSpecificConfig (MPEG-4
 /**
  * gst_codec_utils_aac_get_sample_rate_from_index:
  * @sr_idx: Sample rate index as from the AudioSpecificConfig (MPEG-4
@@ -59,6 +65,50 @@ gst_codec_utils_aac_get_sample_rate_from_index (guint sr_idx)
 }
 
 /**
 }
 
 /**
+ * gst_codec_utils_aac_get_profile:
+ * @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
+ *
+ * Returns the profile of the given AAC stream as a string. The profile is
+ * determined using the AudioObjectType field which is in the first 5 bits of
+ * @audio_config.
+ *
+ * <note>
+ * HE-AAC support has not yet been implemented.
+ * </note>
+ *
+ * Returns: The profile as a const string and NULL if the profile could not be
+ * determined.
+ */
+const gchar *
+gst_codec_utils_aac_get_profile (const guint8 * audio_config, guint len)
+{
+  guint profile;
+
+  if (len < 1)
+    return NULL;
+
+  profile = audio_config[0] >> 3;
+  switch (profile) {
+    case 1:
+      return "main";
+    case 2:
+      return "lc";
+    case 3:
+      return "ssr";
+    case 4:
+      return "ltp";
+    default:
+      break;
+  }
+
+  GST_DEBUG ("Invalid profile idx: %u", profile);
+  return NULL;
+}
+
+/**
  * 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
  * 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
@@ -246,33 +296,55 @@ gst_codec_utils_aac_get_level (const guint8 * audio_config, guint len)
 }
 
 /**
 }
 
 /**
- * gst_codec_utils_aac_caps_set_level:
- * @caps: the #GstCaps to which the level is to be added
+ * gst_codec_utils_aac_caps_set_level_and_profile:
+ * @caps: the #GstCaps to which level and profile fields are 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
  *
  * @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.
+ * Sets the level and profile on @caps if it can be determined from
+ * @audio_config. See #gst_codec_utils_aac_get_level() and
+ * gst_codec_utils_aac_get_profile() for more details on the parameters.
+ * @caps must be audio/mpeg caps with an "mpegversion" field of either 2 or 4.
+ * If mpegversion is 4, the <tt>base-profile</tt> field is also set in @caps.
  *
  *
- * Returns: TRUE if the level could be set, FALSE otherwise.
+ * Returns: TRUE if the level and profile could be set, FALSE otherwise.
  */
 gboolean
  */
 gboolean
-gst_codec_utils_aac_caps_set_level (GstCaps * caps,
+gst_codec_utils_aac_caps_set_level_and_profile (GstCaps * caps,
     const guint8 * audio_config, guint len)
 {
     const guint8 * audio_config, guint len)
 {
-  const gchar *level;
+  GstStructure *s;
+  const gchar *level, *profile;
+  int mpegversion = 0;
 
   g_return_val_if_fail (GST_IS_CAPS (caps), FALSE);
 
   g_return_val_if_fail (GST_IS_CAPS (caps), FALSE);
+  g_return_val_if_fail (GST_CAPS_IS_SIMPLE (caps), FALSE);
+  g_return_val_if_fail (GST_SIMPLE_CAPS_HAS_NAME (caps, "audio/mpeg"), FALSE);
+  g_return_val_if_fail (GST_SIMPLE_CAPS_HAS_FIELD (caps, "mpegversion"), FALSE);
   g_return_val_if_fail (audio_config != NULL, FALSE);
 
   g_return_val_if_fail (audio_config != NULL, FALSE);
 
+  s = gst_caps_get_structure (caps, 0);
+
+  gst_structure_get_int (s, "mpegversion", &mpegversion);
+  g_return_val_if_fail (mpegversion == 2 || mpegversion == 4, FALSE);
+
   level = gst_codec_utils_aac_get_level (audio_config, len);
 
   level = gst_codec_utils_aac_get_level (audio_config, len);
 
-  if (!level)
-    return FALSE;
+  if (level != NULL)
+    gst_structure_set (s, "level", G_TYPE_STRING, level, NULL);
 
 
-  gst_caps_set_simple (caps, "level", G_TYPE_STRING, level, NULL);
+  profile = gst_codec_utils_aac_get_profile (audio_config, len);
+
+  if (profile != NULL) {
+    if (mpegversion == 4) {
+      gst_structure_set (s, "base-profile", G_TYPE_STRING, profile,
+          "profile", G_TYPE_STRING, profile, NULL);
+    } else {
+      gst_structure_set (s, "profile", G_TYPE_STRING, profile, NULL);
+    }
+  }
 
 
-  return TRUE;
+  return (level != NULL && profile != NULL);
 }
 }
index 0b54da2..2a83348 100644 (file)
@@ -30,12 +30,13 @@ G_BEGIN_DECLS
 
 guint         gst_codec_utils_aac_get_sample_rate_from_index (guint sr_idx);
 
 
 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);
+const gchar * gst_codec_utils_aac_get_profile (const guint8 * audio_config, guint len);
 
 
-gboolean      gst_codec_utils_aac_caps_set_level (GstCaps      * caps,
-                                                  const guint8 * audio_config,
-                                                  guint          len);
+const gchar * gst_codec_utils_aac_get_level   (const guint8 * audio_config, guint len);
+
+gboolean      gst_codec_utils_aac_caps_set_level_and_profile (GstCaps      * caps,
+                                                              const guint8 * audio_config,
+                                                              guint          len);
 
 G_END_DECLS
 
 
 G_END_DECLS
 
index d9a011e..81d21d0 100644 (file)
@@ -660,7 +660,6 @@ static void
 aac_type_find (GstTypeFind * tf, gpointer unused)
 {
   /* LUT to convert the AudioObjectType from the ADTS header to a string */
 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" };
   DataScanCtx c = { 0, NULL, 0 };
 
   while (c.offset < AAC_AMOUNT) {
   DataScanCtx c = { 0, NULL, 0 };
 
   while (c.offset < AAC_AMOUNT) {
@@ -693,11 +692,11 @@ aac_type_find (GstTypeFind * tf, gpointer unused)
       snc = GST_READ_UINT16_BE (c.data + len);
       if ((snc & 0xfff6) == 0xfff0) {
         GstCaps *caps;
       snc = GST_READ_UINT16_BE (c.data + len);
       if ((snc & 0xfff6) == 0xfff0) {
         GstCaps *caps;
-        guint mpegversion, sample_freq_idx, channel_config, profile, rate;
+        guint mpegversion, sample_freq_idx, channel_config, profile_idx, rate;
         guint8 audio_config[2];
 
         mpegversion = (c.data[1] & 0x08) ? 2 : 4;
         guint8 audio_config[2];
 
         mpegversion = (c.data[1] & 0x08) ? 2 : 4;
-        profile = c.data[2] >> 6;
+        profile_idx = c.data[2] >> 6;
         sample_freq_idx = ((c.data[2] & 0x3c) >> 2);
         channel_config = ((c.data[2] & 0x01) << 2) + (c.data[3] >> 6);
 
         sample_freq_idx = ((c.data[2] & 0x3c) >> 2);
         channel_config = ((c.data[2] & 0x01) << 2) + (c.data[3] >> 6);
 
@@ -713,13 +712,13 @@ aac_type_find (GstTypeFind * tf, gpointer unused)
         }
 
         rate = gst_codec_utils_aac_get_sample_rate_from_index (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);
+        GST_LOG ("ADTS: profile=%u, rate=%u", profile_idx, 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 */
 
         /* 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 */
-        audio_config[0] = (profile + 1) << 3;
+        audio_config[0] = (profile_idx + 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;
         audio_config[0] |= (sample_freq_idx >> 1) & 0x7;
         audio_config[1] = (sample_freq_idx & 0x1) << 7;
         audio_config[1] |= (channel_config & 0xf) << 3;
@@ -727,11 +726,9 @@ aac_type_find (GstTypeFind * tf, gpointer unused)
         caps = gst_caps_new_simple ("audio/mpeg",
             "framed", G_TYPE_BOOLEAN, FALSE,
             "mpegversion", G_TYPE_INT, mpegversion,
         caps = gst_caps_new_simple ("audio/mpeg",
             "framed", G_TYPE_BOOLEAN, FALSE,
             "mpegversion", G_TYPE_INT, mpegversion,
-            "stream-type", G_TYPE_STRING, "adts",
-            "base-profile", G_TYPE_STRING, profile_to_string[profile],
-            "profile", G_TYPE_STRING, profile_to_string[profile], NULL);
+            "stream-type", G_TYPE_STRING, "adts", NULL);
 
 
-        gst_codec_utils_aac_caps_set_level (caps, audio_config, 2);
+        gst_codec_utils_aac_caps_set_level_and_profile (caps, audio_config, 2);
 
         /* add rate and number of channels if we can */
         if (channel_config != 0 && channel_config <= 7) {
 
         /* add rate and number of channels if we can */
         if (channel_config != 0 && channel_config <= 7) {
index 87ce127..81123d2 100644 (file)
@@ -1,6 +1,7 @@
 EXPORTS
 EXPORTS
-       gst_codec_utils_aac_caps_set_level
+       gst_codec_utils_aac_caps_set_level_and_profile
        gst_codec_utils_aac_get_level
        gst_codec_utils_aac_get_level
+       gst_codec_utils_aac_get_profile
        gst_codec_utils_aac_get_sample_rate_from_index
        gst_discoverer_audio_info_get_bitrate
        gst_discoverer_audio_info_get_channels
        gst_codec_utils_aac_get_sample_rate_from_index
        gst_discoverer_audio_info_get_bitrate
        gst_discoverer_audio_info_get_channels