Home | History | Annotate | Download | only in vpx
      1 /*
      2  * Copyright 2018 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 "C2SoftVpxEnc"
     19 #include <log/log.h>
     20 #include <utils/misc.h>
     21 
     22 #include <media/hardware/VideoAPI.h>
     23 
     24 #include <Codec2BufferUtils.h>
     25 #include <C2Debug.h>
     26 #include "C2SoftVpxEnc.h"
     27 
     28 #ifndef INT32_MAX
     29 #define INT32_MAX   2147483647
     30 #endif
     31 
     32 namespace android {
     33 
     34 #if 0
     35 static size_t getCpuCoreCount() {
     36     long cpuCoreCount = 1;
     37 #if defined(_SC_NPROCESSORS_ONLN)
     38     cpuCoreCount = sysconf(_SC_NPROCESSORS_ONLN);
     39 #else
     40     // _SC_NPROC_ONLN must be defined...
     41     cpuCoreCount = sysconf(_SC_NPROC_ONLN);
     42 #endif
     43     CHECK(cpuCoreCount >= 1);
     44     ALOGV("Number of CPU cores: %ld", cpuCoreCount);
     45     return (size_t)cpuCoreCount;
     46 }
     47 #endif
     48 
     49 C2SoftVpxEnc::C2SoftVpxEnc(const char* name, c2_node_id_t id,
     50                            const std::shared_ptr<IntfImpl>& intfImpl)
     51     : SimpleC2Component(
     52           std::make_shared<SimpleInterface<IntfImpl>>(name, id, intfImpl)),
     53       mIntf(intfImpl),
     54       mCodecContext(nullptr),
     55       mCodecConfiguration(nullptr),
     56       mCodecInterface(nullptr),
     57       mStrideAlign(2),
     58       mColorFormat(VPX_IMG_FMT_I420),
     59       mBitrateControlMode(VPX_VBR),
     60       mErrorResilience(false),
     61       mMinQuantizer(0),
     62       mMaxQuantizer(0),
     63       mTemporalLayers(0),
     64       mTemporalPatternType(VPXTemporalLayerPatternNone),
     65       mTemporalPatternLength(0),
     66       mTemporalPatternIdx(0),
     67       mLastTimestamp(0x7FFFFFFFFFFFFFFFull),
     68       mSignalledOutputEos(false),
     69       mSignalledError(false) {
     70     memset(mTemporalLayerBitrateRatio, 0, sizeof(mTemporalLayerBitrateRatio));
     71     mTemporalLayerBitrateRatio[0] = 100;
     72 }
     73 
     74 C2SoftVpxEnc::~C2SoftVpxEnc() {
     75     onRelease();
     76 }
     77 
     78 c2_status_t C2SoftVpxEnc::onInit() {
     79     status_t err = initEncoder();
     80     return err == OK ? C2_OK : C2_CORRUPTED;
     81 }
     82 
     83 void C2SoftVpxEnc::onRelease() {
     84     if (mCodecContext) {
     85         vpx_codec_destroy(mCodecContext);
     86         delete mCodecContext;
     87         mCodecContext = nullptr;
     88     }
     89 
     90     if (mCodecConfiguration) {
     91         delete mCodecConfiguration;
     92         mCodecConfiguration = nullptr;
     93     }
     94 
     95     // this one is not allocated by us
     96     mCodecInterface = nullptr;
     97 }
     98 
     99 c2_status_t C2SoftVpxEnc::onStop() {
    100     onRelease();
    101     mLastTimestamp = 0x7FFFFFFFFFFFFFFFLL;
    102     mSignalledOutputEos = false;
    103     mSignalledError = false;
    104     return C2_OK;
    105 }
    106 
    107 void C2SoftVpxEnc::onReset() {
    108     (void)onStop();
    109 }
    110 
    111 c2_status_t C2SoftVpxEnc::onFlush_sm() {
    112     return onStop();
    113 }
    114 
    115 status_t C2SoftVpxEnc::initEncoder() {
    116     vpx_codec_err_t codec_return;
    117     status_t result = UNKNOWN_ERROR;
    118     {
    119         IntfImpl::Lock lock = mIntf->lock();
    120         mSize = mIntf->getSize_l();
    121         mBitrate = mIntf->getBitrate_l();
    122         mBitrateMode = mIntf->getBitrateMode_l();
    123         mFrameRate = mIntf->getFrameRate_l();
    124         mIntraRefresh = mIntf->getIntraRefresh_l();
    125         mRequestSync = mIntf->getRequestSync_l();
    126         mTemporalLayers = mIntf->getTemporalLayers_l()->m.layerCount;
    127     }
    128 
    129     switch (mBitrateMode->value) {
    130         case C2Config::BITRATE_CONST:
    131             mBitrateControlMode = VPX_CBR;
    132             break;
    133         case C2Config::BITRATE_VARIABLE:
    134         [[fallthrough]];
    135         default:
    136             mBitrateControlMode = VPX_VBR;
    137             break;
    138     }
    139 
    140     setCodecSpecificInterface();
    141     if (!mCodecInterface) goto CleanUp;
    142 
    143     ALOGD("VPx: initEncoder. BRMode: %u. TSLayers: %zu. KF: %u. QP: %u - %u",
    144           (uint32_t)mBitrateControlMode, mTemporalLayers, mIntf->getSyncFramePeriod(),
    145           mMinQuantizer, mMaxQuantizer);
    146 
    147     mCodecConfiguration = new vpx_codec_enc_cfg_t;
    148     if (!mCodecConfiguration) goto CleanUp;
    149     codec_return = vpx_codec_enc_config_default(mCodecInterface,
    150                                                 mCodecConfiguration,
    151                                                 0);
    152     if (codec_return != VPX_CODEC_OK) {
    153         ALOGE("Error populating default configuration for vpx encoder.");
    154         goto CleanUp;
    155     }
    156 
    157     mCodecConfiguration->g_w = mSize->width;
    158     mCodecConfiguration->g_h = mSize->height;
    159     //mCodecConfiguration->g_threads = getCpuCoreCount();
    160     mCodecConfiguration->g_threads = 0;
    161     mCodecConfiguration->g_error_resilient = mErrorResilience;
    162 
    163     // timebase unit is microsecond
    164     // g_timebase is in seconds (i.e. 1/1000000 seconds)
    165     mCodecConfiguration->g_timebase.num = 1;
    166     mCodecConfiguration->g_timebase.den = 1000000;
    167     // rc_target_bitrate is in kbps, mBitrate in bps
    168     mCodecConfiguration->rc_target_bitrate = (mBitrate->value + 500) / 1000;
    169     mCodecConfiguration->rc_end_usage = mBitrateControlMode;
    170     // Disable frame drop - not allowed in MediaCodec now.
    171     mCodecConfiguration->rc_dropframe_thresh = 0;
    172     // Disable lagged encoding.
    173     mCodecConfiguration->g_lag_in_frames = 0;
    174     if (mBitrateControlMode == VPX_CBR) {
    175         // Disable spatial resizing.
    176         mCodecConfiguration->rc_resize_allowed = 0;
    177         // Single-pass mode.
    178         mCodecConfiguration->g_pass = VPX_RC_ONE_PASS;
    179         // Maximum amount of bits that can be subtracted from the target
    180         // bitrate - expressed as percentage of the target bitrate.
    181         mCodecConfiguration->rc_undershoot_pct = 100;
    182         // Maximum amount of bits that can be added to the target
    183         // bitrate - expressed as percentage of the target bitrate.
    184         mCodecConfiguration->rc_overshoot_pct = 15;
    185         // Initial value of the buffer level in ms.
    186         mCodecConfiguration->rc_buf_initial_sz = 500;
    187         // Amount of data that the encoder should try to maintain in ms.
    188         mCodecConfiguration->rc_buf_optimal_sz = 600;
    189         // The amount of data that may be buffered by the decoding
    190         // application in ms.
    191         mCodecConfiguration->rc_buf_sz = 1000;
    192         // Enable error resilience - needed for packet loss.
    193         mCodecConfiguration->g_error_resilient = 1;
    194         // Maximum key frame interval - for CBR boost to 3000
    195         mCodecConfiguration->kf_max_dist = 3000;
    196         // Encoder determines optimal key frame placement automatically.
    197         mCodecConfiguration->kf_mode = VPX_KF_AUTO;
    198     }
    199 
    200     // Frames temporal pattern - for now WebRTC like pattern is only supported.
    201     switch (mTemporalLayers) {
    202         case 0:
    203             mTemporalPatternLength = 0;
    204             break;
    205         case 1:
    206             mCodecConfiguration->ts_number_layers = 1;
    207             mCodecConfiguration->ts_rate_decimator[0] = 1;
    208             mCodecConfiguration->ts_periodicity = 1;
    209             mCodecConfiguration->ts_layer_id[0] = 0;
    210             mTemporalPattern[0] = kTemporalUpdateLastRefAll;
    211             mTemporalPatternLength = 1;
    212             break;
    213         case 2:
    214             mCodecConfiguration->ts_number_layers = 2;
    215             mCodecConfiguration->ts_rate_decimator[0] = 2;
    216             mCodecConfiguration->ts_rate_decimator[1] = 1;
    217             mCodecConfiguration->ts_periodicity = 2;
    218             mCodecConfiguration->ts_layer_id[0] = 0;
    219             mCodecConfiguration->ts_layer_id[1] = 1;
    220             mTemporalPattern[0] = kTemporalUpdateLastAndGoldenRefAltRef;
    221             mTemporalPattern[1] = kTemporalUpdateGoldenWithoutDependencyRefAltRef;
    222             mTemporalPattern[2] = kTemporalUpdateLastRefAltRef;
    223             mTemporalPattern[3] = kTemporalUpdateGoldenRefAltRef;
    224             mTemporalPattern[4] = kTemporalUpdateLastRefAltRef;
    225             mTemporalPattern[5] = kTemporalUpdateGoldenRefAltRef;
    226             mTemporalPattern[6] = kTemporalUpdateLastRefAltRef;
    227             mTemporalPattern[7] = kTemporalUpdateNone;
    228             mTemporalPatternLength = 8;
    229             break;
    230         case 3:
    231             mCodecConfiguration->ts_number_layers = 3;
    232             mCodecConfiguration->ts_rate_decimator[0] = 4;
    233             mCodecConfiguration->ts_rate_decimator[1] = 2;
    234             mCodecConfiguration->ts_rate_decimator[2] = 1;
    235             mCodecConfiguration->ts_periodicity = 4;
    236             mCodecConfiguration->ts_layer_id[0] = 0;
    237             mCodecConfiguration->ts_layer_id[1] = 2;
    238             mCodecConfiguration->ts_layer_id[2] = 1;
    239             mCodecConfiguration->ts_layer_id[3] = 2;
    240             mTemporalPattern[0] = kTemporalUpdateLastAndGoldenRefAltRef;
    241             mTemporalPattern[1] = kTemporalUpdateNoneNoRefGoldenRefAltRef;
    242             mTemporalPattern[2] = kTemporalUpdateGoldenWithoutDependencyRefAltRef;
    243             mTemporalPattern[3] = kTemporalUpdateNone;
    244             mTemporalPattern[4] = kTemporalUpdateLastRefAltRef;
    245             mTemporalPattern[5] = kTemporalUpdateNone;
    246             mTemporalPattern[6] = kTemporalUpdateGoldenRefAltRef;
    247             mTemporalPattern[7] = kTemporalUpdateNone;
    248             mTemporalPatternLength = 8;
    249             break;
    250         default:
    251             ALOGE("Wrong number of temporal layers %zu", mTemporalLayers);
    252             goto CleanUp;
    253     }
    254     // Set bitrate values for each layer
    255     for (size_t i = 0; i < mCodecConfiguration->ts_number_layers; i++) {
    256         mCodecConfiguration->ts_target_bitrate[i] =
    257             mCodecConfiguration->rc_target_bitrate *
    258             mTemporalLayerBitrateRatio[i] / 100;
    259     }
    260     if (mIntf->getSyncFramePeriod() >= 0) {
    261         mCodecConfiguration->kf_max_dist = mIntf->getSyncFramePeriod();
    262         mCodecConfiguration->kf_min_dist = mIntf->getSyncFramePeriod();
    263         mCodecConfiguration->kf_mode = VPX_KF_AUTO;
    264     }
    265     if (mMinQuantizer > 0) {
    266         mCodecConfiguration->rc_min_quantizer = mMinQuantizer;
    267     }
    268     if (mMaxQuantizer > 0) {
    269         mCodecConfiguration->rc_max_quantizer = mMaxQuantizer;
    270     }
    271     setCodecSpecificConfiguration();
    272     mCodecContext = new vpx_codec_ctx_t;
    273     if (!mCodecContext) goto CleanUp;
    274     codec_return = vpx_codec_enc_init(mCodecContext,
    275                                       mCodecInterface,
    276                                       mCodecConfiguration,
    277                                       0);  // flags
    278     if (codec_return != VPX_CODEC_OK) {
    279         ALOGE("Error initializing vpx encoder");
    280         goto CleanUp;
    281     }
    282 
    283     // Extra CBR settings
    284     if (mBitrateControlMode == VPX_CBR) {
    285         codec_return = vpx_codec_control(mCodecContext,
    286                                          VP8E_SET_STATIC_THRESHOLD,
    287                                          1);
    288         if (codec_return == VPX_CODEC_OK) {
    289             uint32_t rc_max_intra_target =
    290                 (uint32_t)(mCodecConfiguration->rc_buf_optimal_sz * mFrameRate->value / 20 + 0.5);
    291             // Don't go below 3 times per frame bandwidth.
    292             if (rc_max_intra_target < 300) {
    293                 rc_max_intra_target = 300;
    294             }
    295             codec_return = vpx_codec_control(mCodecContext,
    296                                              VP8E_SET_MAX_INTRA_BITRATE_PCT,
    297                                              rc_max_intra_target);
    298         }
    299         if (codec_return == VPX_CODEC_OK) {
    300             codec_return = vpx_codec_control(mCodecContext,
    301                                              VP8E_SET_CPUUSED,
    302                                              -8);
    303         }
    304         if (codec_return != VPX_CODEC_OK) {
    305             ALOGE("Error setting cbr parameters for vpx encoder.");
    306             goto CleanUp;
    307         }
    308     }
    309 
    310     codec_return = setCodecSpecificControls();
    311     if (codec_return != VPX_CODEC_OK) goto CleanUp;
    312 
    313     {
    314         uint32_t width = mSize->width;
    315         uint32_t height = mSize->height;
    316         if (((uint64_t)width * height) >
    317             ((uint64_t)INT32_MAX / 3)) {
    318             ALOGE("b/25812794, Buffer size is too big, width=%u, height=%u.", width, height);
    319         } else {
    320             uint32_t stride = (width + mStrideAlign - 1) & ~(mStrideAlign - 1);
    321             uint32_t vstride = (height + mStrideAlign - 1) & ~(mStrideAlign - 1);
    322             mConversionBuffer = MemoryBlock::Allocate(stride * vstride * 3 / 2);
    323             if (!mConversionBuffer.size()) {
    324                 ALOGE("Allocating conversion buffer failed.");
    325             } else {
    326                 mNumInputFrames = -1;
    327                 return OK;
    328             }
    329         }
    330     }
    331 
    332 CleanUp:
    333     onRelease();
    334     return result;
    335 }
    336 
    337 vpx_enc_frame_flags_t C2SoftVpxEnc::getEncodeFlags() {
    338     vpx_enc_frame_flags_t flags = 0;
    339     if (mTemporalPatternLength > 0) {
    340       int patternIdx = mTemporalPatternIdx % mTemporalPatternLength;
    341       mTemporalPatternIdx++;
    342       switch (mTemporalPattern[patternIdx]) {
    343           case kTemporalUpdateLast:
    344               flags |= VP8_EFLAG_NO_UPD_GF;
    345               flags |= VP8_EFLAG_NO_UPD_ARF;
    346               flags |= VP8_EFLAG_NO_REF_GF;
    347               flags |= VP8_EFLAG_NO_REF_ARF;
    348               break;
    349           case kTemporalUpdateGoldenWithoutDependency:
    350               flags |= VP8_EFLAG_NO_REF_GF;
    351               [[fallthrough]];
    352           case kTemporalUpdateGolden:
    353               flags |= VP8_EFLAG_NO_REF_ARF;
    354               flags |= VP8_EFLAG_NO_UPD_ARF;
    355               flags |= VP8_EFLAG_NO_UPD_LAST;
    356               break;
    357           case kTemporalUpdateAltrefWithoutDependency:
    358               flags |= VP8_EFLAG_NO_REF_ARF;
    359               flags |= VP8_EFLAG_NO_REF_GF;
    360               [[fallthrough]];
    361           case kTemporalUpdateAltref:
    362               flags |= VP8_EFLAG_NO_UPD_GF;
    363               flags |= VP8_EFLAG_NO_UPD_LAST;
    364               break;
    365           case kTemporalUpdateNoneNoRefAltref:
    366               flags |= VP8_EFLAG_NO_REF_ARF;
    367               [[fallthrough]];
    368           case kTemporalUpdateNone:
    369               flags |= VP8_EFLAG_NO_UPD_GF;
    370               flags |= VP8_EFLAG_NO_UPD_ARF;
    371               flags |= VP8_EFLAG_NO_UPD_LAST;
    372               flags |= VP8_EFLAG_NO_UPD_ENTROPY;
    373               break;
    374           case kTemporalUpdateNoneNoRefGoldenRefAltRef:
    375               flags |= VP8_EFLAG_NO_REF_GF;
    376               flags |= VP8_EFLAG_NO_UPD_GF;
    377               flags |= VP8_EFLAG_NO_UPD_ARF;
    378               flags |= VP8_EFLAG_NO_UPD_LAST;
    379               flags |= VP8_EFLAG_NO_UPD_ENTROPY;
    380               break;
    381           case kTemporalUpdateGoldenWithoutDependencyRefAltRef:
    382               flags |= VP8_EFLAG_NO_REF_GF;
    383               flags |= VP8_EFLAG_NO_UPD_ARF;
    384               flags |= VP8_EFLAG_NO_UPD_LAST;
    385               break;
    386           case kTemporalUpdateLastRefAltRef:
    387               flags |= VP8_EFLAG_NO_UPD_GF;
    388               flags |= VP8_EFLAG_NO_UPD_ARF;
    389               flags |= VP8_EFLAG_NO_REF_GF;
    390               break;
    391           case kTemporalUpdateGoldenRefAltRef:
    392               flags |= VP8_EFLAG_NO_UPD_ARF;
    393               flags |= VP8_EFLAG_NO_UPD_LAST;
    394               break;
    395           case kTemporalUpdateLastAndGoldenRefAltRef:
    396               flags |= VP8_EFLAG_NO_UPD_ARF;
    397               flags |= VP8_EFLAG_NO_REF_GF;
    398               break;
    399           case kTemporalUpdateLastRefAll:
    400               flags |= VP8_EFLAG_NO_UPD_ARF;
    401               flags |= VP8_EFLAG_NO_UPD_GF;
    402               break;
    403       }
    404     }
    405     return flags;
    406 }
    407 
    408 // TODO: add support for YUV input color formats
    409 // TODO: add support for SVC, ARF. SVC and ARF returns multiple frames
    410 // (hierarchical / noshow) in one call. These frames should be combined in to
    411 // a single buffer and sent back to the client
    412 void C2SoftVpxEnc::process(
    413         const std::unique_ptr<C2Work> &work,
    414         const std::shared_ptr<C2BlockPool> &pool) {
    415     // Initialize output work
    416     work->result = C2_OK;
    417     work->workletsProcessed = 1u;
    418     work->worklets.front()->output.flags = work->input.flags;
    419 
    420     if (mSignalledError || mSignalledOutputEos) {
    421         work->result = C2_BAD_VALUE;
    422         return;
    423     }
    424     // Initialize encoder if not already
    425     if (!mCodecContext && OK != initEncoder()) {
    426         ALOGE("Failed to initialize encoder");
    427         mSignalledError = true;
    428         work->result = C2_CORRUPTED;
    429         return;
    430     }
    431 
    432     std::shared_ptr<const C2GraphicView> rView;
    433     std::shared_ptr<C2Buffer> inputBuffer;
    434     if (!work->input.buffers.empty()) {
    435         inputBuffer = work->input.buffers[0];
    436         rView = std::make_shared<const C2GraphicView>(
    437                     inputBuffer->data().graphicBlocks().front().map().get());
    438         if (rView->error() != C2_OK) {
    439             ALOGE("graphic view map err = %d", rView->error());
    440             work->result = C2_CORRUPTED;
    441             return;
    442         }
    443     } else {
    444         ALOGV("Empty input Buffer");
    445         uint32_t flags = 0;
    446         if (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) {
    447             flags |= C2FrameData::FLAG_END_OF_STREAM;
    448         }
    449         work->worklets.front()->output.flags = (C2FrameData::flags_t)flags;
    450         work->worklets.front()->output.buffers.clear();
    451         work->worklets.front()->output.ordinal = work->input.ordinal;
    452         work->workletsProcessed = 1u;
    453         return;
    454     }
    455 
    456     const C2ConstGraphicBlock inBuffer =
    457         inputBuffer->data().graphicBlocks().front();
    458     if (inBuffer.width() != mSize->width ||
    459         inBuffer.height() != mSize->height) {
    460         ALOGE("unexpected Input buffer attributes %d(%d) x %d(%d)",
    461               inBuffer.width(), mSize->width, inBuffer.height(),
    462               mSize->height);
    463         mSignalledError = true;
    464         work->result = C2_BAD_VALUE;
    465         return;
    466     }
    467     bool eos = ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0);
    468     vpx_image_t raw_frame;
    469     const C2PlanarLayout &layout = rView->layout();
    470     uint32_t width = rView->width();
    471     uint32_t height = rView->height();
    472     if (width > 0x8000 || height > 0x8000) {
    473         ALOGE("Image too big: %u x %u", width, height);
    474         work->result = C2_BAD_VALUE;
    475         return;
    476     }
    477     uint32_t stride = (width + mStrideAlign - 1) & ~(mStrideAlign - 1);
    478     uint32_t vstride = (height + mStrideAlign - 1) & ~(mStrideAlign - 1);
    479     switch (layout.type) {
    480         case C2PlanarLayout::TYPE_RGB:
    481         case C2PlanarLayout::TYPE_RGBA: {
    482             ConvertRGBToPlanarYUV(mConversionBuffer.data(), stride, vstride,
    483                                   mConversionBuffer.size(), *rView.get());
    484             vpx_img_wrap(&raw_frame, VPX_IMG_FMT_I420, width, height,
    485                          mStrideAlign, mConversionBuffer.data());
    486             break;
    487         }
    488         case C2PlanarLayout::TYPE_YUV: {
    489             if (!IsYUV420(*rView)) {
    490                 ALOGE("input is not YUV420");
    491                 work->result = C2_BAD_VALUE;
    492                 return;
    493             }
    494 
    495             if (layout.planes[layout.PLANE_Y].colInc == 1
    496                     && layout.planes[layout.PLANE_U].colInc == 1
    497                     && layout.planes[layout.PLANE_V].colInc == 1) {
    498                 // I420 compatible - though with custom offset and stride
    499                 vpx_img_wrap(&raw_frame, VPX_IMG_FMT_I420, width, height,
    500                              mStrideAlign, (uint8_t*)rView->data()[0]);
    501                 raw_frame.planes[1] = (uint8_t*)rView->data()[1];
    502                 raw_frame.planes[2] = (uint8_t*)rView->data()[2];
    503                 raw_frame.stride[0] = layout.planes[layout.PLANE_Y].rowInc;
    504                 raw_frame.stride[1] = layout.planes[layout.PLANE_U].rowInc;
    505                 raw_frame.stride[2] = layout.planes[layout.PLANE_V].rowInc;
    506             } else {
    507                 // copy to I420
    508                 MediaImage2 img = CreateYUV420PlanarMediaImage2(width, height, stride, vstride);
    509                 if (mConversionBuffer.size() >= stride * vstride * 3 / 2) {
    510                     status_t err = ImageCopy(mConversionBuffer.data(), &img, *rView);
    511                     if (err != OK) {
    512                         ALOGE("Buffer conversion failed: %d", err);
    513                         work->result = C2_BAD_VALUE;
    514                         return;
    515                     }
    516                     vpx_img_wrap(&raw_frame, VPX_IMG_FMT_I420, stride, vstride,
    517                                  mStrideAlign, (uint8_t*)rView->data()[0]);
    518                     vpx_img_set_rect(&raw_frame, 0, 0, width, height);
    519                 } else {
    520                     ALOGE("Conversion buffer is too small: %u x %u for %zu",
    521                             stride, vstride, mConversionBuffer.size());
    522                     work->result = C2_BAD_VALUE;
    523                     return;
    524                 }
    525             }
    526             break;
    527         }
    528         default:
    529             ALOGE("Unrecognized plane type: %d", layout.type);
    530             work->result = C2_BAD_VALUE;
    531             return;
    532     }
    533 
    534     vpx_enc_frame_flags_t flags = getEncodeFlags();
    535     // handle dynamic config parameters
    536     {
    537         IntfImpl::Lock lock = mIntf->lock();
    538         std::shared_ptr<C2StreamIntraRefreshTuning::output> intraRefresh = mIntf->getIntraRefresh_l();
    539         std::shared_ptr<C2StreamBitrateInfo::output> bitrate = mIntf->getBitrate_l();
    540         std::shared_ptr<C2StreamRequestSyncFrameTuning::output> requestSync = mIntf->getRequestSync_l();
    541         lock.unlock();
    542 
    543         if (intraRefresh != mIntraRefresh) {
    544             mIntraRefresh = intraRefresh;
    545             ALOGV("Got mIntraRefresh request");
    546         }
    547 
    548         if (requestSync != mRequestSync) {
    549             // we can handle IDR immediately
    550             if (requestSync->value) {
    551                 // unset request
    552                 C2StreamRequestSyncFrameTuning::output clearSync(0u, C2_FALSE);
    553                 std::vector<std::unique_ptr<C2SettingResult>> failures;
    554                 mIntf->config({ &clearSync }, C2_MAY_BLOCK, &failures);
    555                 ALOGV("Got sync request");
    556                 flags |= VPX_EFLAG_FORCE_KF;
    557             }
    558             mRequestSync = requestSync;
    559         }
    560 
    561         if (bitrate != mBitrate) {
    562             mBitrate = bitrate;
    563             mCodecConfiguration->rc_target_bitrate =
    564                 (mBitrate->value + 500) / 1000;
    565             vpx_codec_err_t res = vpx_codec_enc_config_set(mCodecContext,
    566                                                            mCodecConfiguration);
    567             if (res != VPX_CODEC_OK) {
    568                 ALOGE("vpx encoder failed to update bitrate: %s",
    569                       vpx_codec_err_to_string(res));
    570                 mSignalledError = true;
    571                 work->result = C2_CORRUPTED;
    572                 return;
    573             }
    574         }
    575     }
    576 
    577     uint64_t inputTimeStamp = work->input.ordinal.timestamp.peekull();
    578     uint32_t frameDuration;
    579     if (inputTimeStamp > mLastTimestamp) {
    580         frameDuration = (uint32_t)(inputTimeStamp - mLastTimestamp);
    581     } else {
    582         // Use default of 30 fps in case of 0 frame rate.
    583         float frameRate = mFrameRate->value;
    584         if (frameRate < 0.001) {
    585             frameRate = 30;
    586         }
    587         frameDuration = (uint32_t)(1000000 / frameRate + 0.5);
    588     }
    589     mLastTimestamp = inputTimeStamp;
    590 
    591     vpx_codec_err_t codec_return = vpx_codec_encode(mCodecContext, &raw_frame,
    592                                                     inputTimeStamp,
    593                                                     frameDuration, flags,
    594                                                     VPX_DL_REALTIME);
    595     if (codec_return != VPX_CODEC_OK) {
    596         ALOGE("vpx encoder failed to encode frame");
    597         mSignalledError = true;
    598         work->result = C2_CORRUPTED;
    599         return;
    600     }
    601 
    602     bool populated = false;
    603     vpx_codec_iter_t encoded_packet_iterator = nullptr;
    604     const vpx_codec_cx_pkt_t* encoded_packet;
    605     while ((encoded_packet = vpx_codec_get_cx_data(
    606                     mCodecContext, &encoded_packet_iterator))) {
    607         if (encoded_packet->kind == VPX_CODEC_CX_FRAME_PKT) {
    608             std::shared_ptr<C2LinearBlock> block;
    609             C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
    610             c2_status_t err = pool->fetchLinearBlock(encoded_packet->data.frame.sz, usage, &block);
    611             if (err != C2_OK) {
    612                 ALOGE("fetchLinearBlock for Output failed with status %d", err);
    613                 work->result = C2_NO_MEMORY;
    614                 return;
    615             }
    616             C2WriteView wView = block->map().get();
    617             if (wView.error()) {
    618                 ALOGE("write view map failed %d", wView.error());
    619                 work->result = C2_CORRUPTED;
    620                 return;
    621             }
    622 
    623             memcpy(wView.data(), encoded_packet->data.frame.buf, encoded_packet->data.frame.sz);
    624             ++mNumInputFrames;
    625 
    626             ALOGD("bytes generated %zu", encoded_packet->data.frame.sz);
    627             uint32_t flags = 0;
    628             if (eos) {
    629                 flags |= C2FrameData::FLAG_END_OF_STREAM;
    630             }
    631             work->worklets.front()->output.flags = (C2FrameData::flags_t)flags;
    632             work->worklets.front()->output.buffers.clear();
    633             std::shared_ptr<C2Buffer> buffer = createLinearBuffer(block);
    634             if (encoded_packet->data.frame.flags & VPX_FRAME_IS_KEY) {
    635                 buffer->setInfo(std::make_shared<C2StreamPictureTypeMaskInfo::output>(
    636                         0u /* stream id */, C2Config::SYNC_FRAME));
    637             }
    638             work->worklets.front()->output.buffers.push_back(buffer);
    639             work->worklets.front()->output.ordinal = work->input.ordinal;
    640             work->worklets.front()->output.ordinal.timestamp = encoded_packet->data.frame.pts;
    641             work->workletsProcessed = 1u;
    642             populated = true;
    643             if (eos) {
    644                 mSignalledOutputEos = true;
    645                 ALOGV("signalled EOS");
    646             }
    647         }
    648     }
    649     if (!populated) {
    650         work->workletsProcessed = 0u;
    651     }
    652 }
    653 
    654 c2_status_t C2SoftVpxEnc::drain(
    655         uint32_t drainMode,
    656         const std::shared_ptr<C2BlockPool> &pool) {
    657     (void)pool;
    658     if (drainMode == NO_DRAIN) {
    659         ALOGW("drain with NO_DRAIN: no-op");
    660         return C2_OK;
    661     }
    662     if (drainMode == DRAIN_CHAIN) {
    663         ALOGW("DRAIN_CHAIN not supported");
    664         return C2_OMITTED;
    665     }
    666 
    667     return C2_OK;
    668 }
    669 
    670 }  // namespace android
    671