1 /*
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
26 static int kDefaultChannelCount = 1;
27 static int kDefaultSamplingRate = 48000;
28
29 extern "C" {
30 #include <Tremolo/codec_internal.h>
31
32 int _vorbis_unpack_books(vorbis_info *vi,oggpack_buffer *opb);
33 int _vorbis_unpack_info(vorbis_info *vi,oggpack_buffer *opb);
34 int _vorbis_unpack_comment(vorbis_comment *vc,oggpack_buffer *opb);
35 }
36
37 namespace android {
38
39 template<class T>
InitOMXParams(T * params)40 static void InitOMXParams(T *params) {
41 params->nSize = sizeof(T);
42 params->nVersion.s.nVersionMajor = 1;
43 params->nVersion.s.nVersionMinor = 0;
44 params->nVersion.s.nRevision = 0;
45 params->nVersion.s.nStep = 0;
46 }
47
SoftVorbis(const char * name,const OMX_CALLBACKTYPE * callbacks,OMX_PTR appData,OMX_COMPONENTTYPE ** component)48 SoftVorbis::SoftVorbis(
49 const char *name,
50 const OMX_CALLBACKTYPE *callbacks,
51 OMX_PTR appData,
52 OMX_COMPONENTTYPE **component)
53 : SimpleSoftOMXComponent(name, callbacks, appData, component),
54 mInputBufferCount(0),
55 mState(NULL),
56 mVi(NULL),
57 mAnchorTimeUs(0),
58 mNumFramesOutput(0),
59 mNumFramesLeftOnPage(-1),
60 mSawInputEos(false),
61 mSignalledOutputEos(false),
62 mSignalledError(false),
63 mOutputPortSettingsChange(NONE) {
64 initPorts();
65 CHECK_EQ(initDecoder(), (status_t)OK);
66 }
67
~SoftVorbis()68 SoftVorbis::~SoftVorbis() {
69 if (mState != NULL) {
70 vorbis_dsp_clear(mState);
71 delete mState;
72 mState = NULL;
73 }
74
75 if (mVi != NULL) {
76 vorbis_info_clear(mVi);
77 delete mVi;
78 mVi = NULL;
79 }
80 }
81
initPorts()82 void SoftVorbis::initPorts() {
83 OMX_PARAM_PORTDEFINITIONTYPE def;
84 InitOMXParams(&def);
85
86 def.nPortIndex = 0;
87 def.eDir = OMX_DirInput;
88 def.nBufferCountMin = kNumBuffers;
89 def.nBufferCountActual = def.nBufferCountMin;
90 def.nBufferSize = kMaxNumSamplesPerBuffer * sizeof(int16_t);
91 def.bEnabled = OMX_TRUE;
92 def.bPopulated = OMX_FALSE;
93 def.eDomain = OMX_PortDomainAudio;
94 def.bBuffersContiguous = OMX_FALSE;
95 def.nBufferAlignment = 1;
96
97 def.format.audio.cMIMEType =
98 const_cast<char *>(MEDIA_MIMETYPE_AUDIO_VORBIS);
99
100 def.format.audio.pNativeRender = NULL;
101 def.format.audio.bFlagErrorConcealment = OMX_FALSE;
102 def.format.audio.eEncoding = OMX_AUDIO_CodingVORBIS;
103
104 addPort(def);
105
106 def.nPortIndex = 1;
107 def.eDir = OMX_DirOutput;
108 def.nBufferCountMin = kNumBuffers;
109 def.nBufferCountActual = def.nBufferCountMin;
110 def.nBufferSize = kMaxNumSamplesPerBuffer * sizeof(int16_t);
111 def.bEnabled = OMX_TRUE;
112 def.bPopulated = OMX_FALSE;
113 def.eDomain = OMX_PortDomainAudio;
114 def.bBuffersContiguous = OMX_FALSE;
115 def.nBufferAlignment = 2;
116
117 def.format.audio.cMIMEType = const_cast<char *>("audio/raw");
118 def.format.audio.pNativeRender = NULL;
119 def.format.audio.bFlagErrorConcealment = OMX_FALSE;
120 def.format.audio.eEncoding = OMX_AUDIO_CodingPCM;
121
122 addPort(def);
123 }
124
initDecoder()125 status_t SoftVorbis::initDecoder() {
126 return OK;
127 }
128
internalGetParameter(OMX_INDEXTYPE index,OMX_PTR params)129 OMX_ERRORTYPE SoftVorbis::internalGetParameter(
130 OMX_INDEXTYPE index, OMX_PTR params) {
131 switch (index) {
132 case OMX_IndexParamAudioPortFormat:
133 {
134 OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams =
135 (OMX_AUDIO_PARAM_PORTFORMATTYPE *)params;
136
137 if (!isValidOMXParam(formatParams)) {
138 return OMX_ErrorBadParameter;
139 }
140
141 if (formatParams->nPortIndex > 1) {
142 return OMX_ErrorUndefined;
143 }
144
145 if (formatParams->nIndex > 0) {
146 return OMX_ErrorNoMore;
147 }
148
149 formatParams->eEncoding =
150 (formatParams->nPortIndex == 0)
151 ? OMX_AUDIO_CodingVORBIS : OMX_AUDIO_CodingPCM;
152
153 return OMX_ErrorNone;
154 }
155
156 case OMX_IndexParamAudioVorbis:
157 {
158 OMX_AUDIO_PARAM_VORBISTYPE *vorbisParams =
159 (OMX_AUDIO_PARAM_VORBISTYPE *)params;
160
161 if (!isValidOMXParam(vorbisParams)) {
162 return OMX_ErrorBadParameter;
163 }
164
165 if (vorbisParams->nPortIndex != 0) {
166 return OMX_ErrorUndefined;
167 }
168
169 vorbisParams->nBitRate = 0;
170 vorbisParams->nMinBitRate = 0;
171 vorbisParams->nMaxBitRate = 0;
172 vorbisParams->nAudioBandWidth = 0;
173 vorbisParams->nQuality = 3;
174 vorbisParams->bManaged = OMX_FALSE;
175 vorbisParams->bDownmix = OMX_FALSE;
176
177 if (!isConfigured()) {
178 vorbisParams->nChannels = kDefaultChannelCount;
179 vorbisParams->nSampleRate = kDefaultSamplingRate;
180 } else {
181 vorbisParams->nChannels = mVi->channels;
182 vorbisParams->nSampleRate = mVi->rate;
183 vorbisParams->nBitRate = mVi->bitrate_nominal;
184 vorbisParams->nMinBitRate = mVi->bitrate_lower;
185 vorbisParams->nMaxBitRate = mVi->bitrate_upper;
186 }
187 return OMX_ErrorNone;
188 }
189
190 case OMX_IndexParamAudioPcm:
191 {
192 OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams =
193 (OMX_AUDIO_PARAM_PCMMODETYPE *)params;
194
195 if (!isValidOMXParam(pcmParams)) {
196 return OMX_ErrorBadParameter;
197 }
198
199 if (pcmParams->nPortIndex != 1) {
200 return OMX_ErrorUndefined;
201 }
202
203 pcmParams->eNumData = OMX_NumericalDataSigned;
204 pcmParams->eEndian = OMX_EndianBig;
205 pcmParams->bInterleaved = OMX_TRUE;
206 pcmParams->nBitPerSample = 16;
207 pcmParams->ePCMMode = OMX_AUDIO_PCMModeLinear;
208 pcmParams->eChannelMapping[0] = OMX_AUDIO_ChannelLF;
209 pcmParams->eChannelMapping[1] = OMX_AUDIO_ChannelRF;
210
211 if (!isConfigured()) {
212 pcmParams->nChannels = kDefaultChannelCount;
213 pcmParams->nSamplingRate = kDefaultSamplingRate;
214 } else {
215 pcmParams->nChannels = mVi->channels;
216 pcmParams->nSamplingRate = mVi->rate;
217 }
218
219 return OMX_ErrorNone;
220 }
221
222 default:
223 return SimpleSoftOMXComponent::internalGetParameter(index, params);
224 }
225 }
226
internalSetParameter(OMX_INDEXTYPE index,const OMX_PTR params)227 OMX_ERRORTYPE SoftVorbis::internalSetParameter(
228 OMX_INDEXTYPE index, const OMX_PTR params) {
229 switch (index) {
230 case OMX_IndexParamStandardComponentRole:
231 {
232 const OMX_PARAM_COMPONENTROLETYPE *roleParams =
233 (const OMX_PARAM_COMPONENTROLETYPE *)params;
234
235 if (!isValidOMXParam(roleParams)) {
236 return OMX_ErrorBadParameter;
237 }
238
239 if (strncmp((const char *)roleParams->cRole,
240 "audio_decoder.vorbis",
241 OMX_MAX_STRINGNAME_SIZE - 1)) {
242 return OMX_ErrorUndefined;
243 }
244
245 return OMX_ErrorNone;
246 }
247
248 case OMX_IndexParamAudioPortFormat:
249 {
250 const OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams =
251 (const OMX_AUDIO_PARAM_PORTFORMATTYPE *)params;
252
253 if (!isValidOMXParam(formatParams)) {
254 return OMX_ErrorBadParameter;
255 }
256
257 if (formatParams->nPortIndex > 1) {
258 return OMX_ErrorUndefined;
259 }
260
261 if ((formatParams->nPortIndex == 0
262 && formatParams->eEncoding != OMX_AUDIO_CodingVORBIS)
263 || (formatParams->nPortIndex == 1
264 && formatParams->eEncoding != OMX_AUDIO_CodingPCM)) {
265 return OMX_ErrorUndefined;
266 }
267
268 return OMX_ErrorNone;
269 }
270
271 case OMX_IndexParamAudioVorbis:
272 {
273 const OMX_AUDIO_PARAM_VORBISTYPE *vorbisParams =
274 (const OMX_AUDIO_PARAM_VORBISTYPE *)params;
275
276 if (!isValidOMXParam(vorbisParams)) {
277 return OMX_ErrorBadParameter;
278 }
279
280 if (vorbisParams->nPortIndex != 0) {
281 return OMX_ErrorUndefined;
282 }
283
284 return OMX_ErrorNone;
285 }
286
287 default:
288 return SimpleSoftOMXComponent::internalSetParameter(index, params);
289 }
290 }
291
isConfigured() const292 bool SoftVorbis::isConfigured() const {
293 return (mState != NULL && mVi != NULL);
294 }
295
makeBitReader(const void * data,size_t size,ogg_buffer * buf,ogg_reference * ref,oggpack_buffer * bits)296 static void makeBitReader(
297 const void *data, size_t size,
298 ogg_buffer *buf, ogg_reference *ref, oggpack_buffer *bits) {
299 buf->data = (uint8_t *)data;
300 buf->size = size;
301 buf->refcount = 1;
302 buf->ptr.owner = NULL;
303
304 ref->buffer = buf;
305 ref->begin = 0;
306 ref->length = size;
307 ref->next = NULL;
308
309 oggpack_readinit(bits, ref);
310 }
311
handleEOS()312 void SoftVorbis::handleEOS() {
313 List<BufferInfo *> &inQueue = getPortQueue(0);
314 List<BufferInfo *> &outQueue = getPortQueue(1);
315
316 CHECK(!inQueue.empty() && !outQueue.empty());
317
318 mSawInputEos = true;
319
320 BufferInfo *outInfo = *outQueue.begin();
321 OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
322 outHeader->nFilledLen = 0;
323 outHeader->nFlags = OMX_BUFFERFLAG_EOS;
324
325 outQueue.erase(outQueue.begin());
326 outInfo->mOwnedByUs = false;
327 notifyFillBufferDone(outHeader);
328 mSignalledOutputEos = true;
329
330 BufferInfo *inInfo = *inQueue.begin();
331 OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
332 inQueue.erase(inQueue.begin());
333 inInfo->mOwnedByUs = false;
334 notifyEmptyBufferDone(inHeader);
335 ++mInputBufferCount;
336 }
337
onQueueFilled(OMX_U32)338 void SoftVorbis::onQueueFilled(OMX_U32 /* portIndex */) {
339 List<BufferInfo *> &inQueue = getPortQueue(0);
340 List<BufferInfo *> &outQueue = getPortQueue(1);
341
342 if (mSignalledError || mOutputPortSettingsChange != NONE) {
343 return;
344 }
345
346 while (!mSignalledOutputEos && (!inQueue.empty() || mSawInputEos) && !outQueue.empty()) {
347 BufferInfo *inInfo = NULL;
348 OMX_BUFFERHEADERTYPE *inHeader = NULL;
349 if (!inQueue.empty()) {
350 inInfo = *inQueue.begin();
351 inHeader = inInfo->mHeader;
352 }
353
354 BufferInfo *outInfo = *outQueue.begin();
355 OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
356
357 int32_t numPageSamples = 0;
358
359 if (inHeader) {
360 // Assume the very first 2 buffers are always codec config (in this case mState is NULL)
361 // After flush, handle CSD
362 if (mInputBufferCount < 2 &&
363 (mState == NULL || (inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG))) {
364 const uint8_t *data = inHeader->pBuffer + inHeader->nOffset;
365 size_t size = inHeader->nFilledLen;
366
367 if ((inHeader->nFlags & OMX_BUFFERFLAG_EOS) && size == 0) {
368 handleEOS();
369 return;
370 }
371
372 if (size < 7) {
373 ALOGE("Too small input buffer: %zu bytes", size);
374 android_errorWriteLog(0x534e4554, "27833616");
375 notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
376 mSignalledError = true;
377 return;
378 }
379
380 ogg_buffer buf;
381 ogg_reference ref;
382 oggpack_buffer bits;
383
384 makeBitReader((const uint8_t *)data + 7, size - 7, &buf, &ref, &bits);
385
386 // Assume very first frame is identification header - or reset identification
387 // header after flush, but allow only specifying setup header after flush if
388 // identification header was already set up.
389 if (mInputBufferCount == 0 &&
390 (mVi == NULL || data[0] == 1 /* identification header */)) {
391 // remove any prior state
392 if (mVi != NULL) {
393 // also clear mState as it may refer to the old mVi
394 if (mState != NULL) {
395 vorbis_dsp_clear(mState);
396 delete mState;
397 mState = NULL;
398 }
399 vorbis_info_clear(mVi);
400 delete mVi;
401 mVi = NULL;
402 }
403
404 CHECK(mVi == NULL);
405 mVi = new vorbis_info;
406 vorbis_info_init(mVi);
407
408 int ret = _vorbis_unpack_info(mVi, &bits);
409 if (ret != 0) {
410 notify(OMX_EventError, OMX_ErrorUndefined, ret, NULL);
411 mSignalledError = true;
412 return;
413 }
414 } else {
415 // remove any prior state
416 if (mState != NULL) {
417 vorbis_dsp_clear(mState);
418 delete mState;
419 mState = NULL;
420 }
421
422 int ret = _vorbis_unpack_books(mVi, &bits);
423 if (ret != 0 || mState != NULL) {
424 notify(OMX_EventError, OMX_ErrorUndefined, ret, NULL);
425 mSignalledError = true;
426 return;
427 }
428
429 CHECK(mState == NULL);
430 mState = new vorbis_dsp_state;
431 CHECK_EQ(0, vorbis_dsp_init(mState, mVi));
432
433 if (mVi->rate != kDefaultSamplingRate ||
434 mVi->channels != kDefaultChannelCount) {
435 ALOGV("vorbis: rate/channels changed: %ld/%d", mVi->rate, mVi->channels);
436 notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
437 mOutputPortSettingsChange = AWAITING_DISABLED;
438 }
439 mInputBufferCount = 1;
440 }
441
442 if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
443 handleEOS();
444 return;
445 }
446
447 inQueue.erase(inQueue.begin());
448 inInfo->mOwnedByUs = false;
449 notifyEmptyBufferDone(inHeader);
450 ++mInputBufferCount;
451
452 continue;
453 }
454
455 if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
456 mSawInputEos = true;
457 }
458
459 if (inHeader->nFilledLen || !mSawInputEos) {
460 if (inHeader->nFilledLen < sizeof(numPageSamples)) {
461 notify(OMX_EventError, OMX_ErrorBadParameter, 0, NULL);
462 mSignalledError = true;
463 ALOGE("onQueueFilled, input header has nFilledLen %u, expected %zu",
464 inHeader->nFilledLen, sizeof(numPageSamples));
465 return;
466 }
467 memcpy(&numPageSamples,
468 inHeader->pBuffer + inHeader->nOffset + inHeader->nFilledLen - 4,
469 sizeof(numPageSamples));
470
471 if (inHeader->nOffset == 0) {
472 mAnchorTimeUs = inHeader->nTimeStamp;
473 mNumFramesOutput = 0;
474 }
475
476 inHeader->nFilledLen -= sizeof(numPageSamples);;
477 }
478 }
479
480 if (numPageSamples >= 0) {
481 mNumFramesLeftOnPage = numPageSamples;
482 }
483
484 ogg_buffer buf;
485 buf.data = inHeader ? inHeader->pBuffer + inHeader->nOffset : NULL;
486 buf.size = inHeader ? inHeader->nFilledLen : 0;
487 buf.refcount = 1;
488 buf.ptr.owner = NULL;
489
490 ogg_reference ref;
491 ref.buffer = &buf;
492 ref.begin = 0;
493 ref.length = buf.size;
494 ref.next = NULL;
495
496 ogg_packet pack;
497 pack.packet = &ref;
498 pack.bytes = ref.length;
499 pack.b_o_s = 0;
500 pack.e_o_s = 0;
501 pack.granulepos = 0;
502 pack.packetno = 0;
503
504 int numFrames = 0;
505
506 outHeader->nFlags = 0;
507
508 if (mState == nullptr || mVi == nullptr) {
509 notify(OMX_EventError, OMX_ErrorStreamCorrupt, 0, NULL);
510 mSignalledError = true;
511 ALOGE("onQueueFilled, input does not have CSD");
512 return;
513 }
514
515 int err = vorbis_dsp_synthesis(mState, &pack, 1);
516 if (err != 0) {
517 // FIXME temporary workaround for log spam
518 #if !defined(__arm__) && !defined(__aarch64__)
519 ALOGV("vorbis_dsp_synthesis returned %d", err);
520 #else
521 ALOGW("vorbis_dsp_synthesis returned %d", err);
522 #endif
523 } else {
524 size_t numSamplesPerBuffer = kMaxNumSamplesPerBuffer;
525 if (numSamplesPerBuffer > outHeader->nAllocLen / sizeof(int16_t)) {
526 numSamplesPerBuffer = outHeader->nAllocLen / sizeof(int16_t);
527 android_errorWriteLog(0x534e4554, "27833616");
528 }
529 numFrames = vorbis_dsp_pcmout(
530 mState, (int16_t *)outHeader->pBuffer,
531 (numSamplesPerBuffer / mVi->channels));
532
533 if (numFrames < 0) {
534 ALOGE("vorbis_dsp_pcmout returned %d", numFrames);
535 numFrames = 0;
536 }
537 }
538
539 if (mNumFramesLeftOnPage >= 0) {
540 if (numFrames > mNumFramesLeftOnPage) {
541 ALOGV("discarding %d frames at end of page",
542 numFrames - mNumFramesLeftOnPage);
543 numFrames = mNumFramesLeftOnPage;
544 if (mSawInputEos) {
545 outHeader->nFlags = OMX_BUFFERFLAG_EOS;
546 mSignalledOutputEos = true;
547 }
548 }
549 mNumFramesLeftOnPage -= numFrames;
550 }
551
552 outHeader->nFilledLen = numFrames * sizeof(int16_t) * mVi->channels;
553 outHeader->nOffset = 0;
554
555 outHeader->nTimeStamp =
556 mAnchorTimeUs
557 + (mNumFramesOutput * 1000000LL) / mVi->rate;
558
559 mNumFramesOutput += numFrames;
560
561 if (inHeader) {
562 inInfo->mOwnedByUs = false;
563 inQueue.erase(inQueue.begin());
564 notifyEmptyBufferDone(inHeader);
565 ++mInputBufferCount;
566 }
567
568 outInfo->mOwnedByUs = false;
569 outQueue.erase(outQueue.begin());
570 notifyFillBufferDone(outHeader);
571 }
572 }
573
onPortFlushCompleted(OMX_U32 portIndex)574 void SoftVorbis::onPortFlushCompleted(OMX_U32 portIndex) {
575 if (portIndex == 0) {
576 mInputBufferCount = 0;
577 mNumFramesOutput = 0;
578 mSawInputEos = false;
579 mSignalledOutputEos = false;
580 mNumFramesLeftOnPage = -1;
581 if (mState != NULL) {
582 // Make sure that the next buffer output does not still
583 // depend on fragments from the last one decoded.
584 vorbis_dsp_restart(mState);
585 }
586 }
587 }
588
onReset()589 void SoftVorbis::onReset() {
590 mInputBufferCount = 0;
591 mNumFramesOutput = 0;
592 if (mState != NULL) {
593 vorbis_dsp_clear(mState);
594 delete mState;
595 mState = NULL;
596 }
597
598 if (mVi != NULL) {
599 vorbis_info_clear(mVi);
600 delete mVi;
601 mVi = NULL;
602 }
603
604 mSawInputEos = false;
605 mSignalledOutputEos = false;
606 mSignalledError = false;
607 mNumFramesLeftOnPage = -1;
608 mOutputPortSettingsChange = NONE;
609 }
610
onPortEnableCompleted(OMX_U32 portIndex,bool enabled)611 void SoftVorbis::onPortEnableCompleted(OMX_U32 portIndex, bool enabled) {
612 if (portIndex != 1) {
613 return;
614 }
615
616 switch (mOutputPortSettingsChange) {
617 case NONE:
618 break;
619
620 case AWAITING_DISABLED:
621 {
622 CHECK(!enabled);
623 mOutputPortSettingsChange = AWAITING_ENABLED;
624 break;
625 }
626
627 default:
628 {
629 CHECK_EQ((int)mOutputPortSettingsChange, (int)AWAITING_ENABLED);
630 CHECK(enabled);
631 mOutputPortSettingsChange = NONE;
632 break;
633 }
634 }
635 }
636
637 } // namespace android
638
639 __attribute__((cfi_canonical_jump_table))
createSoftOMXComponent(const char * name,const OMX_CALLBACKTYPE * callbacks,OMX_PTR appData,OMX_COMPONENTTYPE ** component)640 android::SoftOMXComponent *createSoftOMXComponent(
641 const char *name, const OMX_CALLBACKTYPE *callbacks,
642 OMX_PTR appData, OMX_COMPONENTTYPE **component) {
643 return new android::SoftVorbis(name, callbacks, appData, component);
644 }
645