SoftFlacEncoder.cpp revision 67ef30185837950144d30e5a73d852eb9a7a0a89
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 <utils/Log.h>
20
21#include "SoftFlacEncoder.h"
22
23#include <media/stagefright/foundation/ADebug.h>
24#include <media/stagefright/MediaDefs.h>
25
26#define FLAC_COMPRESSION_LEVEL_MIN     0
27#define FLAC_COMPRESSION_LEVEL_DEFAULT 5
28#define FLAC_COMPRESSION_LEVEL_MAX     8
29
30#if LOG_NDEBUG
31#define UNUSED_UNLESS_VERBOSE(x) (void)(x)
32#else
33#define UNUSED_UNLESS_VERBOSE(x)
34#endif
35
36namespace android {
37
38template<class T>
39static void InitOMXParams(T *params) {
40    params->nSize = sizeof(T);
41    params->nVersion.s.nVersionMajor = 1;
42    params->nVersion.s.nVersionMinor = 0;
43    params->nVersion.s.nRevision = 0;
44    params->nVersion.s.nStep = 0;
45}
46
47SoftFlacEncoder::SoftFlacEncoder(
48        const char *name,
49        const OMX_CALLBACKTYPE *callbacks,
50        OMX_PTR appData,
51        OMX_COMPONENTTYPE **component)
52    : SimpleSoftOMXComponent(name, callbacks, appData, component),
53      mSignalledError(false),
54      mNumChannels(1),
55      mSampleRate(44100),
56      mCompressionLevel(FLAC_COMPRESSION_LEVEL_DEFAULT),
57      mEncoderWriteData(false),
58      mEncoderReturnedEncodedData(false),
59      mEncoderReturnedNbBytes(0),
60      mInputBufferPcm32(NULL)
61#ifdef WRITE_FLAC_HEADER_IN_FIRST_BUFFER
62      , mHeaderOffset(0)
63      , mWroteHeader(false)
64#endif
65{
66    ALOGV("SoftFlacEncoder::SoftFlacEncoder(name=%s)", name);
67    initPorts();
68
69    mFlacStreamEncoder = FLAC__stream_encoder_new();
70    if (mFlacStreamEncoder == NULL) {
71        ALOGE("SoftFlacEncoder::SoftFlacEncoder(name=%s) error instantiating FLAC encoder", name);
72        mSignalledError = true;
73    }
74
75    if (!mSignalledError) { // no use allocating input buffer if we had an error above
76        mInputBufferPcm32 = (FLAC__int32*) malloc(sizeof(FLAC__int32) * 2 * kMaxNumSamplesPerFrame);
77        if (mInputBufferPcm32 == NULL) {
78            ALOGE("SoftFlacEncoder::SoftFlacEncoder(name=%s) error allocating internal input buffer", name);
79            mSignalledError = true;
80        }
81    }
82}
83
84SoftFlacEncoder::~SoftFlacEncoder() {
85    ALOGV("SoftFlacEncoder::~SoftFlacEncoder()");
86    if (mFlacStreamEncoder != NULL) {
87        FLAC__stream_encoder_delete(mFlacStreamEncoder);
88        mFlacStreamEncoder = NULL;
89    }
90    free(mInputBufferPcm32);
91    mInputBufferPcm32 = NULL;
92}
93
94OMX_ERRORTYPE SoftFlacEncoder::initCheck() const {
95    if (mSignalledError) {
96        if (mFlacStreamEncoder == NULL) {
97            ALOGE("initCheck() failed due to NULL encoder");
98        } else if (mInputBufferPcm32 == NULL) {
99            ALOGE("initCheck() failed due to error allocating internal input buffer");
100        }
101        return OMX_ErrorUndefined;
102    } else {
103        return SimpleSoftOMXComponent::initCheck();
104    }
105}
106
107void SoftFlacEncoder::initPorts() {
108    ALOGV("SoftFlacEncoder::initPorts()");
109
110    OMX_PARAM_PORTDEFINITIONTYPE def;
111    InitOMXParams(&def);
112
113    // configure input port of the encoder
114    def.nPortIndex = 0;
115    def.eDir = OMX_DirInput;
116    def.nBufferCountMin = kNumBuffers;// TODO verify that 1 is enough
117    def.nBufferCountActual = def.nBufferCountMin;
118    def.nBufferSize = kMaxInputBufferSize;
119    def.bEnabled = OMX_TRUE;
120    def.bPopulated = OMX_FALSE;
121    def.eDomain = OMX_PortDomainAudio;
122    def.bBuffersContiguous = OMX_FALSE;
123    def.nBufferAlignment = 2;
124
125    def.format.audio.cMIMEType = const_cast<char *>("audio/raw");
126    def.format.audio.pNativeRender = NULL;
127    def.format.audio.bFlagErrorConcealment = OMX_FALSE;
128    def.format.audio.eEncoding = OMX_AUDIO_CodingPCM;
129
130    addPort(def);
131
132    // configure output port of the encoder
133    def.nPortIndex = 1;
134    def.eDir = OMX_DirOutput;
135    def.nBufferCountMin = kNumBuffers;// TODO verify that 1 is enough
136    def.nBufferCountActual = def.nBufferCountMin;
137    def.nBufferSize = kMaxOutputBufferSize;
138    def.bEnabled = OMX_TRUE;
139    def.bPopulated = OMX_FALSE;
140    def.eDomain = OMX_PortDomainAudio;
141    def.bBuffersContiguous = OMX_FALSE;
142    def.nBufferAlignment = 1;
143
144    def.format.audio.cMIMEType = const_cast<char *>(MEDIA_MIMETYPE_AUDIO_FLAC);
145    def.format.audio.pNativeRender = NULL;
146    def.format.audio.bFlagErrorConcealment = OMX_FALSE;
147    def.format.audio.eEncoding = OMX_AUDIO_CodingFLAC;
148
149    addPort(def);
150}
151
152OMX_ERRORTYPE SoftFlacEncoder::internalGetParameter(
153        OMX_INDEXTYPE index, OMX_PTR params) {
154    ALOGV("SoftFlacEncoder::internalGetParameter(index=0x%x)", index);
155
156    switch (index) {
157        case OMX_IndexParamAudioPcm:
158        {
159            OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams =
160                (OMX_AUDIO_PARAM_PCMMODETYPE *)params;
161
162            if (!isValidOMXParam(pcmParams)) {
163                return OMX_ErrorBadParameter;
164            }
165
166            if (pcmParams->nPortIndex > 1) {
167                return OMX_ErrorUndefined;
168            }
169
170            pcmParams->eNumData = OMX_NumericalDataSigned;
171            pcmParams->eEndian = OMX_EndianBig;
172            pcmParams->bInterleaved = OMX_TRUE;
173            pcmParams->nBitPerSample = 16;
174            pcmParams->ePCMMode = OMX_AUDIO_PCMModeLinear;
175            pcmParams->eChannelMapping[0] = OMX_AUDIO_ChannelLF;
176            pcmParams->eChannelMapping[1] = OMX_AUDIO_ChannelRF;
177
178            pcmParams->nChannels = mNumChannels;
179            pcmParams->nSamplingRate = mSampleRate;
180
181            return OMX_ErrorNone;
182        }
183
184        case OMX_IndexParamAudioFlac:
185        {
186            OMX_AUDIO_PARAM_FLACTYPE *flacParams = (OMX_AUDIO_PARAM_FLACTYPE *)params;
187
188            if (!isValidOMXParam(flacParams)) {
189                return OMX_ErrorBadParameter;
190            }
191
192            flacParams->nCompressionLevel = mCompressionLevel;
193            flacParams->nChannels = mNumChannels;
194            flacParams->nSampleRate = mSampleRate;
195            return OMX_ErrorNone;
196        }
197
198        default:
199            return SimpleSoftOMXComponent::internalGetParameter(index, params);
200    }
201}
202
203OMX_ERRORTYPE SoftFlacEncoder::internalSetParameter(
204        OMX_INDEXTYPE index, const OMX_PTR params) {
205    switch (index) {
206        case OMX_IndexParamAudioPcm:
207        {
208            ALOGV("SoftFlacEncoder::internalSetParameter(OMX_IndexParamAudioPcm)");
209            OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams = (OMX_AUDIO_PARAM_PCMMODETYPE *)params;
210
211            if (!isValidOMXParam(pcmParams)) {
212                return OMX_ErrorBadParameter;
213            }
214
215            if (pcmParams->nPortIndex != 0 && pcmParams->nPortIndex != 1) {
216                ALOGE("SoftFlacEncoder::internalSetParameter() Error #1");
217                return OMX_ErrorUndefined;
218            }
219
220            if (pcmParams->nChannels < 1 || pcmParams->nChannels > 2) {
221                return OMX_ErrorUndefined;
222            }
223
224            mNumChannels = pcmParams->nChannels;
225            mSampleRate = pcmParams->nSamplingRate;
226            ALOGV("will encode %d channels at %dHz", mNumChannels, mSampleRate);
227
228            return configureEncoder();
229        }
230
231        case OMX_IndexParamStandardComponentRole:
232        {
233            ALOGV("SoftFlacEncoder::internalSetParameter(OMX_IndexParamStandardComponentRole)");
234            const OMX_PARAM_COMPONENTROLETYPE *roleParams =
235                (const OMX_PARAM_COMPONENTROLETYPE *)params;
236
237            if (!isValidOMXParam(roleParams)) {
238                return OMX_ErrorBadParameter;
239            }
240
241            if (strncmp((const char *)roleParams->cRole,
242                    "audio_encoder.flac",
243                    OMX_MAX_STRINGNAME_SIZE - 1)) {
244                ALOGE("SoftFlacEncoder::internalSetParameter(OMX_IndexParamStandardComponentRole)"
245                        "error");
246                return OMX_ErrorUndefined;
247            }
248
249            return OMX_ErrorNone;
250        }
251
252        case OMX_IndexParamAudioFlac:
253        {
254            // used only for setting the compression level
255            OMX_AUDIO_PARAM_FLACTYPE *flacParams = (OMX_AUDIO_PARAM_FLACTYPE *)params;
256
257            if (!isValidOMXParam(flacParams)) {
258                return OMX_ErrorBadParameter;
259            }
260
261            mCompressionLevel = flacParams->nCompressionLevel; // range clamping done inside encoder
262            return OMX_ErrorNone;
263        }
264
265        case OMX_IndexParamPortDefinition:
266        {
267            OMX_PARAM_PORTDEFINITIONTYPE *defParams =
268                (OMX_PARAM_PORTDEFINITIONTYPE *)params;
269
270            if (!isValidOMXParam(defParams)) {
271                return OMX_ErrorBadParameter;
272            }
273
274            if (defParams->nPortIndex == 0) {
275                if (defParams->nBufferSize > kMaxInputBufferSize) {
276                    ALOGE("Input buffer size must be at most %d bytes",
277                        kMaxInputBufferSize);
278                    return OMX_ErrorUnsupportedSetting;
279                }
280            }
281
282            // fall through
283        }
284
285        default:
286            ALOGV("SoftFlacEncoder::internalSetParameter(default)");
287            return SimpleSoftOMXComponent::internalSetParameter(index, params);
288    }
289}
290
291void SoftFlacEncoder::onQueueFilled(OMX_U32 portIndex) {
292    UNUSED_UNLESS_VERBOSE(portIndex);
293    ALOGV("SoftFlacEncoder::onQueueFilled(portIndex=%d)", portIndex);
294
295    if (mSignalledError) {
296        return;
297    }
298
299    List<BufferInfo *> &inQueue = getPortQueue(0);
300    List<BufferInfo *> &outQueue = getPortQueue(1);
301
302    while (!inQueue.empty() && !outQueue.empty()) {
303        BufferInfo *inInfo = *inQueue.begin();
304        OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
305
306        BufferInfo *outInfo = *outQueue.begin();
307        OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
308
309        if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
310            inQueue.erase(inQueue.begin());
311            inInfo->mOwnedByUs = false;
312            notifyEmptyBufferDone(inHeader);
313
314            outHeader->nFilledLen = 0;
315            outHeader->nFlags = OMX_BUFFERFLAG_EOS;
316
317            outQueue.erase(outQueue.begin());
318            outInfo->mOwnedByUs = false;
319            notifyFillBufferDone(outHeader);
320
321            return;
322        }
323
324        if (inHeader->nFilledLen > kMaxInputBufferSize) {
325            ALOGE("input buffer too large (%d).", inHeader->nFilledLen);
326            mSignalledError = true;
327            notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
328            return;
329        }
330
331        assert(mNumChannels != 0);
332        mEncoderWriteData = true;
333        mEncoderReturnedEncodedData = false;
334        mEncoderReturnedNbBytes = 0;
335        mCurrentInputTimeStamp = inHeader->nTimeStamp;
336
337        const unsigned nbInputFrames = inHeader->nFilledLen / (2 * mNumChannels);
338        const unsigned nbInputSamples = inHeader->nFilledLen / 2;
339        const OMX_S16 * const pcm16 = reinterpret_cast<OMX_S16 *>(inHeader->pBuffer);
340
341        CHECK_LE(nbInputSamples, 2 * kMaxNumSamplesPerFrame);
342        for (unsigned i=0 ; i < nbInputSamples ; i++) {
343            mInputBufferPcm32[i] = (FLAC__int32) pcm16[i];
344        }
345        ALOGV(" about to encode %u samples per channel", nbInputFrames);
346        FLAC__bool ok = FLAC__stream_encoder_process_interleaved(
347                        mFlacStreamEncoder,
348                        mInputBufferPcm32,
349                        nbInputFrames /*samples per channel*/ );
350
351        if (ok) {
352            if (mEncoderReturnedEncodedData && (mEncoderReturnedNbBytes != 0)) {
353                ALOGV(" dequeueing buffer on output port after writing data");
354                outInfo->mOwnedByUs = false;
355                outQueue.erase(outQueue.begin());
356                outInfo = NULL;
357                notifyFillBufferDone(outHeader);
358                outHeader = NULL;
359                mEncoderReturnedEncodedData = false;
360            } else {
361                ALOGV(" encoder process_interleaved returned without data to write");
362            }
363        } else {
364            ALOGE(" error encountered during encoding");
365            mSignalledError = true;
366            notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
367            return;
368        }
369
370        inInfo->mOwnedByUs = false;
371        inQueue.erase(inQueue.begin());
372        inInfo = NULL;
373        notifyEmptyBufferDone(inHeader);
374        inHeader = NULL;
375    }
376}
377
378FLAC__StreamEncoderWriteStatus SoftFlacEncoder::onEncodedFlacAvailable(
379            const FLAC__byte buffer[],
380            size_t bytes, unsigned samples,
381            unsigned current_frame) {
382    UNUSED_UNLESS_VERBOSE(current_frame);
383    ALOGV("SoftFlacEncoder::onEncodedFlacAvailable(bytes=%zu, samples=%u, curr_frame=%u)",
384            bytes, samples, current_frame);
385
386#ifdef WRITE_FLAC_HEADER_IN_FIRST_BUFFER
387    if (samples == 0) {
388        ALOGI(" saving %zu bytes of header", bytes);
389        memcpy(mHeader + mHeaderOffset, buffer, bytes);
390        mHeaderOffset += bytes;// will contain header size when finished receiving header
391        return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
392    }
393
394#endif
395
396    if ((samples == 0) || !mEncoderWriteData) {
397        // called by the encoder because there's header data to save, but it's not the role
398        // of this component (unless WRITE_FLAC_HEADER_IN_FIRST_BUFFER is defined)
399        ALOGV("ignoring %zu bytes of header data (samples=%d)", bytes, samples);
400        return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
401    }
402
403    List<BufferInfo *> &outQueue = getPortQueue(1);
404    CHECK(!outQueue.empty());
405    BufferInfo *outInfo = *outQueue.begin();
406    OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
407
408#ifdef WRITE_FLAC_HEADER_IN_FIRST_BUFFER
409    if (!mWroteHeader) {
410        ALOGI(" writing %d bytes of header on output port", mHeaderOffset);
411        memcpy(outHeader->pBuffer + outHeader->nOffset + outHeader->nFilledLen,
412                mHeader, mHeaderOffset);
413        outHeader->nFilledLen += mHeaderOffset;
414        outHeader->nOffset    += mHeaderOffset;
415        mWroteHeader = true;
416    }
417#endif
418
419    // write encoded data
420    ALOGV(" writing %zu bytes of encoded data on output port", bytes);
421    if (bytes > outHeader->nAllocLen - outHeader->nOffset - outHeader->nFilledLen) {
422        ALOGE(" not enough space left to write encoded data, dropping %zu bytes", bytes);
423        // a fatal error would stop the encoding
424        return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
425    }
426    memcpy(outHeader->pBuffer + outHeader->nOffset, buffer, bytes);
427
428    outHeader->nTimeStamp = mCurrentInputTimeStamp;
429    outHeader->nOffset = 0;
430    outHeader->nFilledLen += bytes;
431    outHeader->nFlags = 0;
432
433    mEncoderReturnedEncodedData = true;
434    mEncoderReturnedNbBytes += bytes;
435
436    return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
437}
438
439
440OMX_ERRORTYPE SoftFlacEncoder::configureEncoder() {
441    ALOGV("SoftFlacEncoder::configureEncoder() numChannel=%d, sampleRate=%d",
442            mNumChannels, mSampleRate);
443
444    if (mSignalledError || (mFlacStreamEncoder == NULL)) {
445        ALOGE("can't configure encoder: no encoder or invalid state");
446        return OMX_ErrorInvalidState;
447    }
448
449    FLAC__bool ok = true;
450    FLAC__StreamEncoderInitStatus initStatus = FLAC__STREAM_ENCODER_INIT_STATUS_OK;
451    ok = ok && FLAC__stream_encoder_set_channels(mFlacStreamEncoder, mNumChannels);
452    ok = ok && FLAC__stream_encoder_set_sample_rate(mFlacStreamEncoder, mSampleRate);
453    ok = ok && FLAC__stream_encoder_set_bits_per_sample(mFlacStreamEncoder, 16);
454    ok = ok && FLAC__stream_encoder_set_compression_level(mFlacStreamEncoder,
455            (unsigned)mCompressionLevel);
456    ok = ok && FLAC__stream_encoder_set_verify(mFlacStreamEncoder, false);
457    if (!ok) { goto return_result; }
458
459    ok &= FLAC__STREAM_ENCODER_INIT_STATUS_OK ==
460            FLAC__stream_encoder_init_stream(mFlacStreamEncoder,
461                    flacEncoderWriteCallback    /*write_callback*/,
462                    NULL /*seek_callback*/,
463                    NULL /*tell_callback*/,
464                    NULL /*metadata_callback*/,
465                    (void *) this /*client_data*/);
466
467return_result:
468    if (ok) {
469        ALOGV("encoder successfully configured");
470        return OMX_ErrorNone;
471    } else {
472        ALOGE("unknown error when configuring encoder");
473        return OMX_ErrorUndefined;
474    }
475}
476
477
478// static
479FLAC__StreamEncoderWriteStatus SoftFlacEncoder::flacEncoderWriteCallback(
480            const FLAC__StreamEncoder * /* encoder */,
481            const FLAC__byte buffer[],
482            size_t bytes,
483            unsigned samples,
484            unsigned current_frame,
485            void *client_data) {
486    return ((SoftFlacEncoder*) client_data)->onEncodedFlacAvailable(
487            buffer, bytes, samples, current_frame);
488}
489
490}  // namespace android
491
492
493android::SoftOMXComponent *createSoftOMXComponent(
494        const char *name, const OMX_CALLBACKTYPE *callbacks,
495        OMX_PTR appData, OMX_COMPONENTTYPE **component) {
496    return new android::SoftFlacEncoder(name, callbacks, appData, component);
497}
498
499