xref: /aosp_15_r20/frameworks/av/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp (revision ec779b8e0859a360c3d303172224686826e6e0e1)
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