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
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      mSawInputEos(false),
58      mSignalledOutputEos(false),
59      mSignalledError(false),
60      mOutputPortSettingsChange(NONE) {
61    initPorts();
62    CHECK_EQ(initDecoder(), (status_t)OK);
63}
64
65SoftVorbis::~SoftVorbis() {
66    if (mState != NULL) {
67        vorbis_dsp_clear(mState);
68        delete mState;
69        mState = NULL;
70    }
71
72    if (mVi != NULL) {
73        vorbis_info_clear(mVi);
74        delete mVi;
75        mVi = NULL;
76    }
77}
78
79void SoftVorbis::initPorts() {
80    OMX_PARAM_PORTDEFINITIONTYPE def;
81    InitOMXParams(&def);
82
83    def.nPortIndex = 0;
84    def.eDir = OMX_DirInput;
85    def.nBufferCountMin = kNumBuffers;
86    def.nBufferCountActual = def.nBufferCountMin;
87    def.nBufferSize = kMaxNumSamplesPerBuffer * sizeof(int16_t);
88    def.bEnabled = OMX_TRUE;
89    def.bPopulated = OMX_FALSE;
90    def.eDomain = OMX_PortDomainAudio;
91    def.bBuffersContiguous = OMX_FALSE;
92    def.nBufferAlignment = 1;
93
94    def.format.audio.cMIMEType =
95        const_cast<char *>(MEDIA_MIMETYPE_AUDIO_VORBIS);
96
97    def.format.audio.pNativeRender = NULL;
98    def.format.audio.bFlagErrorConcealment = OMX_FALSE;
99    def.format.audio.eEncoding = OMX_AUDIO_CodingVORBIS;
100
101    addPort(def);
102
103    def.nPortIndex = 1;
104    def.eDir = OMX_DirOutput;
105    def.nBufferCountMin = kNumBuffers;
106    def.nBufferCountActual = def.nBufferCountMin;
107    def.nBufferSize = kMaxNumSamplesPerBuffer * sizeof(int16_t);
108    def.bEnabled = OMX_TRUE;
109    def.bPopulated = OMX_FALSE;
110    def.eDomain = OMX_PortDomainAudio;
111    def.bBuffersContiguous = OMX_FALSE;
112    def.nBufferAlignment = 2;
113
114    def.format.audio.cMIMEType = const_cast<char *>("audio/raw");
115    def.format.audio.pNativeRender = NULL;
116    def.format.audio.bFlagErrorConcealment = OMX_FALSE;
117    def.format.audio.eEncoding = OMX_AUDIO_CodingPCM;
118
119    addPort(def);
120}
121
122status_t SoftVorbis::initDecoder() {
123    return OK;
124}
125
126OMX_ERRORTYPE SoftVorbis::internalGetParameter(
127        OMX_INDEXTYPE index, OMX_PTR params) {
128    switch (index) {
129        case OMX_IndexParamAudioVorbis:
130        {
131            OMX_AUDIO_PARAM_VORBISTYPE *vorbisParams =
132                (OMX_AUDIO_PARAM_VORBISTYPE *)params;
133
134            if (!isValidOMXParam(vorbisParams)) {
135                return OMX_ErrorBadParameter;
136            }
137
138            if (vorbisParams->nPortIndex != 0) {
139                return OMX_ErrorUndefined;
140            }
141
142            vorbisParams->nBitRate = 0;
143            vorbisParams->nMinBitRate = 0;
144            vorbisParams->nMaxBitRate = 0;
145            vorbisParams->nAudioBandWidth = 0;
146            vorbisParams->nQuality = 3;
147            vorbisParams->bManaged = OMX_FALSE;
148            vorbisParams->bDownmix = OMX_FALSE;
149
150            if (!isConfigured()) {
151                vorbisParams->nChannels = 1;
152                vorbisParams->nSampleRate = 44100;
153            } else {
154                vorbisParams->nChannels = mVi->channels;
155                vorbisParams->nSampleRate = mVi->rate;
156                vorbisParams->nBitRate = mVi->bitrate_nominal;
157                vorbisParams->nMinBitRate = mVi->bitrate_lower;
158                vorbisParams->nMaxBitRate = mVi->bitrate_upper;
159            }
160
161            return OMX_ErrorNone;
162        }
163
164        case OMX_IndexParamAudioPcm:
165        {
166            OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams =
167                (OMX_AUDIO_PARAM_PCMMODETYPE *)params;
168
169            if (!isValidOMXParam(pcmParams)) {
170                return OMX_ErrorBadParameter;
171            }
172
173            if (pcmParams->nPortIndex != 1) {
174                return OMX_ErrorUndefined;
175            }
176
177            pcmParams->eNumData = OMX_NumericalDataSigned;
178            pcmParams->eEndian = OMX_EndianBig;
179            pcmParams->bInterleaved = OMX_TRUE;
180            pcmParams->nBitPerSample = 16;
181            pcmParams->ePCMMode = OMX_AUDIO_PCMModeLinear;
182            pcmParams->eChannelMapping[0] = OMX_AUDIO_ChannelLF;
183            pcmParams->eChannelMapping[1] = OMX_AUDIO_ChannelRF;
184
185            if (!isConfigured()) {
186                pcmParams->nChannels = 1;
187                pcmParams->nSamplingRate = 44100;
188            } else {
189                pcmParams->nChannels = mVi->channels;
190                pcmParams->nSamplingRate = mVi->rate;
191            }
192
193            return OMX_ErrorNone;
194        }
195
196        default:
197            return SimpleSoftOMXComponent::internalGetParameter(index, params);
198    }
199}
200
201OMX_ERRORTYPE SoftVorbis::internalSetParameter(
202        OMX_INDEXTYPE index, const OMX_PTR params) {
203    switch (index) {
204        case OMX_IndexParamStandardComponentRole:
205        {
206            const OMX_PARAM_COMPONENTROLETYPE *roleParams =
207                (const OMX_PARAM_COMPONENTROLETYPE *)params;
208
209            if (!isValidOMXParam(roleParams)) {
210                return OMX_ErrorBadParameter;
211            }
212
213            if (strncmp((const char *)roleParams->cRole,
214                        "audio_decoder.vorbis",
215                        OMX_MAX_STRINGNAME_SIZE - 1)) {
216                return OMX_ErrorUndefined;
217            }
218
219            return OMX_ErrorNone;
220        }
221
222        case OMX_IndexParamAudioVorbis:
223        {
224            const OMX_AUDIO_PARAM_VORBISTYPE *vorbisParams =
225                (const OMX_AUDIO_PARAM_VORBISTYPE *)params;
226
227            if (!isValidOMXParam(vorbisParams)) {
228                return OMX_ErrorBadParameter;
229            }
230
231            if (vorbisParams->nPortIndex != 0) {
232                return OMX_ErrorUndefined;
233            }
234
235            return OMX_ErrorNone;
236        }
237
238        default:
239            return SimpleSoftOMXComponent::internalSetParameter(index, params);
240    }
241}
242
243bool SoftVorbis::isConfigured() const {
244    return mInputBufferCount >= 2;
245}
246
247static void makeBitReader(
248        const void *data, size_t size,
249        ogg_buffer *buf, ogg_reference *ref, oggpack_buffer *bits) {
250    buf->data = (uint8_t *)data;
251    buf->size = size;
252    buf->refcount = 1;
253    buf->ptr.owner = NULL;
254
255    ref->buffer = buf;
256    ref->begin = 0;
257    ref->length = size;
258    ref->next = NULL;
259
260    oggpack_readinit(bits, ref);
261}
262
263void SoftVorbis::onQueueFilled(OMX_U32 portIndex) {
264    List<BufferInfo *> &inQueue = getPortQueue(0);
265    List<BufferInfo *> &outQueue = getPortQueue(1);
266
267    if (mSignalledError || mOutputPortSettingsChange != NONE) {
268        return;
269    }
270
271    if (portIndex == 0 && mInputBufferCount < 2) {
272        BufferInfo *info = *inQueue.begin();
273        OMX_BUFFERHEADERTYPE *header = info->mHeader;
274
275        const uint8_t *data = header->pBuffer + header->nOffset;
276        size_t size = header->nFilledLen;
277        if (size < 7) {
278            ALOGE("Too small input buffer: %zu bytes", size);
279            android_errorWriteLog(0x534e4554, "27833616");
280            notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
281            mSignalledError = true;
282            return;
283        }
284
285        ogg_buffer buf;
286        ogg_reference ref;
287        oggpack_buffer bits;
288
289        makeBitReader(
290                (const uint8_t *)data + 7, size - 7,
291                &buf, &ref, &bits);
292
293        if (mInputBufferCount == 0) {
294            CHECK(mVi == NULL);
295            mVi = new vorbis_info;
296            vorbis_info_init(mVi);
297
298            int ret = _vorbis_unpack_info(mVi, &bits);
299            if (ret != 0) {
300                notify(OMX_EventError, OMX_ErrorUndefined, ret, NULL);
301                mSignalledError = true;
302                return;
303            }
304        } else {
305            int ret = _vorbis_unpack_books(mVi, &bits);
306            if (ret != 0) {
307                notify(OMX_EventError, OMX_ErrorUndefined, ret, NULL);
308                mSignalledError = true;
309                return;
310            }
311
312            CHECK(mState == NULL);
313            mState = new vorbis_dsp_state;
314            CHECK_EQ(0, vorbis_dsp_init(mState, mVi));
315
316            notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
317            mOutputPortSettingsChange = AWAITING_DISABLED;
318        }
319
320        inQueue.erase(inQueue.begin());
321        info->mOwnedByUs = false;
322        notifyEmptyBufferDone(header);
323
324        ++mInputBufferCount;
325
326        return;
327    }
328
329    while ((!inQueue.empty() || (mSawInputEos && !mSignalledOutputEos)) && !outQueue.empty()) {
330        BufferInfo *inInfo = NULL;
331        OMX_BUFFERHEADERTYPE *inHeader = NULL;
332        if (!inQueue.empty()) {
333            inInfo = *inQueue.begin();
334            inHeader = inInfo->mHeader;
335        }
336
337        BufferInfo *outInfo = *outQueue.begin();
338        OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
339
340        int32_t numPageSamples = 0;
341
342        if (inHeader) {
343            if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
344                mSawInputEos = true;
345            }
346
347            if (inHeader->nFilledLen || !mSawInputEos) {
348                if (inHeader->nFilledLen < sizeof(numPageSamples)) {
349                    notify(OMX_EventError, OMX_ErrorBadParameter, 0, NULL);
350                    mSignalledError = true;
351                    ALOGE("onQueueFilled, input header has nFilledLen %u, expected %zu",
352                            inHeader->nFilledLen, sizeof(numPageSamples));
353                    return;
354                }
355                memcpy(&numPageSamples,
356                       inHeader->pBuffer
357                        + inHeader->nOffset + inHeader->nFilledLen - 4,
358                       sizeof(numPageSamples));
359
360                if (inHeader->nOffset == 0) {
361                    mAnchorTimeUs = inHeader->nTimeStamp;
362                    mNumFramesOutput = 0;
363                }
364
365                inHeader->nFilledLen -= sizeof(numPageSamples);;
366            }
367        }
368
369        if (numPageSamples >= 0) {
370            mNumFramesLeftOnPage = numPageSamples;
371        }
372
373        ogg_buffer buf;
374        buf.data = inHeader ? inHeader->pBuffer + inHeader->nOffset : NULL;
375        buf.size = inHeader ? inHeader->nFilledLen : 0;
376        buf.refcount = 1;
377        buf.ptr.owner = NULL;
378
379        ogg_reference ref;
380        ref.buffer = &buf;
381        ref.begin = 0;
382        ref.length = buf.size;
383        ref.next = NULL;
384
385        ogg_packet pack;
386        pack.packet = &ref;
387        pack.bytes = ref.length;
388        pack.b_o_s = 0;
389        pack.e_o_s = 0;
390        pack.granulepos = 0;
391        pack.packetno = 0;
392
393        int numFrames = 0;
394
395        outHeader->nFlags = 0;
396        int err = vorbis_dsp_synthesis(mState, &pack, 1);
397        if (err != 0) {
398            // FIXME temporary workaround for log spam
399#if !defined(__arm__) && !defined(__aarch64__)
400            ALOGV("vorbis_dsp_synthesis returned %d", err);
401#else
402            ALOGW("vorbis_dsp_synthesis returned %d", err);
403#endif
404        } else {
405            size_t numSamplesPerBuffer = kMaxNumSamplesPerBuffer;
406            if (numSamplesPerBuffer > outHeader->nAllocLen / sizeof(int16_t)) {
407                numSamplesPerBuffer = outHeader->nAllocLen / sizeof(int16_t);
408                android_errorWriteLog(0x534e4554, "27833616");
409            }
410            numFrames = vorbis_dsp_pcmout(
411                    mState, (int16_t *)outHeader->pBuffer,
412                    (numSamplesPerBuffer / mVi->channels));
413
414            if (numFrames < 0) {
415                ALOGE("vorbis_dsp_pcmout returned %d", numFrames);
416                numFrames = 0;
417            }
418        }
419
420        if (mNumFramesLeftOnPage >= 0) {
421            if (numFrames > mNumFramesLeftOnPage) {
422                ALOGV("discarding %d frames at end of page",
423                     numFrames - mNumFramesLeftOnPage);
424                numFrames = mNumFramesLeftOnPage;
425                if (mSawInputEos) {
426                    outHeader->nFlags = OMX_BUFFERFLAG_EOS;
427                    mSignalledOutputEos = true;
428                }
429            }
430            mNumFramesLeftOnPage -= numFrames;
431        }
432
433        outHeader->nFilledLen = numFrames * sizeof(int16_t) * mVi->channels;
434        outHeader->nOffset = 0;
435
436        outHeader->nTimeStamp =
437            mAnchorTimeUs
438                + (mNumFramesOutput * 1000000ll) / mVi->rate;
439
440        mNumFramesOutput += numFrames;
441
442        if (inHeader) {
443            inInfo->mOwnedByUs = false;
444            inQueue.erase(inQueue.begin());
445            inInfo = NULL;
446            notifyEmptyBufferDone(inHeader);
447            inHeader = NULL;
448        }
449
450        outInfo->mOwnedByUs = false;
451        outQueue.erase(outQueue.begin());
452        outInfo = NULL;
453        notifyFillBufferDone(outHeader);
454        outHeader = NULL;
455
456        ++mInputBufferCount;
457    }
458}
459
460void SoftVorbis::onPortFlushCompleted(OMX_U32 portIndex) {
461    if (portIndex == 0 && mState != NULL) {
462        // Make sure that the next buffer output does not still
463        // depend on fragments from the last one decoded.
464
465        mNumFramesOutput = 0;
466        mSawInputEos = false;
467        mSignalledOutputEos = false;
468        mNumFramesLeftOnPage = -1;
469        vorbis_dsp_restart(mState);
470    }
471}
472
473void SoftVorbis::onReset() {
474    mInputBufferCount = 0;
475    mNumFramesOutput = 0;
476    if (mState != NULL) {
477        vorbis_dsp_clear(mState);
478        delete mState;
479        mState = NULL;
480    }
481
482    if (mVi != NULL) {
483        vorbis_info_clear(mVi);
484        delete mVi;
485        mVi = NULL;
486    }
487
488    mSawInputEos = false;
489    mSignalledOutputEos = false;
490    mSignalledError = false;
491    mOutputPortSettingsChange = NONE;
492}
493
494void SoftVorbis::onPortEnableCompleted(OMX_U32 portIndex, bool enabled) {
495    if (portIndex != 1) {
496        return;
497    }
498
499    switch (mOutputPortSettingsChange) {
500        case NONE:
501            break;
502
503        case AWAITING_DISABLED:
504        {
505            CHECK(!enabled);
506            mOutputPortSettingsChange = AWAITING_ENABLED;
507            break;
508        }
509
510        default:
511        {
512            CHECK_EQ((int)mOutputPortSettingsChange, (int)AWAITING_ENABLED);
513            CHECK(enabled);
514            mOutputPortSettingsChange = NONE;
515            break;
516        }
517    }
518}
519
520}  // namespace android
521
522android::SoftOMXComponent *createSoftOMXComponent(
523        const char *name, const OMX_CALLBACKTYPE *callbacks,
524        OMX_PTR appData, OMX_COMPONENTTYPE **component) {
525    return new android::SoftVorbis(name, callbacks, appData, component);
526}
527