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 #if LOG_NDEBUG
     31 #define UNUSED_UNLESS_VERBOSE(x) (void)(x)
     32 #else
     33 #define UNUSED_UNLESS_VERBOSE(x)
     34 #endif
     35 
     36 namespace android {
     37 
     38 template<class T>
     39 static 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 
     47 SoftFlacEncoder::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 
     84 SoftFlacEncoder::~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 
     94 OMX_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 
    107 void 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 
    152 OMX_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 (pcmParams->nPortIndex > 1) {
    163                 return OMX_ErrorUndefined;
    164             }
    165 
    166             pcmParams->eNumData = OMX_NumericalDataSigned;
    167             pcmParams->eEndian = OMX_EndianBig;
    168             pcmParams->bInterleaved = OMX_TRUE;
    169             pcmParams->nBitPerSample = 16;
    170             pcmParams->ePCMMode = OMX_AUDIO_PCMModeLinear;
    171             pcmParams->eChannelMapping[0] = OMX_AUDIO_ChannelLF;
    172             pcmParams->eChannelMapping[1] = OMX_AUDIO_ChannelRF;
    173 
    174             pcmParams->nChannels = mNumChannels;
    175             pcmParams->nSamplingRate = mSampleRate;
    176 
    177             return OMX_ErrorNone;
    178         }
    179 
    180         case OMX_IndexParamAudioFlac:
    181         {
    182             OMX_AUDIO_PARAM_FLACTYPE *flacParams = (OMX_AUDIO_PARAM_FLACTYPE *)params;
    183             flacParams->nCompressionLevel = mCompressionLevel;
    184             flacParams->nChannels = mNumChannels;
    185             flacParams->nSampleRate = mSampleRate;
    186             return OMX_ErrorNone;
    187         }
    188 
    189         default:
    190             return SimpleSoftOMXComponent::internalGetParameter(index, params);
    191     }
    192 }
    193 
    194 OMX_ERRORTYPE SoftFlacEncoder::internalSetParameter(
    195         OMX_INDEXTYPE index, const OMX_PTR params) {
    196     switch (index) {
    197         case OMX_IndexParamAudioPcm:
    198         {
    199             ALOGV("SoftFlacEncoder::internalSetParameter(OMX_IndexParamAudioPcm)");
    200             OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams = (OMX_AUDIO_PARAM_PCMMODETYPE *)params;
    201 
    202             if (pcmParams->nPortIndex != 0 && pcmParams->nPortIndex != 1) {
    203                 ALOGE("SoftFlacEncoder::internalSetParameter() Error #1");
    204                 return OMX_ErrorUndefined;
    205             }
    206 
    207             if (pcmParams->nChannels < 1 || pcmParams->nChannels > 2) {
    208                 return OMX_ErrorUndefined;
    209             }
    210 
    211             mNumChannels = pcmParams->nChannels;
    212             mSampleRate = pcmParams->nSamplingRate;
    213             ALOGV("will encode %d channels at %dHz", mNumChannels, mSampleRate);
    214 
    215             return configureEncoder();
    216         }
    217 
    218         case OMX_IndexParamStandardComponentRole:
    219         {
    220             ALOGV("SoftFlacEncoder::internalSetParameter(OMX_IndexParamStandardComponentRole)");
    221             const OMX_PARAM_COMPONENTROLETYPE *roleParams =
    222                 (const OMX_PARAM_COMPONENTROLETYPE *)params;
    223 
    224             if (strncmp((const char *)roleParams->cRole,
    225                     "audio_encoder.flac",
    226                     OMX_MAX_STRINGNAME_SIZE - 1)) {
    227                 ALOGE("SoftFlacEncoder::internalSetParameter(OMX_IndexParamStandardComponentRole)"
    228                         "error");
    229                 return OMX_ErrorUndefined;
    230             }
    231 
    232             return OMX_ErrorNone;
    233         }
    234 
    235         case OMX_IndexParamAudioFlac:
    236         {
    237             // used only for setting the compression level
    238             OMX_AUDIO_PARAM_FLACTYPE *flacParams = (OMX_AUDIO_PARAM_FLACTYPE *)params;
    239             mCompressionLevel = flacParams->nCompressionLevel; // range clamping done inside encoder
    240             return OMX_ErrorNone;
    241         }
    242 
    243         case OMX_IndexParamPortDefinition:
    244         {
    245             OMX_PARAM_PORTDEFINITIONTYPE *defParams =
    246                 (OMX_PARAM_PORTDEFINITIONTYPE *)params;
    247 
    248             if (defParams->nPortIndex == 0) {
    249                 if (defParams->nBufferSize > kMaxInputBufferSize) {
    250                     ALOGE("Input buffer size must be at most %d bytes",
    251                         kMaxInputBufferSize);
    252                     return OMX_ErrorUnsupportedSetting;
    253                 }
    254             }
    255 
    256             // fall through
    257         }
    258 
    259         default:
    260             ALOGV("SoftFlacEncoder::internalSetParameter(default)");
    261             return SimpleSoftOMXComponent::internalSetParameter(index, params);
    262     }
    263 }
    264 
    265 void SoftFlacEncoder::onQueueFilled(OMX_U32 portIndex) {
    266     UNUSED_UNLESS_VERBOSE(portIndex);
    267     ALOGV("SoftFlacEncoder::onQueueFilled(portIndex=%d)", portIndex);
    268 
    269     if (mSignalledError) {
    270         return;
    271     }
    272 
    273     List<BufferInfo *> &inQueue = getPortQueue(0);
    274     List<BufferInfo *> &outQueue = getPortQueue(1);
    275 
    276     while (!inQueue.empty() && !outQueue.empty()) {
    277         BufferInfo *inInfo = *inQueue.begin();
    278         OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
    279 
    280         BufferInfo *outInfo = *outQueue.begin();
    281         OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
    282 
    283         if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
    284             inQueue.erase(inQueue.begin());
    285             inInfo->mOwnedByUs = false;
    286             notifyEmptyBufferDone(inHeader);
    287 
    288             outHeader->nFilledLen = 0;
    289             outHeader->nFlags = OMX_BUFFERFLAG_EOS;
    290 
    291             outQueue.erase(outQueue.begin());
    292             outInfo->mOwnedByUs = false;
    293             notifyFillBufferDone(outHeader);
    294 
    295             return;
    296         }
    297 
    298         if (inHeader->nFilledLen > kMaxInputBufferSize) {
    299             ALOGE("input buffer too large (%d).", inHeader->nFilledLen);
    300             mSignalledError = true;
    301             notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
    302             return;
    303         }
    304 
    305         assert(mNumChannels != 0);
    306         mEncoderWriteData = true;
    307         mEncoderReturnedEncodedData = false;
    308         mEncoderReturnedNbBytes = 0;
    309         mCurrentInputTimeStamp = inHeader->nTimeStamp;
    310 
    311         const unsigned nbInputFrames = inHeader->nFilledLen / (2 * mNumChannels);
    312         const unsigned nbInputSamples = inHeader->nFilledLen / 2;
    313         const OMX_S16 * const pcm16 = reinterpret_cast<OMX_S16 *>(inHeader->pBuffer);
    314 
    315         CHECK_LE(nbInputSamples, 2 * kMaxNumSamplesPerFrame);
    316         for (unsigned i=0 ; i < nbInputSamples ; i++) {
    317             mInputBufferPcm32[i] = (FLAC__int32) pcm16[i];
    318         }
    319         ALOGV(" about to encode %u samples per channel", nbInputFrames);
    320         FLAC__bool ok = FLAC__stream_encoder_process_interleaved(
    321                         mFlacStreamEncoder,
    322                         mInputBufferPcm32,
    323                         nbInputFrames /*samples per channel*/ );
    324 
    325         if (ok) {
    326             if (mEncoderReturnedEncodedData && (mEncoderReturnedNbBytes != 0)) {
    327                 ALOGV(" dequeueing buffer on output port after writing data");
    328                 outInfo->mOwnedByUs = false;
    329                 outQueue.erase(outQueue.begin());
    330                 outInfo = NULL;
    331                 notifyFillBufferDone(outHeader);
    332                 outHeader = NULL;
    333                 mEncoderReturnedEncodedData = false;
    334             } else {
    335                 ALOGV(" encoder process_interleaved returned without data to write");
    336             }
    337         } else {
    338             ALOGE(" error encountered during encoding");
    339             mSignalledError = true;
    340             notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
    341             return;
    342         }
    343 
    344         inInfo->mOwnedByUs = false;
    345         inQueue.erase(inQueue.begin());
    346         inInfo = NULL;
    347         notifyEmptyBufferDone(inHeader);
    348         inHeader = NULL;
    349     }
    350 }
    351 
    352 FLAC__StreamEncoderWriteStatus SoftFlacEncoder::onEncodedFlacAvailable(
    353             const FLAC__byte buffer[],
    354             size_t bytes, unsigned samples,
    355             unsigned current_frame) {
    356     UNUSED_UNLESS_VERBOSE(current_frame);
    357     ALOGV("SoftFlacEncoder::onEncodedFlacAvailable(bytes=%zu, samples=%u, curr_frame=%u)",
    358             bytes, samples, current_frame);
    359 
    360 #ifdef WRITE_FLAC_HEADER_IN_FIRST_BUFFER
    361     if (samples == 0) {
    362         ALOGI(" saving %zu bytes of header", bytes);
    363         memcpy(mHeader + mHeaderOffset, buffer, bytes);
    364         mHeaderOffset += bytes;// will contain header size when finished receiving header
    365         return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
    366     }
    367 
    368 #endif
    369 
    370     if ((samples == 0) || !mEncoderWriteData) {
    371         // called by the encoder because there's header data to save, but it's not the role
    372         // of this component (unless WRITE_FLAC_HEADER_IN_FIRST_BUFFER is defined)
    373         ALOGV("ignoring %zu bytes of header data (samples=%d)", bytes, samples);
    374         return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
    375     }
    376 
    377     List<BufferInfo *> &outQueue = getPortQueue(1);
    378     CHECK(!outQueue.empty());
    379     BufferInfo *outInfo = *outQueue.begin();
    380     OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
    381 
    382 #ifdef WRITE_FLAC_HEADER_IN_FIRST_BUFFER
    383     if (!mWroteHeader) {
    384         ALOGI(" writing %d bytes of header on output port", mHeaderOffset);
    385         memcpy(outHeader->pBuffer + outHeader->nOffset + outHeader->nFilledLen,
    386                 mHeader, mHeaderOffset);
    387         outHeader->nFilledLen += mHeaderOffset;
    388         outHeader->nOffset    += mHeaderOffset;
    389         mWroteHeader = true;
    390     }
    391 #endif
    392 
    393     // write encoded data
    394     ALOGV(" writing %zu bytes of encoded data on output port", bytes);
    395     if (bytes > outHeader->nAllocLen - outHeader->nOffset - outHeader->nFilledLen) {
    396         ALOGE(" not enough space left to write encoded data, dropping %zu bytes", bytes);
    397         // a fatal error would stop the encoding
    398         return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
    399     }
    400     memcpy(outHeader->pBuffer + outHeader->nOffset, buffer, bytes);
    401 
    402     outHeader->nTimeStamp = mCurrentInputTimeStamp;
    403     outHeader->nOffset = 0;
    404     outHeader->nFilledLen += bytes;
    405     outHeader->nFlags = 0;
    406 
    407     mEncoderReturnedEncodedData = true;
    408     mEncoderReturnedNbBytes += bytes;
    409 
    410     return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
    411 }
    412 
    413 
    414 OMX_ERRORTYPE SoftFlacEncoder::configureEncoder() {
    415     ALOGV("SoftFlacEncoder::configureEncoder() numChannel=%d, sampleRate=%d",
    416             mNumChannels, mSampleRate);
    417 
    418     if (mSignalledError || (mFlacStreamEncoder == NULL)) {
    419         ALOGE("can't configure encoder: no encoder or invalid state");
    420         return OMX_ErrorInvalidState;
    421     }
    422 
    423     FLAC__bool ok = true;
    424     FLAC__StreamEncoderInitStatus initStatus = FLAC__STREAM_ENCODER_INIT_STATUS_OK;
    425     ok = ok && FLAC__stream_encoder_set_channels(mFlacStreamEncoder, mNumChannels);
    426     ok = ok && FLAC__stream_encoder_set_sample_rate(mFlacStreamEncoder, mSampleRate);
    427     ok = ok && FLAC__stream_encoder_set_bits_per_sample(mFlacStreamEncoder, 16);
    428     ok = ok && FLAC__stream_encoder_set_compression_level(mFlacStreamEncoder,
    429             (unsigned)mCompressionLevel);
    430     ok = ok && FLAC__stream_encoder_set_verify(mFlacStreamEncoder, false);
    431     if (!ok) { goto return_result; }
    432 
    433     ok &= FLAC__STREAM_ENCODER_INIT_STATUS_OK ==
    434             FLAC__stream_encoder_init_stream(mFlacStreamEncoder,
    435                     flacEncoderWriteCallback    /*write_callback*/,
    436                     NULL /*seek_callback*/,
    437                     NULL /*tell_callback*/,
    438                     NULL /*metadata_callback*/,
    439                     (void *) this /*client_data*/);
    440 
    441 return_result:
    442     if (ok) {
    443         ALOGV("encoder successfully configured");
    444         return OMX_ErrorNone;
    445     } else {
    446         ALOGE("unknown error when configuring encoder");
    447         return OMX_ErrorUndefined;
    448     }
    449 }
    450 
    451 
    452 // static
    453 FLAC__StreamEncoderWriteStatus SoftFlacEncoder::flacEncoderWriteCallback(
    454             const FLAC__StreamEncoder * /* encoder */,
    455             const FLAC__byte buffer[],
    456             size_t bytes,
    457             unsigned samples,
    458             unsigned current_frame,
    459             void *client_data) {
    460     return ((SoftFlacEncoder*) client_data)->onEncodedFlacAvailable(
    461             buffer, bytes, samples, current_frame);
    462 }
    463 
    464 }  // namespace android
    465 
    466 
    467 android::SoftOMXComponent *createSoftOMXComponent(
    468         const char *name, const OMX_CALLBACKTYPE *callbacks,
    469         OMX_PTR appData, OMX_COMPONENTTYPE **component) {
    470     return new android::SoftFlacEncoder(name, callbacks, appData, component);
    471 }
    472 
    473