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