Home | History | Annotate | Download | only in enc
      1 /*
      2  * Copyright (C) 2013 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 "SoftVPXEncoder"
     19 #include "SoftVPXEncoder.h"
     20 
     21 #include <utils/Log.h>
     22 
     23 #include <media/hardware/HardwareAPI.h>
     24 #include <media/hardware/MetadataBufferType.h>
     25 #include <media/stagefright/foundation/ADebug.h>
     26 #include <media/stagefright/MediaDefs.h>
     27 
     28 namespace android {
     29 
     30 
     31 template<class T>
     32 static void InitOMXParams(T *params) {
     33     params->nSize = sizeof(T);
     34     // OMX IL 1.1.2
     35     params->nVersion.s.nVersionMajor = 1;
     36     params->nVersion.s.nVersionMinor = 1;
     37     params->nVersion.s.nRevision = 2;
     38     params->nVersion.s.nStep = 0;
     39 }
     40 
     41 
     42 static int GetCPUCoreCount() {
     43     int cpuCoreCount = 1;
     44 #if defined(_SC_NPROCESSORS_ONLN)
     45     cpuCoreCount = sysconf(_SC_NPROCESSORS_ONLN);
     46 #else
     47     // _SC_NPROC_ONLN must be defined...
     48     cpuCoreCount = sysconf(_SC_NPROC_ONLN);
     49 #endif
     50     CHECK_GE(cpuCoreCount, 1);
     51     return cpuCoreCount;
     52 }
     53 
     54 
     55 // This color conversion utility is copied from SoftMPEG4Encoder.cpp
     56 inline static void ConvertSemiPlanarToPlanar(uint8_t *inyuv,
     57                                              uint8_t* outyuv,
     58                                              int32_t width,
     59                                              int32_t height) {
     60     int32_t outYsize = width * height;
     61     uint32_t *outy =  (uint32_t *) outyuv;
     62     uint16_t *outcb = (uint16_t *) (outyuv + outYsize);
     63     uint16_t *outcr = (uint16_t *) (outyuv + outYsize + (outYsize >> 2));
     64 
     65     /* Y copying */
     66     memcpy(outy, inyuv, outYsize);
     67 
     68     /* U & V copying */
     69     uint32_t *inyuv_4 = (uint32_t *) (inyuv + outYsize);
     70     for (int32_t i = height >> 1; i > 0; --i) {
     71         for (int32_t j = width >> 2; j > 0; --j) {
     72             uint32_t temp = *inyuv_4++;
     73             uint32_t tempU = temp & 0xFF;
     74             tempU = tempU | ((temp >> 8) & 0xFF00);
     75 
     76             uint32_t tempV = (temp >> 8) & 0xFF;
     77             tempV = tempV | ((temp >> 16) & 0xFF00);
     78 
     79             // Flip U and V
     80             *outcb++ = tempV;
     81             *outcr++ = tempU;
     82         }
     83     }
     84 }
     85 
     86 static void ConvertRGB32ToPlanar(
     87         const uint8_t *src, uint8_t *dstY, int32_t width, int32_t height) {
     88     CHECK((width & 1) == 0);
     89     CHECK((height & 1) == 0);
     90 
     91     uint8_t *dstU = dstY + width * height;
     92     uint8_t *dstV = dstU + (width / 2) * (height / 2);
     93 
     94     for (int32_t y = 0; y < height; ++y) {
     95         for (int32_t x = 0; x < width; ++x) {
     96 #ifdef SURFACE_IS_BGR32
     97             unsigned blue = src[4 * x];
     98             unsigned green = src[4 * x + 1];
     99             unsigned red= src[4 * x + 2];
    100 #else
    101             unsigned red= src[4 * x];
    102             unsigned green = src[4 * x + 1];
    103             unsigned blue = src[4 * x + 2];
    104 #endif
    105 
    106             unsigned luma =
    107                 ((red * 66 + green * 129 + blue * 25) >> 8) + 16;
    108 
    109             dstY[x] = luma;
    110 
    111             if ((x & 1) == 0 && (y & 1) == 0) {
    112                 unsigned U =
    113                     ((-red * 38 - green * 74 + blue * 112) >> 8) + 128;
    114 
    115                 unsigned V =
    116                     ((red * 112 - green * 94 - blue * 18) >> 8) + 128;
    117 
    118                 dstU[x / 2] = U;
    119                 dstV[x / 2] = V;
    120             }
    121         }
    122 
    123         if ((y & 1) == 0) {
    124             dstU += width / 2;
    125             dstV += width / 2;
    126         }
    127 
    128         src += 4 * width;
    129         dstY += width;
    130     }
    131 }
    132 
    133 SoftVPXEncoder::SoftVPXEncoder(const char *name,
    134                                const OMX_CALLBACKTYPE *callbacks,
    135                                OMX_PTR appData,
    136                                OMX_COMPONENTTYPE **component)
    137     : SimpleSoftOMXComponent(name, callbacks, appData, component),
    138       mCodecContext(NULL),
    139       mCodecConfiguration(NULL),
    140       mCodecInterface(NULL),
    141       mWidth(176),
    142       mHeight(144),
    143       mBitrate(192000),  // in bps
    144       mBitrateUpdated(false),
    145       mBitrateControlMode(VPX_VBR),  // variable bitrate
    146       mFrameDurationUs(33333),  // Defaults to 30 fps
    147       mDCTPartitions(0),
    148       mErrorResilience(OMX_FALSE),
    149       mColorFormat(OMX_COLOR_FormatYUV420Planar),
    150       mLevel(OMX_VIDEO_VP8Level_Version0),
    151       mConversionBuffer(NULL),
    152       mInputDataIsMeta(false),
    153       mGrallocModule(NULL),
    154       mKeyFrameRequested(false) {
    155     initPorts();
    156 }
    157 
    158 
    159 SoftVPXEncoder::~SoftVPXEncoder() {
    160     releaseEncoder();
    161 }
    162 
    163 
    164 void SoftVPXEncoder::initPorts() {
    165     OMX_PARAM_PORTDEFINITIONTYPE inputPort;
    166     OMX_PARAM_PORTDEFINITIONTYPE outputPort;
    167 
    168     InitOMXParams(&inputPort);
    169     InitOMXParams(&outputPort);
    170 
    171     inputPort.nBufferCountMin = kNumBuffers;
    172     inputPort.nBufferCountActual = inputPort.nBufferCountMin;
    173     inputPort.bEnabled = OMX_TRUE;
    174     inputPort.bPopulated = OMX_FALSE;
    175     inputPort.eDomain = OMX_PortDomainVideo;
    176     inputPort.bBuffersContiguous = OMX_FALSE;
    177     inputPort.format.video.pNativeRender = NULL;
    178     inputPort.format.video.nFrameWidth = mWidth;
    179     inputPort.format.video.nFrameHeight = mHeight;
    180     inputPort.format.video.nStride = inputPort.format.video.nFrameWidth;
    181     inputPort.format.video.nSliceHeight = inputPort.format.video.nFrameHeight;
    182     inputPort.format.video.nBitrate = 0;
    183     // frameRate is reciprocal of frameDuration, which is
    184     // in microseconds. It is also in Q16 format.
    185     inputPort.format.video.xFramerate = (1000000/mFrameDurationUs) << 16;
    186     inputPort.format.video.bFlagErrorConcealment = OMX_FALSE;
    187     inputPort.nPortIndex = kInputPortIndex;
    188     inputPort.eDir = OMX_DirInput;
    189     inputPort.nBufferAlignment = kInputBufferAlignment;
    190     inputPort.format.video.cMIMEType =
    191         const_cast<char *>(MEDIA_MIMETYPE_VIDEO_RAW);
    192     inputPort.format.video.eCompressionFormat = OMX_VIDEO_CodingUnused;
    193     inputPort.format.video.eColorFormat = mColorFormat;
    194     inputPort.format.video.pNativeWindow = NULL;
    195     inputPort.nBufferSize =
    196         (inputPort.format.video.nStride *
    197         inputPort.format.video.nSliceHeight * 3) / 2;
    198 
    199     addPort(inputPort);
    200 
    201     outputPort.nBufferCountMin = kNumBuffers;
    202     outputPort.nBufferCountActual = outputPort.nBufferCountMin;
    203     outputPort.bEnabled = OMX_TRUE;
    204     outputPort.bPopulated = OMX_FALSE;
    205     outputPort.eDomain = OMX_PortDomainVideo;
    206     outputPort.bBuffersContiguous = OMX_FALSE;
    207     outputPort.format.video.pNativeRender = NULL;
    208     outputPort.format.video.nFrameWidth = mWidth;
    209     outputPort.format.video.nFrameHeight = mHeight;
    210     outputPort.format.video.nStride = outputPort.format.video.nFrameWidth;
    211     outputPort.format.video.nSliceHeight = outputPort.format.video.nFrameHeight;
    212     outputPort.format.video.nBitrate = mBitrate;
    213     outputPort.format.video.xFramerate = 0;
    214     outputPort.format.video.bFlagErrorConcealment = OMX_FALSE;
    215     outputPort.nPortIndex = kOutputPortIndex;
    216     outputPort.eDir = OMX_DirOutput;
    217     outputPort.nBufferAlignment = kOutputBufferAlignment;
    218     outputPort.format.video.cMIMEType =
    219         const_cast<char *>(MEDIA_MIMETYPE_VIDEO_VP8);
    220     outputPort.format.video.eCompressionFormat = OMX_VIDEO_CodingVP8;
    221     outputPort.format.video.eColorFormat = OMX_COLOR_FormatUnused;
    222     outputPort.format.video.pNativeWindow = NULL;
    223     outputPort.nBufferSize = 256 * 1024;  // arbitrary
    224 
    225     addPort(outputPort);
    226 }
    227 
    228 
    229 status_t SoftVPXEncoder::initEncoder() {
    230     vpx_codec_err_t codec_return;
    231 
    232     mCodecContext = new vpx_codec_ctx_t;
    233     mCodecConfiguration = new vpx_codec_enc_cfg_t;
    234     mCodecInterface = vpx_codec_vp8_cx();
    235 
    236     if (mCodecInterface == NULL) {
    237         return UNKNOWN_ERROR;
    238     }
    239 
    240     codec_return = vpx_codec_enc_config_default(mCodecInterface,
    241                                                 mCodecConfiguration,
    242                                                 0);  // Codec specific flags
    243 
    244     if (codec_return != VPX_CODEC_OK) {
    245         ALOGE("Error populating default configuration for vpx encoder.");
    246         return UNKNOWN_ERROR;
    247     }
    248 
    249     mCodecConfiguration->g_w = mWidth;
    250     mCodecConfiguration->g_h = mHeight;
    251     mCodecConfiguration->g_threads = GetCPUCoreCount();
    252     mCodecConfiguration->g_error_resilient = mErrorResilience;
    253 
    254     switch (mLevel) {
    255         case OMX_VIDEO_VP8Level_Version0:
    256             mCodecConfiguration->g_profile = 0;
    257             break;
    258 
    259         case OMX_VIDEO_VP8Level_Version1:
    260             mCodecConfiguration->g_profile = 1;
    261             break;
    262 
    263         case OMX_VIDEO_VP8Level_Version2:
    264             mCodecConfiguration->g_profile = 2;
    265             break;
    266 
    267         case OMX_VIDEO_VP8Level_Version3:
    268             mCodecConfiguration->g_profile = 3;
    269             break;
    270 
    271         default:
    272             mCodecConfiguration->g_profile = 0;
    273     }
    274 
    275     // OMX timebase unit is microsecond
    276     // g_timebase is in seconds (i.e. 1/1000000 seconds)
    277     mCodecConfiguration->g_timebase.num = 1;
    278     mCodecConfiguration->g_timebase.den = 1000000;
    279     // rc_target_bitrate is in kbps, mBitrate in bps
    280     mCodecConfiguration->rc_target_bitrate = mBitrate/1000;
    281     mCodecConfiguration->rc_end_usage = mBitrateControlMode;
    282 
    283     codec_return = vpx_codec_enc_init(mCodecContext,
    284                                       mCodecInterface,
    285                                       mCodecConfiguration,
    286                                       0);  // flags
    287 
    288     if (codec_return != VPX_CODEC_OK) {
    289         ALOGE("Error initializing vpx encoder");
    290         return UNKNOWN_ERROR;
    291     }
    292 
    293     codec_return = vpx_codec_control(mCodecContext,
    294                                      VP8E_SET_TOKEN_PARTITIONS,
    295                                      mDCTPartitions);
    296     if (codec_return != VPX_CODEC_OK) {
    297         ALOGE("Error setting dct partitions for vpx encoder.");
    298         return UNKNOWN_ERROR;
    299     }
    300 
    301     if (mColorFormat == OMX_COLOR_FormatYUV420SemiPlanar || mInputDataIsMeta) {
    302         if (mConversionBuffer == NULL) {
    303             mConversionBuffer = (uint8_t *)malloc(mWidth * mHeight * 3 / 2);
    304             if (mConversionBuffer == NULL) {
    305                 ALOGE("Allocating conversion buffer failed.");
    306                 return UNKNOWN_ERROR;
    307             }
    308         }
    309     }
    310     return OK;
    311 }
    312 
    313 
    314 status_t SoftVPXEncoder::releaseEncoder() {
    315     if (mCodecContext != NULL) {
    316         vpx_codec_destroy(mCodecContext);
    317         delete mCodecContext;
    318         mCodecContext = NULL;
    319     }
    320 
    321     if (mCodecConfiguration != NULL) {
    322         delete mCodecConfiguration;
    323         mCodecConfiguration = NULL;
    324     }
    325 
    326     if (mConversionBuffer != NULL) {
    327         delete mConversionBuffer;
    328         mConversionBuffer = NULL;
    329     }
    330 
    331     // this one is not allocated by us
    332     mCodecInterface = NULL;
    333 
    334     return OK;
    335 }
    336 
    337 
    338 OMX_ERRORTYPE SoftVPXEncoder::internalGetParameter(OMX_INDEXTYPE index,
    339                                                    OMX_PTR param) {
    340     // can include extension index OMX_INDEXEXTTYPE
    341     const int32_t indexFull = index;
    342 
    343     switch (indexFull) {
    344         case OMX_IndexParamVideoPortFormat: {
    345             OMX_VIDEO_PARAM_PORTFORMATTYPE *formatParams =
    346                 (OMX_VIDEO_PARAM_PORTFORMATTYPE *)param;
    347 
    348             if (formatParams->nPortIndex == kInputPortIndex) {
    349                 if (formatParams->nIndex >= kNumberOfSupportedColorFormats) {
    350                     return OMX_ErrorNoMore;
    351                 }
    352 
    353                 // Color formats, in order of preference
    354                 if (formatParams->nIndex == 0) {
    355                     formatParams->eColorFormat = OMX_COLOR_FormatYUV420Planar;
    356                 } else if (formatParams->nIndex == 1) {
    357                     formatParams->eColorFormat =
    358                         OMX_COLOR_FormatYUV420SemiPlanar;
    359                 } else {
    360                     formatParams->eColorFormat = OMX_COLOR_FormatAndroidOpaque;
    361                 }
    362 
    363                 formatParams->eCompressionFormat = OMX_VIDEO_CodingUnused;
    364                 // Converting from microseconds
    365                 // Also converting to Q16 format
    366                 formatParams->xFramerate = (1000000/mFrameDurationUs) << 16;
    367                 return OMX_ErrorNone;
    368             } else if (formatParams->nPortIndex == kOutputPortIndex) {
    369                 formatParams->eCompressionFormat = OMX_VIDEO_CodingVP8;
    370                 formatParams->eColorFormat = OMX_COLOR_FormatUnused;
    371                 formatParams->xFramerate = 0;
    372                 return OMX_ErrorNone;
    373             } else {
    374                 return OMX_ErrorBadPortIndex;
    375             }
    376         }
    377 
    378         case OMX_IndexParamVideoBitrate: {
    379             OMX_VIDEO_PARAM_BITRATETYPE *bitrate =
    380                 (OMX_VIDEO_PARAM_BITRATETYPE *)param;
    381 
    382                 if (bitrate->nPortIndex != kOutputPortIndex) {
    383                     return OMX_ErrorUnsupportedIndex;
    384                 }
    385 
    386                 bitrate->nTargetBitrate = mBitrate;
    387 
    388                 if (mBitrateControlMode == VPX_VBR) {
    389                     bitrate->eControlRate = OMX_Video_ControlRateVariable;
    390                 } else if (mBitrateControlMode == VPX_CBR) {
    391                     bitrate->eControlRate = OMX_Video_ControlRateConstant;
    392                 } else {
    393                     return OMX_ErrorUnsupportedSetting;
    394                 }
    395                 return OMX_ErrorNone;
    396         }
    397 
    398         // VP8 specific parameters that use extension headers
    399         case OMX_IndexParamVideoVp8: {
    400             OMX_VIDEO_PARAM_VP8TYPE *vp8Params =
    401                 (OMX_VIDEO_PARAM_VP8TYPE *)param;
    402 
    403                 if (vp8Params->nPortIndex != kOutputPortIndex) {
    404                     return OMX_ErrorUnsupportedIndex;
    405                 }
    406 
    407                 vp8Params->eProfile = OMX_VIDEO_VP8ProfileMain;
    408                 vp8Params->eLevel = mLevel;
    409                 vp8Params->nDCTPartitions = mDCTPartitions;
    410                 vp8Params->bErrorResilientMode = mErrorResilience;
    411                 return OMX_ErrorNone;
    412         }
    413 
    414         case OMX_IndexParamVideoProfileLevelQuerySupported: {
    415             OMX_VIDEO_PARAM_PROFILELEVELTYPE *profileAndLevel =
    416                 (OMX_VIDEO_PARAM_PROFILELEVELTYPE *)param;
    417 
    418             if (profileAndLevel->nPortIndex != kOutputPortIndex) {
    419                 return OMX_ErrorUnsupportedIndex;
    420             }
    421 
    422             switch (profileAndLevel->nProfileIndex) {
    423                 case 0:
    424                     profileAndLevel->eLevel = OMX_VIDEO_VP8Level_Version0;
    425                     break;
    426 
    427                 case 1:
    428                     profileAndLevel->eLevel = OMX_VIDEO_VP8Level_Version1;
    429                     break;
    430 
    431                 case 2:
    432                     profileAndLevel->eLevel = OMX_VIDEO_VP8Level_Version2;
    433                     break;
    434 
    435                 case 3:
    436                     profileAndLevel->eLevel = OMX_VIDEO_VP8Level_Version3;
    437                     break;
    438 
    439                 default:
    440                     return OMX_ErrorNoMore;
    441             }
    442 
    443             profileAndLevel->eProfile = OMX_VIDEO_VP8ProfileMain;
    444             return OMX_ErrorNone;
    445         }
    446 
    447         case OMX_IndexParamVideoProfileLevelCurrent: {
    448             OMX_VIDEO_PARAM_PROFILELEVELTYPE *profileAndLevel =
    449                 (OMX_VIDEO_PARAM_PROFILELEVELTYPE *)param;
    450 
    451             if (profileAndLevel->nPortIndex != kOutputPortIndex) {
    452                 return OMX_ErrorUnsupportedIndex;
    453             }
    454 
    455             profileAndLevel->eLevel = mLevel;
    456             profileAndLevel->eProfile = OMX_VIDEO_VP8ProfileMain;
    457             return OMX_ErrorNone;
    458         }
    459 
    460         default:
    461             return SimpleSoftOMXComponent::internalGetParameter(index, param);
    462     }
    463 }
    464 
    465 
    466 OMX_ERRORTYPE SoftVPXEncoder::internalSetParameter(OMX_INDEXTYPE index,
    467                                                    const OMX_PTR param) {
    468     // can include extension index OMX_INDEXEXTTYPE
    469     const int32_t indexFull = index;
    470 
    471     switch (indexFull) {
    472         case OMX_IndexParamStandardComponentRole:
    473             return internalSetRoleParams(
    474                 (const OMX_PARAM_COMPONENTROLETYPE *)param);
    475 
    476         case OMX_IndexParamVideoBitrate:
    477             return internalSetBitrateParams(
    478                 (const OMX_VIDEO_PARAM_BITRATETYPE *)param);
    479 
    480         case OMX_IndexParamPortDefinition:
    481         {
    482             OMX_ERRORTYPE err = internalSetPortParams(
    483                 (const OMX_PARAM_PORTDEFINITIONTYPE *)param);
    484 
    485             if (err != OMX_ErrorNone) {
    486                 return err;
    487             }
    488 
    489             return SimpleSoftOMXComponent::internalSetParameter(index, param);
    490         }
    491 
    492         case OMX_IndexParamVideoPortFormat:
    493             return internalSetFormatParams(
    494                 (const OMX_VIDEO_PARAM_PORTFORMATTYPE *)param);
    495 
    496         case OMX_IndexParamVideoVp8:
    497             return internalSetVp8Params(
    498                 (const OMX_VIDEO_PARAM_VP8TYPE *)param);
    499 
    500         case OMX_IndexParamVideoProfileLevelCurrent:
    501             return internalSetProfileLevel(
    502                 (const OMX_VIDEO_PARAM_PROFILELEVELTYPE *)param);
    503 
    504         case OMX_IndexVendorStartUnused:
    505         {
    506             // storeMetaDataInBuffers
    507             const StoreMetaDataInBuffersParams *storeParam =
    508                 (const StoreMetaDataInBuffersParams *)param;
    509 
    510             if (storeParam->nPortIndex != kInputPortIndex) {
    511                 return OMX_ErrorBadPortIndex;
    512             }
    513 
    514             mInputDataIsMeta = (storeParam->bStoreMetaData == OMX_TRUE);
    515 
    516             return OMX_ErrorNone;
    517         }
    518 
    519         default:
    520             return SimpleSoftOMXComponent::internalSetParameter(index, param);
    521     }
    522 }
    523 
    524 OMX_ERRORTYPE SoftVPXEncoder::setConfig(
    525         OMX_INDEXTYPE index, const OMX_PTR _params) {
    526     switch (index) {
    527         case OMX_IndexConfigVideoIntraVOPRefresh:
    528         {
    529             OMX_CONFIG_INTRAREFRESHVOPTYPE *params =
    530                 (OMX_CONFIG_INTRAREFRESHVOPTYPE *)_params;
    531 
    532             if (params->nPortIndex != kOutputPortIndex) {
    533                 return OMX_ErrorBadPortIndex;
    534             }
    535 
    536             mKeyFrameRequested = params->IntraRefreshVOP;
    537             return OMX_ErrorNone;
    538         }
    539 
    540         case OMX_IndexConfigVideoBitrate:
    541         {
    542             OMX_VIDEO_CONFIG_BITRATETYPE *params =
    543                 (OMX_VIDEO_CONFIG_BITRATETYPE *)_params;
    544 
    545             if (params->nPortIndex != kOutputPortIndex) {
    546                 return OMX_ErrorBadPortIndex;
    547             }
    548 
    549             if (mBitrate != params->nEncodeBitrate) {
    550                 mBitrate = params->nEncodeBitrate;
    551                 mBitrateUpdated = true;
    552             }
    553             return OMX_ErrorNone;
    554         }
    555 
    556         default:
    557             return SimpleSoftOMXComponent::setConfig(index, _params);
    558     }
    559 }
    560 
    561 OMX_ERRORTYPE SoftVPXEncoder::internalSetProfileLevel(
    562         const OMX_VIDEO_PARAM_PROFILELEVELTYPE* profileAndLevel) {
    563     if (profileAndLevel->nPortIndex != kOutputPortIndex) {
    564         return OMX_ErrorUnsupportedIndex;
    565     }
    566 
    567     if (profileAndLevel->eProfile != OMX_VIDEO_VP8ProfileMain) {
    568         return OMX_ErrorBadParameter;
    569     }
    570 
    571     if (profileAndLevel->eLevel == OMX_VIDEO_VP8Level_Version0 ||
    572         profileAndLevel->eLevel == OMX_VIDEO_VP8Level_Version1 ||
    573         profileAndLevel->eLevel == OMX_VIDEO_VP8Level_Version2 ||
    574         profileAndLevel->eLevel == OMX_VIDEO_VP8Level_Version3) {
    575         mLevel = (OMX_VIDEO_VP8LEVELTYPE)profileAndLevel->eLevel;
    576     } else {
    577         return OMX_ErrorBadParameter;
    578     }
    579 
    580     return OMX_ErrorNone;
    581 }
    582 
    583 
    584 OMX_ERRORTYPE SoftVPXEncoder::internalSetVp8Params(
    585         const OMX_VIDEO_PARAM_VP8TYPE* vp8Params) {
    586     if (vp8Params->nPortIndex != kOutputPortIndex) {
    587         return OMX_ErrorUnsupportedIndex;
    588     }
    589 
    590     if (vp8Params->eProfile != OMX_VIDEO_VP8ProfileMain) {
    591         return OMX_ErrorBadParameter;
    592     }
    593 
    594     if (vp8Params->eLevel == OMX_VIDEO_VP8Level_Version0 ||
    595         vp8Params->eLevel == OMX_VIDEO_VP8Level_Version1 ||
    596         vp8Params->eLevel == OMX_VIDEO_VP8Level_Version2 ||
    597         vp8Params->eLevel == OMX_VIDEO_VP8Level_Version3) {
    598         mLevel = vp8Params->eLevel;
    599     } else {
    600         return OMX_ErrorBadParameter;
    601     }
    602 
    603     if (vp8Params->nDCTPartitions <= kMaxDCTPartitions) {
    604         mDCTPartitions = vp8Params->nDCTPartitions;
    605     } else {
    606         return OMX_ErrorBadParameter;
    607     }
    608 
    609     mErrorResilience = vp8Params->bErrorResilientMode;
    610     return OMX_ErrorNone;
    611 }
    612 
    613 
    614 OMX_ERRORTYPE SoftVPXEncoder::internalSetFormatParams(
    615         const OMX_VIDEO_PARAM_PORTFORMATTYPE* format) {
    616     if (format->nPortIndex == kInputPortIndex) {
    617         if (format->eColorFormat == OMX_COLOR_FormatYUV420Planar ||
    618             format->eColorFormat == OMX_COLOR_FormatYUV420SemiPlanar ||
    619             format->eColorFormat == OMX_COLOR_FormatAndroidOpaque) {
    620             mColorFormat = format->eColorFormat;
    621 
    622             OMX_PARAM_PORTDEFINITIONTYPE *def = &editPortInfo(kInputPortIndex)->mDef;
    623             def->format.video.eColorFormat = mColorFormat;
    624 
    625             return OMX_ErrorNone;
    626         } else {
    627             ALOGE("Unsupported color format %i", format->eColorFormat);
    628             return OMX_ErrorUnsupportedSetting;
    629         }
    630     } else if (format->nPortIndex == kOutputPortIndex) {
    631         if (format->eCompressionFormat == OMX_VIDEO_CodingVP8) {
    632             return OMX_ErrorNone;
    633         } else {
    634             return OMX_ErrorUnsupportedSetting;
    635         }
    636     } else {
    637         return OMX_ErrorBadPortIndex;
    638     }
    639 }
    640 
    641 
    642 OMX_ERRORTYPE SoftVPXEncoder::internalSetRoleParams(
    643         const OMX_PARAM_COMPONENTROLETYPE* role) {
    644     const char* roleText = (const char*)role->cRole;
    645     const size_t roleTextMaxSize = OMX_MAX_STRINGNAME_SIZE - 1;
    646 
    647     if (strncmp(roleText, "video_encoder.vp8", roleTextMaxSize)) {
    648         ALOGE("Unsupported component role");
    649         return OMX_ErrorBadParameter;
    650     }
    651 
    652     return OMX_ErrorNone;
    653 }
    654 
    655 
    656 OMX_ERRORTYPE SoftVPXEncoder::internalSetPortParams(
    657         const OMX_PARAM_PORTDEFINITIONTYPE* port) {
    658     if (port->nPortIndex == kInputPortIndex) {
    659         mWidth = port->format.video.nFrameWidth;
    660         mHeight = port->format.video.nFrameHeight;
    661 
    662         // xFramerate comes in Q16 format, in frames per second unit
    663         const uint32_t framerate = port->format.video.xFramerate >> 16;
    664         // frame duration is in microseconds
    665         mFrameDurationUs = (1000000/framerate);
    666 
    667         if (port->format.video.eColorFormat == OMX_COLOR_FormatYUV420Planar ||
    668             port->format.video.eColorFormat == OMX_COLOR_FormatYUV420SemiPlanar ||
    669             port->format.video.eColorFormat == OMX_COLOR_FormatAndroidOpaque) {
    670             mColorFormat = port->format.video.eColorFormat;
    671         } else {
    672             return OMX_ErrorUnsupportedSetting;
    673         }
    674 
    675         OMX_PARAM_PORTDEFINITIONTYPE *def = &editPortInfo(kInputPortIndex)->mDef;
    676         def->format.video.nFrameWidth = mWidth;
    677         def->format.video.nFrameHeight = mHeight;
    678         def->format.video.xFramerate = port->format.video.xFramerate;
    679         def->format.video.eColorFormat = mColorFormat;
    680 
    681         return OMX_ErrorNone;
    682     } else if (port->nPortIndex == kOutputPortIndex) {
    683         mBitrate = port->format.video.nBitrate;
    684         return OMX_ErrorNone;
    685     } else {
    686         return OMX_ErrorBadPortIndex;
    687     }
    688 }
    689 
    690 
    691 OMX_ERRORTYPE SoftVPXEncoder::internalSetBitrateParams(
    692         const OMX_VIDEO_PARAM_BITRATETYPE* bitrate) {
    693     if (bitrate->nPortIndex != kOutputPortIndex) {
    694         return OMX_ErrorUnsupportedIndex;
    695     }
    696 
    697     mBitrate = bitrate->nTargetBitrate;
    698 
    699     if (bitrate->eControlRate == OMX_Video_ControlRateVariable) {
    700         mBitrateControlMode = VPX_VBR;
    701     } else if (bitrate->eControlRate == OMX_Video_ControlRateConstant) {
    702         mBitrateControlMode = VPX_CBR;
    703     } else {
    704         return OMX_ErrorUnsupportedSetting;
    705     }
    706 
    707     return OMX_ErrorNone;
    708 }
    709 
    710 
    711 void SoftVPXEncoder::onQueueFilled(OMX_U32 portIndex) {
    712     // Initialize encoder if not already
    713     if (mCodecContext == NULL) {
    714         if (OK != initEncoder()) {
    715             ALOGE("Failed to initialize encoder");
    716             notify(OMX_EventError,
    717                    OMX_ErrorUndefined,
    718                    0,  // Extra notification data
    719                    NULL);  // Notification data pointer
    720             return;
    721         }
    722     }
    723 
    724     vpx_codec_err_t codec_return;
    725     List<BufferInfo *> &inputBufferInfoQueue = getPortQueue(kInputPortIndex);
    726     List<BufferInfo *> &outputBufferInfoQueue = getPortQueue(kOutputPortIndex);
    727 
    728     while (!inputBufferInfoQueue.empty() && !outputBufferInfoQueue.empty()) {
    729         BufferInfo *inputBufferInfo = *inputBufferInfoQueue.begin();
    730         OMX_BUFFERHEADERTYPE *inputBufferHeader = inputBufferInfo->mHeader;
    731 
    732         BufferInfo *outputBufferInfo = *outputBufferInfoQueue.begin();
    733         OMX_BUFFERHEADERTYPE *outputBufferHeader = outputBufferInfo->mHeader;
    734 
    735         if (inputBufferHeader->nFlags & OMX_BUFFERFLAG_EOS) {
    736             inputBufferInfoQueue.erase(inputBufferInfoQueue.begin());
    737             inputBufferInfo->mOwnedByUs = false;
    738             notifyEmptyBufferDone(inputBufferHeader);
    739 
    740             outputBufferHeader->nFilledLen = 0;
    741             outputBufferHeader->nFlags = OMX_BUFFERFLAG_EOS;
    742 
    743             outputBufferInfoQueue.erase(outputBufferInfoQueue.begin());
    744             outputBufferInfo->mOwnedByUs = false;
    745             notifyFillBufferDone(outputBufferHeader);
    746             return;
    747         }
    748 
    749         uint8_t *source =
    750             inputBufferHeader->pBuffer + inputBufferHeader->nOffset;
    751 
    752         if (mInputDataIsMeta) {
    753             CHECK_GE(inputBufferHeader->nFilledLen,
    754                      4 + sizeof(buffer_handle_t));
    755 
    756             uint32_t bufferType = *(uint32_t *)source;
    757             CHECK_EQ(bufferType, kMetadataBufferTypeGrallocSource);
    758 
    759             if (mGrallocModule == NULL) {
    760                 CHECK_EQ(0, hw_get_module(
    761                             GRALLOC_HARDWARE_MODULE_ID, &mGrallocModule));
    762             }
    763 
    764             const gralloc_module_t *grmodule =
    765                 (const gralloc_module_t *)mGrallocModule;
    766 
    767             buffer_handle_t handle = *(buffer_handle_t *)(source + 4);
    768 
    769             void *bits;
    770             CHECK_EQ(0,
    771                      grmodule->lock(
    772                          grmodule, handle,
    773                          GRALLOC_USAGE_SW_READ_OFTEN
    774                             | GRALLOC_USAGE_SW_WRITE_NEVER,
    775                          0, 0, mWidth, mHeight, &bits));
    776 
    777             ConvertRGB32ToPlanar(
    778                     (const uint8_t *)bits, mConversionBuffer, mWidth, mHeight);
    779 
    780             source = mConversionBuffer;
    781 
    782             CHECK_EQ(0, grmodule->unlock(grmodule, handle));
    783         } else if (mColorFormat == OMX_COLOR_FormatYUV420SemiPlanar) {
    784             ConvertSemiPlanarToPlanar(
    785                     source, mConversionBuffer, mWidth, mHeight);
    786 
    787             source = mConversionBuffer;
    788         }
    789         vpx_image_t raw_frame;
    790         vpx_img_wrap(&raw_frame, VPX_IMG_FMT_I420, mWidth, mHeight,
    791                      kInputBufferAlignment, source);
    792 
    793         vpx_enc_frame_flags_t flags = 0;
    794         if (mKeyFrameRequested) {
    795             flags |= VPX_EFLAG_FORCE_KF;
    796             mKeyFrameRequested = false;
    797         }
    798 
    799         if (mBitrateUpdated) {
    800             mCodecConfiguration->rc_target_bitrate = mBitrate/1000;
    801             vpx_codec_err_t res = vpx_codec_enc_config_set(mCodecContext,
    802                                                            mCodecConfiguration);
    803             if (res != VPX_CODEC_OK) {
    804                 ALOGE("vp8 encoder failed to update bitrate: %s",
    805                       vpx_codec_err_to_string(res));
    806                 notify(OMX_EventError,
    807                        OMX_ErrorUndefined,
    808                        0, // Extra notification data
    809                        NULL); // Notification data pointer
    810             }
    811             mBitrateUpdated = false;
    812         }
    813 
    814         codec_return = vpx_codec_encode(
    815                 mCodecContext,
    816                 &raw_frame,
    817                 inputBufferHeader->nTimeStamp,  // in timebase units
    818                 mFrameDurationUs,  // frame duration in timebase units
    819                 flags,  // frame flags
    820                 VPX_DL_REALTIME);  // encoding deadline
    821         if (codec_return != VPX_CODEC_OK) {
    822             ALOGE("vpx encoder failed to encode frame");
    823             notify(OMX_EventError,
    824                    OMX_ErrorUndefined,
    825                    0,  // Extra notification data
    826                    NULL);  // Notification data pointer
    827             return;
    828         }
    829 
    830         vpx_codec_iter_t encoded_packet_iterator = NULL;
    831         const vpx_codec_cx_pkt_t* encoded_packet;
    832 
    833         while ((encoded_packet = vpx_codec_get_cx_data(
    834                         mCodecContext, &encoded_packet_iterator))) {
    835             if (encoded_packet->kind == VPX_CODEC_CX_FRAME_PKT) {
    836                 outputBufferHeader->nTimeStamp = encoded_packet->data.frame.pts;
    837                 outputBufferHeader->nFlags = 0;
    838                 if (encoded_packet->data.frame.flags & VPX_FRAME_IS_KEY)
    839                   outputBufferHeader->nFlags |= OMX_BUFFERFLAG_SYNCFRAME;
    840                 outputBufferHeader->nOffset = 0;
    841                 outputBufferHeader->nFilledLen = encoded_packet->data.frame.sz;
    842                 memcpy(outputBufferHeader->pBuffer,
    843                        encoded_packet->data.frame.buf,
    844                        encoded_packet->data.frame.sz);
    845                 outputBufferInfo->mOwnedByUs = false;
    846                 outputBufferInfoQueue.erase(outputBufferInfoQueue.begin());
    847                 notifyFillBufferDone(outputBufferHeader);
    848             }
    849         }
    850 
    851         inputBufferInfo->mOwnedByUs = false;
    852         inputBufferInfoQueue.erase(inputBufferInfoQueue.begin());
    853         notifyEmptyBufferDone(inputBufferHeader);
    854     }
    855 }
    856 
    857 OMX_ERRORTYPE SoftVPXEncoder::getExtensionIndex(
    858         const char *name, OMX_INDEXTYPE *index) {
    859     if (!strcmp(name, "OMX.google.android.index.storeMetaDataInBuffers")) {
    860         *index = OMX_IndexVendorStartUnused;
    861         return OMX_ErrorNone;
    862     }
    863 
    864     return SimpleSoftOMXComponent::getExtensionIndex(name, index);
    865 }
    866 
    867 }  // namespace android
    868 
    869 
    870 android::SoftOMXComponent *createSoftOMXComponent(
    871         const char *name, const OMX_CALLBACKTYPE *callbacks,
    872         OMX_PTR appData, OMX_COMPONENTTYPE **component) {
    873     return new android::SoftVPXEncoder(name, callbacks, appData, component);
    874 }
    875