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