1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #define LOG_NDEBUG 0 18 #define LOG_TAG "CCodec" 19 #include <utils/Log.h> 20 21 #include <sstream> 22 #include <thread> 23 24 #include <C2Config.h> 25 #include <C2Debug.h> 26 #include <C2ParamInternal.h> 27 #include <C2PlatformSupport.h> 28 #include <C2V4l2Support.h> 29 30 #include <android/IOMXBufferSource.h> 31 #include <android/IGraphicBufferSource.h> 32 #include <cutils/properties.h> 33 #include <gui/bufferqueue/1.0/H2BGraphicBufferProducer.h> 34 #include <gui/IGraphicBufferProducer.h> 35 #include <gui/Surface.h> 36 #include <media/omx/1.0/WOmx.h> 37 #include <media/stagefright/codec2/1.0/InputSurface.h> 38 #include <media/stagefright/BufferProducerWrapper.h> 39 #include <media/stagefright/MediaCodecConstants.h> 40 #include <media/stagefright/PersistentSurface.h> 41 42 #include "C2OMXNode.h" 43 #include "CCodec.h" 44 #include "CCodecBufferChannel.h" 45 #include "InputSurfaceWrapper.h" 46 47 namespace android { 48 49 using namespace std::chrono_literals; 50 using ::android::hardware::graphics::bufferqueue::V1_0::utils::H2BGraphicBufferProducer; 51 using BGraphicBufferSource = ::android::IGraphicBufferSource; 52 53 namespace { 54 55 class CCodecWatchdog : public AHandler { 56 private: 57 enum { 58 kWhatRegister, 59 kWhatWatch, 60 }; 61 constexpr static int64_t kWatchIntervalUs = 3000000; // 3 secs 62 63 public: 64 static sp<CCodecWatchdog> getInstance() { 65 Mutexed<sp<CCodecWatchdog>>::Locked instance(sInstance); 66 if (*instance == nullptr) { 67 *instance = new CCodecWatchdog; 68 (*instance)->init(); 69 } 70 return *instance; 71 } 72 73 ~CCodecWatchdog() = default; 74 75 void registerCodec(CCodec *codec) { 76 sp<AMessage> msg = new AMessage(kWhatRegister, this); 77 msg->setPointer("codec", codec); 78 msg->post(); 79 } 80 81 protected: 82 void onMessageReceived(const sp<AMessage> &msg) { 83 switch (msg->what()) { 84 case kWhatRegister: { 85 void *ptr = nullptr; 86 CHECK(msg->findPointer("codec", &ptr)); 87 Mutexed<std::list<wp<CCodec>>>::Locked codecs(mCodecs); 88 codecs->emplace_back((CCodec *)ptr); 89 break; 90 } 91 92 case kWhatWatch: { 93 Mutexed<std::list<wp<CCodec>>>::Locked codecs(mCodecs); 94 for (auto it = codecs->begin(); it != codecs->end(); ) { 95 sp<CCodec> codec = it->promote(); 96 if (codec == nullptr) { 97 it = codecs->erase(it); 98 continue; 99 } 100 codec->initiateReleaseIfStuck(); 101 ++it; 102 } 103 msg->post(kWatchIntervalUs); 104 break; 105 } 106 107 default: { 108 TRESPASS("CCodecWatchdog: unrecognized message"); 109 } 110 } 111 } 112 113 private: 114 CCodecWatchdog() : mLooper(new ALooper) {} 115 116 void init() { 117 mLooper->setName("CCodecWatchdog"); 118 mLooper->registerHandler(this); 119 mLooper->start(); 120 (new AMessage(kWhatWatch, this))->post(kWatchIntervalUs); 121 } 122 123 static Mutexed<sp<CCodecWatchdog>> sInstance; 124 125 sp<ALooper> mLooper; 126 Mutexed<std::list<wp<CCodec>>> mCodecs; 127 }; 128 129 Mutexed<sp<CCodecWatchdog>> CCodecWatchdog::sInstance; 130 131 class C2InputSurfaceWrapper : public InputSurfaceWrapper { 132 public: 133 explicit C2InputSurfaceWrapper( 134 const std::shared_ptr<Codec2Client::InputSurface> &surface) : 135 mSurface(surface) { 136 } 137 138 ~C2InputSurfaceWrapper() override = default; 139 140 status_t connect(const std::shared_ptr<Codec2Client::Component> &comp) override { 141 if (mConnection != nullptr) { 142 return ALREADY_EXISTS; 143 } 144 return static_cast<status_t>( 145 mSurface->connectToComponent(comp, &mConnection)); 146 } 147 148 void disconnect() override { 149 if (mConnection != nullptr) { 150 mConnection->disconnect(); 151 mConnection = nullptr; 152 } 153 } 154 155 status_t signalEndOfInputStream() override { 156 C2InputSurfaceEosTuning eos(true); 157 std::vector<std::unique_ptr<C2SettingResult>> failures; 158 c2_status_t err = mSurface->getConfigurable()->config({&eos}, C2_MAY_BLOCK, &failures); 159 if (err != C2_OK) { 160 return UNKNOWN_ERROR; 161 } 162 return OK; 163 } 164 165 status_t configure(Config &config __unused) { 166 // TODO 167 return OK; 168 } 169 170 private: 171 std::shared_ptr<Codec2Client::InputSurface> mSurface; 172 std::shared_ptr<Codec2Client::InputSurfaceConnection> mConnection; 173 }; 174 175 class GraphicBufferSourceWrapper : public InputSurfaceWrapper { 176 public: 177 // explicit GraphicBufferSourceWrapper(const sp<BGraphicBufferSource> &source) : mSource(source) {} 178 GraphicBufferSourceWrapper( 179 const sp<BGraphicBufferSource> &source, 180 uint32_t width, 181 uint32_t height) 182 : mSource(source), mWidth(width), mHeight(height) {} 183 ~GraphicBufferSourceWrapper() override = default; 184 185 status_t connect(const std::shared_ptr<Codec2Client::Component> &comp) override { 186 // TODO: proper color aspect & dataspace 187 android_dataspace dataSpace = HAL_DATASPACE_BT709; 188 189 mNode = new C2OMXNode(comp); 190 mNode->setFrameSize(mWidth, mHeight); 191 mSource->configure(mNode, dataSpace); 192 193 // TODO: configure according to intf(). 194 // TODO: initial color aspects (dataspace) 195 196 sp<IOMXBufferSource> source = mNode->getSource(); 197 if (source == nullptr) { 198 return NO_INIT; 199 } 200 constexpr size_t kNumSlots = 16; 201 for (size_t i = 0; i < kNumSlots; ++i) { 202 source->onInputBufferAdded(i); 203 } 204 source->onOmxExecuting(); 205 return OK; 206 } 207 208 void disconnect() override { 209 if (mNode == nullptr) { 210 return; 211 } 212 sp<IOMXBufferSource> source = mNode->getSource(); 213 if (source == nullptr) { 214 ALOGD("GBSWrapper::disconnect: node is not configured with OMXBufferSource."); 215 return; 216 } 217 source->onOmxIdle(); 218 source->onOmxLoaded(); 219 mNode.clear(); 220 } 221 222 status_t GetStatus(const binder::Status &status) { 223 status_t err = OK; 224 if (!status.isOk()) { 225 err = status.serviceSpecificErrorCode(); 226 if (err == OK) { 227 err = status.transactionError(); 228 if (err == OK) { 229 // binder status failed, but there is no servie or transaction error 230 err = UNKNOWN_ERROR; 231 } 232 } 233 } 234 return err; 235 } 236 237 status_t signalEndOfInputStream() override { 238 return GetStatus(mSource->signalEndOfInputStream()); 239 } 240 241 status_t configure(Config &config) { 242 std::stringstream status; 243 status_t err = OK; 244 245 // handle each configuration granually, in case we need to handle part of the configuration 246 // elsewhere 247 248 // TRICKY: we do not unset frame delay repeating 249 if (config.mMinFps > 0 && config.mMinFps != mConfig.mMinFps) { 250 int64_t us = 1e6 / config.mMinFps + 0.5; 251 status_t res = GetStatus(mSource->setRepeatPreviousFrameDelayUs(us)); 252 status << " minFps=" << config.mMinFps << " => repeatDelayUs=" << us; 253 if (res != OK) { 254 status << " (=> " << asString(res) << ")"; 255 err = res; 256 } 257 mConfig.mMinFps = config.mMinFps; 258 } 259 260 // TODO: pts gap 261 262 // max fps 263 // TRICKY: we do not unset max fps to 0 unless using fixed fps 264 if ((config.mMaxFps > 0 || (config.mFixedAdjustedFps > 0 && config.mMaxFps == 0)) 265 && config.mMaxFps != mConfig.mMaxFps) { 266 status_t res = GetStatus(mSource->setMaxFps(config.mMaxFps)); 267 status << " maxFps=" << config.mMaxFps; 268 if (res != OK) { 269 status << " (=> " << asString(res) << ")"; 270 err = res; 271 } 272 mConfig.mMaxFps = config.mMaxFps; 273 } 274 275 if (config.mTimeOffsetUs != mConfig.mTimeOffsetUs) { 276 status_t res = GetStatus(mSource->setTimeOffsetUs(config.mTimeOffsetUs)); 277 status << " timeOffset " << config.mTimeOffsetUs << "us"; 278 if (res != OK) { 279 status << " (=> " << asString(res) << ")"; 280 err = res; 281 } 282 mConfig.mTimeOffsetUs = config.mTimeOffsetUs; 283 } 284 285 // TODO: time lapse config 286 287 if (config.mStartAtUs != mConfig.mStartAtUs 288 || (config.mStopped != mConfig.mStopped && !config.mStopped)) { 289 status_t res = GetStatus(mSource->setStartTimeUs(config.mStartAtUs)); 290 status << " start at " << config.mStartAtUs << "us"; 291 if (res != OK) { 292 status << " (=> " << asString(res) << ")"; 293 err = res; 294 } 295 mConfig.mStartAtUs = config.mStartAtUs; 296 mConfig.mStopped = config.mStopped; 297 } 298 299 // suspend-resume 300 if (config.mSuspended != mConfig.mSuspended) { 301 status_t res = GetStatus(mSource->setSuspend(config.mSuspended, config.mSuspendAtUs)); 302 status << " " << (config.mSuspended ? "suspend" : "resume") 303 << " at " << config.mSuspendAtUs << "us"; 304 if (res != OK) { 305 status << " (=> " << asString(res) << ")"; 306 err = res; 307 } 308 mConfig.mSuspended = config.mSuspended; 309 mConfig.mSuspendAtUs = config.mSuspendAtUs; 310 } 311 312 if (config.mStopped != mConfig.mStopped && config.mStopped) { 313 status_t res = GetStatus(mSource->setStopTimeUs(config.mStopAtUs)); 314 status << " stop at " << config.mStopAtUs << "us"; 315 if (res != OK) { 316 status << " (=> " << asString(res) << ")"; 317 err = res; 318 } else { 319 status << " delayUs"; 320 res = GetStatus(mSource->getStopTimeOffsetUs(&config.mInputDelayUs)); 321 if (res != OK) { 322 status << " (=> " << asString(res) << ")"; 323 } else { 324 status << "=" << config.mInputDelayUs << "us"; 325 } 326 mConfig.mInputDelayUs = config.mInputDelayUs; 327 } 328 mConfig.mStopAtUs = config.mStopAtUs; 329 mConfig.mStopped = config.mStopped; 330 } 331 332 // color aspects (android._color-aspects) 333 334 // consumer usage 335 ALOGD("ISConfig%s", status.str().c_str()); 336 return err; 337 } 338 339 private: 340 sp<BGraphicBufferSource> mSource; 341 sp<C2OMXNode> mNode; 342 uint32_t mWidth; 343 uint32_t mHeight; 344 Config mConfig; 345 }; 346 347 class Codec2ClientInterfaceWrapper : public C2ComponentStore { 348 std::shared_ptr<Codec2Client> mClient; 349 350 public: 351 Codec2ClientInterfaceWrapper(std::shared_ptr<Codec2Client> client) 352 : mClient(client) { } 353 354 virtual ~Codec2ClientInterfaceWrapper() = default; 355 356 virtual c2_status_t config_sm( 357 const std::vector<C2Param *> ¶ms, 358 std::vector<std::unique_ptr<C2SettingResult>> *const failures) { 359 return mClient->config(params, C2_MAY_BLOCK, failures); 360 }; 361 362 virtual c2_status_t copyBuffer( 363 std::shared_ptr<C2GraphicBuffer>, 364 std::shared_ptr<C2GraphicBuffer>) { 365 return C2_OMITTED; 366 } 367 368 virtual c2_status_t createComponent( 369 C2String, std::shared_ptr<C2Component> *const component) { 370 component->reset(); 371 return C2_OMITTED; 372 } 373 374 virtual c2_status_t createInterface( 375 C2String, std::shared_ptr<C2ComponentInterface> *const interface) { 376 interface->reset(); 377 return C2_OMITTED; 378 } 379 380 virtual c2_status_t query_sm( 381 const std::vector<C2Param *> &stackParams, 382 const std::vector<C2Param::Index> &heapParamIndices, 383 std::vector<std::unique_ptr<C2Param>> *const heapParams) const { 384 return mClient->query(stackParams, heapParamIndices, C2_MAY_BLOCK, heapParams); 385 } 386 387 virtual c2_status_t querySupportedParams_nb( 388 std::vector<std::shared_ptr<C2ParamDescriptor>> *const params) const { 389 return mClient->querySupportedParams(params); 390 } 391 392 virtual c2_status_t querySupportedValues_sm( 393 std::vector<C2FieldSupportedValuesQuery> &fields) const { 394 return mClient->querySupportedValues(fields, C2_MAY_BLOCK); 395 } 396 397 virtual C2String getName() const { 398 return mClient->getName(); 399 } 400 401 virtual std::shared_ptr<C2ParamReflector> getParamReflector() const { 402 return mClient->getParamReflector(); 403 } 404 405 virtual std::vector<std::shared_ptr<const C2Component::Traits>> listComponents() { 406 return std::vector<std::shared_ptr<const C2Component::Traits>>(); 407 } 408 }; 409 410 } // namespace 411 412 // CCodec::ClientListener 413 414 struct CCodec::ClientListener : public Codec2Client::Listener { 415 416 explicit ClientListener(const wp<CCodec> &codec) : mCodec(codec) {} 417 418 virtual void onWorkDone( 419 const std::weak_ptr<Codec2Client::Component>& component, 420 std::list<std::unique_ptr<C2Work>>& workItems) override { 421 (void)component; 422 sp<CCodec> codec(mCodec.promote()); 423 if (!codec) { 424 return; 425 } 426 codec->onWorkDone(workItems); 427 } 428 429 virtual void onTripped( 430 const std::weak_ptr<Codec2Client::Component>& component, 431 const std::vector<std::shared_ptr<C2SettingResult>>& settingResult 432 ) override { 433 // TODO 434 (void)component; 435 (void)settingResult; 436 } 437 438 virtual void onError( 439 const std::weak_ptr<Codec2Client::Component>& component, 440 uint32_t errorCode) override { 441 // TODO 442 (void)component; 443 (void)errorCode; 444 } 445 446 virtual void onDeath( 447 const std::weak_ptr<Codec2Client::Component>& component) override { 448 { // Log the death of the component. 449 std::shared_ptr<Codec2Client::Component> comp = component.lock(); 450 if (!comp) { 451 ALOGE("Codec2 component died."); 452 } else { 453 ALOGE("Codec2 component \"%s\" died.", comp->getName().c_str()); 454 } 455 } 456 457 // Report to MediaCodec. 458 sp<CCodec> codec(mCodec.promote()); 459 if (!codec || !codec->mCallback) { 460 return; 461 } 462 codec->mCallback->onError(DEAD_OBJECT, ACTION_CODE_FATAL); 463 } 464 465 virtual void onFramesRendered( 466 const std::vector<RenderedFrame>& renderedFrames) override { 467 // TODO 468 (void)renderedFrames; 469 } 470 471 private: 472 wp<CCodec> mCodec; 473 }; 474 475 // CCodecCallbackImpl 476 477 class CCodecCallbackImpl : public CCodecCallback { 478 public: 479 explicit CCodecCallbackImpl(CCodec *codec) : mCodec(codec) {} 480 ~CCodecCallbackImpl() override = default; 481 482 void onError(status_t err, enum ActionCode actionCode) override { 483 mCodec->mCallback->onError(err, actionCode); 484 } 485 486 void onOutputFramesRendered(int64_t mediaTimeUs, nsecs_t renderTimeNs) override { 487 mCodec->mCallback->onOutputFramesRendered( 488 {RenderedFrameInfo(mediaTimeUs, renderTimeNs)}); 489 } 490 491 private: 492 CCodec *mCodec; 493 }; 494 495 // CCodec 496 497 CCodec::CCodec() 498 : mChannel(new CCodecBufferChannel(std::make_shared<CCodecCallbackImpl>(this))) { 499 CCodecWatchdog::getInstance()->registerCodec(this); 500 } 501 502 CCodec::~CCodec() { 503 } 504 505 std::shared_ptr<BufferChannelBase> CCodec::getBufferChannel() { 506 return mChannel; 507 } 508 509 status_t CCodec::tryAndReportOnError(std::function<status_t()> job) { 510 status_t err = job(); 511 if (err != C2_OK) { 512 mCallback->onError(err, ACTION_CODE_FATAL); 513 } 514 return err; 515 } 516 517 void CCodec::initiateAllocateComponent(const sp<AMessage> &msg) { 518 auto setAllocating = [this] { 519 Mutexed<State>::Locked state(mState); 520 if (state->get() != RELEASED) { 521 return INVALID_OPERATION; 522 } 523 state->set(ALLOCATING); 524 return OK; 525 }; 526 if (tryAndReportOnError(setAllocating) != OK) { 527 return; 528 } 529 530 sp<RefBase> codecInfo; 531 CHECK(msg->findObject("codecInfo", &codecInfo)); 532 // For Codec 2.0 components, componentName == codecInfo->getCodecName(). 533 534 sp<AMessage> allocMsg(new AMessage(kWhatAllocate, this)); 535 allocMsg->setObject("codecInfo", codecInfo); 536 allocMsg->post(); 537 } 538 539 void CCodec::allocate(const sp<MediaCodecInfo> &codecInfo) { 540 if (codecInfo == nullptr) { 541 mCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL); 542 return; 543 } 544 ALOGV("allocate(%s)", codecInfo->getCodecName()); 545 mClientListener.reset(new ClientListener(this)); 546 547 AString componentName = codecInfo->getCodecName(); 548 std::shared_ptr<Codec2Client> client; 549 550 // set up preferred component store to access vendor store parameters 551 client = Codec2Client::CreateFromService("default", false); 552 if (client) { 553 ALOGI("setting up '%s' as default (vendor) store", client->getInstanceName().c_str()); 554 SetPreferredCodec2ComponentStore( 555 std::make_shared<Codec2ClientInterfaceWrapper>(client)); 556 } 557 558 std::shared_ptr<Codec2Client::Component> comp = 559 Codec2Client::CreateComponentByName( 560 componentName.c_str(), 561 mClientListener, 562 &client); 563 if (!comp) { 564 ALOGE("Failed Create component: %s", componentName.c_str()); 565 Mutexed<State>::Locked state(mState); 566 state->set(RELEASED); 567 state.unlock(); 568 mCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL); 569 state.lock(); 570 return; 571 } 572 ALOGI("Created component [%s]", componentName.c_str()); 573 mChannel->setComponent(comp); 574 auto setAllocated = [this, comp, client] { 575 Mutexed<State>::Locked state(mState); 576 if (state->get() != ALLOCATING) { 577 state->set(RELEASED); 578 return UNKNOWN_ERROR; 579 } 580 state->set(ALLOCATED); 581 state->comp = comp; 582 mClient = client; 583 return OK; 584 }; 585 if (tryAndReportOnError(setAllocated) != OK) { 586 return; 587 } 588 589 // initialize config here in case setParameters is called prior to configure 590 Mutexed<Config>::Locked config(mConfig); 591 status_t err = config->initialize(mClient, comp); 592 if (err != OK) { 593 ALOGW("Failed to initialize configuration support"); 594 // TODO: report error once we complete implementation. 595 } 596 config->queryConfiguration(comp); 597 598 mCallback->onComponentAllocated(comp->getName().c_str()); 599 } 600 601 void CCodec::initiateConfigureComponent(const sp<AMessage> &format) { 602 auto checkAllocated = [this] { 603 Mutexed<State>::Locked state(mState); 604 return (state->get() != ALLOCATED) ? UNKNOWN_ERROR : OK; 605 }; 606 if (tryAndReportOnError(checkAllocated) != OK) { 607 return; 608 } 609 610 sp<AMessage> msg(new AMessage(kWhatConfigure, this)); 611 msg->setMessage("format", format); 612 msg->post(); 613 } 614 615 void CCodec::configure(const sp<AMessage> &msg) { 616 std::shared_ptr<Codec2Client::Component> comp; 617 auto checkAllocated = [this, &comp] { 618 Mutexed<State>::Locked state(mState); 619 if (state->get() != ALLOCATED) { 620 state->set(RELEASED); 621 return UNKNOWN_ERROR; 622 } 623 comp = state->comp; 624 return OK; 625 }; 626 if (tryAndReportOnError(checkAllocated) != OK) { 627 return; 628 } 629 630 auto doConfig = [msg, comp, this]() -> status_t { 631 AString mime; 632 if (!msg->findString("mime", &mime)) { 633 return BAD_VALUE; 634 } 635 636 int32_t encoder; 637 if (!msg->findInt32("encoder", &encoder)) { 638 encoder = false; 639 } 640 641 // TODO: read from intf() 642 if ((!encoder) != (comp->getName().find("encoder") == std::string::npos)) { 643 return UNKNOWN_ERROR; 644 } 645 646 int32_t storeMeta; 647 if (encoder 648 && msg->findInt32("android._input-metadata-buffer-type", &storeMeta) 649 && storeMeta != kMetadataBufferTypeInvalid) { 650 if (storeMeta != kMetadataBufferTypeANWBuffer) { 651 ALOGD("Only ANW buffers are supported for legacy metadata mode"); 652 return BAD_VALUE; 653 } 654 mChannel->setMetaMode(CCodecBufferChannel::MODE_ANW); 655 } 656 657 sp<RefBase> obj; 658 sp<Surface> surface; 659 if (msg->findObject("native-window", &obj)) { 660 surface = static_cast<Surface *>(obj.get()); 661 setSurface(surface); 662 } 663 664 Mutexed<Config>::Locked config(mConfig); 665 666 /* 667 * Handle input surface configuration 668 */ 669 if ((config->mDomain & (Config::IS_VIDEO | Config::IS_IMAGE)) 670 && (config->mDomain & Config::IS_ENCODER)) { 671 config->mISConfig.reset(new InputSurfaceWrapper::Config{}); 672 { 673 config->mISConfig->mMinFps = 0; 674 int64_t value; 675 if (msg->findInt64("repeat-previous-frame-after", &value) && value > 0) { 676 config->mISConfig->mMinFps = 1e6 / value; 677 } 678 (void)msg->findFloat("max-fps-to-encoder", &config->mISConfig->mMaxFps); 679 config->mISConfig->mMinAdjustedFps = 0; 680 config->mISConfig->mFixedAdjustedFps = 0; 681 if (msg->findInt64("max-pts-gap-to-encoder", &value)) { 682 if (value < 0 && value >= INT32_MIN) { 683 config->mISConfig->mFixedAdjustedFps = -1e6 / value; 684 } else if (value > 0 && value <= INT32_MAX) { 685 config->mISConfig->mMinAdjustedFps = 1e6 / value; 686 } 687 } 688 } 689 690 { 691 double value; 692 if (!msg->findDouble("time-lapse-fps", &value)) { 693 config->mISConfig->mCaptureFps = value; 694 } 695 } 696 697 { 698 config->mISConfig->mSuspended = false; 699 config->mISConfig->mSuspendAtUs = -1; 700 int32_t value; 701 if (msg->findInt32("create-input-buffers-suspended", &value) && value) { 702 config->mISConfig->mSuspended = true; 703 } 704 } 705 } 706 707 /* 708 * Handle desired color format. 709 */ 710 if ((config->mDomain & (Config::IS_VIDEO | Config::IS_IMAGE))) { 711 int32_t format = -1; 712 if (!msg->findInt32(KEY_COLOR_FORMAT, &format)) { 713 /* 714 * Also handle default color format (encoders require color format, so this is only 715 * needed for decoders. 716 */ 717 if (!(config->mDomain & Config::IS_ENCODER)) { 718 format = (surface == nullptr) ? COLOR_FormatYUV420Planar : COLOR_FormatSurface; 719 } 720 } 721 722 if (format >= 0) { 723 msg->setInt32("android._color-format", format); 724 } 725 } 726 727 std::vector<std::unique_ptr<C2Param>> configUpdate; 728 status_t err = config->getConfigUpdateFromSdkParams( 729 comp, msg, Config::CONFIG, C2_DONT_BLOCK, &configUpdate); 730 if (err != OK) { 731 ALOGW("failed to convert configuration to c2 params"); 732 } 733 err = config->setParameters(comp, configUpdate, C2_DONT_BLOCK); 734 if (err != OK) { 735 ALOGW("failed to configure c2 params"); 736 return err; 737 } 738 739 std::vector<std::unique_ptr<C2Param>> params; 740 C2StreamUsageTuning::input usage(0u, 0u); 741 C2StreamMaxBufferSizeInfo::input maxInputSize(0u, 0u); 742 743 std::initializer_list<C2Param::Index> indices { 744 }; 745 c2_status_t c2err = comp->query( 746 { &usage, &maxInputSize }, 747 indices, 748 C2_DONT_BLOCK, 749 ¶ms); 750 if (c2err != C2_OK && c2err != C2_BAD_INDEX) { 751 ALOGE("Failed to query component interface: %d", c2err); 752 return UNKNOWN_ERROR; 753 } 754 if (params.size() != indices.size()) { 755 ALOGE("Component returns wrong number of params: expected %zu actual %zu", 756 indices.size(), params.size()); 757 return UNKNOWN_ERROR; 758 } 759 if (usage && (usage.value & C2MemoryUsage::CPU_READ)) { 760 config->mInputFormat->setInt32("using-sw-read-often", true); 761 } 762 763 // use client specified input size if specified 764 bool clientInputSize = msg->findInt32(KEY_MAX_INPUT_SIZE, (int32_t*)&maxInputSize.value); 765 766 // TEMP: enforce minimum buffer size of 1MB for video decoders 767 if (!clientInputSize && maxInputSize.value == 0 768 && !encoder && !(config->mDomain & Config::IS_AUDIO)) { 769 maxInputSize.value = 1048576u; 770 } 771 772 // TODO: do this based on component requiring linear allocator for input 773 if ((config->mDomain & Config::IS_DECODER) || (config->mDomain & Config::IS_AUDIO)) { 774 // Pass max input size on input format to the buffer channel (if supplied by the 775 // component or by a default) 776 if (maxInputSize.value) { 777 config->mInputFormat->setInt32( 778 KEY_MAX_INPUT_SIZE, 779 (int32_t)(c2_min(maxInputSize.value, uint32_t(INT32_MAX)))); 780 } 781 } 782 783 if ((config->mDomain & (Config::IS_VIDEO | Config::IS_IMAGE))) { 784 // Set desired color format from configuration parameter 785 int32_t format; 786 if (msg->findInt32("android._color-format", &format)) { 787 if (config->mDomain & Config::IS_ENCODER) { 788 config->mInputFormat->setInt32(KEY_COLOR_FORMAT, format); 789 } else { 790 config->mOutputFormat->setInt32(KEY_COLOR_FORMAT, format); 791 } 792 } 793 } 794 795 // propagate encoder delay and padding to output format 796 if ((config->mDomain & Config::IS_DECODER) && (config->mDomain & Config::IS_AUDIO)) { 797 int delay = 0; 798 if (msg->findInt32("encoder-delay", &delay)) { 799 config->mOutputFormat->setInt32("encoder-delay", delay); 800 } 801 int padding = 0; 802 if (msg->findInt32("encoder-padding", &padding)) { 803 config->mOutputFormat->setInt32("encoder-padding", padding); 804 } 805 } 806 807 ALOGD("setup formats input: %s and output: %s", 808 config->mInputFormat->debugString().c_str(), 809 config->mOutputFormat->debugString().c_str()); 810 return OK; 811 }; 812 if (tryAndReportOnError(doConfig) != OK) { 813 return; 814 } 815 816 Mutexed<Config>::Locked config(mConfig); 817 818 mCallback->onComponentConfigured(config->mInputFormat, config->mOutputFormat); 819 } 820 821 void CCodec::initiateCreateInputSurface() { 822 status_t err = [this] { 823 Mutexed<State>::Locked state(mState); 824 if (state->get() != ALLOCATED) { 825 return UNKNOWN_ERROR; 826 } 827 // TODO: read it from intf() properly. 828 if (state->comp->getName().find("encoder") == std::string::npos) { 829 return INVALID_OPERATION; 830 } 831 return OK; 832 }(); 833 if (err != OK) { 834 mCallback->onInputSurfaceCreationFailed(err); 835 return; 836 } 837 838 (new AMessage(kWhatCreateInputSurface, this))->post(); 839 } 840 841 void CCodec::createInputSurface() { 842 status_t err; 843 sp<IGraphicBufferProducer> bufferProducer; 844 845 sp<AMessage> inputFormat; 846 sp<AMessage> outputFormat; 847 { 848 Mutexed<Config>::Locked config(mConfig); 849 inputFormat = config->mInputFormat; 850 outputFormat = config->mOutputFormat; 851 } 852 853 // TODO: Remove this property check and assume it's always true. 854 if (property_get_bool("debug.stagefright.c2inputsurface", false)) { 855 std::shared_ptr<Codec2Client::InputSurface> surface; 856 857 err = static_cast<status_t>(mClient->createInputSurface(&surface)); 858 if (err != OK) { 859 ALOGE("Failed to create input surface: %d", static_cast<int>(err)); 860 mCallback->onInputSurfaceCreationFailed(err); 861 return; 862 } 863 if (!surface) { 864 ALOGE("Failed to create input surface: null input surface"); 865 mCallback->onInputSurfaceCreationFailed(UNKNOWN_ERROR); 866 return; 867 } 868 bufferProducer = surface->getGraphicBufferProducer(); 869 err = setupInputSurface(std::make_shared<C2InputSurfaceWrapper>(surface)); 870 } else { // TODO: Remove this block. 871 using namespace ::android::hardware::media::omx::V1_0; 872 sp<IOmx> tOmx = IOmx::getService("default"); 873 if (tOmx == nullptr) { 874 ALOGE("Failed to create input surface"); 875 mCallback->onInputSurfaceCreationFailed(UNKNOWN_ERROR); 876 return; 877 } 878 sp<IOMX> omx = new utils::LWOmx(tOmx); 879 880 sp<BGraphicBufferSource> bufferSource; 881 err = omx->createInputSurface(&bufferProducer, &bufferSource); 882 883 if (err != OK) { 884 ALOGE("Failed to create input surface: %d", err); 885 mCallback->onInputSurfaceCreationFailed(err); 886 return; 887 } 888 int32_t width = 0; 889 (void)outputFormat->findInt32("width", &width); 890 int32_t height = 0; 891 (void)outputFormat->findInt32("height", &height); 892 err = setupInputSurface(std::make_shared<GraphicBufferSourceWrapper>( 893 bufferSource, width, height)); 894 } 895 896 if (err != OK) { 897 ALOGE("Failed to set up input surface: %d", err); 898 mCallback->onInputSurfaceCreationFailed(err); 899 return; 900 } 901 mCallback->onInputSurfaceCreated( 902 inputFormat, 903 outputFormat, 904 new BufferProducerWrapper(bufferProducer)); 905 } 906 907 status_t CCodec::setupInputSurface(const std::shared_ptr<InputSurfaceWrapper> &surface) { 908 status_t err = mChannel->setInputSurface(surface); 909 if (err != OK) { 910 return err; 911 } 912 913 Mutexed<Config>::Locked config(mConfig); 914 config->mInputSurface = surface; 915 if (config->mISConfig) { 916 surface->configure(*config->mISConfig); 917 } else { 918 ALOGD("ISConfig: no configuration"); 919 } 920 921 // TODO: configure |surface| with other settings. 922 return OK; 923 } 924 925 void CCodec::initiateSetInputSurface(const sp<PersistentSurface> &surface) { 926 sp<AMessage> msg = new AMessage(kWhatSetInputSurface, this); 927 msg->setObject("surface", surface); 928 msg->post(); 929 } 930 931 void CCodec::setInputSurface(const sp<PersistentSurface> &surface) { 932 sp<AMessage> inputFormat; 933 sp<AMessage> outputFormat; 934 { 935 Mutexed<Config>::Locked config(mConfig); 936 inputFormat = config->mInputFormat; 937 outputFormat = config->mOutputFormat; 938 } 939 int32_t width = 0; 940 (void)outputFormat->findInt32("width", &width); 941 int32_t height = 0; 942 (void)outputFormat->findInt32("height", &height); 943 status_t err = setupInputSurface(std::make_shared<GraphicBufferSourceWrapper>( 944 surface->getBufferSource(), width, height)); 945 if (err != OK) { 946 ALOGE("Failed to set up input surface: %d", err); 947 mCallback->onInputSurfaceDeclined(err); 948 return; 949 } 950 mCallback->onInputSurfaceAccepted(inputFormat, outputFormat); 951 } 952 953 void CCodec::initiateStart() { 954 auto setStarting = [this] { 955 Mutexed<State>::Locked state(mState); 956 if (state->get() != ALLOCATED) { 957 return UNKNOWN_ERROR; 958 } 959 state->set(STARTING); 960 return OK; 961 }; 962 if (tryAndReportOnError(setStarting) != OK) { 963 return; 964 } 965 966 (new AMessage(kWhatStart, this))->post(); 967 } 968 969 void CCodec::start() { 970 std::shared_ptr<Codec2Client::Component> comp; 971 auto checkStarting = [this, &comp] { 972 Mutexed<State>::Locked state(mState); 973 if (state->get() != STARTING) { 974 return UNKNOWN_ERROR; 975 } 976 comp = state->comp; 977 return OK; 978 }; 979 if (tryAndReportOnError(checkStarting) != OK) { 980 return; 981 } 982 983 c2_status_t err = comp->start(); 984 if (err != C2_OK) { 985 // TODO: convert err into status_t 986 mCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL); 987 return; 988 } 989 sp<AMessage> inputFormat; 990 sp<AMessage> outputFormat; 991 { 992 Mutexed<Config>::Locked config(mConfig); 993 inputFormat = config->mInputFormat; 994 outputFormat = config->mOutputFormat; 995 } 996 status_t err2 = mChannel->start(inputFormat, outputFormat); 997 if (err2 != OK) { 998 mCallback->onError(err2, ACTION_CODE_FATAL); 999 return; 1000 } 1001 1002 auto setRunning = [this] { 1003 Mutexed<State>::Locked state(mState); 1004 if (state->get() != STARTING) { 1005 return UNKNOWN_ERROR; 1006 } 1007 state->set(RUNNING); 1008 return OK; 1009 }; 1010 if (tryAndReportOnError(setRunning) != OK) { 1011 return; 1012 } 1013 mCallback->onStartCompleted(); 1014 } 1015 1016 void CCodec::initiateShutdown(bool keepComponentAllocated) { 1017 if (keepComponentAllocated) { 1018 initiateStop(); 1019 } else { 1020 initiateRelease(); 1021 } 1022 } 1023 1024 void CCodec::initiateStop() { 1025 { 1026 Mutexed<State>::Locked state(mState); 1027 if (state->get() == ALLOCATED 1028 || state->get() == RELEASED 1029 || state->get() == STOPPING 1030 || state->get() == RELEASING) { 1031 // We're already stopped, released, or doing it right now. 1032 state.unlock(); 1033 mCallback->onStopCompleted(); 1034 state.lock(); 1035 return; 1036 } 1037 state->set(STOPPING); 1038 } 1039 1040 mChannel->stop(); 1041 (new AMessage(kWhatStop, this))->post(); 1042 } 1043 1044 void CCodec::stop() { 1045 std::shared_ptr<Codec2Client::Component> comp; 1046 { 1047 Mutexed<State>::Locked state(mState); 1048 if (state->get() == RELEASING) { 1049 state.unlock(); 1050 // We're already stopped or release is in progress. 1051 mCallback->onStopCompleted(); 1052 state.lock(); 1053 return; 1054 } else if (state->get() != STOPPING) { 1055 state.unlock(); 1056 mCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL); 1057 state.lock(); 1058 return; 1059 } 1060 comp = state->comp; 1061 } 1062 status_t err = comp->stop(); 1063 if (err != C2_OK) { 1064 // TODO: convert err into status_t 1065 mCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL); 1066 } 1067 1068 { 1069 Mutexed<State>::Locked state(mState); 1070 if (state->get() == STOPPING) { 1071 state->set(ALLOCATED); 1072 } 1073 } 1074 mCallback->onStopCompleted(); 1075 } 1076 1077 void CCodec::initiateRelease(bool sendCallback /* = true */) { 1078 { 1079 Mutexed<State>::Locked state(mState); 1080 if (state->get() == RELEASED || state->get() == RELEASING) { 1081 // We're already released or doing it right now. 1082 if (sendCallback) { 1083 state.unlock(); 1084 mCallback->onReleaseCompleted(); 1085 state.lock(); 1086 } 1087 return; 1088 } 1089 if (state->get() == ALLOCATING) { 1090 state->set(RELEASING); 1091 // With the altered state allocate() would fail and clean up. 1092 if (sendCallback) { 1093 state.unlock(); 1094 mCallback->onReleaseCompleted(); 1095 state.lock(); 1096 } 1097 return; 1098 } 1099 state->set(RELEASING); 1100 } 1101 1102 mChannel->stop(); 1103 std::thread([this, sendCallback] { release(sendCallback); }).detach(); 1104 } 1105 1106 void CCodec::release(bool sendCallback) { 1107 std::shared_ptr<Codec2Client::Component> comp; 1108 { 1109 Mutexed<State>::Locked state(mState); 1110 if (state->get() == RELEASED) { 1111 if (sendCallback) { 1112 state.unlock(); 1113 mCallback->onReleaseCompleted(); 1114 state.lock(); 1115 } 1116 return; 1117 } 1118 comp = state->comp; 1119 } 1120 comp->release(); 1121 1122 { 1123 Mutexed<State>::Locked state(mState); 1124 state->set(RELEASED); 1125 state->comp.reset(); 1126 } 1127 if (sendCallback) { 1128 mCallback->onReleaseCompleted(); 1129 } 1130 } 1131 1132 status_t CCodec::setSurface(const sp<Surface> &surface) { 1133 return mChannel->setSurface(surface); 1134 } 1135 1136 void CCodec::signalFlush() { 1137 status_t err = [this] { 1138 Mutexed<State>::Locked state(mState); 1139 if (state->get() == FLUSHED) { 1140 return ALREADY_EXISTS; 1141 } 1142 if (state->get() != RUNNING) { 1143 return UNKNOWN_ERROR; 1144 } 1145 state->set(FLUSHING); 1146 return OK; 1147 }(); 1148 switch (err) { 1149 case ALREADY_EXISTS: 1150 mCallback->onFlushCompleted(); 1151 return; 1152 case OK: 1153 break; 1154 default: 1155 mCallback->onError(err, ACTION_CODE_FATAL); 1156 return; 1157 } 1158 1159 mChannel->stop(); 1160 (new AMessage(kWhatFlush, this))->post(); 1161 } 1162 1163 void CCodec::flush() { 1164 std::shared_ptr<Codec2Client::Component> comp; 1165 auto checkFlushing = [this, &comp] { 1166 Mutexed<State>::Locked state(mState); 1167 if (state->get() != FLUSHING) { 1168 return UNKNOWN_ERROR; 1169 } 1170 comp = state->comp; 1171 return OK; 1172 }; 1173 if (tryAndReportOnError(checkFlushing) != OK) { 1174 return; 1175 } 1176 1177 std::list<std::unique_ptr<C2Work>> flushedWork; 1178 c2_status_t err = comp->flush(C2Component::FLUSH_COMPONENT, &flushedWork); 1179 if (err != C2_OK) { 1180 // TODO: convert err into status_t 1181 mCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL); 1182 } 1183 1184 mChannel->flush(flushedWork); 1185 1186 { 1187 Mutexed<State>::Locked state(mState); 1188 state->set(FLUSHED); 1189 } 1190 mCallback->onFlushCompleted(); 1191 } 1192 1193 void CCodec::signalResume() { 1194 auto setResuming = [this] { 1195 Mutexed<State>::Locked state(mState); 1196 if (state->get() != FLUSHED) { 1197 return UNKNOWN_ERROR; 1198 } 1199 state->set(RESUMING); 1200 return OK; 1201 }; 1202 if (tryAndReportOnError(setResuming) != OK) { 1203 return; 1204 } 1205 1206 (void)mChannel->start(nullptr, nullptr); 1207 1208 { 1209 Mutexed<State>::Locked state(mState); 1210 if (state->get() != RESUMING) { 1211 state.unlock(); 1212 mCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL); 1213 state.lock(); 1214 return; 1215 } 1216 state->set(RUNNING); 1217 } 1218 } 1219 1220 void CCodec::signalSetParameters(const sp<AMessage> ¶ms) { 1221 sp<AMessage> msg = new AMessage(kWhatSetParameters, this); 1222 msg->setMessage("params", params); 1223 msg->post(); 1224 } 1225 1226 void CCodec::setParameters(const sp<AMessage> ¶ms) { 1227 std::shared_ptr<Codec2Client::Component> comp; 1228 auto checkState = [this, &comp] { 1229 Mutexed<State>::Locked state(mState); 1230 if (state->get() == RELEASED) { 1231 return INVALID_OPERATION; 1232 } 1233 comp = state->comp; 1234 return OK; 1235 }; 1236 if (tryAndReportOnError(checkState) != OK) { 1237 return; 1238 } 1239 1240 Mutexed<Config>::Locked config(mConfig); 1241 1242 /** 1243 * Handle input surface parameters 1244 */ 1245 if ((config->mDomain & (Config::IS_VIDEO | Config::IS_IMAGE)) 1246 && (config->mDomain & Config::IS_ENCODER) && config->mInputSurface && config->mISConfig) { 1247 (void)params->findInt64("time-offset-us", &config->mISConfig->mTimeOffsetUs); 1248 1249 if (params->findInt64("skip-frames-before", &config->mISConfig->mStartAtUs)) { 1250 config->mISConfig->mStopped = false; 1251 } else if (params->findInt64("stop-time-us", &config->mISConfig->mStopAtUs)) { 1252 config->mISConfig->mStopped = true; 1253 } 1254 1255 int32_t value; 1256 if (params->findInt32("drop-input-frames", &value)) { 1257 config->mISConfig->mSuspended = value; 1258 config->mISConfig->mSuspendAtUs = -1; 1259 (void)params->findInt64("drop-start-time-us", &config->mISConfig->mSuspendAtUs); 1260 } 1261 1262 (void)config->mInputSurface->configure(*config->mISConfig); 1263 if (config->mISConfig->mStopped) { 1264 config->mInputFormat->setInt64( 1265 "android._stop-time-offset-us", config->mISConfig->mInputDelayUs); 1266 } 1267 } 1268 1269 std::vector<std::unique_ptr<C2Param>> configUpdate; 1270 (void)config->getConfigUpdateFromSdkParams(comp, params, Config::PARAM, C2_MAY_BLOCK, &configUpdate); 1271 if (property_get_bool("debug.stagefright.ccodec_delayed_params", false)) { 1272 // mChannel->queueConfigUpdate(configUpdate); 1273 } else { 1274 (void)config->setParameters(comp, configUpdate, C2_MAY_BLOCK); 1275 } 1276 } 1277 1278 void CCodec::signalEndOfInputStream() { 1279 mCallback->onSignaledInputEOS(mChannel->signalEndOfInputStream()); 1280 } 1281 1282 void CCodec::signalRequestIDRFrame() { 1283 // TODO 1284 } 1285 1286 void CCodec::onWorkDone(std::list<std::unique_ptr<C2Work>> &workItems) { 1287 Mutexed<std::list<std::unique_ptr<C2Work>>>::Locked queue(mWorkDoneQueue); 1288 queue->splice(queue->end(), workItems); 1289 (new AMessage(kWhatWorkDone, this))->post(); 1290 } 1291 1292 void CCodec::onMessageReceived(const sp<AMessage> &msg) { 1293 TimePoint now = std::chrono::steady_clock::now(); 1294 switch (msg->what()) { 1295 case kWhatAllocate: { 1296 // C2ComponentStore::createComponent() should return within 100ms. 1297 setDeadline(now + 150ms, "allocate"); 1298 sp<RefBase> obj; 1299 CHECK(msg->findObject("codecInfo", &obj)); 1300 allocate((MediaCodecInfo *)obj.get()); 1301 break; 1302 } 1303 case kWhatConfigure: { 1304 // C2Component::commit_sm() should return within 5ms. 1305 setDeadline(now + 50ms, "configure"); 1306 sp<AMessage> format; 1307 CHECK(msg->findMessage("format", &format)); 1308 configure(format); 1309 break; 1310 } 1311 case kWhatStart: { 1312 // C2Component::start() should return within 500ms. 1313 setDeadline(now + 550ms, "start"); 1314 start(); 1315 break; 1316 } 1317 case kWhatStop: { 1318 // C2Component::stop() should return within 500ms. 1319 setDeadline(now + 550ms, "stop"); 1320 stop(); 1321 break; 1322 } 1323 case kWhatFlush: { 1324 // C2Component::flush_sm() should return within 5ms. 1325 setDeadline(now + 50ms, "flush"); 1326 flush(); 1327 break; 1328 } 1329 case kWhatCreateInputSurface: { 1330 // Surface operations may be briefly blocking. 1331 setDeadline(now + 100ms, "createInputSurface"); 1332 createInputSurface(); 1333 break; 1334 } 1335 case kWhatSetInputSurface: { 1336 // Surface operations may be briefly blocking. 1337 setDeadline(now + 100ms, "setInputSurface"); 1338 sp<RefBase> obj; 1339 CHECK(msg->findObject("surface", &obj)); 1340 sp<PersistentSurface> surface(static_cast<PersistentSurface *>(obj.get())); 1341 setInputSurface(surface); 1342 break; 1343 } 1344 case kWhatSetParameters: { 1345 setDeadline(now + 50ms, "setParameters"); 1346 sp<AMessage> params; 1347 CHECK(msg->findMessage("params", ¶ms)); 1348 setParameters(params); 1349 break; 1350 } 1351 case kWhatWorkDone: { 1352 std::unique_ptr<C2Work> work; 1353 { 1354 Mutexed<std::list<std::unique_ptr<C2Work>>>::Locked queue(mWorkDoneQueue); 1355 if (queue->empty()) { 1356 break; 1357 } 1358 work.swap(queue->front()); 1359 queue->pop_front(); 1360 if (!queue->empty()) { 1361 (new AMessage(kWhatWorkDone, this))->post(); 1362 } 1363 } 1364 1365 // handle configuration changes in work done 1366 Mutexed<Config>::Locked config(mConfig); 1367 bool changed = false; 1368 Config::Watcher<C2StreamInitDataInfo::output> initData = 1369 config->watch<C2StreamInitDataInfo::output>(); 1370 if (!work->worklets.empty() 1371 && (work->worklets.front()->output.flags 1372 & C2FrameData::FLAG_DISCARD_FRAME) == 0) { 1373 1374 // copy buffer info to config 1375 std::vector<std::unique_ptr<C2Param>> updates = 1376 std::move(work->worklets.front()->output.configUpdate); 1377 unsigned stream = 0; 1378 for (const std::shared_ptr<C2Buffer> &buf : work->worklets.front()->output.buffers) { 1379 for (const std::shared_ptr<const C2Info> &info : buf->info()) { 1380 // move all info into output-stream #0 domain 1381 updates.emplace_back(C2Param::CopyAsStream(*info, true /* output */, stream)); 1382 } 1383 for (const C2ConstGraphicBlock &block : buf->data().graphicBlocks()) { 1384 // ALOGV("got output buffer with crop %u,%u+%u,%u and size %u,%u", 1385 // block.crop().left, block.crop().top, 1386 // block.crop().width, block.crop().height, 1387 // block.width(), block.height()); 1388 updates.emplace_back(new C2StreamCropRectInfo::output(stream, block.crop())); 1389 updates.emplace_back(new C2StreamPictureSizeInfo::output( 1390 stream, block.width(), block.height())); 1391 break; // for now only do the first block 1392 } 1393 ++stream; 1394 } 1395 1396 changed = config->updateConfiguration(updates, config->mOutputDomain); 1397 1398 // copy standard infos to graphic buffers if not already present (otherwise, we 1399 // may overwrite the actual intermediate value with a final value) 1400 stream = 0; 1401 const static std::vector<C2Param::Index> stdGfxInfos = { 1402 C2StreamRotationInfo::output::PARAM_TYPE, 1403 C2StreamColorAspectsInfo::output::PARAM_TYPE, 1404 C2StreamHdrStaticInfo::output::PARAM_TYPE, 1405 C2StreamPixelAspectRatioInfo::output::PARAM_TYPE, 1406 C2StreamSurfaceScalingInfo::output::PARAM_TYPE 1407 }; 1408 for (const std::shared_ptr<C2Buffer> &buf : work->worklets.front()->output.buffers) { 1409 if (buf->data().graphicBlocks().size()) { 1410 for (C2Param::Index ix : stdGfxInfos) { 1411 if (!buf->hasInfo(ix)) { 1412 const C2Param *param = 1413 config->getConfigParameterValue(ix.withStream(stream)); 1414 if (param) { 1415 std::shared_ptr<C2Param> info(C2Param::Copy(*param)); 1416 buf->setInfo(std::static_pointer_cast<C2Info>(info)); 1417 } 1418 } 1419 } 1420 } 1421 ++stream; 1422 } 1423 } 1424 mChannel->onWorkDone( 1425 std::move(work), changed ? config->mOutputFormat : nullptr, 1426 initData.hasChanged() ? initData.update().get() : nullptr); 1427 break; 1428 } 1429 default: { 1430 ALOGE("unrecognized message"); 1431 break; 1432 } 1433 } 1434 setDeadline(TimePoint::max(), "none"); 1435 } 1436 1437 void CCodec::setDeadline(const TimePoint &newDeadline, const char *name) { 1438 Mutexed<NamedTimePoint>::Locked deadline(mDeadline); 1439 deadline->set(newDeadline, name); 1440 } 1441 1442 void CCodec::initiateReleaseIfStuck() { 1443 std::string name; 1444 { 1445 Mutexed<NamedTimePoint>::Locked deadline(mDeadline); 1446 if (deadline->get() >= std::chrono::steady_clock::now()) { 1447 // We're not stuck. 1448 return; 1449 } 1450 name = deadline->getName(); 1451 } 1452 1453 ALOGW("previous call to %s exceeded timeout", name.c_str()); 1454 initiateRelease(false); 1455 mCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL); 1456 } 1457 1458 } // namespace android 1459 1460 extern "C" android::CodecBase *CreateCodec() { 1461 return new android::CCodec; 1462 } 1463 1464