faac: Add the profile and level to the caps

Also negotiate the profile from the downstream peer caps
instead of using a property.

Fixes bug #650594.
This commit is contained in:
Sebastian Dröge 2011-05-27 10:11:32 +02:00
parent 7f0aa4061e
commit 6702de4237
3 changed files with 86 additions and 86 deletions

View file

@ -4,7 +4,7 @@ libgstfaac_la_SOURCES = gstfaac.c
libgstfaac_la_CFLAGS = $(FAAC_CFLAGS) $(GST_CFLAGS) $(GST_BASE_CFLAGS) \ libgstfaac_la_CFLAGS = $(FAAC_CFLAGS) $(GST_CFLAGS) $(GST_BASE_CFLAGS) \
$(GST_PLUGINS_BASE_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS)
libgstfaac_la_LIBADD = $(FAAC_LIBS) $(GST_BASE_LIBS) $(GST_PLUGINS_BASE_LIBS) \ 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_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
libgstfaac_la_LIBTOOLFLAGS = --tag=disable-static libgstfaac_la_LIBTOOLFLAGS = --tag=disable-static

View file

@ -24,11 +24,6 @@
* *
* faac encodes raw audio to AAC (MPEG-4 part 3) streams. * 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> * <refsect2>
* <title>Example launch line</title> * <title>Example launch line</title>
* |[ * |[
@ -44,6 +39,7 @@
#include <string.h> #include <string.h>
#include <gst/audio/multichannel.h> #include <gst/audio/multichannel.h>
#include <gst/pbutils/codec-utils.h>
#include "gstfaac.h" #include "gstfaac.h"
@ -72,10 +68,17 @@
#endif #endif
#define SRC_CAPS \ #define SRC_CAPS \
"audio/mpeg, " \ "audio/mpeg, " \
"mpegversion = (int) { 4, 2 }, " \ "mpegversion = (int) 4, " \
"channels = (int) [ 1, 6 ], " \ "channels = (int) [ 1, 6 ], " \
"rate = (int) [ 8000, 96000 ], " \ "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", static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC, GST_PAD_SRC,
GST_PAD_ALWAYS, GST_PAD_ALWAYS,
@ -121,10 +124,8 @@ static GstElementClass *parent_class = NULL;
GST_DEBUG_CATEGORY_STATIC (faac_debug); GST_DEBUG_CATEGORY_STATIC (faac_debug);
#define GST_CAT_DEFAULT faac_debug #define GST_CAT_DEFAULT faac_debug
#define FAAC_DEFAULT_MPEGVERSION 4
#define FAAC_DEFAULT_OUTPUTFORMAT 0 /* RAW */ #define FAAC_DEFAULT_OUTPUTFORMAT 0 /* RAW */
#define FAAC_DEFAULT_BITRATE 128 * 1000 #define FAAC_DEFAULT_BITRATE 128 * 1000
#define FAAC_DEFAULT_PROFILE LOW
#define FAAC_DEFAULT_TNS FALSE #define FAAC_DEFAULT_TNS FALSE
#define FAAC_DEFAULT_MIDSIDE TRUE #define FAAC_DEFAULT_MIDSIDE TRUE
#define FAAC_DEFAULT_SHORTCTL SHORTCTL_NORMAL #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"); 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 ()) #define GST_TYPE_FAAC_SHORTCTL (gst_faac_shortctl_get_type ())
static GType static GType
gst_faac_shortctl_get_type (void) 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", g_param_spec_int ("bitrate", "Bitrate (bps)", "Bitrate in bits/sec",
8 * 1000, 320 * 1000, FAAC_DEFAULT_BITRATE, 8 * 1000, 320 * 1000, FAAC_DEFAULT_BITRATE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); 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_object_class_install_property (gobject_class, PROP_TNS,
g_param_spec_boolean ("tns", "TNS", "Use temporal noise shaping", g_param_spec_boolean ("tns", "TNS", "Use temporal noise shaping",
FAAC_DEFAULT_TNS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); 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->adapter = gst_adapter_new ();
faac->profile = LOW;
faac->mpegversion = 4;
/* default properties */ /* default properties */
faac->bitrate = FAAC_DEFAULT_BITRATE; faac->bitrate = FAAC_DEFAULT_BITRATE;
faac->profile = FAAC_DEFAULT_PROFILE;
faac->shortctl = FAAC_DEFAULT_SHORTCTL; faac->shortctl = FAAC_DEFAULT_SHORTCTL;
faac->outputformat = FAAC_DEFAULT_OUTPUTFORMAT; faac->outputformat = FAAC_DEFAULT_OUTPUTFORMAT;
faac->tns = FAAC_DEFAULT_TNS; faac->tns = FAAC_DEFAULT_TNS;
@ -410,6 +387,7 @@ gst_faac_negotiate (GstFaac * faac)
if (caps && gst_caps_get_size (caps) > 0) { if (caps && gst_caps_get_size (caps) > 0) {
GstStructure *s = gst_caps_get_structure (caps, 0); GstStructure *s = gst_caps_get_structure (caps, 0);
const gchar *str = NULL; const gchar *str = NULL;
gint i = 4;
if ((str = gst_structure_get_string (s, "stream-format"))) { if ((str = gst_structure_get_string (s, "stream-format"))) {
if (strcmp (str, "adts") == 0) { if (strcmp (str, "adts") == 0) {
@ -423,11 +401,30 @@ gst_faac_negotiate (GstFaac * faac)
faac->outputformat = 0; 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) if (caps)
gst_caps_unref (caps); gst_caps_unref (caps);
} }
static gboolean static gboolean
@ -521,39 +518,14 @@ refuse_caps:
static gboolean static gboolean
gst_faac_configure_source_pad (GstFaac * faac) gst_faac_configure_source_pad (GstFaac * faac)
{ {
GstCaps *allowed_caps;
GstCaps *srccaps; GstCaps *srccaps;
gboolean ret = FALSE; gboolean ret = FALSE;
gint n, ver, mpegversion = 2;
faacEncConfiguration *conf; faacEncConfiguration *conf;
guint maxbitrate; 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 */ /* we negotiated caps update current configuration */
conf = faacEncGetCurrentConfiguration (faac->handle); conf = faacEncGetCurrentConfiguration (faac->handle);
conf->mpegVersion = (mpegversion == 4) ? MPEG4 : MPEG2; conf->mpegVersion = (faac->mpegversion == 4) ? MPEG4 : MPEG2;
conf->aacObjectType = faac->profile; conf->aacObjectType = faac->profile;
conf->allowMidside = faac->midside; conf->allowMidside = faac->midside;
conf->useLfe = 0; conf->useLfe = 0;
@ -591,14 +563,14 @@ gst_faac_configure_source_pad (GstFaac * faac)
/* now create a caps for it all */ /* now create a caps for it all */
srccaps = gst_caps_new_simple ("audio/mpeg", srccaps = gst_caps_new_simple ("audio/mpeg",
"mpegversion", G_TYPE_INT, mpegversion, "mpegversion", G_TYPE_INT, faac->mpegversion,
"channels", G_TYPE_INT, faac->channels, "channels", G_TYPE_INT, faac->channels,
"rate", G_TYPE_INT, faac->samplerate, "rate", G_TYPE_INT, faac->samplerate,
"stream-format", G_TYPE_STRING, (faac->outputformat ? "adts" : "raw"), "stream-format", G_TYPE_STRING, (faac->outputformat ? "adts" : "raw"),
NULL); NULL);
if (!faac->outputformat) { /* DecoderSpecificInfo is only available for mpegversion=4 */
GstBuffer *codec_data; if (faac->mpegversion == 4) {
guint8 *config = NULL; guint8 *config = NULL;
gulong config_len = 0; gulong config_len = 0;
@ -606,16 +578,49 @@ gst_faac_configure_source_pad (GstFaac * faac)
GST_DEBUG_OBJECT (faac, "retrieving decoder info"); GST_DEBUG_OBJECT (faac, "retrieving decoder info");
faacEncGetDecoderSpecificInfo (faac->handle, &config, &config_len); faacEncGetDecoderSpecificInfo (faac->handle, &config, &config_len);
/* copy it into a buffer */ if (!gst_codec_utils_aac_caps_set_level_and_profile (srccaps, config,
codec_data = gst_buffer_new_and_alloc (config_len); config_len)) {
memcpy (GST_BUFFER_DATA (codec_data), 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);
}
free (config); free (config);
} else {
const gchar *profile;
/* add to caps */ /* Add least add the profile to the caps */
gst_caps_set_simple (srccaps, switch (faac->profile) {
"codec_data", GST_TYPE_BUFFER, codec_data, NULL); case MAIN:
profile = "main";
gst_buffer_unref (codec_data); 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); GST_DEBUG_OBJECT (faac, "src pad caps: %" GST_PTR_FORMAT, srccaps);
@ -626,16 +631,16 @@ gst_faac_configure_source_pad (GstFaac * faac)
return ret; return ret;
/* ERROR */ /* ERROR */
empty_caps:
{
gst_caps_unref (allowed_caps);
return FALSE;
}
set_failed: set_failed:
{ {
GST_WARNING_OBJECT (faac, "Faac doesn't support the current configuration"); GST_WARNING_OBJECT (faac, "Faac doesn't support the current configuration");
return FALSE; return FALSE;
} }
invalid_codec_data:
{
GST_ERROR_OBJECT (faac, "Invalid codec data");
return FALSE;
}
} }
static GstFlowReturn static GstFlowReturn
@ -850,9 +855,6 @@ gst_faac_set_property (GObject * object,
case PROP_BITRATE: case PROP_BITRATE:
faac->bitrate = g_value_get_int (value); faac->bitrate = g_value_get_int (value);
break; break;
case PROP_PROFILE:
faac->profile = g_value_get_enum (value);
break;
case PROP_TNS: case PROP_TNS:
faac->tns = g_value_get_boolean (value); faac->tns = g_value_get_boolean (value);
break; break;
@ -882,9 +884,6 @@ gst_faac_get_property (GObject * object,
case PROP_BITRATE: case PROP_BITRATE:
g_value_set_int (value, faac->bitrate); g_value_set_int (value, faac->bitrate);
break; break;
case PROP_PROFILE:
g_value_set_enum (value, faac->profile);
break;
case PROP_TNS: case PROP_TNS:
g_value_set_boolean (value, faac->tns); g_value_set_boolean (value, faac->tns);
break; break;

View file

@ -54,6 +54,7 @@ struct _GstFaac {
bps, bps,
bitrate, bitrate,
profile, profile,
mpegversion,
shortctl, shortctl,
outputformat; outputformat;
gboolean tns, gboolean tns,