diff --git a/omx/Makefile.am b/omx/Makefile.am index 72a7a2666d..a67157ddd4 100644 --- a/omx/Makefile.am +++ b/omx/Makefile.am @@ -12,6 +12,7 @@ libgstopenmax_la_SOURCES = \ gstomxmpeg4videoenc.c \ gstomxh264enc.c \ gstomxh263enc.c \ + gstomxaacenc.c \ gstbasevideocodec.c \ gstbasevideodecoder.c \ gstbasevideoencoder.c \ @@ -32,6 +33,7 @@ noinst_HEADERS = \ gstomxmpeg4videoenc.h \ gstomxh264enc.h \ gstomxh263enc.h \ + gstomxaacenc.h \ gstbasevideocodec.h \ gstbasevideodecoder.h \ gstbasevideoencoder.h \ diff --git a/omx/gstomx.c b/omx/gstomx.c index 05766f641b..772f3c48fc 100644 --- a/omx/gstomx.c +++ b/omx/gstomx.c @@ -33,6 +33,7 @@ #include "gstomxmpeg4videoenc.h" #include "gstomxh264enc.h" #include "gstomxh263enc.h" +#include "gstomxaacenc.h" GST_DEBUG_CATEGORY (gstomx_debug); #define GST_CAT_DEFAULT gstomx_debug @@ -1772,7 +1773,7 @@ static GType (*types[]) (void) = { gst_omx_mpeg4_video_dec_get_type, gst_omx_h264_dec_get_type, gst_omx_h263_dec_get_type, gst_omx_wmv_dec_get_type, gst_omx_mpeg4_video_enc_get_type, gst_omx_h264_enc_get_type, - gst_omx_h263_enc_get_type}; + gst_omx_h263_enc_get_type, gst_omx_aac_enc_get_type}; static GKeyFile *config = NULL; GKeyFile * diff --git a/omx/gstomx.conf b/omx/gstomx.conf index 944fe170dc..78f8e7d23c 100644 --- a/omx/gstomx.conf +++ b/omx/gstomx.conf @@ -24,3 +24,12 @@ rank=0 in-port-index=0 out-port-index=1 hacks=event-port-settings-changed-ndata-parameter-swap;video-framerate-integer;syncframe-flag-not-used + +[omxaacenc] +type-name=GstOMXAACEnc +core-name=/usr/local/lib/libomxil-bellagio.so.0 +component-name=OMX.st.audio_encoder.aac +rank=0 +in-port-index=0 +out-port-index=1 +hacks=event-port-settings-changed-ndata-parameter-swap diff --git a/omx/gstomxaacenc.c b/omx/gstomxaacenc.c new file mode 100644 index 0000000000..703e77690a --- /dev/null +++ b/omx/gstomxaacenc.c @@ -0,0 +1,432 @@ +/* + * Copyright (C) 2011, Hewlett-Packard Development Company, L.P. + * Author: Sebastian Dröge , Collabora Ltd. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation + * version 2.1 of the License. + * + * 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include "gstomxaacenc.h" + +GST_DEBUG_CATEGORY_STATIC (gst_omx_aac_enc_debug_category); +#define GST_CAT_DEFAULT gst_omx_aac_enc_debug_category + +/* prototypes */ +static void gst_omx_aac_enc_finalize (GObject * object); +static void gst_omx_aac_enc_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); +static void gst_omx_aac_enc_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); +static gboolean gst_omx_aac_enc_set_format (GstOMXAudioEnc * enc, + GstOMXPort * port, GstAudioState * state); +static GstCaps *gst_omx_aac_enc_get_caps (GstOMXAudioEnc * enc, + GstOMXPort * port, GstAudioState * state); + +enum +{ + PROP_0, + PROP_BITRATE, + PROP_AAC_TOOLS, + PROP_AAC_ERROR_RESILIENCE_TOOLS +}; + +#define DEFAULT_BITRATE (128000) +#define DEFAULT_AAC_TOOLS (OMX_AUDIO_AACToolMS | OMX_AUDIO_AACToolIS | OMX_AUDIO_AACToolTNS | OMX_AUDIO_AACToolPNS | OMX_AUDIO_AACToolLTP) +#define DEFAULT_AAC_ER_TOOLS (OMX_AUDIO_AACERNone) + +#define GST_TYPE_OMX_AAC_TOOLS (gst_omx_aac_tools_get_type ()) +static GType +gst_omx_aac_tools_get_type (void) +{ + static gsize id = 0; + static const GFlagsValue values[] = { + {OMX_AUDIO_AACToolMS, "Mid/side joint coding", "ms"}, + {OMX_AUDIO_AACToolIS, "Intensity stereo", "is"}, + {OMX_AUDIO_AACToolTNS, "Temporal noise shaping", "tns"}, + {OMX_AUDIO_AACToolPNS, "Perceptual noise substitution", "pns"}, + {OMX_AUDIO_AACToolLTP, "Long term prediction", "ltp"}, + {0, NULL, NULL} + }; + + if (g_once_init_enter (&id)) { + GType tmp = g_flags_register_static ("GstOMXAACTools", values); + g_once_init_leave (&id, tmp); + } + + return (GType) id; +} + +#define GST_TYPE_OMX_AAC_ER_TOOLS (gst_omx_aac_er_tools_get_type ()) +static GType +gst_omx_aac_er_tools_get_type (void) +{ + static gsize id = 0; + static const GFlagsValue values[] = { + {OMX_AUDIO_AACERVCB11, "Virtual code books", "vcb11"}, + {OMX_AUDIO_AACERRVLC, "Reversible variable length coding", "rvlc"}, + {OMX_AUDIO_AACERHCR, "Huffman codeword reordering", "hcr"}, + {0, NULL, NULL} + }; + + if (g_once_init_enter (&id)) { + GType tmp = g_flags_register_static ("GstOMXAACERTools", values); + g_once_init_leave (&id, tmp); + } + + return (GType) id; +} + +/* class initialization */ + +#define DEBUG_INIT(bla) \ + GST_DEBUG_CATEGORY_INIT (gst_omx_aac_enc_debug_category, "omxaacenc", 0, \ + "debug category for gst-omx audio encoder base class"); + +GST_BOILERPLATE_FULL (GstOMXAACEnc, gst_omx_aac_enc, + GstOMXAudioEnc, GST_TYPE_OMX_AUDIO_ENC, DEBUG_INIT); + +static void +gst_omx_aac_enc_base_init (gpointer g_class) +{ + GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); + GstOMXAudioEncClass *audioenc_class = GST_OMX_AUDIO_ENC_CLASS (g_class); + + gst_element_class_set_details_simple (element_class, + "OpenMAX AAC Audio Encoder", + "Codec/Encoder/Audio", + "Encode AAC audio streams", + "Sebastian Dröge "); + + /* If no role was set from the config file we set the + * default AAC audio encoder role */ + if (!audioenc_class->component_role) + audioenc_class->component_role = "audio_encoder.aac"; +} + +static void +gst_omx_aac_enc_class_init (GstOMXAACEncClass * klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GstOMXAudioEncClass *audioenc_class = GST_OMX_AUDIO_ENC_CLASS (klass); + + gobject_class->finalize = gst_omx_aac_enc_finalize; + gobject_class->set_property = gst_omx_aac_enc_set_property; + gobject_class->get_property = gst_omx_aac_enc_get_property; + + g_object_class_install_property (gobject_class, PROP_BITRATE, + g_param_spec_uint ("bitrate", "Bitrate", + "Bitrate", + 0, G_MAXUINT, DEFAULT_BITRATE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | + GST_PARAM_MUTABLE_READY)); + + g_object_class_install_property (gobject_class, PROP_AAC_TOOLS, + g_param_spec_flags ("aac-tools", "AAC Tools", + "Allowed AAC tools", + GST_TYPE_OMX_AAC_TOOLS, + DEFAULT_AAC_TOOLS, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | + GST_PARAM_MUTABLE_READY)); + + g_object_class_install_property (gobject_class, + PROP_AAC_ERROR_RESILIENCE_TOOLS, + g_param_spec_flags ("aac-error-resilience-tools", + "AAC Error Resilience Tools", "Allowed AAC error resilience tools", + GST_TYPE_OMX_AAC_ER_TOOLS, DEFAULT_AAC_ER_TOOLS, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | + GST_PARAM_MUTABLE_READY)); + + audioenc_class->set_format = GST_DEBUG_FUNCPTR (gst_omx_aac_enc_set_format); + audioenc_class->get_caps = GST_DEBUG_FUNCPTR (gst_omx_aac_enc_get_caps); + + audioenc_class->default_src_template_caps = "audio/mpeg, " + "mpegversion=(int){2, 4}, " + "stream-format=(string){raw, adts, adif, loas, latm}"; +} + +static void +gst_omx_aac_enc_init (GstOMXAACEnc * self, GstOMXAACEncClass * klass) +{ + self->bitrate = DEFAULT_BITRATE; + self->aac_tools = DEFAULT_AAC_TOOLS; + self->aac_er_tools = DEFAULT_AAC_ER_TOOLS; +} + +static void +gst_omx_aac_enc_finalize (GObject * object) +{ + /* GstOMXAACEnc *self = GST_OMX_AAC_ENC (object); */ + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +gst_omx_aac_enc_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstOMXAACEnc *self = GST_OMX_AAC_ENC (object); + + switch (prop_id) { + case PROP_BITRATE: + self->bitrate = g_value_get_uint (value); + break; + case PROP_AAC_TOOLS: + self->aac_tools = g_value_get_flags (value); + break; + case PROP_AAC_ERROR_RESILIENCE_TOOLS: + self->aac_er_tools = g_value_get_flags (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_omx_aac_enc_get_property (GObject * object, guint prop_id, GValue * value, + GParamSpec * pspec) +{ + GstOMXAACEnc *self = GST_OMX_AAC_ENC (object); + + switch (prop_id) { + case PROP_BITRATE: + g_value_set_uint (value, self->bitrate); + break; + case PROP_AAC_TOOLS: + g_value_set_flags (value, self->aac_tools); + break; + case PROP_AAC_ERROR_RESILIENCE_TOOLS: + g_value_set_flags (value, self->aac_er_tools); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static gboolean +gst_omx_aac_enc_set_format (GstOMXAudioEnc * enc, GstOMXPort * port, + GstAudioState * state) +{ + GstOMXAACEnc *self = GST_OMX_AAC_ENC (enc); + OMX_AUDIO_PARAM_AACPROFILETYPE aac_profile; + GstCaps *peercaps; + OMX_AUDIO_AACSTREAMFORMATTYPE stream_format = OMX_AUDIO_AACStreamFormatRAW; + OMX_AUDIO_AACPROFILETYPE profile = OMX_AUDIO_AACObjectLC; + OMX_ERRORTYPE err; + + GST_OMX_INIT_STRUCT (&aac_profile); + aac_profile.nPortIndex = enc->out_port->index; + + err = + gst_omx_component_get_parameter (enc->component, OMX_IndexParamAudioAac, + &aac_profile); + if (err != OMX_ErrorNone) { + GST_ERROR_OBJECT (self, + "Failed to get AAC parameters from component: %s (0x%08x)", + gst_omx_error_to_string (err), err); + return FALSE; + } + + peercaps = gst_pad_peer_get_caps (GST_BASE_AUDIO_ENCODER_SRC_PAD (self)); + if (peercaps) { + GstCaps *intersection; + GstStructure *s; + gint mpegversion = 0; + const gchar *profile_string, *stream_format_string; + + intersection = + gst_caps_intersect (peercaps, + gst_pad_get_pad_template_caps (GST_BASE_AUDIO_ENCODER_SRC_PAD (self))); + gst_caps_unref (peercaps); + if (gst_caps_is_empty (intersection)) { + gst_caps_unref (intersection); + GST_ERROR_OBJECT (self, "Empty caps"); + return FALSE; + } + + s = gst_caps_get_structure (intersection, 0); + + if (gst_structure_get_int (s, "mpegversion", &mpegversion)) { + profile_string = + gst_structure_get_string (s, + ((mpegversion == 2) ? "profile" : "base-profile")); + + if (profile_string) { + if (g_str_equal (profile_string, "main")) { + profile = OMX_AUDIO_AACObjectMain; + } else if (g_str_equal (profile_string, "lc")) { + profile = OMX_AUDIO_AACObjectLC; + } else if (g_str_equal (profile_string, "ssr")) { + profile = OMX_AUDIO_AACObjectSSR; + } else if (g_str_equal (profile_string, "ltp")) { + profile = OMX_AUDIO_AACObjectLTP; + } else { + GST_ERROR_OBJECT (self, "Unsupported profile '%s'", profile_string); + gst_caps_unref (intersection); + return FALSE; + } + } + } + + stream_format_string = gst_structure_get_string (s, "stream-format"); + if (stream_format_string) { + if (g_str_equal (stream_format_string, "raw")) { + stream_format = OMX_AUDIO_AACStreamFormatRAW; + } else if (g_str_equal (stream_format_string, "adts")) { + if (mpegversion == 2) { + stream_format = OMX_AUDIO_AACStreamFormatMP2ADTS; + } else { + stream_format = OMX_AUDIO_AACStreamFormatMP4ADTS; + } + } else if (g_str_equal (stream_format_string, "loas")) { + stream_format = OMX_AUDIO_AACStreamFormatMP4LOAS; + } else if (g_str_equal (stream_format_string, "latm")) { + stream_format = OMX_AUDIO_AACStreamFormatMP4LATM; + } else if (g_str_equal (stream_format_string, "adif")) { + stream_format = OMX_AUDIO_AACStreamFormatADIF; + } else { + GST_ERROR_OBJECT (self, "Unsupported stream-format '%s'", + stream_format_string); + gst_caps_unref (intersection); + return FALSE; + } + } + + gst_caps_unref (intersection); + } + + aac_profile.eAACProfile = profile; + aac_profile.eAACStreamFormat = stream_format; + + aac_profile.nAACtools = self->aac_tools; + aac_profile.nAACERtools = self->aac_er_tools; + + aac_profile.nBitRate = self->bitrate; + + err = + gst_omx_component_set_parameter (enc->component, OMX_IndexParamAudioAac, + &aac_profile); + if (err != OMX_ErrorNone) { + GST_ERROR_OBJECT (self, "Error setting AAC parameters: %s (0x%08x)", + gst_omx_error_to_string (err), err); + return FALSE; + } + + return TRUE; +} + +static GstCaps * +gst_omx_aac_enc_get_caps (GstOMXAudioEnc * enc, GstOMXPort * port, + GstAudioState * state) +{ + GstCaps *caps; + OMX_ERRORTYPE err; + OMX_AUDIO_PARAM_AACPROFILETYPE aac_profile; + gint mpegversion = 4; + const gchar *stream_format = NULL, *profile = NULL; + + GST_OMX_INIT_STRUCT (&aac_profile); + aac_profile.nPortIndex = enc->out_port->index; + + err = + gst_omx_component_get_parameter (enc->component, OMX_IndexParamAudioAac, + &aac_profile); + if (err != OMX_ErrorNone) { + GST_ERROR_OBJECT (enc, + "Failed to get AAC parameters from component: %s (0x%08x)", + gst_omx_error_to_string (err), err); + return NULL; + } + + switch (aac_profile.eAACProfile) { + case OMX_AUDIO_AACObjectMain: + profile = "main"; + break; + case OMX_AUDIO_AACObjectLC: + profile = "lc"; + break; + case OMX_AUDIO_AACObjectSSR: + profile = "ssr"; + break; + case OMX_AUDIO_AACObjectLTP: + profile = "ltp"; + break; + case OMX_AUDIO_AACObjectHE: + case OMX_AUDIO_AACObjectScalable: + case OMX_AUDIO_AACObjectERLC: + case OMX_AUDIO_AACObjectLD: + case OMX_AUDIO_AACObjectHE_PS: + default: + GST_ERROR_OBJECT (enc, "Unsupported profile %d", aac_profile.eAACProfile); + break; + } + + switch (aac_profile.eAACStreamFormat) { + case OMX_AUDIO_AACStreamFormatMP2ADTS: + mpegversion = 2; + stream_format = "adts"; + break; + case OMX_AUDIO_AACStreamFormatMP4ADTS: + mpegversion = 4; + stream_format = "adts"; + break; + case OMX_AUDIO_AACStreamFormatMP4LOAS: + mpegversion = 4; + stream_format = "loas"; + break; + case OMX_AUDIO_AACStreamFormatMP4LATM: + mpegversion = 4; + stream_format = "latm"; + break; + case OMX_AUDIO_AACStreamFormatADIF: + mpegversion = 4; + stream_format = "adif"; + break; + case OMX_AUDIO_AACStreamFormatRAW: + mpegversion = 4; + stream_format = "raw"; + break; + case OMX_AUDIO_AACStreamFormatMP4FF: + default: + GST_ERROR_OBJECT (enc, "Unsupported stream-format %u", + aac_profile.eAACStreamFormat); + break; + } + + caps = gst_caps_new_simple ("audio/mpeg", NULL); + + if (mpegversion != 0) + gst_caps_set_simple (caps, "mpegversion", G_TYPE_INT, mpegversion, + "stream-format", G_TYPE_STRING, stream_format, NULL); + if (profile != NULL && mpegversion == 2) + gst_caps_set_simple (caps, "profile", G_TYPE_STRING, profile, NULL); + if (profile != NULL && mpegversion == 4) + gst_caps_set_simple (caps, "base-profile", G_TYPE_STRING, profile, NULL); + if (aac_profile.nChannels != 0) + gst_caps_set_simple (caps, "channels", G_TYPE_INT, aac_profile.nChannels, + NULL); + if (aac_profile.nSampleRate != 0) + gst_caps_set_simple (caps, "rate", G_TYPE_INT, aac_profile.nSampleRate, + NULL); + + return caps; +} diff --git a/omx/gstomxaacenc.h b/omx/gstomxaacenc.h new file mode 100644 index 0000000000..b6c3daa9b7 --- /dev/null +++ b/omx/gstomxaacenc.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2011, Hewlett-Packard Development Company, L.P. + * Author: Sebastian Dröge , Collabora Ltd. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation + * version 2.1 of the License. + * + * 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef __GST_OMX_AAC_ENC_H__ +#define __GST_OMX_AAC_ENC_H__ + +#include +#include "gstomxaudioenc.h" + +G_BEGIN_DECLS + +#define GST_TYPE_OMX_AAC_ENC \ + (gst_omx_aac_enc_get_type()) +#define GST_OMX_AAC_ENC(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_OMX_AAC_ENC,GstOMXAACEnc)) +#define GST_OMX_AAC_ENC_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_OMX_AAC_ENC,GstOMXAACEncClass)) +#define GST_OMX_AAC_ENC_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj),GST_TYPE_OMX_AAC_ENC,GstOMXAACEncClass)) +#define GST_IS_OMX_AAC_ENC(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_OMX_AAC_ENC)) +#define GST_IS_OMX_AAC_ENC_CLASS(obj) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_OMX_AAC_ENC)) + +typedef struct _GstOMXAACEnc GstOMXAACEnc; +typedef struct _GstOMXAACEncClass GstOMXAACEncClass; + +struct _GstOMXAACEnc +{ + GstOMXAudioEnc parent; + + /* properties */ + guint bitrate; + guint aac_tools; + guint aac_er_tools; +}; + +struct _GstOMXAACEncClass +{ + GstOMXAudioEncClass parent_class; +}; + +GType gst_omx_aac_enc_get_type (void); + +G_END_DECLS + +#endif /* __GST_OMX_AAC_ENC_H__ */ +