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 = kMaxInputBufferSize;
    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         case OMX_IndexParamPortDefinition:
    238         {
    239             OMX_PARAM_PORTDEFINITIONTYPE *defParams =
    240                 (OMX_PARAM_PORTDEFINITIONTYPE *)params;
    241 
    242             if (defParams->nPortIndex == 0) {
    243                 if (defParams->nBufferSize > kMaxInputBufferSize) {
    244                     ALOGE("Input buffer size must be at most %zu bytes",
    245                         kMaxInputBufferSize);
    246                     return OMX_ErrorUnsupportedSetting;
    247                 }
    248             }
    249 
    250             // fall through
    251         }
    252 
    253         default:
    254             ALOGV("SoftFlacEncoder::internalSetParameter(default)");
    255             return SimpleSoftOMXComponent::internalSetParameter(index, params);
    256     }
    257 }
    258 
    259 void SoftFlacEncoder::onQueueFilled(OMX_U32 portIndex) {
    260 
    261     ALOGV("SoftFlacEncoder::onQueueFilled(portIndex=%ld)", portIndex);
    262 
    263     if (mSignalledError) {
    264         return;
    265     }
    266 
    267     List<BufferInfo *> &inQueue = getPortQueue(0);
    268     List<BufferInfo *> &outQueue = getPortQueue(1);
    269 
    270     while (!inQueue.empty() && !outQueue.empty()) {
    271         BufferInfo *inInfo = *inQueue.begin();
    272         OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
    273 
    274         BufferInfo *outInfo = *outQueue.begin();
    275         OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
    276 
    277         if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
    278             inQueue.erase(inQueue.begin());
    279             inInfo->mOwnedByUs = false;
    280             notifyEmptyBufferDone(inHeader);
    281 
    282             outHeader->nFilledLen = 0;
    283             outHeader->nFlags = OMX_BUFFERFLAG_EOS;
    284 
    285             outQueue.erase(outQueue.begin());
    286             outInfo->mOwnedByUs = false;
    287             notifyFillBufferDone(outHeader);
    288 
    289             return;
    290         }
    291 
    292         if (inHeader->nFilledLen > kMaxInputBufferSize) {
    293             ALOGE("input buffer too large (%ld).", inHeader->nFilledLen);
    294             mSignalledError = true;
    295             notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
    296             return;
    297         }
    298 
    299         assert(mNumChannels != 0);
    300         mEncoderWriteData = true;
    301         mEncoderReturnedEncodedData = false;
    302         mEncoderReturnedNbBytes = 0;
    303         mCurrentInputTimeStamp = inHeader->nTimeStamp;
    304 
    305         const unsigned nbInputFrames = inHeader->nFilledLen / (2 * mNumChannels);
    306         const unsigned nbInputSamples = inHeader->nFilledLen / 2;
    307         const OMX_S16 * const pcm16 = reinterpret_cast<OMX_S16 *>(inHeader->pBuffer);
    308 
    309         CHECK_LE(nbInputSamples, 2 * kMaxNumSamplesPerFrame);
    310         for (unsigned i=0 ; i < nbInputSamples ; i++) {
    311             mInputBufferPcm32[i] = (FLAC__int32) pcm16[i];
    312         }
    313         ALOGV(" about to encode %u samples per channel", nbInputFrames);
    314         FLAC__bool ok = FLAC__stream_encoder_process_interleaved(
    315                         mFlacStreamEncoder,
    316                         mInputBufferPcm32,
    317                         nbInputFrames /*samples per channel*/ );
    318 
    319         if (ok) {
    320             if (mEncoderReturnedEncodedData && (mEncoderReturnedNbBytes != 0)) {
    321                 ALOGV(" dequeueing buffer on output port after writing data");
    322                 outInfo->mOwnedByUs = false;
    323                 outQueue.erase(outQueue.begin());
    324                 outInfo = NULL;
    325                 notifyFillBufferDone(outHeader);
    326                 outHeader = NULL;
    327                 mEncoderReturnedEncodedData = false;
    328             } else {
    329                 ALOGV(" encoder process_interleaved returned without data to write");
    330             }
    331         } else {
    332             ALOGE(" error encountered during encoding");
    333             mSignalledError = true;
    334             notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
    335             return;
    336         }
    337 
    338         inInfo->mOwnedByUs = false;
    339         inQueue.erase(inQueue.begin());
    340         inInfo = NULL;
    341         notifyEmptyBufferDone(inHeader);
    342         inHeader = NULL;
    343     }
    344 }
    345 
    346 
    347 FLAC__StreamEncoderWriteStatus SoftFlacEncoder::onEncodedFlacAvailable(
    348             const FLAC__byte buffer[],
    349             size_t bytes, unsigned samples, unsigned current_frame) {
    350     ALOGV("SoftFlacEncoder::onEncodedFlacAvailable(bytes=%d, samples=%d, curr_frame=%d)",
    351             bytes, samples, current_frame);
    352 
    353 #ifdef WRITE_FLAC_HEADER_IN_FIRST_BUFFER
    354     if (samples == 0) {
    355         ALOGI(" saving %d bytes of header", bytes);
    356         memcpy(mHeader + mHeaderOffset, buffer, bytes);
    357         mHeaderOffset += bytes;// will contain header size when finished receiving header
    358         return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
    359     }
    360 
    361 #endif
    362 
    363     if ((samples == 0) || !mEncoderWriteData) {
    364         // called by the encoder because there's header data to save, but it's not the role
    365         // of this component (unless WRITE_FLAC_HEADER_IN_FIRST_BUFFER is defined)
    366         ALOGV("ignoring %d bytes of header data (samples=%d)", bytes, samples);
    367         return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
    368     }
    369 
    370     List<BufferInfo *> &outQueue = getPortQueue(1);
    371     CHECK(!outQueue.empty());
    372     BufferInfo *outInfo = *outQueue.begin();
    373     OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
    374 
    375 #ifdef WRITE_FLAC_HEADER_IN_FIRST_BUFFER
    376     if (!mWroteHeader) {
    377         ALOGI(" writing %d bytes of header on output port", mHeaderOffset);
    378         memcpy(outHeader->pBuffer + outHeader->nOffset + outHeader->nFilledLen,
    379                 mHeader, mHeaderOffset);
    380         outHeader->nFilledLen += mHeaderOffset;
    381         outHeader->nOffset    += mHeaderOffset;
    382         mWroteHeader = true;
    383     }
    384 #endif
    385 
    386     // write encoded data
    387     ALOGV(" writing %d bytes of encoded data on output port", bytes);
    388     if (bytes > outHeader->nAllocLen - outHeader->nOffset - outHeader->nFilledLen) {
    389         ALOGE(" not enough space left to write encoded data, dropping %u bytes", bytes);
    390         // a fatal error would stop the encoding
    391         return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
    392     }
    393     memcpy(outHeader->pBuffer + outHeader->nOffset, buffer, bytes);
    394 
    395     outHeader->nTimeStamp = mCurrentInputTimeStamp;
    396     outHeader->nOffset = 0;
    397     outHeader->nFilledLen += bytes;
    398     outHeader->nFlags = 0;
    399 
    400     mEncoderReturnedEncodedData = true;
    401     mEncoderReturnedNbBytes += bytes;
    402 
    403     return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
    404 }
    405 
    406 
    407 OMX_ERRORTYPE SoftFlacEncoder::configureEncoder() {
    408     ALOGV("SoftFlacEncoder::configureEncoder() numChannel=%ld, sampleRate=%ld",
    409             mNumChannels, mSampleRate);
    410 
    411     if (mSignalledError || (mFlacStreamEncoder == NULL)) {
    412         ALOGE("can't configure encoder: no encoder or invalid state");
    413         return OMX_ErrorInvalidState;
    414     }
    415 
    416     FLAC__bool ok = true;
    417     FLAC__StreamEncoderInitStatus initStatus = FLAC__STREAM_ENCODER_INIT_STATUS_OK;
    418     ok = ok && FLAC__stream_encoder_set_channels(mFlacStreamEncoder, mNumChannels);
    419     ok = ok && FLAC__stream_encoder_set_sample_rate(mFlacStreamEncoder, mSampleRate);
    420     ok = ok && FLAC__stream_encoder_set_bits_per_sample(mFlacStreamEncoder, 16);
    421     ok = ok && FLAC__stream_encoder_set_compression_level(mFlacStreamEncoder,
    422             (unsigned)mCompressionLevel);
    423     ok = ok && FLAC__stream_encoder_set_verify(mFlacStreamEncoder, false);
    424     if (!ok) { goto return_result; }
    425 
    426     ok &= FLAC__STREAM_ENCODER_INIT_STATUS_OK ==
    427             FLAC__stream_encoder_init_stream(mFlacStreamEncoder,
    428                     flacEncoderWriteCallback    /*write_callback*/,
    429                     NULL /*seek_callback*/,
    430                     NULL /*tell_callback*/,
    431                     NULL /*metadata_callback*/,
    432                     (void *) this /*client_data*/);
    433 
    434 return_result:
    435     if (ok) {
    436         ALOGV("encoder successfully configured");
    437         return OMX_ErrorNone;
    438     } else {
    439         ALOGE("unknown error when configuring encoder");
    440         return OMX_ErrorUndefined;
    441     }
    442 }
    443 
    444 
    445 // static
    446 FLAC__StreamEncoderWriteStatus SoftFlacEncoder::flacEncoderWriteCallback(
    447             const FLAC__StreamEncoder *encoder, const FLAC__byte buffer[],
    448             size_t bytes, unsigned samples, unsigned current_frame, void *client_data) {
    449     return ((SoftFlacEncoder*) client_data)->onEncodedFlacAvailable(
    450             buffer, bytes, samples, current_frame);
    451 }
    452 
    453 }  // namespace android
    454 
    455 
    456 android::SoftOMXComponent *createSoftOMXComponent(
    457         const char *name, const OMX_CALLBACKTYPE *callbacks,
    458         OMX_PTR appData, OMX_COMPONENTTYPE **component) {
    459     return new android::SoftFlacEncoder(name, callbacks, appData, component);
    460 }
    461 
    462