Home | History | Annotate | Download | only in avc
      1 /*
      2  * Copyright 2017 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 "C2SoftAvcDec"
     19 #include <log/log.h>
     20 
     21 #include <media/stagefright/foundation/MediaDefs.h>
     22 
     23 #include <C2Debug.h>
     24 #include <C2PlatformSupport.h>
     25 #include <SimpleC2Interface.h>
     26 
     27 #include "C2SoftAvcDec.h"
     28 #include "ih264d.h"
     29 
     30 namespace android {
     31 
     32 namespace {
     33 
     34 constexpr char COMPONENT_NAME[] = "c2.android.avc.decoder";
     35 
     36 }  // namespace
     37 
     38 class C2SoftAvcDec::IntfImpl : public SimpleInterface<void>::BaseParams {
     39 public:
     40     explicit IntfImpl(const std::shared_ptr<C2ReflectorHelper> &helper)
     41         : SimpleInterface<void>::BaseParams(
     42                 helper,
     43                 COMPONENT_NAME,
     44                 C2Component::KIND_DECODER,
     45                 C2Component::DOMAIN_VIDEO,
     46                 MEDIA_MIMETYPE_VIDEO_AVC) {
     47         noPrivateBuffers(); // TODO: account for our buffers here
     48         noInputReferences();
     49         noOutputReferences();
     50         noInputLatency();
     51         noTimeStretch();
     52 
     53         // TODO: output latency and reordering
     54 
     55         addParameter(
     56                 DefineParam(mAttrib, C2_PARAMKEY_COMPONENT_ATTRIBUTES)
     57                 .withConstValue(new C2ComponentAttributesSetting(C2Component::ATTRIB_IS_TEMPORAL))
     58                 .build());
     59 
     60         // coded and output picture size is the same for this codec
     61         addParameter(
     62                 DefineParam(mSize, C2_PARAMKEY_PICTURE_SIZE)
     63                 .withDefault(new C2StreamPictureSizeInfo::output(0u, 320, 240))
     64                 .withFields({
     65                     C2F(mSize, width).inRange(2, 4080, 2),
     66                     C2F(mSize, height).inRange(2, 4080, 2),
     67                 })
     68                 .withSetter(SizeSetter)
     69                 .build());
     70 
     71         addParameter(
     72                 DefineParam(mMaxSize, C2_PARAMKEY_MAX_PICTURE_SIZE)
     73                 .withDefault(new C2StreamMaxPictureSizeTuning::output(0u, 320, 240))
     74                 .withFields({
     75                     C2F(mSize, width).inRange(2, 4080, 2),
     76                     C2F(mSize, height).inRange(2, 4080, 2),
     77                 })
     78                 .withSetter(MaxPictureSizeSetter, mSize)
     79                 .build());
     80 
     81         addParameter(
     82                 DefineParam(mProfileLevel, C2_PARAMKEY_PROFILE_LEVEL)
     83                 .withDefault(new C2StreamProfileLevelInfo::input(0u,
     84                         C2Config::PROFILE_AVC_CONSTRAINED_BASELINE, C2Config::LEVEL_AVC_5_2))
     85                 .withFields({
     86                     C2F(mProfileLevel, profile).oneOf({
     87                             C2Config::PROFILE_AVC_CONSTRAINED_BASELINE,
     88                             C2Config::PROFILE_AVC_BASELINE,
     89                             C2Config::PROFILE_AVC_MAIN,
     90                             C2Config::PROFILE_AVC_CONSTRAINED_HIGH,
     91                             C2Config::PROFILE_AVC_PROGRESSIVE_HIGH,
     92                             C2Config::PROFILE_AVC_HIGH}),
     93                     C2F(mProfileLevel, level).oneOf({
     94                             C2Config::LEVEL_AVC_1, C2Config::LEVEL_AVC_1B, C2Config::LEVEL_AVC_1_1,
     95                             C2Config::LEVEL_AVC_1_2, C2Config::LEVEL_AVC_1_3,
     96                             C2Config::LEVEL_AVC_2, C2Config::LEVEL_AVC_2_1, C2Config::LEVEL_AVC_2_2,
     97                             C2Config::LEVEL_AVC_3, C2Config::LEVEL_AVC_3_1, C2Config::LEVEL_AVC_3_2,
     98                             C2Config::LEVEL_AVC_4, C2Config::LEVEL_AVC_4_1, C2Config::LEVEL_AVC_4_2,
     99                             C2Config::LEVEL_AVC_5, C2Config::LEVEL_AVC_5_1, C2Config::LEVEL_AVC_5_2
    100                     })
    101                 })
    102                 .withSetter(ProfileLevelSetter, mSize)
    103                 .build());
    104 
    105         addParameter(
    106                 DefineParam(mMaxInputSize, C2_PARAMKEY_INPUT_MAX_BUFFER_SIZE)
    107                 .withDefault(new C2StreamMaxBufferSizeInfo::input(0u, 0))
    108                 .withFields({
    109                     C2F(mMaxInputSize, value).any(),
    110                 })
    111                 .calculatedAs(MaxInputSizeSetter, mMaxSize)
    112                 .build());
    113 
    114         C2ChromaOffsetStruct locations[1] = { C2ChromaOffsetStruct::ITU_YUV_420_0() };
    115         std::shared_ptr<C2StreamColorInfo::output> defaultColorInfo =
    116             C2StreamColorInfo::output::AllocShared(
    117                     1u, 0u, 8u /* bitDepth */, C2Color::YUV_420);
    118         memcpy(defaultColorInfo->m.locations, locations, sizeof(locations));
    119 
    120         defaultColorInfo =
    121             C2StreamColorInfo::output::AllocShared(
    122                     { C2ChromaOffsetStruct::ITU_YUV_420_0() },
    123                     0u, 8u /* bitDepth */, C2Color::YUV_420);
    124         helper->addStructDescriptors<C2ChromaOffsetStruct>();
    125 
    126         addParameter(
    127                 DefineParam(mColorInfo, C2_PARAMKEY_CODED_COLOR_INFO)
    128                 .withConstValue(defaultColorInfo)
    129                 .build());
    130 
    131         addParameter(
    132                 DefineParam(mDefaultColorAspects, C2_PARAMKEY_DEFAULT_COLOR_ASPECTS)
    133                 .withDefault(new C2StreamColorAspectsTuning::input(
    134                         0u, C2Color::RANGE_UNSPECIFIED, C2Color::PRIMARIES_UNSPECIFIED,
    135                         C2Color::TRANSFER_UNSPECIFIED, C2Color::MATRIX_UNSPECIFIED))
    136                 .withFields({
    137                     C2F(mDefaultColorAspects, range).inRange(
    138                                 C2Color::RANGE_UNSPECIFIED,     C2Color::RANGE_OTHER),
    139                     C2F(mDefaultColorAspects, primaries).inRange(
    140                                 C2Color::PRIMARIES_UNSPECIFIED, C2Color::PRIMARIES_OTHER),
    141                     C2F(mDefaultColorAspects, transfer).inRange(
    142                                 C2Color::TRANSFER_UNSPECIFIED,  C2Color::TRANSFER_OTHER),
    143                     C2F(mDefaultColorAspects, matrix).inRange(
    144                                 C2Color::MATRIX_UNSPECIFIED,    C2Color::MATRIX_OTHER)
    145                 })
    146                 .withSetter(DefaultColorAspectsSetter)
    147                 .build());
    148 
    149         addParameter(
    150                 DefineParam(mCodedColorAspects, C2_PARAMKEY_DEFAULT_COLOR_ASPECTS)
    151                 .withDefault(new C2StreamColorAspectsInfo::input(
    152                         0u, C2Color::RANGE_UNSPECIFIED, C2Color::PRIMARIES_UNSPECIFIED,
    153                         C2Color::TRANSFER_UNSPECIFIED, C2Color::MATRIX_UNSPECIFIED))
    154                 .withFields({
    155                     C2F(mCodedColorAspects, range).inRange(
    156                                 C2Color::RANGE_UNSPECIFIED,     C2Color::RANGE_OTHER),
    157                     C2F(mCodedColorAspects, primaries).inRange(
    158                                 C2Color::PRIMARIES_UNSPECIFIED, C2Color::PRIMARIES_OTHER),
    159                     C2F(mCodedColorAspects, transfer).inRange(
    160                                 C2Color::TRANSFER_UNSPECIFIED,  C2Color::TRANSFER_OTHER),
    161                     C2F(mCodedColorAspects, matrix).inRange(
    162                                 C2Color::MATRIX_UNSPECIFIED,    C2Color::MATRIX_OTHER)
    163                 })
    164                 .withSetter(CodedColorAspectsSetter)
    165                 .build());
    166 
    167         addParameter(
    168                 DefineParam(mColorAspects, C2_PARAMKEY_COLOR_ASPECTS)
    169                 .withDefault(new C2StreamColorAspectsInfo::output(
    170                         0u, C2Color::RANGE_UNSPECIFIED, C2Color::PRIMARIES_UNSPECIFIED,
    171                         C2Color::TRANSFER_UNSPECIFIED, C2Color::MATRIX_UNSPECIFIED))
    172                 .withFields({
    173                     C2F(mColorAspects, range).inRange(
    174                                 C2Color::RANGE_UNSPECIFIED,     C2Color::RANGE_OTHER),
    175                     C2F(mColorAspects, primaries).inRange(
    176                                 C2Color::PRIMARIES_UNSPECIFIED, C2Color::PRIMARIES_OTHER),
    177                     C2F(mColorAspects, transfer).inRange(
    178                                 C2Color::TRANSFER_UNSPECIFIED,  C2Color::TRANSFER_OTHER),
    179                     C2F(mColorAspects, matrix).inRange(
    180                                 C2Color::MATRIX_UNSPECIFIED,    C2Color::MATRIX_OTHER)
    181                 })
    182                 .withSetter(ColorAspectsSetter, mDefaultColorAspects, mCodedColorAspects)
    183                 .build());
    184 
    185         // TODO: support more formats?
    186         addParameter(
    187                 DefineParam(mPixelFormat, C2_PARAMKEY_PIXEL_FORMAT)
    188                 .withConstValue(new C2StreamPixelFormatInfo::output(
    189                                      0u, HAL_PIXEL_FORMAT_YCBCR_420_888))
    190                 .build());
    191 
    192         addParameter(
    193                 DefineParam(mVuiRotation, C2_PARAMKEY_VUI_ROTATION)
    194                 .withDefault(new C2StreamRotationInfo::input(0u, 0))
    195                 .withFields({ C2F(mVuiRotation, value).inRange(0, 270, 90) })
    196                 .withSetter(VuiRotationSetter)
    197                 .build());
    198 
    199         addParameter(
    200                 DefineParam(mRotation, C2_PARAMKEY_ROTATION)
    201                 .withDefault(new C2StreamRotationInfo::output(0u, 0))
    202                 .withFields({ C2F(mRotation, value).inRange(0, 270, 90) })
    203                 .withSetter(RotationSetter, mVuiRotation)
    204                 .build());
    205     }
    206 
    207     static C2R SizeSetter(bool mayBlock, const C2P<C2StreamPictureSizeInfo::output> &oldMe,
    208                           C2P<C2VideoSizeStreamInfo::output> &me) {
    209         (void)mayBlock;
    210         C2R res = C2R::Ok();
    211         if (!me.F(me.v.width).supportsAtAll(me.v.width)) {
    212             res = res.plus(C2SettingResultBuilder::BadValue(me.F(me.v.width)));
    213             me.set().width = oldMe.v.width;
    214         }
    215         if (!me.F(me.v.height).supportsAtAll(me.v.height)) {
    216             res = res.plus(C2SettingResultBuilder::BadValue(me.F(me.v.height)));
    217             me.set().height = oldMe.v.height;
    218         }
    219         return res;
    220     }
    221 
    222     static C2R MaxPictureSizeSetter(bool mayBlock, C2P<C2StreamMaxPictureSizeTuning::output> &me,
    223                                     const C2P<C2StreamPictureSizeInfo::output> &size) {
    224         (void)mayBlock;
    225         // TODO: get max width/height from the size's field helpers vs. hardcoding
    226         me.set().width = c2_min(c2_max(me.v.width, size.v.width), 4080u);
    227         me.set().height = c2_min(c2_max(me.v.height, size.v.height), 4080u);
    228         return C2R::Ok();
    229     }
    230 
    231     static C2R MaxInputSizeSetter(bool mayBlock, C2P<C2StreamMaxBufferSizeInfo::input> &me,
    232                                   const C2P<C2StreamMaxPictureSizeTuning::output> &maxSize) {
    233         (void)mayBlock;
    234         // assume compression ratio of 2
    235         me.set().value = (((maxSize.v.width + 15) / 16) * ((maxSize.v.height + 15) / 16) * 192);
    236         return C2R::Ok();
    237     }
    238 
    239     static C2R ProfileLevelSetter(bool mayBlock, C2P<C2StreamProfileLevelInfo::input> &me,
    240                                   const C2P<C2StreamPictureSizeInfo::output> &size) {
    241         (void)mayBlock;
    242         (void)size;
    243         (void)me;  // TODO: validate
    244         return C2R::Ok();
    245     }
    246 
    247     static C2R DefaultColorAspectsSetter(bool mayBlock, C2P<C2StreamColorAspectsTuning::input> &me) {
    248         (void)mayBlock;
    249         (void)me;
    250         // take all values
    251         return C2R::Ok();
    252     }
    253 
    254     static C2R CodedColorAspectsSetter(bool mayBlock, C2P<C2StreamColorAspectsInfo::input> &me) {
    255         (void)mayBlock;
    256         (void)me;
    257         // take all values
    258         return C2R::Ok();
    259     }
    260 
    261     static C2R ColorAspectsSetter(bool mayBlock, C2P<C2StreamColorAspectsInfo::output> &me,
    262                                   const C2P<C2StreamColorAspectsTuning::input> &def,
    263                                   const C2P<C2StreamColorAspectsInfo::input> &coded) {
    264         (void)mayBlock;
    265         // take default values for all unspecified fields, and coded values for specified ones
    266         me.set().range = coded.v.range == RANGE_UNSPECIFIED ? def.v.range : coded.v.range;
    267         me.set().primaries = coded.v.primaries == PRIMARIES_UNSPECIFIED ? def.v.primaries : coded.v.primaries;
    268         me.set().transfer = coded.v.transfer == TRANSFER_UNSPECIFIED ? def.v.transfer : coded.v.transfer;
    269         me.set().matrix = coded.v.matrix == MATRIX_UNSPECIFIED ? def.v.matrix : coded.v.matrix;
    270         // TODO: validate
    271         return C2R::Ok();
    272     }
    273 
    274     static C2R VuiRotationSetter(bool mayBlock, C2P<C2StreamRotationInfo::input> &me) {
    275         (void)mayBlock;
    276         /// round to nearest 90 degrees and normalize from 0 to 270
    277         me.set().value = ((((me.v.value / 45) + 1) / 2) & 3) * 90;
    278         return C2R::Ok(); // TODO: proper info return
    279     }
    280 
    281     static C2R RotationSetter(bool mayBlock, C2P<C2StreamRotationInfo::output> &me,
    282                               const C2P<C2StreamRotationInfo::input> &vui) {
    283         (void)mayBlock;
    284         me.set().value = vui.v.value;
    285         return C2R::Ok(); // TODO: proper info return
    286     }
    287 
    288 private:
    289     std::shared_ptr<C2StreamProfileLevelInfo::input> mProfileLevel;
    290     std::shared_ptr<C2StreamPictureSizeInfo::output> mSize;
    291     std::shared_ptr<C2StreamMaxPictureSizeTuning::output> mMaxSize;
    292     std::shared_ptr<C2StreamMaxBufferSizeInfo::input> mMaxInputSize;
    293     std::shared_ptr<C2StreamColorInfo::output> mColorInfo;
    294     std::shared_ptr<C2StreamColorAspectsTuning::input> mDefaultColorAspects;
    295     std::shared_ptr<C2StreamColorAspectsInfo::input> mCodedColorAspects;
    296     std::shared_ptr<C2StreamColorAspectsInfo::output> mColorAspects;
    297     std::shared_ptr<C2StreamPixelFormatInfo::output> mPixelFormat;
    298     std::shared_ptr<C2StreamRotationInfo::input> mVuiRotation;
    299     std::shared_ptr<C2StreamRotationInfo::output> mRotation;
    300 };
    301 
    302 static size_t getCpuCoreCount() {
    303     long cpuCoreCount = 1;
    304 #if defined(_SC_NPROCESSORS_ONLN)
    305     cpuCoreCount = sysconf(_SC_NPROCESSORS_ONLN);
    306 #else
    307     // _SC_NPROC_ONLN must be defined...
    308     cpuCoreCount = sysconf(_SC_NPROC_ONLN);
    309 #endif
    310     CHECK(cpuCoreCount >= 1);
    311     ALOGV("Number of CPU cores: %ld", cpuCoreCount);
    312     return (size_t)cpuCoreCount;
    313 }
    314 
    315 static void *ivd_aligned_malloc(void *ctxt, WORD32 alignment, WORD32 size) {
    316     (void) ctxt;
    317     return memalign(alignment, size);
    318 }
    319 
    320 static void ivd_aligned_free(void *ctxt, void *mem) {
    321     (void) ctxt;
    322     free(mem);
    323 }
    324 
    325 C2SoftAvcDec::C2SoftAvcDec(
    326         const char *name,
    327         c2_node_id_t id,
    328         const std::shared_ptr<IntfImpl> &intfImpl)
    329     : SimpleC2Component(std::make_shared<SimpleInterface<IntfImpl>>(name, id, intfImpl)),
    330       mIntf(intfImpl),
    331       mDecHandle(nullptr),
    332       mOutBufferFlush(nullptr),
    333       mIvColorFormat(IV_YUV_420P),
    334       mWidth(320),
    335       mHeight(240) {
    336     GENERATE_FILE_NAMES();
    337     CREATE_DUMP_FILE(mInFile);
    338 }
    339 
    340 C2SoftAvcDec::~C2SoftAvcDec() {
    341     onRelease();
    342 }
    343 
    344 c2_status_t C2SoftAvcDec::onInit() {
    345     status_t err = initDecoder();
    346     return err == OK ? C2_OK : C2_CORRUPTED;
    347 }
    348 
    349 c2_status_t C2SoftAvcDec::onStop() {
    350     if (OK != resetDecoder()) return C2_CORRUPTED;
    351     resetPlugin();
    352     return C2_OK;
    353 }
    354 
    355 void C2SoftAvcDec::onReset() {
    356     (void) onStop();
    357 }
    358 
    359 void C2SoftAvcDec::onRelease() {
    360     (void) deleteDecoder();
    361     if (mOutBufferFlush) {
    362         ivd_aligned_free(nullptr, mOutBufferFlush);
    363         mOutBufferFlush = nullptr;
    364     }
    365     if (mOutBlock) {
    366         mOutBlock.reset();
    367     }
    368 }
    369 
    370 c2_status_t C2SoftAvcDec::onFlush_sm() {
    371     if (OK != setFlushMode()) return C2_CORRUPTED;
    372 
    373     uint32_t bufferSize = mStride * mHeight * 3 / 2;
    374     mOutBufferFlush = (uint8_t *)ivd_aligned_malloc(nullptr, 128, bufferSize);
    375     if (!mOutBufferFlush) {
    376         ALOGE("could not allocate tmp output buffer (for flush) of size %u ", bufferSize);
    377         return C2_NO_MEMORY;
    378     }
    379 
    380     while (true) {
    381         ivd_video_decode_ip_t s_decode_ip;
    382         ivd_video_decode_op_t s_decode_op;
    383 
    384         setDecodeArgs(&s_decode_ip, &s_decode_op, nullptr, nullptr, 0, 0, 0);
    385         (void) ivdec_api_function(mDecHandle, &s_decode_ip, &s_decode_op);
    386         if (0 == s_decode_op.u4_output_present) {
    387             resetPlugin();
    388             break;
    389         }
    390     }
    391 
    392     ivd_aligned_free(nullptr, mOutBufferFlush);
    393     mOutBufferFlush = nullptr;
    394 
    395     return C2_OK;
    396 }
    397 
    398 status_t C2SoftAvcDec::createDecoder() {
    399     ivdext_create_ip_t s_create_ip;
    400     ivdext_create_op_t s_create_op;
    401 
    402     s_create_ip.s_ivd_create_ip_t.u4_size = sizeof(ivdext_create_ip_t);
    403     s_create_ip.s_ivd_create_ip_t.e_cmd = IVD_CMD_CREATE;
    404     s_create_ip.s_ivd_create_ip_t.u4_share_disp_buf = 0;
    405     s_create_ip.s_ivd_create_ip_t.e_output_format = mIvColorFormat;
    406     s_create_ip.s_ivd_create_ip_t.pf_aligned_alloc = ivd_aligned_malloc;
    407     s_create_ip.s_ivd_create_ip_t.pf_aligned_free = ivd_aligned_free;
    408     s_create_ip.s_ivd_create_ip_t.pv_mem_ctxt = nullptr;
    409     s_create_op.s_ivd_create_op_t.u4_size = sizeof(ivdext_create_op_t);
    410     IV_API_CALL_STATUS_T status = ivdec_api_function(nullptr,
    411                                                      &s_create_ip,
    412                                                      &s_create_op);
    413     if (status != IV_SUCCESS) {
    414         ALOGE("error in %s: 0x%x", __func__,
    415               s_create_op.s_ivd_create_op_t.u4_error_code);
    416         return UNKNOWN_ERROR;
    417     }
    418     mDecHandle = (iv_obj_t*)s_create_op.s_ivd_create_op_t.pv_handle;
    419     mDecHandle->pv_fxns = (void *)ivdec_api_function;
    420     mDecHandle->u4_size = sizeof(iv_obj_t);
    421 
    422     return OK;
    423 }
    424 
    425 status_t C2SoftAvcDec::setNumCores() {
    426     ivdext_ctl_set_num_cores_ip_t s_set_num_cores_ip;
    427     ivdext_ctl_set_num_cores_op_t s_set_num_cores_op;
    428 
    429     s_set_num_cores_ip.u4_size = sizeof(ivdext_ctl_set_num_cores_ip_t);
    430     s_set_num_cores_ip.e_cmd = IVD_CMD_VIDEO_CTL;
    431     s_set_num_cores_ip.e_sub_cmd = IVDEXT_CMD_CTL_SET_NUM_CORES;
    432     s_set_num_cores_ip.u4_num_cores = mNumCores;
    433     s_set_num_cores_op.u4_size = sizeof(ivdext_ctl_set_num_cores_op_t);
    434     IV_API_CALL_STATUS_T status = ivdec_api_function(mDecHandle,
    435                                                      &s_set_num_cores_ip,
    436                                                      &s_set_num_cores_op);
    437     if (IV_SUCCESS != status) {
    438         ALOGD("error in %s: 0x%x", __func__, s_set_num_cores_op.u4_error_code);
    439         return UNKNOWN_ERROR;
    440     }
    441 
    442     return OK;
    443 }
    444 
    445 status_t C2SoftAvcDec::setParams(size_t stride) {
    446     ivd_ctl_set_config_ip_t s_set_dyn_params_ip;
    447     ivd_ctl_set_config_op_t s_set_dyn_params_op;
    448 
    449     s_set_dyn_params_ip.u4_size = sizeof(ivd_ctl_set_config_ip_t);
    450     s_set_dyn_params_ip.e_cmd = IVD_CMD_VIDEO_CTL;
    451     s_set_dyn_params_ip.e_sub_cmd = IVD_CMD_CTL_SETPARAMS;
    452     s_set_dyn_params_ip.u4_disp_wd = (UWORD32) stride;
    453     s_set_dyn_params_ip.e_frm_skip_mode = IVD_SKIP_NONE;
    454     s_set_dyn_params_ip.e_frm_out_mode = IVD_DISPLAY_FRAME_OUT;
    455     s_set_dyn_params_ip.e_vid_dec_mode = IVD_DECODE_FRAME;
    456     s_set_dyn_params_op.u4_size = sizeof(ivd_ctl_set_config_op_t);
    457     IV_API_CALL_STATUS_T status = ivdec_api_function(mDecHandle,
    458                                                      &s_set_dyn_params_ip,
    459                                                      &s_set_dyn_params_op);
    460     if (status != IV_SUCCESS) {
    461         ALOGE("error in %s: 0x%x", __func__, s_set_dyn_params_op.u4_error_code);
    462         return UNKNOWN_ERROR;
    463     }
    464 
    465     return OK;
    466 }
    467 
    468 void C2SoftAvcDec::getVersion() {
    469     ivd_ctl_getversioninfo_ip_t s_get_versioninfo_ip;
    470     ivd_ctl_getversioninfo_op_t s_get_versioninfo_op;
    471     UWORD8 au1_buf[512];
    472 
    473     s_get_versioninfo_ip.u4_size = sizeof(ivd_ctl_getversioninfo_ip_t);
    474     s_get_versioninfo_ip.e_cmd = IVD_CMD_VIDEO_CTL;
    475     s_get_versioninfo_ip.e_sub_cmd = IVD_CMD_CTL_GETVERSION;
    476     s_get_versioninfo_ip.pv_version_buffer = au1_buf;
    477     s_get_versioninfo_ip.u4_version_buffer_size = sizeof(au1_buf);
    478     s_get_versioninfo_op.u4_size = sizeof(ivd_ctl_getversioninfo_op_t);
    479     IV_API_CALL_STATUS_T status = ivdec_api_function(mDecHandle,
    480                                                      &s_get_versioninfo_ip,
    481                                                      &s_get_versioninfo_op);
    482     if (status != IV_SUCCESS) {
    483         ALOGD("error in %s: 0x%x", __func__,
    484               s_get_versioninfo_op.u4_error_code);
    485     } else {
    486         ALOGV("ittiam decoder version number: %s",
    487               (char *) s_get_versioninfo_ip.pv_version_buffer);
    488     }
    489 }
    490 
    491 status_t C2SoftAvcDec::initDecoder() {
    492     if (OK != createDecoder()) return UNKNOWN_ERROR;
    493     mNumCores = MIN(getCpuCoreCount(), MAX_NUM_CORES);
    494     mStride = ALIGN64(mWidth);
    495     mSignalledError = false;
    496     mPreference = kPreferBitstream;
    497     memset(&mDefaultColorAspects, 0, sizeof(ColorAspects));
    498     memset(&mBitstreamColorAspects, 0, sizeof(ColorAspects));
    499     memset(&mFinalColorAspects, 0, sizeof(ColorAspects));
    500     mUpdateColorAspects = false;
    501     resetPlugin();
    502     (void) setNumCores();
    503     if (OK != setParams(mStride)) return UNKNOWN_ERROR;
    504     (void) getVersion();
    505 
    506     return OK;
    507 }
    508 
    509 bool C2SoftAvcDec::setDecodeArgs(ivd_video_decode_ip_t *ps_decode_ip,
    510                                  ivd_video_decode_op_t *ps_decode_op,
    511                                  C2ReadView *inBuffer,
    512                                  C2GraphicView *outBuffer,
    513                                  size_t inOffset,
    514                                  size_t inSize,
    515                                  uint32_t tsMarker) {
    516     uint32_t displayStride = mStride;
    517     uint32_t displayHeight = mHeight;
    518     size_t lumaSize = displayStride * displayHeight;
    519     size_t chromaSize = lumaSize >> 2;
    520 
    521     ps_decode_ip->u4_size = sizeof(ivd_video_decode_ip_t);
    522     ps_decode_ip->e_cmd = IVD_CMD_VIDEO_DECODE;
    523     if (inBuffer) {
    524         ps_decode_ip->u4_ts = tsMarker;
    525         ps_decode_ip->pv_stream_buffer = const_cast<uint8_t *>(inBuffer->data() + inOffset);
    526         ps_decode_ip->u4_num_Bytes = inSize;
    527     } else {
    528         ps_decode_ip->u4_ts = 0;
    529         ps_decode_ip->pv_stream_buffer = nullptr;
    530         ps_decode_ip->u4_num_Bytes = 0;
    531     }
    532     ps_decode_ip->s_out_buffer.u4_min_out_buf_size[0] = lumaSize;
    533     ps_decode_ip->s_out_buffer.u4_min_out_buf_size[1] = chromaSize;
    534     ps_decode_ip->s_out_buffer.u4_min_out_buf_size[2] = chromaSize;
    535     if (outBuffer) {
    536         if (outBuffer->width() < displayStride || outBuffer->height() < displayHeight) {
    537             ALOGE("Output buffer too small: provided (%dx%d) required (%ux%u)",
    538                   outBuffer->width(), outBuffer->height(), displayStride, displayHeight);
    539             return false;
    540         }
    541         ps_decode_ip->s_out_buffer.pu1_bufs[0] = outBuffer->data()[C2PlanarLayout::PLANE_Y];
    542         ps_decode_ip->s_out_buffer.pu1_bufs[1] = outBuffer->data()[C2PlanarLayout::PLANE_U];
    543         ps_decode_ip->s_out_buffer.pu1_bufs[2] = outBuffer->data()[C2PlanarLayout::PLANE_V];
    544     } else {
    545         ps_decode_ip->s_out_buffer.pu1_bufs[0] = mOutBufferFlush;
    546         ps_decode_ip->s_out_buffer.pu1_bufs[1] = mOutBufferFlush + lumaSize;
    547         ps_decode_ip->s_out_buffer.pu1_bufs[2] = mOutBufferFlush + lumaSize + chromaSize;
    548     }
    549     ps_decode_ip->s_out_buffer.u4_num_bufs = 3;
    550     ps_decode_op->u4_size = sizeof(ivd_video_decode_op_t);
    551 
    552     return true;
    553 }
    554 
    555 bool C2SoftAvcDec::colorAspectsDiffer(
    556         const ColorAspects &a, const ColorAspects &b) {
    557     if (a.mRange != b.mRange
    558         || a.mPrimaries != b.mPrimaries
    559         || a.mTransfer != b.mTransfer
    560         || a.mMatrixCoeffs != b.mMatrixCoeffs) {
    561         return true;
    562     }
    563     return false;
    564 }
    565 
    566 void C2SoftAvcDec::updateFinalColorAspects(
    567         const ColorAspects &otherAspects, const ColorAspects &preferredAspects) {
    568     Mutex::Autolock autoLock(mColorAspectsLock);
    569     ColorAspects newAspects;
    570     newAspects.mRange = preferredAspects.mRange != ColorAspects::RangeUnspecified ?
    571         preferredAspects.mRange : otherAspects.mRange;
    572     newAspects.mPrimaries = preferredAspects.mPrimaries != ColorAspects::PrimariesUnspecified ?
    573         preferredAspects.mPrimaries : otherAspects.mPrimaries;
    574     newAspects.mTransfer = preferredAspects.mTransfer != ColorAspects::TransferUnspecified ?
    575         preferredAspects.mTransfer : otherAspects.mTransfer;
    576     newAspects.mMatrixCoeffs = preferredAspects.mMatrixCoeffs != ColorAspects::MatrixUnspecified ?
    577         preferredAspects.mMatrixCoeffs : otherAspects.mMatrixCoeffs;
    578 
    579     // Check to see if need update mFinalColorAspects.
    580     if (colorAspectsDiffer(mFinalColorAspects, newAspects)) {
    581         mFinalColorAspects = newAspects;
    582         mUpdateColorAspects = true;
    583     }
    584 }
    585 
    586 status_t C2SoftAvcDec::handleColorAspectsChange() {
    587     if (mPreference == kPreferBitstream) {
    588         updateFinalColorAspects(mDefaultColorAspects, mBitstreamColorAspects);
    589     } else if (mPreference == kPreferContainer) {
    590         updateFinalColorAspects(mBitstreamColorAspects, mDefaultColorAspects);
    591     } else {
    592         return C2_CORRUPTED;
    593     }
    594     return C2_OK;
    595 }
    596 
    597 bool C2SoftAvcDec::getVuiParams() {
    598     ivdext_ctl_get_vui_params_ip_t s_get_vui_params_ip;
    599     ivdext_ctl_get_vui_params_op_t s_get_vui_params_op;
    600 
    601     s_get_vui_params_ip.u4_size = sizeof(ivdext_ctl_get_vui_params_ip_t);
    602     s_get_vui_params_ip.e_cmd = IVD_CMD_VIDEO_CTL;
    603     s_get_vui_params_ip.e_sub_cmd =
    604             (IVD_CONTROL_API_COMMAND_TYPE_T) IH264D_CMD_CTL_GET_VUI_PARAMS;
    605     s_get_vui_params_op.u4_size = sizeof(ivdext_ctl_get_vui_params_op_t);
    606     IV_API_CALL_STATUS_T status = ivdec_api_function(mDecHandle,
    607                                                      &s_get_vui_params_ip,
    608                                                      &s_get_vui_params_op);
    609     if (status != IV_SUCCESS) {
    610         ALOGD("error in %s: 0x%x", __func__, s_get_vui_params_op.u4_error_code);
    611         return false;
    612     }
    613 
    614     int32_t primaries = s_get_vui_params_op.u1_colour_primaries;
    615     int32_t transfer = s_get_vui_params_op.u1_tfr_chars;
    616     int32_t coeffs = s_get_vui_params_op.u1_matrix_coeffs;
    617     bool fullRange = s_get_vui_params_op.u1_video_full_range_flag;
    618 
    619     ColorAspects colorAspects;
    620     ColorUtils::convertIsoColorAspectsToCodecAspects(
    621             primaries, transfer, coeffs, fullRange, colorAspects);
    622     // Update color aspects if necessary.
    623     if (colorAspectsDiffer(colorAspects, mBitstreamColorAspects)) {
    624         mBitstreamColorAspects = colorAspects;
    625         status_t err = handleColorAspectsChange();
    626         CHECK(err == OK);
    627     }
    628 
    629     return true;
    630 }
    631 
    632 status_t C2SoftAvcDec::setFlushMode() {
    633     ivd_ctl_flush_ip_t s_set_flush_ip;
    634     ivd_ctl_flush_op_t s_set_flush_op;
    635 
    636     s_set_flush_ip.u4_size = sizeof(ivd_ctl_flush_ip_t);
    637     s_set_flush_ip.e_cmd = IVD_CMD_VIDEO_CTL;
    638     s_set_flush_ip.e_sub_cmd = IVD_CMD_CTL_FLUSH;
    639     s_set_flush_op.u4_size = sizeof(ivd_ctl_flush_op_t);
    640     IV_API_CALL_STATUS_T status = ivdec_api_function(mDecHandle,
    641                                                      &s_set_flush_ip,
    642                                                      &s_set_flush_op);
    643     if (status != IV_SUCCESS) {
    644         ALOGE("error in %s: 0x%x", __func__, s_set_flush_op.u4_error_code);
    645         return UNKNOWN_ERROR;
    646     }
    647 
    648     return OK;
    649 }
    650 
    651 status_t C2SoftAvcDec::resetDecoder() {
    652     ivd_ctl_reset_ip_t s_reset_ip;
    653     ivd_ctl_reset_op_t s_reset_op;
    654 
    655     s_reset_ip.u4_size = sizeof(ivd_ctl_reset_ip_t);
    656     s_reset_ip.e_cmd = IVD_CMD_VIDEO_CTL;
    657     s_reset_ip.e_sub_cmd = IVD_CMD_CTL_RESET;
    658     s_reset_op.u4_size = sizeof(ivd_ctl_reset_op_t);
    659     IV_API_CALL_STATUS_T status = ivdec_api_function(mDecHandle,
    660                                                      &s_reset_ip,
    661                                                      &s_reset_op);
    662     if (IV_SUCCESS != status) {
    663         ALOGE("error in %s: 0x%x", __func__, s_reset_op.u4_error_code);
    664         return UNKNOWN_ERROR;
    665     }
    666     mStride = 0;
    667     (void) setNumCores();
    668     mSignalledError = false;
    669 
    670     return OK;
    671 }
    672 
    673 void C2SoftAvcDec::resetPlugin() {
    674     mSignalledOutputEos = false;
    675     gettimeofday(&mTimeStart, nullptr);
    676     gettimeofday(&mTimeEnd, nullptr);
    677 }
    678 
    679 status_t C2SoftAvcDec::deleteDecoder() {
    680     if (mDecHandle) {
    681         ivdext_delete_ip_t s_delete_ip;
    682         ivdext_delete_op_t s_delete_op;
    683 
    684         s_delete_ip.s_ivd_delete_ip_t.u4_size = sizeof(ivdext_delete_ip_t);
    685         s_delete_ip.s_ivd_delete_ip_t.e_cmd = IVD_CMD_DELETE;
    686         s_delete_op.s_ivd_delete_op_t.u4_size = sizeof(ivdext_delete_op_t);
    687         IV_API_CALL_STATUS_T status = ivdec_api_function(mDecHandle,
    688                                                          &s_delete_ip,
    689                                                          &s_delete_op);
    690         if (status != IV_SUCCESS) {
    691             ALOGE("error in %s: 0x%x", __func__,
    692                   s_delete_op.s_ivd_delete_op_t.u4_error_code);
    693             return UNKNOWN_ERROR;
    694         }
    695         mDecHandle = nullptr;
    696     }
    697 
    698     return OK;
    699 }
    700 
    701 static void fillEmptyWork(const std::unique_ptr<C2Work> &work) {
    702     uint32_t flags = 0;
    703     if (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) {
    704         flags |= C2FrameData::FLAG_END_OF_STREAM;
    705         ALOGV("signalling eos");
    706     }
    707     work->worklets.front()->output.flags = (C2FrameData::flags_t)flags;
    708     work->worklets.front()->output.buffers.clear();
    709     work->worklets.front()->output.ordinal = work->input.ordinal;
    710     work->workletsProcessed = 1u;
    711 }
    712 
    713 void C2SoftAvcDec::finishWork(uint64_t index, const std::unique_ptr<C2Work> &work) {
    714     std::shared_ptr<C2Buffer> buffer = createGraphicBuffer(std::move(mOutBlock),
    715                                                            C2Rect(mWidth, mHeight));
    716     mOutBlock = nullptr;
    717     auto fillWork = [buffer, index](const std::unique_ptr<C2Work> &work) {
    718         uint32_t flags = 0;
    719         if ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM) &&
    720                 (c2_cntr64_t(index) == work->input.ordinal.frameIndex)) {
    721             flags |= C2FrameData::FLAG_END_OF_STREAM;
    722             ALOGV("signalling eos");
    723         }
    724         work->worklets.front()->output.flags = (C2FrameData::flags_t)flags;
    725         work->worklets.front()->output.buffers.clear();
    726         work->worklets.front()->output.buffers.push_back(buffer);
    727         work->worklets.front()->output.ordinal = work->input.ordinal;
    728         work->workletsProcessed = 1u;
    729     };
    730     if (work && c2_cntr64_t(index) == work->input.ordinal.frameIndex) {
    731         fillWork(work);
    732     } else {
    733         finish(index, fillWork);
    734     }
    735 }
    736 
    737 c2_status_t C2SoftAvcDec::ensureDecoderState(const std::shared_ptr<C2BlockPool> &pool) {
    738     if (!mDecHandle) {
    739         ALOGE("not supposed to be here, invalid decoder context");
    740         return C2_CORRUPTED;
    741     }
    742     if (mStride != ALIGN64(mWidth)) {
    743         mStride = ALIGN64(mWidth);
    744         if (OK != setParams(mStride)) return C2_CORRUPTED;
    745     }
    746     if (mOutBlock &&
    747             (mOutBlock->width() != mStride || mOutBlock->height() != mHeight)) {
    748         mOutBlock.reset();
    749     }
    750     if (!mOutBlock) {
    751         uint32_t format = HAL_PIXEL_FORMAT_YV12;
    752         C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
    753         c2_status_t err = pool->fetchGraphicBlock(mStride, mHeight, format, usage, &mOutBlock);
    754         if (err != C2_OK) {
    755             ALOGE("fetchGraphicBlock for Output failed with status %d", err);
    756             return err;
    757         }
    758         ALOGV("provided (%dx%d) required (%dx%d)",
    759               mOutBlock->width(), mOutBlock->height(), mStride, mHeight);
    760     }
    761 
    762     return C2_OK;
    763 }
    764 
    765 // TODO: can overall error checking be improved?
    766 // TODO: allow configuration of color format and usage for graphic buffers instead
    767 //       of hard coding them to HAL_PIXEL_FORMAT_YV12
    768 // TODO: pass coloraspects information to surface
    769 // TODO: test support for dynamic change in resolution
    770 // TODO: verify if the decoder sent back all frames
    771 void C2SoftAvcDec::process(
    772         const std::unique_ptr<C2Work> &work,
    773         const std::shared_ptr<C2BlockPool> &pool) {
    774     work->result = C2_OK;
    775     work->workletsProcessed = 0u;
    776     if (mSignalledError || mSignalledOutputEos) {
    777         work->result = C2_BAD_VALUE;
    778         return;
    779     }
    780 
    781     size_t inOffset = 0u;
    782     size_t inSize = 0u;
    783     uint32_t workIndex = work->input.ordinal.frameIndex.peeku() & 0xFFFFFFFF;
    784     C2ReadView rView = mDummyReadView;
    785     if (!work->input.buffers.empty()) {
    786         rView = work->input.buffers[0]->data().linearBlocks().front().map().get();
    787         inSize = rView.capacity();
    788         if (inSize && rView.error()) {
    789             ALOGE("read view map failed %d", rView.error());
    790             work->result = rView.error();
    791             return;
    792         }
    793     }
    794     bool eos = ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0);
    795     bool hasPicture = false;
    796 
    797     ALOGV("in buffer attr. size %zu timestamp %d frameindex %d, flags %x",
    798           inSize, (int)work->input.ordinal.timestamp.peeku(),
    799           (int)work->input.ordinal.frameIndex.peeku(), work->input.flags);
    800     size_t inPos = 0;
    801     while (inPos < inSize) {
    802         if (C2_OK != ensureDecoderState(pool)) {
    803             mSignalledError = true;
    804             work->result = C2_CORRUPTED;
    805             return;
    806         }
    807 
    808         ivd_video_decode_ip_t s_decode_ip;
    809         ivd_video_decode_op_t s_decode_op;
    810         {
    811             C2GraphicView wView = mOutBlock->map().get();
    812             if (wView.error()) {
    813                 ALOGE("graphic view map failed %d", wView.error());
    814                 work->result = wView.error();
    815                 return;
    816             }
    817             if (!setDecodeArgs(&s_decode_ip, &s_decode_op, &rView, &wView,
    818                                inOffset + inPos, inSize - inPos, workIndex)) {
    819                 mSignalledError = true;
    820                 work->result = C2_CORRUPTED;
    821                 return;
    822             }
    823             WORD32 delay;
    824             GETTIME(&mTimeStart, NULL);
    825             TIME_DIFF(mTimeEnd, mTimeStart, delay);
    826             (void) ivdec_api_function(mDecHandle, &s_decode_ip, &s_decode_op);
    827             WORD32 decodeTime;
    828             GETTIME(&mTimeEnd, nullptr);
    829             TIME_DIFF(mTimeStart, mTimeEnd, decodeTime);
    830             ALOGV("decodeTime=%6d delay=%6d numBytes=%6d", decodeTime, delay,
    831                   s_decode_op.u4_num_bytes_consumed);
    832         }
    833         if (IVD_MEM_ALLOC_FAILED == (s_decode_op.u4_error_code & 0xFF)) {
    834             ALOGE("allocation failure in decoder");
    835             work->result = C2_CORRUPTED;
    836             mSignalledError = true;
    837             return;
    838         } else if (IVD_STREAM_WIDTH_HEIGHT_NOT_SUPPORTED == (s_decode_op.u4_error_code & 0xFF)) {
    839             ALOGE("unsupported resolution : %dx%d", mWidth, mHeight);
    840             work->result = C2_CORRUPTED;
    841             mSignalledError = true;
    842             return;
    843         } else if (IVD_RES_CHANGED == (s_decode_op.u4_error_code & 0xFF)) {
    844             ALOGV("resolution changed");
    845             drainInternal(DRAIN_COMPONENT_NO_EOS, pool, work);
    846             resetDecoder();
    847             resetPlugin();
    848             continue;
    849         }
    850         if (0 < s_decode_op.u4_pic_wd && 0 < s_decode_op.u4_pic_ht) {
    851             if (s_decode_op.u4_pic_wd != mWidth || s_decode_op.u4_pic_ht != mHeight) {
    852                 mWidth = s_decode_op.u4_pic_wd;
    853                 mHeight = s_decode_op.u4_pic_ht;
    854                 CHECK_EQ(0u, s_decode_op.u4_output_present);
    855 
    856                 C2VideoSizeStreamInfo::output size(0u, mWidth, mHeight);
    857                 std::vector<std::unique_ptr<C2SettingResult>> failures;
    858                 (void)mIntf->config({&size}, C2_MAY_BLOCK, &failures);
    859                 work->worklets.front()->output.configUpdate.push_back(C2Param::Copy(size));
    860                 continue;
    861             }
    862         }
    863         (void) getVuiParams();
    864         if (mUpdateColorAspects) {
    865             mUpdateColorAspects = false;
    866         }
    867         hasPicture |= (1 == s_decode_op.u4_frame_decoded_flag);
    868         if (s_decode_op.u4_output_present) {
    869             finishWork(s_decode_op.u4_ts, work);
    870         }
    871         inPos += s_decode_op.u4_num_bytes_consumed;
    872         if (hasPicture && (inSize - inPos)) {
    873             ALOGD("decoded frame in current access nal, ignoring further trailing bytes %d",
    874                   (int)inSize - (int)inPos);
    875             break;
    876         }
    877     }
    878     if (eos) {
    879         drainInternal(DRAIN_COMPONENT_WITH_EOS, pool, work);
    880         mSignalledOutputEos = true;
    881     } else if (!hasPicture) {
    882         fillEmptyWork(work);
    883     }
    884 }
    885 
    886 c2_status_t C2SoftAvcDec::drainInternal(
    887         uint32_t drainMode,
    888         const std::shared_ptr<C2BlockPool> &pool,
    889         const std::unique_ptr<C2Work> &work) {
    890     if (drainMode == NO_DRAIN) {
    891         ALOGW("drain with NO_DRAIN: no-op");
    892         return C2_OK;
    893     }
    894     if (drainMode == DRAIN_CHAIN) {
    895         ALOGW("DRAIN_CHAIN not supported");
    896         return C2_OMITTED;
    897     }
    898 
    899     if (OK != setFlushMode()) return C2_CORRUPTED;
    900     while (true) {
    901         if (C2_OK != ensureDecoderState(pool)) {
    902             mSignalledError = true;
    903             work->result = C2_CORRUPTED;
    904             return C2_CORRUPTED;
    905         }
    906         C2GraphicView wView = mOutBlock->map().get();
    907         if (wView.error()) {
    908             ALOGE("graphic view map failed %d", wView.error());
    909             return C2_CORRUPTED;
    910         }
    911         ivd_video_decode_ip_t s_decode_ip;
    912         ivd_video_decode_op_t s_decode_op;
    913         if (!setDecodeArgs(&s_decode_ip, &s_decode_op, nullptr, &wView, 0, 0, 0)) {
    914             mSignalledError = true;
    915             return C2_CORRUPTED;
    916         }
    917         (void) ivdec_api_function(mDecHandle, &s_decode_ip, &s_decode_op);
    918         if (s_decode_op.u4_output_present) {
    919             finishWork(s_decode_op.u4_ts, work);
    920         } else {
    921             break;
    922         }
    923     }
    924 
    925     if (drainMode == DRAIN_COMPONENT_WITH_EOS &&
    926             work && work->workletsProcessed == 0u) {
    927         fillEmptyWork(work);
    928     }
    929 
    930     return C2_OK;
    931 }
    932 
    933 c2_status_t C2SoftAvcDec::drain(
    934         uint32_t drainMode,
    935         const std::shared_ptr<C2BlockPool> &pool) {
    936     return drainInternal(drainMode, pool, nullptr);
    937 }
    938 
    939 class C2SoftAvcDecFactory : public C2ComponentFactory {
    940 public:
    941     C2SoftAvcDecFactory() : mHelper(std::static_pointer_cast<C2ReflectorHelper>(
    942         GetCodec2PlatformComponentStore()->getParamReflector())) {
    943     }
    944 
    945     virtual c2_status_t createComponent(
    946             c2_node_id_t id,
    947             std::shared_ptr<C2Component>* const component,
    948             std::function<void(C2Component*)> deleter) override {
    949         *component = std::shared_ptr<C2Component>(
    950                 new C2SoftAvcDec(COMPONENT_NAME,
    951                                  id,
    952                                  std::make_shared<C2SoftAvcDec::IntfImpl>(mHelper)),
    953                 deleter);
    954         return C2_OK;
    955     }
    956 
    957     virtual c2_status_t createInterface(
    958             c2_node_id_t id,
    959             std::shared_ptr<C2ComponentInterface>* const interface,
    960             std::function<void(C2ComponentInterface*)> deleter) override {
    961         *interface = std::shared_ptr<C2ComponentInterface>(
    962                 new SimpleInterface<C2SoftAvcDec::IntfImpl>(
    963                         COMPONENT_NAME, id, std::make_shared<C2SoftAvcDec::IntfImpl>(mHelper)),
    964                 deleter);
    965         return C2_OK;
    966     }
    967 
    968     virtual ~C2SoftAvcDecFactory() override = default;
    969 
    970 private:
    971     std::shared_ptr<C2ReflectorHelper> mHelper;
    972 };
    973 
    974 }  // namespace android
    975 
    976 extern "C" ::C2ComponentFactory* CreateCodec2Factory() {
    977     ALOGV("in %s", __func__);
    978     return new ::android::C2SoftAvcDecFactory();
    979 }
    980 
    981 extern "C" void DestroyCodec2Factory(::C2ComponentFactory* factory) {
    982     ALOGV("in %s", __func__);
    983     delete factory;
    984 }
    985