omxvideoenc: drain encoder on ALLOCATION and DRAIN queries
[platform/upstream/gstreamer.git] / omx / gstomxmp3dec.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 "gstomxmp3dec.h"
27
28 GST_DEBUG_CATEGORY_STATIC (gst_omx_mp3_dec_debug_category);
29 #define GST_CAT_DEFAULT gst_omx_mp3_dec_debug_category
30
31 /* prototypes */
32 static gboolean gst_omx_mp3_dec_set_format (GstOMXAudioDec * dec,
33     GstOMXPort * port, GstCaps * caps);
34 static gboolean gst_omx_mp3_dec_is_format_change (GstOMXAudioDec * dec,
35     GstOMXPort * port, GstCaps * caps);
36 static gint gst_omx_mp3_dec_get_samples_per_frame (GstOMXAudioDec * dec,
37     GstOMXPort * port);
38 static gboolean gst_omx_mp3_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_mp3_dec_debug_category, "omxmp3dec", 0, \
45       "debug category for gst-omx mp3 audio decoder");
46
47 G_DEFINE_TYPE_WITH_CODE (GstOMXMP3Dec, gst_omx_mp3_dec,
48     GST_TYPE_OMX_AUDIO_DEC, DEBUG_INIT);
49
50
51 static void
52 gst_omx_mp3_dec_class_init (GstOMXMP3DecClass * klass)
53 {
54   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
55   GstOMXAudioDecClass *audiodec_class = GST_OMX_AUDIO_DEC_CLASS (klass);
56
57   audiodec_class->set_format = GST_DEBUG_FUNCPTR (gst_omx_mp3_dec_set_format);
58   audiodec_class->is_format_change =
59       GST_DEBUG_FUNCPTR (gst_omx_mp3_dec_is_format_change);
60   audiodec_class->get_samples_per_frame =
61       GST_DEBUG_FUNCPTR (gst_omx_mp3_dec_get_samples_per_frame);
62   audiodec_class->get_channel_positions =
63       GST_DEBUG_FUNCPTR (gst_omx_mp3_dec_get_channel_positions);
64
65   audiodec_class->cdata.default_sink_template_caps = "audio/mpeg, "
66       "mpegversion=(int)1, "
67       "layer=(int)3, "
68       "mpegaudioversion=(int)[1,3], "
69       "rate=(int)[8000,48000], "
70       "channels=(int)[1,2], " "parsed=(boolean) true";
71
72   gst_element_class_set_static_metadata (element_class,
73       "OpenMAX MP3 Audio Decoder",
74       "Codec/Decoder/Audio/Hardware",
75       "Decode MP3 audio streams",
76       "Sebastian Dröge <sebastian@centricular.com>");
77
78   gst_omx_set_default_role (&audiodec_class->cdata, "audio_decoder.mp3");
79 }
80
81 static void
82 gst_omx_mp3_dec_init (GstOMXMP3Dec * self)
83 {
84   self->spf = -1;
85 }
86
87 static gboolean
88 gst_omx_mp3_dec_set_format (GstOMXAudioDec * dec, GstOMXPort * port,
89     GstCaps * caps)
90 {
91   GstOMXMP3Dec *self = GST_OMX_MP3_DEC (dec);
92   OMX_PARAM_PORTDEFINITIONTYPE port_def;
93   OMX_AUDIO_PARAM_MP3TYPE mp3_param;
94   OMX_ERRORTYPE err;
95   GstStructure *s;
96   gint rate, channels, layer, mpegaudioversion;
97
98   gst_omx_port_get_port_definition (port, &port_def);
99   port_def.format.audio.eEncoding = OMX_AUDIO_CodingMP3;
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 MP3 format on component: %s (0x%08x)",
104         gst_omx_error_to_string (err), err);
105     return FALSE;
106   }
107
108   GST_OMX_INIT_STRUCT (&mp3_param);
109   mp3_param.nPortIndex = port->index;
110
111   err =
112       gst_omx_component_get_parameter (dec->dec, OMX_IndexParamAudioMp3,
113       &mp3_param);
114   if (err != OMX_ErrorNone) {
115     GST_ERROR_OBJECT (self,
116         "Failed to get MP3 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, "mpegaudioversion", &mpegaudioversion) ||
124       !gst_structure_get_int (s, "layer", &layer) ||
125       !gst_structure_get_int (s, "rate", &rate) ||
126       !gst_structure_get_int (s, "channels", &channels)) {
127     GST_ERROR_OBJECT (self, "Incomplete caps");
128     return FALSE;
129   }
130
131   self->spf = (mpegaudioversion == 1 ? 1152 : 576);
132
133   mp3_param.nChannels = channels;
134   mp3_param.nBitRate = 0;       /* unknown */
135   mp3_param.nSampleRate = rate;
136   mp3_param.nAudioBandWidth = 0;        /* decoder decision */
137   mp3_param.eChannelMode = 0;   /* FIXME */
138   if (mpegaudioversion == 1)
139     mp3_param.eFormat = OMX_AUDIO_MP3StreamFormatMP1Layer3;
140   else if (mpegaudioversion == 2)
141     mp3_param.eFormat = OMX_AUDIO_MP3StreamFormatMP2Layer3;
142   else
143     mp3_param.eFormat = OMX_AUDIO_MP3StreamFormatMP2_5Layer3;
144
145   err =
146       gst_omx_component_set_parameter (dec->dec, OMX_IndexParamAudioMp3,
147       &mp3_param);
148   if (err != OMX_ErrorNone) {
149     GST_ERROR_OBJECT (self, "Error setting MP3 parameters: %s (0x%08x)",
150         gst_omx_error_to_string (err), err);
151     return FALSE;
152   }
153
154   return TRUE;
155 }
156
157 static gboolean
158 gst_omx_mp3_dec_is_format_change (GstOMXAudioDec * dec, GstOMXPort * port,
159     GstCaps * caps)
160 {
161   GstOMXMP3Dec *self = GST_OMX_MP3_DEC (dec);
162   OMX_AUDIO_PARAM_MP3TYPE mp3_param;
163   OMX_ERRORTYPE err;
164   GstStructure *s;
165   gint rate, channels, layer, mpegaudioversion;
166
167   GST_OMX_INIT_STRUCT (&mp3_param);
168   mp3_param.nPortIndex = port->index;
169
170   err =
171       gst_omx_component_get_parameter (dec->dec, OMX_IndexParamAudioMp3,
172       &mp3_param);
173   if (err != OMX_ErrorNone) {
174     GST_ERROR_OBJECT (self,
175         "Failed to get MP3 parameters from component: %s (0x%08x)",
176         gst_omx_error_to_string (err), err);
177     return FALSE;
178   }
179
180   s = gst_caps_get_structure (caps, 0);
181
182   if (!gst_structure_get_int (s, "mpegaudioversion", &mpegaudioversion) ||
183       !gst_structure_get_int (s, "layer", &layer) ||
184       !gst_structure_get_int (s, "rate", &rate) ||
185       !gst_structure_get_int (s, "channels", &channels)) {
186     GST_ERROR_OBJECT (self, "Incomplete caps");
187     return FALSE;
188   }
189
190   if (mp3_param.nChannels != channels)
191     return TRUE;
192
193   if (mp3_param.nSampleRate != rate)
194     return TRUE;
195
196   if (mpegaudioversion == 1
197       && mp3_param.eFormat != OMX_AUDIO_MP3StreamFormatMP1Layer3)
198     return TRUE;
199   if (mpegaudioversion == 2
200       && mp3_param.eFormat != OMX_AUDIO_MP3StreamFormatMP2Layer3)
201     return TRUE;
202   if (mpegaudioversion == 3
203       && mp3_param.eFormat != OMX_AUDIO_MP3StreamFormatMP2_5Layer3)
204     return TRUE;
205
206   return FALSE;
207 }
208
209 static gint
210 gst_omx_mp3_dec_get_samples_per_frame (GstOMXAudioDec * dec, GstOMXPort * port)
211 {
212   return GST_OMX_MP3_DEC (dec)->spf;
213 }
214
215 static gboolean
216 gst_omx_mp3_dec_get_channel_positions (GstOMXAudioDec * dec,
217     GstOMXPort * port, GstAudioChannelPosition position[OMX_AUDIO_MAXCHANNELS])
218 {
219   OMX_AUDIO_PARAM_PCMMODETYPE pcm_param;
220   OMX_ERRORTYPE err;
221
222   GST_OMX_INIT_STRUCT (&pcm_param);
223   pcm_param.nPortIndex = port->index;
224   err =
225       gst_omx_component_get_parameter (dec->dec, OMX_IndexParamAudioPcm,
226       &pcm_param);
227   if (err != OMX_ErrorNone) {
228     GST_ERROR_OBJECT (dec, "Failed to get PCM parameters: %s (0x%08x)",
229         gst_omx_error_to_string (err), err);
230     return FALSE;
231   }
232
233   switch (pcm_param.nChannels) {
234     case 1:
235       position[0] = GST_AUDIO_CHANNEL_POSITION_MONO;
236       break;
237     case 2:
238       position[0] = GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT;
239       position[1] = GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT;
240       break;
241     default:
242       return FALSE;
243   }
244
245   return TRUE;
246 }