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 #include <utils/misc.h>
     23 
     24 #include <media/hardware/HardwareAPI.h>
     25 #include <media/hardware/MetadataBufferType.h>
     26 #include <media/stagefright/foundation/ADebug.h>
     27 #include <media/stagefright/MediaDefs.h>
     28 
     29 namespace android {
     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 static const CodecProfileLevel kProfileLevels[] = {
     55     { OMX_VIDEO_VP8ProfileMain, OMX_VIDEO_VP8Level_Version0 },
     56     { OMX_VIDEO_VP8ProfileMain, OMX_VIDEO_VP8Level_Version1 },
     57     { OMX_VIDEO_VP8ProfileMain, OMX_VIDEO_VP8Level_Version2 },
     58     { OMX_VIDEO_VP8ProfileMain, OMX_VIDEO_VP8Level_Version3 },
     59 };
     60 
     61 SoftVPXEncoder::SoftVPXEncoder(const char *name,
     62                                const OMX_CALLBACKTYPE *callbacks,
     63                                OMX_PTR appData,
     64                                OMX_COMPONENTTYPE **component)
     65     : SoftVideoEncoderOMXComponent(
     66             name, "video_encoder.vp8", OMX_VIDEO_CodingVP8,
     67             kProfileLevels, NELEM(kProfileLevels),
     68             176 /* width */, 144 /* height */,
     69             callbacks, appData, component),
     70       mCodecContext(NULL),
     71       mCodecConfiguration(NULL),
     72       mCodecInterface(NULL),
     73       mBitrateUpdated(false),
     74       mBitrateControlMode(VPX_VBR),  // variable bitrate
     75       mDCTPartitions(0),
     76       mErrorResilience(OMX_FALSE),
     77       mLevel(OMX_VIDEO_VP8Level_Version0),
     78       mKeyFrameInterval(0),
     79       mMinQuantizer(0),
     80       mMaxQuantizer(0),
     81       mTemporalLayers(0),
     82       mTemporalPatternType(OMX_VIDEO_VPXTemporalLayerPatternNone),
     83       mTemporalPatternLength(0),
     84       mTemporalPatternIdx(0),
     85       mLastTimestamp(0x7FFFFFFFFFFFFFFFLL),
     86       mConversionBuffer(NULL),
     87       mKeyFrameRequested(false) {
     88     memset(mTemporalLayerBitrateRatio, 0, sizeof(mTemporalLayerBitrateRatio));
     89     mTemporalLayerBitrateRatio[0] = 100;
     90 
     91     const size_t kMinOutputBufferSize = 1024 * 1024; // arbitrary
     92 
     93     initPorts(
     94             kNumBuffers, kNumBuffers, kMinOutputBufferSize,
     95             MEDIA_MIMETYPE_VIDEO_VP8, 2 /* minCompressionRatio */);
     96 }
     97 
     98 
     99 SoftVPXEncoder::~SoftVPXEncoder() {
    100     releaseEncoder();
    101 }
    102 
    103 status_t SoftVPXEncoder::initEncoder() {
    104     vpx_codec_err_t codec_return;
    105 
    106     mCodecContext = new vpx_codec_ctx_t;
    107     mCodecConfiguration = new vpx_codec_enc_cfg_t;
    108     mCodecInterface = vpx_codec_vp8_cx();
    109 
    110     if (mCodecInterface == NULL) {
    111         return UNKNOWN_ERROR;
    112     }
    113     ALOGD("VP8: initEncoder. BRMode: %u. TSLayers: %zu. KF: %u. QP: %u - %u",
    114           (uint32_t)mBitrateControlMode, mTemporalLayers, mKeyFrameInterval,
    115           mMinQuantizer, mMaxQuantizer);
    116     codec_return = vpx_codec_enc_config_default(mCodecInterface,
    117                                                 mCodecConfiguration,
    118                                                 0);  // Codec specific flags
    119 
    120     if (codec_return != VPX_CODEC_OK) {
    121         ALOGE("Error populating default configuration for vpx encoder.");
    122         return UNKNOWN_ERROR;
    123     }
    124 
    125     mCodecConfiguration->g_w = mWidth;
    126     mCodecConfiguration->g_h = mHeight;
    127     mCodecConfiguration->g_threads = GetCPUCoreCount();
    128     mCodecConfiguration->g_error_resilient = mErrorResilience;
    129 
    130     switch (mLevel) {
    131         case OMX_VIDEO_VP8Level_Version0:
    132             mCodecConfiguration->g_profile = 0;
    133             break;
    134 
    135         case OMX_VIDEO_VP8Level_Version1:
    136             mCodecConfiguration->g_profile = 1;
    137             break;
    138 
    139         case OMX_VIDEO_VP8Level_Version2:
    140             mCodecConfiguration->g_profile = 2;
    141             break;
    142 
    143         case OMX_VIDEO_VP8Level_Version3:
    144             mCodecConfiguration->g_profile = 3;
    145             break;
    146 
    147         default:
    148             mCodecConfiguration->g_profile = 0;
    149     }
    150 
    151     // OMX timebase unit is microsecond
    152     // g_timebase is in seconds (i.e. 1/1000000 seconds)
    153     mCodecConfiguration->g_timebase.num = 1;
    154     mCodecConfiguration->g_timebase.den = 1000000;
    155     // rc_target_bitrate is in kbps, mBitrate in bps
    156     mCodecConfiguration->rc_target_bitrate = (mBitrate + 500) / 1000;
    157     mCodecConfiguration->rc_end_usage = mBitrateControlMode;
    158     // Disable frame drop - not allowed in MediaCodec now.
    159     mCodecConfiguration->rc_dropframe_thresh = 0;
    160     if (mBitrateControlMode == VPX_CBR) {
    161         // Disable spatial resizing.
    162         mCodecConfiguration->rc_resize_allowed = 0;
    163         // Single-pass mode.
    164         mCodecConfiguration->g_pass = VPX_RC_ONE_PASS;
    165         // Maximum amount of bits that can be subtracted from the target
    166         // bitrate - expressed as percentage of the target bitrate.
    167         mCodecConfiguration->rc_undershoot_pct = 100;
    168         // Maximum amount of bits that can be added to the target
    169         // bitrate - expressed as percentage of the target bitrate.
    170         mCodecConfiguration->rc_overshoot_pct = 15;
    171         // Initial value of the buffer level in ms.
    172         mCodecConfiguration->rc_buf_initial_sz = 500;
    173         // Amount of data that the encoder should try to maintain in ms.
    174         mCodecConfiguration->rc_buf_optimal_sz = 600;
    175         // The amount of data that may be buffered by the decoding
    176         // application in ms.
    177         mCodecConfiguration->rc_buf_sz = 1000;
    178         // Enable error resilience - needed for packet loss.
    179         mCodecConfiguration->g_error_resilient = 1;
    180         // Disable lagged encoding.
    181         mCodecConfiguration->g_lag_in_frames = 0;
    182         // Maximum key frame interval - for CBR boost to 3000
    183         mCodecConfiguration->kf_max_dist = 3000;
    184         // Encoder determines optimal key frame placement automatically.
    185         mCodecConfiguration->kf_mode = VPX_KF_AUTO;
    186     }
    187 
    188     // Frames temporal pattern - for now WebRTC like pattern is only supported.
    189     switch (mTemporalLayers) {
    190         case 0:
    191         {
    192             mTemporalPatternLength = 0;
    193             break;
    194         }
    195         case 1:
    196         {
    197             mCodecConfiguration->ts_number_layers = 1;
    198             mCodecConfiguration->ts_rate_decimator[0] = 1;
    199             mCodecConfiguration->ts_periodicity = 1;
    200             mCodecConfiguration->ts_layer_id[0] = 0;
    201             mTemporalPattern[0] = kTemporalUpdateLastRefAll;
    202             mTemporalPatternLength = 1;
    203             break;
    204         }
    205         case 2:
    206         {
    207             mCodecConfiguration->ts_number_layers = 2;
    208             mCodecConfiguration->ts_rate_decimator[0] = 2;
    209             mCodecConfiguration->ts_rate_decimator[1] = 1;
    210             mCodecConfiguration->ts_periodicity = 2;
    211             mCodecConfiguration->ts_layer_id[0] = 0;
    212             mCodecConfiguration->ts_layer_id[1] = 1;
    213             mTemporalPattern[0] = kTemporalUpdateLastAndGoldenRefAltRef;
    214             mTemporalPattern[1] = kTemporalUpdateGoldenWithoutDependencyRefAltRef;
    215             mTemporalPattern[2] = kTemporalUpdateLastRefAltRef;
    216             mTemporalPattern[3] = kTemporalUpdateGoldenRefAltRef;
    217             mTemporalPattern[4] = kTemporalUpdateLastRefAltRef;
    218             mTemporalPattern[5] = kTemporalUpdateGoldenRefAltRef;
    219             mTemporalPattern[6] = kTemporalUpdateLastRefAltRef;
    220             mTemporalPattern[7] = kTemporalUpdateNone;
    221             mTemporalPatternLength = 8;
    222             break;
    223         }
    224         case 3:
    225         {
    226             mCodecConfiguration->ts_number_layers = 3;
    227             mCodecConfiguration->ts_rate_decimator[0] = 4;
    228             mCodecConfiguration->ts_rate_decimator[1] = 2;
    229             mCodecConfiguration->ts_rate_decimator[2] = 1;
    230             mCodecConfiguration->ts_periodicity = 4;
    231             mCodecConfiguration->ts_layer_id[0] = 0;
    232             mCodecConfiguration->ts_layer_id[1] = 2;
    233             mCodecConfiguration->ts_layer_id[2] = 1;
    234             mCodecConfiguration->ts_layer_id[3] = 2;
    235             mTemporalPattern[0] = kTemporalUpdateLastAndGoldenRefAltRef;
    236             mTemporalPattern[1] = kTemporalUpdateNoneNoRefGoldenRefAltRef;
    237             mTemporalPattern[2] = kTemporalUpdateGoldenWithoutDependencyRefAltRef;
    238             mTemporalPattern[3] = kTemporalUpdateNone;
    239             mTemporalPattern[4] = kTemporalUpdateLastRefAltRef;
    240             mTemporalPattern[5] = kTemporalUpdateNone;
    241             mTemporalPattern[6] = kTemporalUpdateGoldenRefAltRef;
    242             mTemporalPattern[7] = kTemporalUpdateNone;
    243             mTemporalPatternLength = 8;
    244             break;
    245         }
    246         default:
    247         {
    248             ALOGE("Wrong number of temporal layers %zu", mTemporalLayers);
    249             return UNKNOWN_ERROR;
    250         }
    251     }
    252 
    253     // Set bitrate values for each layer
    254     for (size_t i = 0; i < mCodecConfiguration->ts_number_layers; i++) {
    255         mCodecConfiguration->ts_target_bitrate[i] =
    256             mCodecConfiguration->rc_target_bitrate *
    257             mTemporalLayerBitrateRatio[i] / 100;
    258     }
    259     if (mKeyFrameInterval > 0) {
    260         mCodecConfiguration->kf_max_dist = mKeyFrameInterval;
    261         mCodecConfiguration->kf_min_dist = mKeyFrameInterval;
    262         mCodecConfiguration->kf_mode = VPX_KF_AUTO;
    263     }
    264     if (mMinQuantizer > 0) {
    265         mCodecConfiguration->rc_min_quantizer = mMinQuantizer;
    266     }
    267     if (mMaxQuantizer > 0) {
    268         mCodecConfiguration->rc_max_quantizer = mMaxQuantizer;
    269     }
    270 
    271     codec_return = vpx_codec_enc_init(mCodecContext,
    272                                       mCodecInterface,
    273                                       mCodecConfiguration,
    274                                       0);  // flags
    275 
    276     if (codec_return != VPX_CODEC_OK) {
    277         ALOGE("Error initializing vpx encoder");
    278         return UNKNOWN_ERROR;
    279     }
    280 
    281     codec_return = vpx_codec_control(mCodecContext,
    282                                      VP8E_SET_TOKEN_PARTITIONS,
    283                                      mDCTPartitions);
    284     if (codec_return != VPX_CODEC_OK) {
    285         ALOGE("Error setting dct partitions for vpx encoder.");
    286         return UNKNOWN_ERROR;
    287     }
    288 
    289     // Extra CBR settings
    290     if (mBitrateControlMode == VPX_CBR) {
    291         codec_return = vpx_codec_control(mCodecContext,
    292                                          VP8E_SET_STATIC_THRESHOLD,
    293                                          1);
    294         if (codec_return == VPX_CODEC_OK) {
    295             uint32_t rc_max_intra_target =
    296                 mCodecConfiguration->rc_buf_optimal_sz * (mFramerate >> 17) / 10;
    297             // Don't go below 3 times per frame bandwidth.
    298             if (rc_max_intra_target < 300) {
    299                 rc_max_intra_target = 300;
    300             }
    301             codec_return = vpx_codec_control(mCodecContext,
    302                                              VP8E_SET_MAX_INTRA_BITRATE_PCT,
    303                                              rc_max_intra_target);
    304         }
    305         if (codec_return == VPX_CODEC_OK) {
    306             codec_return = vpx_codec_control(mCodecContext,
    307                                              VP8E_SET_CPUUSED,
    308                                              -8);
    309         }
    310         if (codec_return != VPX_CODEC_OK) {
    311             ALOGE("Error setting cbr parameters for vpx encoder.");
    312             return UNKNOWN_ERROR;
    313         }
    314     }
    315 
    316     if (mColorFormat != OMX_COLOR_FormatYUV420Planar || mInputDataIsMeta) {
    317         free(mConversionBuffer);
    318         mConversionBuffer = (uint8_t *)malloc(mWidth * mHeight * 3 / 2);
    319         if (mConversionBuffer == NULL) {
    320             ALOGE("Allocating conversion buffer failed.");
    321             return UNKNOWN_ERROR;
    322         }
    323     }
    324     return OK;
    325 }
    326 
    327 
    328 status_t SoftVPXEncoder::releaseEncoder() {
    329     if (mCodecContext != NULL) {
    330         vpx_codec_destroy(mCodecContext);
    331         delete mCodecContext;
    332         mCodecContext = NULL;
    333     }
    334 
    335     if (mCodecConfiguration != NULL) {
    336         delete mCodecConfiguration;
    337         mCodecConfiguration = NULL;
    338     }
    339 
    340     if (mConversionBuffer != NULL) {
    341         free(mConversionBuffer);
    342         mConversionBuffer = NULL;
    343     }
    344 
    345     // this one is not allocated by us
    346     mCodecInterface = NULL;
    347 
    348     return OK;
    349 }
    350 
    351 
    352 OMX_ERRORTYPE SoftVPXEncoder::internalGetParameter(OMX_INDEXTYPE index,
    353                                                    OMX_PTR param) {
    354     // can include extension index OMX_INDEXEXTTYPE
    355     const int32_t indexFull = index;
    356 
    357     switch (indexFull) {
    358         case OMX_IndexParamVideoBitrate: {
    359             OMX_VIDEO_PARAM_BITRATETYPE *bitrate =
    360                 (OMX_VIDEO_PARAM_BITRATETYPE *)param;
    361 
    362                 if (bitrate->nPortIndex != kOutputPortIndex) {
    363                     return OMX_ErrorUnsupportedIndex;
    364                 }
    365 
    366                 bitrate->nTargetBitrate = mBitrate;
    367 
    368                 if (mBitrateControlMode == VPX_VBR) {
    369                     bitrate->eControlRate = OMX_Video_ControlRateVariable;
    370                 } else if (mBitrateControlMode == VPX_CBR) {
    371                     bitrate->eControlRate = OMX_Video_ControlRateConstant;
    372                 } else {
    373                     return OMX_ErrorUnsupportedSetting;
    374                 }
    375                 return OMX_ErrorNone;
    376         }
    377 
    378         // VP8 specific parameters that use extension headers
    379         case OMX_IndexParamVideoVp8: {
    380             OMX_VIDEO_PARAM_VP8TYPE *vp8Params =
    381                 (OMX_VIDEO_PARAM_VP8TYPE *)param;
    382 
    383                 if (vp8Params->nPortIndex != kOutputPortIndex) {
    384                     return OMX_ErrorUnsupportedIndex;
    385                 }
    386 
    387                 vp8Params->eProfile = OMX_VIDEO_VP8ProfileMain;
    388                 vp8Params->eLevel = mLevel;
    389                 vp8Params->nDCTPartitions = mDCTPartitions;
    390                 vp8Params->bErrorResilientMode = mErrorResilience;
    391                 return OMX_ErrorNone;
    392         }
    393 
    394         case OMX_IndexParamVideoAndroidVp8Encoder: {
    395             OMX_VIDEO_PARAM_ANDROID_VP8ENCODERTYPE *vp8AndroidParams =
    396                 (OMX_VIDEO_PARAM_ANDROID_VP8ENCODERTYPE *)param;
    397 
    398                 if (vp8AndroidParams->nPortIndex != kOutputPortIndex) {
    399                     return OMX_ErrorUnsupportedIndex;
    400                 }
    401 
    402                 vp8AndroidParams->nKeyFrameInterval = mKeyFrameInterval;
    403                 vp8AndroidParams->eTemporalPattern = mTemporalPatternType;
    404                 vp8AndroidParams->nTemporalLayerCount = mTemporalLayers;
    405                 vp8AndroidParams->nMinQuantizer = mMinQuantizer;
    406                 vp8AndroidParams->nMaxQuantizer = mMaxQuantizer;
    407                 memcpy(vp8AndroidParams->nTemporalLayerBitrateRatio,
    408                        mTemporalLayerBitrateRatio, sizeof(mTemporalLayerBitrateRatio));
    409                 return OMX_ErrorNone;
    410         }
    411 
    412         default:
    413             return SoftVideoEncoderOMXComponent::internalGetParameter(index, param);
    414     }
    415 }
    416 
    417 
    418 OMX_ERRORTYPE SoftVPXEncoder::internalSetParameter(OMX_INDEXTYPE index,
    419                                                    const OMX_PTR param) {
    420     // can include extension index OMX_INDEXEXTTYPE
    421     const int32_t indexFull = index;
    422 
    423     switch (indexFull) {
    424         case OMX_IndexParamVideoBitrate:
    425             return internalSetBitrateParams(
    426                 (const OMX_VIDEO_PARAM_BITRATETYPE *)param);
    427 
    428         case OMX_IndexParamVideoVp8:
    429             return internalSetVp8Params(
    430                 (const OMX_VIDEO_PARAM_VP8TYPE *)param);
    431 
    432         case OMX_IndexParamVideoAndroidVp8Encoder:
    433             return internalSetAndroidVp8Params(
    434                 (const OMX_VIDEO_PARAM_ANDROID_VP8ENCODERTYPE *)param);
    435 
    436         default:
    437             return SoftVideoEncoderOMXComponent::internalSetParameter(index, param);
    438     }
    439 }
    440 
    441 OMX_ERRORTYPE SoftVPXEncoder::setConfig(
    442         OMX_INDEXTYPE index, const OMX_PTR _params) {
    443     switch (index) {
    444         case OMX_IndexConfigVideoIntraVOPRefresh:
    445         {
    446             OMX_CONFIG_INTRAREFRESHVOPTYPE *params =
    447                 (OMX_CONFIG_INTRAREFRESHVOPTYPE *)_params;
    448 
    449             if (params->nPortIndex != kOutputPortIndex) {
    450                 return OMX_ErrorBadPortIndex;
    451             }
    452 
    453             mKeyFrameRequested = params->IntraRefreshVOP;
    454             return OMX_ErrorNone;
    455         }
    456 
    457         case OMX_IndexConfigVideoBitrate:
    458         {
    459             OMX_VIDEO_CONFIG_BITRATETYPE *params =
    460                 (OMX_VIDEO_CONFIG_BITRATETYPE *)_params;
    461 
    462             if (params->nPortIndex != kOutputPortIndex) {
    463                 return OMX_ErrorBadPortIndex;
    464             }
    465 
    466             if (mBitrate != params->nEncodeBitrate) {
    467                 mBitrate = params->nEncodeBitrate;
    468                 mBitrateUpdated = true;
    469             }
    470             return OMX_ErrorNone;
    471         }
    472 
    473         default:
    474             return SimpleSoftOMXComponent::setConfig(index, _params);
    475     }
    476 }
    477 
    478 OMX_ERRORTYPE SoftVPXEncoder::internalSetVp8Params(
    479         const OMX_VIDEO_PARAM_VP8TYPE* vp8Params) {
    480     if (vp8Params->nPortIndex != kOutputPortIndex) {
    481         return OMX_ErrorUnsupportedIndex;
    482     }
    483 
    484     if (vp8Params->eProfile != OMX_VIDEO_VP8ProfileMain) {
    485         return OMX_ErrorBadParameter;
    486     }
    487 
    488     if (vp8Params->eLevel == OMX_VIDEO_VP8Level_Version0 ||
    489         vp8Params->eLevel == OMX_VIDEO_VP8Level_Version1 ||
    490         vp8Params->eLevel == OMX_VIDEO_VP8Level_Version2 ||
    491         vp8Params->eLevel == OMX_VIDEO_VP8Level_Version3) {
    492         mLevel = vp8Params->eLevel;
    493     } else {
    494         return OMX_ErrorBadParameter;
    495     }
    496 
    497     if (vp8Params->nDCTPartitions <= kMaxDCTPartitions) {
    498         mDCTPartitions = vp8Params->nDCTPartitions;
    499     } else {
    500         return OMX_ErrorBadParameter;
    501     }
    502 
    503     mErrorResilience = vp8Params->bErrorResilientMode;
    504     return OMX_ErrorNone;
    505 }
    506 
    507 OMX_ERRORTYPE SoftVPXEncoder::internalSetAndroidVp8Params(
    508         const OMX_VIDEO_PARAM_ANDROID_VP8ENCODERTYPE* vp8AndroidParams) {
    509     if (vp8AndroidParams->nPortIndex != kOutputPortIndex) {
    510         return OMX_ErrorUnsupportedIndex;
    511     }
    512     if (vp8AndroidParams->eTemporalPattern != OMX_VIDEO_VPXTemporalLayerPatternNone &&
    513         vp8AndroidParams->eTemporalPattern != OMX_VIDEO_VPXTemporalLayerPatternWebRTC) {
    514         return OMX_ErrorBadParameter;
    515     }
    516     if (vp8AndroidParams->nTemporalLayerCount > OMX_VIDEO_ANDROID_MAXVP8TEMPORALLAYERS) {
    517         return OMX_ErrorBadParameter;
    518     }
    519     if (vp8AndroidParams->nMinQuantizer > vp8AndroidParams->nMaxQuantizer) {
    520         return OMX_ErrorBadParameter;
    521     }
    522 
    523     mTemporalPatternType = vp8AndroidParams->eTemporalPattern;
    524     if (vp8AndroidParams->eTemporalPattern == OMX_VIDEO_VPXTemporalLayerPatternWebRTC) {
    525         mTemporalLayers = vp8AndroidParams->nTemporalLayerCount;
    526     } else if (vp8AndroidParams->eTemporalPattern == OMX_VIDEO_VPXTemporalLayerPatternNone) {
    527         mTemporalLayers = 0;
    528     }
    529     // Check the bitrate distribution between layers is in increasing order
    530     if (mTemporalLayers > 1) {
    531         for (size_t i = 0; i < mTemporalLayers - 1; i++) {
    532             if (vp8AndroidParams->nTemporalLayerBitrateRatio[i + 1] <=
    533                     vp8AndroidParams->nTemporalLayerBitrateRatio[i]) {
    534                 ALOGE("Wrong bitrate ratio - should be in increasing order.");
    535                 return OMX_ErrorBadParameter;
    536             }
    537         }
    538     }
    539     mKeyFrameInterval = vp8AndroidParams->nKeyFrameInterval;
    540     mMinQuantizer = vp8AndroidParams->nMinQuantizer;
    541     mMaxQuantizer = vp8AndroidParams->nMaxQuantizer;
    542     memcpy(mTemporalLayerBitrateRatio, vp8AndroidParams->nTemporalLayerBitrateRatio,
    543             sizeof(mTemporalLayerBitrateRatio));
    544     ALOGD("VP8: internalSetAndroidVp8Params. BRMode: %u. TS: %zu. KF: %u."
    545           " QP: %u - %u BR0: %u. BR1: %u. BR2: %u",
    546           (uint32_t)mBitrateControlMode, mTemporalLayers, mKeyFrameInterval,
    547           mMinQuantizer, mMaxQuantizer, mTemporalLayerBitrateRatio[0],
    548           mTemporalLayerBitrateRatio[1], mTemporalLayerBitrateRatio[2]);
    549     return OMX_ErrorNone;
    550 }
    551 
    552 OMX_ERRORTYPE SoftVPXEncoder::internalSetBitrateParams(
    553         const OMX_VIDEO_PARAM_BITRATETYPE* bitrate) {
    554     if (bitrate->nPortIndex != kOutputPortIndex) {
    555         return OMX_ErrorUnsupportedIndex;
    556     }
    557 
    558     mBitrate = bitrate->nTargetBitrate;
    559 
    560     if (bitrate->eControlRate == OMX_Video_ControlRateVariable) {
    561         mBitrateControlMode = VPX_VBR;
    562     } else if (bitrate->eControlRate == OMX_Video_ControlRateConstant) {
    563         mBitrateControlMode = VPX_CBR;
    564     } else {
    565         return OMX_ErrorUnsupportedSetting;
    566     }
    567 
    568     return OMX_ErrorNone;
    569 }
    570 
    571 vpx_enc_frame_flags_t SoftVPXEncoder::getEncodeFlags() {
    572     vpx_enc_frame_flags_t flags = 0;
    573     int patternIdx = mTemporalPatternIdx % mTemporalPatternLength;
    574     mTemporalPatternIdx++;
    575     switch (mTemporalPattern[patternIdx]) {
    576         case kTemporalUpdateLast:
    577             flags |= VP8_EFLAG_NO_UPD_GF;
    578             flags |= VP8_EFLAG_NO_UPD_ARF;
    579             flags |= VP8_EFLAG_NO_REF_GF;
    580             flags |= VP8_EFLAG_NO_REF_ARF;
    581             break;
    582         case kTemporalUpdateGoldenWithoutDependency:
    583             flags |= VP8_EFLAG_NO_REF_GF;
    584             // Deliberately no break here.
    585         case kTemporalUpdateGolden:
    586             flags |= VP8_EFLAG_NO_REF_ARF;
    587             flags |= VP8_EFLAG_NO_UPD_ARF;
    588             flags |= VP8_EFLAG_NO_UPD_LAST;
    589             break;
    590         case kTemporalUpdateAltrefWithoutDependency:
    591             flags |= VP8_EFLAG_NO_REF_ARF;
    592             flags |= VP8_EFLAG_NO_REF_GF;
    593             // Deliberately no break here.
    594         case kTemporalUpdateAltref:
    595             flags |= VP8_EFLAG_NO_UPD_GF;
    596             flags |= VP8_EFLAG_NO_UPD_LAST;
    597             break;
    598         case kTemporalUpdateNoneNoRefAltref:
    599             flags |= VP8_EFLAG_NO_REF_ARF;
    600             // Deliberately no break here.
    601         case kTemporalUpdateNone:
    602             flags |= VP8_EFLAG_NO_UPD_GF;
    603             flags |= VP8_EFLAG_NO_UPD_ARF;
    604             flags |= VP8_EFLAG_NO_UPD_LAST;
    605             flags |= VP8_EFLAG_NO_UPD_ENTROPY;
    606             break;
    607         case kTemporalUpdateNoneNoRefGoldenRefAltRef:
    608             flags |= VP8_EFLAG_NO_REF_GF;
    609             flags |= VP8_EFLAG_NO_UPD_GF;
    610             flags |= VP8_EFLAG_NO_UPD_ARF;
    611             flags |= VP8_EFLAG_NO_UPD_LAST;
    612             flags |= VP8_EFLAG_NO_UPD_ENTROPY;
    613             break;
    614         case kTemporalUpdateGoldenWithoutDependencyRefAltRef:
    615             flags |= VP8_EFLAG_NO_REF_GF;
    616             flags |= VP8_EFLAG_NO_UPD_ARF;
    617             flags |= VP8_EFLAG_NO_UPD_LAST;
    618             break;
    619         case kTemporalUpdateLastRefAltRef:
    620             flags |= VP8_EFLAG_NO_UPD_GF;
    621             flags |= VP8_EFLAG_NO_UPD_ARF;
    622             flags |= VP8_EFLAG_NO_REF_GF;
    623             break;
    624         case kTemporalUpdateGoldenRefAltRef:
    625             flags |= VP8_EFLAG_NO_UPD_ARF;
    626             flags |= VP8_EFLAG_NO_UPD_LAST;
    627             break;
    628         case kTemporalUpdateLastAndGoldenRefAltRef:
    629             flags |= VP8_EFLAG_NO_UPD_ARF;
    630             flags |= VP8_EFLAG_NO_REF_GF;
    631             break;
    632         case kTemporalUpdateLastRefAll:
    633             flags |= VP8_EFLAG_NO_UPD_ARF;
    634             flags |= VP8_EFLAG_NO_UPD_GF;
    635             break;
    636     }
    637     return flags;
    638 }
    639 
    640 void SoftVPXEncoder::onQueueFilled(OMX_U32 /* portIndex */) {
    641     // Initialize encoder if not already
    642     if (mCodecContext == NULL) {
    643         if (OK != initEncoder()) {
    644             ALOGE("Failed to initialize encoder");
    645             notify(OMX_EventError,
    646                    OMX_ErrorUndefined,
    647                    0,  // Extra notification data
    648                    NULL);  // Notification data pointer
    649             return;
    650         }
    651     }
    652 
    653     vpx_codec_err_t codec_return;
    654     List<BufferInfo *> &inputBufferInfoQueue = getPortQueue(kInputPortIndex);
    655     List<BufferInfo *> &outputBufferInfoQueue = getPortQueue(kOutputPortIndex);
    656 
    657     while (!inputBufferInfoQueue.empty() && !outputBufferInfoQueue.empty()) {
    658         BufferInfo *inputBufferInfo = *inputBufferInfoQueue.begin();
    659         OMX_BUFFERHEADERTYPE *inputBufferHeader = inputBufferInfo->mHeader;
    660 
    661         BufferInfo *outputBufferInfo = *outputBufferInfoQueue.begin();
    662         OMX_BUFFERHEADERTYPE *outputBufferHeader = outputBufferInfo->mHeader;
    663 
    664         if (inputBufferHeader->nFlags & OMX_BUFFERFLAG_EOS) {
    665             inputBufferInfoQueue.erase(inputBufferInfoQueue.begin());
    666             inputBufferInfo->mOwnedByUs = false;
    667             notifyEmptyBufferDone(inputBufferHeader);
    668 
    669             outputBufferHeader->nFilledLen = 0;
    670             outputBufferHeader->nFlags = OMX_BUFFERFLAG_EOS;
    671 
    672             outputBufferInfoQueue.erase(outputBufferInfoQueue.begin());
    673             outputBufferInfo->mOwnedByUs = false;
    674             notifyFillBufferDone(outputBufferHeader);
    675             return;
    676         }
    677 
    678         const uint8_t *source =
    679             inputBufferHeader->pBuffer + inputBufferHeader->nOffset;
    680 
    681         if (mInputDataIsMeta) {
    682             source = extractGraphicBuffer(
    683                     mConversionBuffer, mWidth * mHeight * 3 / 2,
    684                     source, inputBufferHeader->nFilledLen,
    685                     mWidth, mHeight);
    686             if (source == NULL) {
    687                 ALOGE("Unable to extract gralloc buffer in metadata mode");
    688                 notify(OMX_EventError, OMX_ErrorUndefined, 0, 0);
    689                 return;
    690             }
    691         } else if (mColorFormat == OMX_COLOR_FormatYUV420SemiPlanar) {
    692             ConvertYUV420SemiPlanarToYUV420Planar(
    693                     source, mConversionBuffer, mWidth, mHeight);
    694 
    695             source = mConversionBuffer;
    696         }
    697         vpx_image_t raw_frame;
    698         vpx_img_wrap(&raw_frame, VPX_IMG_FMT_I420, mWidth, mHeight,
    699                      kInputBufferAlignment, (uint8_t *)source);
    700 
    701         vpx_enc_frame_flags_t flags = 0;
    702         if (mTemporalPatternLength > 0) {
    703             flags = getEncodeFlags();
    704         }
    705         if (mKeyFrameRequested) {
    706             flags |= VPX_EFLAG_FORCE_KF;
    707             mKeyFrameRequested = false;
    708         }
    709 
    710         if (mBitrateUpdated) {
    711             mCodecConfiguration->rc_target_bitrate = mBitrate/1000;
    712             vpx_codec_err_t res = vpx_codec_enc_config_set(mCodecContext,
    713                                                            mCodecConfiguration);
    714             if (res != VPX_CODEC_OK) {
    715                 ALOGE("vp8 encoder failed to update bitrate: %s",
    716                       vpx_codec_err_to_string(res));
    717                 notify(OMX_EventError,
    718                        OMX_ErrorUndefined,
    719                        0, // Extra notification data
    720                        NULL); // Notification data pointer
    721             }
    722             mBitrateUpdated = false;
    723         }
    724 
    725         uint32_t frameDuration;
    726         if (inputBufferHeader->nTimeStamp > mLastTimestamp) {
    727             frameDuration = (uint32_t)(inputBufferHeader->nTimeStamp - mLastTimestamp);
    728         } else {
    729             frameDuration = (uint32_t)(((uint64_t)1000000 << 16) / mFramerate);
    730         }
    731         mLastTimestamp = inputBufferHeader->nTimeStamp;
    732         codec_return = vpx_codec_encode(
    733                 mCodecContext,
    734                 &raw_frame,
    735                 inputBufferHeader->nTimeStamp,  // in timebase units
    736                 frameDuration,  // frame duration in timebase units
    737                 flags,  // frame flags
    738                 VPX_DL_REALTIME);  // encoding deadline
    739         if (codec_return != VPX_CODEC_OK) {
    740             ALOGE("vpx encoder failed to encode frame");
    741             notify(OMX_EventError,
    742                    OMX_ErrorUndefined,
    743                    0,  // Extra notification data
    744                    NULL);  // Notification data pointer
    745             return;
    746         }
    747 
    748         vpx_codec_iter_t encoded_packet_iterator = NULL;
    749         const vpx_codec_cx_pkt_t* encoded_packet;
    750 
    751         while ((encoded_packet = vpx_codec_get_cx_data(
    752                         mCodecContext, &encoded_packet_iterator))) {
    753             if (encoded_packet->kind == VPX_CODEC_CX_FRAME_PKT) {
    754                 outputBufferHeader->nTimeStamp = encoded_packet->data.frame.pts;
    755                 outputBufferHeader->nFlags = 0;
    756                 if (encoded_packet->data.frame.flags & VPX_FRAME_IS_KEY)
    757                   outputBufferHeader->nFlags |= OMX_BUFFERFLAG_SYNCFRAME;
    758                 outputBufferHeader->nOffset = 0;
    759                 outputBufferHeader->nFilledLen = encoded_packet->data.frame.sz;
    760                 memcpy(outputBufferHeader->pBuffer,
    761                        encoded_packet->data.frame.buf,
    762                        encoded_packet->data.frame.sz);
    763                 outputBufferInfo->mOwnedByUs = false;
    764                 outputBufferInfoQueue.erase(outputBufferInfoQueue.begin());
    765                 notifyFillBufferDone(outputBufferHeader);
    766             }
    767         }
    768 
    769         inputBufferInfo->mOwnedByUs = false;
    770         inputBufferInfoQueue.erase(inputBufferInfoQueue.begin());
    771         notifyEmptyBufferDone(inputBufferHeader);
    772     }
    773 }
    774 
    775 }  // namespace android
    776 
    777 
    778 android::SoftOMXComponent *createSoftOMXComponent(
    779         const char *name, const OMX_CALLBACKTYPE *callbacks,
    780         OMX_PTR appData, OMX_COMPONENTTYPE **component) {
    781     return new android::SoftVPXEncoder(name, callbacks, appData, component);
    782 }
    783