| /* |
| * Copyright 2024 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| //#define LOG_NDEBUG 0 |
| #define LOG_TAG "Codec2-InputSurface" |
| #include <android-base/logging.h> |
| #include <android/binder_auto_utils.h> |
| #include <android/binder_interface_utils.h> |
| |
| #include <mutex> |
| |
| #include <C2Config.h> |
| |
| #include <codec2/aidl/inputsurface/InputSurface.h> |
| #include <codec2/aidl/inputsurface/InputSurfaceConnection.h> |
| #include <codec2/aidl/inputsurface/InputSurfaceSource.h> |
| |
| |
| namespace aidl::android::hardware::media::c2::utils { |
| |
| using ImageConfig = InputSurface::ImageConfig; |
| using StreamConfig = InputSurface::StreamConfig; |
| using WorkStatusConfig = InputSurface::WorkStatusConfig; |
| |
| template <typename T> |
| static C2R BasicSetter(bool, C2InterfaceHelper::C2P<T> &) { |
| return C2R::Ok(); |
| } |
| |
| // Derived class of C2InterfaceHelper |
| class InputSurface::Interface : public C2InterfaceHelper { |
| public: |
| explicit Interface( |
| const std::shared_ptr<C2ReflectorHelper> &helper) |
| : C2InterfaceHelper(helper) { |
| |
| setDerivedInstance(this); |
| |
| addParameter( |
| DefineParam(mBlockSize, C2_PARAMKEY_BLOCK_SIZE) |
| .withDefault(new C2StreamBlockSizeInfo::output( |
| 0u, kDefaultImageWidth, kDefaultImageHeight)) |
| .withFields({ |
| C2F(mBlockSize, width).inRange(2, 8192, 2), |
| C2F(mBlockSize, height).inRange(2, 8192, 2),}) |
| .withSetter(BlockSizeSetter) |
| .build()); |
| addParameter( |
| DefineParam(mBlockCount, C2_PARAMKEY_BLOCK_COUNT) |
| .withDefault(new C2StreamBlockCountInfo::output( |
| 0u, kDefaultImageBufferCount)) |
| .withFields({C2F(mBlockCount, value).any()}) |
| .withSetter(BlockCountSetter) |
| .build()); |
| addParameter( |
| DefineParam(mPixelFormat, C2_PARAMKEY_PIXEL_FORMAT) |
| .withDefault(new C2StreamPixelFormatInfo::output( |
| 0u, HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED)) |
| .withFields({C2F(mPixelFormat, value).any()}) |
| .withSetter(BasicSetter<decltype(mPixelFormat)::element_type>) |
| .build()); |
| addParameter( |
| DefineParam(mUsage, C2_PARAMKEY_OUTPUT_STREAM_USAGE) |
| .withDefault(new C2StreamUsageTuning::output(0u, 0ULL)) |
| .withFields({C2F(mUsage, value).any()}) |
| .withSetter(BasicSetter<decltype(mUsage)::element_type>) |
| .build()); |
| addParameter( |
| DefineParam(mDataspace, C2_PARAMKEY_DATA_SPACE) |
| .withDefault(new C2StreamDataSpaceInfo::output( |
| 0u, kDefaultImageDataspace)) |
| .withFields({C2F(mDataspace, value).any()}) |
| .withSetter(BasicSetter<decltype(mDataspace)::element_type>) |
| .build()); |
| |
| addParameter( |
| DefineParam(mMinFps, C2_PARAMKEY_INPUT_SURFACE_MIN_FRAME_RATE) |
| .withDefault(new C2PortMinFrameRateTuning::output(0.0)) |
| .withFields({C2F(mMinFps, value).any()}) |
| .withSetter(BasicSetter<decltype(mMinFps)::element_type>) |
| .build()); |
| addParameter( |
| DefineParam(mMaxFps, C2_PARAMKEY_INPUT_SURFACE_MAX_FRAME_RATE) |
| .withDefault(new C2PortMaxFrameRateTuning::output(0.0)) |
| .withFields({C2F(mMaxFps, value).any()}) |
| .withSetter(BasicSetter<decltype(mMaxFps)::element_type>) |
| .build()); |
| addParameter( |
| DefineParam(mCaptureFps, C2_PARAMKEY_INPUT_SURFACE_CAPTURE_FRAME_RATE) |
| .withDefault(new C2PortCaptureFrameRateTuning::output(0.0)) |
| .withFields({C2F(mCaptureFps, value).any()}) |
| .withSetter(BasicSetter<decltype(mCaptureFps)::element_type>) |
| .build()); |
| addParameter( |
| DefineParam(mCodedFps, C2_PARAMKEY_FRAME_RATE) |
| .withDefault(new C2StreamFrameRateInfo::output(0u, 0.0)) |
| .withFields({C2F(mCodedFps, value).any()}) |
| .withSetter(BasicSetter<decltype(mCodedFps)::element_type>) |
| .build()); |
| addParameter( |
| DefineParam(mTimeOffset, C2_PARAMKEY_FRAME_RATE) |
| .withDefault(new C2ComponentTimeOffsetTuning(0ULL)) |
| .withFields({C2F(mTimeOffset, value).any()}) |
| .withSetter(BasicSetter<decltype(mTimeOffset)::element_type>) |
| .build()); |
| addParameter( |
| DefineParam(mStarted, C2_PARAMKEY_INPUT_SURFACE_START_AT) |
| .withDefault(new C2PortStartTimestampTuning::output(0ULL)) |
| .withFields({ |
| C2F(mStarted, enabled).any(), |
| C2F(mStarted, timestamp).any()}) |
| .withSetter(BasicSetter<decltype(mStarted)::element_type>) |
| .build()); |
| addParameter( |
| DefineParam(mStopped, C2_PARAMKEY_INPUT_SURFACE_STOP_AT) |
| .withDefault(new C2PortStopTimestampTuning::output()) |
| .withFields({ |
| C2F(mStopped, enabled).any(), |
| C2F(mStopped, timestamp).any()}) |
| .withSetter(BasicSetter<decltype(mStopped)::element_type>) |
| .build()); |
| addParameter( |
| DefineParam(mSuspended, C2_PARAMKEY_INPUT_SURFACE_SUSPEND_AT) |
| .withDefault(new C2PortSuspendTimestampTuning::output()) |
| .withFields({ |
| C2F(mSuspended, enabled).any(), |
| C2F(mSuspended, timestamp).any()}) |
| .withSetter(BasicSetter<decltype(mSuspended)::element_type>) |
| .build()); |
| addParameter( |
| DefineParam(mResumed, C2_PARAMKEY_INPUT_SURFACE_RESUME_AT) |
| .withDefault(new C2PortResumeTimestampTuning::output(0ULL)) |
| .withFields({ |
| C2F(mResumed, enabled).any(), |
| C2F(mResumed, timestamp).any()}) |
| .withSetter(BasicSetter<decltype(mResumed)::element_type>) |
| .build()); |
| addParameter( |
| DefineParam(mGap, C2_PARAMKEY_INPUT_SURFACE_TIMESTAMP_ADJUSTMENT) |
| .withDefault(new C2PortTimestampGapTuning::output( |
| C2TimestampGapAdjustmentStruct::NONE, 0ULL)) |
| .withFields({ |
| C2F(mGap, mode) |
| .oneOf({ |
| C2TimestampGapAdjustmentStruct::NONE, |
| C2TimestampGapAdjustmentStruct::MIN_GAP, |
| C2TimestampGapAdjustmentStruct::FIXED_GAP}), |
| C2F(mGap, value).any()}) |
| .withSetter(BasicSetter<decltype(mGap)::element_type>) |
| .build()); |
| addParameter( |
| DefineParam(mStopTimeOffset, C2_PARAMKEY_INPUT_SURFACE_STOP_TIME_OFFSET) |
| .withDefault(new C2PortStopTimeOffset::output(0ULL)) |
| .withFields({C2F(mStopTimeOffset, value).any()}) |
| .withSetter(BasicSetter<decltype(mStopTimeOffset)::element_type>) |
| .build()); |
| |
| addParameter( |
| DefineParam(mInputDone, C2_PARAMKEY_LAYER_INDEX) |
| .withDefault(new C2StreamLayerIndexInfo::output(0u, UINT32_MAX)) |
| .withFields({C2F(mInputDone, value).any()}) |
| .withSetter(BasicSetter<decltype(mInputDone)::element_type>) |
| .build()); |
| addParameter( |
| DefineParam(mInputDoneCount, C2_PARAMKEY_LAYER_INDEX) |
| .withDefault(new C2StreamLayerCountInfo::input(0u, 0)) |
| .withFields({C2F(mInputDoneCount, value).any()}) |
| .withSetter(InputDoneCountSetter) |
| .build()); |
| addParameter( |
| DefineParam(mEmptyCount, C2_PARAMKEY_LAYER_COUNT) |
| .withDefault(new C2StreamLayerCountInfo::output(0u, 0)) |
| .withFields({C2F(mEmptyCount, value).any()}) |
| .withSetter(EmptyCountSetter) |
| .build()); |
| } |
| |
| void getImageConfig(ImageConfig* _Nonnull config) { |
| config->mWidth = mBlockSize->width; |
| config->mHeight = mBlockSize->height; |
| config->mFormat = mPixelFormat->value; |
| config->mNumBuffers = mBlockCount->value; |
| config->mUsage = mUsage->value; |
| config->mDataspace = mDataspace->value; |
| } |
| |
| void getStreamConfig(StreamConfig* _Nonnull config) { |
| config->mMinFps = mMinFps->value; |
| config->mMaxFps = mMaxFps->value; |
| config->mCaptureFps = mCaptureFps->value; |
| config->mCodedFps = mCodedFps->value; |
| config->mTimeOffsetUs = mTimeOffset->value; |
| |
| bool suspended = mSuspended->enabled; |
| bool resumed = mResumed->enabled; |
| CHECK(resumed != suspended); |
| config->mSuspended = suspended; |
| config->mSuspendAtUs = mSuspended->timestamp; |
| config->mResumeAtUs = mResumed->timestamp; |
| bool stopped = mStopped->enabled; |
| bool started = mStarted->enabled; |
| CHECK(stopped != started); |
| config->mStopped = stopped; |
| config->mStopAtUs = mStopped->timestamp; |
| config->mStartAtUs = mStarted->timestamp; |
| |
| config->mAdjustedFpsMode = mGap->mode; |
| config->mAdjustedGapUs = mGap->value; |
| } |
| |
| void getWorkStatusConfig(WorkStatusConfig* _Nonnull config) { |
| if (mInputDone->value == UINT32_MAX) { |
| config->mLastDoneIndex = -1; |
| } else { |
| config->mLastDoneIndex = mInputDone->value; |
| } |
| config->mLastDoneCount = mInputDoneCount->value; |
| config->mEmptyCount = mEmptyCount->value; |
| } |
| |
| private: |
| // setters |
| static C2R BlockSizeSetter(bool mayBlock, |
| C2InterfaceHelper::C2P<C2StreamBlockSizeInfo::output> &me) { |
| (void)mayBlock; |
| uint32_t width_ = c2_min(me.v.width, 8192u); |
| uint32_t height_ = c2_min(me.v.height, 8192u); |
| if (width_ % 2 != 0) width_++; |
| if (height_ % 2 != 0) height_++; |
| me.set().width = width_; |
| me.set().height = height_; |
| return C2R::Ok(); |
| } |
| static C2R BlockCountSetter(bool mayBlock, |
| C2InterfaceHelper::C2P<C2StreamBlockCountInfo::output> &me) { |
| (void)mayBlock; |
| me.set().value = c2_min(me.v.value, kDefaultImageBufferCount); |
| return C2R::Ok(); |
| } |
| |
| static C2R InputDoneCountSetter(bool mayBlock, |
| C2InterfaceHelper::C2P<C2StreamLayerCountInfo::input> &me) { |
| (void)mayBlock; |
| me.set().value = me.v.value + 1; |
| return C2R::Ok(); |
| } |
| |
| static C2R EmptyCountSetter(bool mayBlock, |
| C2InterfaceHelper::C2P<C2StreamLayerCountInfo::output> &me) { |
| (void)mayBlock; |
| me.set().value = me.v.value + 1; |
| return C2R::Ok(); |
| } |
| |
| private: |
| // buffer configuraration |
| std::shared_ptr<C2StreamBlockSizeInfo::output> mBlockSize; |
| std::shared_ptr<C2StreamBlockCountInfo::output> mBlockCount; |
| std::shared_ptr<C2StreamPixelFormatInfo::output> mPixelFormat; |
| std::shared_ptr<C2StreamUsageTuning::output> mUsage; |
| std::shared_ptr<C2StreamDataSpaceInfo::output> mDataspace; |
| |
| // input surface source configuration |
| std::shared_ptr<C2PortMinFrameRateTuning::output> mMinFps; |
| std::shared_ptr<C2PortMaxFrameRateTuning::output> mMaxFps; |
| std::shared_ptr<C2PortCaptureFrameRateTuning::output> mCaptureFps; |
| std::shared_ptr<C2StreamFrameRateInfo::output> mCodedFps; |
| std::shared_ptr<C2ComponentTimeOffsetTuning> mTimeOffset; // unsigned, but |
| // signed |
| std::shared_ptr<C2PortSuspendTimestampTuning::output> mSuspended; |
| std::shared_ptr<C2PortResumeTimestampTuning::output> mResumed; |
| std::shared_ptr<C2PortStartTimestampTuning::output> mStarted; |
| std::shared_ptr<C2PortStopTimestampTuning::output> mStopped; |
| std::shared_ptr<C2PortTimestampGapTuning::output> mGap; |
| std::shared_ptr<C2PortStopTimeOffset::output> mStopTimeOffset; // query |
| |
| // current work status configuration |
| // TODO: remove this and move this to onWorkDone() |
| std::shared_ptr<C2StreamLayerIndexInfo::output> mInputDone; |
| std::shared_ptr<C2StreamLayerCountInfo::input> mInputDoneCount; |
| std::shared_ptr<C2StreamLayerCountInfo::output> mEmptyCount; |
| }; |
| |
| class InputSurface::ConfigurableIntf : public ConfigurableC2Intf { |
| public: |
| ConfigurableIntf( |
| const std::shared_ptr<InputSurface::Interface> &intf, |
| const std::shared_ptr<InputSurface> &surface) |
| : ConfigurableC2Intf("input-surface", 0), |
| mIntf(intf), mSurface(surface) { |
| } |
| |
| virtual ~ConfigurableIntf() override = default; |
| |
| virtual c2_status_t query( |
| const std::vector<C2Param::Index> &indices, |
| c2_blocking_t mayBlock, |
| std::vector<std::unique_ptr<C2Param>>* const params |
| ) const override { |
| // std::lock_guard<std::mutex> l(mConfigLock); |
| std::lock_guard<std::mutex> l(mConfigLock); |
| return mIntf->query({}, indices, mayBlock, params); |
| } |
| |
| virtual c2_status_t config( |
| const std::vector<C2Param*> ¶ms, |
| c2_blocking_t mayBlock, |
| std::vector<std::unique_ptr<C2SettingResult>>* const failures |
| ) override { |
| auto surface = mSurface.lock(); |
| if (!surface) { |
| return C2_CORRUPTED; |
| } |
| |
| c2_status_t err; |
| { |
| ImageConfig imageConfig; |
| StreamConfig streamConfig; |
| WorkStatusConfig workStatusConfig; |
| int64_t inputDelayUs = 0; |
| |
| std::lock_guard<std::mutex> l(mConfigLock); |
| err = mIntf->config(params, mayBlock, failures); |
| |
| mIntf->getImageConfig(&imageConfig); |
| mIntf->getStreamConfig(&streamConfig); |
| mIntf->getWorkStatusConfig(&workStatusConfig); |
| if (surface->updateConfig( |
| imageConfig, streamConfig, workStatusConfig, &inputDelayUs)) { |
| C2PortStopTimeOffset::output offsetConfig(inputDelayUs); |
| std::vector<std::unique_ptr<C2SettingResult>> fail; |
| c2_status_t updateErr = mIntf->config({&offsetConfig}, mayBlock, &fail); |
| } |
| } |
| return err; |
| } |
| |
| virtual c2_status_t querySupportedParams( |
| std::vector<std::shared_ptr<C2ParamDescriptor>>* const params |
| ) const override { |
| std::lock_guard<std::mutex> l(mConfigLock); |
| return mIntf->querySupportedParams(params); |
| } |
| |
| virtual c2_status_t querySupportedValues( |
| std::vector<C2FieldSupportedValuesQuery>& fields, |
| c2_blocking_t mayBlock) const override { |
| std::lock_guard<std::mutex> l(mConfigLock); |
| return mIntf->querySupportedValues(fields, mayBlock); |
| } |
| |
| private: |
| const std::shared_ptr<InputSurface::Interface> mIntf; |
| const std::weak_ptr<InputSurface> mSurface; |
| |
| mutable std::mutex mConfigLock; |
| }; |
| |
| InputSurface::InputSurface() { |
| mIntf = std::make_shared<Interface>( |
| std::make_shared<C2ReflectorHelper>()); |
| |
| // mConfigurable is initialized lazily. |
| // mInit indicates the initialization status of mConfigurable. |
| mInit = C2_NO_INIT; |
| } |
| |
| InputSurface::~InputSurface() { |
| release(); |
| } |
| |
| ::ndk::ScopedAStatus InputSurface::getSurface(::aidl::android::view::Surface* surface) { |
| std::lock_guard<std::mutex> l(mLock); |
| ANativeWindow *window = mSource->getNativeWindow(); |
| if (window) { |
| surface->reset(window); |
| return ::ndk::ScopedAStatus::ok(); |
| } |
| return ::ndk::ScopedAStatus::fromServiceSpecificError(C2_CORRUPTED); |
| } |
| |
| ::ndk::ScopedAStatus InputSurface::getConfigurable( |
| std::shared_ptr<IConfigurable>* configurable) { |
| if (mInit == C2_NO_INIT) { |
| mConfigurable = SharedRefBase::make<CachedConfigurable>( |
| std::make_unique<ConfigurableIntf>(mIntf, this->ref<InputSurface>())); |
| mInit = C2_OK; |
| } |
| if (mConfigurable) { |
| *configurable = mConfigurable; |
| return ::ndk::ScopedAStatus::ok(); |
| } |
| return ::ndk::ScopedAStatus::fromServiceSpecificError(C2_CORRUPTED); |
| } |
| |
| ::ndk::ScopedAStatus InputSurface::connect( |
| const std::shared_ptr<IInputSink>& sink, |
| std::shared_ptr<IInputSurfaceConnection>* connection) { |
| mConnection = SharedRefBase::make<InputSurfaceConnection>(sink, mSource); |
| *connection = mConnection; |
| return ::ndk::ScopedAStatus::ok(); |
| } |
| |
| void InputSurface::updateImageConfig(ImageConfig &config) { |
| std::unique_lock<std::mutex> l(mLock); |
| if (mImageConfig.mWidth != config.mWidth) { |
| mImageConfig.mWidth = config.mWidth; |
| } |
| if (mImageConfig.mHeight != config.mHeight) { |
| mImageConfig.mHeight = config.mHeight; |
| } |
| if (mImageConfig.mFormat != config.mFormat) { |
| mImageConfig.mFormat = config.mFormat; |
| } |
| if (mImageConfig.mNumBuffers != config.mNumBuffers) { |
| mImageConfig.mNumBuffers = config.mNumBuffers; |
| } |
| if (mImageConfig.mUsage != config.mUsage) { |
| mImageConfig.mUsage = config.mUsage; |
| } |
| if (mImageConfig.mDataspace != config.mDataspace) { |
| mImageConfig.mDataspace = config.mDataspace; |
| } |
| } |
| |
| bool InputSurface::updateStreamConfig( |
| StreamConfig &config, int64_t *inputDelayUs) { |
| std::stringstream status; |
| c2_status_t err = C2_OK; |
| bool inputDelayUpdated = false; |
| |
| std::unique_lock<std::mutex> l(mLock); |
| // handle StreamConfig changes. |
| // TRICKY: we do not unset frame delay repeating |
| if (config.mMinFps > 0 && config.mMinFps != mStreamConfig.mMinFps) { |
| int64_t us = 1e6 / config.mMinFps + 0.5; |
| c2_status_t res = mSource->setRepeatPreviousFrameDelayUs(us); |
| status << " minFps=" << config.mMinFps << " => repeatDelayUs=" << us; |
| if (res != C2_OK) { |
| status << " (=> " << asString(res) << ")"; |
| err = res; |
| } |
| mStreamConfig.mMinFps = config.mMinFps; |
| } |
| bool fixedModeUpdate = false; |
| if (config.mAdjustedFpsMode != C2TimestampGapAdjustmentStruct::NONE && ( |
| config.mAdjustedFpsMode != mStreamConfig.mAdjustedFpsMode || |
| config.mAdjustedGapUs != mStreamConfig.mAdjustedGapUs)) { |
| // TODO: configure GapUs to connection |
| // The original codes do not update config, figure out why. |
| mStreamConfig.mAdjustedFpsMode = config.mAdjustedFpsMode; |
| mStreamConfig.mAdjustedGapUs = config.mAdjustedGapUs; |
| fixedModeUpdate = (config.mAdjustedFpsMode == C2TimestampGapAdjustmentStruct::FIXED_GAP); |
| // TODO: update Gap to Connection. |
| } |
| // TRICKY: we do not unset max fps to 0 unless using fixed fps |
| if ((config.mMaxFps > 0 || (fixedModeUpdate && config.mMaxFps == -1)) |
| && config.mMaxFps != mStreamConfig.mMaxFps) { |
| c2_status_t res = mSource->setMaxFps(config.mMaxFps); |
| status << " maxFps=" << config.mMaxFps; |
| if (res != C2_OK) { |
| status << " (=> " << asString(res) << ")"; |
| err = res; |
| } |
| mStreamConfig.mMaxFps = config.mMaxFps; |
| } |
| if (config.mTimeOffsetUs != mStreamConfig.mTimeOffsetUs) { |
| c2_status_t res = mSource->setTimeOffsetUs(config.mTimeOffsetUs); |
| status << " timeOffset " << config.mTimeOffsetUs << "us"; |
| if (res != C2_OK) { |
| status << " (=> " << asString(res) << ")"; |
| err = res; |
| } |
| mStreamConfig.mTimeOffsetUs = config.mTimeOffsetUs; |
| } |
| if (config.mCaptureFps != mStreamConfig.mCaptureFps || |
| config.mCodedFps != mStreamConfig.mCodedFps) { |
| c2_status_t res = mSource->setTimeLapseConfig( |
| config.mCodedFps, config.mCaptureFps); |
| status << " timeLapse " << config.mCaptureFps << "fps as " |
| << config.mCodedFps << "fps"; |
| if (res != C2_OK) { |
| status << " (=> " << asString(res) << ")"; |
| err = res; |
| } |
| mStreamConfig.mCaptureFps = config.mCaptureFps; |
| mStreamConfig.mCodedFps = config.mCodedFps; |
| } |
| if (config.mStartAtUs != mStreamConfig.mStartAtUs || |
| (config.mStopped != mStreamConfig.mStopped && !config.mStopped)) { |
| c2_status_t res = mSource->setStartTimeUs(config.mStartAtUs); |
| status << " start at " << config.mStartAtUs << "us"; |
| if (res != C2_OK) { |
| status << " (=> " << asString(res) << ")"; |
| err = res; |
| } |
| mStreamConfig.mStartAtUs = config.mStartAtUs; |
| mStreamConfig.mStopped = config.mStopped; |
| } |
| if (config.mSuspended != mStreamConfig.mSuspended) { |
| c2_status_t res = mSource->setSuspend(config.mSuspended, config.mSuspendAtUs); |
| status << " " << (config.mSuspended ? "suspend" : "resume") |
| << " at " << config.mSuspendAtUs << "us"; |
| if (res != C2_OK) { |
| status << " (=> " << asString(res) << ")"; |
| err = res; |
| } |
| mStreamConfig.mSuspended = config.mSuspended; |
| mStreamConfig.mSuspendAtUs = config.mSuspendAtUs; |
| } |
| if (config.mStopped != mStreamConfig.mStopped && config.mStopped) { |
| // start time has changed or started from stop. |
| c2_status_t res = mSource->setStopTimeUs(config.mStopAtUs); |
| status << " stop at " << config.mStopAtUs << "us"; |
| if (res != C2_OK) { |
| status << " (=> " << asString(res) << ")"; |
| err = res; |
| } else { |
| status << " delayUs"; |
| res = mSource->getStopTimeOffsetUs(inputDelayUs); |
| if (res != C2_OK) { |
| status << " (=> " << asString(res) << ")"; |
| } else { |
| status << "=" << *inputDelayUs << "us"; |
| inputDelayUpdated = true; |
| } |
| } |
| mStreamConfig.mStopAtUs = config.mStopAtUs; |
| mStreamConfig.mStopped = config.mStopped; |
| } |
| if (status.str().empty()) { |
| ALOGD("StreamConfig not changed"); |
| } else { |
| ALOGD("StreamConfig%s", status.str().c_str()); |
| } |
| return inputDelayUpdated; |
| } |
| |
| void InputSurface::updateWorkStatusConfig(WorkStatusConfig &config) { |
| (void)config; |
| // TODO |
| } |
| |
| bool InputSurface::updateConfig( |
| ImageConfig &imageConfig, StreamConfig &streamConfig, |
| WorkStatusConfig &workStatusConfig, int64_t *inputDelayUs) { |
| updateImageConfig(imageConfig); |
| bool ret = updateStreamConfig(streamConfig, inputDelayUs); |
| updateWorkStatusConfig(workStatusConfig); |
| |
| return ret; |
| } |
| |
| void InputSurface::release() { |
| ALOGD("all refs are gone"); |
| // TODO clean up |
| } |
| |
| } // namespace aidl::android::hardware::media::c2::utils |