1 /*
2 * Copyright (C) 2012 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 "SoftFlacEncoder"
19 #include <android-base/macros.h>
20 #include <utils/Log.h>
21
22 #include "SoftFlacEncoder.h"
23 #include <audio_utils/primitives.h>
24 #include <media/stagefright/foundation/ADebug.h>
25 #include <media/stagefright/MediaDefs.h>
26
27 #define FLAC_COMPRESSION_LEVEL_MIN 0
28 #define FLAC_COMPRESSION_LEVEL_DEFAULT 5
29 #define FLAC_COMPRESSION_LEVEL_MAX 8
30
31 #if LOG_NDEBUG
32 #define UNUSED_UNLESS_VERBOSE(x) (void)(x)
33 #else
34 #define UNUSED_UNLESS_VERBOSE(x)
35 #endif
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
SoftFlacEncoder(const char * name,const OMX_CALLBACKTYPE * callbacks,OMX_PTR appData,OMX_COMPONENTTYPE ** component)48 SoftFlacEncoder::SoftFlacEncoder(
49 const char *name,
50 const OMX_CALLBACKTYPE *callbacks,
51 OMX_PTR appData,
52 OMX_COMPONENTTYPE **component)
53 : SimpleSoftOMXComponent(name, callbacks, appData, component),
54 mSignalledError(false),
55 mNumChannels(1),
56 mSampleRate(44100),
57 mCompressionLevel(FLAC_COMPRESSION_LEVEL_DEFAULT),
58 mEncoderWriteData(false),
59 mEncoderReturnedEncodedData(false),
60 mSawInputEOS(false),
61 mSentOutputEOS(false),
62 mEncoderReturnedNbBytes(0),
63 mInputBufferPcm32(NULL),
64 mHeaderOffset(0),
65 mHeaderComplete(false),
66 mWroteHeader(false)
67 {
68 ALOGV("SoftFlacEncoder::SoftFlacEncoder(name=%s)", name);
69 initPorts();
70
71 mFlacStreamEncoder = FLAC__stream_encoder_new();
72 if (mFlacStreamEncoder == NULL) {
73 ALOGE("SoftFlacEncoder::SoftFlacEncoder(name=%s) error instantiating FLAC encoder", name);
74 mSignalledError = true;
75 }
76
77 if (!mSignalledError) { // no use allocating input buffer if we had an error above
78 // 2x the pcm16 samples can exist with the same size as pcmFloat samples.
79 mInputBufferPcm32 = (FLAC__int32*) malloc(
80 sizeof(FLAC__int32) * kNumSamplesPerFrame * kMaxChannels * 2);
81 if (mInputBufferPcm32 == NULL) {
82 ALOGE("SoftFlacEncoder::SoftFlacEncoder(name=%s) error allocating internal input buffer", name);
83 mSignalledError = true;
84 }
85 }
86 }
87
~SoftFlacEncoder()88 SoftFlacEncoder::~SoftFlacEncoder() {
89 ALOGV("SoftFlacEncoder::~SoftFlacEncoder()");
90 if (mFlacStreamEncoder != NULL) {
91 FLAC__stream_encoder_delete(mFlacStreamEncoder);
92 mFlacStreamEncoder = NULL;
93 }
94 free(mInputBufferPcm32);
95 mInputBufferPcm32 = NULL;
96 }
97
initCheck() const98 OMX_ERRORTYPE SoftFlacEncoder::initCheck() const {
99 if (mSignalledError) {
100 if (mFlacStreamEncoder == NULL) {
101 ALOGE("initCheck() failed due to NULL encoder");
102 } else if (mInputBufferPcm32 == NULL) {
103 ALOGE("initCheck() failed due to error allocating internal input buffer");
104 }
105 return OMX_ErrorUndefined;
106 } else {
107 return SimpleSoftOMXComponent::initCheck();
108 }
109 }
110
initPorts()111 void SoftFlacEncoder::initPorts() {
112 ALOGV("SoftFlacEncoder::initPorts()");
113
114 OMX_PARAM_PORTDEFINITIONTYPE def;
115 InitOMXParams(&def);
116
117 // configure input port of the encoder
118 def.nPortIndex = 0;
119 def.eDir = OMX_DirInput;
120 def.nBufferCountMin = kNumBuffers;
121 def.nBufferCountActual = def.nBufferCountMin;
122 def.nBufferSize = kMaxInputBufferSize;
123 def.bEnabled = OMX_TRUE;
124 def.bPopulated = OMX_FALSE;
125 def.eDomain = OMX_PortDomainAudio;
126 def.bBuffersContiguous = OMX_FALSE;
127 def.nBufferAlignment = sizeof(float);
128
129 def.format.audio.cMIMEType = const_cast<char *>("audio/raw");
130 def.format.audio.pNativeRender = NULL;
131 def.format.audio.bFlagErrorConcealment = OMX_FALSE;
132 def.format.audio.eEncoding = OMX_AUDIO_CodingPCM;
133
134 addPort(def);
135
136 // configure output port of the encoder
137 def.nPortIndex = 1;
138 def.eDir = OMX_DirOutput;
139 def.nBufferCountMin = kNumBuffers;
140 def.nBufferCountActual = def.nBufferCountMin;
141 def.nBufferSize = kMaxOutputBufferSize;
142 def.bEnabled = OMX_TRUE;
143 def.bPopulated = OMX_FALSE;
144 def.eDomain = OMX_PortDomainAudio;
145 def.bBuffersContiguous = OMX_FALSE;
146 def.nBufferAlignment = 1;
147
148 def.format.audio.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_AUDIO_FLAC);
149 def.format.audio.pNativeRender = NULL;
150 def.format.audio.bFlagErrorConcealment = OMX_FALSE;
151 def.format.audio.eEncoding = OMX_AUDIO_CodingFLAC;
152
153 addPort(def);
154 }
155
internalGetParameter(OMX_INDEXTYPE index,OMX_PTR params)156 OMX_ERRORTYPE SoftFlacEncoder::internalGetParameter(
157 OMX_INDEXTYPE index, OMX_PTR params) {
158 ALOGV("SoftFlacEncoder::internalGetParameter(index=0x%x)", index);
159
160 switch (index) {
161 case OMX_IndexParamAudioPortFormat:
162 {
163 OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams =
164 (OMX_AUDIO_PARAM_PORTFORMATTYPE *)params;
165
166 if (!isValidOMXParam(formatParams)) {
167 return OMX_ErrorBadParameter;
168 }
169
170 if (formatParams->nPortIndex > 1) {
171 return OMX_ErrorUndefined;
172 }
173
174 if (formatParams->nIndex > 0) {
175 return OMX_ErrorNoMore;
176 }
177
178 formatParams->eEncoding =
179 (formatParams->nPortIndex == 0)
180 ? OMX_AUDIO_CodingPCM : OMX_AUDIO_CodingFLAC;
181
182 return OMX_ErrorNone;
183 }
184
185 case OMX_IndexParamAudioPcm:
186 {
187 OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams =
188 (OMX_AUDIO_PARAM_PCMMODETYPE *)params;
189
190 if (!isValidOMXParam(pcmParams)) {
191 return OMX_ErrorBadParameter;
192 }
193
194 if (pcmParams->nPortIndex != 0) {
195 return OMX_ErrorUndefined;
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
206 pcmParams->nChannels = mNumChannels;
207 pcmParams->nSamplingRate = mSampleRate;
208
209 return OMX_ErrorNone;
210 }
211
212 case OMX_IndexParamAudioFlac:
213 {
214 OMX_AUDIO_PARAM_FLACTYPE *flacParams = (OMX_AUDIO_PARAM_FLACTYPE *)params;
215
216 if (!isValidOMXParam(flacParams)) {
217 return OMX_ErrorBadParameter;
218 }
219
220 if (flacParams->nPortIndex != 1) {
221 return OMX_ErrorUndefined;
222 }
223
224 flacParams->nCompressionLevel = mCompressionLevel;
225 flacParams->nChannels = mNumChannels;
226 flacParams->nSampleRate = mSampleRate;
227 return OMX_ErrorNone;
228 }
229
230 default:
231 return SimpleSoftOMXComponent::internalGetParameter(index, params);
232 }
233 }
234
internalSetParameter(OMX_INDEXTYPE index,const OMX_PTR params)235 OMX_ERRORTYPE SoftFlacEncoder::internalSetParameter(
236 OMX_INDEXTYPE index, const OMX_PTR params) {
237 switch (index) {
238 case OMX_IndexParamAudioPortFormat:
239 {
240 const OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams =
241 (const OMX_AUDIO_PARAM_PORTFORMATTYPE *)params;
242
243 if (!isValidOMXParam(formatParams)) {
244 return OMX_ErrorBadParameter;
245 }
246
247 if (formatParams->nPortIndex > 1) {
248 return OMX_ErrorUndefined;
249 }
250
251 if ((formatParams->nPortIndex == 0
252 && formatParams->eEncoding != OMX_AUDIO_CodingPCM)
253 || (formatParams->nPortIndex == 1
254 && formatParams->eEncoding != OMX_AUDIO_CodingFLAC)) {
255 return OMX_ErrorUndefined;
256 }
257
258 return OMX_ErrorNone;
259 }
260
261 case OMX_IndexParamAudioPcm:
262 {
263 ALOGV("SoftFlacEncoder::internalSetParameter(OMX_IndexParamAudioPcm)");
264 OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams = (OMX_AUDIO_PARAM_PCMMODETYPE *)params;
265
266 if (!isValidOMXParam(pcmParams)) {
267 return OMX_ErrorBadParameter;
268 }
269
270 if (pcmParams->nPortIndex != 0) {
271 ALOGE("SoftFlacEncoder::internalSetParameter() Error #1");
272 return OMX_ErrorUndefined;
273 }
274
275 if (pcmParams->nChannels < 1 || pcmParams->nChannels > kMaxChannels) {
276 return OMX_ErrorUndefined;
277 }
278
279 mNumChannels = pcmParams->nChannels;
280 mSampleRate = pcmParams->nSamplingRate;
281
282 if (pcmParams->eNumData == OMX_NumericalDataFloat && pcmParams->nBitPerSample == 32) {
283 mNumericalData = OMX_NumericalDataFloat;
284 mBitsPerSample = 32;
285 } else if (pcmParams->eNumData == OMX_NumericalDataSigned
286 && pcmParams->nBitPerSample == 16) {
287 mNumericalData = OMX_NumericalDataSigned;
288 mBitsPerSample = 16;
289 } else {
290 ALOGE("%s: invalid eNumData %d, nBitsPerSample %d",
291 __func__, pcmParams->eNumData, pcmParams->nBitPerSample);
292 return OMX_ErrorUndefined;
293 }
294
295 ALOGV("will encode %d channels at %dHz", mNumChannels, mSampleRate);
296
297 return configureEncoder();
298 }
299
300 case OMX_IndexParamStandardComponentRole:
301 {
302 ALOGV("SoftFlacEncoder::internalSetParameter(OMX_IndexParamStandardComponentRole)");
303 const OMX_PARAM_COMPONENTROLETYPE *roleParams =
304 (const OMX_PARAM_COMPONENTROLETYPE *)params;
305
306 if (!isValidOMXParam(roleParams)) {
307 return OMX_ErrorBadParameter;
308 }
309
310 if (strncmp((const char *)roleParams->cRole,
311 "audio_encoder.flac",
312 OMX_MAX_STRINGNAME_SIZE - 1)) {
313 ALOGE("SoftFlacEncoder::internalSetParameter(OMX_IndexParamStandardComponentRole)"
314 "error");
315 return OMX_ErrorUndefined;
316 }
317
318 return OMX_ErrorNone;
319 }
320
321 case OMX_IndexParamAudioFlac:
322 {
323 // used only for setting the compression level
324 OMX_AUDIO_PARAM_FLACTYPE *flacParams = (OMX_AUDIO_PARAM_FLACTYPE *)params;
325
326 if (!isValidOMXParam(flacParams)) {
327 return OMX_ErrorBadParameter;
328 }
329
330 if (flacParams->nPortIndex != 1) {
331 return OMX_ErrorUndefined;
332 }
333
334 mCompressionLevel = flacParams->nCompressionLevel; // range clamping done inside encoder
335 return OMX_ErrorNone;
336 }
337
338 case OMX_IndexParamPortDefinition:
339 {
340 OMX_PARAM_PORTDEFINITIONTYPE *defParams =
341 (OMX_PARAM_PORTDEFINITIONTYPE *)params;
342
343 if (!isValidOMXParam(defParams)) {
344 return OMX_ErrorBadParameter;
345 }
346
347 if (defParams->nPortIndex == 0) {
348 if (defParams->nBufferSize > kMaxInputBufferSize) {
349 ALOGE("Input buffer size must be at most %d bytes",
350 kMaxInputBufferSize);
351 return OMX_ErrorUnsupportedSetting;
352 }
353 }
354
355 FALLTHROUGH_INTENDED;
356 }
357
358 default:
359 ALOGV("SoftFlacEncoder::internalSetParameter(default)");
360 return SimpleSoftOMXComponent::internalSetParameter(index, params);
361 }
362 }
363
onQueueFilled(OMX_U32 portIndex)364 void SoftFlacEncoder::onQueueFilled(OMX_U32 portIndex) {
365 UNUSED_UNLESS_VERBOSE(portIndex);
366 ALOGV("SoftFlacEncoder::onQueueFilled(portIndex=%d)", portIndex);
367
368 if (mSignalledError) {
369 return;
370 }
371
372 List<BufferInfo *> &inQueue = getPortQueue(0);
373 List<BufferInfo *> &outQueue = getPortQueue(1);
374
375 const bool inputFloat = mNumericalData == OMX_NumericalDataFloat;
376 const size_t sampleSize = inputFloat ? sizeof(float) : sizeof(int16_t);
377 const size_t frameSize = sampleSize * mNumChannels;
378
379 FLAC__bool ok = true;
380
381 while ((!inQueue.empty() || mSawInputEOS) && !outQueue.empty() && !mSentOutputEOS) {
382 if (!inQueue.empty()) {
383 BufferInfo *inInfo = *inQueue.begin();
384 OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
385
386 if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
387 ALOGV("saw EOS on buffer of size %u", inHeader->nFilledLen);
388 mSawInputEOS = true;
389 }
390
391 if (inHeader->nFilledLen > kMaxInputBufferSize) {
392 ALOGE("input buffer too large (%d).", inHeader->nFilledLen);
393 mSignalledError = true;
394 notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
395 return;
396 }
397
398 assert(mNumChannels != 0);
399 mEncoderWriteData = true;
400 mEncoderReturnedEncodedData = false;
401 mEncoderReturnedNbBytes = 0;
402 if (inHeader->nFilledLen) {
403 mCurrentInputTimeStamp = inHeader->nTimeStamp;
404
405 const unsigned nbInputFrames = inHeader->nFilledLen / frameSize;
406 const unsigned nbInputSamples = inHeader->nFilledLen / sampleSize;
407
408 if (inputFloat) {
409 CHECK_LE(nbInputSamples, kNumSamplesPerFrame * kMaxChannels);
410 const float * const pcmFloat = reinterpret_cast<float *>(inHeader->pBuffer);
411 memcpy_to_q8_23_from_float_with_clamp(
412 mInputBufferPcm32, pcmFloat, nbInputSamples);
413 } else {
414 // note nbInputSamples may be 2x as large for pcm16 data.
415 CHECK_LE(nbInputSamples, kNumSamplesPerFrame * kMaxChannels * 2);
416 const int16_t * const pcm16 = reinterpret_cast<int16_t *>(inHeader->pBuffer);
417 for (unsigned i = 0; i < nbInputSamples; ++i) {
418 mInputBufferPcm32[i] = (FLAC__int32) pcm16[i];
419 }
420 }
421 ALOGV(" about to encode %u samples per channel", nbInputFrames);
422 ok = FLAC__stream_encoder_process_interleaved(
423 mFlacStreamEncoder,
424 mInputBufferPcm32,
425 nbInputFrames /*samples per channel*/ );
426 }
427
428 inInfo->mOwnedByUs = false;
429 inQueue.erase(inQueue.begin());
430 inInfo = NULL;
431 notifyEmptyBufferDone(inHeader);
432 inHeader = NULL;
433 }
434
435 BufferInfo *outInfo = *outQueue.begin();
436 OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
437
438 if (ok) {
439 ALOGV("encoded %d, bytes %lld, eos %d", mEncoderReturnedEncodedData,
440 (long long )mEncoderReturnedNbBytes, mSawInputEOS);
441 if (mSawInputEOS && !mEncoderReturnedEncodedData) {
442 ALOGV("finishing encoder");
443 mSentOutputEOS = true;
444 FLAC__stream_encoder_finish(mFlacStreamEncoder);
445 outHeader->nFlags = OMX_BUFFERFLAG_EOS;
446 }
447 if (mSawInputEOS || mEncoderReturnedEncodedData) {
448 ALOGV(" dequeueing buffer on output port after writing data");
449 outInfo->mOwnedByUs = false;
450 outQueue.erase(outQueue.begin());
451 outInfo = NULL;
452 notifyFillBufferDone(outHeader);
453 outHeader = NULL;
454 mEncoderReturnedEncodedData = false;
455 }
456 } else {
457 ALOGE(" error encountered during encoding");
458 mSignalledError = true;
459 notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
460 return;
461 }
462
463 }
464 }
465
onEncodedFlacAvailable(const FLAC__byte buffer[],size_t bytes,unsigned samples,unsigned current_frame)466 FLAC__StreamEncoderWriteStatus SoftFlacEncoder::onEncodedFlacAvailable(
467 const FLAC__byte buffer[],
468 size_t bytes, unsigned samples,
469 unsigned current_frame) {
470 UNUSED_UNLESS_VERBOSE(current_frame);
471 ALOGV("SoftFlacEncoder::onEncodedFlacAvailable(bytes=%zu, samples=%u, curr_frame=%u)",
472 bytes, samples, current_frame);
473
474 if (samples == 0) {
475 ALOGV("saving %zu bytes of header", bytes);
476 if (mHeaderOffset + bytes > sizeof(mHeader) || mHeaderComplete) {
477 ALOGW("header is too big, or header already received");
478 mSignalledError = true;
479 notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
480 } else {
481 memcpy(mHeader + mHeaderOffset, buffer, bytes);
482 mHeaderOffset += bytes;// will contain header size when finished receiving header
483 if (buffer[0] & 0x80) {
484 mHeaderComplete = true;
485 }
486 }
487 return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
488 }
489
490 if ((samples == 0) || !mEncoderWriteData) {
491 // called by the encoder because there's header data to save, but it's not the role
492 // of this component (unless WRITE_FLAC_HEADER_IN_FIRST_BUFFER is defined)
493 ALOGV("ignoring %zu bytes of header data (samples=%d)", bytes, samples);
494 return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
495 }
496
497 List<BufferInfo *> &outQueue = getPortQueue(1);
498 CHECK(!outQueue.empty());
499 BufferInfo *outInfo = *outQueue.begin();
500 OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
501
502 if (mHeaderComplete && !mWroteHeader) {
503 ALOGV(" writing %d bytes of header on output port", mHeaderOffset);
504 memcpy(outHeader->pBuffer + outHeader->nOffset + outHeader->nFilledLen,
505 mHeader, mHeaderOffset);
506 outHeader->nFilledLen += mHeaderOffset;
507 mWroteHeader = true;
508 outInfo->mOwnedByUs = false;
509 outQueue.erase(outQueue.begin());
510 outHeader->nFlags = OMX_BUFFERFLAG_CODECCONFIG;
511 notifyFillBufferDone(outHeader);
512 outInfo = NULL;
513 outHeader = NULL;
514 // get the next buffer for the rest of the data
515 CHECK(!outQueue.empty());
516 outInfo = *outQueue.begin();
517 outHeader = outInfo->mHeader;
518 }
519
520 // write encoded data
521 ALOGV(" writing %zu bytes of encoded data on output port", bytes);
522 if (bytes > outHeader->nAllocLen - outHeader->nOffset - outHeader->nFilledLen) {
523 ALOGE(" not enough space left to write encoded data, dropping %zu bytes", bytes);
524 // a fatal error would stop the encoding
525 return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
526 }
527 memcpy(outHeader->pBuffer + outHeader->nOffset, buffer, bytes);
528
529 outHeader->nTimeStamp = mCurrentInputTimeStamp;
530 outHeader->nOffset = 0;
531 outHeader->nFilledLen += bytes;
532 outHeader->nFlags = 0;
533
534 mEncoderReturnedEncodedData = true;
535 mEncoderReturnedNbBytes += bytes;
536
537 return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
538 }
539
540
configureEncoder()541 OMX_ERRORTYPE SoftFlacEncoder::configureEncoder() {
542 ALOGV("SoftFlacEncoder::configureEncoder() numChannel=%d, sampleRate=%d",
543 mNumChannels, mSampleRate);
544
545 if (mSignalledError || (mFlacStreamEncoder == NULL)) {
546 ALOGE("can't configure encoder: no encoder or invalid state");
547 return OMX_ErrorInvalidState;
548 }
549
550 const bool inputFloat = mNumericalData == OMX_NumericalDataFloat;
551 const int codecBitsPerSample = inputFloat ? 24 : 16;
552 FLAC__bool ok = true;
553 ok = ok && FLAC__stream_encoder_set_channels(mFlacStreamEncoder, mNumChannels);
554 ok = ok && FLAC__stream_encoder_set_sample_rate(mFlacStreamEncoder, mSampleRate);
555 ok = ok && FLAC__stream_encoder_set_bits_per_sample(mFlacStreamEncoder, codecBitsPerSample);
556 ok = ok && FLAC__stream_encoder_set_compression_level(mFlacStreamEncoder,
557 (unsigned)mCompressionLevel);
558 ok = ok && FLAC__stream_encoder_set_verify(mFlacStreamEncoder, false);
559 if (!ok) { goto return_result; }
560
561 ok &= FLAC__STREAM_ENCODER_INIT_STATUS_OK ==
562 FLAC__stream_encoder_init_stream(mFlacStreamEncoder,
563 flacEncoderWriteCallback /*write_callback*/,
564 NULL /*seek_callback*/,
565 NULL /*tell_callback*/,
566 NULL /*metadata_callback*/,
567 (void *) this /*client_data*/);
568
569 return_result:
570 if (ok) {
571 ALOGV("encoder successfully configured");
572 return OMX_ErrorNone;
573 } else {
574 ALOGE("unknown error when configuring encoder");
575 return OMX_ErrorUndefined;
576 }
577 }
578
579
580 // static
flacEncoderWriteCallback(const FLAC__StreamEncoder *,const FLAC__byte buffer[],size_t bytes,unsigned samples,unsigned current_frame,void * client_data)581 FLAC__StreamEncoderWriteStatus SoftFlacEncoder::flacEncoderWriteCallback(
582 const FLAC__StreamEncoder * /* encoder */,
583 const FLAC__byte buffer[],
584 size_t bytes,
585 unsigned samples,
586 unsigned current_frame,
587 void *client_data) {
588 return ((SoftFlacEncoder*) client_data)->onEncodedFlacAvailable(
589 buffer, bytes, samples, current_frame);
590 }
591
592 } // namespace android
593
594
595 __attribute__((cfi_canonical_jump_table))
createSoftOMXComponent(const char * name,const OMX_CALLBACKTYPE * callbacks,OMX_PTR appData,OMX_COMPONENTTYPE ** component)596 android::SoftOMXComponent *createSoftOMXComponent(
597 const char *name, const OMX_CALLBACKTYPE *callbacks,
598 OMX_PTR appData, OMX_COMPONENTTYPE **component) {
599 return new android::SoftFlacEncoder(name, callbacks, appData, component);
600 }
601
602