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