Home | History | Annotate | Download | only in aom
      1 /*
      2  * Copyright (C) 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 "C2SoftAomDec"
     19 #include <log/log.h>
     20 
     21 #include <media/stagefright/foundation/AUtils.h>
     22 #include <media/stagefright/foundation/MediaDefs.h>
     23 
     24 #include <C2Debug.h>
     25 #include <C2PlatformSupport.h>
     26 #include <SimpleC2Interface.h>
     27 
     28 #include "C2SoftAomDec.h"
     29 
     30 namespace android {
     31 
     32 constexpr char COMPONENT_NAME[] = "c2.android.av1.decoder";
     33 
     34 class C2SoftAomDec::IntfImpl : public SimpleInterface<void>::BaseParams {
     35   public:
     36     explicit IntfImpl(const std::shared_ptr<C2ReflectorHelper>& helper)
     37         : SimpleInterface<void>::BaseParams(
     38               helper, COMPONENT_NAME, C2Component::KIND_DECODER,
     39               C2Component::DOMAIN_VIDEO, MEDIA_MIMETYPE_VIDEO_AV1) {
     40         noPrivateBuffers();  // TODO: account for our buffers here
     41         noInputReferences();
     42         noOutputReferences();
     43         noInputLatency();
     44         noTimeStretch();
     45 
     46         addParameter(DefineParam(mAttrib, C2_PARAMKEY_COMPONENT_ATTRIBUTES)
     47                          .withConstValue(new C2ComponentAttributesSetting(
     48                              C2Component::ATTRIB_IS_TEMPORAL))
     49                          .build());
     50 
     51         addParameter(
     52             DefineParam(mSize, C2_PARAMKEY_PICTURE_SIZE)
     53                 .withDefault(new C2StreamPictureSizeInfo::output(0u, 320, 240))
     54                 .withFields({
     55                     C2F(mSize, width).inRange(2, 2048, 2),
     56                     C2F(mSize, height).inRange(2, 2048, 2),
     57                 })
     58                 .withSetter(SizeSetter)
     59                 .build());
     60 
     61         addParameter(
     62                 DefineParam(mProfileLevel, C2_PARAMKEY_PROFILE_LEVEL)
     63                 .withDefault(new C2StreamProfileLevelInfo::input(0u,
     64                         C2Config::PROFILE_AV1_0, C2Config::LEVEL_AV1_2_1))
     65                 .withFields({
     66                     C2F(mProfileLevel, profile).oneOf({
     67                             C2Config::PROFILE_AV1_0,
     68                             C2Config::PROFILE_AV1_1}),
     69                     C2F(mProfileLevel, level).oneOf({
     70                             C2Config::LEVEL_AV1_2,
     71                             C2Config::LEVEL_AV1_2_1,
     72                             C2Config::LEVEL_AV1_2_2,
     73                             C2Config::LEVEL_AV1_3,
     74                             C2Config::LEVEL_AV1_3_1,
     75                             C2Config::LEVEL_AV1_3_2,
     76                     })
     77                 })
     78                 .withSetter(ProfileLevelSetter, mSize)
     79                 .build());
     80 
     81         mHdr10PlusInfoInput = C2StreamHdr10PlusInfo::input::AllocShared(0);
     82         addParameter(
     83                 DefineParam(mHdr10PlusInfoInput, C2_PARAMKEY_INPUT_HDR10_PLUS_INFO)
     84                 .withDefault(mHdr10PlusInfoInput)
     85                 .withFields({
     86                     C2F(mHdr10PlusInfoInput, m.value).any(),
     87                 })
     88                 .withSetter(Hdr10PlusInfoInputSetter)
     89                 .build());
     90 
     91         mHdr10PlusInfoOutput = C2StreamHdr10PlusInfo::output::AllocShared(0);
     92         addParameter(
     93                 DefineParam(mHdr10PlusInfoOutput, C2_PARAMKEY_OUTPUT_HDR10_PLUS_INFO)
     94                 .withDefault(mHdr10PlusInfoOutput)
     95                 .withFields({
     96                     C2F(mHdr10PlusInfoOutput, m.value).any(),
     97                 })
     98                 .withSetter(Hdr10PlusInfoOutputSetter)
     99                 .build());
    100 
    101         addParameter(DefineParam(mMaxSize, C2_PARAMKEY_MAX_PICTURE_SIZE)
    102                          .withDefault(new C2StreamMaxPictureSizeTuning::output(
    103                              0u, 320, 240))
    104                          .withFields({
    105                              C2F(mSize, width).inRange(2, 2048, 2),
    106                              C2F(mSize, height).inRange(2, 2048, 2),
    107                          })
    108                          .withSetter(MaxPictureSizeSetter, mSize)
    109                          .build());
    110 
    111         addParameter(
    112             DefineParam(mMaxInputSize, C2_PARAMKEY_INPUT_MAX_BUFFER_SIZE)
    113                 .withDefault(
    114                     new C2StreamMaxBufferSizeInfo::input(0u, 320 * 240 * 3 / 4))
    115                 .withFields({
    116                     C2F(mMaxInputSize, value).any(),
    117                 })
    118                 .calculatedAs(MaxInputSizeSetter, mMaxSize)
    119                 .build());
    120 
    121         C2ChromaOffsetStruct locations[1] = {
    122             C2ChromaOffsetStruct::ITU_YUV_420_0()};
    123         std::shared_ptr<C2StreamColorInfo::output> defaultColorInfo =
    124             C2StreamColorInfo::output::AllocShared(1u, 0u, 8u /* bitDepth */,
    125                                                    C2Color::YUV_420);
    126         memcpy(defaultColorInfo->m.locations, locations, sizeof(locations));
    127 
    128         defaultColorInfo = C2StreamColorInfo::output::AllocShared(
    129             {C2ChromaOffsetStruct::ITU_YUV_420_0()}, 0u, 8u /* bitDepth */,
    130             C2Color::YUV_420);
    131         helper->addStructDescriptors<C2ChromaOffsetStruct>();
    132 
    133         addParameter(DefineParam(mColorInfo, C2_PARAMKEY_CODED_COLOR_INFO)
    134                          .withConstValue(defaultColorInfo)
    135                          .build());
    136 
    137         addParameter(
    138                 DefineParam(mDefaultColorAspects, C2_PARAMKEY_DEFAULT_COLOR_ASPECTS)
    139                 .withDefault(new C2StreamColorAspectsTuning::output(
    140                         0u, C2Color::RANGE_UNSPECIFIED, C2Color::PRIMARIES_UNSPECIFIED,
    141                         C2Color::TRANSFER_UNSPECIFIED, C2Color::MATRIX_UNSPECIFIED))
    142                 .withFields({
    143                     C2F(mDefaultColorAspects, range).inRange(
    144                                 C2Color::RANGE_UNSPECIFIED,     C2Color::RANGE_OTHER),
    145                     C2F(mDefaultColorAspects, primaries).inRange(
    146                                 C2Color::PRIMARIES_UNSPECIFIED, C2Color::PRIMARIES_OTHER),
    147                     C2F(mDefaultColorAspects, transfer).inRange(
    148                                 C2Color::TRANSFER_UNSPECIFIED,  C2Color::TRANSFER_OTHER),
    149                     C2F(mDefaultColorAspects, matrix).inRange(
    150                                 C2Color::MATRIX_UNSPECIFIED,    C2Color::MATRIX_OTHER)
    151                 })
    152                 .withSetter(DefaultColorAspectsSetter)
    153                 .build());
    154 
    155         // TODO: support more formats?
    156         addParameter(DefineParam(mPixelFormat, C2_PARAMKEY_PIXEL_FORMAT)
    157                          .withConstValue(new C2StreamPixelFormatInfo::output(
    158                              0u, HAL_PIXEL_FORMAT_YCBCR_420_888))
    159                          .build());
    160     }
    161 
    162     static C2R SizeSetter(bool mayBlock,
    163                           const C2P<C2StreamPictureSizeInfo::output>& oldMe,
    164                           C2P<C2StreamPictureSizeInfo::output>& me) {
    165         (void)mayBlock;
    166         C2R res = C2R::Ok();
    167         if (!me.F(me.v.width).supportsAtAll(me.v.width)) {
    168             res = res.plus(C2SettingResultBuilder::BadValue(me.F(me.v.width)));
    169             me.set().width = oldMe.v.width;
    170         }
    171         if (!me.F(me.v.height).supportsAtAll(me.v.height)) {
    172             res = res.plus(C2SettingResultBuilder::BadValue(me.F(me.v.height)));
    173             me.set().height = oldMe.v.height;
    174         }
    175         return res;
    176     }
    177 
    178     static C2R MaxPictureSizeSetter(
    179         bool mayBlock, C2P<C2StreamMaxPictureSizeTuning::output>& me,
    180         const C2P<C2StreamPictureSizeInfo::output>& size) {
    181         (void)mayBlock;
    182         // TODO: get max width/height from the size's field helpers vs.
    183         // hardcoding
    184         me.set().width = c2_min(c2_max(me.v.width, size.v.width), 4096u);
    185         me.set().height = c2_min(c2_max(me.v.height, size.v.height), 4096u);
    186         return C2R::Ok();
    187     }
    188 
    189     static C2R MaxInputSizeSetter(
    190         bool mayBlock, C2P<C2StreamMaxBufferSizeInfo::input>& me,
    191         const C2P<C2StreamMaxPictureSizeTuning::output>& maxSize) {
    192         (void)mayBlock;
    193         // assume compression ratio of 2
    194         me.set().value = (((maxSize.v.width + 63) / 64) *
    195                           ((maxSize.v.height + 63) / 64) * 3072);
    196         return C2R::Ok();
    197     }
    198     static C2R DefaultColorAspectsSetter(bool mayBlock, C2P<C2StreamColorAspectsTuning::output> &me) {
    199         (void)mayBlock;
    200         if (me.v.range > C2Color::RANGE_OTHER) {
    201             me.set().range = C2Color::RANGE_OTHER;
    202         }
    203         if (me.v.primaries > C2Color::PRIMARIES_OTHER) {
    204             me.set().primaries = C2Color::PRIMARIES_OTHER;
    205         }
    206         if (me.v.transfer > C2Color::TRANSFER_OTHER) {
    207             me.set().transfer = C2Color::TRANSFER_OTHER;
    208         }
    209         if (me.v.matrix > C2Color::MATRIX_OTHER) {
    210             me.set().matrix = C2Color::MATRIX_OTHER;
    211         }
    212         return C2R::Ok();
    213     }
    214 
    215     static C2R ProfileLevelSetter(bool mayBlock, C2P<C2StreamProfileLevelInfo::input> &me,
    216                                   const C2P<C2StreamPictureSizeInfo::output> &size) {
    217         (void)mayBlock;
    218         (void)size;
    219         (void)me;  // TODO: validate
    220         return C2R::Ok();
    221     }
    222     std::shared_ptr<C2StreamColorAspectsTuning::output> getDefaultColorAspects_l() {
    223         return mDefaultColorAspects;
    224     }
    225 
    226     static C2R Hdr10PlusInfoInputSetter(bool mayBlock, C2P<C2StreamHdr10PlusInfo::input> &me) {
    227         (void)mayBlock;
    228         (void)me;  // TODO: validate
    229         return C2R::Ok();
    230     }
    231 
    232     static C2R Hdr10PlusInfoOutputSetter(bool mayBlock, C2P<C2StreamHdr10PlusInfo::output> &me) {
    233         (void)mayBlock;
    234         (void)me;  // TODO: validate
    235         return C2R::Ok();
    236     }
    237 
    238   private:
    239     std::shared_ptr<C2StreamProfileLevelInfo::input> mProfileLevel;
    240     std::shared_ptr<C2StreamPictureSizeInfo::output> mSize;
    241     std::shared_ptr<C2StreamMaxPictureSizeTuning::output> mMaxSize;
    242     std::shared_ptr<C2StreamMaxBufferSizeInfo::input> mMaxInputSize;
    243     std::shared_ptr<C2StreamColorInfo::output> mColorInfo;
    244     std::shared_ptr<C2StreamPixelFormatInfo::output> mPixelFormat;
    245     std::shared_ptr<C2StreamColorAspectsTuning::output> mDefaultColorAspects;
    246     std::shared_ptr<C2StreamHdr10PlusInfo::input> mHdr10PlusInfoInput;
    247     std::shared_ptr<C2StreamHdr10PlusInfo::output> mHdr10PlusInfoOutput;
    248 };
    249 
    250 C2SoftAomDec::C2SoftAomDec(const char* name, c2_node_id_t id,
    251                            const std::shared_ptr<IntfImpl>& intfImpl)
    252     : SimpleC2Component(
    253           std::make_shared<SimpleInterface<IntfImpl>>(name, id, intfImpl)),
    254       mIntf(intfImpl),
    255       mCodecCtx(nullptr){
    256 
    257     GENERATE_FILE_NAMES();
    258     CREATE_DUMP_FILE(mInFile);
    259     CREATE_DUMP_FILE(mOutFile);
    260 
    261     gettimeofday(&mTimeStart, nullptr);
    262     gettimeofday(&mTimeEnd, nullptr);
    263 }
    264 
    265 C2SoftAomDec::~C2SoftAomDec() {
    266     onRelease();
    267 }
    268 
    269 c2_status_t C2SoftAomDec::onInit() {
    270     status_t err = initDecoder();
    271     return err == OK ? C2_OK : C2_CORRUPTED;
    272 }
    273 
    274 c2_status_t C2SoftAomDec::onStop() {
    275     mSignalledError = false;
    276     mSignalledOutputEos = false;
    277     return C2_OK;
    278 }
    279 
    280 void C2SoftAomDec::onReset() {
    281     (void)onStop();
    282     c2_status_t err = onFlush_sm();
    283     if (err != C2_OK) {
    284         ALOGW("Failed to flush decoder. Try to hard reset decoder.");
    285         destroyDecoder();
    286         (void)initDecoder();
    287     }
    288 }
    289 
    290 void C2SoftAomDec::onRelease() {
    291     destroyDecoder();
    292 }
    293 
    294 c2_status_t C2SoftAomDec::onFlush_sm() {
    295     if (aom_codec_decode(mCodecCtx, nullptr, 0, nullptr)) {
    296         ALOGE("Failed to flush av1 decoder.");
    297         return C2_CORRUPTED;
    298     }
    299 
    300     aom_codec_iter_t iter = nullptr;
    301     while (aom_codec_get_frame(mCodecCtx, &iter)) {
    302     }
    303 
    304     mSignalledError = false;
    305     mSignalledOutputEos = false;
    306 
    307     return C2_OK;
    308 }
    309 
    310 static int GetCPUCoreCount() {
    311     int cpuCoreCount = 1;
    312 #if defined(_SC_NPROCESSORS_ONLN)
    313     cpuCoreCount = sysconf(_SC_NPROCESSORS_ONLN);
    314 #else
    315     // _SC_NPROC_ONLN must be defined...
    316     cpuCoreCount = sysconf(_SC_NPROC_ONLN);
    317 #endif
    318     CHECK(cpuCoreCount >= 1);
    319     ALOGV("Number of CPU cores: %d", cpuCoreCount);
    320     return cpuCoreCount;
    321 }
    322 
    323 status_t C2SoftAomDec::initDecoder() {
    324     mSignalledError = false;
    325     mSignalledOutputEos = false;
    326     if (!mCodecCtx) {
    327         mCodecCtx = new aom_codec_ctx_t;
    328     }
    329 
    330     if (!mCodecCtx) {
    331         ALOGE("mCodecCtx is null");
    332         return NO_MEMORY;
    333     }
    334 
    335     aom_codec_dec_cfg_t cfg;
    336     memset(&cfg, 0, sizeof(aom_codec_dec_cfg_t));
    337     cfg.threads = GetCPUCoreCount();
    338     cfg.allow_lowbitdepth = 1;
    339 
    340     aom_codec_flags_t flags;
    341     memset(&flags, 0, sizeof(aom_codec_flags_t));
    342 
    343     aom_codec_err_t err;
    344     if ((err = aom_codec_dec_init(mCodecCtx, aom_codec_av1_dx(), &cfg, 0))) {
    345         ALOGE("av1 decoder failed to initialize. (%d)", err);
    346         return UNKNOWN_ERROR;
    347     }
    348 
    349     return OK;
    350 }
    351 
    352 status_t C2SoftAomDec::destroyDecoder() {
    353     if (mCodecCtx) {
    354         aom_codec_destroy(mCodecCtx);
    355         delete mCodecCtx;
    356         mCodecCtx = nullptr;
    357     }
    358     return OK;
    359 }
    360 
    361 void fillEmptyWork(const std::unique_ptr<C2Work>& work) {
    362     uint32_t flags = 0;
    363     if (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) {
    364         flags |= C2FrameData::FLAG_END_OF_STREAM;
    365         ALOGV("signalling eos");
    366     }
    367     work->worklets.front()->output.flags = (C2FrameData::flags_t)flags;
    368     work->worklets.front()->output.buffers.clear();
    369     work->worklets.front()->output.ordinal = work->input.ordinal;
    370     work->workletsProcessed = 1u;
    371 }
    372 
    373 void C2SoftAomDec::finishWork(uint64_t index,
    374                               const std::unique_ptr<C2Work>& work,
    375                               const std::shared_ptr<C2GraphicBlock>& block) {
    376     std::shared_ptr<C2Buffer> buffer =
    377         createGraphicBuffer(block, C2Rect(mWidth, mHeight));
    378     auto fillWork = [buffer, index, intf = this->mIntf](
    379             const std::unique_ptr<C2Work>& work) {
    380         uint32_t flags = 0;
    381         if ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM) &&
    382             (c2_cntr64_t(index) == work->input.ordinal.frameIndex)) {
    383             flags |= C2FrameData::FLAG_END_OF_STREAM;
    384             ALOGV("signalling eos");
    385         }
    386         work->worklets.front()->output.flags = (C2FrameData::flags_t)flags;
    387         work->worklets.front()->output.buffers.clear();
    388         work->worklets.front()->output.buffers.push_back(buffer);
    389         work->worklets.front()->output.ordinal = work->input.ordinal;
    390         work->workletsProcessed = 1u;
    391 
    392         for (const std::unique_ptr<C2Param> &param: work->input.configUpdate) {
    393             if (param) {
    394                 C2StreamHdr10PlusInfo::input *hdr10PlusInfo =
    395                         C2StreamHdr10PlusInfo::input::From(param.get());
    396 
    397                 if (hdr10PlusInfo != nullptr) {
    398                     std::vector<std::unique_ptr<C2SettingResult>> failures;
    399                     std::unique_ptr<C2Param> outParam = C2Param::CopyAsStream(
    400                             *param.get(), true /*output*/, param->stream());
    401                     c2_status_t err = intf->config(
    402                             { outParam.get() }, C2_MAY_BLOCK, &failures);
    403                     if (err == C2_OK) {
    404                         work->worklets.front()->output.configUpdate.push_back(
    405                                 C2Param::Copy(*outParam.get()));
    406                     } else {
    407                         ALOGE("finishWork: Config update size failed");
    408                     }
    409                     break;
    410                 }
    411             }
    412         }
    413     };
    414     if (work && c2_cntr64_t(index) == work->input.ordinal.frameIndex) {
    415         fillWork(work);
    416     } else {
    417         finish(index, fillWork);
    418     }
    419 }
    420 
    421 void C2SoftAomDec::process(const std::unique_ptr<C2Work>& work,
    422                            const std::shared_ptr<C2BlockPool>& pool) {
    423     work->result = C2_OK;
    424     work->workletsProcessed = 0u;
    425     work->worklets.front()->output.configUpdate.clear();
    426     work->worklets.front()->output.flags = work->input.flags;
    427     if (mSignalledError || mSignalledOutputEos) {
    428         work->result = C2_BAD_VALUE;
    429         return;
    430     }
    431 
    432     size_t inOffset = 0u;
    433     size_t inSize = 0u;
    434     C2ReadView rView = mDummyReadView;
    435     if (!work->input.buffers.empty()) {
    436         rView =
    437             work->input.buffers[0]->data().linearBlocks().front().map().get();
    438         inSize = rView.capacity();
    439         if (inSize && rView.error()) {
    440             ALOGE("read view map failed %d", rView.error());
    441             work->result = C2_CORRUPTED;
    442             return;
    443         }
    444     }
    445 
    446     bool codecConfig =
    447         ((work->input.flags & C2FrameData::FLAG_CODEC_CONFIG) != 0);
    448     bool eos = ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0);
    449 
    450     ALOGV("in buffer attr. size %zu timestamp %d frameindex %d, flags %x",
    451           inSize, (int)work->input.ordinal.timestamp.peeku(),
    452           (int)work->input.ordinal.frameIndex.peeku(), work->input.flags);
    453 
    454     if (codecConfig) {
    455         fillEmptyWork(work);
    456         return;
    457     }
    458 
    459     int64_t frameIndex = work->input.ordinal.frameIndex.peekll();
    460     if (inSize) {
    461         uint8_t* bitstream = const_cast<uint8_t*>(rView.data() + inOffset);
    462         int32_t decodeTime = 0;
    463         int32_t delay = 0;
    464 
    465         DUMP_TO_FILE(mOutFile, bitstream, inSize);
    466         GETTIME(&mTimeStart, nullptr);
    467         TIME_DIFF(mTimeEnd, mTimeStart, delay);
    468 
    469         aom_codec_err_t err =
    470             aom_codec_decode(mCodecCtx, bitstream, inSize, &frameIndex);
    471 
    472         GETTIME(&mTimeEnd, nullptr);
    473         TIME_DIFF(mTimeStart, mTimeEnd, decodeTime);
    474         ALOGV("decodeTime=%4d delay=%4d\n", decodeTime, delay);
    475 
    476         if (err != AOM_CODEC_OK) {
    477             ALOGE("av1 decoder failed to decode frame err: %d", err);
    478             work->result = C2_CORRUPTED;
    479             work->workletsProcessed = 1u;
    480             mSignalledError = true;
    481             return;
    482         }
    483 
    484     } else {
    485         if (aom_codec_decode(mCodecCtx, nullptr, 0, nullptr)) {
    486             ALOGE("Failed to flush av1 decoder.");
    487             work->result = C2_CORRUPTED;
    488             work->workletsProcessed = 1u;
    489             mSignalledError = true;
    490             return;
    491         }
    492     }
    493 
    494     (void)outputBuffer(pool, work);
    495 
    496     if (eos) {
    497         drainInternal(DRAIN_COMPONENT_WITH_EOS, pool, work);
    498         mSignalledOutputEos = true;
    499     } else if (!inSize) {
    500         fillEmptyWork(work);
    501     }
    502 }
    503 
    504 static void copyOutputBufferToYuvPlanarFrame(
    505         uint8_t *dst, const uint8_t *srcY, const uint8_t *srcU, const uint8_t *srcV,
    506         size_t srcYStride, size_t srcUStride, size_t srcVStride,
    507         size_t dstYStride, size_t dstUVStride,
    508         uint32_t width, uint32_t height) {
    509     uint8_t* dstStart = dst;
    510 
    511     for (size_t i = 0; i < height; ++i) {
    512         memcpy(dst, srcY, width);
    513         srcY += srcYStride;
    514         dst += dstYStride;
    515     }
    516 
    517     dst = dstStart + dstYStride * height;
    518     for (size_t i = 0; i < height / 2; ++i) {
    519          memcpy(dst, srcV, width / 2);
    520         srcV += srcVStride;
    521         dst += dstUVStride;
    522     }
    523 
    524     dst = dstStart + (dstYStride * height) + (dstUVStride * height / 2);
    525     for (size_t i = 0; i < height / 2; ++i) {
    526          memcpy(dst, srcU, width / 2);
    527         srcU += srcUStride;
    528         dst += dstUVStride;
    529     }
    530 }
    531 
    532 static void convertYUV420Planar16ToY410(uint32_t *dst,
    533         const uint16_t *srcY, const uint16_t *srcU, const uint16_t *srcV,
    534         size_t srcYStride, size_t srcUStride, size_t srcVStride,
    535         size_t dstStride, size_t width, size_t height) {
    536 
    537     // Converting two lines at a time, slightly faster
    538     for (size_t y = 0; y < height; y += 2) {
    539         uint32_t *dstTop = (uint32_t *) dst;
    540         uint32_t *dstBot = (uint32_t *) (dst + dstStride);
    541         uint16_t *ySrcTop = (uint16_t*) srcY;
    542         uint16_t *ySrcBot = (uint16_t*) (srcY + srcYStride);
    543         uint16_t *uSrc = (uint16_t*) srcU;
    544         uint16_t *vSrc = (uint16_t*) srcV;
    545 
    546         uint32_t u01, v01, y01, y23, y45, y67, uv0, uv1;
    547         size_t x = 0;
    548         for (; x < width - 3; x += 4) {
    549 
    550             u01 = *((uint32_t*)uSrc); uSrc += 2;
    551             v01 = *((uint32_t*)vSrc); vSrc += 2;
    552 
    553             y01 = *((uint32_t*)ySrcTop); ySrcTop += 2;
    554             y23 = *((uint32_t*)ySrcTop); ySrcTop += 2;
    555             y45 = *((uint32_t*)ySrcBot); ySrcBot += 2;
    556             y67 = *((uint32_t*)ySrcBot); ySrcBot += 2;
    557 
    558             uv0 = (u01 & 0x3FF) | ((v01 & 0x3FF) << 20);
    559             uv1 = (u01 >> 16) | ((v01 >> 16) << 20);
    560 
    561             *dstTop++ = 3 << 30 | ((y01 & 0x3FF) << 10) | uv0;
    562             *dstTop++ = 3 << 30 | ((y01 >> 16) << 10) | uv0;
    563             *dstTop++ = 3 << 30 | ((y23 & 0x3FF) << 10) | uv1;
    564             *dstTop++ = 3 << 30 | ((y23 >> 16) << 10) | uv1;
    565 
    566             *dstBot++ = 3 << 30 | ((y45 & 0x3FF) << 10) | uv0;
    567             *dstBot++ = 3 << 30 | ((y45 >> 16) << 10) | uv0;
    568             *dstBot++ = 3 << 30 | ((y67 & 0x3FF) << 10) | uv1;
    569             *dstBot++ = 3 << 30 | ((y67 >> 16) << 10) | uv1;
    570         }
    571 
    572         // There should be at most 2 more pixels to process. Note that we don't
    573         // need to consider odd case as the buffer is always aligned to even.
    574         if (x < width) {
    575             u01 = *uSrc;
    576             v01 = *vSrc;
    577             y01 = *((uint32_t*)ySrcTop);
    578             y45 = *((uint32_t*)ySrcBot);
    579             uv0 = (u01 & 0x3FF) | ((v01 & 0x3FF) << 20);
    580             *dstTop++ = ((y01 & 0x3FF) << 10) | uv0;
    581             *dstTop++ = ((y01 >> 16) << 10) | uv0;
    582             *dstBot++ = ((y45 & 0x3FF) << 10) | uv0;
    583             *dstBot++ = ((y45 >> 16) << 10) | uv0;
    584         }
    585 
    586         srcY += srcYStride * 2;
    587         srcU += srcUStride;
    588         srcV += srcVStride;
    589         dst += dstStride * 2;
    590     }
    591 
    592     return;
    593 }
    594 
    595 static void convertYUV420Planar16ToYUV420Planar(uint8_t *dst,
    596         const uint16_t *srcY, const uint16_t *srcU, const uint16_t *srcV,
    597         size_t srcYStride, size_t srcUStride, size_t srcVStride,
    598         size_t dstYStride, size_t dstUVStride, size_t width, size_t height) {
    599 
    600     uint8_t *dstY = (uint8_t *)dst;
    601     size_t dstYSize = dstYStride * height;
    602     size_t dstUVSize = dstUVStride * height / 2;
    603     uint8_t *dstV = dstY + dstYSize;
    604     uint8_t *dstU = dstV + dstUVSize;
    605 
    606     for (size_t y = 0; y < height; ++y) {
    607         for (size_t x = 0; x < width; ++x) {
    608             dstY[x] = (uint8_t)(srcY[x] >> 2);
    609         }
    610 
    611         srcY += srcYStride;
    612         dstY += dstYStride;
    613     }
    614 
    615     for (size_t y = 0; y < (height + 1) / 2; ++y) {
    616         for (size_t x = 0; x < (width + 1) / 2; ++x) {
    617             dstU[x] = (uint8_t)(srcU[x] >> 2);
    618             dstV[x] = (uint8_t)(srcV[x] >> 2);
    619         }
    620 
    621         srcU += srcUStride;
    622         srcV += srcVStride;
    623         dstU += dstUVStride;
    624         dstV += dstUVStride;
    625     }
    626     return;
    627 }
    628 bool C2SoftAomDec::outputBuffer(
    629         const std::shared_ptr<C2BlockPool> &pool,
    630         const std::unique_ptr<C2Work> &work)
    631 {
    632     if (!(work && pool)) return false;
    633 
    634     aom_codec_iter_t iter = nullptr;
    635     aom_image_t* img = aom_codec_get_frame(mCodecCtx, &iter);
    636 
    637     if (!img) return false;
    638 
    639     if (img->d_w != mWidth || img->d_h != mHeight) {
    640         mWidth = img->d_w;
    641         mHeight = img->d_h;
    642 
    643         C2StreamPictureSizeInfo::output size(0u, mWidth, mHeight);
    644         std::vector<std::unique_ptr<C2SettingResult>> failures;
    645         c2_status_t err = mIntf->config({&size}, C2_MAY_BLOCK, &failures);
    646         if (err == C2_OK) {
    647             work->worklets.front()->output.configUpdate.push_back(
    648                 C2Param::Copy(size));
    649         } else {
    650             ALOGE("Config update size failed");
    651             mSignalledError = true;
    652             work->result = C2_CORRUPTED;
    653             work->workletsProcessed = 1u;
    654             return false;
    655         }
    656     }
    657 
    658     CHECK(img->fmt == AOM_IMG_FMT_I420 || img->fmt == AOM_IMG_FMT_I42016);
    659 
    660     std::shared_ptr<C2GraphicBlock> block;
    661     uint32_t format = HAL_PIXEL_FORMAT_YV12;
    662     if (img->fmt == AOM_IMG_FMT_I42016) {
    663         IntfImpl::Lock lock = mIntf->lock();
    664         std::shared_ptr<C2StreamColorAspectsTuning::output> defaultColorAspects = mIntf->getDefaultColorAspects_l();
    665 
    666         if (defaultColorAspects->primaries == C2Color::PRIMARIES_BT2020 &&
    667             defaultColorAspects->matrix == C2Color::MATRIX_BT2020 &&
    668             defaultColorAspects->transfer == C2Color::TRANSFER_ST2084) {
    669             format = HAL_PIXEL_FORMAT_RGBA_1010102;
    670         }
    671     }
    672     C2MemoryUsage usage = {C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE};
    673 
    674     c2_status_t err = pool->fetchGraphicBlock(align(mWidth, 16), mHeight,
    675                                               format, usage, &block);
    676 
    677     if (err != C2_OK) {
    678         ALOGE("fetchGraphicBlock for Output failed with status %d", err);
    679         work->result = err;
    680         return false;
    681     }
    682 
    683     C2GraphicView wView = block->map().get();
    684 
    685     if (wView.error()) {
    686         ALOGE("graphic view map failed %d", wView.error());
    687         work->result = C2_CORRUPTED;
    688         return false;
    689     }
    690 
    691     ALOGV("provided (%dx%d) required (%dx%d), out frameindex %d",
    692           block->width(), block->height(), mWidth, mHeight,
    693           (int)*(int64_t*)img->user_priv);
    694 
    695     uint8_t* dst = const_cast<uint8_t*>(wView.data()[C2PlanarLayout::PLANE_Y]);
    696     size_t srcYStride = img->stride[AOM_PLANE_Y];
    697     size_t srcUStride = img->stride[AOM_PLANE_U];
    698     size_t srcVStride = img->stride[AOM_PLANE_V];
    699     C2PlanarLayout layout = wView.layout();
    700     size_t dstYStride = layout.planes[C2PlanarLayout::PLANE_Y].rowInc;
    701     size_t dstUVStride = layout.planes[C2PlanarLayout::PLANE_U].rowInc;
    702 
    703     if (img->fmt == AOM_IMG_FMT_I42016) {
    704         const uint16_t *srcY = (const uint16_t *)img->planes[AOM_PLANE_Y];
    705         const uint16_t *srcU = (const uint16_t *)img->planes[AOM_PLANE_U];
    706         const uint16_t *srcV = (const uint16_t *)img->planes[AOM_PLANE_V];
    707 
    708         if (format == HAL_PIXEL_FORMAT_RGBA_1010102) {
    709             convertYUV420Planar16ToY410((uint32_t *)dst, srcY, srcU, srcV, srcYStride / 2,
    710                                     srcUStride / 2, srcVStride / 2,
    711                                     dstYStride / sizeof(uint32_t),
    712                                     mWidth, mHeight);
    713         } else {
    714             convertYUV420Planar16ToYUV420Planar(dst, srcY, srcU, srcV, srcYStride / 2,
    715                                     srcUStride / 2, srcVStride / 2,
    716                                     dstYStride, dstUVStride,
    717                                     mWidth, mHeight);
    718         }
    719     } else {
    720         const uint8_t *srcY = (const uint8_t *)img->planes[AOM_PLANE_Y];
    721         const uint8_t *srcU = (const uint8_t *)img->planes[AOM_PLANE_U];
    722         const uint8_t *srcV = (const uint8_t *)img->planes[AOM_PLANE_V];
    723         copyOutputBufferToYuvPlanarFrame(
    724                 dst, srcY, srcU, srcV,
    725                 srcYStride, srcUStride, srcVStride,
    726                 dstYStride, dstUVStride,
    727                 mWidth, mHeight);
    728     }
    729     finishWork(*(int64_t*)img->user_priv, work, std::move(block));
    730     block = nullptr;
    731     return true;
    732 }
    733 
    734 c2_status_t C2SoftAomDec::drainInternal(
    735     uint32_t drainMode, const std::shared_ptr<C2BlockPool>& pool,
    736     const std::unique_ptr<C2Work>& work) {
    737     if (drainMode == NO_DRAIN) {
    738         ALOGW("drain with NO_DRAIN: no-op");
    739         return C2_OK;
    740     }
    741     if (drainMode == DRAIN_CHAIN) {
    742         ALOGW("DRAIN_CHAIN not supported");
    743         return C2_OMITTED;
    744     }
    745 
    746     if (aom_codec_decode(mCodecCtx, nullptr, 0, nullptr)) {
    747         ALOGE("Failed to flush av1 decoder.");
    748         return C2_CORRUPTED;
    749     }
    750 
    751     while ((outputBuffer(pool, work))) {
    752     }
    753 
    754     if (drainMode == DRAIN_COMPONENT_WITH_EOS && work &&
    755         work->workletsProcessed == 0u) {
    756         fillEmptyWork(work);
    757     }
    758 
    759     return C2_OK;
    760 }
    761 
    762 c2_status_t C2SoftAomDec::drain(uint32_t drainMode,
    763                                 const std::shared_ptr<C2BlockPool>& pool) {
    764     return drainInternal(drainMode, pool, nullptr);
    765 }
    766 
    767 class C2SoftAomFactory : public C2ComponentFactory {
    768    public:
    769     C2SoftAomFactory()
    770         : mHelper(std::static_pointer_cast<C2ReflectorHelper>(
    771               GetCodec2PlatformComponentStore()->getParamReflector())) {}
    772 
    773     virtual c2_status_t createComponent(
    774         c2_node_id_t id, std::shared_ptr<C2Component>* const component,
    775         std::function<void(C2Component*)> deleter) override {
    776         *component = std::shared_ptr<C2Component>(
    777             new C2SoftAomDec(COMPONENT_NAME, id,
    778                              std::make_shared<C2SoftAomDec::IntfImpl>(mHelper)),
    779             deleter);
    780         return C2_OK;
    781     }
    782 
    783     virtual c2_status_t createInterface(
    784         c2_node_id_t id, std::shared_ptr<C2ComponentInterface>* const interface,
    785         std::function<void(C2ComponentInterface*)> deleter) override {
    786         *interface = std::shared_ptr<C2ComponentInterface>(
    787             new SimpleInterface<C2SoftAomDec::IntfImpl>(
    788                 COMPONENT_NAME, id,
    789                 std::make_shared<C2SoftAomDec::IntfImpl>(mHelper)),
    790             deleter);
    791         return C2_OK;
    792     }
    793 
    794     virtual ~C2SoftAomFactory() override = default;
    795 
    796    private:
    797     std::shared_ptr<C2ReflectorHelper> mHelper;
    798 };
    799 
    800 }  // namespace android
    801 
    802 extern "C" ::C2ComponentFactory* CreateCodec2Factory() {
    803     ALOGV("in %s", __func__);
    804     return new ::android::C2SoftAomFactory();
    805 }
    806 
    807 extern "C" void DestroyCodec2Factory(::C2ComponentFactory* factory) {
    808     ALOGV("in %s", __func__);
    809     delete factory;
    810 }
    811