xref: /aosp_15_r20/frameworks/av/media/libstagefright/codecs/flac/enc/SoftFlacEncoder.cpp (revision ec779b8e0859a360c3d303172224686826e6e0e1)
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