Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 67ee990d authored by Alex Glaznev's avatar Alex Glaznev Committed by Android (Google) Code Review
Browse files

Merge "Support VP8 encoder key frame interval and number of temporal layers configuration."

parents e2731412 4154795d
Loading
Loading
Loading
Loading
+70 −0
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@
#include <media/hardware/HardwareAPI.h>

#include <OMX_AudioExt.h>
#include <OMX_VideoExt.h>
#include <OMX_Component.h>
#include <OMX_IndexExt.h>

@@ -2370,12 +2371,81 @@ status_t ACodec::setupAVCEncoderParameters(const sp<AMessage> &msg) {

status_t ACodec::setupVPXEncoderParameters(const sp<AMessage> &msg) {
    int32_t bitrate;
    int32_t iFrameInterval = 0;
    size_t tsLayers = 0;
    OMX_VIDEO_ANDROID_VPXTEMPORALLAYERPATTERNTYPE pattern =
        OMX_VIDEO_VPXTemporalLayerPatternNone;
    static const uint32_t kVp8LayerRateAlloction
        [OMX_VIDEO_ANDROID_MAXVP8TEMPORALLAYERS]
        [OMX_VIDEO_ANDROID_MAXVP8TEMPORALLAYERS] = {
        {100, 100, 100},  // 1 layer
        { 60, 100, 100},  // 2 layers {60%, 40%}
        { 40,  60, 100},  // 3 layers {40%, 20%, 40%}
    };
    if (!msg->findInt32("bitrate", &bitrate)) {
        return INVALID_OPERATION;
    }
    msg->findInt32("i-frame-interval", &iFrameInterval);

    OMX_VIDEO_CONTROLRATETYPE bitrateMode = getBitrateMode(msg);

    float frameRate;
    if (!msg->findFloat("frame-rate", &frameRate)) {
        int32_t tmp;
        if (!msg->findInt32("frame-rate", &tmp)) {
            return INVALID_OPERATION;
        }
        frameRate = (float)tmp;
    }

    AString tsSchema;
    if (msg->findString("ts-schema", &tsSchema)) {
        if (tsSchema == "webrtc.vp8.1-layer") {
            pattern = OMX_VIDEO_VPXTemporalLayerPatternWebRTC;
            tsLayers = 1;
        } else if (tsSchema == "webrtc.vp8.2-layer") {
            pattern = OMX_VIDEO_VPXTemporalLayerPatternWebRTC;
            tsLayers = 2;
        } else if (tsSchema == "webrtc.vp8.3-layer") {
            pattern = OMX_VIDEO_VPXTemporalLayerPatternWebRTC;
            tsLayers = 3;
        } else {
            ALOGW("Unsupported ts-schema [%s]", tsSchema.c_str());
        }
    }

    OMX_VIDEO_PARAM_ANDROID_VP8ENCODERTYPE vp8type;
    InitOMXParams(&vp8type);
    vp8type.nPortIndex = kPortIndexOutput;
    status_t err = mOMX->getParameter(
            mNode, (OMX_INDEXTYPE)OMX_IndexParamVideoAndroidVp8Encoder,
            &vp8type, sizeof(vp8type));

    if (err == OK) {
        if (iFrameInterval > 0) {
            vp8type.nKeyFrameInterval = setPFramesSpacing(iFrameInterval, frameRate);
        }
        vp8type.eTemporalPattern = pattern;
        vp8type.nTemporalLayerCount = tsLayers;
        if (tsLayers > 0) {
            for (size_t i = 0; i < OMX_VIDEO_ANDROID_MAXVP8TEMPORALLAYERS; i++) {
                vp8type.nTemporalLayerBitrateRatio[i] =
                    kVp8LayerRateAlloction[tsLayers - 1][i];
            }
        }
        if (bitrateMode == OMX_Video_ControlRateConstant) {
            vp8type.nMinQuantizer = 2;
            vp8type.nMaxQuantizer = 63;
        }

        err = mOMX->setParameter(
                mNode, (OMX_INDEXTYPE)OMX_IndexParamVideoAndroidVp8Encoder,
                &vp8type, sizeof(vp8type));
        if (err != OK) {
            ALOGW("Extended VP8 parameters set failed: %d", err);
        }
    }

    return configureBitrate(bitrate, bitrateMode);
}

+246 −12
Original line number Diff line number Diff line
@@ -27,7 +27,6 @@

namespace android {


template<class T>
static void InitOMXParams(T *params) {
    params->nSize = sizeof(T);
@@ -148,10 +147,20 @@ SoftVPXEncoder::SoftVPXEncoder(const char *name,
      mErrorResilience(OMX_FALSE),
      mColorFormat(OMX_COLOR_FormatYUV420Planar),
      mLevel(OMX_VIDEO_VP8Level_Version0),
      mKeyFrameInterval(0),
      mMinQuantizer(0),
      mMaxQuantizer(0),
      mTemporalLayers(0),
      mTemporalPatternType(OMX_VIDEO_VPXTemporalLayerPatternNone),
      mTemporalPatternLength(0),
      mTemporalPatternIdx(0),
      mLastTimestamp(0x7FFFFFFFFFFFFFFFLL),
      mConversionBuffer(NULL),
      mInputDataIsMeta(false),
      mGrallocModule(NULL),
      mKeyFrameRequested(false) {
    memset(mTemporalLayerBitrateRatio, 0, sizeof(mTemporalLayerBitrateRatio));
    mTemporalLayerBitrateRatio[0] = 100;
    initPorts();
}

@@ -235,7 +244,9 @@ status_t SoftVPXEncoder::initEncoder() {
    if (mCodecInterface == NULL) {
        return UNKNOWN_ERROR;
    }

    ALOGD("VP8: initEncoder. BRMode: %u. TSLayers: %zu. KF: %u. QP: %u - %u",
          (uint32_t)mBitrateControlMode, mTemporalLayers, mKeyFrameInterval,
          mMinQuantizer, mMaxQuantizer);
    codec_return = vpx_codec_enc_config_default(mCodecInterface,
                                                mCodecConfiguration,
                                                0);  // Codec specific flags
@@ -276,7 +287,7 @@ status_t SoftVPXEncoder::initEncoder() {
    mCodecConfiguration->g_timebase.num = 1;
    mCodecConfiguration->g_timebase.den = 1000000;
    // rc_target_bitrate is in kbps, mBitrate in bps
    mCodecConfiguration->rc_target_bitrate = mBitrate / 1000;
    mCodecConfiguration->rc_target_bitrate = (mBitrate + 500) / 1000;
    mCodecConfiguration->rc_end_usage = mBitrateControlMode;
    // Disable frame drop - not allowed in MediaCodec now.
    mCodecConfiguration->rc_dropframe_thresh = 0;
@@ -285,10 +296,6 @@ status_t SoftVPXEncoder::initEncoder() {
        mCodecConfiguration->rc_resize_allowed = 0;
        // Single-pass mode.
        mCodecConfiguration->g_pass = VPX_RC_ONE_PASS;
        // Minimum quantization level.
        mCodecConfiguration->rc_min_quantizer = 2;
        // Maximum quantization level.
        mCodecConfiguration->rc_max_quantizer = 63;
        // Maximum amount of bits that can be subtracted from the target
        // bitrate - expressed as percentage of the target bitrate.
        mCodecConfiguration->rc_undershoot_pct = 100;
@@ -306,10 +313,95 @@ status_t SoftVPXEncoder::initEncoder() {
        mCodecConfiguration->g_error_resilient = 1;
        // Disable lagged encoding.
        mCodecConfiguration->g_lag_in_frames = 0;
        // Maximum key frame interval - for CBR boost to 3000
        mCodecConfiguration->kf_max_dist = 3000;
        // Encoder determines optimal key frame placement automatically.
        mCodecConfiguration->kf_mode = VPX_KF_AUTO;
    }

    // Frames temporal pattern - for now WebRTC like pattern is only supported.
    switch (mTemporalLayers) {
        case 0:
        {
            mTemporalPatternLength = 0;
            break;
        }
        case 1:
        {
            mCodecConfiguration->ts_number_layers = 1;
            mCodecConfiguration->ts_rate_decimator[0] = 1;
            mCodecConfiguration->ts_periodicity = 1;
            mCodecConfiguration->ts_layer_id[0] = 0;
            mTemporalPattern[0] = kTemporalUpdateLastRefAll;
            mTemporalPatternLength = 1;
            break;
        }
        case 2:
        {
            mCodecConfiguration->ts_number_layers = 2;
            mCodecConfiguration->ts_rate_decimator[0] = 2;
            mCodecConfiguration->ts_rate_decimator[1] = 1;
            mCodecConfiguration->ts_periodicity = 2;
            mCodecConfiguration->ts_layer_id[0] = 0;
            mCodecConfiguration->ts_layer_id[1] = 1;
            mTemporalPattern[0] = kTemporalUpdateLastAndGoldenRefAltRef;
            mTemporalPattern[1] = kTemporalUpdateGoldenWithoutDependencyRefAltRef;
            mTemporalPattern[2] = kTemporalUpdateLastRefAltRef;
            mTemporalPattern[3] = kTemporalUpdateGoldenRefAltRef;
            mTemporalPattern[4] = kTemporalUpdateLastRefAltRef;
            mTemporalPattern[5] = kTemporalUpdateGoldenRefAltRef;
            mTemporalPattern[6] = kTemporalUpdateLastRefAltRef;
            mTemporalPattern[7] = kTemporalUpdateNone;
            mTemporalPatternLength = 8;
            break;
        }
        case 3:
        {
            mCodecConfiguration->ts_number_layers = 3;
            mCodecConfiguration->ts_rate_decimator[0] = 4;
            mCodecConfiguration->ts_rate_decimator[1] = 2;
            mCodecConfiguration->ts_rate_decimator[2] = 1;
            mCodecConfiguration->ts_periodicity = 4;
            mCodecConfiguration->ts_layer_id[0] = 0;
            mCodecConfiguration->ts_layer_id[1] = 2;
            mCodecConfiguration->ts_layer_id[2] = 1;
            mCodecConfiguration->ts_layer_id[3] = 2;
            mTemporalPattern[0] = kTemporalUpdateLastAndGoldenRefAltRef;
            mTemporalPattern[1] = kTemporalUpdateNoneNoRefGoldenRefAltRef;
            mTemporalPattern[2] = kTemporalUpdateGoldenWithoutDependencyRefAltRef;
            mTemporalPattern[3] = kTemporalUpdateNone;
            mTemporalPattern[4] = kTemporalUpdateLastRefAltRef;
            mTemporalPattern[5] = kTemporalUpdateNone;
            mTemporalPattern[6] = kTemporalUpdateGoldenRefAltRef;
            mTemporalPattern[7] = kTemporalUpdateNone;
            mTemporalPatternLength = 8;
            break;
        }
        default:
        {
            ALOGE("Wrong number of temporal layers %u", mTemporalLayers);
            return UNKNOWN_ERROR;
        }
    }

    // Set bitrate values for each layer
    for (size_t i = 0; i < mCodecConfiguration->ts_number_layers; i++) {
        mCodecConfiguration->ts_target_bitrate[i] =
            mCodecConfiguration->rc_target_bitrate *
            mTemporalLayerBitrateRatio[i] / 100;
    }
    if (mKeyFrameInterval > 0) {
        mCodecConfiguration->kf_max_dist = mKeyFrameInterval;
        mCodecConfiguration->kf_min_dist = mKeyFrameInterval;
        mCodecConfiguration->kf_mode = VPX_KF_AUTO;
    }
    if (mMinQuantizer > 0) {
        mCodecConfiguration->rc_min_quantizer = mMinQuantizer;
    }
    if (mMaxQuantizer > 0) {
        mCodecConfiguration->rc_max_quantizer = mMaxQuantizer;
    }

    codec_return = vpx_codec_enc_init(mCodecContext,
                                      mCodecInterface,
                                      mCodecConfiguration,
@@ -466,6 +558,24 @@ OMX_ERRORTYPE SoftVPXEncoder::internalGetParameter(OMX_INDEXTYPE index,
                return OMX_ErrorNone;
        }

        case OMX_IndexParamVideoAndroidVp8Encoder: {
            OMX_VIDEO_PARAM_ANDROID_VP8ENCODERTYPE *vp8AndroidParams =
                (OMX_VIDEO_PARAM_ANDROID_VP8ENCODERTYPE *)param;

                if (vp8AndroidParams->nPortIndex != kOutputPortIndex) {
                    return OMX_ErrorUnsupportedIndex;
                }

                vp8AndroidParams->nKeyFrameInterval = mKeyFrameInterval;
                vp8AndroidParams->eTemporalPattern = mTemporalPatternType;
                vp8AndroidParams->nTemporalLayerCount = mTemporalLayers;
                vp8AndroidParams->nMinQuantizer = mMinQuantizer;
                vp8AndroidParams->nMaxQuantizer = mMaxQuantizer;
                memcpy(vp8AndroidParams->nTemporalLayerBitrateRatio,
                       mTemporalLayerBitrateRatio, sizeof(mTemporalLayerBitrateRatio));
                return OMX_ErrorNone;
        }

        case OMX_IndexParamVideoProfileLevelQuerySupported: {
            OMX_VIDEO_PARAM_PROFILELEVELTYPE *profileAndLevel =
                (OMX_VIDEO_PARAM_PROFILELEVELTYPE *)param;
@@ -552,11 +662,15 @@ OMX_ERRORTYPE SoftVPXEncoder::internalSetParameter(OMX_INDEXTYPE index,
            return internalSetVp8Params(
                (const OMX_VIDEO_PARAM_VP8TYPE *)param);

        case OMX_IndexParamVideoAndroidVp8Encoder:
            return internalSetAndroidVp8Params(
                (const OMX_VIDEO_PARAM_ANDROID_VP8ENCODERTYPE *)param);

        case OMX_IndexParamVideoProfileLevelCurrent:
            return internalSetProfileLevel(
                (const OMX_VIDEO_PARAM_PROFILELEVELTYPE *)param);

        case OMX_IndexVendorStartUnused:
        case kStoreMetaDataExtensionIndex:
        {
            // storeMetaDataInBuffers
            const StoreMetaDataInBuffersParams *storeParam =
@@ -665,6 +779,50 @@ OMX_ERRORTYPE SoftVPXEncoder::internalSetVp8Params(
    return OMX_ErrorNone;
}

OMX_ERRORTYPE SoftVPXEncoder::internalSetAndroidVp8Params(
        const OMX_VIDEO_PARAM_ANDROID_VP8ENCODERTYPE* vp8AndroidParams) {
    if (vp8AndroidParams->nPortIndex != kOutputPortIndex) {
        return OMX_ErrorUnsupportedIndex;
    }
    if (vp8AndroidParams->eTemporalPattern != OMX_VIDEO_VPXTemporalLayerPatternNone &&
        vp8AndroidParams->eTemporalPattern != OMX_VIDEO_VPXTemporalLayerPatternWebRTC) {
        return OMX_ErrorBadParameter;
    }
    if (vp8AndroidParams->nTemporalLayerCount > OMX_VIDEO_ANDROID_MAXVP8TEMPORALLAYERS) {
        return OMX_ErrorBadParameter;
    }
    if (vp8AndroidParams->nMinQuantizer > vp8AndroidParams->nMaxQuantizer) {
        return OMX_ErrorBadParameter;
    }

    mTemporalPatternType = vp8AndroidParams->eTemporalPattern;
    if (vp8AndroidParams->eTemporalPattern == OMX_VIDEO_VPXTemporalLayerPatternWebRTC) {
        mTemporalLayers = vp8AndroidParams->nTemporalLayerCount;
    } else if (vp8AndroidParams->eTemporalPattern == OMX_VIDEO_VPXTemporalLayerPatternNone) {
        mTemporalLayers = 0;
    }
    // Check the bitrate distribution between layers is in increasing order
    if (mTemporalLayers > 1) {
        for (size_t i = 0; i < mTemporalLayers - 1; i++) {
            if (vp8AndroidParams->nTemporalLayerBitrateRatio[i + 1] <=
                    vp8AndroidParams->nTemporalLayerBitrateRatio[i]) {
                ALOGE("Wrong bitrate ratio - should be in increasing order.");
                return OMX_ErrorBadParameter;
            }
        }
    }
    mKeyFrameInterval = vp8AndroidParams->nKeyFrameInterval;
    mMinQuantizer = vp8AndroidParams->nMinQuantizer;
    mMaxQuantizer = vp8AndroidParams->nMaxQuantizer;
    memcpy(mTemporalLayerBitrateRatio, vp8AndroidParams->nTemporalLayerBitrateRatio,
            sizeof(mTemporalLayerBitrateRatio));
    ALOGD("VP8: internalSetAndroidVp8Params. BRMode: %u. TS: %zu. KF: %u."
          " QP: %u - %u BR0: %u. BR1: %u. BR2: %u",
          (uint32_t)mBitrateControlMode, mTemporalLayers, mKeyFrameInterval,
          mMinQuantizer, mMaxQuantizer, mTemporalLayerBitrateRatio[0],
          mTemporalLayerBitrateRatio[1], mTemporalLayerBitrateRatio[2]);
    return OMX_ErrorNone;
}

OMX_ERRORTYPE SoftVPXEncoder::internalSetFormatParams(
        const OMX_VIDEO_PARAM_PORTFORMATTYPE* format) {
@@ -728,7 +886,7 @@ OMX_ERRORTYPE SoftVPXEncoder::internalSetPortParams(
        OMX_PARAM_PORTDEFINITIONTYPE *def = &editPortInfo(kInputPortIndex)->mDef;
        def->format.video.nFrameWidth = mWidth;
        def->format.video.nFrameHeight = mHeight;
        def->format.video.xFramerate = port->format.video.xFramerate;
        def->format.video.xFramerate = mFramerate;
        def->format.video.eColorFormat = mColorFormat;
        def = &editPortInfo(kOutputPortIndex)->mDef;
        def->format.video.nFrameWidth = mWidth;
@@ -770,6 +928,74 @@ OMX_ERRORTYPE SoftVPXEncoder::internalSetBitrateParams(
    return OMX_ErrorNone;
}

vpx_enc_frame_flags_t SoftVPXEncoder::getEncodeFlags() {
    vpx_enc_frame_flags_t flags = 0;
    int patternIdx = mTemporalPatternIdx % mTemporalPatternLength;
    mTemporalPatternIdx++;
    switch (mTemporalPattern[patternIdx]) {
        case kTemporalUpdateLast:
            flags |= VP8_EFLAG_NO_UPD_GF;
            flags |= VP8_EFLAG_NO_UPD_ARF;
            flags |= VP8_EFLAG_NO_REF_GF;
            flags |= VP8_EFLAG_NO_REF_ARF;
            break;
        case kTemporalUpdateGoldenWithoutDependency:
            flags |= VP8_EFLAG_NO_REF_GF;
            // Deliberately no break here.
        case kTemporalUpdateGolden:
            flags |= VP8_EFLAG_NO_REF_ARF;
            flags |= VP8_EFLAG_NO_UPD_ARF;
            flags |= VP8_EFLAG_NO_UPD_LAST;
            break;
        case kTemporalUpdateAltrefWithoutDependency:
            flags |= VP8_EFLAG_NO_REF_ARF;
            flags |= VP8_EFLAG_NO_REF_GF;
            // Deliberately no break here.
        case kTemporalUpdateAltref:
            flags |= VP8_EFLAG_NO_UPD_GF;
            flags |= VP8_EFLAG_NO_UPD_LAST;
            break;
        case kTemporalUpdateNoneNoRefAltref:
            flags |= VP8_EFLAG_NO_REF_ARF;
            // Deliberately no break here.
        case kTemporalUpdateNone:
            flags |= VP8_EFLAG_NO_UPD_GF;
            flags |= VP8_EFLAG_NO_UPD_ARF;
            flags |= VP8_EFLAG_NO_UPD_LAST;
            flags |= VP8_EFLAG_NO_UPD_ENTROPY;
            break;
        case kTemporalUpdateNoneNoRefGoldenRefAltRef:
            flags |= VP8_EFLAG_NO_REF_GF;
            flags |= VP8_EFLAG_NO_UPD_GF;
            flags |= VP8_EFLAG_NO_UPD_ARF;
            flags |= VP8_EFLAG_NO_UPD_LAST;
            flags |= VP8_EFLAG_NO_UPD_ENTROPY;
            break;
        case kTemporalUpdateGoldenWithoutDependencyRefAltRef:
            flags |= VP8_EFLAG_NO_REF_GF;
            flags |= VP8_EFLAG_NO_UPD_ARF;
            flags |= VP8_EFLAG_NO_UPD_LAST;
            break;
        case kTemporalUpdateLastRefAltRef:
            flags |= VP8_EFLAG_NO_UPD_GF;
            flags |= VP8_EFLAG_NO_UPD_ARF;
            flags |= VP8_EFLAG_NO_REF_GF;
            break;
        case kTemporalUpdateGoldenRefAltRef:
            flags |= VP8_EFLAG_NO_UPD_ARF;
            flags |= VP8_EFLAG_NO_UPD_LAST;
            break;
        case kTemporalUpdateLastAndGoldenRefAltRef:
            flags |= VP8_EFLAG_NO_UPD_ARF;
            flags |= VP8_EFLAG_NO_REF_GF;
            break;
        case kTemporalUpdateLastRefAll:
            flags |= VP8_EFLAG_NO_UPD_ARF;
            flags |= VP8_EFLAG_NO_UPD_GF;
            break;
    }
    return flags;
}

void SoftVPXEncoder::onQueueFilled(OMX_U32 portIndex) {
    // Initialize encoder if not already
@@ -854,6 +1080,9 @@ void SoftVPXEncoder::onQueueFilled(OMX_U32 portIndex) {
                     kInputBufferAlignment, source);

        vpx_enc_frame_flags_t flags = 0;
        if (mTemporalPatternLength > 0) {
            flags = getEncodeFlags();
        }
        if (mKeyFrameRequested) {
            flags |= VPX_EFLAG_FORCE_KF;
            mKeyFrameRequested = false;
@@ -874,7 +1103,13 @@ void SoftVPXEncoder::onQueueFilled(OMX_U32 portIndex) {
            mBitrateUpdated = false;
        }

        uint32_t frameDuration = (uint32_t)(((uint64_t)1000000 << 16) / mFramerate);
        uint32_t frameDuration;
        if (inputBufferHeader->nTimeStamp > mLastTimestamp) {
            frameDuration = (uint32_t)(inputBufferHeader->nTimeStamp - mLastTimestamp);
        } else {
            frameDuration = (uint32_t)(((uint64_t)1000000 << 16) / mFramerate);
        }
        mLastTimestamp = inputBufferHeader->nTimeStamp;
        codec_return = vpx_codec_encode(
                mCodecContext,
                &raw_frame,
@@ -921,10 +1156,9 @@ void SoftVPXEncoder::onQueueFilled(OMX_U32 portIndex) {
OMX_ERRORTYPE SoftVPXEncoder::getExtensionIndex(
        const char *name, OMX_INDEXTYPE *index) {
    if (!strcmp(name, "OMX.google.android.index.storeMetaDataInBuffers")) {
        *index = OMX_IndexVendorStartUnused;
        *(int32_t*)index = kStoreMetaDataExtensionIndex;
        return OMX_ErrorNone;
    }

    return SimpleSoftOMXComponent::getExtensionIndex(name, index);
}

+78 −0
Original line number Diff line number Diff line
@@ -91,6 +91,47 @@ protected:
            const char *name, OMX_INDEXTYPE *index);

private:
    enum {
        kStoreMetaDataExtensionIndex = OMX_IndexVendorStartUnused + 1,
    };

    enum TemporalReferences {
        // For 1 layer case: reference all (last, golden, and alt ref), but only
        // update last.
        kTemporalUpdateLastRefAll = 12,
        // First base layer frame for 3 temporal layers, which updates last and
        // golden with alt ref dependency.
        kTemporalUpdateLastAndGoldenRefAltRef = 11,
        // First enhancement layer with alt ref dependency.
        kTemporalUpdateGoldenRefAltRef = 10,
        // First enhancement layer with alt ref dependency.
        kTemporalUpdateGoldenWithoutDependencyRefAltRef = 9,
        // Base layer with alt ref dependency.
        kTemporalUpdateLastRefAltRef = 8,
        // Highest enhacement layer without dependency on golden with alt ref
        // dependency.
        kTemporalUpdateNoneNoRefGoldenRefAltRef = 7,
        // Second layer and last frame in cycle, for 2 layers.
        kTemporalUpdateNoneNoRefAltref = 6,
        // Highest enhancement layer.
        kTemporalUpdateNone = 5,
        // Second enhancement layer.
        kTemporalUpdateAltref = 4,
        // Second enhancement layer without dependency on previous frames in
        // the second enhancement layer.
        kTemporalUpdateAltrefWithoutDependency = 3,
        // First enhancement layer.
        kTemporalUpdateGolden = 2,
        // First enhancement layer without dependency on previous frames in
        // the first enhancement layer.
        kTemporalUpdateGoldenWithoutDependency = 1,
        // Base layer.
        kTemporalUpdateLast = 0,
    };
    enum {
        kMaxTemporalPattern = 8
    };

    // number of buffers allocated per port
    static const uint32_t kNumBuffers = 4;

@@ -159,6 +200,36 @@ private:
    // something else.
    OMX_VIDEO_VP8LEVELTYPE mLevel;

    // Key frame interval in frames
    uint32_t mKeyFrameInterval;

    // Minimum (best quality) quantizer
    uint32_t mMinQuantizer;

    // Maximum (worst quality) quantizer
    uint32_t mMaxQuantizer;

    // Number of coding temporal layers to be used.
    size_t mTemporalLayers;

    // Temporal layer bitrare ratio in percentage
    uint32_t mTemporalLayerBitrateRatio[OMX_VIDEO_ANDROID_MAXVP8TEMPORALLAYERS];

    // Temporal pattern type
    OMX_VIDEO_ANDROID_VPXTEMPORALLAYERPATTERNTYPE mTemporalPatternType;

    // Temporal pattern length
    size_t mTemporalPatternLength;

    // Temporal pattern current index
    size_t mTemporalPatternIdx;

    // Frame type temporal pattern
    TemporalReferences mTemporalPattern[kMaxTemporalPattern];

    // Last input buffer timestamp
    OMX_TICKS mLastTimestamp;

    // Conversion buffer is needed to convert semi
    // planar yuv420 to planar format
    // It is only allocated if input format is
@@ -184,6 +255,9 @@ private:
    // dtor.
    status_t releaseEncoder();

    // Get current encode flags
    vpx_enc_frame_flags_t getEncodeFlags();

    // Handles port changes with respect to color formats
    OMX_ERRORTYPE internalSetFormatParams(
        const OMX_VIDEO_PARAM_PORTFORMATTYPE* format);
@@ -205,6 +279,10 @@ private:
    OMX_ERRORTYPE internalSetVp8Params(
        const OMX_VIDEO_PARAM_VP8TYPE* vp8Params);

    // Handles Android vp8 specific parameters.
    OMX_ERRORTYPE internalSetAndroidVp8Params(
        const OMX_VIDEO_PARAM_ANDROID_VP8ENCODERTYPE* vp8AndroidParams);

    // Updates encoder profile
    OMX_ERRORTYPE internalSetProfileLevel(
        const OMX_VIDEO_PARAM_PROFILELEVELTYPE* profileAndLevel);