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