blob: f6770b012fb2f5fee50da4bcd762e18f5677ef40 [file] [log] [blame]
Andreas Huber4b3913a2011-05-11 14:13:42 -07001/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17//#define LOG_NDEBUG 0
18#define LOG_TAG "SoftMP3"
19#include <utils/Log.h>
20
21#include "SoftMP3.h"
22
23#include <media/stagefright/foundation/ADebug.h>
24#include <media/stagefright/MediaDefs.h>
25
26#include "include/pvmp3decoder_api.h"
27
28namespace android {
29
30template<class T>
31static void InitOMXParams(T *params) {
32 params->nSize = sizeof(T);
33 params->nVersion.s.nVersionMajor = 1;
34 params->nVersion.s.nVersionMinor = 0;
35 params->nVersion.s.nRevision = 0;
36 params->nVersion.s.nStep = 0;
37}
38
39SoftMP3::SoftMP3(
40 const char *name,
41 const OMX_CALLBACKTYPE *callbacks,
42 OMX_PTR appData,
43 OMX_COMPONENTTYPE **component)
44 : SimpleSoftOMXComponent(name, callbacks, appData, component),
45 mConfig(new tPVMP3DecoderExternal),
46 mDecoderBuf(NULL),
47 mAnchorTimeUs(0),
48 mNumFramesOutput(0),
49 mNumChannels(2),
50 mSamplingRate(44100),
51 mSignalledError(false),
52 mOutputPortSettingsChange(NONE) {
53 initPorts();
54 initDecoder();
55}
56
57SoftMP3::~SoftMP3() {
58 if (mDecoderBuf != NULL) {
59 free(mDecoderBuf);
60 mDecoderBuf = NULL;
61 }
62
63 delete mConfig;
64 mConfig = NULL;
65}
66
67void SoftMP3::initPorts() {
68 OMX_PARAM_PORTDEFINITIONTYPE def;
69 InitOMXParams(&def);
70
71 def.nPortIndex = 0;
72 def.eDir = OMX_DirInput;
73 def.nBufferCountMin = kNumBuffers;
74 def.nBufferCountActual = def.nBufferCountMin;
75 def.nBufferSize = 8192;
76 def.bEnabled = OMX_TRUE;
77 def.bPopulated = OMX_FALSE;
78 def.eDomain = OMX_PortDomainAudio;
79 def.bBuffersContiguous = OMX_FALSE;
80 def.nBufferAlignment = 1;
81
82 def.format.audio.cMIMEType =
83 const_cast<char *>(MEDIA_MIMETYPE_AUDIO_MPEG);
84
85 def.format.audio.pNativeRender = NULL;
86 def.format.audio.bFlagErrorConcealment = OMX_FALSE;
87 def.format.audio.eEncoding = OMX_AUDIO_CodingMP3;
88
89 addPort(def);
90
91 def.nPortIndex = 1;
92 def.eDir = OMX_DirOutput;
93 def.nBufferCountMin = kNumBuffers;
94 def.nBufferCountActual = def.nBufferCountMin;
95 def.nBufferSize = kOutputBufferSize;
96 def.bEnabled = OMX_TRUE;
97 def.bPopulated = OMX_FALSE;
98 def.eDomain = OMX_PortDomainAudio;
99 def.bBuffersContiguous = OMX_FALSE;
100 def.nBufferAlignment = 2;
101
102 def.format.audio.cMIMEType = const_cast<char *>("audio/raw");
103 def.format.audio.pNativeRender = NULL;
104 def.format.audio.bFlagErrorConcealment = OMX_FALSE;
105 def.format.audio.eEncoding = OMX_AUDIO_CodingPCM;
106
107 addPort(def);
108}
109
110void SoftMP3::initDecoder() {
111 mConfig->equalizerType = flat;
112 mConfig->crcEnabled = false;
113
114 uint32_t memRequirements = pvmp3_decoderMemRequirements();
115 mDecoderBuf = malloc(memRequirements);
116
117 pvmp3_InitDecoder(mConfig, mDecoderBuf);
118}
119
120OMX_ERRORTYPE SoftMP3::internalGetParameter(
121 OMX_INDEXTYPE index, OMX_PTR params) {
122 switch (index) {
123 case OMX_IndexParamAudioPcm:
124 {
125 OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams =
126 (OMX_AUDIO_PARAM_PCMMODETYPE *)params;
127
128 if (pcmParams->nPortIndex > 1) {
129 return OMX_ErrorUndefined;
130 }
131
132 pcmParams->eNumData = OMX_NumericalDataSigned;
133 pcmParams->eEndian = OMX_EndianBig;
134 pcmParams->bInterleaved = OMX_TRUE;
135 pcmParams->nBitPerSample = 16;
136 pcmParams->ePCMMode = OMX_AUDIO_PCMModeLinear;
137 pcmParams->eChannelMapping[0] = OMX_AUDIO_ChannelLF;
138 pcmParams->eChannelMapping[1] = OMX_AUDIO_ChannelRF;
139
140 pcmParams->nChannels = mNumChannels;
141 pcmParams->nSamplingRate = mSamplingRate;
142
143 return OMX_ErrorNone;
144 }
145
146 default:
147 return SimpleSoftOMXComponent::internalGetParameter(index, params);
148 }
149}
150
151OMX_ERRORTYPE SoftMP3::internalSetParameter(
152 OMX_INDEXTYPE index, const OMX_PTR params) {
153 switch (index) {
154 case OMX_IndexParamStandardComponentRole:
155 {
156 const OMX_PARAM_COMPONENTROLETYPE *roleParams =
157 (const OMX_PARAM_COMPONENTROLETYPE *)params;
158
159 if (strncmp((const char *)roleParams->cRole,
160 "audio_decoder.mp3",
161 OMX_MAX_STRINGNAME_SIZE - 1)) {
162 return OMX_ErrorUndefined;
163 }
164
165 return OMX_ErrorNone;
166 }
167
168 default:
169 return SimpleSoftOMXComponent::internalSetParameter(index, params);
170 }
171}
172
173void SoftMP3::onQueueFilled(OMX_U32 portIndex) {
174 if (mSignalledError || mOutputPortSettingsChange != NONE) {
175 return;
176 }
177
178 List<BufferInfo *> &inQueue = getPortQueue(0);
179 List<BufferInfo *> &outQueue = getPortQueue(1);
180
181 while (!inQueue.empty() && !outQueue.empty()) {
182 BufferInfo *inInfo = *inQueue.begin();
183 OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
184
185 BufferInfo *outInfo = *outQueue.begin();
186 OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
187
188 if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
189 inQueue.erase(inQueue.begin());
190 inInfo->mOwnedByUs = false;
191 notifyEmptyBufferDone(inHeader);
192
193 outHeader->nFilledLen = 0;
194 outHeader->nFlags = OMX_BUFFERFLAG_EOS;
195
196 outQueue.erase(outQueue.begin());
197 outInfo->mOwnedByUs = false;
198 notifyFillBufferDone(outHeader);
199 return;
200 }
201
202 if (inHeader->nOffset == 0) {
203 mAnchorTimeUs = inHeader->nTimeStamp;
204 mNumFramesOutput = 0;
205 }
206
207 mConfig->pInputBuffer =
208 inHeader->pBuffer + inHeader->nOffset;
209
210 mConfig->inputBufferCurrentLength = inHeader->nFilledLen;
211 mConfig->inputBufferMaxLength = 0;
212 mConfig->inputBufferUsedLength = 0;
213
214 mConfig->outputFrameSize = kOutputBufferSize / sizeof(int16_t);
215
216 mConfig->pOutputBuffer =
217 reinterpret_cast<int16_t *>(outHeader->pBuffer);
218
219 ERROR_CODE decoderErr;
220 if ((decoderErr = pvmp3_framedecoder(mConfig, mDecoderBuf))
221 != NO_DECODING_ERROR) {
222 LOGV("mp3 decoder returned error %d", decoderErr);
223
224 if (decoderErr != NO_ENOUGH_MAIN_DATA_ERROR ||
225 mConfig->outputFrameSize == 0) {
226
227 if (mConfig->outputFrameSize == 0) {
228 LOGE("Output frame size is 0");
229 }
230
231 notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL);
232 mSignalledError = true;
233 return;
234 }
235
236 // This is recoverable, just ignore the current frame and
237 // play silence instead.
238 memset(outHeader->pBuffer,
239 0,
240 mConfig->outputFrameSize * sizeof(int16_t));
241
242 mConfig->inputBufferUsedLength = inHeader->nFilledLen;
243 } else if (mConfig->samplingRate != mSamplingRate
244 || mConfig->num_channels != mNumChannels) {
245 mSamplingRate = mConfig->samplingRate;
246 mNumChannels = mConfig->num_channels;
247
248 notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
249 mOutputPortSettingsChange = AWAITING_DISABLED;
250 return;
251 }
252
253 outHeader->nOffset = 0;
254 outHeader->nFilledLen = mConfig->outputFrameSize * sizeof(int16_t);
255
256 outHeader->nTimeStamp =
257 mAnchorTimeUs
258 + (mNumFramesOutput * 1000000ll) / mConfig->samplingRate;
259
260 outHeader->nFlags = 0;
261
262 CHECK_GE(inHeader->nFilledLen, mConfig->inputBufferUsedLength);
263
264 inHeader->nOffset += mConfig->inputBufferUsedLength;
265 inHeader->nFilledLen -= mConfig->inputBufferUsedLength;
266
267 mNumFramesOutput += mConfig->outputFrameSize / mNumChannels;
268
269 if (inHeader->nFilledLen == 0) {
270 inInfo->mOwnedByUs = false;
271 inQueue.erase(inQueue.begin());
272 inInfo = NULL;
273 notifyEmptyBufferDone(inHeader);
274 inHeader = NULL;
275 }
276
277 outInfo->mOwnedByUs = false;
278 outQueue.erase(outQueue.begin());
279 outInfo = NULL;
280 notifyFillBufferDone(outHeader);
281 outHeader = NULL;
282 }
283}
284
285void SoftMP3::onPortFlushCompleted(OMX_U32 portIndex) {
286 if (portIndex == 0) {
287 // Make sure that the next buffer output does not still
288 // depend on fragments from the last one decoded.
289 pvmp3_InitDecoder(mConfig, mDecoderBuf);
290 }
291}
292
293void SoftMP3::onPortEnableCompleted(OMX_U32 portIndex, bool enabled) {
294 if (portIndex != 1) {
295 return;
296 }
297
298 switch (mOutputPortSettingsChange) {
299 case NONE:
300 break;
301
302 case AWAITING_DISABLED:
303 {
304 CHECK(!enabled);
305 mOutputPortSettingsChange = AWAITING_ENABLED;
306 break;
307 }
308
309 default:
310 {
311 CHECK_EQ((int)mOutputPortSettingsChange, (int)AWAITING_ENABLED);
312 CHECK(enabled);
313 mOutputPortSettingsChange = NONE;
314 break;
315 }
316 }
317}
318
319} // namespace android
320
321android::SoftOMXComponent *createSoftOMXComponent(
322 const char *name, const OMX_CALLBACKTYPE *callbacks,
323 OMX_PTR appData, OMX_COMPONENTTYPE **component) {
324 return new android::SoftMP3(name, callbacks, appData, component);
325}