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