Home | History | Annotate | Download | only in mpeg4_h263
      1 /*
      2  * Copyright 2018 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 //#define LOG_NDEBUG 0
     18 #ifdef MPEG4
     19   #define LOG_TAG "C2SoftMpeg4Enc"
     20 #else
     21   #define LOG_TAG "C2SoftH263Enc"
     22 #endif
     23 #include <log/log.h>
     24 
     25 #include <inttypes.h>
     26 
     27 #include <media/hardware/VideoAPI.h>
     28 #include <media/stagefright/foundation/AUtils.h>
     29 #include <media/stagefright/MediaDefs.h>
     30 #include <utils/misc.h>
     31 
     32 #include <C2Debug.h>
     33 #include <C2PlatformSupport.h>
     34 #include <SimpleC2Interface.h>
     35 #include <util/C2InterfaceHelper.h>
     36 
     37 #include "C2SoftMpeg4Enc.h"
     38 #include "mp4enc_api.h"
     39 
     40 namespace android {
     41 
     42 namespace {
     43 
     44 #ifdef MPEG4
     45 constexpr char COMPONENT_NAME[] = "c2.android.mpeg4.encoder";
     46 const char *MEDIA_MIMETYPE_VIDEO = MEDIA_MIMETYPE_VIDEO_MPEG4;
     47 #else
     48 constexpr char COMPONENT_NAME[] = "c2.android.h263.encoder";
     49 const char *MEDIA_MIMETYPE_VIDEO = MEDIA_MIMETYPE_VIDEO_H263;
     50 #endif
     51 
     52 } // namepsace
     53 
     54 class C2SoftMpeg4Enc::IntfImpl : public SimpleInterface<void>::BaseParams {
     55    public:
     56     explicit IntfImpl(const std::shared_ptr<C2ReflectorHelper> &helper)
     57         : SimpleInterface<void>::BaseParams(
     58                 helper,
     59                 COMPONENT_NAME,
     60                 C2Component::KIND_ENCODER,
     61                 C2Component::DOMAIN_VIDEO,
     62                 MEDIA_MIMETYPE_VIDEO) {
     63         noPrivateBuffers(); // TODO: account for our buffers here
     64         noInputReferences();
     65         noOutputReferences();
     66         noInputLatency();
     67         noTimeStretch();
     68         setDerivedInstance(this);
     69 
     70         addParameter(
     71                 DefineParam(mAttrib, C2_PARAMKEY_COMPONENT_ATTRIBUTES)
     72                 .withConstValue(new C2ComponentAttributesSetting(
     73                     C2Component::ATTRIB_IS_TEMPORAL))
     74                 .build());
     75 
     76         addParameter(
     77                 DefineParam(mUsage, C2_PARAMKEY_INPUT_STREAM_USAGE)
     78                 .withConstValue(new C2StreamUsageTuning::input(
     79                         0u, (uint64_t)C2MemoryUsage::CPU_READ))
     80                 .build());
     81 
     82         addParameter(
     83             DefineParam(mSize, C2_PARAMKEY_PICTURE_SIZE)
     84                 .withDefault(new C2StreamPictureSizeInfo::input(0u, 176, 144))
     85                 .withFields({
     86 #ifdef MPEG4
     87                     C2F(mSize, width).inRange(16, 176, 16),
     88                     C2F(mSize, height).inRange(16, 144, 16),
     89 #else
     90                     C2F(mSize, width).oneOf({176, 352}),
     91                     C2F(mSize, height).oneOf({144, 288}),
     92 #endif
     93                 })
     94                 .withSetter(SizeSetter)
     95                 .build());
     96 
     97         addParameter(
     98             DefineParam(mFrameRate, C2_PARAMKEY_FRAME_RATE)
     99                 .withDefault(new C2StreamFrameRateInfo::output(0u, 17.))
    100                 // TODO: More restriction?
    101                 .withFields({C2F(mFrameRate, value).greaterThan(0.)})
    102                 .withSetter(
    103                     Setter<decltype(*mFrameRate)>::StrictValueWithNoDeps)
    104                 .build());
    105 
    106         addParameter(
    107             DefineParam(mBitrate, C2_PARAMKEY_BITRATE)
    108                 .withDefault(new C2StreamBitrateInfo::output(0u, 64000))
    109                 .withFields({C2F(mBitrate, value).inRange(4096, 12000000)})
    110                 .withSetter(BitrateSetter)
    111                 .build());
    112 
    113         addParameter(
    114                 DefineParam(mSyncFramePeriod, C2_PARAMKEY_SYNC_FRAME_INTERVAL)
    115                 .withDefault(new C2StreamSyncFrameIntervalTuning::output(0u, 1000000))
    116                 .withFields({C2F(mSyncFramePeriod, value).any()})
    117                 .withSetter(Setter<decltype(*mSyncFramePeriod)>::StrictValueWithNoDeps)
    118                 .build());
    119 
    120 #ifdef MPEG4
    121         addParameter(
    122                 DefineParam(mProfileLevel, C2_PARAMKEY_PROFILE_LEVEL)
    123                 .withDefault(new C2StreamProfileLevelInfo::output(
    124                         0u, PROFILE_MP4V_SIMPLE, LEVEL_MP4V_2))
    125                 .withFields({
    126                     C2F(mProfileLevel, profile).equalTo(
    127                             PROFILE_MP4V_SIMPLE),
    128                     C2F(mProfileLevel, level).oneOf({
    129                             C2Config::LEVEL_MP4V_0,
    130                             C2Config::LEVEL_MP4V_0B,
    131                             C2Config::LEVEL_MP4V_1,
    132                             C2Config::LEVEL_MP4V_2})
    133                 })
    134                 .withSetter(ProfileLevelSetter)
    135                 .build());
    136 #else
    137         addParameter(
    138                 DefineParam(mProfileLevel, C2_PARAMKEY_PROFILE_LEVEL)
    139                 .withDefault(new C2StreamProfileLevelInfo::output(
    140                         0u, PROFILE_H263_BASELINE, LEVEL_H263_45))
    141                 .withFields({
    142                     C2F(mProfileLevel, profile).equalTo(
    143                             PROFILE_H263_BASELINE),
    144                     C2F(mProfileLevel, level).oneOf({
    145                             C2Config::LEVEL_H263_10,
    146                             C2Config::LEVEL_H263_20,
    147                             C2Config::LEVEL_H263_30,
    148                             C2Config::LEVEL_H263_40,
    149                             C2Config::LEVEL_H263_45})
    150                 })
    151                 .withSetter(ProfileLevelSetter)
    152                 .build());
    153 #endif
    154     }
    155 
    156     static C2R BitrateSetter(bool mayBlock, C2P<C2StreamBitrateInfo::output> &me) {
    157         (void)mayBlock;
    158         C2R res = C2R::Ok();
    159         if (me.v.value <= 4096) {
    160             me.set().value = 4096;
    161         }
    162         return res;
    163     }
    164 
    165     static C2R SizeSetter(bool mayBlock, const C2P<C2StreamPictureSizeInfo::input> &oldMe,
    166                           C2P<C2StreamPictureSizeInfo::input> &me) {
    167         (void)mayBlock;
    168         C2R res = C2R::Ok();
    169         if (!me.F(me.v.width).supportsAtAll(me.v.width)) {
    170             res = res.plus(C2SettingResultBuilder::BadValue(me.F(me.v.width)));
    171             me.set().width = oldMe.v.width;
    172         }
    173         if (!me.F(me.v.height).supportsAtAll(me.v.height)) {
    174             res = res.plus(C2SettingResultBuilder::BadValue(me.F(me.v.height)));
    175             me.set().height = oldMe.v.height;
    176         }
    177         return res;
    178     }
    179 
    180     static C2R ProfileLevelSetter(
    181             bool mayBlock,
    182             C2P<C2StreamProfileLevelInfo::output> &me) {
    183         (void)mayBlock;
    184         if (!me.F(me.v.profile).supportsAtAll(me.v.profile)) {
    185 #ifdef MPEG4
    186             me.set().profile = PROFILE_MP4V_SIMPLE;
    187 #else
    188             me.set().profile = PROFILE_H263_BASELINE;
    189 #endif
    190         }
    191         if (!me.F(me.v.level).supportsAtAll(me.v.level)) {
    192 #ifdef MPEG4
    193             me.set().level = LEVEL_MP4V_2;
    194 #else
    195             me.set().level = LEVEL_H263_45;
    196 #endif
    197         }
    198         return C2R::Ok();
    199     }
    200 
    201     // unsafe getters
    202     std::shared_ptr<C2StreamPictureSizeInfo::input> getSize_l() const { return mSize; }
    203     std::shared_ptr<C2StreamFrameRateInfo::output> getFrameRate_l() const { return mFrameRate; }
    204     std::shared_ptr<C2StreamBitrateInfo::output> getBitrate_l() const { return mBitrate; }
    205     uint32_t getSyncFramePeriod() const {
    206         if (mSyncFramePeriod->value < 0 || mSyncFramePeriod->value == INT64_MAX) {
    207             return 0;
    208         }
    209         double period = mSyncFramePeriod->value / 1e6 * mFrameRate->value;
    210         return (uint32_t)c2_max(c2_min(period + 0.5, double(UINT32_MAX)), 1.);
    211     }
    212 
    213    private:
    214     std::shared_ptr<C2StreamUsageTuning::input> mUsage;
    215     std::shared_ptr<C2StreamPictureSizeInfo::input> mSize;
    216     std::shared_ptr<C2StreamFrameRateInfo::output> mFrameRate;
    217     std::shared_ptr<C2StreamBitrateInfo::output> mBitrate;
    218     std::shared_ptr<C2StreamProfileLevelInfo::output> mProfileLevel;
    219     std::shared_ptr<C2StreamSyncFrameIntervalTuning::output> mSyncFramePeriod;
    220 };
    221 
    222 C2SoftMpeg4Enc::C2SoftMpeg4Enc(const char* name, c2_node_id_t id,
    223                                const std::shared_ptr<IntfImpl>& intfImpl)
    224     : SimpleC2Component(
    225           std::make_shared<SimpleInterface<IntfImpl>>(name, id, intfImpl)),
    226       mIntf(intfImpl),
    227       mHandle(nullptr),
    228       mEncParams(nullptr),
    229       mStarted(false),
    230       mOutBufferSize(524288) {
    231 }
    232 
    233 C2SoftMpeg4Enc::~C2SoftMpeg4Enc() {
    234     onRelease();
    235 }
    236 
    237 c2_status_t C2SoftMpeg4Enc::onInit() {
    238 #ifdef MPEG4
    239     mEncodeMode = COMBINE_MODE_WITH_ERR_RES;
    240 #else
    241     mEncodeMode = H263_MODE;
    242 #endif
    243     if (!mHandle) {
    244         mHandle = new tagvideoEncControls;
    245     }
    246 
    247     if (!mEncParams) {
    248         mEncParams = new tagvideoEncOptions;
    249     }
    250 
    251     if (!(mEncParams && mHandle)) return C2_NO_MEMORY;
    252 
    253     mSignalledOutputEos = false;
    254     mSignalledError = false;
    255 
    256     return initEncoder();
    257 }
    258 
    259 c2_status_t C2SoftMpeg4Enc::onStop() {
    260     if (!mStarted) {
    261         return C2_OK;
    262     }
    263     if (mHandle) {
    264         (void)PVCleanUpVideoEncoder(mHandle);
    265     }
    266     mStarted = false;
    267     mSignalledOutputEos = false;
    268     mSignalledError = false;
    269     return C2_OK;
    270 }
    271 
    272 void C2SoftMpeg4Enc::onReset() {
    273     onStop();
    274     initEncoder();
    275 }
    276 
    277 void C2SoftMpeg4Enc::onRelease() {
    278     onStop();
    279     if (mEncParams) {
    280         delete mEncParams;
    281         mEncParams = nullptr;
    282     }
    283     if (mHandle) {
    284         delete mHandle;
    285         mHandle = nullptr;
    286     }
    287 }
    288 
    289 c2_status_t C2SoftMpeg4Enc::onFlush_sm() {
    290     return C2_OK;
    291 }
    292 
    293 static void fillEmptyWork(const std::unique_ptr<C2Work> &work) {
    294     uint32_t flags = 0;
    295     if (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) {
    296         flags |= C2FrameData::FLAG_END_OF_STREAM;
    297         ALOGV("signalling eos");
    298     }
    299     work->worklets.front()->output.flags = (C2FrameData::flags_t)flags;
    300     work->worklets.front()->output.buffers.clear();
    301     work->worklets.front()->output.ordinal = work->input.ordinal;
    302     work->workletsProcessed = 1u;
    303 }
    304 
    305 c2_status_t C2SoftMpeg4Enc::initEncParams() {
    306     if (mHandle) {
    307         memset(mHandle, 0, sizeof(tagvideoEncControls));
    308     } else return C2_CORRUPTED;
    309     if (mEncParams) {
    310         memset(mEncParams, 0, sizeof(tagvideoEncOptions));
    311     } else return C2_CORRUPTED;
    312 
    313     if (!PVGetDefaultEncOption(mEncParams, 0)) {
    314         ALOGE("Failed to get default encoding parameters");
    315         return C2_CORRUPTED;
    316     }
    317 
    318     if (mFrameRate->value == 0) {
    319         ALOGE("Framerate should not be 0");
    320         return C2_BAD_VALUE;
    321     }
    322 
    323     mEncParams->encMode = mEncodeMode;
    324     mEncParams->encWidth[0] = mSize->width;
    325     mEncParams->encHeight[0] = mSize->height;
    326     mEncParams->encFrameRate[0] = mFrameRate->value + 0.5;
    327     mEncParams->rcType = VBR_1;
    328     mEncParams->vbvDelay = 5.0f;
    329     mEncParams->profile_level = CORE_PROFILE_LEVEL2;
    330     mEncParams->packetSize = 32;
    331     mEncParams->rvlcEnable = PV_OFF;
    332     mEncParams->numLayers = 1;
    333     mEncParams->timeIncRes = 1000;
    334     mEncParams->tickPerSrc = mEncParams->timeIncRes / (mFrameRate->value + 0.5);
    335     mEncParams->bitRate[0] = mBitrate->value;
    336     mEncParams->iQuant[0] = 15;
    337     mEncParams->pQuant[0] = 12;
    338     mEncParams->quantType[0] = 0;
    339     mEncParams->noFrameSkipped = PV_OFF;
    340 
    341     // PV's MPEG4 encoder requires the video dimension of multiple
    342     if (mSize->width % 16 != 0 || mSize->height % 16 != 0) {
    343         ALOGE("Video frame size %dx%d must be a multiple of 16",
    344               mSize->width, mSize->height);
    345         return C2_BAD_VALUE;
    346     }
    347 
    348     // Set IDR frame refresh interval
    349     mEncParams->intraPeriod = mIntf->getSyncFramePeriod();
    350     mEncParams->numIntraMB = 0;
    351     mEncParams->sceneDetect = PV_ON;
    352     mEncParams->searchRange = 16;
    353     mEncParams->mv8x8Enable = PV_OFF;
    354     mEncParams->gobHeaderInterval = 0;
    355     mEncParams->useACPred = PV_ON;
    356     mEncParams->intraDCVlcTh = 0;
    357 
    358     return C2_OK;
    359 }
    360 
    361 c2_status_t C2SoftMpeg4Enc::initEncoder() {
    362     if (mStarted) {
    363         return C2_OK;
    364     }
    365     {
    366         IntfImpl::Lock lock = mIntf->lock();
    367         mSize = mIntf->getSize_l();
    368         mBitrate = mIntf->getBitrate_l();
    369         mFrameRate = mIntf->getFrameRate_l();
    370     }
    371     c2_status_t err = initEncParams();
    372     if (C2_OK != err) {
    373         ALOGE("Failed to initialized encoder params");
    374         mSignalledError = true;
    375         return err;
    376     }
    377     if (!PVInitVideoEncoder(mHandle, mEncParams)) {
    378         ALOGE("Failed to initialize the encoder");
    379         mSignalledError = true;
    380         return C2_CORRUPTED;
    381     }
    382 
    383     // 1st buffer for codec specific data
    384     mNumInputFrames = -1;
    385     mStarted = true;
    386     return C2_OK;
    387 }
    388 
    389 void C2SoftMpeg4Enc::process(
    390         const std::unique_ptr<C2Work> &work,
    391         const std::shared_ptr<C2BlockPool> &pool) {
    392     // Initialize output work
    393     work->result = C2_OK;
    394     work->workletsProcessed = 1u;
    395     work->worklets.front()->output.flags = work->input.flags;
    396     if (mSignalledError || mSignalledOutputEos) {
    397         work->result = C2_BAD_VALUE;
    398         return;
    399     }
    400 
    401     // Initialize encoder if not already initialized
    402     if (!mStarted && C2_OK != initEncoder()) {
    403         ALOGE("Failed to initialize encoder");
    404         mSignalledError = true;
    405         work->result = C2_CORRUPTED;
    406         return;
    407     }
    408 
    409     std::shared_ptr<C2LinearBlock> block;
    410     C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
    411     c2_status_t err = pool->fetchLinearBlock(mOutBufferSize, usage, &block);
    412     if (err != C2_OK) {
    413         ALOGE("fetchLinearBlock for Output failed with status %d", err);
    414         work->result = C2_NO_MEMORY;
    415         return;
    416     }
    417 
    418     C2WriteView wView = block->map().get();
    419     if (wView.error()) {
    420         ALOGE("write view map failed %d", wView.error());
    421         work->result = wView.error();
    422         return;
    423     }
    424 
    425     uint8_t *outPtr = (uint8_t *)wView.data();
    426     if (mNumInputFrames < 0) {
    427         // The very first thing we want to output is the codec specific data.
    428         int32_t outputSize = mOutBufferSize;
    429         if (!PVGetVolHeader(mHandle, outPtr, &outputSize, 0)) {
    430             ALOGE("Failed to get VOL header");
    431             mSignalledError = true;
    432             work->result = C2_CORRUPTED;
    433             return;
    434         } else {
    435             ALOGV("Bytes Generated in header %d\n", outputSize);
    436         }
    437 
    438         ++mNumInputFrames;
    439         std::unique_ptr<C2StreamInitDataInfo::output> csd =
    440             C2StreamInitDataInfo::output::AllocUnique(outputSize, 0u);
    441         if (!csd) {
    442             ALOGE("CSD allocation failed");
    443             mSignalledError = true;
    444             work->result = C2_NO_MEMORY;
    445             return;
    446         }
    447         memcpy(csd->m.value, outPtr, outputSize);
    448         work->worklets.front()->output.configUpdate.push_back(std::move(csd));
    449     }
    450 
    451     std::shared_ptr<const C2GraphicView> rView;
    452     std::shared_ptr<C2Buffer> inputBuffer;
    453     bool eos = ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0);
    454     if (!work->input.buffers.empty()) {
    455         inputBuffer = work->input.buffers[0];
    456         rView = std::make_shared<const C2GraphicView>(
    457                 inputBuffer->data().graphicBlocks().front().map().get());
    458         if (rView->error() != C2_OK) {
    459             ALOGE("graphic view map err = %d", rView->error());
    460             work->result = rView->error();
    461             return;
    462         }
    463     } else {
    464         fillEmptyWork(work);
    465         if (eos) {
    466             mSignalledOutputEos = true;
    467             ALOGV("signalled EOS");
    468         }
    469         return;
    470     }
    471 
    472     uint64_t inputTimeStamp = work->input.ordinal.timestamp.peekull();
    473     const C2ConstGraphicBlock inBuffer = inputBuffer->data().graphicBlocks().front();
    474     if (inBuffer.width() < mSize->width ||
    475         inBuffer.height() < mSize->height) {
    476         /* Expect width height to be configured */
    477         ALOGW("unexpected Capacity Aspect %d(%d) x %d(%d)", inBuffer.width(),
    478               mSize->width, inBuffer.height(), mSize->height);
    479         work->result = C2_BAD_VALUE;
    480         return;
    481     }
    482 
    483     const C2PlanarLayout &layout = rView->layout();
    484     uint8_t *yPlane = const_cast<uint8_t *>(rView->data()[C2PlanarLayout::PLANE_Y]);
    485     uint8_t *uPlane = const_cast<uint8_t *>(rView->data()[C2PlanarLayout::PLANE_U]);
    486     uint8_t *vPlane = const_cast<uint8_t *>(rView->data()[C2PlanarLayout::PLANE_V]);
    487     int32_t yStride = layout.planes[C2PlanarLayout::PLANE_Y].rowInc;
    488     int32_t uStride = layout.planes[C2PlanarLayout::PLANE_U].rowInc;
    489     int32_t vStride = layout.planes[C2PlanarLayout::PLANE_V].rowInc;
    490     uint32_t width = mSize->width;
    491     uint32_t height = mSize->height;
    492     // width and height are always even (as block size is 16x16)
    493     CHECK_EQ((width & 1u), 0u);
    494     CHECK_EQ((height & 1u), 0u);
    495     size_t yPlaneSize = width * height;
    496     switch (layout.type) {
    497         case C2PlanarLayout::TYPE_RGB:
    498             [[fallthrough]];
    499         case C2PlanarLayout::TYPE_RGBA: {
    500             MemoryBlock conversionBuffer = mConversionBuffers.fetch(yPlaneSize * 3 / 2);
    501             mConversionBuffersInUse.emplace(conversionBuffer.data(), conversionBuffer);
    502             yPlane = conversionBuffer.data();
    503             uPlane = yPlane + yPlaneSize;
    504             vPlane = uPlane + yPlaneSize / 4;
    505             yStride = width;
    506             uStride = vStride = width / 2;
    507             ConvertRGBToPlanarYUV(yPlane, yStride, height, conversionBuffer.size(), *rView.get());
    508             break;
    509         }
    510         case C2PlanarLayout::TYPE_YUV: {
    511             if (!IsYUV420(*rView)) {
    512                 ALOGE("input is not YUV420");
    513                 work->result = C2_BAD_VALUE;
    514                 break;
    515             }
    516 
    517             if (layout.planes[layout.PLANE_Y].colInc == 1
    518                     && layout.planes[layout.PLANE_U].colInc == 1
    519                     && layout.planes[layout.PLANE_V].colInc == 1
    520                     && uStride == vStride
    521                     && yStride == 2 * vStride) {
    522                 // I420 compatible - planes are already set up above
    523                 break;
    524             }
    525 
    526             // copy to I420
    527             MemoryBlock conversionBuffer = mConversionBuffers.fetch(yPlaneSize * 3 / 2);
    528             mConversionBuffersInUse.emplace(conversionBuffer.data(), conversionBuffer);
    529             MediaImage2 img = CreateYUV420PlanarMediaImage2(width, height, width, height);
    530             status_t err = ImageCopy(conversionBuffer.data(), &img, *rView);
    531             if (err != OK) {
    532                 ALOGE("Buffer conversion failed: %d", err);
    533                 work->result = C2_BAD_VALUE;
    534                 return;
    535             }
    536             yPlane = conversionBuffer.data();
    537             uPlane = yPlane + yPlaneSize;
    538             vPlane = uPlane + yPlaneSize / 4;
    539             yStride = width;
    540             uStride = vStride = width / 2;
    541             break;
    542         }
    543 
    544         case C2PlanarLayout::TYPE_YUVA:
    545             ALOGE("YUVA plane type is not supported");
    546             work->result = C2_BAD_VALUE;
    547             return;
    548 
    549         default:
    550             ALOGE("Unrecognized plane type: %d", layout.type);
    551             work->result = C2_BAD_VALUE;
    552             return;
    553     }
    554 
    555     CHECK(NULL != yPlane);
    556     /* Encode frames */
    557     VideoEncFrameIO vin, vout;
    558     memset(&vin, 0, sizeof(vin));
    559     memset(&vout, 0, sizeof(vout));
    560     vin.yChan = yPlane;
    561     vin.uChan = uPlane;
    562     vin.vChan = vPlane;
    563     vin.timestamp = (inputTimeStamp + 500) / 1000;  // in ms
    564     vin.height = align(height, 16);
    565     vin.pitch = align(width, 16);
    566 
    567     uint32_t modTimeMs = 0;
    568     int32_t nLayer = 0;
    569     MP4HintTrack hintTrack;
    570     int32_t outputSize = mOutBufferSize;
    571     if (!PVEncodeVideoFrame(mHandle, &vin, &vout, &modTimeMs, outPtr, &outputSize, &nLayer) ||
    572         !PVGetHintTrack(mHandle, &hintTrack)) {
    573         ALOGE("Failed to encode frame or get hint track at frame %" PRId64, mNumInputFrames);
    574         mSignalledError = true;
    575         work->result = C2_CORRUPTED;
    576         return;
    577     }
    578     ALOGV("outputSize filled : %d", outputSize);
    579     ++mNumInputFrames;
    580     CHECK(NULL == PVGetOverrunBuffer(mHandle));
    581 
    582     fillEmptyWork(work);
    583     if (outputSize) {
    584         std::shared_ptr<C2Buffer> buffer = createLinearBuffer(block, 0, outputSize);
    585         work->worklets.front()->output.ordinal.timestamp = inputTimeStamp;
    586         if (hintTrack.CodeType == 0) {
    587             buffer->setInfo(std::make_shared<C2StreamPictureTypeMaskInfo::output>(
    588                     0u /* stream id */, C2Config::SYNC_FRAME));
    589         }
    590         work->worklets.front()->output.buffers.push_back(buffer);
    591     }
    592     if (eos) {
    593         mSignalledOutputEos = true;
    594     }
    595 
    596     mConversionBuffersInUse.erase(yPlane);
    597 }
    598 
    599 c2_status_t C2SoftMpeg4Enc::drain(
    600         uint32_t drainMode,
    601         const std::shared_ptr<C2BlockPool> &pool) {
    602     (void)pool;
    603     if (drainMode == NO_DRAIN) {
    604         ALOGW("drain with NO_DRAIN: no-op");
    605         return C2_OK;
    606     }
    607     if (drainMode == DRAIN_CHAIN) {
    608         ALOGW("DRAIN_CHAIN not supported");
    609         return C2_OMITTED;
    610     }
    611 
    612     return C2_OK;
    613 }
    614 
    615 class C2SoftMpeg4EncFactory : public C2ComponentFactory {
    616 public:
    617     C2SoftMpeg4EncFactory()
    618         : mHelper(std::static_pointer_cast<C2ReflectorHelper>(
    619               GetCodec2PlatformComponentStore()->getParamReflector())) {}
    620 
    621     virtual c2_status_t createComponent(
    622             c2_node_id_t id,
    623             std::shared_ptr<C2Component>* const component,
    624             std::function<void(C2Component*)> deleter) override {
    625         *component = std::shared_ptr<C2Component>(
    626             new C2SoftMpeg4Enc(
    627                 COMPONENT_NAME, id,
    628                 std::make_shared<C2SoftMpeg4Enc::IntfImpl>(mHelper)),
    629             deleter);
    630         return C2_OK;
    631     }
    632 
    633     virtual c2_status_t createInterface(
    634             c2_node_id_t id,
    635             std::shared_ptr<C2ComponentInterface>* const interface,
    636             std::function<void(C2ComponentInterface*)> deleter) override {
    637         *interface = std::shared_ptr<C2ComponentInterface>(
    638             new SimpleInterface<C2SoftMpeg4Enc::IntfImpl>(
    639                 COMPONENT_NAME, id,
    640                 std::make_shared<C2SoftMpeg4Enc::IntfImpl>(mHelper)),
    641             deleter);
    642         return C2_OK;
    643     }
    644 
    645     virtual ~C2SoftMpeg4EncFactory() override = default;
    646 
    647 private:
    648     std::shared_ptr<C2ReflectorHelper> mHelper;
    649 };
    650 
    651 }  // namespace android
    652 
    653 extern "C" ::C2ComponentFactory* CreateCodec2Factory() {
    654     ALOGV("in %s", __func__);
    655     return new ::android::C2SoftMpeg4EncFactory();
    656 }
    657 
    658 extern "C" void DestroyCodec2Factory(::C2ComponentFactory* factory) {
    659     ALOGV("in %s", __func__);
    660     delete factory;
    661 }
    662