blob: 409111137faf03de7a16edaa9e204e4dd3a4973e [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 "SoftVorbis"
19#include <utils/Log.h>
20
21#include "SoftVorbis.h"
22
23#include <media/stagefright/foundation/ADebug.h>
24#include <media/stagefright/MediaDefs.h>
25
26extern "C" {
27 #include <Tremolo/codec_internal.h>
28
29 int _vorbis_unpack_books(vorbis_info *vi,oggpack_buffer *opb);
30 int _vorbis_unpack_info(vorbis_info *vi,oggpack_buffer *opb);
31 int _vorbis_unpack_comment(vorbis_comment *vc,oggpack_buffer *opb);
32}
33
34namespace android {
35
36template<class T>
37static void InitOMXParams(T *params) {
38 params->nSize = sizeof(T);
39 params->nVersion.s.nVersionMajor = 1;
40 params->nVersion.s.nVersionMinor = 0;
41 params->nVersion.s.nRevision = 0;
42 params->nVersion.s.nStep = 0;
43}
44
45SoftVorbis::SoftVorbis(
46 const char *name,
47 const OMX_CALLBACKTYPE *callbacks,
48 OMX_PTR appData,
49 OMX_COMPONENTTYPE **component)
50 : SimpleSoftOMXComponent(name, callbacks, appData, component),
51 mInputBufferCount(0),
52 mState(NULL),
53 mVi(NULL),
54 mAnchorTimeUs(0),
55 mNumFramesOutput(0),
56 mNumFramesLeftOnPage(-1),
57 mOutputPortSettingsChange(NONE) {
58 initPorts();
59 CHECK_EQ(initDecoder(), (status_t)OK);
60}
61
62SoftVorbis::~SoftVorbis() {
63 if (mState != NULL) {
64 vorbis_dsp_clear(mState);
65 delete mState;
66 mState = NULL;
67 }
68
69 if (mVi != NULL) {
70 vorbis_info_clear(mVi);
71 delete mVi;
72 mVi = NULL;
73 }
74}
75
76void SoftVorbis::initPorts() {
77 OMX_PARAM_PORTDEFINITIONTYPE def;
78 InitOMXParams(&def);
79
80 def.nPortIndex = 0;
81 def.eDir = OMX_DirInput;
82 def.nBufferCountMin = kNumBuffers;
83 def.nBufferCountActual = def.nBufferCountMin;
84 def.nBufferSize = 8192;
85 def.bEnabled = OMX_TRUE;
86 def.bPopulated = OMX_FALSE;
87 def.eDomain = OMX_PortDomainAudio;
88 def.bBuffersContiguous = OMX_FALSE;
89 def.nBufferAlignment = 1;
90
91 def.format.audio.cMIMEType =
92 const_cast<char *>(MEDIA_MIMETYPE_AUDIO_VORBIS);
93
94 def.format.audio.pNativeRender = NULL;
95 def.format.audio.bFlagErrorConcealment = OMX_FALSE;
96 def.format.audio.eEncoding = OMX_AUDIO_CodingAAC;
97
98 addPort(def);
99
100 def.nPortIndex = 1;
101 def.eDir = OMX_DirOutput;
102 def.nBufferCountMin = kNumBuffers;
103 def.nBufferCountActual = def.nBufferCountMin;
104 def.nBufferSize = kMaxNumSamplesPerBuffer * sizeof(int16_t);
105 def.bEnabled = OMX_TRUE;
106 def.bPopulated = OMX_FALSE;
107 def.eDomain = OMX_PortDomainAudio;
108 def.bBuffersContiguous = OMX_FALSE;
109 def.nBufferAlignment = 2;
110
111 def.format.audio.cMIMEType = const_cast<char *>("audio/raw");
112 def.format.audio.pNativeRender = NULL;
113 def.format.audio.bFlagErrorConcealment = OMX_FALSE;
114 def.format.audio.eEncoding = OMX_AUDIO_CodingPCM;
115
116 addPort(def);
117}
118
119status_t SoftVorbis::initDecoder() {
120 return OK;
121}
122
123OMX_ERRORTYPE SoftVorbis::internalGetParameter(
124 OMX_INDEXTYPE index, OMX_PTR params) {
125 switch (index) {
126 case OMX_IndexParamAudioVorbis:
127 {
128 OMX_AUDIO_PARAM_VORBISTYPE *vorbisParams =
129 (OMX_AUDIO_PARAM_VORBISTYPE *)params;
130
131 if (vorbisParams->nPortIndex != 0) {
132 return OMX_ErrorUndefined;
133 }
134
135 vorbisParams->nBitRate = 0;
136 vorbisParams->nMinBitRate = 0;
137 vorbisParams->nMaxBitRate = 0;
138 vorbisParams->nAudioBandWidth = 0;
139 vorbisParams->nQuality = 3;
140 vorbisParams->bManaged = OMX_FALSE;
141 vorbisParams->bDownmix = OMX_FALSE;
142
143 if (!isConfigured()) {
144 vorbisParams->nChannels = 1;
145 vorbisParams->nSampleRate = 44100;
146 } else {
147 vorbisParams->nChannels = mVi->channels;
148 vorbisParams->nSampleRate = mVi->rate;
149 vorbisParams->nBitRate = mVi->bitrate_nominal;
150 vorbisParams->nMinBitRate = mVi->bitrate_lower;
151 vorbisParams->nMaxBitRate = mVi->bitrate_upper;
152 }
153
154 return OMX_ErrorNone;
155 }
156
157 case OMX_IndexParamAudioPcm:
158 {
159 OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams =
160 (OMX_AUDIO_PARAM_PCMMODETYPE *)params;
161
162 if (pcmParams->nPortIndex != 1) {
163 return OMX_ErrorUndefined;
164 }
165
166 pcmParams->eNumData = OMX_NumericalDataSigned;
167 pcmParams->eEndian = OMX_EndianBig;
168 pcmParams->bInterleaved = OMX_TRUE;
169 pcmParams->nBitPerSample = 16;
170 pcmParams->ePCMMode = OMX_AUDIO_PCMModeLinear;
171 pcmParams->eChannelMapping[0] = OMX_AUDIO_ChannelLF;
172 pcmParams->eChannelMapping[1] = OMX_AUDIO_ChannelRF;
173
174 if (!isConfigured()) {
175 pcmParams->nChannels = 1;
176 pcmParams->nSamplingRate = 44100;
177 } else {
178 pcmParams->nChannels = mVi->channels;
179 pcmParams->nSamplingRate = mVi->rate;
180 }
181
182 return OMX_ErrorNone;
183 }
184
185 default:
186 return SimpleSoftOMXComponent::internalGetParameter(index, params);
187 }
188}
189
190OMX_ERRORTYPE SoftVorbis::internalSetParameter(
191 OMX_INDEXTYPE index, const OMX_PTR params) {
192 switch (index) {
193 case OMX_IndexParamStandardComponentRole:
194 {
195 const OMX_PARAM_COMPONENTROLETYPE *roleParams =
196 (const OMX_PARAM_COMPONENTROLETYPE *)params;
197
198 if (strncmp((const char *)roleParams->cRole,
199 "audio_decoder.vorbis",
200 OMX_MAX_STRINGNAME_SIZE - 1)) {
201 return OMX_ErrorUndefined;
202 }
203
204 return OMX_ErrorNone;
205 }
206
207 case OMX_IndexParamAudioVorbis:
208 {
209 const OMX_AUDIO_PARAM_VORBISTYPE *vorbisParams =
210 (const OMX_AUDIO_PARAM_VORBISTYPE *)params;
211
212 if (vorbisParams->nPortIndex != 0) {
213 return OMX_ErrorUndefined;
214 }
215
216 return OMX_ErrorNone;
217 }
218
219 default:
220 return SimpleSoftOMXComponent::internalSetParameter(index, params);
221 }
222}
223
224bool SoftVorbis::isConfigured() const {
225 return mInputBufferCount >= 2;
226}
227
228static void makeBitReader(
229 const void *data, size_t size,
230 ogg_buffer *buf, ogg_reference *ref, oggpack_buffer *bits) {
231 buf->data = (uint8_t *)data;
232 buf->size = size;
233 buf->refcount = 1;
234 buf->ptr.owner = NULL;
235
236 ref->buffer = buf;
237 ref->begin = 0;
238 ref->length = size;
239 ref->next = NULL;
240
241 oggpack_readinit(bits, ref);
242}
243
244void SoftVorbis::onQueueFilled(OMX_U32 portIndex) {
245 List<BufferInfo *> &inQueue = getPortQueue(0);
246 List<BufferInfo *> &outQueue = getPortQueue(1);
247
248 if (mOutputPortSettingsChange != NONE) {
249 return;
250 }
251
252 if (portIndex == 0 && mInputBufferCount < 2) {
253 BufferInfo *info = *inQueue.begin();
254 OMX_BUFFERHEADERTYPE *header = info->mHeader;
255
256 const uint8_t *data = header->pBuffer + header->nOffset;
257 size_t size = header->nFilledLen;
258
259 ogg_buffer buf;
260 ogg_reference ref;
261 oggpack_buffer bits;
262
263 makeBitReader(
264 (const uint8_t *)data + 7, size - 7,
265 &buf, &ref, &bits);
266
267 if (mInputBufferCount == 0) {
268 CHECK(mVi == NULL);
269 mVi = new vorbis_info;
270 vorbis_info_init(mVi);
271
272 CHECK_EQ(0, _vorbis_unpack_info(mVi, &bits));
273 } else {
274 CHECK_EQ(0, _vorbis_unpack_books(mVi, &bits));
275
276 CHECK(mState == NULL);
277 mState = new vorbis_dsp_state;
278 CHECK_EQ(0, vorbis_dsp_init(mState, mVi));
279
280 notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
281 mOutputPortSettingsChange = AWAITING_DISABLED;
282 }
283
284 inQueue.erase(inQueue.begin());
285 info->mOwnedByUs = false;
286 notifyEmptyBufferDone(header);
287
288 ++mInputBufferCount;
289
290 return;
291 }
292
293 while (!inQueue.empty() && !outQueue.empty()) {
294 BufferInfo *inInfo = *inQueue.begin();
295 OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
296
297 BufferInfo *outInfo = *outQueue.begin();
298 OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
299
300 if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
301 inQueue.erase(inQueue.begin());
302 inInfo->mOwnedByUs = false;
303 notifyEmptyBufferDone(inHeader);
304
305 outHeader->nFilledLen = 0;
306 outHeader->nFlags = OMX_BUFFERFLAG_EOS;
307
308 outQueue.erase(outQueue.begin());
309 outInfo->mOwnedByUs = false;
310 notifyFillBufferDone(outHeader);
311 return;
312 }
313
314 int32_t numPageSamples;
315 CHECK_GE(inHeader->nFilledLen, sizeof(numPageSamples));
316 memcpy(&numPageSamples,
317 inHeader->pBuffer
318 + inHeader->nOffset + inHeader->nFilledLen - 4,
319 sizeof(numPageSamples));
320
321 if (numPageSamples >= 0) {
322 mNumFramesLeftOnPage = numPageSamples;
323 }
324
325 if (inHeader->nOffset == 0) {
326 mAnchorTimeUs = inHeader->nTimeStamp;
327 mNumFramesOutput = 0;
328 }
329
330 inHeader->nFilledLen -= sizeof(numPageSamples);;
331
332 ogg_buffer buf;
333 buf.data = inHeader->pBuffer + inHeader->nOffset;
334 buf.size = inHeader->nFilledLen;
335 buf.refcount = 1;
336 buf.ptr.owner = NULL;
337
338 ogg_reference ref;
339 ref.buffer = &buf;
340 ref.begin = 0;
341 ref.length = buf.size;
342 ref.next = NULL;
343
344 ogg_packet pack;
345 pack.packet = &ref;
346 pack.bytes = ref.length;
347 pack.b_o_s = 0;
348 pack.e_o_s = 0;
349 pack.granulepos = 0;
350 pack.packetno = 0;
351
352 int numFrames = 0;
353
354 int err = vorbis_dsp_synthesis(mState, &pack, 1);
355 if (err != 0) {
356 LOGW("vorbis_dsp_synthesis returned %d", err);
357 } else {
358 numFrames = vorbis_dsp_pcmout(
359 mState, (int16_t *)outHeader->pBuffer,
360 kMaxNumSamplesPerBuffer);
361
362 if (numFrames < 0) {
363 LOGE("vorbis_dsp_pcmout returned %d", numFrames);
364 numFrames = 0;
365 }
366 }
367
368 if (mNumFramesLeftOnPage >= 0) {
369 if (numFrames > mNumFramesLeftOnPage) {
370 LOGV("discarding %d frames at end of page",
371 numFrames - mNumFramesLeftOnPage);
372 numFrames = mNumFramesLeftOnPage;
373 }
374 mNumFramesLeftOnPage -= numFrames;
375 }
376
377 outHeader->nFilledLen = numFrames * sizeof(int16_t) * mVi->channels;
378 outHeader->nOffset = 0;
379 outHeader->nFlags = 0;
380
381 outHeader->nTimeStamp =
382 mAnchorTimeUs
383 + (mNumFramesOutput * 1000000ll) / mVi->rate;
384
385 mNumFramesOutput += numFrames;
386
387 inInfo->mOwnedByUs = false;
388 inQueue.erase(inQueue.begin());
389 inInfo = NULL;
390 notifyEmptyBufferDone(inHeader);
391 inHeader = NULL;
392
393 outInfo->mOwnedByUs = false;
394 outQueue.erase(outQueue.begin());
395 outInfo = NULL;
396 notifyFillBufferDone(outHeader);
397 outHeader = NULL;
398
399 ++mInputBufferCount;
400 }
401}
402
403void SoftVorbis::onPortFlushCompleted(OMX_U32 portIndex) {
404 if (portIndex == 0 && mState != NULL) {
405 // Make sure that the next buffer output does not still
406 // depend on fragments from the last one decoded.
407
408 mNumFramesOutput = 0;
409 vorbis_dsp_restart(mState);
410 }
411}
412
413void SoftVorbis::onPortEnableCompleted(OMX_U32 portIndex, bool enabled) {
414 if (portIndex != 1) {
415 return;
416 }
417
418 switch (mOutputPortSettingsChange) {
419 case NONE:
420 break;
421
422 case AWAITING_DISABLED:
423 {
424 CHECK(!enabled);
425 mOutputPortSettingsChange = AWAITING_ENABLED;
426 break;
427 }
428
429 default:
430 {
431 CHECK_EQ((int)mOutputPortSettingsChange, (int)AWAITING_ENABLED);
432 CHECK(enabled);
433 mOutputPortSettingsChange = NONE;
434 break;
435 }
436 }
437}
438
439} // namespace android
440
441android::SoftOMXComponent *createSoftOMXComponent(
442 const char *name, const OMX_CALLBACKTYPE *callbacks,
443 OMX_PTR appData, OMX_COMPONENTTYPE **component) {
444 return new android::SoftVorbis(name, callbacks, appData, component);
445}