faac: Add the profile and level to the caps
authorSebastian Dröge <sebastian.droege@collabora.co.uk>
Fri, 27 May 2011 08:11:32 +0000 (10:11 +0200)
committerSebastian Dröge <sebastian.droege@collabora.co.uk>
Fri, 27 May 2011 08:11:32 +0000 (10:11 +0200)
Also negotiate the profile from the downstream peer caps
instead of using a property.

Fixes bug #650594.

ext/faac/Makefile.am
ext/faac/gstfaac.c
ext/faac/gstfaac.h

index b4ec10a..3cdf9ca 100644 (file)
@@ -4,7 +4,7 @@ libgstfaac_la_SOURCES = gstfaac.c
 libgstfaac_la_CFLAGS = $(FAAC_CFLAGS) $(GST_CFLAGS) $(GST_BASE_CFLAGS) \
        $(GST_PLUGINS_BASE_CFLAGS)
 libgstfaac_la_LIBADD = $(FAAC_LIBS) $(GST_BASE_LIBS) $(GST_PLUGINS_BASE_LIBS) \
-       -lgstaudio-@GST_MAJORMINOR@
+       -lgstaudio-@GST_MAJORMINOR@ -lgstpbutils-@GST_MAJORMINOR@
 libgstfaac_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
 libgstfaac_la_LIBTOOLFLAGS = --tag=disable-static
 
index 5bc44f9..2ed0f6f 100644 (file)
  *
  * faac encodes raw audio to AAC (MPEG-4 part 3) streams.
  *
- *
- * The #GstFaac:profile property determines the AAC profile, where the default
- * LC (Low Complexity) profile is most widely used, supported and suitable for
- * general use. The other profiles are very rarely used and often not supported.
- *
  * <refsect2>
  * <title>Example launch line</title>
  * |[
@@ -44,6 +39,7 @@
 #include <string.h>
 
 #include <gst/audio/multichannel.h>
+#include <gst/pbutils/codec-utils.h>
 
 #include "gstfaac.h"
 
 #endif
 #define SRC_CAPS \
     "audio/mpeg, "                     \
-    "mpegversion = (int) { 4, 2 }, "   \
+    "mpegversion = (int) 4, "   \
     "channels = (int) [ 1, 6 ], "      \
     "rate = (int) [ 8000, 96000 ], "   \
-    "stream-format = (string) { adts, raw } "
+    "stream-format = (string) { adts, raw }, " \
+    "base-profile = (string) { main, lc, ssr, ltp }; " \
+    "audio/mpeg, "                     \
+    "mpegversion = (int) 2, "   \
+    "channels = (int) [ 1, 6 ], "      \
+    "rate = (int) [ 8000, 96000 ], "   \
+    "stream-format = (string) { adts, raw }, " \
+    "profile = (string) { main, lc }"
 static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
     GST_PAD_SRC,
     GST_PAD_ALWAYS,
@@ -121,10 +124,8 @@ static GstElementClass *parent_class = NULL;
 GST_DEBUG_CATEGORY_STATIC (faac_debug);
 #define GST_CAT_DEFAULT faac_debug
 
-#define FAAC_DEFAULT_MPEGVERSION 4
 #define FAAC_DEFAULT_OUTPUTFORMAT 0     /* RAW */
 #define FAAC_DEFAULT_BITRATE      128 * 1000
-#define FAAC_DEFAULT_PROFILE      LOW
 #define FAAC_DEFAULT_TNS          FALSE
 #define FAAC_DEFAULT_MIDSIDE      TRUE
 #define FAAC_DEFAULT_SHORTCTL     SHORTCTL_NORMAL
@@ -180,28 +181,6 @@ gst_faac_base_init (GstFaacClass * klass)
   GST_DEBUG_CATEGORY_INIT (faac_debug, "faac", 0, "AAC encoding");
 }
 
-#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, "LC", "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)
@@ -240,10 +219,6 @@ gst_faac_class_init (GstFaacClass * klass)
       g_param_spec_int ("bitrate", "Bitrate (bps)", "Bitrate in bits/sec",
           8 * 1000, 320 * 1000, FAAC_DEFAULT_BITRATE,
           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-  g_object_class_install_property (gobject_class, PROP_PROFILE,
-      g_param_spec_enum ("profile", "Profile", "MPEG/AAC encoding profile",
-          GST_TYPE_FAAC_PROFILE, FAAC_DEFAULT_PROFILE,
-          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
   g_object_class_install_property (gobject_class, PROP_TNS,
       g_param_spec_boolean ("tns", "TNS", "Use temporal noise shaping",
           FAAC_DEFAULT_TNS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
@@ -280,9 +255,11 @@ gst_faac_init (GstFaac * faac)
 
   faac->adapter = gst_adapter_new ();
 
+  faac->profile = LOW;
+  faac->mpegversion = 4;
+
   /* default properties */
   faac->bitrate = FAAC_DEFAULT_BITRATE;
-  faac->profile = FAAC_DEFAULT_PROFILE;
   faac->shortctl = FAAC_DEFAULT_SHORTCTL;
   faac->outputformat = FAAC_DEFAULT_OUTPUTFORMAT;
   faac->tns = FAAC_DEFAULT_TNS;
@@ -410,6 +387,7 @@ gst_faac_negotiate (GstFaac * faac)
   if (caps && gst_caps_get_size (caps) > 0) {
     GstStructure *s = gst_caps_get_structure (caps, 0);
     const gchar *str = NULL;
+    gint i = 4;
 
     if ((str = gst_structure_get_string (s, "stream-format"))) {
       if (strcmp (str, "adts") == 0) {
@@ -423,11 +401,30 @@ gst_faac_negotiate (GstFaac * faac)
         faac->outputformat = 0;
       }
     }
+
+    if ((str = gst_structure_get_string (s, "profile"))) {
+      if (strcmp (str, "main") == 0) {
+        faac->profile = MAIN;
+      } else if (strcmp (str, "lc") == 0) {
+        faac->profile = LOW;
+      } else if (strcmp (str, "ssr") == 0) {
+        faac->profile = SSR;
+      } else if (strcmp (str, "ltp") == 0) {
+        faac->profile = LTP;
+      } else {
+        faac->profile = LOW;
+      }
+    }
+
+    if (!gst_structure_get_int (s, "mpegversion", &i) || i == 4) {
+      faac->mpegversion = 4;
+    } else {
+      faac->mpegversion = 2;
+    }
   }
 
   if (caps)
     gst_caps_unref (caps);
-
 }
 
 static gboolean
@@ -521,39 +518,14 @@ refuse_caps:
 static gboolean
 gst_faac_configure_source_pad (GstFaac * faac)
 {
-  GstCaps *allowed_caps;
   GstCaps *srccaps;
   gboolean ret = FALSE;
-  gint n, ver, mpegversion = 2;
   faacEncConfiguration *conf;
   guint maxbitrate;
 
-  mpegversion = FAAC_DEFAULT_MPEGVERSION;
-
-  allowed_caps = gst_pad_get_allowed_caps (faac->srcpad);
-  GST_DEBUG_OBJECT (faac, "allowed caps: %" GST_PTR_FORMAT, allowed_caps);
-
-  if (allowed_caps) {
-    if (gst_caps_is_empty (allowed_caps))
-      goto empty_caps;
-
-    if (!gst_caps_is_any (allowed_caps)) {
-      for (n = 0; n < gst_caps_get_size (allowed_caps); n++) {
-        GstStructure *s = gst_caps_get_structure (allowed_caps, n);
-
-        if (gst_structure_get_int (s, "mpegversion", &ver) &&
-            (ver == 4 || ver == 2)) {
-          mpegversion = ver;
-          break;
-        }
-      }
-    }
-    gst_caps_unref (allowed_caps);
-  }
-
   /* we negotiated caps update current configuration */
   conf = faacEncGetCurrentConfiguration (faac->handle);
-  conf->mpegVersion = (mpegversion == 4) ? MPEG4 : MPEG2;
+  conf->mpegVersion = (faac->mpegversion == 4) ? MPEG4 : MPEG2;
   conf->aacObjectType = faac->profile;
   conf->allowMidside = faac->midside;
   conf->useLfe = 0;
@@ -591,14 +563,14 @@ gst_faac_configure_source_pad (GstFaac * faac)
 
   /* now create a caps for it all */
   srccaps = gst_caps_new_simple ("audio/mpeg",
-      "mpegversion", G_TYPE_INT, mpegversion,
+      "mpegversion", G_TYPE_INT, faac->mpegversion,
       "channels", G_TYPE_INT, faac->channels,
       "rate", G_TYPE_INT, faac->samplerate,
       "stream-format", G_TYPE_STRING, (faac->outputformat ? "adts" : "raw"),
       NULL);
 
-  if (!faac->outputformat) {
-    GstBuffer *codec_data;
+  /* DecoderSpecificInfo is only available for mpegversion=4 */
+  if (faac->mpegversion == 4) {
     guint8 *config = NULL;
     gulong config_len = 0;
 
@@ -606,16 +578,49 @@ gst_faac_configure_source_pad (GstFaac * faac)
     GST_DEBUG_OBJECT (faac, "retrieving decoder info");
     faacEncGetDecoderSpecificInfo (faac->handle, &config, &config_len);
 
-    /* copy it into a buffer */
-    codec_data = gst_buffer_new_and_alloc (config_len);
-    memcpy (GST_BUFFER_DATA (codec_data), config, config_len);
-    free (config);
+    if (!gst_codec_utils_aac_caps_set_level_and_profile (srccaps, config,
+            config_len)) {
+      free (config);
+      gst_caps_unref (srccaps);
+      goto invalid_codec_data;
+    }
+
+    if (!faac->outputformat) {
+      GstBuffer *codec_data;
+
+      /* copy it into a buffer */
+      codec_data = gst_buffer_new_and_alloc (config_len);
+      memcpy (GST_BUFFER_DATA (codec_data), config, config_len);
+
+      /* add to caps */
+      gst_caps_set_simple (srccaps,
+          "codec_data", GST_TYPE_BUFFER, codec_data, NULL);
+
+      gst_buffer_unref (codec_data);
+    }
 
-    /* add to caps */
-    gst_caps_set_simple (srccaps,
-        "codec_data", GST_TYPE_BUFFER, codec_data, NULL);
+    free (config);
+  } else {
+    const gchar *profile;
 
-    gst_buffer_unref (codec_data);
+    /* Add least add the profile to the caps */
+    switch (faac->profile) {
+      case MAIN:
+        profile = "main";
+        break;
+      case LTP:
+        profile = "ltp";
+        break;
+      case SSR:
+        profile = "ssr";
+        break;
+      case LOW:
+      default:
+        profile = "lc";
+        break;
+    }
+    gst_caps_set_simple (srccaps, "profile", G_TYPE_STRING, profile, NULL);
+    /* FIXME: How to get the profile for mpegversion==2? */
   }
 
   GST_DEBUG_OBJECT (faac, "src pad caps: %" GST_PTR_FORMAT, srccaps);
@@ -626,14 +631,14 @@ gst_faac_configure_source_pad (GstFaac * faac)
   return ret;
 
   /* ERROR */
-empty_caps:
+set_failed:
   {
-    gst_caps_unref (allowed_caps);
+    GST_WARNING_OBJECT (faac, "Faac doesn't support the current configuration");
     return FALSE;
   }
-set_failed:
+invalid_codec_data:
   {
-    GST_WARNING_OBJECT (faac, "Faac doesn't support the current configuration");
+    GST_ERROR_OBJECT (faac, "Invalid codec data");
     return FALSE;
   }
 }
@@ -850,9 +855,6 @@ gst_faac_set_property (GObject * object,
     case PROP_BITRATE:
       faac->bitrate = g_value_get_int (value);
       break;
-    case PROP_PROFILE:
-      faac->profile = g_value_get_enum (value);
-      break;
     case PROP_TNS:
       faac->tns = g_value_get_boolean (value);
       break;
@@ -882,9 +884,6 @@ gst_faac_get_property (GObject * object,
     case PROP_BITRATE:
       g_value_set_int (value, faac->bitrate);
       break;
-    case PROP_PROFILE:
-      g_value_set_enum (value, faac->profile);
-      break;
     case PROP_TNS:
       g_value_set_boolean (value, faac->tns);
       break;
index 7a282ec..49e2b85 100644 (file)
@@ -54,6 +54,7 @@ struct _GstFaac {
        bps,
        bitrate,
        profile,
+       mpegversion,
        shortctl,
        outputformat;
   gboolean tns,