1 /*
2 * Copyright (C) 2017 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 "SoftFlacDecoder"
19 #include <utils/Log.h>
20
21 #include "SoftFlacDecoder.h"
22 #include <OMX_AudioExt.h>
23 #include <OMX_IndexExt.h>
24
25 #include <cutils/properties.h>
26 #include <media/stagefright/foundation/ADebug.h>
27 #include <media/stagefright/MediaErrors.h>
28 #include <utils/misc.h>
29
30 namespace android {
31
32 template<class T>
InitOMXParams(T * params)33 static void InitOMXParams(T *params) {
34 params->nSize = sizeof(T);
35 params->nVersion.s.nVersionMajor = 1;
36 params->nVersion.s.nVersionMinor = 0;
37 params->nVersion.s.nRevision = 0;
38 params->nVersion.s.nStep = 0;
39 }
40
SoftFlacDecoder(const char * name,const OMX_CALLBACKTYPE * callbacks,OMX_PTR appData,OMX_COMPONENTTYPE ** component)41 SoftFlacDecoder::SoftFlacDecoder(
42 const char *name,
43 const OMX_CALLBACKTYPE *callbacks,
44 OMX_PTR appData,
45 OMX_COMPONENTTYPE **component)
46 : SimpleSoftOMXComponent(name, callbacks, appData, component),
47 mFLACDecoder(NULL),
48 mInputBufferCount(0),
49 mHasStreamInfo(false),
50 mSignalledError(false),
51 mSawInputEOS(false),
52 mFinishedDecoder(false),
53 mOutputPortSettingsChange(NONE) {
54 ALOGV("ctor:");
55 memset(&mStreamInfo, 0, sizeof(mStreamInfo));
56 initPorts();
57 initDecoder();
58 }
59
~SoftFlacDecoder()60 SoftFlacDecoder::~SoftFlacDecoder() {
61 ALOGV("dtor:");
62 delete mFLACDecoder;
63 }
64
initPorts()65 void SoftFlacDecoder::initPorts() {
66 ALOGV("initPorts:");
67 OMX_PARAM_PORTDEFINITIONTYPE def;
68 InitOMXParams(&def);
69
70 def.nPortIndex = 0;
71 def.eDir = OMX_DirInput;
72 def.nBufferCountMin = kNumInputBuffers;
73 def.nBufferCountActual = def.nBufferCountMin;
74 def.nBufferSize = 32768;
75 def.bEnabled = OMX_TRUE;
76 def.bPopulated = OMX_FALSE;
77 def.eDomain = OMX_PortDomainAudio;
78 def.bBuffersContiguous = OMX_FALSE;
79 def.nBufferAlignment = 1;
80
81 def.format.audio.cMIMEType = const_cast<char *>("audio/flac");
82 def.format.audio.pNativeRender = NULL;
83 def.format.audio.bFlagErrorConcealment = OMX_FALSE;
84 def.format.audio.eEncoding = OMX_AUDIO_CodingFLAC;
85
86 addPort(def);
87
88 def.nPortIndex = 1;
89 def.eDir = OMX_DirOutput;
90 def.nBufferCountMin = kNumOutputBuffers;
91 def.nBufferCountActual = def.nBufferCountMin;
92 def.nBufferSize = kNumSamplesPerFrame * FLACDecoder::kMaxChannels * sizeof(float);
93 def.bEnabled = OMX_TRUE;
94 def.bPopulated = OMX_FALSE;
95 def.eDomain = OMX_PortDomainAudio;
96 def.bBuffersContiguous = OMX_FALSE;
97 def.nBufferAlignment = sizeof(float);
98
99 def.format.audio.cMIMEType = const_cast<char *>("audio/raw");
100 def.format.audio.pNativeRender = NULL;
101 def.format.audio.bFlagErrorConcealment = OMX_FALSE;
102 def.format.audio.eEncoding = OMX_AUDIO_CodingPCM;
103
104 addPort(def);
105 }
106
initDecoder()107 void SoftFlacDecoder::initDecoder() {
108 ALOGV("initDecoder:");
109 mFLACDecoder = FLACDecoder::Create();
110 if (mFLACDecoder == NULL) {
111 ALOGE("initDecoder: failed to create FLACDecoder");
112 mSignalledError = true;
113 }
114 }
115
initCheck() const116 OMX_ERRORTYPE SoftFlacDecoder::initCheck() const {
117 if (mSignalledError) {
118 if (mFLACDecoder == NULL) {
119 ALOGE("initCheck: failed due to NULL encoder");
120 return OMX_ErrorDynamicResourcesUnavailable;
121 }
122 return OMX_ErrorUndefined;
123 }
124
125 return SimpleSoftOMXComponent::initCheck();
126 }
127
internalGetParameter(OMX_INDEXTYPE index,OMX_PTR params)128 OMX_ERRORTYPE SoftFlacDecoder::internalGetParameter(
129 OMX_INDEXTYPE index, OMX_PTR params) {
130 ALOGV("internalGetParameter: index(%x)", index);
131 switch ((OMX_U32)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_CodingFLAC : OMX_AUDIO_CodingPCM;
152
153 return OMX_ErrorNone;
154 }
155 case OMX_IndexParamAudioFlac:
156 {
157 OMX_AUDIO_PARAM_FLACTYPE *flacParams =
158 (OMX_AUDIO_PARAM_FLACTYPE *)params;
159
160 if (!isValidOMXParam(flacParams)) {
161 ALOGE("internalGetParameter(OMX_IndexParamAudioFlac): invalid omx params");
162 return OMX_ErrorBadParameter;
163 }
164
165 if (flacParams->nPortIndex != 0) {
166 ALOGE("internalGetParameter(OMX_IndexParamAudioFlac): bad port index");
167 return OMX_ErrorBadPortIndex;
168 }
169
170 flacParams->nCompressionLevel = 0;
171
172 if (isConfigured()) {
173 flacParams->nChannels = mStreamInfo.channels;
174 flacParams->nSampleRate = mStreamInfo.sample_rate;
175 } else {
176 flacParams->nChannels = 2;
177 flacParams->nSampleRate = 44100;
178 }
179
180 return OMX_ErrorNone;
181 }
182
183 case OMX_IndexParamAudioPcm:
184 {
185 OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams =
186 (OMX_AUDIO_PARAM_PCMMODETYPE *)params;
187
188 if (!isValidOMXParam(pcmParams)) {
189 ALOGE("internalGetParameter(OMX_IndexParamAudioPcm): invalid omx params");
190 return OMX_ErrorBadParameter;
191 }
192
193 if (pcmParams->nPortIndex != 1) {
194 ALOGE("internalGetParameter(OMX_IndexParamAudioPcm): bad port index");
195 return OMX_ErrorBadPortIndex;
196 }
197
198 pcmParams->eNumData = mNumericalData;
199 pcmParams->eEndian = OMX_EndianBig;
200 pcmParams->bInterleaved = OMX_TRUE;
201 pcmParams->nBitPerSample = mBitsPerSample;
202 pcmParams->ePCMMode = OMX_AUDIO_PCMModeLinear;
203 pcmParams->eChannelMapping[0] = OMX_AUDIO_ChannelLF;
204 pcmParams->eChannelMapping[1] = OMX_AUDIO_ChannelRF;
205 pcmParams->eChannelMapping[2] = OMX_AUDIO_ChannelCF;
206 pcmParams->eChannelMapping[3] = OMX_AUDIO_ChannelLFE;
207 pcmParams->eChannelMapping[4] = OMX_AUDIO_ChannelLS;
208 pcmParams->eChannelMapping[5] = OMX_AUDIO_ChannelRS;
209
210 if (isConfigured()) {
211 pcmParams->nChannels = mStreamInfo.channels;
212 pcmParams->nSamplingRate = mStreamInfo.sample_rate;
213 } else {
214 pcmParams->nChannels = 2;
215 pcmParams->nSamplingRate = 44100;
216 }
217
218 return OMX_ErrorNone;
219 }
220
221 default:
222 return SimpleSoftOMXComponent::internalGetParameter(index, params);
223 }
224 }
225
internalSetParameter(OMX_INDEXTYPE index,const OMX_PTR params)226 OMX_ERRORTYPE SoftFlacDecoder::internalSetParameter(
227 OMX_INDEXTYPE index, const OMX_PTR params) {
228 ALOGV("internalSetParameter: index(%x)", (int)index);
229 switch ((int)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.flac",
241 OMX_MAX_STRINGNAME_SIZE - 1) != 0) {
242 return OMX_ErrorInvalidComponentName;
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_CodingFLAC)
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_IndexParamAudioPcm:
272 {
273 const OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams =
274 (OMX_AUDIO_PARAM_PCMMODETYPE *)params;
275
276 if (!isValidOMXParam(pcmParams)) {
277 return OMX_ErrorBadParameter;
278 }
279
280 if (pcmParams->nPortIndex != 1) {
281 return OMX_ErrorBadPortIndex;
282 }
283
284 if (pcmParams->eNumData == OMX_NumericalDataFloat && pcmParams->nBitPerSample == 32) {
285 mNumericalData = OMX_NumericalDataFloat;
286 mBitsPerSample = 32;
287 } else if (pcmParams->eNumData == OMX_NumericalDataSigned
288 && pcmParams->nBitPerSample == 16) {
289 mNumericalData = OMX_NumericalDataSigned;
290 mBitsPerSample = 16;
291 } else {
292 ALOGE("Invalid eNumData %d, nBitsPerSample %d",
293 pcmParams->eNumData, pcmParams->nBitPerSample);
294 return OMX_ErrorUndefined;
295 }
296
297 return OMX_ErrorNone;
298 }
299
300 default:
301 return SimpleSoftOMXComponent::internalSetParameter(index, params);
302 }
303 }
304
isConfigured() const305 bool SoftFlacDecoder::isConfigured() const {
306 return mHasStreamInfo;
307 }
308
onQueueFilled(OMX_U32)309 void SoftFlacDecoder::onQueueFilled(OMX_U32 /* portIndex */) {
310 if (mSignalledError || mOutputPortSettingsChange != NONE) {
311 return;
312 }
313
314 List<BufferInfo *> &inQueue = getPortQueue(0);
315 List<BufferInfo *> &outQueue = getPortQueue(1);
316
317 const bool outputFloat = mNumericalData == OMX_NumericalDataFloat;
318
319 ALOGV("onQueueFilled %d/%d:", inQueue.empty(), outQueue.empty());
320 while ((!inQueue.empty() || mSawInputEOS) && !outQueue.empty() && !mFinishedDecoder) {
321 BufferInfo *outInfo = *outQueue.begin();
322 OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
323 void *outBuffer = reinterpret_cast<void *>(outHeader->pBuffer + outHeader->nOffset);
324 size_t outBufferSize = outHeader->nAllocLen - outHeader->nOffset;
325 int64_t timeStamp = 0;
326
327 if (!inQueue.empty()) {
328 BufferInfo *inInfo = *inQueue.begin();
329 OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
330 uint8_t* inBuffer = inHeader->pBuffer + inHeader->nOffset;
331 uint32_t inBufferLength = inHeader->nFilledLen;
332 ALOGV("input: %u bytes", inBufferLength);
333 if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
334 ALOGV("saw EOS");
335 mSawInputEOS = true;
336 if (mInputBufferCount == 0 && inHeader->nFilledLen == 0) {
337 // first buffer was empty and EOS: signal EOS on output and return
338 ALOGV("empty first EOS");
339 outHeader->nFilledLen = 0;
340 outHeader->nTimeStamp = inHeader->nTimeStamp;
341 outHeader->nFlags = OMX_BUFFERFLAG_EOS;
342 outInfo->mOwnedByUs = false;
343 outQueue.erase(outQueue.begin());
344 notifyFillBufferDone(outHeader);
345 mFinishedDecoder = true;
346 inInfo->mOwnedByUs = false;
347 inQueue.erase(inQueue.begin());
348 notifyEmptyBufferDone(inHeader);
349 return;
350 }
351 }
352
353 if (mInputBufferCount == 0 && !(inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG)) {
354 ALOGE("onQueueFilled: first buffer should have OMX_BUFFERFLAG_CODECCONFIG set");
355 inHeader->nFlags |= OMX_BUFFERFLAG_CODECCONFIG;
356 }
357 if ((inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG) != 0) {
358 ALOGV("received config buffer of size %u", inBufferLength);
359 status_t decoderErr = mFLACDecoder->parseMetadata(inBuffer, inBufferLength);
360 mInputBufferCount++;
361
362 if (decoderErr != OK && decoderErr != WOULD_BLOCK) {
363 ALOGE("onQueueFilled: FLACDecoder parseMetaData returns error %d", decoderErr);
364 mSignalledError = true;
365 notify(OMX_EventError, OMX_ErrorStreamCorrupt, decoderErr, NULL);
366 return;
367 }
368
369 inInfo->mOwnedByUs = false;
370 inQueue.erase(inQueue.begin());
371 notifyEmptyBufferDone(inHeader);
372
373 if (decoderErr == WOULD_BLOCK) {
374 continue;
375 }
376 mStreamInfo = mFLACDecoder->getStreamInfo();
377 mHasStreamInfo = true;
378
379 // Only send out port settings changed event if both sample rate
380 // and numChannels are valid.
381 if (mStreamInfo.sample_rate && mStreamInfo.channels) {
382 ALOGD("onQueueFilled: initially configuring decoder: %d Hz, %d channels",
383 mStreamInfo.sample_rate, mStreamInfo.channels);
384
385 notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
386 mOutputPortSettingsChange = AWAITING_DISABLED;
387 }
388 return;
389 }
390
391 status_t decoderErr = mFLACDecoder->decodeOneFrame(
392 inBuffer, inBufferLength, outBuffer, &outBufferSize, outputFloat);
393 if (decoderErr != OK) {
394 ALOGE("onQueueFilled: FLACDecoder decodeOneFrame returns error %d", decoderErr);
395 mSignalledError = true;
396 notify(OMX_EventError, OMX_ErrorStreamCorrupt, decoderErr, NULL);
397 return;
398 }
399
400 mInputBufferCount++;
401 timeStamp = inHeader->nTimeStamp;
402 inInfo->mOwnedByUs = false;
403 inQueue.erase(inQueue.begin());
404 notifyEmptyBufferDone(inHeader);
405
406 if (outBufferSize == 0) {
407 ALOGV("no output, trying again");
408 continue;
409 }
410 } else if (mSawInputEOS) {
411 status_t decoderErr = mFLACDecoder->decodeOneFrame(
412 nullptr /* inBuffer */, 0 /* inBufferLen */,
413 outBuffer, &outBufferSize, outputFloat);
414 mFinishedDecoder = true;
415 if (decoderErr != OK) {
416 ALOGE("onQueueFilled: FLACDecoder finish returns error %d", decoderErr);
417 mSignalledError = true;
418 notify(OMX_EventError, OMX_ErrorStreamCorrupt, decoderErr, NULL);
419 return;
420 }
421 outHeader->nFlags = OMX_BUFFERFLAG_EOS;
422 } else {
423 // no more input buffers at this time, loop and see if there is more output
424 continue;
425 }
426
427 outHeader->nFilledLen = outBufferSize;
428 outHeader->nTimeStamp = timeStamp;
429
430 outInfo->mOwnedByUs = false;
431 outQueue.erase(outQueue.begin());
432 notifyFillBufferDone(outHeader);
433 }
434 }
435
onPortFlushCompleted(OMX_U32 portIndex)436 void SoftFlacDecoder::onPortFlushCompleted(OMX_U32 portIndex) {
437 ALOGV("onPortFlushCompleted: portIndex(%u)", portIndex);
438 if (portIndex == 0) {
439 drainDecoder();
440 }
441 }
442
drainDecoder()443 void SoftFlacDecoder::drainDecoder() {
444 mFLACDecoder->flush();
445 mSawInputEOS = false;
446 mFinishedDecoder = false;
447 }
448
onReset()449 void SoftFlacDecoder::onReset() {
450 ALOGV("onReset");
451 drainDecoder();
452
453 memset(&mStreamInfo, 0, sizeof(mStreamInfo));
454 mHasStreamInfo = false;
455 mInputBufferCount = 0;
456 mSignalledError = false;
457 mOutputPortSettingsChange = NONE;
458 }
459
onPortEnableCompleted(OMX_U32 portIndex,bool enabled)460 void SoftFlacDecoder::onPortEnableCompleted(OMX_U32 portIndex, bool enabled) {
461 ALOGV("onPortEnableCompleted: portIndex(%u), enabled(%d)", portIndex, enabled);
462 if (portIndex != 1) {
463 return;
464 }
465
466 switch (mOutputPortSettingsChange) {
467 case NONE:
468 break;
469
470 case AWAITING_DISABLED:
471 {
472 CHECK(!enabled);
473 mOutputPortSettingsChange = AWAITING_ENABLED;
474 PortInfo *info = editPortInfo(1 /* portIndex */);
475 if (!info->mDef.bEnabled) {
476 info->mDef.nBufferSize =
477 mStreamInfo.max_blocksize * mStreamInfo.channels * sizeof(float);
478 }
479 break;
480 }
481
482 default:
483 {
484 CHECK_EQ((int)mOutputPortSettingsChange, (int)AWAITING_ENABLED);
485 CHECK(enabled);
486 mOutputPortSettingsChange = NONE;
487 break;
488 }
489 }
490 }
491
492 } // namespace android
493
494 __attribute__((cfi_canonical_jump_table))
createSoftOMXComponent(const char * name,const OMX_CALLBACKTYPE * callbacks,OMX_PTR appData,OMX_COMPONENTTYPE ** component)495 android::SoftOMXComponent *createSoftOMXComponent(
496 const char *name, const OMX_CALLBACKTYPE *callbacks,
497 OMX_PTR appData, OMX_COMPONENTTYPE **component) {
498 ALOGV("createSoftOMXComponent: flac decoder");
499 return new android::SoftFlacDecoder(name, callbacks, appData, component);
500 }
501