Home | History | Annotate | Download | only in mpeg4_h263
      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 #ifdef MPEG4
     19   #define LOG_TAG "C2SoftMpeg4Dec"
     20 #else
     21   #define LOG_TAG "C2SoftH263Dec"
     22 #endif
     23 #include <log/log.h>
     24 
     25 #include <media/stagefright/foundation/AUtils.h>
     26 #include <media/stagefright/foundation/MediaDefs.h>
     27 
     28 #include <C2Debug.h>
     29 #include <C2PlatformSupport.h>
     30 #include <SimpleC2Interface.h>
     31 
     32 #include "C2SoftMpeg4Dec.h"
     33 #include "mp4dec_api.h"
     34 
     35 namespace android {
     36 
     37 #ifdef MPEG4
     38 constexpr char COMPONENT_NAME[] = "c2.android.mpeg4.decoder";
     39 #else
     40 constexpr char COMPONENT_NAME[] = "c2.android.h263.decoder";
     41 #endif
     42 
     43 class C2SoftMpeg4Dec::IntfImpl : public SimpleInterface<void>::BaseParams {
     44 public:
     45     explicit IntfImpl(const std::shared_ptr<C2ReflectorHelper> &helper)
     46         : SimpleInterface<void>::BaseParams(
     47                 helper,
     48                 COMPONENT_NAME,
     49                 C2Component::KIND_DECODER,
     50                 C2Component::DOMAIN_VIDEO,
     51 #ifdef MPEG4
     52                 MEDIA_MIMETYPE_VIDEO_MPEG4
     53 #else
     54                 MEDIA_MIMETYPE_VIDEO_H263
     55 #endif
     56                 ) {
     57         noPrivateBuffers(); // TODO: account for our buffers here
     58         noInputReferences();
     59         noOutputReferences();
     60         noInputLatency();
     61         noTimeStretch();
     62 
     63         // TODO: Proper support for reorder depth.
     64         addParameter(
     65                 DefineParam(mActualOutputDelay, C2_PARAMKEY_OUTPUT_DELAY)
     66                 .withConstValue(new C2PortActualDelayTuning::output(1u))
     67                 .build());
     68 
     69         addParameter(
     70                 DefineParam(mAttrib, C2_PARAMKEY_COMPONENT_ATTRIBUTES)
     71                 .withConstValue(new C2ComponentAttributesSetting(C2Component::ATTRIB_IS_TEMPORAL))
     72                 .build());
     73 
     74         addParameter(
     75                 DefineParam(mSize, C2_PARAMKEY_PICTURE_SIZE)
     76                 .withDefault(new C2StreamPictureSizeInfo::output(0u, 176, 144))
     77                 .withFields({
     78 #ifdef MPEG4
     79                     C2F(mSize, width).inRange(2, 1920, 2),
     80                     C2F(mSize, height).inRange(2, 1088, 2),
     81 #else
     82                     C2F(mSize, width).inRange(2, 352, 2),
     83                     C2F(mSize, height).inRange(2, 288, 2),
     84 #endif
     85                 })
     86                 .withSetter(SizeSetter)
     87                 .build());
     88 
     89 #ifdef MPEG4
     90         addParameter(
     91                 DefineParam(mProfileLevel, C2_PARAMKEY_PROFILE_LEVEL)
     92                 .withDefault(new C2StreamProfileLevelInfo::input(0u,
     93                         C2Config::PROFILE_MP4V_SIMPLE, C2Config::LEVEL_MP4V_3))
     94                 .withFields({
     95                     C2F(mProfileLevel, profile).equalTo(
     96                             C2Config::PROFILE_MP4V_SIMPLE),
     97                     C2F(mProfileLevel, level).oneOf({
     98                             C2Config::LEVEL_MP4V_0,
     99                             C2Config::LEVEL_MP4V_0B,
    100                             C2Config::LEVEL_MP4V_1,
    101                             C2Config::LEVEL_MP4V_2,
    102                             C2Config::LEVEL_MP4V_3,
    103                             C2Config::LEVEL_MP4V_3B,
    104                             C2Config::LEVEL_MP4V_4,
    105                             C2Config::LEVEL_MP4V_4A,
    106                             C2Config::LEVEL_MP4V_5,
    107                             C2Config::LEVEL_MP4V_6})
    108                 })
    109                 .withSetter(ProfileLevelSetter, mSize)
    110                 .build());
    111 #else
    112         addParameter(
    113                 DefineParam(mProfileLevel, C2_PARAMKEY_PROFILE_LEVEL)
    114                 .withDefault(new C2StreamProfileLevelInfo::input(0u,
    115                         C2Config::PROFILE_H263_BASELINE, C2Config::LEVEL_H263_30))
    116                 .withFields({
    117                     C2F(mProfileLevel, profile).oneOf({
    118                             C2Config::PROFILE_H263_BASELINE,
    119                             C2Config::PROFILE_H263_ISWV2}),
    120                     C2F(mProfileLevel, level).oneOf({
    121                             C2Config::LEVEL_H263_10,
    122                             C2Config::LEVEL_H263_20,
    123                             C2Config::LEVEL_H263_30,
    124                             C2Config::LEVEL_H263_40,
    125                             C2Config::LEVEL_H263_45})
    126                 })
    127                 .withSetter(ProfileLevelSetter, mSize)
    128                 .build());
    129 #endif
    130 
    131         addParameter(
    132                 DefineParam(mMaxSize, C2_PARAMKEY_MAX_PICTURE_SIZE)
    133 #ifdef MPEG4
    134                 .withDefault(new C2StreamMaxPictureSizeTuning::output(0u, 1920, 1088))
    135 #else
    136                 .withDefault(new C2StreamMaxPictureSizeTuning::output(0u, 352, 288))
    137 #endif
    138                 .withFields({
    139 #ifdef MPEG4
    140                     C2F(mSize, width).inRange(2, 1920, 2),
    141                     C2F(mSize, height).inRange(2, 1088, 2),
    142 #else
    143                     C2F(mSize, width).inRange(2, 352, 2),
    144                     C2F(mSize, height).inRange(2, 288, 2),
    145 #endif
    146                 })
    147                 .withSetter(MaxPictureSizeSetter, mSize)
    148                 .build());
    149 
    150         addParameter(
    151                 DefineParam(mMaxInputSize, C2_PARAMKEY_INPUT_MAX_BUFFER_SIZE)
    152 #ifdef MPEG4
    153                 .withDefault(new C2StreamMaxBufferSizeInfo::input(0u, 1920 * 1088 * 3 / 2))
    154 #else
    155                 .withDefault(new C2StreamMaxBufferSizeInfo::input(0u, 352 * 288 * 3 / 2))
    156 #endif
    157                 .withFields({
    158                     C2F(mMaxInputSize, value).any(),
    159                 })
    160                 .calculatedAs(MaxInputSizeSetter, mMaxSize)
    161                 .build());
    162 
    163         C2ChromaOffsetStruct locations[1] = { C2ChromaOffsetStruct::ITU_YUV_420_0() };
    164         std::shared_ptr<C2StreamColorInfo::output> defaultColorInfo =
    165             C2StreamColorInfo::output::AllocShared(
    166                     1u, 0u, 8u /* bitDepth */, C2Color::YUV_420);
    167         memcpy(defaultColorInfo->m.locations, locations, sizeof(locations));
    168 
    169         defaultColorInfo =
    170             C2StreamColorInfo::output::AllocShared(
    171                     { C2ChromaOffsetStruct::ITU_YUV_420_0() },
    172                     0u, 8u /* bitDepth */, C2Color::YUV_420);
    173         helper->addStructDescriptors<C2ChromaOffsetStruct>();
    174 
    175         addParameter(
    176                 DefineParam(mColorInfo, C2_PARAMKEY_CODED_COLOR_INFO)
    177                 .withConstValue(defaultColorInfo)
    178                 .build());
    179 
    180         // TODO: support more formats?
    181         addParameter(
    182                 DefineParam(mPixelFormat, C2_PARAMKEY_PIXEL_FORMAT)
    183                 .withConstValue(new C2StreamPixelFormatInfo::output(
    184                                      0u, HAL_PIXEL_FORMAT_YCBCR_420_888))
    185                 .build());
    186     }
    187 
    188     static C2R SizeSetter(bool mayBlock, const C2P<C2StreamPictureSizeInfo::output> &oldMe,
    189                           C2P<C2StreamPictureSizeInfo::output> &me) {
    190         (void)mayBlock;
    191         C2R res = C2R::Ok();
    192         if (!me.F(me.v.width).supportsAtAll(me.v.width)) {
    193             res = res.plus(C2SettingResultBuilder::BadValue(me.F(me.v.width)));
    194             me.set().width = oldMe.v.width;
    195         }
    196         if (!me.F(me.v.height).supportsAtAll(me.v.height)) {
    197             res = res.plus(C2SettingResultBuilder::BadValue(me.F(me.v.height)));
    198             me.set().height = oldMe.v.height;
    199         }
    200         return res;
    201     }
    202 
    203     static C2R MaxPictureSizeSetter(bool mayBlock, C2P<C2StreamMaxPictureSizeTuning::output> &me,
    204                                     const C2P<C2StreamPictureSizeInfo::output> &size) {
    205         (void)mayBlock;
    206         // TODO: get max width/height from the size's field helpers vs. hardcoding
    207 #ifdef MPEG4
    208         me.set().width = c2_min(c2_max(me.v.width, size.v.width), 1920u);
    209         me.set().height = c2_min(c2_max(me.v.height, size.v.height), 1088u);
    210 #else
    211         me.set().width = c2_min(c2_max(me.v.width, size.v.width), 352u);
    212         me.set().height = c2_min(c2_max(me.v.height, size.v.height), 288u);
    213 #endif
    214         return C2R::Ok();
    215     }
    216 
    217     static C2R MaxInputSizeSetter(bool mayBlock, C2P<C2StreamMaxBufferSizeInfo::input> &me,
    218                                   const C2P<C2StreamMaxPictureSizeTuning::output> &maxSize) {
    219         (void)mayBlock;
    220         // assume compression ratio of 1
    221         me.set().value = (((maxSize.v.width + 15) / 16) * ((maxSize.v.height + 15) / 16) * 384);
    222         return C2R::Ok();
    223     }
    224 
    225     static C2R ProfileLevelSetter(bool mayBlock, C2P<C2StreamProfileLevelInfo::input> &me,
    226                                   const C2P<C2StreamPictureSizeInfo::output> &size) {
    227         (void)mayBlock;
    228         (void)size;
    229         (void)me;  // TODO: validate
    230         return C2R::Ok();
    231     }
    232 
    233     uint32_t getMaxWidth() const { return mMaxSize->width; }
    234     uint32_t getMaxHeight() const { return mMaxSize->height; }
    235 
    236 private:
    237     std::shared_ptr<C2StreamProfileLevelInfo::input> mProfileLevel;
    238     std::shared_ptr<C2StreamPictureSizeInfo::output> mSize;
    239     std::shared_ptr<C2StreamMaxPictureSizeTuning::output> mMaxSize;
    240     std::shared_ptr<C2StreamMaxBufferSizeInfo::input> mMaxInputSize;
    241     std::shared_ptr<C2StreamColorInfo::output> mColorInfo;
    242     std::shared_ptr<C2StreamPixelFormatInfo::output> mPixelFormat;
    243 };
    244 
    245 C2SoftMpeg4Dec::C2SoftMpeg4Dec(
    246         const char *name,
    247         c2_node_id_t id,
    248         const std::shared_ptr<IntfImpl> &intfImpl)
    249     : SimpleC2Component(std::make_shared<SimpleInterface<IntfImpl>>(name, id, intfImpl)),
    250       mIntf(intfImpl),
    251       mDecHandle(nullptr),
    252       mOutputBuffer{},
    253       mInitialized(false) {
    254 }
    255 
    256 C2SoftMpeg4Dec::~C2SoftMpeg4Dec() {
    257     onRelease();
    258 }
    259 
    260 c2_status_t C2SoftMpeg4Dec::onInit() {
    261     status_t err = initDecoder();
    262     return err == OK ? C2_OK : C2_CORRUPTED;
    263 }
    264 
    265 c2_status_t C2SoftMpeg4Dec::onStop() {
    266     if (mInitialized) {
    267         if (mDecHandle) {
    268             PVCleanUpVideoDecoder(mDecHandle);
    269         }
    270         mInitialized = false;
    271     }
    272     for (int32_t i = 0; i < kNumOutputBuffers; ++i) {
    273         if (mOutputBuffer[i]) {
    274             free(mOutputBuffer[i]);
    275             mOutputBuffer[i] = nullptr;
    276         }
    277     }
    278     mNumSamplesOutput = 0;
    279     mFramesConfigured = false;
    280     mSignalledOutputEos = false;
    281     mSignalledError = false;
    282 
    283     return C2_OK;
    284 }
    285 
    286 void C2SoftMpeg4Dec::onReset() {
    287     (void)onStop();
    288     (void)onInit();
    289 }
    290 
    291 void C2SoftMpeg4Dec::onRelease() {
    292     if (mInitialized) {
    293         if (mDecHandle) {
    294             PVCleanUpVideoDecoder(mDecHandle);
    295             delete mDecHandle;
    296             mDecHandle = nullptr;
    297         }
    298         mInitialized = false;
    299     }
    300     if (mOutBlock) {
    301         mOutBlock.reset();
    302     }
    303     for (int32_t i = 0; i < kNumOutputBuffers; ++i) {
    304         if (mOutputBuffer[i]) {
    305             free(mOutputBuffer[i]);
    306             mOutputBuffer[i] = nullptr;
    307         }
    308     }
    309 }
    310 
    311 c2_status_t C2SoftMpeg4Dec::onFlush_sm() {
    312     if (mInitialized) {
    313         if (PV_TRUE != PVResetVideoDecoder(mDecHandle)) {
    314             return C2_CORRUPTED;
    315         }
    316     }
    317     mSignalledOutputEos = false;
    318     mSignalledError = false;
    319     return C2_OK;
    320 }
    321 
    322 status_t C2SoftMpeg4Dec::initDecoder() {
    323 #ifdef MPEG4
    324     mIsMpeg4 = true;
    325 #else
    326     mIsMpeg4 = false;
    327 #endif
    328     if (!mDecHandle) {
    329         mDecHandle = new tagvideoDecControls;
    330     }
    331     if (!mDecHandle) {
    332         ALOGE("mDecHandle is null");
    333         return NO_MEMORY;
    334     }
    335     memset(mDecHandle, 0, sizeof(tagvideoDecControls));
    336 
    337     /* TODO: bring these values to 352 and 288. It cannot be done as of now
    338      * because, h263 doesn't seem to allow port reconfiguration. In OMX, the
    339      * problem of larger width and height than default width and height is
    340      * overcome by adaptivePlayBack() api call. This call gets width and height
    341      * information from extractor. Such a thing is not possible here.
    342      * So we are configuring to larger values.*/
    343     mWidth = 1408;
    344     mHeight = 1152;
    345     mNumSamplesOutput = 0;
    346     mInitialized = false;
    347     mFramesConfigured = false;
    348     mSignalledOutputEos = false;
    349     mSignalledError = false;
    350 
    351     return OK;
    352 }
    353 
    354 void fillEmptyWork(const std::unique_ptr<C2Work> &work) {
    355     uint32_t flags = 0;
    356     if (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) {
    357         flags |= C2FrameData::FLAG_END_OF_STREAM;
    358         ALOGV("signalling eos");
    359     }
    360     work->worklets.front()->output.flags = (C2FrameData::flags_t)flags;
    361     work->worklets.front()->output.buffers.clear();
    362     work->worklets.front()->output.ordinal = work->input.ordinal;
    363     work->workletsProcessed = 1u;
    364 }
    365 
    366 void C2SoftMpeg4Dec::finishWork(uint64_t index, const std::unique_ptr<C2Work> &work) {
    367     std::shared_ptr<C2Buffer> buffer = createGraphicBuffer(std::move(mOutBlock),
    368                                                            C2Rect(mWidth, mHeight));
    369     mOutBlock = nullptr;
    370     auto fillWork = [buffer, index](const std::unique_ptr<C2Work> &work) {
    371         uint32_t flags = 0;
    372         if ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM) &&
    373                 (c2_cntr64_t(index) == work->input.ordinal.frameIndex)) {
    374             flags |= C2FrameData::FLAG_END_OF_STREAM;
    375             ALOGV("signalling eos");
    376         }
    377         work->worklets.front()->output.flags = (C2FrameData::flags_t)flags;
    378         work->worklets.front()->output.buffers.clear();
    379         work->worklets.front()->output.buffers.push_back(buffer);
    380         work->worklets.front()->output.ordinal = work->input.ordinal;
    381         work->workletsProcessed = 1u;
    382     };
    383     if (work && c2_cntr64_t(index) == work->input.ordinal.frameIndex) {
    384         fillWork(work);
    385     } else {
    386         finish(index, fillWork);
    387     }
    388 }
    389 
    390 c2_status_t C2SoftMpeg4Dec::ensureDecoderState(const std::shared_ptr<C2BlockPool> &pool) {
    391     if (!mDecHandle) {
    392         ALOGE("not supposed to be here, invalid decoder context");
    393         return C2_CORRUPTED;
    394     }
    395 
    396     mOutputBufferSize = align(mIntf->getMaxWidth(), 16) * align(mIntf->getMaxHeight(), 16) * 3 / 2;
    397     for (int32_t i = 0; i < kNumOutputBuffers; ++i) {
    398         if (!mOutputBuffer[i]) {
    399             mOutputBuffer[i] = (uint8_t *)malloc(mOutputBufferSize);
    400             if (!mOutputBuffer[i]) {
    401                 return C2_NO_MEMORY;
    402             }
    403         }
    404     }
    405     if (mOutBlock &&
    406             (mOutBlock->width() != align(mWidth, 16) || mOutBlock->height() != mHeight)) {
    407         mOutBlock.reset();
    408     }
    409     if (!mOutBlock) {
    410         uint32_t format = HAL_PIXEL_FORMAT_YV12;
    411         C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
    412         c2_status_t err = pool->fetchGraphicBlock(align(mWidth, 16), mHeight, format, usage, &mOutBlock);
    413         if (err != C2_OK) {
    414             ALOGE("fetchGraphicBlock for Output failed with status %d", err);
    415             return err;
    416         }
    417         ALOGV("provided (%dx%d) required (%dx%d)",
    418               mOutBlock->width(), mOutBlock->height(), mWidth, mHeight);
    419     }
    420     return C2_OK;
    421 }
    422 
    423 bool C2SoftMpeg4Dec::handleResChange(const std::unique_ptr<C2Work> &work) {
    424     uint32_t disp_width, disp_height;
    425     PVGetVideoDimensions(mDecHandle, (int32 *)&disp_width, (int32 *)&disp_height);
    426 
    427     uint32_t buf_width, buf_height;
    428     PVGetBufferDimensions(mDecHandle, (int32 *)&buf_width, (int32 *)&buf_height);
    429 
    430     CHECK_LE(disp_width, buf_width);
    431     CHECK_LE(disp_height, buf_height);
    432 
    433     ALOGV("display size (%dx%d), buffer size (%dx%d)",
    434            disp_width, disp_height, buf_width, buf_height);
    435 
    436     bool resChanged = false;
    437     if (disp_width != mWidth || disp_height != mHeight) {
    438         mWidth = disp_width;
    439         mHeight = disp_height;
    440         resChanged = true;
    441         for (int32_t i = 0; i < kNumOutputBuffers; ++i) {
    442             if (mOutputBuffer[i]) {
    443                 free(mOutputBuffer[i]);
    444                 mOutputBuffer[i] = nullptr;
    445             }
    446         }
    447 
    448         if (!mIsMpeg4) {
    449             PVCleanUpVideoDecoder(mDecHandle);
    450 
    451             uint8_t *vol_data[1]{};
    452             int32_t vol_size = 0;
    453 
    454             if (!PVInitVideoDecoder(
    455                     mDecHandle, vol_data, &vol_size, 1, mIntf->getMaxWidth(), mIntf->getMaxHeight(), H263_MODE)) {
    456                 ALOGE("Error in PVInitVideoDecoder H263_MODE while resChanged was set to true");
    457                 mSignalledError = true;
    458                 work->result = C2_CORRUPTED;
    459                 return true;
    460             }
    461         }
    462         mFramesConfigured = false;
    463     }
    464     return resChanged;
    465 }
    466 
    467 /* TODO: can remove temporary copy after library supports writing to display
    468  * buffer Y, U and V plane pointers using stride info. */
    469 static void copyOutputBufferToYuvPlanarFrame(
    470         uint8_t *dst, uint8_t *src,
    471         size_t dstYStride, size_t dstUVStride,
    472         size_t srcYStride, uint32_t width,
    473         uint32_t height) {
    474     size_t srcUVStride = srcYStride / 2;
    475     uint8_t *srcStart = src;
    476     uint8_t *dstStart = dst;
    477     size_t vStride = align(height, 16);
    478     for (size_t i = 0; i < height; ++i) {
    479          memcpy(dst, src, width);
    480          src += srcYStride;
    481          dst += dstYStride;
    482     }
    483     /* U buffer */
    484     src = srcStart + vStride * srcYStride;
    485     dst = dstStart + (dstYStride * height) + (dstUVStride * height / 2);
    486     for (size_t i = 0; i < height / 2; ++i) {
    487          memcpy(dst, src, width / 2);
    488          src += srcUVStride;
    489          dst += dstUVStride;
    490     }
    491     /* V buffer */
    492     src = srcStart + vStride * srcYStride * 5 / 4;
    493     dst = dstStart + (dstYStride * height);
    494     for (size_t i = 0; i < height / 2; ++i) {
    495          memcpy(dst, src, width / 2);
    496          src += srcUVStride;
    497          dst += dstUVStride;
    498     }
    499 }
    500 
    501 void C2SoftMpeg4Dec::process(
    502         const std::unique_ptr<C2Work> &work,
    503         const std::shared_ptr<C2BlockPool> &pool) {
    504     // Initialize output work
    505     work->result = C2_OK;
    506     work->workletsProcessed = 1u;
    507     work->worklets.front()->output.configUpdate.clear();
    508     work->worklets.front()->output.flags = work->input.flags;
    509 
    510     if (mSignalledError || mSignalledOutputEos) {
    511         work->result = C2_BAD_VALUE;
    512         return;
    513     }
    514 
    515     size_t inOffset = 0u;
    516     size_t inSize = 0u;
    517     uint32_t workIndex = work->input.ordinal.frameIndex.peeku() & 0xFFFFFFFF;
    518     C2ReadView rView = mDummyReadView;
    519     if (!work->input.buffers.empty()) {
    520         rView = work->input.buffers[0]->data().linearBlocks().front().map().get();
    521         inSize = rView.capacity();
    522         if (inSize && rView.error()) {
    523             ALOGE("read view map failed %d", rView.error());
    524             work->result = C2_CORRUPTED;
    525             return;
    526         }
    527     }
    528     ALOGV("in buffer attr. size %zu timestamp %d frameindex %d, flags %x",
    529           inSize, (int)work->input.ordinal.timestamp.peeku(),
    530           (int)work->input.ordinal.frameIndex.peeku(), work->input.flags);
    531 
    532     bool eos = ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0);
    533     if (inSize == 0) {
    534         fillEmptyWork(work);
    535         if (eos) {
    536             mSignalledOutputEos = true;
    537         }
    538         return;
    539     }
    540 
    541     uint8_t *bitstream = const_cast<uint8_t *>(rView.data() + inOffset);
    542     uint32_t *start_code = (uint32_t *)bitstream;
    543     bool volHeader = *start_code == 0xB0010000;
    544     if (volHeader) {
    545         PVCleanUpVideoDecoder(mDecHandle);
    546         mInitialized = false;
    547     }
    548 
    549     if (!mInitialized) {
    550         uint8_t *vol_data[1]{};
    551         int32_t vol_size = 0;
    552 
    553         bool codecConfig = (work->input.flags & C2FrameData::FLAG_CODEC_CONFIG) != 0;
    554         if (codecConfig || volHeader) {
    555             vol_data[0] = bitstream;
    556             vol_size = inSize;
    557         }
    558         MP4DecodingMode mode = (mIsMpeg4) ? MPEG4_MODE : H263_MODE;
    559         if (!PVInitVideoDecoder(
    560                 mDecHandle, vol_data, &vol_size, 1,
    561                 mIntf->getMaxWidth(), mIntf->getMaxHeight(), mode)) {
    562             ALOGE("PVInitVideoDecoder failed. Unsupported content?");
    563             mSignalledError = true;
    564             work->result = C2_CORRUPTED;
    565             return;
    566         }
    567         mInitialized = true;
    568         MP4DecodingMode actualMode = PVGetDecBitstreamMode(mDecHandle);
    569         if (mode != actualMode) {
    570             ALOGE("Decoded mode not same as actual mode of the decoder");
    571             mSignalledError = true;
    572             work->result = C2_CORRUPTED;
    573             return;
    574         }
    575 
    576         PVSetPostProcType(mDecHandle, 0);
    577         if (handleResChange(work)) {
    578             ALOGI("Setting width and height");
    579             C2StreamPictureSizeInfo::output size(0u, mWidth, mHeight);
    580             std::vector<std::unique_ptr<C2SettingResult>> failures;
    581             c2_status_t err = mIntf->config({&size}, C2_MAY_BLOCK, &failures);
    582             if (err == OK) {
    583                 work->worklets.front()->output.configUpdate.push_back(
    584                     C2Param::Copy(size));
    585             } else {
    586                 ALOGE("Config update size failed");
    587                 mSignalledError = true;
    588                 work->result = C2_CORRUPTED;
    589                 return;
    590             }
    591         }
    592         if (codecConfig) {
    593             fillEmptyWork(work);
    594             return;
    595         }
    596     }
    597 
    598     size_t inPos = 0;
    599     while (inPos < inSize) {
    600         c2_status_t err = ensureDecoderState(pool);
    601         if (C2_OK != err) {
    602             mSignalledError = true;
    603             work->result = err;
    604             return;
    605         }
    606         C2GraphicView wView = mOutBlock->map().get();
    607         if (wView.error()) {
    608             ALOGE("graphic view map failed %d", wView.error());
    609             work->result = C2_CORRUPTED;
    610             return;
    611         }
    612 
    613         uint32_t yFrameSize = sizeof(uint8) * mDecHandle->size;
    614         if (mOutputBufferSize < yFrameSize * 3 / 2){
    615             ALOGE("Too small output buffer: %zu bytes", mOutputBufferSize);
    616             mSignalledError = true;
    617             work->result = C2_NO_MEMORY;
    618             return;
    619         }
    620 
    621         if (!mFramesConfigured) {
    622             PVSetReferenceYUV(mDecHandle,mOutputBuffer[1]);
    623             mFramesConfigured = true;
    624         }
    625 
    626         // Need to check if header contains new info, e.g., width/height, etc.
    627         VopHeaderInfo header_info;
    628         uint32_t useExtTimestamp = (inPos == 0);
    629         int32_t tmpInSize = (int32_t)inSize;
    630         uint8_t *bitstreamTmp = bitstream;
    631         uint32_t timestamp = workIndex;
    632         if (PVDecodeVopHeader(
    633                     mDecHandle, &bitstreamTmp, &timestamp, &tmpInSize,
    634                     &header_info, &useExtTimestamp,
    635                     mOutputBuffer[mNumSamplesOutput & 1]) != PV_TRUE) {
    636             ALOGE("failed to decode vop header.");
    637             mSignalledError = true;
    638             work->result = C2_CORRUPTED;
    639             return;
    640         }
    641 
    642         // H263 doesn't have VOL header, the frame size information is in short header, i.e. the
    643         // decoder may detect size change after PVDecodeVopHeader.
    644         bool resChange = handleResChange(work);
    645         if (mIsMpeg4 && resChange) {
    646             mSignalledError = true;
    647             work->result = C2_CORRUPTED;
    648             return;
    649         } else if (resChange) {
    650             ALOGI("Setting width and height");
    651             C2StreamPictureSizeInfo::output size(0u, mWidth, mHeight);
    652             std::vector<std::unique_ptr<C2SettingResult>> failures;
    653             c2_status_t err = mIntf->config({&size}, C2_MAY_BLOCK, &failures);
    654             if (err == OK) {
    655                 work->worklets.front()->output.configUpdate.push_back(C2Param::Copy(size));
    656             } else {
    657                 ALOGE("Config update size failed");
    658                 mSignalledError = true;
    659                 work->result = C2_CORRUPTED;
    660                 return;
    661             }
    662             continue;
    663         }
    664 
    665         if (PVDecodeVopBody(mDecHandle, &tmpInSize) != PV_TRUE) {
    666             ALOGE("failed to decode video frame.");
    667             mSignalledError = true;
    668             work->result = C2_CORRUPTED;
    669             return;
    670         }
    671         if (handleResChange(work)) {
    672             mSignalledError = true;
    673             work->result = C2_CORRUPTED;
    674             return;
    675         }
    676 
    677         uint8_t *outputBufferY = wView.data()[C2PlanarLayout::PLANE_Y];
    678         C2PlanarLayout layout = wView.layout();
    679         size_t dstYStride = layout.planes[C2PlanarLayout::PLANE_Y].rowInc;
    680         size_t dstUVStride = layout.planes[C2PlanarLayout::PLANE_U].rowInc;
    681         (void)copyOutputBufferToYuvPlanarFrame(
    682                 outputBufferY,
    683                 mOutputBuffer[mNumSamplesOutput & 1],
    684                 dstYStride, dstUVStride,
    685                 align(mWidth, 16), mWidth, mHeight);
    686 
    687         inPos += inSize - (size_t)tmpInSize;
    688         finishWork(workIndex, work);
    689         ++mNumSamplesOutput;
    690         if (inSize - inPos != 0) {
    691             ALOGD("decoded frame, ignoring further trailing bytes %d",
    692                   (int)inSize - (int)inPos);
    693             break;
    694         }
    695     }
    696 }
    697 
    698 c2_status_t C2SoftMpeg4Dec::drain(
    699         uint32_t drainMode,
    700         const std::shared_ptr<C2BlockPool> &pool) {
    701     (void)pool;
    702     if (drainMode == NO_DRAIN) {
    703         ALOGW("drain with NO_DRAIN: no-op");
    704         return C2_OK;
    705     }
    706     if (drainMode == DRAIN_CHAIN) {
    707         ALOGW("DRAIN_CHAIN not supported");
    708         return C2_OMITTED;
    709     }
    710     return C2_OK;
    711 }
    712 
    713 class C2SoftMpeg4DecFactory : public C2ComponentFactory {
    714 public:
    715     C2SoftMpeg4DecFactory() : mHelper(std::static_pointer_cast<C2ReflectorHelper>(
    716         GetCodec2PlatformComponentStore()->getParamReflector())) {
    717     }
    718 
    719     virtual c2_status_t createComponent(
    720             c2_node_id_t id,
    721             std::shared_ptr<C2Component>* const component,
    722             std::function<void(C2Component*)> deleter) override {
    723         *component = std::shared_ptr<C2Component>(
    724                 new C2SoftMpeg4Dec(COMPONENT_NAME,
    725                                    id,
    726                                    std::make_shared<C2SoftMpeg4Dec::IntfImpl>(mHelper)),
    727                 deleter);
    728         return C2_OK;
    729     }
    730 
    731     virtual c2_status_t createInterface(
    732             c2_node_id_t id,
    733             std::shared_ptr<C2ComponentInterface>* const interface,
    734             std::function<void(C2ComponentInterface*)> deleter) override {
    735         *interface = std::shared_ptr<C2ComponentInterface>(
    736                 new SimpleInterface<C2SoftMpeg4Dec::IntfImpl>(
    737                         COMPONENT_NAME, id, std::make_shared<C2SoftMpeg4Dec::IntfImpl>(mHelper)),
    738                 deleter);
    739         return C2_OK;
    740     }
    741 
    742     virtual ~C2SoftMpeg4DecFactory() override = default;
    743 
    744 private:
    745     std::shared_ptr<C2ReflectorHelper> mHelper;
    746 };
    747 
    748 }  // namespace android
    749 
    750 extern "C" ::C2ComponentFactory* CreateCodec2Factory() {
    751     ALOGV("in %s", __func__);
    752     return new ::android::C2SoftMpeg4DecFactory();
    753 }
    754 
    755 extern "C" void DestroyCodec2Factory(::C2ComponentFactory* factory) {
    756     ALOGV("in %s", __func__);
    757     delete factory;
    758 }
    759