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 (!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 
    203 OMX_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 
    291 void 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 
    378 FLAC__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 
    440 OMX_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     ok = ok && FLAC__stream_encoder_set_channels(mFlacStreamEncoder, mNumChannels);
    451     ok = ok && FLAC__stream_encoder_set_sample_rate(mFlacStreamEncoder, mSampleRate);
    452     ok = ok && FLAC__stream_encoder_set_bits_per_sample(mFlacStreamEncoder, 16);
    453     ok = ok && FLAC__stream_encoder_set_compression_level(mFlacStreamEncoder,
    454             (unsigned)mCompressionLevel);
    455     ok = ok && FLAC__stream_encoder_set_verify(mFlacStreamEncoder, false);
    456     if (!ok) { goto return_result; }
    457 
    458     ok &= FLAC__STREAM_ENCODER_INIT_STATUS_OK ==
    459             FLAC__stream_encoder_init_stream(mFlacStreamEncoder,
    460                     flacEncoderWriteCallback    /*write_callback*/,
    461                     NULL /*seek_callback*/,
    462                     NULL /*tell_callback*/,
    463                     NULL /*metadata_callback*/,
    464                     (void *) this /*client_data*/);
    465 
    466 return_result:
    467     if (ok) {
    468         ALOGV("encoder successfully configured");
    469         return OMX_ErrorNone;
    470     } else {
    471         ALOGE("unknown error when configuring encoder");
    472         return OMX_ErrorUndefined;
    473     }
    474 }
    475 
    476 
    477 // static
    478 FLAC__StreamEncoderWriteStatus SoftFlacEncoder::flacEncoderWriteCallback(
    479             const FLAC__StreamEncoder * /* encoder */,
    480             const FLAC__byte buffer[],
    481             size_t bytes,
    482             unsigned samples,
    483             unsigned current_frame,
    484             void *client_data) {
    485     return ((SoftFlacEncoder*) client_data)->onEncodedFlacAvailable(
    486             buffer, bytes, samples, current_frame);
    487 }
    488 
    489 }  // namespace android
    490 
    491 
    492 android::SoftOMXComponent *createSoftOMXComponent(
    493         const char *name, const OMX_CALLBACKTYPE *callbacks,
    494         OMX_PTR appData, OMX_COMPONENTTYPE **component) {
    495     return new android::SoftFlacEncoder(name, callbacks, appData, component);
    496 }
    497 
    498