diff --git a/omx/Makefile.am b/omx/Makefile.am index da567f9a05..73c450ef36 100644 --- a/omx/Makefile.am +++ b/omx/Makefile.am @@ -32,6 +32,7 @@ libgstomx_la_SOURCES = \ gstomxh263enc.c \ gstomxaacdec.c \ gstomxmp3dec.c \ + gstomxmp3enc.c \ gstomxaacenc.c \ gstomxamrdec.c \ gstomxaudiosink.c \ @@ -60,6 +61,7 @@ noinst_HEADERS = \ gstomxh263enc.h \ gstomxaacdec.h \ gstomxmp3dec.h \ + gstomxmp3enc.h \ gstomxaacenc.h \ gstomxamrdec.h \ gstomxaudiosink.h \ diff --git a/omx/gstomx.c b/omx/gstomx.c index 507aa9b436..04c49c01f6 100644 --- a/omx/gstomx.c +++ b/omx/gstomx.c @@ -41,6 +41,7 @@ #include "gstomxh263enc.h" #include "gstomxaacdec.h" #include "gstomxmp3dec.h" +#include "gstomxmp3enc.h" #include "gstomxaacenc.h" #include "gstomxamrdec.h" #include "gstomxanalogaudiosink.h" @@ -2290,6 +2291,7 @@ static const GGetTypeFunction types[] = { gst_omx_h264_enc_get_type, gst_omx_h263_enc_get_type, gst_omx_aac_enc_get_type, gst_omx_mjpeg_dec_get_type, gst_omx_aac_dec_get_type, gst_omx_mp3_dec_get_type, + gst_omx_aac_dec_get_type, gst_omx_mp3_enc_get_type, gst_omx_amr_dec_get_type #ifdef HAVE_VP8 , gst_omx_vp8_dec_get_type diff --git a/omx/gstomxmp3enc.c b/omx/gstomxmp3enc.c new file mode 100644 index 0000000000..20a137ba33 --- /dev/null +++ b/omx/gstomxmp3enc.c @@ -0,0 +1,278 @@ +/* + * Copyright (C) 2017 + * Author: Julien Isorce + * + * 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 "gstomxmp3enc.h" + +GST_DEBUG_CATEGORY_STATIC (gst_omx_mp3_enc_debug_category); +#define GST_CAT_DEFAULT gst_omx_mp3_enc_debug_category + +/* prototypes */ +static void gst_omx_mp3_enc_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); +static void gst_omx_mp3_enc_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); +static gboolean gst_omx_mp3_enc_set_format (GstOMXAudioEnc * enc, + GstOMXPort * port, GstAudioInfo * info); +static GstCaps *gst_omx_mp3_enc_get_caps (GstOMXAudioEnc * enc, + GstOMXPort * port, GstAudioInfo * info); +static guint gst_omx_mp3_enc_get_num_samples (GstOMXAudioEnc * enc, + GstOMXPort * port, GstAudioInfo * info, GstOMXBuffer * buf); + +enum +{ + PROP_0, + PROP_BITRATE +}; + +#define DEFAULT_BITRATE (128) + +/* class initialization */ + +#define DEBUG_INIT \ + GST_DEBUG_CATEGORY_INIT (gst_omx_mp3_enc_debug_category, "omxmp3enc", 0, \ + "debug category for gst-omx audio encoder base class"); + +G_DEFINE_TYPE_WITH_CODE (GstOMXMP3Enc, gst_omx_mp3_enc, + GST_TYPE_OMX_AUDIO_ENC, DEBUG_INIT); + + +static void +gst_omx_mp3_enc_class_init (GstOMXMP3EncClass * klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GstElementClass *element_class = GST_ELEMENT_CLASS (klass); + GstOMXAudioEncClass *audioenc_class = GST_OMX_AUDIO_ENC_CLASS (klass); + + gobject_class->set_property = gst_omx_mp3_enc_set_property; + gobject_class->get_property = gst_omx_mp3_enc_get_property; + + g_object_class_install_property (gobject_class, PROP_BITRATE, + g_param_spec_uint ("bitrate", "Bitrate (kb/s)", + "Bitrate in kbit/sec", + 0, G_MAXUINT, DEFAULT_BITRATE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | + GST_PARAM_MUTABLE_READY)); + + audioenc_class->set_format = GST_DEBUG_FUNCPTR (gst_omx_mp3_enc_set_format); + audioenc_class->get_caps = GST_DEBUG_FUNCPTR (gst_omx_mp3_enc_get_caps); + audioenc_class->get_num_samples = + GST_DEBUG_FUNCPTR (gst_omx_mp3_enc_get_num_samples); + + audioenc_class->cdata.default_src_template_caps = "audio/mpeg, " + "mpegversion=(int)1, " + "layer=(int)3, " + "mpegaudioversion=(int)[1,3], " + "rate=(int)[8000,48000], " "channels=(int)[1,2]"; + + gst_element_class_set_static_metadata (element_class, + "OpenMAX MP3 Audio Encoder", + "Codec/Encoder/Audio", + "Encode AAC audio streams", "Julien Isorce "); + + gst_omx_set_default_role (&audioenc_class->cdata, "audio_encoder.mp3"); +} + +static void +gst_omx_mp3_enc_init (GstOMXMP3Enc * self) +{ + self->mpegaudioversion = 1; + self->bitrate = DEFAULT_BITRATE; +} + +static void +gst_omx_mp3_enc_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstOMXMP3Enc *self = GST_OMX_MP3_ENC (object); + + switch (prop_id) { + case PROP_BITRATE: + self->bitrate = g_value_get_uint (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_omx_mp3_enc_get_property (GObject * object, guint prop_id, GValue * value, + GParamSpec * pspec) +{ + GstOMXMP3Enc *self = GST_OMX_MP3_ENC (object); + + switch (prop_id) { + case PROP_BITRATE: + g_value_set_uint (value, self->bitrate); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static gboolean +gst_omx_mp3_enc_set_format (GstOMXAudioEnc * enc, GstOMXPort * port, + GstAudioInfo * info) +{ + GstOMXMP3Enc *self = GST_OMX_MP3_ENC (enc); + OMX_AUDIO_PARAM_MP3TYPE mp3_param; + GstCaps *peercaps; + OMX_ERRORTYPE err; + + GST_OMX_INIT_STRUCT (&mp3_param); + mp3_param.nPortIndex = enc->enc_out_port->index; + + err = + gst_omx_component_get_parameter (enc->enc, OMX_IndexParamAudioMp3, + &mp3_param); + if (err != OMX_ErrorNone) { + GST_ERROR_OBJECT (self, + "Failed to get MP# parameters from component: %s (0x%08x)", + gst_omx_error_to_string (err), err); + return FALSE; + } + + peercaps = gst_pad_peer_query_caps (GST_AUDIO_ENCODER_SRC_PAD (self), + gst_pad_get_pad_template_caps (GST_AUDIO_ENCODER_SRC_PAD (self))); + if (peercaps) { + GstStructure *s; + gint mpegaudioversion = 0; + + if (gst_caps_is_empty (peercaps)) { + gst_caps_unref (peercaps); + GST_ERROR_OBJECT (self, "Empty caps"); + return FALSE; + } + + s = gst_caps_get_structure (peercaps, 0); + + if (gst_structure_get_int (s, "mpegaudioversion", &mpegaudioversion)) { + switch (mpegaudioversion) { + case 1: + mp3_param.eFormat = OMX_AUDIO_MP3StreamFormatMP1Layer3; + break; + case 2: + mp3_param.eFormat = OMX_AUDIO_MP3StreamFormatMP2Layer3; + break; + case 3: + mp3_param.eFormat = OMX_AUDIO_MP3StreamFormatMP2_5Layer3; + break; + default: + GST_ERROR_OBJECT (self, "Unsupported mpegaudioversion '%d'", + mpegaudioversion); + gst_caps_unref (peercaps); + return FALSE; + } + self->mpegaudioversion = mpegaudioversion; + } + + gst_caps_unref (peercaps); + + mp3_param.nSampleRate = info->rate; + mp3_param.nChannels = info->channels; + + mp3_param.eChannelMode = + info->channels == + 1 ? OMX_AUDIO_ChannelModeMono : OMX_AUDIO_ChannelModeStereo; + } + + mp3_param.nBitRate = self->bitrate; + + err = + gst_omx_component_set_parameter (enc->enc, OMX_IndexParamAudioMp3, + &mp3_param); + if (err != OMX_ErrorNone) { + GST_ERROR_OBJECT (self, "Error setting MP3 parameters: %s (0x%08x)", + gst_omx_error_to_string (err), err); + return FALSE; + } + + return TRUE; +} + +static GstCaps * +gst_omx_mp3_enc_get_caps (GstOMXAudioEnc * enc, GstOMXPort * port, + GstAudioInfo * info) +{ + GstCaps *caps; + OMX_ERRORTYPE err; + OMX_AUDIO_PARAM_MP3TYPE mp3_param; + gint mpegaudioversion = 0; + + GST_OMX_INIT_STRUCT (&mp3_param); + mp3_param.nPortIndex = enc->enc_out_port->index; + + err = + gst_omx_component_get_parameter (enc->enc, OMX_IndexParamAudioMp3, + &mp3_param); + if (err != OMX_ErrorNone) { + GST_ERROR_OBJECT (enc, + "Failed to get MP3 parameters from component: %s (0x%08x)", + gst_omx_error_to_string (err), err); + return NULL; + } + + switch (mp3_param.eFormat) { + case OMX_AUDIO_MP3StreamFormatMP1Layer3: + mpegaudioversion = 1; + break; + case OMX_AUDIO_MP3StreamFormatMP2Layer3: + mpegaudioversion = 2; + break; + case OMX_AUDIO_MP3StreamFormatMP2_5Layer3: + mpegaudioversion = 3; + break; + default: + GST_ERROR_OBJECT (enc, "Unsupported mpegaudioversion %d", + mp3_param.eFormat); + break; + } + + caps = + gst_caps_new_simple ("audio/mpeg", "mpegversion", G_TYPE_INT, 1, "layer", + G_TYPE_INT, 3, NULL); + + if (mpegaudioversion != 0) + gst_caps_set_simple (caps, "mpegaudioversion", G_TYPE_INT, mpegaudioversion, + NULL); + if (mp3_param.nChannels != 0) + gst_caps_set_simple (caps, "channels", G_TYPE_INT, mp3_param.nChannels, + NULL); + if (mp3_param.nSampleRate != 0) + gst_caps_set_simple (caps, "rate", G_TYPE_INT, mp3_param.nSampleRate, NULL); + + return caps; + +} + +static guint +gst_omx_mp3_enc_get_num_samples (GstOMXAudioEnc * enc, GstOMXPort * port, + GstAudioInfo * info, GstOMXBuffer * buf) +{ + GstOMXMP3Enc *self = GST_OMX_MP3_ENC (enc); + return (self->mpegaudioversion == 1) ? 1152 : 576; +} diff --git a/omx/gstomxmp3enc.h b/omx/gstomxmp3enc.h new file mode 100644 index 0000000000..74e115e6c6 --- /dev/null +++ b/omx/gstomxmp3enc.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2017 + * Author: Julien Isorce + * + * 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_MP3_ENC_H__ +#define __GST_OMX_MP3_ENC_H__ + +#include +#include "gstomxaudioenc.h" + +G_BEGIN_DECLS + +#define GST_TYPE_OMX_MP3_ENC \ + (gst_omx_mp3_enc_get_type()) +#define GST_OMX_MP3_ENC(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_OMX_MP3_ENC,GstOMXMP3Enc)) +#define GST_OMX_MP3_ENC_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_OMX_MP3_ENC,GstOMXMP3EncClass)) +#define GST_OMX_MP3_ENC_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj),GST_TYPE_OMX_MP3_ENC,GstOMXMP3EncClass)) +#define GST_IS_OMX_MP3_ENC(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_OMX_MP3_ENC)) +#define GST_IS_OMX_MP3_ENC_CLASS(obj) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_OMX_MP3_ENC)) + +typedef struct _GstOMXMP3Enc GstOMXMP3Enc; +typedef struct _GstOMXMP3EncClass GstOMXMP3EncClass; + +struct _GstOMXMP3Enc +{ + GstOMXAudioEnc parent; + + guint mpegaudioversion; + + /* properties */ + guint bitrate; +}; + +struct _GstOMXMP3EncClass +{ + GstOMXAudioEncClass parent_class; +}; + +GType gst_omx_mp3_enc_get_type (void); + +G_END_DECLS + +#endif /* __GST_OMX_MP3_ENC_H__ */ +