omxvideodec: support interlace-mode=interleaved input
[platform/upstream/gstreamer.git] / omx / gstomxaacdec.c
1 /*
2  * Copyright (C) 2014, Sebastian Dröge <sebastian@centricular.com>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation
7  * version 2.1 of the License.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
17  *
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include <gst/gst.h>
25
26 #include "gstomxaacdec.h"
27
28 GST_DEBUG_CATEGORY_STATIC (gst_omx_aac_dec_debug_category);
29 #define GST_CAT_DEFAULT gst_omx_aac_dec_debug_category
30
31 /* prototypes */
32 static gboolean gst_omx_aac_dec_set_format (GstOMXAudioDec * dec,
33     GstOMXPort * port, GstCaps * caps);
34 static gboolean gst_omx_aac_dec_is_format_change (GstOMXAudioDec * dec,
35     GstOMXPort * port, GstCaps * caps);
36 static gint gst_omx_aac_dec_get_samples_per_frame (GstOMXAudioDec * dec,
37     GstOMXPort * port);
38 static gboolean gst_omx_aac_dec_get_channel_positions (GstOMXAudioDec * dec,
39     GstOMXPort * port, GstAudioChannelPosition position[OMX_AUDIO_MAXCHANNELS]);
40
41 /* class initialization */
42
43 #define DEBUG_INIT \
44   GST_DEBUG_CATEGORY_INIT (gst_omx_aac_dec_debug_category, "omxaacdec", 0, \
45       "debug category for gst-omx aac audio decoder");
46
47 G_DEFINE_TYPE_WITH_CODE (GstOMXAACDec, gst_omx_aac_dec,
48     GST_TYPE_OMX_AUDIO_DEC, DEBUG_INIT);
49
50 static void
51 gst_omx_aac_dec_class_init (GstOMXAACDecClass * klass)
52 {
53   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
54   GstOMXAudioDecClass *audiodec_class = GST_OMX_AUDIO_DEC_CLASS (klass);
55
56   audiodec_class->set_format = GST_DEBUG_FUNCPTR (gst_omx_aac_dec_set_format);
57   audiodec_class->is_format_change =
58       GST_DEBUG_FUNCPTR (gst_omx_aac_dec_is_format_change);
59   audiodec_class->get_samples_per_frame =
60       GST_DEBUG_FUNCPTR (gst_omx_aac_dec_get_samples_per_frame);
61   audiodec_class->get_channel_positions =
62       GST_DEBUG_FUNCPTR (gst_omx_aac_dec_get_channel_positions);
63
64   audiodec_class->cdata.default_sink_template_caps = "audio/mpeg, "
65       "mpegversion=(int){2, 4}, "
66       "stream-format=(string) { raw, adts, adif, loas }, "
67       "rate=(int)[8000,48000], "
68       "channels=(int)[1,9], " "framed=(boolean) true";
69
70   gst_element_class_set_static_metadata (element_class,
71       "OpenMAX AAC Audio Decoder",
72       "Codec/Decoder/Audio/Hardware",
73       "Decode AAC audio streams",
74       "Sebastian Dröge <sebastian@centricular.com>");
75
76   gst_omx_set_default_role (&audiodec_class->cdata, "audio_decoder.aac");
77 }
78
79 static void
80 gst_omx_aac_dec_init (GstOMXAACDec * self)
81 {
82   /* FIXME: Other values exist too! */
83   self->spf = 1024;
84 }
85
86 static gboolean
87 gst_omx_aac_dec_set_format (GstOMXAudioDec * dec, GstOMXPort * port,
88     GstCaps * caps)
89 {
90   GstOMXAACDec *self = GST_OMX_AAC_DEC (dec);
91   OMX_PARAM_PORTDEFINITIONTYPE port_def;
92   OMX_AUDIO_PARAM_AACPROFILETYPE aac_param;
93   OMX_ERRORTYPE err;
94   GstStructure *s;
95   gint rate, channels, mpegversion;
96   const gchar *stream_format;
97
98   gst_omx_port_get_port_definition (port, &port_def);
99   port_def.format.audio.eEncoding = OMX_AUDIO_CodingAAC;
100   err = gst_omx_port_update_port_definition (port, &port_def);
101   if (err != OMX_ErrorNone) {
102     GST_ERROR_OBJECT (self,
103         "Failed to set AAC format on component: %s (0x%08x)",
104         gst_omx_error_to_string (err), err);
105     return FALSE;
106   }
107
108   GST_OMX_INIT_STRUCT (&aac_param);
109   aac_param.nPortIndex = port->index;
110
111   err =
112       gst_omx_component_get_parameter (dec->dec, OMX_IndexParamAudioAac,
113       &aac_param);
114   if (err != OMX_ErrorNone) {
115     GST_ERROR_OBJECT (self,
116         "Failed to get AAC parameters from component: %s (0x%08x)",
117         gst_omx_error_to_string (err), err);
118     return FALSE;
119   }
120
121   s = gst_caps_get_structure (caps, 0);
122
123   if (!gst_structure_get_int (s, "mpegversion", &mpegversion) ||
124       !gst_structure_get_int (s, "rate", &rate) ||
125       !gst_structure_get_int (s, "channels", &channels)) {
126     GST_ERROR_OBJECT (self, "Incomplete caps");
127     return FALSE;
128   }
129
130   stream_format = gst_structure_get_string (s, "stream-format");
131   if (!stream_format) {
132     GST_ERROR_OBJECT (self, "Incomplete caps");
133     return FALSE;
134   }
135
136   aac_param.nChannels = channels;
137   aac_param.nSampleRate = rate;
138   aac_param.nBitRate = 0;       /* unknown */
139   aac_param.nAudioBandWidth = 0;        /* decoder decision */
140   aac_param.eChannelMode = 0;   /* FIXME */
141   if (mpegversion == 2)
142     aac_param.eAACStreamFormat = OMX_AUDIO_AACStreamFormatMP2ADTS;
143   else if (strcmp (stream_format, "adts") == 0)
144     aac_param.eAACStreamFormat = OMX_AUDIO_AACStreamFormatMP4ADTS;
145   else if (strcmp (stream_format, "loas") == 0)
146     aac_param.eAACStreamFormat = OMX_AUDIO_AACStreamFormatMP4LOAS;
147   else if (strcmp (stream_format, "adif") == 0)
148     aac_param.eAACStreamFormat = OMX_AUDIO_AACStreamFormatADIF;
149   else if (strcmp (stream_format, "raw") == 0)
150     aac_param.eAACStreamFormat = OMX_AUDIO_AACStreamFormatRAW;
151   else {
152     GST_ERROR_OBJECT (self, "Unexpected format: %s", stream_format);
153     return FALSE;
154   }
155
156   err =
157       gst_omx_component_set_parameter (dec->dec, OMX_IndexParamAudioAac,
158       &aac_param);
159   if (err != OMX_ErrorNone) {
160     GST_ERROR_OBJECT (self, "Error setting AAC parameters: %s (0x%08x)",
161         gst_omx_error_to_string (err), err);
162     return FALSE;
163   }
164
165   return TRUE;
166 }
167
168 static gboolean
169 gst_omx_aac_dec_is_format_change (GstOMXAudioDec * dec, GstOMXPort * port,
170     GstCaps * caps)
171 {
172   GstOMXAACDec *self = GST_OMX_AAC_DEC (dec);
173   OMX_AUDIO_PARAM_AACPROFILETYPE aac_param;
174   OMX_ERRORTYPE err;
175   GstStructure *s;
176   gint rate, channels, mpegversion;
177   const gchar *stream_format;
178
179   GST_OMX_INIT_STRUCT (&aac_param);
180   aac_param.nPortIndex = port->index;
181
182   err =
183       gst_omx_component_get_parameter (dec->dec, OMX_IndexParamAudioAac,
184       &aac_param);
185   if (err != OMX_ErrorNone) {
186     GST_ERROR_OBJECT (self,
187         "Failed to get AAC parameters from component: %s (0x%08x)",
188         gst_omx_error_to_string (err), err);
189     return FALSE;
190   }
191
192   s = gst_caps_get_structure (caps, 0);
193
194   if (!gst_structure_get_int (s, "mpegversion", &mpegversion) ||
195       !gst_structure_get_int (s, "rate", &rate) ||
196       !gst_structure_get_int (s, "channels", &channels)) {
197     GST_ERROR_OBJECT (self, "Incomplete caps");
198     return FALSE;
199   }
200
201   stream_format = gst_structure_get_string (s, "stream-format");
202   if (!stream_format) {
203     GST_ERROR_OBJECT (self, "Incomplete caps");
204     return FALSE;
205   }
206
207   if (aac_param.nChannels != channels)
208     return TRUE;
209
210   if (aac_param.nSampleRate != rate)
211     return TRUE;
212
213   if (mpegversion == 2
214       && aac_param.eAACStreamFormat != OMX_AUDIO_AACStreamFormatMP2ADTS)
215     return TRUE;
216   if (aac_param.eAACStreamFormat == OMX_AUDIO_AACStreamFormatMP4ADTS &&
217       strcmp (stream_format, "adts") != 0)
218     return TRUE;
219   if (aac_param.eAACStreamFormat == OMX_AUDIO_AACStreamFormatMP4LOAS &&
220       strcmp (stream_format, "loas") != 0)
221     return TRUE;
222   if (aac_param.eAACStreamFormat == OMX_AUDIO_AACStreamFormatADIF &&
223       strcmp (stream_format, "adif") != 0)
224     return TRUE;
225   if (aac_param.eAACStreamFormat == OMX_AUDIO_AACStreamFormatRAW &&
226       strcmp (stream_format, "raw") != 0)
227     return TRUE;
228
229   return FALSE;
230 }
231
232 static gint
233 gst_omx_aac_dec_get_samples_per_frame (GstOMXAudioDec * dec, GstOMXPort * port)
234 {
235   return GST_OMX_AAC_DEC (dec)->spf;
236 }
237
238 static gboolean
239 gst_omx_aac_dec_get_channel_positions (GstOMXAudioDec * dec,
240     GstOMXPort * port, GstAudioChannelPosition position[OMX_AUDIO_MAXCHANNELS])
241 {
242   OMX_AUDIO_PARAM_PCMMODETYPE pcm_param;
243   OMX_ERRORTYPE err;
244
245   GST_OMX_INIT_STRUCT (&pcm_param);
246   pcm_param.nPortIndex = port->index;
247   err =
248       gst_omx_component_get_parameter (dec->dec, OMX_IndexParamAudioPcm,
249       &pcm_param);
250   if (err != OMX_ErrorNone) {
251     GST_ERROR_OBJECT (dec, "Failed to get PCM parameters: %s (0x%08x)",
252         gst_omx_error_to_string (err), err);
253     return FALSE;
254   }
255
256   /* FIXME: Rather arbitrary values here, based on what we do in gstfaac.c */
257   switch (pcm_param.nChannels) {
258     case 1:
259       position[0] = GST_AUDIO_CHANNEL_POSITION_MONO;
260       break;
261     case 2:
262       position[0] = GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT;
263       position[1] = GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT;
264       break;
265     case 3:
266       position[0] = GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER;
267       position[1] = GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT;
268       position[2] = GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT;
269       break;
270     case 4:
271       position[0] = GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER;
272       position[1] = GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT;
273       position[2] = GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT;
274       position[3] = GST_AUDIO_CHANNEL_POSITION_REAR_CENTER;
275       break;
276     case 5:
277       position[0] = GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER;
278       position[1] = GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT;
279       position[2] = GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT;
280       position[3] = GST_AUDIO_CHANNEL_POSITION_REAR_LEFT;
281       position[4] = GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT;
282       break;
283     case 6:
284       position[0] = GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER;
285       position[1] = GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT;
286       position[2] = GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT;
287       position[3] = GST_AUDIO_CHANNEL_POSITION_REAR_LEFT;
288       position[4] = GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT;
289       position[5] = GST_AUDIO_CHANNEL_POSITION_LFE1;
290       break;
291     default:
292       return FALSE;
293   }
294
295   return TRUE;
296 }