| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 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 |  | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 29 | #include <android/IOMXBufferSource.h> | 
| Pawin Vongmasa | bf69de9 | 2019-10-29 06:21:27 -0700 | [diff] [blame] | 30 | #include <android/hardware/media/c2/1.0/IInputSurface.h> | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 31 | #include <android/hardware/media/omx/1.0/IGraphicBufferSource.h> | 
|  | 32 | #include <android/hardware/media/omx/1.0/IOmx.h> | 
|  | 33 | #include <android-base/stringprintf.h> | 
|  | 34 | #include <cutils/properties.h> | 
|  | 35 | #include <gui/IGraphicBufferProducer.h> | 
|  | 36 | #include <gui/Surface.h> | 
|  | 37 | #include <gui/bufferqueue/1.0/H2BGraphicBufferProducer.h> | 
| Wonsik Kim | 9917d4a | 2019-10-24 12:56:38 -0700 | [diff] [blame] | 38 | #include <media/omx/1.0/WOmxNode.h> | 
|  | 39 | #include <media/openmax/OMX_Core.h> | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 40 | #include <media/openmax/OMX_IndexExt.h> | 
| Wonsik Kim | 1f5063d | 2021-05-03 15:41:17 -0700 | [diff] [blame] | 41 | #include <media/stagefright/foundation/avc_utils.h> | 
| Wonsik Kim | 9917d4a | 2019-10-24 12:56:38 -0700 | [diff] [blame] | 42 | #include <media/stagefright/omx/1.0/WGraphicBufferSource.h> | 
|  | 43 | #include <media/stagefright/omx/OmxGraphicBufferSource.h> | 
| Wonsik Kim | 155d5cb | 2019-10-09 12:49:49 -0700 | [diff] [blame] | 44 | #include <media/stagefright/CCodec.h> | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 45 | #include <media/stagefright/BufferProducerWrapper.h> | 
|  | 46 | #include <media/stagefright/MediaCodecConstants.h> | 
|  | 47 | #include <media/stagefright/PersistentSurface.h> | 
| ted.sun | 765db4d | 2020-06-23 14:03:41 +0800 | [diff] [blame] | 48 | #include <utils/NativeHandle.h> | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 49 |  | 
|  | 50 | #include "C2OMXNode.h" | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 51 | #include "CCodecBufferChannel.h" | 
| Wonsik Kim | 155d5cb | 2019-10-09 12:49:49 -0700 | [diff] [blame] | 52 | #include "CCodecConfig.h" | 
| Wonsik Kim | fb7a767 | 2019-12-27 17:13:33 -0800 | [diff] [blame] | 53 | #include "Codec2Mapper.h" | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 54 | #include "InputSurfaceWrapper.h" | 
|  | 55 |  | 
|  | 56 | extern "C" android::PersistentSurface *CreateInputSurface(); | 
|  | 57 |  | 
|  | 58 | namespace android { | 
|  | 59 |  | 
|  | 60 | using namespace std::chrono_literals; | 
|  | 61 | using ::android::hardware::graphics::bufferqueue::V1_0::utils::H2BGraphicBufferProducer; | 
|  | 62 | using android::base::StringPrintf; | 
| Pawin Vongmasa | d0f0e14 | 2018-11-15 03:36:28 -0800 | [diff] [blame] | 63 | using ::android::hardware::media::c2::V1_0::IInputSurface; | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 64 |  | 
| Wonsik Kim | 9917d4a | 2019-10-24 12:56:38 -0700 | [diff] [blame] | 65 | typedef hardware::media::omx::V1_0::IGraphicBufferSource HGraphicBufferSource; | 
| Wonsik Kim | 155d5cb | 2019-10-09 12:49:49 -0700 | [diff] [blame] | 66 | typedef CCodecConfig Config; | 
| Wonsik Kim | 9917d4a | 2019-10-24 12:56:38 -0700 | [diff] [blame] | 67 |  | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 68 | namespace { | 
|  | 69 |  | 
|  | 70 | class CCodecWatchdog : public AHandler { | 
|  | 71 | private: | 
|  | 72 | enum { | 
|  | 73 | kWhatWatch, | 
|  | 74 | }; | 
|  | 75 | constexpr static int64_t kWatchIntervalUs = 3300000;  // 3.3 secs | 
|  | 76 |  | 
|  | 77 | public: | 
|  | 78 | static sp<CCodecWatchdog> getInstance() { | 
|  | 79 | static sp<CCodecWatchdog> instance(new CCodecWatchdog); | 
|  | 80 | static std::once_flag flag; | 
|  | 81 | // Call Init() only once. | 
|  | 82 | std::call_once(flag, Init, instance); | 
|  | 83 | return instance; | 
|  | 84 | } | 
|  | 85 |  | 
|  | 86 | ~CCodecWatchdog() = default; | 
|  | 87 |  | 
|  | 88 | void watch(sp<CCodec> codec) { | 
|  | 89 | bool shouldPost = false; | 
|  | 90 | { | 
|  | 91 | Mutexed<std::set<wp<CCodec>>>::Locked codecs(mCodecsToWatch); | 
|  | 92 | // If a watch message is in flight, piggy-back this instance as well. | 
|  | 93 | // Otherwise, post a new watch message. | 
|  | 94 | shouldPost = codecs->empty(); | 
|  | 95 | codecs->emplace(codec); | 
|  | 96 | } | 
|  | 97 | if (shouldPost) { | 
|  | 98 | ALOGV("posting watch message"); | 
|  | 99 | (new AMessage(kWhatWatch, this))->post(kWatchIntervalUs); | 
|  | 100 | } | 
|  | 101 | } | 
|  | 102 |  | 
|  | 103 | protected: | 
|  | 104 | void onMessageReceived(const sp<AMessage> &msg) { | 
|  | 105 | switch (msg->what()) { | 
|  | 106 | case kWhatWatch: { | 
|  | 107 | Mutexed<std::set<wp<CCodec>>>::Locked codecs(mCodecsToWatch); | 
|  | 108 | ALOGV("watch for %zu codecs", codecs->size()); | 
|  | 109 | for (auto it = codecs->begin(); it != codecs->end(); ++it) { | 
|  | 110 | sp<CCodec> codec = it->promote(); | 
|  | 111 | if (codec == nullptr) { | 
|  | 112 | continue; | 
|  | 113 | } | 
|  | 114 | codec->initiateReleaseIfStuck(); | 
|  | 115 | } | 
|  | 116 | codecs->clear(); | 
|  | 117 | break; | 
|  | 118 | } | 
|  | 119 |  | 
|  | 120 | default: { | 
|  | 121 | TRESPASS("CCodecWatchdog: unrecognized message"); | 
|  | 122 | } | 
|  | 123 | } | 
|  | 124 | } | 
|  | 125 |  | 
|  | 126 | private: | 
|  | 127 | CCodecWatchdog() : mLooper(new ALooper) {} | 
|  | 128 |  | 
|  | 129 | static void Init(const sp<CCodecWatchdog> &thiz) { | 
|  | 130 | ALOGV("Init"); | 
|  | 131 | thiz->mLooper->setName("CCodecWatchdog"); | 
|  | 132 | thiz->mLooper->registerHandler(thiz); | 
|  | 133 | thiz->mLooper->start(); | 
|  | 134 | } | 
|  | 135 |  | 
|  | 136 | sp<ALooper> mLooper; | 
|  | 137 |  | 
|  | 138 | Mutexed<std::set<wp<CCodec>>> mCodecsToWatch; | 
|  | 139 | }; | 
|  | 140 |  | 
|  | 141 | class C2InputSurfaceWrapper : public InputSurfaceWrapper { | 
|  | 142 | public: | 
|  | 143 | explicit C2InputSurfaceWrapper( | 
|  | 144 | const std::shared_ptr<Codec2Client::InputSurface> &surface) : | 
|  | 145 | mSurface(surface) { | 
|  | 146 | } | 
|  | 147 |  | 
|  | 148 | ~C2InputSurfaceWrapper() override = default; | 
|  | 149 |  | 
|  | 150 | status_t connect(const std::shared_ptr<Codec2Client::Component> &comp) override { | 
|  | 151 | if (mConnection != nullptr) { | 
|  | 152 | return ALREADY_EXISTS; | 
|  | 153 | } | 
| Pawin Vongmasa | 1c75a23 | 2019-01-09 04:41:52 -0800 | [diff] [blame] | 154 | return toStatusT(comp->connectToInputSurface(mSurface, &mConnection)); | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 155 | } | 
|  | 156 |  | 
|  | 157 | void disconnect() override { | 
|  | 158 | if (mConnection != nullptr) { | 
|  | 159 | mConnection->disconnect(); | 
|  | 160 | mConnection = nullptr; | 
|  | 161 | } | 
|  | 162 | } | 
|  | 163 |  | 
|  | 164 | status_t start() override { | 
|  | 165 | // InputSurface does not distinguish started state | 
|  | 166 | return OK; | 
|  | 167 | } | 
|  | 168 |  | 
|  | 169 | status_t signalEndOfInputStream() override { | 
|  | 170 | C2InputSurfaceEosTuning eos(true); | 
|  | 171 | std::vector<std::unique_ptr<C2SettingResult>> failures; | 
| Pawin Vongmasa | 1c75a23 | 2019-01-09 04:41:52 -0800 | [diff] [blame] | 172 | c2_status_t err = mSurface->config({&eos}, C2_MAY_BLOCK, &failures); | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 173 | if (err != C2_OK) { | 
|  | 174 | return UNKNOWN_ERROR; | 
|  | 175 | } | 
|  | 176 | return OK; | 
|  | 177 | } | 
|  | 178 |  | 
|  | 179 | status_t configure(Config &config __unused) { | 
|  | 180 | // TODO | 
|  | 181 | return OK; | 
|  | 182 | } | 
|  | 183 |  | 
|  | 184 | private: | 
|  | 185 | std::shared_ptr<Codec2Client::InputSurface> mSurface; | 
|  | 186 | std::shared_ptr<Codec2Client::InputSurfaceConnection> mConnection; | 
|  | 187 | }; | 
|  | 188 |  | 
|  | 189 | class GraphicBufferSourceWrapper : public InputSurfaceWrapper { | 
|  | 190 | public: | 
| Wonsik Kim | 9917d4a | 2019-10-24 12:56:38 -0700 | [diff] [blame] | 191 | typedef hardware::media::omx::V1_0::Status OmxStatus; | 
|  | 192 |  | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 193 | GraphicBufferSourceWrapper( | 
| Wonsik Kim | 9917d4a | 2019-10-24 12:56:38 -0700 | [diff] [blame] | 194 | const sp<HGraphicBufferSource> &source, | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 195 | uint32_t width, | 
| Wonsik Kim | 9eac4d1 | 2019-05-23 12:58:48 -0700 | [diff] [blame] | 196 | uint32_t height, | 
|  | 197 | uint64_t usage) | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 198 | : mSource(source), mWidth(width), mHeight(height) { | 
|  | 199 | mDataSpace = HAL_DATASPACE_BT709; | 
| Wonsik Kim | 9eac4d1 | 2019-05-23 12:58:48 -0700 | [diff] [blame] | 200 | mConfig.mUsage = usage; | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 201 | } | 
|  | 202 | ~GraphicBufferSourceWrapper() override = default; | 
|  | 203 |  | 
|  | 204 | status_t connect(const std::shared_ptr<Codec2Client::Component> &comp) override { | 
|  | 205 | mNode = new C2OMXNode(comp); | 
| Wonsik Kim | 9917d4a | 2019-10-24 12:56:38 -0700 | [diff] [blame] | 206 | mOmxNode = new hardware::media::omx::V1_0::utils::TWOmxNode(mNode); | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 207 | mNode->setFrameSize(mWidth, mHeight); | 
|  | 208 |  | 
| Wonsik Kim | 9eac4d1 | 2019-05-23 12:58:48 -0700 | [diff] [blame] | 209 | // Usage is queried during configure(), so setting it beforehand. | 
|  | 210 | OMX_U32 usage = mConfig.mUsage & 0xFFFFFFFF; | 
|  | 211 | (void)mNode->setParameter( | 
|  | 212 | (OMX_INDEXTYPE)OMX_IndexParamConsumerUsageBits, | 
|  | 213 | &usage, sizeof(usage)); | 
|  | 214 |  | 
| Wonsik Kim | 9917d4a | 2019-10-24 12:56:38 -0700 | [diff] [blame] | 215 | mSource->configure( | 
|  | 216 | mOmxNode, static_cast<hardware::graphics::common::V1_0::Dataspace>(mDataSpace)); | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 217 | return OK; | 
|  | 218 | } | 
|  | 219 |  | 
|  | 220 | void disconnect() override { | 
|  | 221 | if (mNode == nullptr) { | 
|  | 222 | return; | 
|  | 223 | } | 
|  | 224 | sp<IOMXBufferSource> source = mNode->getSource(); | 
|  | 225 | if (source == nullptr) { | 
|  | 226 | ALOGD("GBSWrapper::disconnect: node is not configured with OMXBufferSource."); | 
|  | 227 | return; | 
|  | 228 | } | 
|  | 229 | source->onOmxIdle(); | 
|  | 230 | source->onOmxLoaded(); | 
|  | 231 | mNode.clear(); | 
| Wonsik Kim | 9917d4a | 2019-10-24 12:56:38 -0700 | [diff] [blame] | 232 | mOmxNode.clear(); | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 233 | } | 
|  | 234 |  | 
| Wonsik Kim | 9917d4a | 2019-10-24 12:56:38 -0700 | [diff] [blame] | 235 | status_t GetStatus(hardware::Return<OmxStatus> &&status) { | 
|  | 236 | if (status.isOk()) { | 
|  | 237 | return static_cast<status_t>(status.withDefault(OmxStatus::UNKNOWN_ERROR)); | 
|  | 238 | } else if (status.isDeadObject()) { | 
|  | 239 | return DEAD_OBJECT; | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 240 | } | 
| Wonsik Kim | 9917d4a | 2019-10-24 12:56:38 -0700 | [diff] [blame] | 241 | return UNKNOWN_ERROR; | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 242 | } | 
|  | 243 |  | 
|  | 244 | status_t start() override { | 
|  | 245 | sp<IOMXBufferSource> source = mNode->getSource(); | 
|  | 246 | if (source == nullptr) { | 
|  | 247 | return NO_INIT; | 
|  | 248 | } | 
| Taehwan Kim | 8b3bcdd | 2020-11-26 22:40:40 +0900 | [diff] [blame] | 249 |  | 
| Wonsik Kim | 0f6b61d | 2021-01-05 18:55:22 -0800 | [diff] [blame] | 250 | size_t numSlots = 16; | 
| Wonsik Kim | 34d6601 | 2021-03-01 16:40:33 -0800 | [diff] [blame] | 251 | constexpr OMX_U32 kPortIndexInput = 0; | 
| Taehwan Kim | 8b3bcdd | 2020-11-26 22:40:40 +0900 | [diff] [blame] | 252 |  | 
| Wonsik Kim | 34d6601 | 2021-03-01 16:40:33 -0800 | [diff] [blame] | 253 | OMX_PARAM_PORTDEFINITIONTYPE param; | 
|  | 254 | param.nPortIndex = kPortIndexInput; | 
|  | 255 | status_t err = mNode->getParameter(OMX_IndexParamPortDefinition, | 
|  | 256 | ¶m, sizeof(param)); | 
|  | 257 | if (err == OK) { | 
|  | 258 | numSlots = param.nBufferCountActual; | 
| Taehwan Kim | 8b3bcdd | 2020-11-26 22:40:40 +0900 | [diff] [blame] | 259 | } | 
|  | 260 |  | 
|  | 261 | for (size_t i = 0; i < numSlots; ++i) { | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 262 | source->onInputBufferAdded(i); | 
|  | 263 | } | 
|  | 264 |  | 
|  | 265 | source->onOmxExecuting(); | 
|  | 266 | return OK; | 
|  | 267 | } | 
|  | 268 |  | 
|  | 269 | status_t signalEndOfInputStream() override { | 
|  | 270 | return GetStatus(mSource->signalEndOfInputStream()); | 
|  | 271 | } | 
|  | 272 |  | 
|  | 273 | status_t configure(Config &config) { | 
|  | 274 | std::stringstream status; | 
|  | 275 | status_t err = OK; | 
|  | 276 |  | 
|  | 277 | // handle each configuration granually, in case we need to handle part of the configuration | 
|  | 278 | // elsewhere | 
|  | 279 |  | 
|  | 280 | // TRICKY: we do not unset frame delay repeating | 
|  | 281 | if (config.mMinFps > 0 && config.mMinFps != mConfig.mMinFps) { | 
|  | 282 | int64_t us = 1e6 / config.mMinFps + 0.5; | 
|  | 283 | status_t res = GetStatus(mSource->setRepeatPreviousFrameDelayUs(us)); | 
|  | 284 | status << " minFps=" << config.mMinFps << " => repeatDelayUs=" << us; | 
|  | 285 | if (res != OK) { | 
|  | 286 | status << " (=> " << asString(res) << ")"; | 
|  | 287 | err = res; | 
|  | 288 | } | 
|  | 289 | mConfig.mMinFps = config.mMinFps; | 
|  | 290 | } | 
|  | 291 |  | 
|  | 292 | // pts gap | 
|  | 293 | if (config.mMinAdjustedFps > 0 || config.mFixedAdjustedFps > 0) { | 
|  | 294 | if (mNode != nullptr) { | 
|  | 295 | OMX_PARAM_U32TYPE ptrGapParam = {}; | 
|  | 296 | ptrGapParam.nSize = sizeof(OMX_PARAM_U32TYPE); | 
| Wonsik Kim | 95ba016 | 2019-03-19 15:51:54 -0700 | [diff] [blame] | 297 | float gap = (config.mMinAdjustedFps > 0) | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 298 | ? c2_min(INT32_MAX + 0., 1e6 / config.mMinAdjustedFps + 0.5) | 
|  | 299 | : c2_max(0. - INT32_MAX, -1e6 / config.mFixedAdjustedFps - 0.5); | 
| Wonsik Kim | 95ba016 | 2019-03-19 15:51:54 -0700 | [diff] [blame] | 300 | // float -> uint32_t is undefined if the value is negative. | 
|  | 301 | // First convert to int32_t to ensure the expected behavior. | 
|  | 302 | ptrGapParam.nU32 = int32_t(gap); | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 303 | (void)mNode->setParameter( | 
|  | 304 | (OMX_INDEXTYPE)OMX_IndexParamMaxFrameDurationForBitrateControl, | 
|  | 305 | &ptrGapParam, sizeof(ptrGapParam)); | 
|  | 306 | } | 
|  | 307 | } | 
|  | 308 |  | 
|  | 309 | // max fps | 
|  | 310 | // TRICKY: we do not unset max fps to 0 unless using fixed fps | 
| Wonsik Kim | 95ba016 | 2019-03-19 15:51:54 -0700 | [diff] [blame] | 311 | if ((config.mMaxFps > 0 || (config.mFixedAdjustedFps > 0 && config.mMaxFps == -1)) | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 312 | && config.mMaxFps != mConfig.mMaxFps) { | 
|  | 313 | status_t res = GetStatus(mSource->setMaxFps(config.mMaxFps)); | 
|  | 314 | status << " maxFps=" << config.mMaxFps; | 
|  | 315 | if (res != OK) { | 
|  | 316 | status << " (=> " << asString(res) << ")"; | 
|  | 317 | err = res; | 
|  | 318 | } | 
|  | 319 | mConfig.mMaxFps = config.mMaxFps; | 
|  | 320 | } | 
|  | 321 |  | 
|  | 322 | if (config.mTimeOffsetUs != mConfig.mTimeOffsetUs) { | 
|  | 323 | status_t res = GetStatus(mSource->setTimeOffsetUs(config.mTimeOffsetUs)); | 
|  | 324 | status << " timeOffset " << config.mTimeOffsetUs << "us"; | 
|  | 325 | if (res != OK) { | 
|  | 326 | status << " (=> " << asString(res) << ")"; | 
|  | 327 | err = res; | 
|  | 328 | } | 
|  | 329 | mConfig.mTimeOffsetUs = config.mTimeOffsetUs; | 
|  | 330 | } | 
|  | 331 |  | 
|  | 332 | if (config.mCaptureFps != mConfig.mCaptureFps || config.mCodedFps != mConfig.mCodedFps) { | 
|  | 333 | status_t res = | 
|  | 334 | GetStatus(mSource->setTimeLapseConfig(config.mCodedFps, config.mCaptureFps)); | 
|  | 335 | status << " timeLapse " << config.mCaptureFps << "fps as " << config.mCodedFps << "fps"; | 
|  | 336 | if (res != OK) { | 
|  | 337 | status << " (=> " << asString(res) << ")"; | 
|  | 338 | err = res; | 
|  | 339 | } | 
|  | 340 | mConfig.mCaptureFps = config.mCaptureFps; | 
|  | 341 | mConfig.mCodedFps = config.mCodedFps; | 
|  | 342 | } | 
|  | 343 |  | 
|  | 344 | if (config.mStartAtUs != mConfig.mStartAtUs | 
|  | 345 | || (config.mStopped != mConfig.mStopped && !config.mStopped)) { | 
|  | 346 | status_t res = GetStatus(mSource->setStartTimeUs(config.mStartAtUs)); | 
|  | 347 | status << " start at " << config.mStartAtUs << "us"; | 
|  | 348 | if (res != OK) { | 
|  | 349 | status << " (=> " << asString(res) << ")"; | 
|  | 350 | err = res; | 
|  | 351 | } | 
|  | 352 | mConfig.mStartAtUs = config.mStartAtUs; | 
|  | 353 | mConfig.mStopped = config.mStopped; | 
|  | 354 | } | 
|  | 355 |  | 
|  | 356 | // suspend-resume | 
|  | 357 | if (config.mSuspended != mConfig.mSuspended) { | 
|  | 358 | status_t res = GetStatus(mSource->setSuspend(config.mSuspended, config.mSuspendAtUs)); | 
|  | 359 | status << " " << (config.mSuspended ? "suspend" : "resume") | 
|  | 360 | << " at " << config.mSuspendAtUs << "us"; | 
|  | 361 | if (res != OK) { | 
|  | 362 | status << " (=> " << asString(res) << ")"; | 
|  | 363 | err = res; | 
|  | 364 | } | 
|  | 365 | mConfig.mSuspended = config.mSuspended; | 
|  | 366 | mConfig.mSuspendAtUs = config.mSuspendAtUs; | 
|  | 367 | } | 
|  | 368 |  | 
|  | 369 | if (config.mStopped != mConfig.mStopped && config.mStopped) { | 
|  | 370 | status_t res = GetStatus(mSource->setStopTimeUs(config.mStopAtUs)); | 
|  | 371 | status << " stop at " << config.mStopAtUs << "us"; | 
|  | 372 | if (res != OK) { | 
|  | 373 | status << " (=> " << asString(res) << ")"; | 
|  | 374 | err = res; | 
|  | 375 | } else { | 
|  | 376 | status << " delayUs"; | 
| Wonsik Kim | 9917d4a | 2019-10-24 12:56:38 -0700 | [diff] [blame] | 377 | hardware::Return<void> trans = mSource->getStopTimeOffsetUs( | 
|  | 378 | [&res, &delayUs = config.mInputDelayUs]( | 
|  | 379 | auto status, auto stopTimeOffsetUs) { | 
|  | 380 | res = static_cast<status_t>(status); | 
|  | 381 | delayUs = stopTimeOffsetUs; | 
|  | 382 | }); | 
|  | 383 | if (!trans.isOk()) { | 
|  | 384 | res = trans.isDeadObject() ? DEAD_OBJECT : UNKNOWN_ERROR; | 
|  | 385 | } | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 386 | if (res != OK) { | 
|  | 387 | status << " (=> " << asString(res) << ")"; | 
|  | 388 | } else { | 
|  | 389 | status << "=" << config.mInputDelayUs << "us"; | 
|  | 390 | } | 
|  | 391 | mConfig.mInputDelayUs = config.mInputDelayUs; | 
|  | 392 | } | 
|  | 393 | mConfig.mStopAtUs = config.mStopAtUs; | 
|  | 394 | mConfig.mStopped = config.mStopped; | 
|  | 395 | } | 
|  | 396 |  | 
|  | 397 | // color aspects (android._color-aspects) | 
|  | 398 |  | 
| Wonsik Kim | 9eac4d1 | 2019-05-23 12:58:48 -0700 | [diff] [blame] | 399 | // consumer usage is queried earlier. | 
|  | 400 |  | 
| Wonsik Kim | bd55793 | 2019-07-02 15:51:20 -0700 | [diff] [blame] | 401 | if (status.str().empty()) { | 
|  | 402 | ALOGD("ISConfig not changed"); | 
|  | 403 | } else { | 
|  | 404 | ALOGD("ISConfig%s", status.str().c_str()); | 
|  | 405 | } | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 406 | return err; | 
|  | 407 | } | 
|  | 408 |  | 
| Wonsik Kim | 4f3314d | 2019-03-26 17:00:34 -0700 | [diff] [blame] | 409 | void onInputBufferDone(c2_cntr64_t index) override { | 
|  | 410 | mNode->onInputBufferDone(index); | 
|  | 411 | } | 
|  | 412 |  | 
| Wonsik Kim | 673dd19 | 2021-01-29 14:58:12 -0800 | [diff] [blame] | 413 | android_dataspace getDataspace() override { | 
|  | 414 | return mNode->getDataspace(); | 
|  | 415 | } | 
|  | 416 |  | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 417 | private: | 
| Wonsik Kim | 9917d4a | 2019-10-24 12:56:38 -0700 | [diff] [blame] | 418 | sp<HGraphicBufferSource> mSource; | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 419 | sp<C2OMXNode> mNode; | 
| Wonsik Kim | 9917d4a | 2019-10-24 12:56:38 -0700 | [diff] [blame] | 420 | sp<hardware::media::omx::V1_0::IOmxNode> mOmxNode; | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 421 | uint32_t mWidth; | 
|  | 422 | uint32_t mHeight; | 
|  | 423 | Config mConfig; | 
|  | 424 | }; | 
|  | 425 |  | 
|  | 426 | class Codec2ClientInterfaceWrapper : public C2ComponentStore { | 
|  | 427 | std::shared_ptr<Codec2Client> mClient; | 
|  | 428 |  | 
|  | 429 | public: | 
|  | 430 | Codec2ClientInterfaceWrapper(std::shared_ptr<Codec2Client> client) | 
|  | 431 | : mClient(client) { } | 
|  | 432 |  | 
|  | 433 | virtual ~Codec2ClientInterfaceWrapper() = default; | 
|  | 434 |  | 
|  | 435 | virtual c2_status_t config_sm( | 
|  | 436 | const std::vector<C2Param *> ¶ms, | 
|  | 437 | std::vector<std::unique_ptr<C2SettingResult>> *const failures) { | 
|  | 438 | return mClient->config(params, C2_MAY_BLOCK, failures); | 
|  | 439 | }; | 
|  | 440 |  | 
|  | 441 | virtual c2_status_t copyBuffer( | 
|  | 442 | std::shared_ptr<C2GraphicBuffer>, | 
|  | 443 | std::shared_ptr<C2GraphicBuffer>) { | 
|  | 444 | return C2_OMITTED; | 
|  | 445 | } | 
|  | 446 |  | 
|  | 447 | virtual c2_status_t createComponent( | 
|  | 448 | C2String, std::shared_ptr<C2Component> *const component) { | 
|  | 449 | component->reset(); | 
|  | 450 | return C2_OMITTED; | 
|  | 451 | } | 
|  | 452 |  | 
|  | 453 | virtual c2_status_t createInterface( | 
|  | 454 | C2String, std::shared_ptr<C2ComponentInterface> *const interface) { | 
|  | 455 | interface->reset(); | 
|  | 456 | return C2_OMITTED; | 
|  | 457 | } | 
|  | 458 |  | 
|  | 459 | virtual c2_status_t query_sm( | 
|  | 460 | const std::vector<C2Param *> &stackParams, | 
|  | 461 | const std::vector<C2Param::Index> &heapParamIndices, | 
|  | 462 | std::vector<std::unique_ptr<C2Param>> *const heapParams) const { | 
|  | 463 | return mClient->query(stackParams, heapParamIndices, C2_MAY_BLOCK, heapParams); | 
|  | 464 | } | 
|  | 465 |  | 
|  | 466 | virtual c2_status_t querySupportedParams_nb( | 
|  | 467 | std::vector<std::shared_ptr<C2ParamDescriptor>> *const params) const { | 
|  | 468 | return mClient->querySupportedParams(params); | 
|  | 469 | } | 
|  | 470 |  | 
|  | 471 | virtual c2_status_t querySupportedValues_sm( | 
|  | 472 | std::vector<C2FieldSupportedValuesQuery> &fields) const { | 
|  | 473 | return mClient->querySupportedValues(fields, C2_MAY_BLOCK); | 
|  | 474 | } | 
|  | 475 |  | 
|  | 476 | virtual C2String getName() const { | 
|  | 477 | return mClient->getName(); | 
|  | 478 | } | 
|  | 479 |  | 
|  | 480 | virtual std::shared_ptr<C2ParamReflector> getParamReflector() const { | 
|  | 481 | return mClient->getParamReflector(); | 
|  | 482 | } | 
|  | 483 |  | 
|  | 484 | virtual std::vector<std::shared_ptr<const C2Component::Traits>> listComponents() { | 
|  | 485 | return std::vector<std::shared_ptr<const C2Component::Traits>>(); | 
|  | 486 | } | 
|  | 487 | }; | 
|  | 488 |  | 
| Wonsik Kim | 970bf0b | 2020-11-10 11:54:15 -0800 | [diff] [blame] | 489 | void RevertOutputFormatIfNeeded( | 
|  | 490 | const sp<AMessage> &oldFormat, sp<AMessage> ¤tFormat) { | 
|  | 491 | // We used to not report changes to these keys to the client. | 
|  | 492 | const static std::set<std::string> sIgnoredKeys({ | 
|  | 493 | KEY_BIT_RATE, | 
| Harish Mahendrakar | 8c53750 | 2021-02-23 21:20:22 -0800 | [diff] [blame] | 494 | KEY_FRAME_RATE, | 
| Wonsik Kim | 970bf0b | 2020-11-10 11:54:15 -0800 | [diff] [blame] | 495 | KEY_MAX_BIT_RATE, | 
| Harish Mahendrakar | 8c53750 | 2021-02-23 21:20:22 -0800 | [diff] [blame] | 496 | KEY_MAX_WIDTH, | 
|  | 497 | KEY_MAX_HEIGHT, | 
| Wonsik Kim | 970bf0b | 2020-11-10 11:54:15 -0800 | [diff] [blame] | 498 | "csd-0", | 
|  | 499 | "csd-1", | 
|  | 500 | "csd-2", | 
|  | 501 | }); | 
|  | 502 | if (currentFormat == oldFormat) { | 
|  | 503 | return; | 
|  | 504 | } | 
|  | 505 | sp<AMessage> diff = currentFormat->changesFrom(oldFormat); | 
|  | 506 | AMessage::Type type; | 
|  | 507 | for (size_t i = diff->countEntries(); i > 0; --i) { | 
|  | 508 | if (sIgnoredKeys.count(diff->getEntryNameAt(i - 1, &type)) > 0) { | 
|  | 509 | diff->removeEntryAt(i - 1); | 
|  | 510 | } | 
|  | 511 | } | 
|  | 512 | if (diff->countEntries() == 0) { | 
|  | 513 | currentFormat = oldFormat; | 
|  | 514 | } | 
|  | 515 | } | 
|  | 516 |  | 
| Wonsik Kim | 1f5063d | 2021-05-03 15:41:17 -0700 | [diff] [blame] | 517 | void AmendOutputFormatWithCodecSpecificData( | 
| Greg Kaiser | f2572aa | 2021-05-10 12:50:27 -0700 | [diff] [blame] | 518 | const uint8_t *data, size_t size, const std::string &mediaType, | 
| Wonsik Kim | 1f5063d | 2021-05-03 15:41:17 -0700 | [diff] [blame] | 519 | const sp<AMessage> &outputFormat) { | 
|  | 520 | if (mediaType == MIMETYPE_VIDEO_AVC) { | 
|  | 521 | // Codec specific data should be SPS and PPS in a single buffer, | 
|  | 522 | // each prefixed by a startcode (0x00 0x00 0x00 0x01). | 
|  | 523 | // We separate the two and put them into the output format | 
|  | 524 | // under the keys "csd-0" and "csd-1". | 
|  | 525 |  | 
|  | 526 | unsigned csdIndex = 0; | 
|  | 527 |  | 
|  | 528 | const uint8_t *nalStart; | 
|  | 529 | size_t nalSize; | 
|  | 530 | while (getNextNALUnit(&data, &size, &nalStart, &nalSize, true) == OK) { | 
|  | 531 | sp<ABuffer> csd = new ABuffer(nalSize + 4); | 
|  | 532 | memcpy(csd->data(), "\x00\x00\x00\x01", 4); | 
|  | 533 | memcpy(csd->data() + 4, nalStart, nalSize); | 
|  | 534 |  | 
|  | 535 | outputFormat->setBuffer( | 
|  | 536 | AStringPrintf("csd-%u", csdIndex).c_str(), csd); | 
|  | 537 |  | 
|  | 538 | ++csdIndex; | 
|  | 539 | } | 
|  | 540 |  | 
|  | 541 | if (csdIndex != 2) { | 
|  | 542 | ALOGW("Expected two NAL units from AVC codec config, but %u found", | 
|  | 543 | csdIndex); | 
|  | 544 | } | 
|  | 545 | } else { | 
|  | 546 | // For everything else we just stash the codec specific data into | 
|  | 547 | // the output format as a single piece of csd under "csd-0". | 
|  | 548 | sp<ABuffer> csd = new ABuffer(size); | 
|  | 549 | memcpy(csd->data(), data, size); | 
|  | 550 | csd->setRange(0, size); | 
|  | 551 | outputFormat->setBuffer("csd-0", csd); | 
|  | 552 | } | 
|  | 553 | } | 
|  | 554 |  | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 555 | }  // namespace | 
|  | 556 |  | 
|  | 557 | // CCodec::ClientListener | 
|  | 558 |  | 
|  | 559 | struct CCodec::ClientListener : public Codec2Client::Listener { | 
|  | 560 |  | 
|  | 561 | explicit ClientListener(const wp<CCodec> &codec) : mCodec(codec) {} | 
|  | 562 |  | 
|  | 563 | virtual void onWorkDone( | 
|  | 564 | const std::weak_ptr<Codec2Client::Component>& component, | 
| Wonsik Kim | ab34ed6 | 2019-01-31 15:28:46 -0800 | [diff] [blame] | 565 | std::list<std::unique_ptr<C2Work>>& workItems) override { | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 566 | (void)component; | 
|  | 567 | sp<CCodec> codec(mCodec.promote()); | 
|  | 568 | if (!codec) { | 
|  | 569 | return; | 
|  | 570 | } | 
| Wonsik Kim | ab34ed6 | 2019-01-31 15:28:46 -0800 | [diff] [blame] | 571 | codec->onWorkDone(workItems); | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 572 | } | 
|  | 573 |  | 
|  | 574 | virtual void onTripped( | 
|  | 575 | const std::weak_ptr<Codec2Client::Component>& component, | 
|  | 576 | const std::vector<std::shared_ptr<C2SettingResult>>& settingResult | 
|  | 577 | ) override { | 
|  | 578 | // TODO | 
|  | 579 | (void)component; | 
|  | 580 | (void)settingResult; | 
|  | 581 | } | 
|  | 582 |  | 
|  | 583 | virtual void onError( | 
|  | 584 | const std::weak_ptr<Codec2Client::Component>& component, | 
|  | 585 | uint32_t errorCode) override { | 
| Praveen Chavan | 72eff01 | 2020-11-20 23:20:28 -0800 | [diff] [blame] | 586 | { | 
|  | 587 | // Component is only used for reporting as we use a separate listener for each instance | 
|  | 588 | std::shared_ptr<Codec2Client::Component> comp = component.lock(); | 
|  | 589 | if (!comp) { | 
|  | 590 | ALOGD("Component died with error: 0x%x", errorCode); | 
|  | 591 | } else { | 
|  | 592 | ALOGD("Component \"%s\" returned error: 0x%x", comp->getName().c_str(), errorCode); | 
|  | 593 | } | 
|  | 594 | } | 
|  | 595 |  | 
|  | 596 | // Report to MediaCodec | 
| Wonsik Kim | 10f33c0 | 2021-03-04 15:04:14 -0800 | [diff] [blame] | 597 | // Note: for now we do not propagate the error code to MediaCodec | 
|  | 598 | // except for C2_NO_MEMORY, as we would need to translate to a MediaCodec error. | 
| Praveen Chavan | 72eff01 | 2020-11-20 23:20:28 -0800 | [diff] [blame] | 599 | sp<CCodec> codec(mCodec.promote()); | 
|  | 600 | if (!codec || !codec->mCallback) { | 
|  | 601 | return; | 
|  | 602 | } | 
| Wonsik Kim | 10f33c0 | 2021-03-04 15:04:14 -0800 | [diff] [blame] | 603 | codec->mCallback->onError( | 
|  | 604 | errorCode == C2_NO_MEMORY ? NO_MEMORY : UNKNOWN_ERROR, | 
|  | 605 | ACTION_CODE_FATAL); | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 606 | } | 
|  | 607 |  | 
|  | 608 | virtual void onDeath( | 
|  | 609 | const std::weak_ptr<Codec2Client::Component>& component) override { | 
|  | 610 | { // Log the death of the component. | 
|  | 611 | std::shared_ptr<Codec2Client::Component> comp = component.lock(); | 
|  | 612 | if (!comp) { | 
|  | 613 | ALOGE("Codec2 component died."); | 
|  | 614 | } else { | 
|  | 615 | ALOGE("Codec2 component \"%s\" died.", comp->getName().c_str()); | 
|  | 616 | } | 
|  | 617 | } | 
|  | 618 |  | 
|  | 619 | // Report to MediaCodec. | 
|  | 620 | sp<CCodec> codec(mCodec.promote()); | 
|  | 621 | if (!codec || !codec->mCallback) { | 
|  | 622 | return; | 
|  | 623 | } | 
|  | 624 | codec->mCallback->onError(DEAD_OBJECT, ACTION_CODE_FATAL); | 
|  | 625 | } | 
|  | 626 |  | 
| Pawin Vongmasa | 1c75a23 | 2019-01-09 04:41:52 -0800 | [diff] [blame] | 627 | virtual void onFrameRendered(uint64_t bufferQueueId, | 
|  | 628 | int32_t slotId, | 
|  | 629 | int64_t timestampNs) override { | 
|  | 630 | // TODO: implement | 
|  | 631 | (void)bufferQueueId; | 
|  | 632 | (void)slotId; | 
|  | 633 | (void)timestampNs; | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 634 | } | 
|  | 635 |  | 
|  | 636 | virtual void onInputBufferDone( | 
| Wonsik Kim | ab34ed6 | 2019-01-31 15:28:46 -0800 | [diff] [blame] | 637 | uint64_t frameIndex, size_t arrayIndex) override { | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 638 | sp<CCodec> codec(mCodec.promote()); | 
|  | 639 | if (codec) { | 
| Wonsik Kim | ab34ed6 | 2019-01-31 15:28:46 -0800 | [diff] [blame] | 640 | codec->onInputBufferDone(frameIndex, arrayIndex); | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 641 | } | 
|  | 642 | } | 
|  | 643 |  | 
|  | 644 | private: | 
|  | 645 | wp<CCodec> mCodec; | 
|  | 646 | }; | 
|  | 647 |  | 
|  | 648 | // CCodecCallbackImpl | 
|  | 649 |  | 
|  | 650 | class CCodecCallbackImpl : public CCodecCallback { | 
|  | 651 | public: | 
|  | 652 | explicit CCodecCallbackImpl(CCodec *codec) : mCodec(codec) {} | 
|  | 653 | ~CCodecCallbackImpl() override = default; | 
|  | 654 |  | 
|  | 655 | void onError(status_t err, enum ActionCode actionCode) override { | 
|  | 656 | mCodec->mCallback->onError(err, actionCode); | 
|  | 657 | } | 
|  | 658 |  | 
|  | 659 | void onOutputFramesRendered(int64_t mediaTimeUs, nsecs_t renderTimeNs) override { | 
|  | 660 | mCodec->mCallback->onOutputFramesRendered( | 
|  | 661 | {RenderedFrameInfo(mediaTimeUs, renderTimeNs)}); | 
|  | 662 | } | 
|  | 663 |  | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 664 | void onOutputBuffersChanged() override { | 
|  | 665 | mCodec->mCallback->onOutputBuffersChanged(); | 
|  | 666 | } | 
|  | 667 |  | 
| Guillaume Chelfi | 867d4dd | 2021-07-01 18:38:45 +0200 | [diff] [blame] | 668 | void onFirstTunnelFrameReady() override { | 
|  | 669 | mCodec->mCallback->onFirstTunnelFrameReady(); | 
|  | 670 | } | 
|  | 671 |  | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 672 | private: | 
|  | 673 | CCodec *mCodec; | 
|  | 674 | }; | 
|  | 675 |  | 
|  | 676 | // CCodec | 
|  | 677 |  | 
|  | 678 | CCodec::CCodec() | 
| Wonsik Kim | 155d5cb | 2019-10-09 12:49:49 -0700 | [diff] [blame] | 679 | : mChannel(new CCodecBufferChannel(std::make_shared<CCodecCallbackImpl>(this))), | 
|  | 680 | mConfig(new CCodecConfig) { | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 681 | } | 
|  | 682 |  | 
|  | 683 | CCodec::~CCodec() { | 
|  | 684 | } | 
|  | 685 |  | 
|  | 686 | std::shared_ptr<BufferChannelBase> CCodec::getBufferChannel() { | 
|  | 687 | return mChannel; | 
|  | 688 | } | 
|  | 689 |  | 
|  | 690 | status_t CCodec::tryAndReportOnError(std::function<status_t()> job) { | 
|  | 691 | status_t err = job(); | 
|  | 692 | if (err != C2_OK) { | 
|  | 693 | mCallback->onError(err, ACTION_CODE_FATAL); | 
|  | 694 | } | 
|  | 695 | return err; | 
|  | 696 | } | 
|  | 697 |  | 
|  | 698 | void CCodec::initiateAllocateComponent(const sp<AMessage> &msg) { | 
|  | 699 | auto setAllocating = [this] { | 
|  | 700 | Mutexed<State>::Locked state(mState); | 
|  | 701 | if (state->get() != RELEASED) { | 
|  | 702 | return INVALID_OPERATION; | 
|  | 703 | } | 
|  | 704 | state->set(ALLOCATING); | 
|  | 705 | return OK; | 
|  | 706 | }; | 
|  | 707 | if (tryAndReportOnError(setAllocating) != OK) { | 
|  | 708 | return; | 
|  | 709 | } | 
|  | 710 |  | 
|  | 711 | sp<RefBase> codecInfo; | 
|  | 712 | CHECK(msg->findObject("codecInfo", &codecInfo)); | 
|  | 713 | // For Codec 2.0 components, componentName == codecInfo->getCodecName(). | 
|  | 714 |  | 
|  | 715 | sp<AMessage> allocMsg(new AMessage(kWhatAllocate, this)); | 
|  | 716 | allocMsg->setObject("codecInfo", codecInfo); | 
|  | 717 | allocMsg->post(); | 
|  | 718 | } | 
|  | 719 |  | 
|  | 720 | void CCodec::allocate(const sp<MediaCodecInfo> &codecInfo) { | 
|  | 721 | if (codecInfo == nullptr) { | 
|  | 722 | mCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL); | 
|  | 723 | return; | 
|  | 724 | } | 
|  | 725 | ALOGD("allocate(%s)", codecInfo->getCodecName()); | 
|  | 726 | mClientListener.reset(new ClientListener(this)); | 
|  | 727 |  | 
|  | 728 | AString componentName = codecInfo->getCodecName(); | 
|  | 729 | std::shared_ptr<Codec2Client> client; | 
|  | 730 |  | 
|  | 731 | // set up preferred component store to access vendor store parameters | 
| Pawin Vongmasa | 892c81d | 2019-03-12 00:56:50 -0700 | [diff] [blame] | 732 | client = Codec2Client::CreateFromService("default"); | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 733 | if (client) { | 
| Pawin Vongmasa | 1c75a23 | 2019-01-09 04:41:52 -0800 | [diff] [blame] | 734 | ALOGI("setting up '%s' as default (vendor) store", client->getServiceName().c_str()); | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 735 | SetPreferredCodec2ComponentStore( | 
|  | 736 | std::make_shared<Codec2ClientInterfaceWrapper>(client)); | 
|  | 737 | } | 
|  | 738 |  | 
|  | 739 | std::shared_ptr<Codec2Client::Component> comp = | 
|  | 740 | Codec2Client::CreateComponentByName( | 
|  | 741 | componentName.c_str(), | 
|  | 742 | mClientListener, | 
|  | 743 | &client); | 
|  | 744 | if (!comp) { | 
|  | 745 | ALOGE("Failed Create component: %s", componentName.c_str()); | 
|  | 746 | Mutexed<State>::Locked state(mState); | 
|  | 747 | state->set(RELEASED); | 
|  | 748 | state.unlock(); | 
|  | 749 | mCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL); | 
|  | 750 | state.lock(); | 
|  | 751 | return; | 
|  | 752 | } | 
|  | 753 | ALOGI("Created component [%s]", componentName.c_str()); | 
|  | 754 | mChannel->setComponent(comp); | 
|  | 755 | auto setAllocated = [this, comp, client] { | 
|  | 756 | Mutexed<State>::Locked state(mState); | 
|  | 757 | if (state->get() != ALLOCATING) { | 
|  | 758 | state->set(RELEASED); | 
|  | 759 | return UNKNOWN_ERROR; | 
|  | 760 | } | 
|  | 761 | state->set(ALLOCATED); | 
|  | 762 | state->comp = comp; | 
|  | 763 | mClient = client; | 
|  | 764 | return OK; | 
|  | 765 | }; | 
|  | 766 | if (tryAndReportOnError(setAllocated) != OK) { | 
|  | 767 | return; | 
|  | 768 | } | 
|  | 769 |  | 
|  | 770 | // initialize config here in case setParameters is called prior to configure | 
| Wonsik Kim | 155d5cb | 2019-10-09 12:49:49 -0700 | [diff] [blame] | 771 | Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig); | 
|  | 772 | const std::unique_ptr<Config> &config = *configLocked; | 
| Wonsik Kim | 8a6ed37 | 2019-12-03 16:05:51 -0800 | [diff] [blame] | 773 | status_t err = config->initialize(mClient->getParamReflector(), comp); | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 774 | if (err != OK) { | 
|  | 775 | ALOGW("Failed to initialize configuration support"); | 
|  | 776 | // TODO: report error once we complete implementation. | 
|  | 777 | } | 
|  | 778 | config->queryConfiguration(comp); | 
|  | 779 |  | 
|  | 780 | mCallback->onComponentAllocated(componentName.c_str()); | 
|  | 781 | } | 
|  | 782 |  | 
|  | 783 | void CCodec::initiateConfigureComponent(const sp<AMessage> &format) { | 
|  | 784 | auto checkAllocated = [this] { | 
|  | 785 | Mutexed<State>::Locked state(mState); | 
|  | 786 | return (state->get() != ALLOCATED) ? UNKNOWN_ERROR : OK; | 
|  | 787 | }; | 
|  | 788 | if (tryAndReportOnError(checkAllocated) != OK) { | 
|  | 789 | return; | 
|  | 790 | } | 
|  | 791 |  | 
|  | 792 | sp<AMessage> msg(new AMessage(kWhatConfigure, this)); | 
|  | 793 | msg->setMessage("format", format); | 
|  | 794 | msg->post(); | 
|  | 795 | } | 
|  | 796 |  | 
|  | 797 | void CCodec::configure(const sp<AMessage> &msg) { | 
|  | 798 | std::shared_ptr<Codec2Client::Component> comp; | 
|  | 799 | auto checkAllocated = [this, &comp] { | 
|  | 800 | Mutexed<State>::Locked state(mState); | 
|  | 801 | if (state->get() != ALLOCATED) { | 
|  | 802 | state->set(RELEASED); | 
|  | 803 | return UNKNOWN_ERROR; | 
|  | 804 | } | 
|  | 805 | comp = state->comp; | 
|  | 806 | return OK; | 
|  | 807 | }; | 
|  | 808 | if (tryAndReportOnError(checkAllocated) != OK) { | 
|  | 809 | return; | 
|  | 810 | } | 
|  | 811 |  | 
|  | 812 | auto doConfig = [msg, comp, this]() -> status_t { | 
|  | 813 | AString mime; | 
|  | 814 | if (!msg->findString("mime", &mime)) { | 
|  | 815 | return BAD_VALUE; | 
|  | 816 | } | 
|  | 817 |  | 
|  | 818 | int32_t encoder; | 
|  | 819 | if (!msg->findInt32("encoder", &encoder)) { | 
|  | 820 | encoder = false; | 
|  | 821 | } | 
|  | 822 |  | 
| Wonsik Kim | fb7a767 | 2019-12-27 17:13:33 -0800 | [diff] [blame] | 823 | int32_t flags; | 
|  | 824 | if (!msg->findInt32("flags", &flags)) { | 
|  | 825 | return BAD_VALUE; | 
|  | 826 | } | 
|  | 827 |  | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 828 | // TODO: read from intf() | 
|  | 829 | if ((!encoder) != (comp->getName().find("encoder") == std::string::npos)) { | 
|  | 830 | return UNKNOWN_ERROR; | 
|  | 831 | } | 
|  | 832 |  | 
|  | 833 | int32_t storeMeta; | 
|  | 834 | if (encoder | 
|  | 835 | && msg->findInt32("android._input-metadata-buffer-type", &storeMeta) | 
|  | 836 | && storeMeta != kMetadataBufferTypeInvalid) { | 
|  | 837 | if (storeMeta != kMetadataBufferTypeANWBuffer) { | 
|  | 838 | ALOGD("Only ANW buffers are supported for legacy metadata mode"); | 
|  | 839 | return BAD_VALUE; | 
|  | 840 | } | 
|  | 841 | mChannel->setMetaMode(CCodecBufferChannel::MODE_ANW); | 
|  | 842 | } | 
|  | 843 |  | 
| ted.sun | 765db4d | 2020-06-23 14:03:41 +0800 | [diff] [blame] | 844 | status_t err = OK; | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 845 | sp<RefBase> obj; | 
|  | 846 | sp<Surface> surface; | 
|  | 847 | if (msg->findObject("native-window", &obj)) { | 
|  | 848 | surface = static_cast<Surface *>(obj.get()); | 
| ted.sun | 765db4d | 2020-06-23 14:03:41 +0800 | [diff] [blame] | 849 | // setup tunneled playback | 
|  | 850 | if (surface != nullptr) { | 
|  | 851 | Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig); | 
|  | 852 | const std::unique_ptr<Config> &config = *configLocked; | 
|  | 853 | if ((config->mDomain & Config::IS_DECODER) | 
|  | 854 | && (config->mDomain & Config::IS_VIDEO)) { | 
|  | 855 | int32_t tunneled; | 
|  | 856 | if (msg->findInt32("feature-tunneled-playback", &tunneled) && tunneled != 0) { | 
|  | 857 | ALOGI("Configuring TUNNELED video playback."); | 
|  | 858 |  | 
|  | 859 | err = configureTunneledVideoPlayback(comp, &config->mSidebandHandle, msg); | 
|  | 860 | if (err != OK) { | 
|  | 861 | ALOGE("configureTunneledVideoPlayback failed!"); | 
|  | 862 | return err; | 
|  | 863 | } | 
|  | 864 | config->mTunneled = true; | 
|  | 865 | } | 
|  | 866 | } | 
|  | 867 | } | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 868 | setSurface(surface); | 
|  | 869 | } | 
|  | 870 |  | 
| Wonsik Kim | 155d5cb | 2019-10-09 12:49:49 -0700 | [diff] [blame] | 871 | Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig); | 
|  | 872 | const std::unique_ptr<Config> &config = *configLocked; | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 873 | config->mUsingSurface = surface != nullptr; | 
| Wonsik Kim | fb7a767 | 2019-12-27 17:13:33 -0800 | [diff] [blame] | 874 | config->mBuffersBoundToCodec = ((flags & CONFIGURE_FLAG_USE_BLOCK_MODEL) == 0); | 
|  | 875 | ALOGD("[%s] buffers are %sbound to CCodec for this session", | 
|  | 876 | comp->getName().c_str(), config->mBuffersBoundToCodec ? "" : "not "); | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 877 |  | 
| Wonsik Kim | 1114eea | 2019-02-25 14:35:24 -0800 | [diff] [blame] | 878 | // Enforce required parameters | 
|  | 879 | int32_t i32; | 
|  | 880 | float flt; | 
|  | 881 | if (config->mDomain & Config::IS_AUDIO) { | 
|  | 882 | if (!msg->findInt32(KEY_SAMPLE_RATE, &i32)) { | 
|  | 883 | ALOGD("sample rate is missing, which is required for audio components."); | 
|  | 884 | return BAD_VALUE; | 
|  | 885 | } | 
|  | 886 | if (!msg->findInt32(KEY_CHANNEL_COUNT, &i32)) { | 
|  | 887 | ALOGD("channel count is missing, which is required for audio components."); | 
|  | 888 | return BAD_VALUE; | 
|  | 889 | } | 
|  | 890 | if ((config->mDomain & Config::IS_ENCODER) | 
|  | 891 | && !mime.equalsIgnoreCase(MEDIA_MIMETYPE_AUDIO_FLAC) | 
|  | 892 | && !msg->findInt32(KEY_BIT_RATE, &i32) | 
|  | 893 | && !msg->findFloat(KEY_BIT_RATE, &flt)) { | 
|  | 894 | ALOGD("bitrate is missing, which is required for audio encoders."); | 
|  | 895 | return BAD_VALUE; | 
|  | 896 | } | 
|  | 897 | } | 
| Wonsik Kim | d91f3fb | 2021-02-24 12:35:31 -0800 | [diff] [blame] | 898 | int32_t width = 0; | 
|  | 899 | int32_t height = 0; | 
| Wonsik Kim | 1114eea | 2019-02-25 14:35:24 -0800 | [diff] [blame] | 900 | if (config->mDomain & (Config::IS_IMAGE | Config::IS_VIDEO)) { | 
| Wonsik Kim | d91f3fb | 2021-02-24 12:35:31 -0800 | [diff] [blame] | 901 | if (!msg->findInt32(KEY_WIDTH, &width)) { | 
| Wonsik Kim | 1114eea | 2019-02-25 14:35:24 -0800 | [diff] [blame] | 902 | ALOGD("width is missing, which is required for image/video components."); | 
|  | 903 | return BAD_VALUE; | 
|  | 904 | } | 
| Wonsik Kim | d91f3fb | 2021-02-24 12:35:31 -0800 | [diff] [blame] | 905 | if (!msg->findInt32(KEY_HEIGHT, &height)) { | 
| Wonsik Kim | 1114eea | 2019-02-25 14:35:24 -0800 | [diff] [blame] | 906 | ALOGD("height is missing, which is required for image/video components."); | 
|  | 907 | return BAD_VALUE; | 
|  | 908 | } | 
|  | 909 | if ((config->mDomain & Config::IS_ENCODER) && (config->mDomain & Config::IS_VIDEO)) { | 
| Harish Mahendrakar | 71cbb9d | 2019-05-21 11:21:27 -0700 | [diff] [blame] | 910 | int32_t mode = BITRATE_MODE_VBR; | 
|  | 911 | if (msg->findInt32(KEY_BITRATE_MODE, &mode) && mode == BITRATE_MODE_CQ) { | 
| Harish Mahendrakar | 817d318 | 2019-03-11 16:37:47 -0700 | [diff] [blame] | 912 | if (!msg->findInt32(KEY_QUALITY, &i32)) { | 
|  | 913 | ALOGD("quality is missing, which is required for video encoders in CQ."); | 
|  | 914 | return BAD_VALUE; | 
|  | 915 | } | 
|  | 916 | } else { | 
|  | 917 | if (!msg->findInt32(KEY_BIT_RATE, &i32) | 
|  | 918 | && !msg->findFloat(KEY_BIT_RATE, &flt)) { | 
|  | 919 | ALOGD("bitrate is missing, which is required for video encoders."); | 
|  | 920 | return BAD_VALUE; | 
|  | 921 | } | 
| Wonsik Kim | 1114eea | 2019-02-25 14:35:24 -0800 | [diff] [blame] | 922 | } | 
|  | 923 | if (!msg->findInt32(KEY_I_FRAME_INTERVAL, &i32) | 
|  | 924 | && !msg->findFloat(KEY_I_FRAME_INTERVAL, &flt)) { | 
|  | 925 | ALOGD("I frame interval is missing, which is required for video encoders."); | 
|  | 926 | return BAD_VALUE; | 
|  | 927 | } | 
| Wonsik Kim | aab2eea | 2019-05-22 10:37:58 -0700 | [diff] [blame] | 928 | if (!msg->findInt32(KEY_FRAME_RATE, &i32) | 
|  | 929 | && !msg->findFloat(KEY_FRAME_RATE, &flt)) { | 
|  | 930 | ALOGD("frame rate is missing, which is required for video encoders."); | 
|  | 931 | return BAD_VALUE; | 
|  | 932 | } | 
| Wonsik Kim | 1114eea | 2019-02-25 14:35:24 -0800 | [diff] [blame] | 933 | } | 
|  | 934 | } | 
|  | 935 |  | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 936 | /* | 
|  | 937 | * Handle input surface configuration | 
|  | 938 | */ | 
|  | 939 | if ((config->mDomain & (Config::IS_VIDEO | Config::IS_IMAGE)) | 
|  | 940 | && (config->mDomain & Config::IS_ENCODER)) { | 
|  | 941 | config->mISConfig.reset(new InputSurfaceWrapper::Config{}); | 
|  | 942 | { | 
|  | 943 | config->mISConfig->mMinFps = 0; | 
|  | 944 | int64_t value; | 
| Chong Zhang | 038e8f8 | 2019-02-06 19:05:14 -0800 | [diff] [blame] | 945 | if (msg->findInt64(KEY_REPEAT_PREVIOUS_FRAME_AFTER, &value) && value > 0) { | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 946 | config->mISConfig->mMinFps = 1e6 / value; | 
|  | 947 | } | 
| Wonsik Kim | 95ba016 | 2019-03-19 15:51:54 -0700 | [diff] [blame] | 948 | if (!msg->findFloat( | 
|  | 949 | KEY_MAX_FPS_TO_ENCODER, &config->mISConfig->mMaxFps)) { | 
|  | 950 | config->mISConfig->mMaxFps = -1; | 
|  | 951 | } | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 952 | config->mISConfig->mMinAdjustedFps = 0; | 
|  | 953 | config->mISConfig->mFixedAdjustedFps = 0; | 
| Chong Zhang | 038e8f8 | 2019-02-06 19:05:14 -0800 | [diff] [blame] | 954 | if (msg->findInt64(KEY_MAX_PTS_GAP_TO_ENCODER, &value)) { | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 955 | if (value < 0 && value >= INT32_MIN) { | 
|  | 956 | config->mISConfig->mFixedAdjustedFps = -1e6 / value; | 
| Wonsik Kim | 95ba016 | 2019-03-19 15:51:54 -0700 | [diff] [blame] | 957 | config->mISConfig->mMaxFps = -1; | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 958 | } else if (value > 0 && value <= INT32_MAX) { | 
|  | 959 | config->mISConfig->mMinAdjustedFps = 1e6 / value; | 
|  | 960 | } | 
|  | 961 | } | 
|  | 962 | } | 
|  | 963 |  | 
|  | 964 | { | 
| Wonsik Kim | 8e55f3a | 2019-09-03 14:10:37 -0700 | [diff] [blame] | 965 | bool captureFpsFound = false; | 
|  | 966 | double timeLapseFps; | 
|  | 967 | float captureRate; | 
|  | 968 | if (msg->findDouble("time-lapse-fps", &timeLapseFps)) { | 
|  | 969 | config->mISConfig->mCaptureFps = timeLapseFps; | 
|  | 970 | captureFpsFound = true; | 
|  | 971 | } else if (msg->findAsFloat(KEY_CAPTURE_RATE, &captureRate)) { | 
|  | 972 | config->mISConfig->mCaptureFps = captureRate; | 
|  | 973 | captureFpsFound = true; | 
|  | 974 | } | 
|  | 975 | if (captureFpsFound) { | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 976 | (void)msg->findAsFloat(KEY_FRAME_RATE, &config->mISConfig->mCodedFps); | 
|  | 977 | } | 
|  | 978 | } | 
|  | 979 |  | 
|  | 980 | { | 
|  | 981 | config->mISConfig->mSuspended = false; | 
|  | 982 | config->mISConfig->mSuspendAtUs = -1; | 
|  | 983 | int32_t value; | 
| Chong Zhang | 038e8f8 | 2019-02-06 19:05:14 -0800 | [diff] [blame] | 984 | if (msg->findInt32(KEY_CREATE_INPUT_SURFACE_SUSPENDED, &value) && value) { | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 985 | config->mISConfig->mSuspended = true; | 
|  | 986 | } | 
|  | 987 | } | 
| Wonsik Kim | 9eac4d1 | 2019-05-23 12:58:48 -0700 | [diff] [blame] | 988 | config->mISConfig->mUsage = 0; | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 989 | } | 
|  | 990 |  | 
|  | 991 | /* | 
|  | 992 | * Handle desired color format. | 
|  | 993 | */ | 
| Wonsik Kim | d79ee1f | 2020-08-27 17:41:56 -0700 | [diff] [blame] | 994 | int32_t defaultColorFormat = COLOR_FormatYUV420Flexible; | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 995 | if ((config->mDomain & (Config::IS_VIDEO | Config::IS_IMAGE))) { | 
| Wonsik Kim | d79ee1f | 2020-08-27 17:41:56 -0700 | [diff] [blame] | 996 | int32_t format = 0; | 
|  | 997 | // Query vendor format for Flexible YUV | 
|  | 998 | std::vector<std::unique_ptr<C2Param>> heapParams; | 
|  | 999 | C2StoreFlexiblePixelFormatDescriptorsInfo *pixelFormatInfo = nullptr; | 
|  | 1000 | if (mClient->query( | 
|  | 1001 | {}, | 
|  | 1002 | {C2StoreFlexiblePixelFormatDescriptorsInfo::PARAM_TYPE}, | 
|  | 1003 | C2_MAY_BLOCK, | 
|  | 1004 | &heapParams) == C2_OK | 
|  | 1005 | && heapParams.size() == 1u) { | 
|  | 1006 | pixelFormatInfo = C2StoreFlexiblePixelFormatDescriptorsInfo::From( | 
|  | 1007 | heapParams[0].get()); | 
|  | 1008 | } else { | 
|  | 1009 | pixelFormatInfo = nullptr; | 
|  | 1010 | } | 
|  | 1011 | std::optional<uint32_t> flexPixelFormat{}; | 
|  | 1012 | std::optional<uint32_t> flexPlanarPixelFormat{}; | 
|  | 1013 | std::optional<uint32_t> flexSemiPlanarPixelFormat{}; | 
|  | 1014 | if (pixelFormatInfo && *pixelFormatInfo) { | 
|  | 1015 | for (size_t i = 0; i < pixelFormatInfo->flexCount(); ++i) { | 
|  | 1016 | const C2FlexiblePixelFormatDescriptorStruct &desc = | 
|  | 1017 | pixelFormatInfo->m.values[i]; | 
|  | 1018 | if (desc.bitDepth != 8 | 
|  | 1019 | || desc.subsampling != C2Color::YUV_420 | 
|  | 1020 | // TODO(b/180076105): some device report wrong layout | 
|  | 1021 | // || desc.layout == C2Color::INTERLEAVED_PACKED | 
|  | 1022 | // || desc.layout == C2Color::INTERLEAVED_ALIGNED | 
|  | 1023 | || desc.layout == C2Color::UNKNOWN_LAYOUT) { | 
|  | 1024 | continue; | 
|  | 1025 | } | 
|  | 1026 | if (!flexPixelFormat) { | 
|  | 1027 | flexPixelFormat = desc.pixelFormat; | 
|  | 1028 | } | 
|  | 1029 | if (desc.layout == C2Color::PLANAR_PACKED && !flexPlanarPixelFormat) { | 
|  | 1030 | flexPlanarPixelFormat = desc.pixelFormat; | 
|  | 1031 | } | 
|  | 1032 | if (desc.layout == C2Color::SEMIPLANAR_PACKED && !flexSemiPlanarPixelFormat) { | 
|  | 1033 | flexSemiPlanarPixelFormat = desc.pixelFormat; | 
|  | 1034 | } | 
|  | 1035 | } | 
|  | 1036 | } | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1037 | if (!msg->findInt32(KEY_COLOR_FORMAT, &format)) { | 
| Wonsik Kim | d79ee1f | 2020-08-27 17:41:56 -0700 | [diff] [blame] | 1038 | // Also handle default color format (encoders require color format, so this is only | 
|  | 1039 | // needed for decoders. | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1040 | if (!(config->mDomain & Config::IS_ENCODER)) { | 
| Wonsik Kim | d79ee1f | 2020-08-27 17:41:56 -0700 | [diff] [blame] | 1041 | if (surface == nullptr) { | 
| Wonsik Kim | 1eb88a9 | 2021-03-29 20:44:04 -0700 | [diff] [blame] | 1042 | const char *prefix = ""; | 
|  | 1043 | if (flexSemiPlanarPixelFormat) { | 
|  | 1044 | format = COLOR_FormatYUV420SemiPlanar; | 
|  | 1045 | prefix = "semi-"; | 
|  | 1046 | } else { | 
|  | 1047 | format = COLOR_FormatYUV420Planar; | 
|  | 1048 | } | 
|  | 1049 | ALOGD("Client requested ByteBuffer mode decoder w/o color format set: " | 
|  | 1050 | "using default %splanar color format", prefix); | 
| Wonsik Kim | d79ee1f | 2020-08-27 17:41:56 -0700 | [diff] [blame] | 1051 | } else { | 
|  | 1052 | format = COLOR_FormatSurface; | 
|  | 1053 | } | 
|  | 1054 | defaultColorFormat = format; | 
|  | 1055 | } | 
|  | 1056 | } else { | 
|  | 1057 | if ((config->mDomain & Config::IS_ENCODER) || !surface) { | 
|  | 1058 | switch (format) { | 
|  | 1059 | case COLOR_FormatYUV420Flexible: | 
|  | 1060 | format = flexPixelFormat.value_or(COLOR_FormatYUV420Planar); | 
|  | 1061 | break; | 
|  | 1062 | case COLOR_FormatYUV420Planar: | 
|  | 1063 | case COLOR_FormatYUV420PackedPlanar: | 
|  | 1064 | format = flexPlanarPixelFormat.value_or( | 
|  | 1065 | flexPixelFormat.value_or(format)); | 
|  | 1066 | break; | 
|  | 1067 | case COLOR_FormatYUV420SemiPlanar: | 
|  | 1068 | case COLOR_FormatYUV420PackedSemiPlanar: | 
|  | 1069 | format = flexSemiPlanarPixelFormat.value_or( | 
|  | 1070 | flexPixelFormat.value_or(format)); | 
|  | 1071 | break; | 
|  | 1072 | default: | 
|  | 1073 | // No-op | 
|  | 1074 | break; | 
|  | 1075 | } | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1076 | } | 
|  | 1077 | } | 
|  | 1078 |  | 
| Wonsik Kim | d79ee1f | 2020-08-27 17:41:56 -0700 | [diff] [blame] | 1079 | if (format != 0) { | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1080 | msg->setInt32("android._color-format", format); | 
|  | 1081 | } | 
|  | 1082 | } | 
|  | 1083 |  | 
| Wonsik Kim | 77e97c7 | 2021-01-20 10:33:22 -0800 | [diff] [blame] | 1084 | /* | 
|  | 1085 | * Handle dataspace | 
|  | 1086 | */ | 
|  | 1087 | int32_t usingRecorder; | 
|  | 1088 | if (msg->findInt32("android._using-recorder", &usingRecorder) && usingRecorder) { | 
|  | 1089 | android_dataspace dataSpace = HAL_DATASPACE_BT709; | 
|  | 1090 | int32_t width, height; | 
|  | 1091 | if (msg->findInt32("width", &width) | 
|  | 1092 | && msg->findInt32("height", &height)) { | 
| Wonsik Kim | 4f13d11 | 2021-03-17 04:37:46 +0000 | [diff] [blame] | 1093 | ColorAspects aspects; | 
|  | 1094 | getColorAspectsFromFormat(msg, aspects); | 
|  | 1095 | setDefaultCodecColorAspectsIfNeeded(aspects, width, height); | 
| Wonsik Kim | 77e97c7 | 2021-01-20 10:33:22 -0800 | [diff] [blame] | 1096 | // TODO: read dataspace / color aspect from the component | 
| Wonsik Kim | 4f13d11 | 2021-03-17 04:37:46 +0000 | [diff] [blame] | 1097 | setColorAspectsIntoFormat(aspects, const_cast<sp<AMessage> &>(msg)); | 
|  | 1098 | dataSpace = getDataSpaceForColorAspects(aspects, true /* mayexpand */); | 
| Wonsik Kim | 77e97c7 | 2021-01-20 10:33:22 -0800 | [diff] [blame] | 1099 | } | 
|  | 1100 | msg->setInt32("android._dataspace", (int32_t)dataSpace); | 
|  | 1101 | ALOGD("setting dataspace to %x", dataSpace); | 
|  | 1102 | } | 
|  | 1103 |  | 
| Wonsik Kim | 8a6ed37 | 2019-12-03 16:05:51 -0800 | [diff] [blame] | 1104 | int32_t subscribeToAllVendorParams; | 
|  | 1105 | if (msg->findInt32("x-*", &subscribeToAllVendorParams) && subscribeToAllVendorParams) { | 
|  | 1106 | if (config->subscribeToAllVendorParams(comp, C2_MAY_BLOCK) != OK) { | 
|  | 1107 | ALOGD("[%s] Failed to subscribe to all vendor params", comp->getName().c_str()); | 
|  | 1108 | } | 
|  | 1109 | } | 
|  | 1110 |  | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1111 | std::vector<std::unique_ptr<C2Param>> configUpdate; | 
| Wonsik Kim | aa484ac | 2019-02-13 16:54:02 -0800 | [diff] [blame] | 1112 | // NOTE: We used to ignore "video-bitrate" at configure; replicate | 
|  | 1113 | //       the behavior here. | 
|  | 1114 | sp<AMessage> sdkParams = msg; | 
|  | 1115 | int32_t videoBitrate; | 
|  | 1116 | if (sdkParams->findInt32(PARAMETER_KEY_VIDEO_BITRATE, &videoBitrate)) { | 
|  | 1117 | sdkParams = msg->dup(); | 
|  | 1118 | sdkParams->removeEntryAt(sdkParams->findEntryByName(PARAMETER_KEY_VIDEO_BITRATE)); | 
|  | 1119 | } | 
| ted.sun | 765db4d | 2020-06-23 14:03:41 +0800 | [diff] [blame] | 1120 | err = config->getConfigUpdateFromSdkParams( | 
| Wonsik Kim | aa484ac | 2019-02-13 16:54:02 -0800 | [diff] [blame] | 1121 | comp, sdkParams, Config::IS_CONFIG, C2_DONT_BLOCK, &configUpdate); | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1122 | if (err != OK) { | 
|  | 1123 | ALOGW("failed to convert configuration to c2 params"); | 
|  | 1124 | } | 
| Wonsik Kim | aab2eea | 2019-05-22 10:37:58 -0700 | [diff] [blame] | 1125 |  | 
|  | 1126 | int32_t maxBframes = 0; | 
|  | 1127 | if ((config->mDomain & Config::IS_ENCODER) | 
|  | 1128 | && (config->mDomain & Config::IS_VIDEO) | 
|  | 1129 | && sdkParams->findInt32(KEY_MAX_B_FRAMES, &maxBframes) | 
|  | 1130 | && maxBframes > 0) { | 
|  | 1131 | std::unique_ptr<C2StreamGopTuning::output> gop = | 
|  | 1132 | C2StreamGopTuning::output::AllocUnique(2 /* flexCount */, 0u /* stream */); | 
|  | 1133 | gop->m.values[0] = { P_FRAME, UINT32_MAX }; | 
|  | 1134 | gop->m.values[1] = { | 
|  | 1135 | C2Config::picture_type_t(P_FRAME | B_FRAME), | 
|  | 1136 | uint32_t(maxBframes) | 
|  | 1137 | }; | 
|  | 1138 | configUpdate.push_back(std::move(gop)); | 
|  | 1139 | } | 
|  | 1140 |  | 
| Ray Essick | a9a724a | 2021-03-10 19:40:01 -0800 | [diff] [blame] | 1141 | if ((config->mDomain & Config::IS_ENCODER) | 
|  | 1142 | && (config->mDomain & Config::IS_VIDEO)) { | 
|  | 1143 | // we may not use all 3 of these entries | 
|  | 1144 | std::unique_ptr<C2StreamPictureQuantizationTuning::output> qp = | 
|  | 1145 | C2StreamPictureQuantizationTuning::output::AllocUnique(3 /* flexCount */, | 
|  | 1146 | 0u /* stream */); | 
|  | 1147 |  | 
|  | 1148 | int ix = 0; | 
|  | 1149 |  | 
|  | 1150 | int32_t iMax = INT32_MAX; | 
|  | 1151 | int32_t iMin = INT32_MIN; | 
|  | 1152 | (void) sdkParams->findInt32(KEY_VIDEO_QP_I_MAX, &iMax); | 
|  | 1153 | (void) sdkParams->findInt32(KEY_VIDEO_QP_I_MIN, &iMin); | 
|  | 1154 | if (iMax != INT32_MAX || iMin != INT32_MIN) { | 
|  | 1155 | qp->m.values[ix++] = {I_FRAME, iMin, iMax}; | 
|  | 1156 | } | 
|  | 1157 |  | 
|  | 1158 | int32_t pMax = INT32_MAX; | 
|  | 1159 | int32_t pMin = INT32_MIN; | 
|  | 1160 | (void) sdkParams->findInt32(KEY_VIDEO_QP_P_MAX, &pMax); | 
|  | 1161 | (void) sdkParams->findInt32(KEY_VIDEO_QP_P_MIN, &pMin); | 
|  | 1162 | if (pMax != INT32_MAX || pMin != INT32_MIN) { | 
|  | 1163 | qp->m.values[ix++] = {P_FRAME, pMin, pMax}; | 
|  | 1164 | } | 
|  | 1165 |  | 
|  | 1166 | int32_t bMax = INT32_MAX; | 
|  | 1167 | int32_t bMin = INT32_MIN; | 
|  | 1168 | (void) sdkParams->findInt32(KEY_VIDEO_QP_B_MAX, &bMax); | 
|  | 1169 | (void) sdkParams->findInt32(KEY_VIDEO_QP_B_MIN, &bMin); | 
|  | 1170 | if (bMax != INT32_MAX || bMin != INT32_MIN) { | 
|  | 1171 | qp->m.values[ix++] = {B_FRAME, bMin, bMax}; | 
|  | 1172 | } | 
|  | 1173 |  | 
|  | 1174 | // adjust to reflect actual use. | 
|  | 1175 | qp->setFlexCount(ix); | 
|  | 1176 |  | 
|  | 1177 | configUpdate.push_back(std::move(qp)); | 
|  | 1178 | } | 
|  | 1179 |  | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1180 | err = config->setParameters(comp, configUpdate, C2_DONT_BLOCK); | 
|  | 1181 | if (err != OK) { | 
|  | 1182 | ALOGW("failed to configure c2 params"); | 
|  | 1183 | return err; | 
|  | 1184 | } | 
|  | 1185 |  | 
|  | 1186 | std::vector<std::unique_ptr<C2Param>> params; | 
|  | 1187 | C2StreamUsageTuning::input usage(0u, 0u); | 
|  | 1188 | C2StreamMaxBufferSizeInfo::input maxInputSize(0u, 0u); | 
| Wonsik Kim | 9ca01d3 | 2019-04-01 14:45:47 -0700 | [diff] [blame] | 1189 | C2PrependHeaderModeSetting prepend(PREPEND_HEADER_TO_NONE); | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1190 |  | 
| Wonsik Kim | 58d8333 | 2021-02-07 22:19:56 -0800 | [diff] [blame] | 1191 | C2Param::Index colorAspectsRequestIndex = | 
|  | 1192 | C2StreamColorAspectsInfo::output::PARAM_TYPE | C2Param::CoreIndex::IS_REQUEST_FLAG; | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1193 | std::initializer_list<C2Param::Index> indices { | 
| Wonsik Kim | 58d8333 | 2021-02-07 22:19:56 -0800 | [diff] [blame] | 1194 | colorAspectsRequestIndex.withStream(0u), | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1195 | }; | 
|  | 1196 | c2_status_t c2err = comp->query( | 
| Wonsik Kim | 9ca01d3 | 2019-04-01 14:45:47 -0700 | [diff] [blame] | 1197 | { &usage, &maxInputSize, &prepend }, | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1198 | indices, | 
|  | 1199 | C2_DONT_BLOCK, | 
|  | 1200 | ¶ms); | 
|  | 1201 | if (c2err != C2_OK && c2err != C2_BAD_INDEX) { | 
|  | 1202 | ALOGE("Failed to query component interface: %d", c2err); | 
|  | 1203 | return UNKNOWN_ERROR; | 
|  | 1204 | } | 
| Wonsik Kim | 9eac4d1 | 2019-05-23 12:58:48 -0700 | [diff] [blame] | 1205 | if (usage) { | 
|  | 1206 | if (usage.value & C2MemoryUsage::CPU_READ) { | 
|  | 1207 | config->mInputFormat->setInt32("using-sw-read-often", true); | 
|  | 1208 | } | 
|  | 1209 | if (config->mISConfig) { | 
|  | 1210 | C2AndroidMemoryUsage androidUsage(C2MemoryUsage(usage.value)); | 
|  | 1211 | config->mISConfig->mUsage = androidUsage.asGrallocUsage(); | 
|  | 1212 | } | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1213 | } | 
|  | 1214 |  | 
|  | 1215 | // NOTE: we don't blindly use client specified input size if specified as clients | 
|  | 1216 | // at times specify too small size. Instead, mimic the behavior from OMX, where the | 
|  | 1217 | // client specified size is only used to ask for bigger buffers than component suggested | 
|  | 1218 | // size. | 
|  | 1219 | int32_t clientInputSize = 0; | 
|  | 1220 | bool clientSpecifiedInputSize = | 
|  | 1221 | msg->findInt32(KEY_MAX_INPUT_SIZE, &clientInputSize) && clientInputSize > 0; | 
|  | 1222 | // TEMP: enforce minimum buffer size of 1MB for video decoders | 
|  | 1223 | // and 16K / 4K for audio encoders/decoders | 
|  | 1224 | if (maxInputSize.value == 0) { | 
|  | 1225 | if (config->mDomain & Config::IS_AUDIO) { | 
|  | 1226 | maxInputSize.value = encoder ? 16384 : 4096; | 
|  | 1227 | } else if (!encoder) { | 
|  | 1228 | maxInputSize.value = 1048576u; | 
|  | 1229 | } | 
|  | 1230 | } | 
|  | 1231 |  | 
|  | 1232 | // verify that CSD fits into this size (if defined) | 
|  | 1233 | if ((config->mDomain & Config::IS_DECODER) && maxInputSize.value > 0) { | 
|  | 1234 | sp<ABuffer> csd; | 
|  | 1235 | for (size_t ix = 0; msg->findBuffer(StringPrintf("csd-%zu", ix).c_str(), &csd); ++ix) { | 
|  | 1236 | if (csd && csd->size() > maxInputSize.value) { | 
|  | 1237 | maxInputSize.value = csd->size(); | 
|  | 1238 | } | 
|  | 1239 | } | 
|  | 1240 | } | 
|  | 1241 |  | 
|  | 1242 | // TODO: do this based on component requiring linear allocator for input | 
|  | 1243 | if ((config->mDomain & Config::IS_DECODER) || (config->mDomain & Config::IS_AUDIO)) { | 
|  | 1244 | if (clientSpecifiedInputSize) { | 
|  | 1245 | // Warn that we're overriding client's max input size if necessary. | 
|  | 1246 | if ((uint32_t)clientInputSize < maxInputSize.value) { | 
|  | 1247 | ALOGD("client requested max input size %d, which is smaller than " | 
|  | 1248 | "what component recommended (%u); overriding with component " | 
|  | 1249 | "recommendation.", clientInputSize, maxInputSize.value); | 
|  | 1250 | ALOGW("This behavior is subject to change. It is recommended that " | 
|  | 1251 | "app developers double check whether the requested " | 
|  | 1252 | "max input size is in reasonable range."); | 
|  | 1253 | } else { | 
|  | 1254 | maxInputSize.value = clientInputSize; | 
|  | 1255 | } | 
|  | 1256 | } | 
|  | 1257 | // Pass max input size on input format to the buffer channel (if supplied by the | 
|  | 1258 | // component or by a default) | 
|  | 1259 | if (maxInputSize.value) { | 
|  | 1260 | config->mInputFormat->setInt32( | 
|  | 1261 | KEY_MAX_INPUT_SIZE, | 
|  | 1262 | (int32_t)(c2_min(maxInputSize.value, uint32_t(INT32_MAX)))); | 
|  | 1263 | } | 
|  | 1264 | } | 
|  | 1265 |  | 
| Wonsik Kim | 9ca01d3 | 2019-04-01 14:45:47 -0700 | [diff] [blame] | 1266 | int32_t clientPrepend; | 
|  | 1267 | if ((config->mDomain & Config::IS_VIDEO) | 
|  | 1268 | && (config->mDomain & Config::IS_ENCODER) | 
| Lajos Molnar | a2b5f5a | 2020-10-14 16:36:18 -0700 | [diff] [blame] | 1269 | && msg->findInt32(KEY_PREPEND_HEADER_TO_SYNC_FRAMES, &clientPrepend) | 
| Wonsik Kim | 9ca01d3 | 2019-04-01 14:45:47 -0700 | [diff] [blame] | 1270 | && clientPrepend | 
|  | 1271 | && (!prepend || prepend.value != PREPEND_HEADER_TO_ALL_SYNC)) { | 
| Lajos Molnar | a2b5f5a | 2020-10-14 16:36:18 -0700 | [diff] [blame] | 1272 | ALOGE("Failed to set KEY_PREPEND_HEADER_TO_SYNC_FRAMES"); | 
| Wonsik Kim | 9ca01d3 | 2019-04-01 14:45:47 -0700 | [diff] [blame] | 1273 | return BAD_VALUE; | 
|  | 1274 | } | 
|  | 1275 |  | 
| Wonsik Kim | d91f3fb | 2021-02-24 12:35:31 -0800 | [diff] [blame] | 1276 | int32_t componentColorFormat = 0; | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1277 | if ((config->mDomain & (Config::IS_VIDEO | Config::IS_IMAGE))) { | 
|  | 1278 | // propagate HDR static info to output format for both encoders and decoders | 
|  | 1279 | // if component supports this info, we will update from component, but only the raw port, | 
|  | 1280 | // so don't propagate if component already filled it in. | 
|  | 1281 | sp<ABuffer> hdrInfo; | 
|  | 1282 | if (msg->findBuffer(KEY_HDR_STATIC_INFO, &hdrInfo) | 
|  | 1283 | && !config->mOutputFormat->findBuffer(KEY_HDR_STATIC_INFO, &hdrInfo)) { | 
|  | 1284 | config->mOutputFormat->setBuffer(KEY_HDR_STATIC_INFO, hdrInfo); | 
|  | 1285 | } | 
|  | 1286 |  | 
|  | 1287 | // Set desired color format from configuration parameter | 
|  | 1288 | int32_t format; | 
| Wonsik Kim | d79ee1f | 2020-08-27 17:41:56 -0700 | [diff] [blame] | 1289 | if (!msg->findInt32(KEY_COLOR_FORMAT, &format)) { | 
|  | 1290 | format = defaultColorFormat; | 
|  | 1291 | } | 
|  | 1292 | if (config->mDomain & Config::IS_ENCODER) { | 
|  | 1293 | config->mInputFormat->setInt32(KEY_COLOR_FORMAT, format); | 
| Wonsik Kim | d91f3fb | 2021-02-24 12:35:31 -0800 | [diff] [blame] | 1294 | if (msg->findInt32("android._color-format", &componentColorFormat)) { | 
|  | 1295 | config->mInputFormat->setInt32("android._color-format", componentColorFormat); | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1296 | } | 
| Wonsik Kim | d79ee1f | 2020-08-27 17:41:56 -0700 | [diff] [blame] | 1297 | } else { | 
|  | 1298 | config->mOutputFormat->setInt32(KEY_COLOR_FORMAT, format); | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1299 | } | 
|  | 1300 | } | 
|  | 1301 |  | 
|  | 1302 | // propagate encoder delay and padding to output format | 
|  | 1303 | if ((config->mDomain & Config::IS_DECODER) && (config->mDomain & Config::IS_AUDIO)) { | 
|  | 1304 | int delay = 0; | 
|  | 1305 | if (msg->findInt32("encoder-delay", &delay)) { | 
|  | 1306 | config->mOutputFormat->setInt32("encoder-delay", delay); | 
|  | 1307 | } | 
|  | 1308 | int padding = 0; | 
|  | 1309 | if (msg->findInt32("encoder-padding", &padding)) { | 
|  | 1310 | config->mOutputFormat->setInt32("encoder-padding", padding); | 
|  | 1311 | } | 
|  | 1312 | } | 
|  | 1313 |  | 
|  | 1314 | // set channel-mask | 
|  | 1315 | if (config->mDomain & Config::IS_AUDIO) { | 
|  | 1316 | int32_t mask; | 
|  | 1317 | if (msg->findInt32(KEY_CHANNEL_MASK, &mask)) { | 
|  | 1318 | if (config->mDomain & Config::IS_ENCODER) { | 
|  | 1319 | config->mInputFormat->setInt32(KEY_CHANNEL_MASK, mask); | 
|  | 1320 | } else { | 
|  | 1321 | config->mOutputFormat->setInt32(KEY_CHANNEL_MASK, mask); | 
|  | 1322 | } | 
|  | 1323 | } | 
|  | 1324 | } | 
|  | 1325 |  | 
| Wonsik Kim | 58d8333 | 2021-02-07 22:19:56 -0800 | [diff] [blame] | 1326 | std::unique_ptr<C2Param> colorTransferRequestParam; | 
|  | 1327 | for (std::unique_ptr<C2Param> ¶m : params) { | 
|  | 1328 | if (param->index() == colorAspectsRequestIndex.withStream(0u)) { | 
|  | 1329 | ALOGI("found color transfer request param"); | 
|  | 1330 | colorTransferRequestParam = std::move(param); | 
|  | 1331 | } | 
|  | 1332 | } | 
|  | 1333 | int32_t colorTransferRequest = 0; | 
|  | 1334 | if (config->mDomain & (Config::IS_IMAGE | Config::IS_VIDEO) | 
|  | 1335 | && !sdkParams->findInt32("color-transfer-request", &colorTransferRequest)) { | 
|  | 1336 | colorTransferRequest = 0; | 
|  | 1337 | } | 
|  | 1338 |  | 
|  | 1339 | if (colorTransferRequest != 0) { | 
|  | 1340 | if (colorTransferRequestParam && *colorTransferRequestParam) { | 
|  | 1341 | C2StreamColorAspectsInfo::output *info = | 
|  | 1342 | static_cast<C2StreamColorAspectsInfo::output *>( | 
|  | 1343 | colorTransferRequestParam.get()); | 
|  | 1344 | if (!C2Mapper::map(info->transfer, &colorTransferRequest)) { | 
|  | 1345 | colorTransferRequest = 0; | 
|  | 1346 | } | 
|  | 1347 | } else { | 
|  | 1348 | colorTransferRequest = 0; | 
|  | 1349 | } | 
|  | 1350 | config->mInputFormat->setInt32("color-transfer-request", colorTransferRequest); | 
|  | 1351 | } | 
|  | 1352 |  | 
| Wonsik Kim | d91f3fb | 2021-02-24 12:35:31 -0800 | [diff] [blame] | 1353 | if (componentColorFormat != 0 && componentColorFormat != COLOR_FormatSurface) { | 
|  | 1354 | // Need to get stride/vstride | 
|  | 1355 | uint32_t pixelFormat = PIXEL_FORMAT_UNKNOWN; | 
|  | 1356 | if (C2Mapper::mapPixelFormatFrameworkToCodec(componentColorFormat, &pixelFormat)) { | 
|  | 1357 | // TODO: retrieve these values without allocating a buffer. | 
|  | 1358 | //       Currently allocating a buffer is necessary to retrieve the layout. | 
|  | 1359 | int64_t blockUsage = | 
|  | 1360 | usage.value | C2MemoryUsage::CPU_READ | C2MemoryUsage::CPU_WRITE; | 
|  | 1361 | std::shared_ptr<C2GraphicBlock> block = FetchGraphicBlock( | 
|  | 1362 | width, height, pixelFormat, blockUsage, {comp->getName()}); | 
|  | 1363 | sp<GraphicBlockBuffer> buffer; | 
|  | 1364 | if (block) { | 
|  | 1365 | buffer = GraphicBlockBuffer::Allocate( | 
|  | 1366 | config->mInputFormat, | 
|  | 1367 | block, | 
|  | 1368 | [](size_t size) -> sp<ABuffer> { return new ABuffer(size); }); | 
|  | 1369 | } else { | 
|  | 1370 | ALOGD("Failed to allocate a graphic block " | 
|  | 1371 | "(width=%d height=%d pixelFormat=%u usage=%llx)", | 
|  | 1372 | width, height, pixelFormat, (long long)blockUsage); | 
|  | 1373 | // This means that byte buffer mode is not supported in this configuration | 
|  | 1374 | // anyway. Skip setting stride/vstride to input format. | 
|  | 1375 | } | 
|  | 1376 | if (buffer) { | 
|  | 1377 | sp<ABuffer> imageData = buffer->getImageData(); | 
|  | 1378 | MediaImage2 *img = nullptr; | 
|  | 1379 | if (imageData && imageData->data() | 
|  | 1380 | && imageData->size() >= sizeof(MediaImage2)) { | 
|  | 1381 | img = (MediaImage2*)imageData->data(); | 
|  | 1382 | } | 
|  | 1383 | if (img && img->mNumPlanes > 0 && img->mType != img->MEDIA_IMAGE_TYPE_UNKNOWN) { | 
|  | 1384 | int32_t stride = img->mPlane[0].mRowInc; | 
|  | 1385 | config->mInputFormat->setInt32(KEY_STRIDE, stride); | 
|  | 1386 | if (img->mNumPlanes > 1 && stride > 0) { | 
|  | 1387 | int64_t offsetDelta = | 
|  | 1388 | (int64_t)img->mPlane[1].mOffset - (int64_t)img->mPlane[0].mOffset; | 
|  | 1389 | if (offsetDelta % stride == 0) { | 
|  | 1390 | int32_t vstride = int32_t(offsetDelta / stride); | 
|  | 1391 | config->mInputFormat->setInt32(KEY_SLICE_HEIGHT, vstride); | 
|  | 1392 | } else { | 
|  | 1393 | ALOGD("Cannot report accurate slice height: " | 
|  | 1394 | "offsetDelta = %lld stride = %d", | 
|  | 1395 | (long long)offsetDelta, stride); | 
|  | 1396 | } | 
|  | 1397 | } | 
|  | 1398 | } | 
|  | 1399 | } | 
|  | 1400 | } | 
|  | 1401 | } | 
|  | 1402 |  | 
|  | 1403 | ALOGD("setup formats input: %s", | 
|  | 1404 | config->mInputFormat->debugString().c_str()); | 
|  | 1405 | ALOGD("setup formats output: %s", | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1406 | config->mOutputFormat->debugString().c_str()); | 
|  | 1407 | return OK; | 
|  | 1408 | }; | 
|  | 1409 | if (tryAndReportOnError(doConfig) != OK) { | 
|  | 1410 | return; | 
|  | 1411 | } | 
|  | 1412 |  | 
| Wonsik Kim | 155d5cb | 2019-10-09 12:49:49 -0700 | [diff] [blame] | 1413 | Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig); | 
|  | 1414 | const std::unique_ptr<Config> &config = *configLocked; | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1415 |  | 
| Houxiang Dai | 183ca3d | 2021-02-04 14:20:11 +0800 | [diff] [blame] | 1416 | config->queryConfiguration(comp); | 
|  | 1417 |  | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1418 | mCallback->onComponentConfigured(config->mInputFormat, config->mOutputFormat); | 
|  | 1419 | } | 
|  | 1420 |  | 
|  | 1421 | void CCodec::initiateCreateInputSurface() { | 
|  | 1422 | status_t err = [this] { | 
|  | 1423 | Mutexed<State>::Locked state(mState); | 
|  | 1424 | if (state->get() != ALLOCATED) { | 
|  | 1425 | return UNKNOWN_ERROR; | 
|  | 1426 | } | 
|  | 1427 | // TODO: read it from intf() properly. | 
|  | 1428 | if (state->comp->getName().find("encoder") == std::string::npos) { | 
|  | 1429 | return INVALID_OPERATION; | 
|  | 1430 | } | 
|  | 1431 | return OK; | 
|  | 1432 | }(); | 
|  | 1433 | if (err != OK) { | 
|  | 1434 | mCallback->onInputSurfaceCreationFailed(err); | 
|  | 1435 | return; | 
|  | 1436 | } | 
|  | 1437 |  | 
|  | 1438 | (new AMessage(kWhatCreateInputSurface, this))->post(); | 
|  | 1439 | } | 
|  | 1440 |  | 
| Lajos Molnar | 4711827 | 2019-01-31 16:28:04 -0800 | [diff] [blame] | 1441 | sp<PersistentSurface> CCodec::CreateOmxInputSurface() { | 
|  | 1442 | using namespace android::hardware::media::omx::V1_0; | 
|  | 1443 | using namespace android::hardware::media::omx::V1_0::utils; | 
|  | 1444 | using namespace android::hardware::graphics::bufferqueue::V1_0::utils; | 
|  | 1445 | typedef android::hardware::media::omx::V1_0::Status OmxStatus; | 
|  | 1446 | android::sp<IOmx> omx = IOmx::getService(); | 
|  | 1447 | typedef android::hardware::graphics::bufferqueue::V1_0:: | 
|  | 1448 | IGraphicBufferProducer HGraphicBufferProducer; | 
|  | 1449 | typedef android::hardware::media::omx::V1_0:: | 
|  | 1450 | IGraphicBufferSource HGraphicBufferSource; | 
|  | 1451 | OmxStatus s; | 
|  | 1452 | android::sp<HGraphicBufferProducer> gbp; | 
|  | 1453 | android::sp<HGraphicBufferSource> gbs; | 
| Pawin Vongmasa | 1858832 | 2019-05-18 01:52:13 -0700 | [diff] [blame] | 1454 |  | 
| Chong Zhang | c8ce1d8 | 2019-03-27 10:18:38 -0700 | [diff] [blame] | 1455 | using ::android::hardware::Return; | 
|  | 1456 | Return<void> transStatus = omx->createInputSurface( | 
| Lajos Molnar | 4711827 | 2019-01-31 16:28:04 -0800 | [diff] [blame] | 1457 | [&s, &gbp, &gbs]( | 
|  | 1458 | OmxStatus status, | 
|  | 1459 | const android::sp<HGraphicBufferProducer>& producer, | 
|  | 1460 | const android::sp<HGraphicBufferSource>& source) { | 
|  | 1461 | s = status; | 
|  | 1462 | gbp = producer; | 
|  | 1463 | gbs = source; | 
|  | 1464 | }); | 
|  | 1465 | if (transStatus.isOk() && s == OmxStatus::OK) { | 
| Wonsik Kim | 9917d4a | 2019-10-24 12:56:38 -0700 | [diff] [blame] | 1466 | return new PersistentSurface(new H2BGraphicBufferProducer(gbp), gbs); | 
| Lajos Molnar | 4711827 | 2019-01-31 16:28:04 -0800 | [diff] [blame] | 1467 | } | 
|  | 1468 |  | 
|  | 1469 | return nullptr; | 
|  | 1470 | } | 
|  | 1471 |  | 
|  | 1472 | sp<PersistentSurface> CCodec::CreateCompatibleInputSurface() { | 
|  | 1473 | sp<PersistentSurface> surface(CreateInputSurface()); | 
|  | 1474 |  | 
|  | 1475 | if (surface == nullptr) { | 
|  | 1476 | surface = CreateOmxInputSurface(); | 
|  | 1477 | } | 
|  | 1478 |  | 
|  | 1479 | return surface; | 
|  | 1480 | } | 
|  | 1481 |  | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1482 | void CCodec::createInputSurface() { | 
|  | 1483 | status_t err; | 
|  | 1484 | sp<IGraphicBufferProducer> bufferProducer; | 
|  | 1485 |  | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1486 | sp<AMessage> outputFormat; | 
| Wonsik Kim | 9eac4d1 | 2019-05-23 12:58:48 -0700 | [diff] [blame] | 1487 | uint64_t usage = 0; | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1488 | { | 
| Wonsik Kim | 155d5cb | 2019-10-09 12:49:49 -0700 | [diff] [blame] | 1489 | Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig); | 
|  | 1490 | const std::unique_ptr<Config> &config = *configLocked; | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1491 | outputFormat = config->mOutputFormat; | 
| Wonsik Kim | 9eac4d1 | 2019-05-23 12:58:48 -0700 | [diff] [blame] | 1492 | usage = config->mISConfig ? config->mISConfig->mUsage : 0; | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1493 | } | 
|  | 1494 |  | 
| Lajos Molnar | 4711827 | 2019-01-31 16:28:04 -0800 | [diff] [blame] | 1495 | sp<PersistentSurface> persistentSurface = CreateCompatibleInputSurface(); | 
| Wonsik Kim | 9917d4a | 2019-10-24 12:56:38 -0700 | [diff] [blame] | 1496 | sp<hidl::base::V1_0::IBase> hidlTarget = persistentSurface->getHidlTarget(); | 
|  | 1497 | sp<IInputSurface> hidlInputSurface = IInputSurface::castFrom(hidlTarget); | 
|  | 1498 | sp<HGraphicBufferSource> gbs = HGraphicBufferSource::castFrom(hidlTarget); | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1499 |  | 
| Wonsik Kim | 9917d4a | 2019-10-24 12:56:38 -0700 | [diff] [blame] | 1500 | if (hidlInputSurface) { | 
| Pawin Vongmasa | 1c75a23 | 2019-01-09 04:41:52 -0800 | [diff] [blame] | 1501 | std::shared_ptr<Codec2Client::InputSurface> inputSurface = | 
|  | 1502 | std::make_shared<Codec2Client::InputSurface>(hidlInputSurface); | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1503 | err = setupInputSurface(std::make_shared<C2InputSurfaceWrapper>( | 
| Pawin Vongmasa | 1c75a23 | 2019-01-09 04:41:52 -0800 | [diff] [blame] | 1504 | inputSurface)); | 
|  | 1505 | bufferProducer = inputSurface->getGraphicBufferProducer(); | 
| Wonsik Kim | 9917d4a | 2019-10-24 12:56:38 -0700 | [diff] [blame] | 1506 | } else if (gbs) { | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1507 | int32_t width = 0; | 
|  | 1508 | (void)outputFormat->findInt32("width", &width); | 
|  | 1509 | int32_t height = 0; | 
|  | 1510 | (void)outputFormat->findInt32("height", &height); | 
|  | 1511 | err = setupInputSurface(std::make_shared<GraphicBufferSourceWrapper>( | 
| Wonsik Kim | 9917d4a | 2019-10-24 12:56:38 -0700 | [diff] [blame] | 1512 | gbs, width, height, usage)); | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1513 | bufferProducer = persistentSurface->getBufferProducer(); | 
| Wonsik Kim | 9917d4a | 2019-10-24 12:56:38 -0700 | [diff] [blame] | 1514 | } else { | 
|  | 1515 | ALOGE("Corrupted input surface"); | 
|  | 1516 | mCallback->onInputSurfaceCreationFailed(UNKNOWN_ERROR); | 
|  | 1517 | return; | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1518 | } | 
|  | 1519 |  | 
|  | 1520 | if (err != OK) { | 
|  | 1521 | ALOGE("Failed to set up input surface: %d", err); | 
|  | 1522 | mCallback->onInputSurfaceCreationFailed(err); | 
|  | 1523 | return; | 
|  | 1524 | } | 
|  | 1525 |  | 
| Wonsik Kim | 7b9e6db | 2021-05-10 13:31:40 -0700 | [diff] [blame] | 1526 | // Formats can change after setupInputSurface | 
|  | 1527 | sp<AMessage> inputFormat; | 
|  | 1528 | { | 
|  | 1529 | Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig); | 
|  | 1530 | const std::unique_ptr<Config> &config = *configLocked; | 
|  | 1531 | inputFormat = config->mInputFormat; | 
|  | 1532 | outputFormat = config->mOutputFormat; | 
|  | 1533 | } | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1534 | mCallback->onInputSurfaceCreated( | 
|  | 1535 | inputFormat, | 
|  | 1536 | outputFormat, | 
|  | 1537 | new BufferProducerWrapper(bufferProducer)); | 
|  | 1538 | } | 
|  | 1539 |  | 
|  | 1540 | status_t CCodec::setupInputSurface(const std::shared_ptr<InputSurfaceWrapper> &surface) { | 
| Wonsik Kim | 155d5cb | 2019-10-09 12:49:49 -0700 | [diff] [blame] | 1541 | Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig); | 
|  | 1542 | const std::unique_ptr<Config> &config = *configLocked; | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1543 | config->mUsingSurface = true; | 
|  | 1544 |  | 
|  | 1545 | // we are now using surface - apply default color aspects to input format - as well as | 
|  | 1546 | // get dataspace | 
| Wonsik Kim | 8a6ed37 | 2019-12-03 16:05:51 -0800 | [diff] [blame] | 1547 | bool inputFormatChanged = config->updateFormats(Config::IS_INPUT); | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1548 | ALOGD("input format %s to %s", | 
|  | 1549 | inputFormatChanged ? "changed" : "unchanged", | 
|  | 1550 | config->mInputFormat->debugString().c_str()); | 
|  | 1551 |  | 
|  | 1552 | // configure dataspace | 
|  | 1553 | static_assert(sizeof(int32_t) == sizeof(android_dataspace), "dataspace size mismatch"); | 
|  | 1554 | android_dataspace dataSpace = HAL_DATASPACE_UNKNOWN; | 
|  | 1555 | (void)config->mInputFormat->findInt32("android._dataspace", (int32_t*)&dataSpace); | 
|  | 1556 | surface->setDataSpace(dataSpace); | 
|  | 1557 |  | 
|  | 1558 | status_t err = mChannel->setInputSurface(surface); | 
|  | 1559 | if (err != OK) { | 
|  | 1560 | // undo input format update | 
|  | 1561 | config->mUsingSurface = false; | 
| Wonsik Kim | 8a6ed37 | 2019-12-03 16:05:51 -0800 | [diff] [blame] | 1562 | (void)config->updateFormats(Config::IS_INPUT); | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1563 | return err; | 
|  | 1564 | } | 
|  | 1565 | config->mInputSurface = surface; | 
|  | 1566 |  | 
|  | 1567 | if (config->mISConfig) { | 
|  | 1568 | surface->configure(*config->mISConfig); | 
|  | 1569 | } else { | 
|  | 1570 | ALOGD("ISConfig: no configuration"); | 
|  | 1571 | } | 
|  | 1572 |  | 
| Pawin Vongmasa | 1f21336 | 2019-01-24 06:59:16 -0800 | [diff] [blame] | 1573 | return OK; | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1574 | } | 
|  | 1575 |  | 
|  | 1576 | void CCodec::initiateSetInputSurface(const sp<PersistentSurface> &surface) { | 
|  | 1577 | sp<AMessage> msg = new AMessage(kWhatSetInputSurface, this); | 
|  | 1578 | msg->setObject("surface", surface); | 
|  | 1579 | msg->post(); | 
|  | 1580 | } | 
|  | 1581 |  | 
|  | 1582 | void CCodec::setInputSurface(const sp<PersistentSurface> &surface) { | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1583 | sp<AMessage> outputFormat; | 
| Wonsik Kim | 9eac4d1 | 2019-05-23 12:58:48 -0700 | [diff] [blame] | 1584 | uint64_t usage = 0; | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1585 | { | 
| Wonsik Kim | 155d5cb | 2019-10-09 12:49:49 -0700 | [diff] [blame] | 1586 | Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig); | 
|  | 1587 | const std::unique_ptr<Config> &config = *configLocked; | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1588 | outputFormat = config->mOutputFormat; | 
| Wonsik Kim | 9eac4d1 | 2019-05-23 12:58:48 -0700 | [diff] [blame] | 1589 | usage = config->mISConfig ? config->mISConfig->mUsage : 0; | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1590 | } | 
| Wonsik Kim | 9917d4a | 2019-10-24 12:56:38 -0700 | [diff] [blame] | 1591 | sp<hidl::base::V1_0::IBase> hidlTarget = surface->getHidlTarget(); | 
|  | 1592 | sp<IInputSurface> inputSurface = IInputSurface::castFrom(hidlTarget); | 
|  | 1593 | sp<HGraphicBufferSource> gbs = HGraphicBufferSource::castFrom(hidlTarget); | 
|  | 1594 | if (inputSurface) { | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1595 | status_t err = setupInputSurface(std::make_shared<C2InputSurfaceWrapper>( | 
|  | 1596 | std::make_shared<Codec2Client::InputSurface>(inputSurface))); | 
|  | 1597 | if (err != OK) { | 
|  | 1598 | ALOGE("Failed to set up input surface: %d", err); | 
|  | 1599 | mCallback->onInputSurfaceDeclined(err); | 
|  | 1600 | return; | 
|  | 1601 | } | 
| Wonsik Kim | 9917d4a | 2019-10-24 12:56:38 -0700 | [diff] [blame] | 1602 | } else if (gbs) { | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1603 | int32_t width = 0; | 
|  | 1604 | (void)outputFormat->findInt32("width", &width); | 
|  | 1605 | int32_t height = 0; | 
|  | 1606 | (void)outputFormat->findInt32("height", &height); | 
|  | 1607 | status_t err = setupInputSurface(std::make_shared<GraphicBufferSourceWrapper>( | 
| Wonsik Kim | 9917d4a | 2019-10-24 12:56:38 -0700 | [diff] [blame] | 1608 | gbs, width, height, usage)); | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1609 | if (err != OK) { | 
|  | 1610 | ALOGE("Failed to set up input surface: %d", err); | 
|  | 1611 | mCallback->onInputSurfaceDeclined(err); | 
|  | 1612 | return; | 
|  | 1613 | } | 
| Wonsik Kim | 9917d4a | 2019-10-24 12:56:38 -0700 | [diff] [blame] | 1614 | } else { | 
|  | 1615 | ALOGE("Failed to set input surface: Corrupted surface."); | 
|  | 1616 | mCallback->onInputSurfaceDeclined(UNKNOWN_ERROR); | 
|  | 1617 | return; | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1618 | } | 
| Wonsik Kim | 7b9e6db | 2021-05-10 13:31:40 -0700 | [diff] [blame] | 1619 | // Formats can change after setupInputSurface | 
|  | 1620 | sp<AMessage> inputFormat; | 
|  | 1621 | { | 
|  | 1622 | Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig); | 
|  | 1623 | const std::unique_ptr<Config> &config = *configLocked; | 
|  | 1624 | inputFormat = config->mInputFormat; | 
|  | 1625 | outputFormat = config->mOutputFormat; | 
|  | 1626 | } | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1627 | mCallback->onInputSurfaceAccepted(inputFormat, outputFormat); | 
|  | 1628 | } | 
|  | 1629 |  | 
|  | 1630 | void CCodec::initiateStart() { | 
|  | 1631 | auto setStarting = [this] { | 
|  | 1632 | Mutexed<State>::Locked state(mState); | 
|  | 1633 | if (state->get() != ALLOCATED) { | 
|  | 1634 | return UNKNOWN_ERROR; | 
|  | 1635 | } | 
|  | 1636 | state->set(STARTING); | 
|  | 1637 | return OK; | 
|  | 1638 | }; | 
|  | 1639 | if (tryAndReportOnError(setStarting) != OK) { | 
|  | 1640 | return; | 
|  | 1641 | } | 
|  | 1642 |  | 
|  | 1643 | (new AMessage(kWhatStart, this))->post(); | 
|  | 1644 | } | 
|  | 1645 |  | 
|  | 1646 | void CCodec::start() { | 
|  | 1647 | std::shared_ptr<Codec2Client::Component> comp; | 
|  | 1648 | auto checkStarting = [this, &comp] { | 
|  | 1649 | Mutexed<State>::Locked state(mState); | 
|  | 1650 | if (state->get() != STARTING) { | 
|  | 1651 | return UNKNOWN_ERROR; | 
|  | 1652 | } | 
|  | 1653 | comp = state->comp; | 
|  | 1654 | return OK; | 
|  | 1655 | }; | 
|  | 1656 | if (tryAndReportOnError(checkStarting) != OK) { | 
|  | 1657 | return; | 
|  | 1658 | } | 
|  | 1659 |  | 
|  | 1660 | c2_status_t err = comp->start(); | 
|  | 1661 | if (err != C2_OK) { | 
|  | 1662 | mCallback->onError(toStatusT(err, C2_OPERATION_Component_start), | 
|  | 1663 | ACTION_CODE_FATAL); | 
|  | 1664 | return; | 
|  | 1665 | } | 
|  | 1666 | sp<AMessage> inputFormat; | 
|  | 1667 | sp<AMessage> outputFormat; | 
| Pawin Vongmasa | 1f21336 | 2019-01-24 06:59:16 -0800 | [diff] [blame] | 1668 | status_t err2 = OK; | 
| Wonsik Kim | fb7a767 | 2019-12-27 17:13:33 -0800 | [diff] [blame] | 1669 | bool buffersBoundToCodec = false; | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1670 | { | 
| Wonsik Kim | 155d5cb | 2019-10-09 12:49:49 -0700 | [diff] [blame] | 1671 | Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig); | 
|  | 1672 | const std::unique_ptr<Config> &config = *configLocked; | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1673 | inputFormat = config->mInputFormat; | 
| Wonsik Kim | 274c832 | 2020-02-28 10:42:21 -0800 | [diff] [blame] | 1674 | // start triggers format dup | 
|  | 1675 | outputFormat = config->mOutputFormat = config->mOutputFormat->dup(); | 
| Pawin Vongmasa | 1f21336 | 2019-01-24 06:59:16 -0800 | [diff] [blame] | 1676 | if (config->mInputSurface) { | 
|  | 1677 | err2 = config->mInputSurface->start(); | 
| Wonsik Kim | 673dd19 | 2021-01-29 14:58:12 -0800 | [diff] [blame] | 1678 | config->mInputSurfaceDataspace = config->mInputSurface->getDataspace(); | 
| Pawin Vongmasa | 1f21336 | 2019-01-24 06:59:16 -0800 | [diff] [blame] | 1679 | } | 
| Wonsik Kim | fb7a767 | 2019-12-27 17:13:33 -0800 | [diff] [blame] | 1680 | buffersBoundToCodec = config->mBuffersBoundToCodec; | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1681 | } | 
| Pawin Vongmasa | 1f21336 | 2019-01-24 06:59:16 -0800 | [diff] [blame] | 1682 | if (err2 != OK) { | 
|  | 1683 | mCallback->onError(err2, ACTION_CODE_FATAL); | 
|  | 1684 | return; | 
|  | 1685 | } | 
| Wonsik Kim | fb7a767 | 2019-12-27 17:13:33 -0800 | [diff] [blame] | 1686 | err2 = mChannel->start(inputFormat, outputFormat, buffersBoundToCodec); | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1687 | if (err2 != OK) { | 
|  | 1688 | mCallback->onError(err2, ACTION_CODE_FATAL); | 
|  | 1689 | return; | 
|  | 1690 | } | 
|  | 1691 |  | 
|  | 1692 | auto setRunning = [this] { | 
|  | 1693 | Mutexed<State>::Locked state(mState); | 
|  | 1694 | if (state->get() != STARTING) { | 
|  | 1695 | return UNKNOWN_ERROR; | 
|  | 1696 | } | 
|  | 1697 | state->set(RUNNING); | 
|  | 1698 | return OK; | 
|  | 1699 | }; | 
|  | 1700 | if (tryAndReportOnError(setRunning) != OK) { | 
|  | 1701 | return; | 
|  | 1702 | } | 
|  | 1703 | mCallback->onStartCompleted(); | 
|  | 1704 |  | 
|  | 1705 | (void)mChannel->requestInitialInputBuffers(); | 
|  | 1706 | } | 
|  | 1707 |  | 
|  | 1708 | void CCodec::initiateShutdown(bool keepComponentAllocated) { | 
|  | 1709 | if (keepComponentAllocated) { | 
|  | 1710 | initiateStop(); | 
|  | 1711 | } else { | 
|  | 1712 | initiateRelease(); | 
|  | 1713 | } | 
|  | 1714 | } | 
|  | 1715 |  | 
|  | 1716 | void CCodec::initiateStop() { | 
|  | 1717 | { | 
|  | 1718 | Mutexed<State>::Locked state(mState); | 
|  | 1719 | if (state->get() == ALLOCATED | 
|  | 1720 | || state->get()  == RELEASED | 
|  | 1721 | || state->get() == STOPPING | 
|  | 1722 | || state->get() == RELEASING) { | 
|  | 1723 | // We're already stopped, released, or doing it right now. | 
|  | 1724 | state.unlock(); | 
|  | 1725 | mCallback->onStopCompleted(); | 
|  | 1726 | state.lock(); | 
|  | 1727 | return; | 
|  | 1728 | } | 
|  | 1729 | state->set(STOPPING); | 
|  | 1730 | } | 
|  | 1731 |  | 
| Wonsik Kim | 936a89c | 2020-05-08 16:07:50 -0700 | [diff] [blame] | 1732 | mChannel->reset(); | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1733 | (new AMessage(kWhatStop, this))->post(); | 
|  | 1734 | } | 
|  | 1735 |  | 
|  | 1736 | void CCodec::stop() { | 
|  | 1737 | std::shared_ptr<Codec2Client::Component> comp; | 
|  | 1738 | { | 
|  | 1739 | Mutexed<State>::Locked state(mState); | 
|  | 1740 | if (state->get() == RELEASING) { | 
|  | 1741 | state.unlock(); | 
|  | 1742 | // We're already stopped or release is in progress. | 
|  | 1743 | mCallback->onStopCompleted(); | 
|  | 1744 | state.lock(); | 
|  | 1745 | return; | 
|  | 1746 | } else if (state->get() != STOPPING) { | 
|  | 1747 | state.unlock(); | 
|  | 1748 | mCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL); | 
|  | 1749 | state.lock(); | 
|  | 1750 | return; | 
|  | 1751 | } | 
|  | 1752 | comp = state->comp; | 
|  | 1753 | } | 
|  | 1754 | status_t err = comp->stop(); | 
|  | 1755 | if (err != C2_OK) { | 
|  | 1756 | // TODO: convert err into status_t | 
|  | 1757 | mCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL); | 
|  | 1758 | } | 
|  | 1759 |  | 
|  | 1760 | { | 
| Wonsik Kim | 155d5cb | 2019-10-09 12:49:49 -0700 | [diff] [blame] | 1761 | Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig); | 
|  | 1762 | const std::unique_ptr<Config> &config = *configLocked; | 
| Pawin Vongmasa | 1f21336 | 2019-01-24 06:59:16 -0800 | [diff] [blame] | 1763 | if (config->mInputSurface) { | 
|  | 1764 | config->mInputSurface->disconnect(); | 
|  | 1765 | config->mInputSurface = nullptr; | 
| Wonsik Kim | 673dd19 | 2021-01-29 14:58:12 -0800 | [diff] [blame] | 1766 | config->mInputSurfaceDataspace = HAL_DATASPACE_UNKNOWN; | 
| Pawin Vongmasa | 1f21336 | 2019-01-24 06:59:16 -0800 | [diff] [blame] | 1767 | } | 
|  | 1768 | } | 
|  | 1769 | { | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1770 | Mutexed<State>::Locked state(mState); | 
|  | 1771 | if (state->get() == STOPPING) { | 
|  | 1772 | state->set(ALLOCATED); | 
|  | 1773 | } | 
|  | 1774 | } | 
|  | 1775 | mCallback->onStopCompleted(); | 
|  | 1776 | } | 
|  | 1777 |  | 
|  | 1778 | void CCodec::initiateRelease(bool sendCallback /* = true */) { | 
| Pawin Vongmasa | 1f21336 | 2019-01-24 06:59:16 -0800 | [diff] [blame] | 1779 | bool clearInputSurfaceIfNeeded = false; | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1780 | { | 
|  | 1781 | Mutexed<State>::Locked state(mState); | 
|  | 1782 | if (state->get() == RELEASED || state->get() == RELEASING) { | 
|  | 1783 | // We're already released or doing it right now. | 
|  | 1784 | if (sendCallback) { | 
|  | 1785 | state.unlock(); | 
|  | 1786 | mCallback->onReleaseCompleted(); | 
|  | 1787 | state.lock(); | 
|  | 1788 | } | 
|  | 1789 | return; | 
|  | 1790 | } | 
|  | 1791 | if (state->get() == ALLOCATING) { | 
|  | 1792 | state->set(RELEASING); | 
|  | 1793 | // With the altered state allocate() would fail and clean up. | 
|  | 1794 | if (sendCallback) { | 
|  | 1795 | state.unlock(); | 
|  | 1796 | mCallback->onReleaseCompleted(); | 
|  | 1797 | state.lock(); | 
|  | 1798 | } | 
|  | 1799 | return; | 
|  | 1800 | } | 
| Pawin Vongmasa | 1f21336 | 2019-01-24 06:59:16 -0800 | [diff] [blame] | 1801 | if (state->get() == STARTING | 
|  | 1802 | || state->get() == RUNNING | 
|  | 1803 | || state->get() == STOPPING) { | 
|  | 1804 | // Input surface may have been started, so clean up is needed. | 
|  | 1805 | clearInputSurfaceIfNeeded = true; | 
|  | 1806 | } | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1807 | state->set(RELEASING); | 
|  | 1808 | } | 
|  | 1809 |  | 
| Pawin Vongmasa | 1f21336 | 2019-01-24 06:59:16 -0800 | [diff] [blame] | 1810 | if (clearInputSurfaceIfNeeded) { | 
| Wonsik Kim | 155d5cb | 2019-10-09 12:49:49 -0700 | [diff] [blame] | 1811 | Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig); | 
|  | 1812 | const std::unique_ptr<Config> &config = *configLocked; | 
| Pawin Vongmasa | 1f21336 | 2019-01-24 06:59:16 -0800 | [diff] [blame] | 1813 | if (config->mInputSurface) { | 
|  | 1814 | config->mInputSurface->disconnect(); | 
|  | 1815 | config->mInputSurface = nullptr; | 
| Wonsik Kim | 673dd19 | 2021-01-29 14:58:12 -0800 | [diff] [blame] | 1816 | config->mInputSurfaceDataspace = HAL_DATASPACE_UNKNOWN; | 
| Pawin Vongmasa | 1f21336 | 2019-01-24 06:59:16 -0800 | [diff] [blame] | 1817 | } | 
|  | 1818 | } | 
|  | 1819 |  | 
| Wonsik Kim | 936a89c | 2020-05-08 16:07:50 -0700 | [diff] [blame] | 1820 | mChannel->reset(); | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1821 | // thiz holds strong ref to this while the thread is running. | 
|  | 1822 | sp<CCodec> thiz(this); | 
|  | 1823 | std::thread([thiz, sendCallback] { thiz->release(sendCallback); }).detach(); | 
|  | 1824 | } | 
|  | 1825 |  | 
|  | 1826 | void CCodec::release(bool sendCallback) { | 
|  | 1827 | std::shared_ptr<Codec2Client::Component> comp; | 
|  | 1828 | { | 
|  | 1829 | Mutexed<State>::Locked state(mState); | 
|  | 1830 | if (state->get() == RELEASED) { | 
|  | 1831 | if (sendCallback) { | 
|  | 1832 | state.unlock(); | 
|  | 1833 | mCallback->onReleaseCompleted(); | 
|  | 1834 | state.lock(); | 
|  | 1835 | } | 
|  | 1836 | return; | 
|  | 1837 | } | 
|  | 1838 | comp = state->comp; | 
|  | 1839 | } | 
|  | 1840 | comp->release(); | 
|  | 1841 |  | 
|  | 1842 | { | 
|  | 1843 | Mutexed<State>::Locked state(mState); | 
|  | 1844 | state->set(RELEASED); | 
|  | 1845 | state->comp.reset(); | 
|  | 1846 | } | 
| Wonsik Kim | 936a89c | 2020-05-08 16:07:50 -0700 | [diff] [blame] | 1847 | (new AMessage(kWhatRelease, this))->post(); | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1848 | if (sendCallback) { | 
|  | 1849 | mCallback->onReleaseCompleted(); | 
|  | 1850 | } | 
|  | 1851 | } | 
|  | 1852 |  | 
|  | 1853 | status_t CCodec::setSurface(const sp<Surface> &surface) { | 
| Wonsik Kim | 75e22f4 | 2021-04-14 23:34:51 -0700 | [diff] [blame] | 1854 | { | 
|  | 1855 | Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig); | 
|  | 1856 | const std::unique_ptr<Config> &config = *configLocked; | 
|  | 1857 | if (config->mTunneled && config->mSidebandHandle != nullptr) { | 
|  | 1858 | sp<ANativeWindow> nativeWindow = static_cast<ANativeWindow *>(surface.get()); | 
|  | 1859 | status_t err = native_window_set_sideband_stream( | 
|  | 1860 | nativeWindow.get(), | 
|  | 1861 | const_cast<native_handle_t *>(config->mSidebandHandle->handle())); | 
|  | 1862 | if (err != OK) { | 
|  | 1863 | ALOGE("NativeWindow(%p) native_window_set_sideband_stream(%p) failed! (err %d).", | 
|  | 1864 | nativeWindow.get(), config->mSidebandHandle->handle(), err); | 
|  | 1865 | return err; | 
|  | 1866 | } | 
| ted.sun | 765db4d | 2020-06-23 14:03:41 +0800 | [diff] [blame] | 1867 | } | 
|  | 1868 | } | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1869 | return mChannel->setSurface(surface); | 
|  | 1870 | } | 
|  | 1871 |  | 
|  | 1872 | void CCodec::signalFlush() { | 
|  | 1873 | status_t err = [this] { | 
|  | 1874 | Mutexed<State>::Locked state(mState); | 
|  | 1875 | if (state->get() == FLUSHED) { | 
|  | 1876 | return ALREADY_EXISTS; | 
|  | 1877 | } | 
|  | 1878 | if (state->get() != RUNNING) { | 
|  | 1879 | return UNKNOWN_ERROR; | 
|  | 1880 | } | 
|  | 1881 | state->set(FLUSHING); | 
|  | 1882 | return OK; | 
|  | 1883 | }(); | 
|  | 1884 | switch (err) { | 
|  | 1885 | case ALREADY_EXISTS: | 
|  | 1886 | mCallback->onFlushCompleted(); | 
|  | 1887 | return; | 
|  | 1888 | case OK: | 
|  | 1889 | break; | 
|  | 1890 | default: | 
|  | 1891 | mCallback->onError(err, ACTION_CODE_FATAL); | 
|  | 1892 | return; | 
|  | 1893 | } | 
|  | 1894 |  | 
|  | 1895 | mChannel->stop(); | 
|  | 1896 | (new AMessage(kWhatFlush, this))->post(); | 
|  | 1897 | } | 
|  | 1898 |  | 
|  | 1899 | void CCodec::flush() { | 
|  | 1900 | std::shared_ptr<Codec2Client::Component> comp; | 
|  | 1901 | auto checkFlushing = [this, &comp] { | 
|  | 1902 | Mutexed<State>::Locked state(mState); | 
|  | 1903 | if (state->get() != FLUSHING) { | 
|  | 1904 | return UNKNOWN_ERROR; | 
|  | 1905 | } | 
|  | 1906 | comp = state->comp; | 
|  | 1907 | return OK; | 
|  | 1908 | }; | 
|  | 1909 | if (tryAndReportOnError(checkFlushing) != OK) { | 
|  | 1910 | return; | 
|  | 1911 | } | 
|  | 1912 |  | 
|  | 1913 | std::list<std::unique_ptr<C2Work>> flushedWork; | 
|  | 1914 | c2_status_t err = comp->flush(C2Component::FLUSH_COMPONENT, &flushedWork); | 
|  | 1915 | { | 
|  | 1916 | Mutexed<std::list<std::unique_ptr<C2Work>>>::Locked queue(mWorkDoneQueue); | 
|  | 1917 | flushedWork.splice(flushedWork.end(), *queue); | 
|  | 1918 | } | 
|  | 1919 | if (err != C2_OK) { | 
|  | 1920 | // TODO: convert err into status_t | 
|  | 1921 | mCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL); | 
|  | 1922 | } | 
|  | 1923 |  | 
|  | 1924 | mChannel->flush(flushedWork); | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1925 |  | 
|  | 1926 | { | 
|  | 1927 | Mutexed<State>::Locked state(mState); | 
| Iris Chang | ce521ee | 2019-07-05 16:18:54 +0800 | [diff] [blame] | 1928 | if (state->get() == FLUSHING) { | 
|  | 1929 | state->set(FLUSHED); | 
|  | 1930 | } | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1931 | } | 
|  | 1932 | mCallback->onFlushCompleted(); | 
|  | 1933 | } | 
|  | 1934 |  | 
|  | 1935 | void CCodec::signalResume() { | 
| Wonsik Kim | e75a5da | 2020-02-14 17:29:03 -0800 | [diff] [blame] | 1936 | std::shared_ptr<Codec2Client::Component> comp; | 
|  | 1937 | auto setResuming = [this, &comp] { | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1938 | Mutexed<State>::Locked state(mState); | 
|  | 1939 | if (state->get() != FLUSHED) { | 
|  | 1940 | return UNKNOWN_ERROR; | 
|  | 1941 | } | 
|  | 1942 | state->set(RESUMING); | 
| Wonsik Kim | e75a5da | 2020-02-14 17:29:03 -0800 | [diff] [blame] | 1943 | comp = state->comp; | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1944 | return OK; | 
|  | 1945 | }; | 
|  | 1946 | if (tryAndReportOnError(setResuming) != OK) { | 
|  | 1947 | return; | 
|  | 1948 | } | 
|  | 1949 |  | 
| Wonsik Kim | e75a5da | 2020-02-14 17:29:03 -0800 | [diff] [blame] | 1950 | { | 
|  | 1951 | Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig); | 
|  | 1952 | const std::unique_ptr<Config> &config = *configLocked; | 
| Harish Mahendrakar | 8c53750 | 2021-02-23 21:20:22 -0800 | [diff] [blame] | 1953 | sp<AMessage> outputFormat = config->mOutputFormat; | 
| Wonsik Kim | e75a5da | 2020-02-14 17:29:03 -0800 | [diff] [blame] | 1954 | config->queryConfiguration(comp); | 
| Harish Mahendrakar | 8c53750 | 2021-02-23 21:20:22 -0800 | [diff] [blame] | 1955 | RevertOutputFormatIfNeeded(outputFormat, config->mOutputFormat); | 
| Wonsik Kim | e75a5da | 2020-02-14 17:29:03 -0800 | [diff] [blame] | 1956 | } | 
|  | 1957 |  | 
| Wonsik Kim | fb7a767 | 2019-12-27 17:13:33 -0800 | [diff] [blame] | 1958 | (void)mChannel->start(nullptr, nullptr, [&]{ | 
|  | 1959 | Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig); | 
|  | 1960 | const std::unique_ptr<Config> &config = *configLocked; | 
|  | 1961 | return config->mBuffersBoundToCodec; | 
|  | 1962 | }()); | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1963 |  | 
|  | 1964 | { | 
|  | 1965 | Mutexed<State>::Locked state(mState); | 
|  | 1966 | if (state->get() != RESUMING) { | 
|  | 1967 | state.unlock(); | 
|  | 1968 | mCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL); | 
|  | 1969 | state.lock(); | 
|  | 1970 | return; | 
|  | 1971 | } | 
|  | 1972 | state->set(RUNNING); | 
|  | 1973 | } | 
|  | 1974 |  | 
|  | 1975 | (void)mChannel->requestInitialInputBuffers(); | 
|  | 1976 | } | 
|  | 1977 |  | 
| Wonsik Kim | aa484ac | 2019-02-13 16:54:02 -0800 | [diff] [blame] | 1978 | void CCodec::signalSetParameters(const sp<AMessage> &msg) { | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 1979 | std::shared_ptr<Codec2Client::Component> comp; | 
|  | 1980 | auto checkState = [this, &comp] { | 
|  | 1981 | Mutexed<State>::Locked state(mState); | 
|  | 1982 | if (state->get() == RELEASED) { | 
|  | 1983 | return INVALID_OPERATION; | 
|  | 1984 | } | 
|  | 1985 | comp = state->comp; | 
|  | 1986 | return OK; | 
|  | 1987 | }; | 
|  | 1988 | if (tryAndReportOnError(checkState) != OK) { | 
|  | 1989 | return; | 
|  | 1990 | } | 
|  | 1991 |  | 
| Wonsik Kim | aa484ac | 2019-02-13 16:54:02 -0800 | [diff] [blame] | 1992 | // NOTE: We used to ignore "bitrate" at setParameters; replicate | 
|  | 1993 | //       the behavior here. | 
|  | 1994 | sp<AMessage> params = msg; | 
|  | 1995 | int32_t bitrate; | 
|  | 1996 | if (params->findInt32(KEY_BIT_RATE, &bitrate)) { | 
|  | 1997 | params = msg->dup(); | 
|  | 1998 | params->removeEntryAt(params->findEntryByName(KEY_BIT_RATE)); | 
|  | 1999 | } | 
|  | 2000 |  | 
| Houxiang Dai | 5a97b47 | 2021-03-22 17:56:04 +0800 | [diff] [blame] | 2001 | int32_t syncId = 0; | 
|  | 2002 | if (params->findInt32("audio-hw-sync", &syncId) | 
|  | 2003 | || params->findInt32("hw-av-sync-id", &syncId)) { | 
|  | 2004 | configureTunneledVideoPlayback(comp, nullptr, params); | 
|  | 2005 | } | 
|  | 2006 |  | 
| Wonsik Kim | 155d5cb | 2019-10-09 12:49:49 -0700 | [diff] [blame] | 2007 | Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig); | 
|  | 2008 | const std::unique_ptr<Config> &config = *configLocked; | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 2009 |  | 
|  | 2010 | /** | 
|  | 2011 | * Handle input surface parameters | 
|  | 2012 | */ | 
|  | 2013 | if ((config->mDomain & (Config::IS_VIDEO | Config::IS_IMAGE)) | 
| Wonsik Kim | 8a6ed37 | 2019-12-03 16:05:51 -0800 | [diff] [blame] | 2014 | && (config->mDomain & Config::IS_ENCODER) | 
|  | 2015 | && config->mInputSurface && config->mISConfig) { | 
| Chong Zhang | 038e8f8 | 2019-02-06 19:05:14 -0800 | [diff] [blame] | 2016 | (void)params->findInt64(PARAMETER_KEY_OFFSET_TIME, &config->mISConfig->mTimeOffsetUs); | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 2017 |  | 
|  | 2018 | if (params->findInt64("skip-frames-before", &config->mISConfig->mStartAtUs)) { | 
|  | 2019 | config->mISConfig->mStopped = false; | 
|  | 2020 | } else if (params->findInt64("stop-time-us", &config->mISConfig->mStopAtUs)) { | 
|  | 2021 | config->mISConfig->mStopped = true; | 
|  | 2022 | } | 
|  | 2023 |  | 
|  | 2024 | int32_t value; | 
| Chong Zhang | 038e8f8 | 2019-02-06 19:05:14 -0800 | [diff] [blame] | 2025 | if (params->findInt32(PARAMETER_KEY_SUSPEND, &value)) { | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 2026 | config->mISConfig->mSuspended = value; | 
|  | 2027 | config->mISConfig->mSuspendAtUs = -1; | 
| Chong Zhang | 038e8f8 | 2019-02-06 19:05:14 -0800 | [diff] [blame] | 2028 | (void)params->findInt64(PARAMETER_KEY_SUSPEND_TIME, &config->mISConfig->mSuspendAtUs); | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 2029 | } | 
|  | 2030 |  | 
|  | 2031 | (void)config->mInputSurface->configure(*config->mISConfig); | 
|  | 2032 | if (config->mISConfig->mStopped) { | 
|  | 2033 | config->mInputFormat->setInt64( | 
|  | 2034 | "android._stop-time-offset-us", config->mISConfig->mInputDelayUs); | 
|  | 2035 | } | 
|  | 2036 | } | 
|  | 2037 |  | 
|  | 2038 | std::vector<std::unique_ptr<C2Param>> configUpdate; | 
|  | 2039 | (void)config->getConfigUpdateFromSdkParams( | 
|  | 2040 | comp, params, Config::IS_PARAM, C2_MAY_BLOCK, &configUpdate); | 
|  | 2041 | // Prefer to pass parameters to the buffer channel, so they can be synchronized with the frames. | 
|  | 2042 | // Parameter synchronization is not defined when using input surface. For now, route | 
|  | 2043 | // these directly to the component. | 
|  | 2044 | if (config->mInputSurface == nullptr | 
|  | 2045 | && (property_get_bool("debug.stagefright.ccodec_delayed_params", false) | 
|  | 2046 | || comp->getName().find("c2.android.") == 0)) { | 
|  | 2047 | mChannel->setParameters(configUpdate); | 
|  | 2048 | } else { | 
| Wonsik Kim | 970bf0b | 2020-11-10 11:54:15 -0800 | [diff] [blame] | 2049 | sp<AMessage> outputFormat = config->mOutputFormat; | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 2050 | (void)config->setParameters(comp, configUpdate, C2_MAY_BLOCK); | 
| Wonsik Kim | 970bf0b | 2020-11-10 11:54:15 -0800 | [diff] [blame] | 2051 | RevertOutputFormatIfNeeded(outputFormat, config->mOutputFormat); | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 2052 | } | 
|  | 2053 | } | 
|  | 2054 |  | 
|  | 2055 | void CCodec::signalEndOfInputStream() { | 
|  | 2056 | mCallback->onSignaledInputEOS(mChannel->signalEndOfInputStream()); | 
|  | 2057 | } | 
|  | 2058 |  | 
|  | 2059 | void CCodec::signalRequestIDRFrame() { | 
|  | 2060 | std::shared_ptr<Codec2Client::Component> comp; | 
|  | 2061 | { | 
|  | 2062 | Mutexed<State>::Locked state(mState); | 
|  | 2063 | if (state->get() == RELEASED) { | 
|  | 2064 | ALOGD("no IDR request sent since component is released"); | 
|  | 2065 | return; | 
|  | 2066 | } | 
|  | 2067 | comp = state->comp; | 
|  | 2068 | } | 
|  | 2069 | ALOGV("request IDR"); | 
| Wonsik Kim | 155d5cb | 2019-10-09 12:49:49 -0700 | [diff] [blame] | 2070 | Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig); | 
|  | 2071 | const std::unique_ptr<Config> &config = *configLocked; | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 2072 | std::vector<std::unique_ptr<C2Param>> params; | 
|  | 2073 | params.push_back( | 
|  | 2074 | std::make_unique<C2StreamRequestSyncFrameTuning::output>(0u, true)); | 
|  | 2075 | config->setParameters(comp, params, C2_MAY_BLOCK); | 
|  | 2076 | } | 
|  | 2077 |  | 
| Wonsik Kim | 874ad38 | 2021-03-12 09:59:36 -0800 | [diff] [blame] | 2078 | status_t CCodec::querySupportedParameters(std::vector<std::string> *names) { | 
|  | 2079 | Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig); | 
|  | 2080 | const std::unique_ptr<Config> &config = *configLocked; | 
|  | 2081 | return config->querySupportedParameters(names); | 
|  | 2082 | } | 
|  | 2083 |  | 
|  | 2084 | status_t CCodec::describeParameter( | 
|  | 2085 | const std::string &name, CodecParameterDescriptor *desc) { | 
|  | 2086 | Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig); | 
|  | 2087 | const std::unique_ptr<Config> &config = *configLocked; | 
|  | 2088 | return config->describe(name, desc); | 
|  | 2089 | } | 
|  | 2090 |  | 
|  | 2091 | status_t CCodec::subscribeToParameters(const std::vector<std::string> &names) { | 
|  | 2092 | std::shared_ptr<Codec2Client::Component> comp = mState.lock()->comp; | 
|  | 2093 | if (!comp) { | 
|  | 2094 | return INVALID_OPERATION; | 
|  | 2095 | } | 
|  | 2096 | Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig); | 
|  | 2097 | const std::unique_ptr<Config> &config = *configLocked; | 
|  | 2098 | return config->subscribeToVendorConfigUpdate(comp, names); | 
|  | 2099 | } | 
|  | 2100 |  | 
|  | 2101 | status_t CCodec::unsubscribeFromParameters(const std::vector<std::string> &names) { | 
|  | 2102 | std::shared_ptr<Codec2Client::Component> comp = mState.lock()->comp; | 
|  | 2103 | if (!comp) { | 
|  | 2104 | return INVALID_OPERATION; | 
|  | 2105 | } | 
|  | 2106 | Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig); | 
|  | 2107 | const std::unique_ptr<Config> &config = *configLocked; | 
|  | 2108 | return config->unsubscribeFromVendorConfigUpdate(comp, names); | 
|  | 2109 | } | 
|  | 2110 |  | 
| Wonsik Kim | ab34ed6 | 2019-01-31 15:28:46 -0800 | [diff] [blame] | 2111 | void CCodec::onWorkDone(std::list<std::unique_ptr<C2Work>> &workItems) { | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 2112 | if (!workItems.empty()) { | 
| Wonsik Kim | ab34ed6 | 2019-01-31 15:28:46 -0800 | [diff] [blame] | 2113 | Mutexed<std::list<std::unique_ptr<C2Work>>>::Locked queue(mWorkDoneQueue); | 
|  | 2114 | queue->splice(queue->end(), workItems); | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 2115 | } | 
|  | 2116 | (new AMessage(kWhatWorkDone, this))->post(); | 
|  | 2117 | } | 
|  | 2118 |  | 
| Wonsik Kim | ab34ed6 | 2019-01-31 15:28:46 -0800 | [diff] [blame] | 2119 | void CCodec::onInputBufferDone(uint64_t frameIndex, size_t arrayIndex) { | 
|  | 2120 | mChannel->onInputBufferDone(frameIndex, arrayIndex); | 
| Wonsik Kim | 4f3314d | 2019-03-26 17:00:34 -0700 | [diff] [blame] | 2121 | if (arrayIndex == 0) { | 
|  | 2122 | // We always put no more than one buffer per work, if we use an input surface. | 
| Wonsik Kim | 155d5cb | 2019-10-09 12:49:49 -0700 | [diff] [blame] | 2123 | Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig); | 
|  | 2124 | const std::unique_ptr<Config> &config = *configLocked; | 
| Wonsik Kim | 4f3314d | 2019-03-26 17:00:34 -0700 | [diff] [blame] | 2125 | if (config->mInputSurface) { | 
|  | 2126 | config->mInputSurface->onInputBufferDone(frameIndex); | 
|  | 2127 | } | 
|  | 2128 | } | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 2129 | } | 
|  | 2130 |  | 
|  | 2131 | void CCodec::onMessageReceived(const sp<AMessage> &msg) { | 
|  | 2132 | TimePoint now = std::chrono::steady_clock::now(); | 
|  | 2133 | CCodecWatchdog::getInstance()->watch(this); | 
|  | 2134 | switch (msg->what()) { | 
|  | 2135 | case kWhatAllocate: { | 
|  | 2136 | // C2ComponentStore::createComponent() should return within 100ms. | 
| Wonsik Kim | 9ee5a7c | 2019-06-17 11:33:24 -0700 | [diff] [blame] | 2137 | setDeadline(now, 1500ms, "allocate"); | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 2138 | sp<RefBase> obj; | 
|  | 2139 | CHECK(msg->findObject("codecInfo", &obj)); | 
|  | 2140 | allocate((MediaCodecInfo *)obj.get()); | 
|  | 2141 | break; | 
|  | 2142 | } | 
|  | 2143 | case kWhatConfigure: { | 
|  | 2144 | // C2Component::commit_sm() should return within 5ms. | 
| Wonsik Kim | 9ee5a7c | 2019-06-17 11:33:24 -0700 | [diff] [blame] | 2145 | setDeadline(now, 1500ms, "configure"); | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 2146 | sp<AMessage> format; | 
|  | 2147 | CHECK(msg->findMessage("format", &format)); | 
|  | 2148 | configure(format); | 
|  | 2149 | break; | 
|  | 2150 | } | 
|  | 2151 | case kWhatStart: { | 
|  | 2152 | // C2Component::start() should return within 500ms. | 
| Wonsik Kim | 9ee5a7c | 2019-06-17 11:33:24 -0700 | [diff] [blame] | 2153 | setDeadline(now, 1500ms, "start"); | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 2154 | start(); | 
|  | 2155 | break; | 
|  | 2156 | } | 
|  | 2157 | case kWhatStop: { | 
|  | 2158 | // C2Component::stop() should return within 500ms. | 
| Wonsik Kim | 9ee5a7c | 2019-06-17 11:33:24 -0700 | [diff] [blame] | 2159 | setDeadline(now, 1500ms, "stop"); | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 2160 | stop(); | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 2161 | break; | 
|  | 2162 | } | 
|  | 2163 | case kWhatFlush: { | 
|  | 2164 | // C2Component::flush_sm() should return within 5ms. | 
| Wonsik Kim | 9ee5a7c | 2019-06-17 11:33:24 -0700 | [diff] [blame] | 2165 | setDeadline(now, 1500ms, "flush"); | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 2166 | flush(); | 
|  | 2167 | break; | 
|  | 2168 | } | 
| Wonsik Kim | 936a89c | 2020-05-08 16:07:50 -0700 | [diff] [blame] | 2169 | case kWhatRelease: { | 
|  | 2170 | mChannel->release(); | 
|  | 2171 | mClient.reset(); | 
|  | 2172 | mClientListener.reset(); | 
|  | 2173 | break; | 
|  | 2174 | } | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 2175 | case kWhatCreateInputSurface: { | 
|  | 2176 | // Surface operations may be briefly blocking. | 
| Wonsik Kim | 9ee5a7c | 2019-06-17 11:33:24 -0700 | [diff] [blame] | 2177 | setDeadline(now, 1500ms, "createInputSurface"); | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 2178 | createInputSurface(); | 
|  | 2179 | break; | 
|  | 2180 | } | 
|  | 2181 | case kWhatSetInputSurface: { | 
|  | 2182 | // Surface operations may be briefly blocking. | 
| Wonsik Kim | 9ee5a7c | 2019-06-17 11:33:24 -0700 | [diff] [blame] | 2183 | setDeadline(now, 1500ms, "setInputSurface"); | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 2184 | sp<RefBase> obj; | 
|  | 2185 | CHECK(msg->findObject("surface", &obj)); | 
|  | 2186 | sp<PersistentSurface> surface(static_cast<PersistentSurface *>(obj.get())); | 
|  | 2187 | setInputSurface(surface); | 
|  | 2188 | break; | 
|  | 2189 | } | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 2190 | case kWhatWorkDone: { | 
|  | 2191 | std::unique_ptr<C2Work> work; | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 2192 | bool shouldPost = false; | 
|  | 2193 | { | 
|  | 2194 | Mutexed<std::list<std::unique_ptr<C2Work>>>::Locked queue(mWorkDoneQueue); | 
|  | 2195 | if (queue->empty()) { | 
|  | 2196 | break; | 
|  | 2197 | } | 
|  | 2198 | work.swap(queue->front()); | 
|  | 2199 | queue->pop_front(); | 
|  | 2200 | shouldPost = !queue->empty(); | 
|  | 2201 | } | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 2202 | if (shouldPost) { | 
|  | 2203 | (new AMessage(kWhatWorkDone, this))->post(); | 
|  | 2204 | } | 
|  | 2205 |  | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 2206 | // handle configuration changes in work done | 
| Wonsik Kim | 1f5063d | 2021-05-03 15:41:17 -0700 | [diff] [blame] | 2207 | std::shared_ptr<const C2StreamInitDataInfo::output> initData; | 
| Wonsik Kim | 75e22f4 | 2021-04-14 23:34:51 -0700 | [diff] [blame] | 2208 | sp<AMessage> outputFormat = nullptr; | 
|  | 2209 | { | 
|  | 2210 | Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig); | 
|  | 2211 | const std::unique_ptr<Config> &config = *configLocked; | 
|  | 2212 | Config::Watcher<C2StreamInitDataInfo::output> initDataWatcher = | 
|  | 2213 | config->watch<C2StreamInitDataInfo::output>(); | 
|  | 2214 | if (!work->worklets.empty() | 
|  | 2215 | && (work->worklets.front()->output.flags | 
|  | 2216 | & C2FrameData::FLAG_DISCARD_FRAME) == 0) { | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 2217 |  | 
| Wonsik Kim | 75e22f4 | 2021-04-14 23:34:51 -0700 | [diff] [blame] | 2218 | // copy buffer info to config | 
|  | 2219 | std::vector<std::unique_ptr<C2Param>> updates; | 
|  | 2220 | for (const std::unique_ptr<C2Param> ¶m | 
|  | 2221 | : work->worklets.front()->output.configUpdate) { | 
|  | 2222 | updates.push_back(C2Param::Copy(*param)); | 
|  | 2223 | } | 
|  | 2224 | unsigned stream = 0; | 
|  | 2225 | std::vector<std::shared_ptr<C2Buffer>> &outputBuffers = | 
|  | 2226 | work->worklets.front()->output.buffers; | 
|  | 2227 | for (const std::shared_ptr<C2Buffer> &buf : outputBuffers) { | 
|  | 2228 | for (const std::shared_ptr<const C2Info> &info : buf->info()) { | 
|  | 2229 | // move all info into output-stream #0 domain | 
|  | 2230 | updates.emplace_back( | 
|  | 2231 | C2Param::CopyAsStream(*info, true /* output */, stream)); | 
|  | 2232 | } | 
|  | 2233 |  | 
|  | 2234 | const std::vector<C2ConstGraphicBlock> blocks = buf->data().graphicBlocks(); | 
|  | 2235 | // for now only do the first block | 
|  | 2236 | if (!blocks.empty()) { | 
|  | 2237 | // ALOGV("got output buffer with crop %u,%u+%u,%u and size %u,%u", | 
|  | 2238 | //      block.crop().left, block.crop().top, | 
|  | 2239 | //      block.crop().width, block.crop().height, | 
|  | 2240 | //      block.width(), block.height()); | 
|  | 2241 | const C2ConstGraphicBlock &block = blocks[0]; | 
|  | 2242 | updates.emplace_back(new C2StreamCropRectInfo::output( | 
|  | 2243 | stream, block.crop())); | 
|  | 2244 | updates.emplace_back(new C2StreamPictureSizeInfo::output( | 
|  | 2245 | stream, block.crop().width, block.crop().height)); | 
|  | 2246 | } | 
|  | 2247 | ++stream; | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 2248 | } | 
| George Burgess IV | c813a59 | 2020-02-22 22:54:44 -0800 | [diff] [blame] | 2249 |  | 
| Wonsik Kim | 75e22f4 | 2021-04-14 23:34:51 -0700 | [diff] [blame] | 2250 | sp<AMessage> oldFormat = config->mOutputFormat; | 
|  | 2251 | config->updateConfiguration(updates, config->mOutputDomain); | 
|  | 2252 | RevertOutputFormatIfNeeded(oldFormat, config->mOutputFormat); | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 2253 |  | 
| Wonsik Kim | 75e22f4 | 2021-04-14 23:34:51 -0700 | [diff] [blame] | 2254 | // copy standard infos to graphic buffers if not already present (otherwise, we | 
|  | 2255 | // may overwrite the actual intermediate value with a final value) | 
|  | 2256 | stream = 0; | 
|  | 2257 | const static C2Param::Index stdGfxInfos[] = { | 
|  | 2258 | C2StreamRotationInfo::output::PARAM_TYPE, | 
|  | 2259 | C2StreamColorAspectsInfo::output::PARAM_TYPE, | 
|  | 2260 | C2StreamDataSpaceInfo::output::PARAM_TYPE, | 
|  | 2261 | C2StreamHdrStaticInfo::output::PARAM_TYPE, | 
|  | 2262 | C2StreamHdr10PlusInfo::output::PARAM_TYPE, | 
|  | 2263 | C2StreamPixelAspectRatioInfo::output::PARAM_TYPE, | 
|  | 2264 | C2StreamSurfaceScalingInfo::output::PARAM_TYPE | 
|  | 2265 | }; | 
|  | 2266 | for (const std::shared_ptr<C2Buffer> &buf : outputBuffers) { | 
|  | 2267 | if (buf->data().graphicBlocks().size()) { | 
|  | 2268 | for (C2Param::Index ix : stdGfxInfos) { | 
|  | 2269 | if (!buf->hasInfo(ix)) { | 
|  | 2270 | const C2Param *param = | 
|  | 2271 | config->getConfigParameterValue(ix.withStream(stream)); | 
|  | 2272 | if (param) { | 
|  | 2273 | std::shared_ptr<C2Param> info(C2Param::Copy(*param)); | 
|  | 2274 | buf->setInfo(std::static_pointer_cast<C2Info>(info)); | 
|  | 2275 | } | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 2276 | } | 
|  | 2277 | } | 
|  | 2278 | } | 
| Wonsik Kim | 75e22f4 | 2021-04-14 23:34:51 -0700 | [diff] [blame] | 2279 | ++stream; | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 2280 | } | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 2281 | } | 
| Wonsik Kim | 75e22f4 | 2021-04-14 23:34:51 -0700 | [diff] [blame] | 2282 | if (config->mInputSurface) { | 
| Brijesh Patel | ab46367 | 2020-11-25 15:38:28 +0530 | [diff] [blame] | 2283 | if (work->worklets.empty() | 
|  | 2284 | || !work->worklets.back() | 
|  | 2285 | || (work->worklets.back()->output.flags | 
|  | 2286 | & C2FrameData::FLAG_INCOMPLETE) == 0) { | 
|  | 2287 | config->mInputSurface->onInputBufferDone(work->input.ordinal.frameIndex); | 
|  | 2288 | } | 
| Wonsik Kim | 75e22f4 | 2021-04-14 23:34:51 -0700 | [diff] [blame] | 2289 | } | 
|  | 2290 | if (initDataWatcher.hasChanged()) { | 
| Wonsik Kim | 1f5063d | 2021-05-03 15:41:17 -0700 | [diff] [blame] | 2291 | initData = initDataWatcher.update(); | 
|  | 2292 | AmendOutputFormatWithCodecSpecificData( | 
|  | 2293 | initData->m.value, initData->flexCount(), config->mCodingMediaType, | 
|  | 2294 | config->mOutputFormat); | 
| Wonsik Kim | 75e22f4 | 2021-04-14 23:34:51 -0700 | [diff] [blame] | 2295 | } | 
|  | 2296 | outputFormat = config->mOutputFormat; | 
| Wonsik Kim | 4f3314d | 2019-03-26 17:00:34 -0700 | [diff] [blame] | 2297 | } | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 2298 | mChannel->onWorkDone( | 
| Wonsik Kim | 1f5063d | 2021-05-03 15:41:17 -0700 | [diff] [blame] | 2299 | std::move(work), outputFormat, initData ? initData.get() : nullptr); | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 2300 | break; | 
|  | 2301 | } | 
|  | 2302 | case kWhatWatch: { | 
|  | 2303 | // watch message already posted; no-op. | 
|  | 2304 | break; | 
|  | 2305 | } | 
|  | 2306 | default: { | 
|  | 2307 | ALOGE("unrecognized message"); | 
|  | 2308 | break; | 
|  | 2309 | } | 
|  | 2310 | } | 
|  | 2311 | setDeadline(TimePoint::max(), 0ms, "none"); | 
|  | 2312 | } | 
|  | 2313 |  | 
|  | 2314 | void CCodec::setDeadline( | 
|  | 2315 | const TimePoint &now, | 
|  | 2316 | const std::chrono::milliseconds &timeout, | 
|  | 2317 | const char *name) { | 
|  | 2318 | int32_t mult = std::max(1, property_get_int32("debug.stagefright.ccodec_timeout_mult", 1)); | 
|  | 2319 | Mutexed<NamedTimePoint>::Locked deadline(mDeadline); | 
|  | 2320 | deadline->set(now + (timeout * mult), name); | 
|  | 2321 | } | 
|  | 2322 |  | 
| ted.sun | 765db4d | 2020-06-23 14:03:41 +0800 | [diff] [blame] | 2323 | status_t CCodec::configureTunneledVideoPlayback( | 
|  | 2324 | std::shared_ptr<Codec2Client::Component> comp, | 
|  | 2325 | sp<NativeHandle> *sidebandHandle, | 
|  | 2326 | const sp<AMessage> &msg) { | 
|  | 2327 | std::vector<std::unique_ptr<C2SettingResult>> failures; | 
|  | 2328 |  | 
|  | 2329 | std::unique_ptr<C2PortTunneledModeTuning::output> tunneledPlayback = | 
|  | 2330 | C2PortTunneledModeTuning::output::AllocUnique( | 
|  | 2331 | 1, | 
|  | 2332 | C2PortTunneledModeTuning::Struct::SIDEBAND, | 
|  | 2333 | C2PortTunneledModeTuning::Struct::REALTIME, | 
|  | 2334 | 0); | 
|  | 2335 | // TODO: use KEY_AUDIO_HW_SYNC, KEY_HARDWARE_AV_SYNC_ID when they are in MediaCodecConstants.h | 
|  | 2336 | if (msg->findInt32("audio-hw-sync", &tunneledPlayback->m.syncId[0])) { | 
|  | 2337 | tunneledPlayback->m.syncType = C2PortTunneledModeTuning::Struct::sync_type_t::AUDIO_HW_SYNC; | 
|  | 2338 | } else if (msg->findInt32("hw-av-sync-id", &tunneledPlayback->m.syncId[0])) { | 
|  | 2339 | tunneledPlayback->m.syncType = C2PortTunneledModeTuning::Struct::sync_type_t::HW_AV_SYNC; | 
|  | 2340 | } else { | 
|  | 2341 | tunneledPlayback->m.syncType = C2PortTunneledModeTuning::Struct::sync_type_t::REALTIME; | 
|  | 2342 | tunneledPlayback->setFlexCount(0); | 
|  | 2343 | } | 
|  | 2344 | c2_status_t c2err = comp->config({ tunneledPlayback.get() }, C2_MAY_BLOCK, &failures); | 
|  | 2345 | if (c2err != C2_OK) { | 
|  | 2346 | return UNKNOWN_ERROR; | 
|  | 2347 | } | 
|  | 2348 |  | 
| Houxiang Dai | 5a97b47 | 2021-03-22 17:56:04 +0800 | [diff] [blame] | 2349 | if (sidebandHandle == nullptr) { | 
|  | 2350 | return OK; | 
|  | 2351 | } | 
|  | 2352 |  | 
| ted.sun | 765db4d | 2020-06-23 14:03:41 +0800 | [diff] [blame] | 2353 | std::vector<std::unique_ptr<C2Param>> params; | 
|  | 2354 | c2err = comp->query({}, {C2PortTunnelHandleTuning::output::PARAM_TYPE}, C2_DONT_BLOCK, ¶ms); | 
|  | 2355 | if (c2err == C2_OK && params.size() == 1u) { | 
|  | 2356 | C2PortTunnelHandleTuning::output *videoTunnelSideband = | 
|  | 2357 | C2PortTunnelHandleTuning::output::From(params[0].get()); | 
|  | 2358 | // Currently, Codec2 only supports non-fd case for sideband native_handle. | 
|  | 2359 | native_handle_t *handle = native_handle_create(0, videoTunnelSideband->flexCount()); | 
|  | 2360 | *sidebandHandle = NativeHandle::create(handle, true /* ownsHandle */); | 
|  | 2361 | if (handle != nullptr && videoTunnelSideband->flexCount()) { | 
|  | 2362 | memcpy(handle->data, videoTunnelSideband->m.values, | 
|  | 2363 | sizeof(int32_t) * videoTunnelSideband->flexCount()); | 
|  | 2364 | return OK; | 
|  | 2365 | } else { | 
|  | 2366 | return NO_MEMORY; | 
|  | 2367 | } | 
|  | 2368 | } | 
|  | 2369 | return UNKNOWN_ERROR; | 
|  | 2370 | } | 
|  | 2371 |  | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 2372 | void CCodec::initiateReleaseIfStuck() { | 
|  | 2373 | std::string name; | 
|  | 2374 | bool pendingDeadline = false; | 
| Wonsik Kim | ab34ed6 | 2019-01-31 15:28:46 -0800 | [diff] [blame] | 2375 | { | 
|  | 2376 | Mutexed<NamedTimePoint>::Locked deadline(mDeadline); | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 2377 | if (deadline->get() < std::chrono::steady_clock::now()) { | 
|  | 2378 | name = deadline->getName(); | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 2379 | } | 
|  | 2380 | if (deadline->get() != TimePoint::max()) { | 
|  | 2381 | pendingDeadline = true; | 
|  | 2382 | } | 
|  | 2383 | } | 
| Wonsik Kim | 75e22f4 | 2021-04-14 23:34:51 -0700 | [diff] [blame] | 2384 | bool tunneled = false; | 
| Wonsik Kim | abca11e | 2021-04-30 13:11:41 -0700 | [diff] [blame] | 2385 | bool isMediaTypeKnown = false; | 
| Wonsik Kim | 75e22f4 | 2021-04-14 23:34:51 -0700 | [diff] [blame] | 2386 | { | 
| Wonsik Kim | abca11e | 2021-04-30 13:11:41 -0700 | [diff] [blame] | 2387 | static const std::set<std::string> kKnownMediaTypes{ | 
|  | 2388 | MIMETYPE_VIDEO_VP8, | 
|  | 2389 | MIMETYPE_VIDEO_VP9, | 
|  | 2390 | MIMETYPE_VIDEO_AV1, | 
|  | 2391 | MIMETYPE_VIDEO_AVC, | 
|  | 2392 | MIMETYPE_VIDEO_HEVC, | 
|  | 2393 | MIMETYPE_VIDEO_MPEG4, | 
|  | 2394 | MIMETYPE_VIDEO_H263, | 
|  | 2395 | MIMETYPE_VIDEO_MPEG2, | 
|  | 2396 | MIMETYPE_VIDEO_RAW, | 
|  | 2397 | MIMETYPE_VIDEO_DOLBY_VISION, | 
|  | 2398 |  | 
|  | 2399 | MIMETYPE_AUDIO_AMR_NB, | 
|  | 2400 | MIMETYPE_AUDIO_AMR_WB, | 
|  | 2401 | MIMETYPE_AUDIO_MPEG, | 
|  | 2402 | MIMETYPE_AUDIO_AAC, | 
|  | 2403 | MIMETYPE_AUDIO_QCELP, | 
|  | 2404 | MIMETYPE_AUDIO_VORBIS, | 
|  | 2405 | MIMETYPE_AUDIO_OPUS, | 
|  | 2406 | MIMETYPE_AUDIO_G711_ALAW, | 
|  | 2407 | MIMETYPE_AUDIO_G711_MLAW, | 
|  | 2408 | MIMETYPE_AUDIO_RAW, | 
|  | 2409 | MIMETYPE_AUDIO_FLAC, | 
|  | 2410 | MIMETYPE_AUDIO_MSGSM, | 
|  | 2411 | MIMETYPE_AUDIO_AC3, | 
|  | 2412 | MIMETYPE_AUDIO_EAC3, | 
|  | 2413 |  | 
|  | 2414 | MIMETYPE_IMAGE_ANDROID_HEIC, | 
|  | 2415 | }; | 
| Wonsik Kim | 75e22f4 | 2021-04-14 23:34:51 -0700 | [diff] [blame] | 2416 | Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig); | 
|  | 2417 | const std::unique_ptr<Config> &config = *configLocked; | 
|  | 2418 | tunneled = config->mTunneled; | 
| Wonsik Kim | abca11e | 2021-04-30 13:11:41 -0700 | [diff] [blame] | 2419 | isMediaTypeKnown = (kKnownMediaTypes.count(config->mCodingMediaType) != 0); | 
| Wonsik Kim | 75e22f4 | 2021-04-14 23:34:51 -0700 | [diff] [blame] | 2420 | } | 
| Wonsik Kim | abca11e | 2021-04-30 13:11:41 -0700 | [diff] [blame] | 2421 | if (!tunneled && isMediaTypeKnown && name.empty()) { | 
| Wonsik Kim | ab34ed6 | 2019-01-31 15:28:46 -0800 | [diff] [blame] | 2422 | constexpr std::chrono::steady_clock::duration kWorkDurationThreshold = 3s; | 
|  | 2423 | std::chrono::steady_clock::duration elapsed = mChannel->elapsed(); | 
|  | 2424 | if (elapsed >= kWorkDurationThreshold) { | 
|  | 2425 | name = "queue"; | 
|  | 2426 | } | 
|  | 2427 | if (elapsed > 0s) { | 
|  | 2428 | pendingDeadline = true; | 
|  | 2429 | } | 
|  | 2430 | } | 
|  | 2431 | if (name.empty()) { | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 2432 | // We're not stuck. | 
|  | 2433 | if (pendingDeadline) { | 
|  | 2434 | // If we are not stuck yet but still has deadline coming up, | 
|  | 2435 | // post watch message to check back later. | 
|  | 2436 | (new AMessage(kWhatWatch, this))->post(); | 
|  | 2437 | } | 
|  | 2438 | return; | 
|  | 2439 | } | 
|  | 2440 |  | 
|  | 2441 | ALOGW("previous call to %s exceeded timeout", name.c_str()); | 
|  | 2442 | initiateRelease(false); | 
|  | 2443 | mCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL); | 
|  | 2444 | } | 
|  | 2445 |  | 
| Wonsik Kim | 155d5cb | 2019-10-09 12:49:49 -0700 | [diff] [blame] | 2446 | // static | 
|  | 2447 | PersistentSurface *CCodec::CreateInputSurface() { | 
| Pawin Vongmasa | 1858832 | 2019-05-18 01:52:13 -0700 | [diff] [blame] | 2448 | using namespace android; | 
| Wonsik Kim | 9917d4a | 2019-10-24 12:56:38 -0700 | [diff] [blame] | 2449 | using ::android::hardware::media::omx::V1_0::implementation::TWGraphicBufferSource; | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 2450 | // Attempt to create a Codec2's input surface. | 
| Pawin Vongmasa | 1858832 | 2019-05-18 01:52:13 -0700 | [diff] [blame] | 2451 | std::shared_ptr<Codec2Client::InputSurface> inputSurface = | 
|  | 2452 | Codec2Client::CreateInputSurface(); | 
| Lajos Molnar | 4711827 | 2019-01-31 16:28:04 -0800 | [diff] [blame] | 2453 | if (!inputSurface) { | 
| Pawin Vongmasa | 1858832 | 2019-05-18 01:52:13 -0700 | [diff] [blame] | 2454 | if (property_get_int32("debug.stagefright.c2inputsurface", 0) == -1) { | 
|  | 2455 | sp<IGraphicBufferProducer> gbp; | 
|  | 2456 | sp<OmxGraphicBufferSource> gbs = new OmxGraphicBufferSource(); | 
|  | 2457 | status_t err = gbs->initCheck(); | 
|  | 2458 | if (err != OK) { | 
|  | 2459 | ALOGE("Failed to create persistent input surface: error %d", err); | 
|  | 2460 | return nullptr; | 
|  | 2461 | } | 
|  | 2462 | return new PersistentSurface( | 
| Wonsik Kim | 9917d4a | 2019-10-24 12:56:38 -0700 | [diff] [blame] | 2463 | gbs->getIGraphicBufferProducer(), new TWGraphicBufferSource(gbs)); | 
| Pawin Vongmasa | 1858832 | 2019-05-18 01:52:13 -0700 | [diff] [blame] | 2464 | } else { | 
|  | 2465 | return nullptr; | 
|  | 2466 | } | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 2467 | } | 
| Pawin Vongmasa | 1858832 | 2019-05-18 01:52:13 -0700 | [diff] [blame] | 2468 | return new PersistentSurface( | 
| Lajos Molnar | 4711827 | 2019-01-31 16:28:04 -0800 | [diff] [blame] | 2469 | inputSurface->getGraphicBufferProducer(), | 
| Pawin Vongmasa | 1858832 | 2019-05-18 01:52:13 -0700 | [diff] [blame] | 2470 | static_cast<sp<android::hidl::base::V1_0::IBase>>( | 
| Lajos Molnar | 4711827 | 2019-01-31 16:28:04 -0800 | [diff] [blame] | 2471 | inputSurface->getHalInterface())); | 
| Pawin Vongmasa | 3665390 | 2018-11-15 00:10:25 -0800 | [diff] [blame] | 2472 | } | 
|  | 2473 |  | 
| Wonsik Kim | ffb889a | 2020-05-28 11:32:25 -0700 | [diff] [blame] | 2474 | class IntfCache { | 
|  | 2475 | public: | 
|  | 2476 | IntfCache() = default; | 
|  | 2477 |  | 
|  | 2478 | status_t init(const std::string &name) { | 
|  | 2479 | std::shared_ptr<Codec2Client::Interface> intf{ | 
|  | 2480 | Codec2Client::CreateInterfaceByName(name.c_str())}; | 
|  | 2481 | if (!intf) { | 
|  | 2482 | ALOGW("IntfCache [%s]: Unrecognized interface name", name.c_str()); | 
|  | 2483 | mInitStatus = NO_INIT; | 
|  | 2484 | return NO_INIT; | 
|  | 2485 | } | 
|  | 2486 | const static C2StreamUsageTuning::input sUsage{0u /* stream id */}; | 
|  | 2487 | mFields.push_back(C2FieldSupportedValuesQuery::Possible( | 
|  | 2488 | C2ParamField{&sUsage, &sUsage.value})); | 
|  | 2489 | c2_status_t err = intf->querySupportedValues(mFields, C2_MAY_BLOCK); | 
|  | 2490 | if (err != C2_OK) { | 
|  | 2491 | ALOGW("IntfCache [%s]: failed to query usage supported value (err=%d)", | 
|  | 2492 | name.c_str(), err); | 
|  | 2493 | mFields[0].status = err; | 
|  | 2494 | } | 
|  | 2495 | std::vector<std::unique_ptr<C2Param>> params; | 
|  | 2496 | err = intf->query( | 
|  | 2497 | {&mApiFeatures}, | 
|  | 2498 | {C2PortAllocatorsTuning::input::PARAM_TYPE}, | 
|  | 2499 | C2_MAY_BLOCK, | 
|  | 2500 | ¶ms); | 
|  | 2501 | if (err != C2_OK && err != C2_BAD_INDEX) { | 
|  | 2502 | ALOGW("IntfCache [%s]: failed to query api features (err=%d)", | 
|  | 2503 | name.c_str(), err); | 
|  | 2504 | } | 
|  | 2505 | while (!params.empty()) { | 
|  | 2506 | C2Param *param = params.back().release(); | 
|  | 2507 | params.pop_back(); | 
|  | 2508 | if (!param) { | 
|  | 2509 | continue; | 
|  | 2510 | } | 
|  | 2511 | if (param->type() == C2PortAllocatorsTuning::input::PARAM_TYPE) { | 
|  | 2512 | mInputAllocators.reset( | 
| Wonsik Kim | d79ee1f | 2020-08-27 17:41:56 -0700 | [diff] [blame] | 2513 | C2PortAllocatorsTuning::input::From(param)); | 
| Wonsik Kim | ffb889a | 2020-05-28 11:32:25 -0700 | [diff] [blame] | 2514 | } | 
|  | 2515 | } | 
|  | 2516 | mInitStatus = OK; | 
|  | 2517 | return OK; | 
| Wonsik Kim | fcf46c3 | 2020-04-22 13:50:45 -0700 | [diff] [blame] | 2518 | } | 
| Wonsik Kim | ffb889a | 2020-05-28 11:32:25 -0700 | [diff] [blame] | 2519 |  | 
|  | 2520 | status_t initCheck() const { return mInitStatus; } | 
|  | 2521 |  | 
|  | 2522 | const C2FieldSupportedValuesQuery &getUsageSupportedValues() const { | 
|  | 2523 | CHECK_EQ(1u, mFields.size()); | 
|  | 2524 | return mFields[0]; | 
|  | 2525 | } | 
|  | 2526 |  | 
|  | 2527 | const C2ApiFeaturesSetting &getApiFeatures() const { | 
|  | 2528 | return mApiFeatures; | 
|  | 2529 | } | 
|  | 2530 |  | 
|  | 2531 | const C2PortAllocatorsTuning::input &getInputAllocators() const { | 
|  | 2532 | static std::unique_ptr<C2PortAllocatorsTuning::input> sInvalidated = []{ | 
|  | 2533 | std::unique_ptr<C2PortAllocatorsTuning::input> param = | 
|  | 2534 | C2PortAllocatorsTuning::input::AllocUnique(0); | 
|  | 2535 | param->invalidate(); | 
|  | 2536 | return param; | 
|  | 2537 | }(); | 
|  | 2538 | return mInputAllocators ? *mInputAllocators : *sInvalidated; | 
|  | 2539 | } | 
|  | 2540 |  | 
|  | 2541 | private: | 
|  | 2542 | status_t mInitStatus{NO_INIT}; | 
|  | 2543 |  | 
|  | 2544 | std::vector<C2FieldSupportedValuesQuery> mFields; | 
|  | 2545 | C2ApiFeaturesSetting mApiFeatures; | 
|  | 2546 | std::unique_ptr<C2PortAllocatorsTuning::input> mInputAllocators; | 
|  | 2547 | }; | 
|  | 2548 |  | 
|  | 2549 | static const IntfCache &GetIntfCache(const std::string &name) { | 
|  | 2550 | static IntfCache sNullIntfCache; | 
|  | 2551 | static std::mutex sMutex; | 
|  | 2552 | static std::map<std::string, IntfCache> sCache; | 
|  | 2553 | std::unique_lock<std::mutex> lock{sMutex}; | 
|  | 2554 | auto it = sCache.find(name); | 
|  | 2555 | if (it == sCache.end()) { | 
|  | 2556 | lock.unlock(); | 
|  | 2557 | IntfCache intfCache; | 
|  | 2558 | status_t err = intfCache.init(name); | 
|  | 2559 | if (err != OK) { | 
|  | 2560 | return sNullIntfCache; | 
|  | 2561 | } | 
|  | 2562 | lock.lock(); | 
|  | 2563 | it = sCache.insert({name, std::move(intfCache)}).first; | 
|  | 2564 | } | 
|  | 2565 | return it->second; | 
| Wonsik Kim | fcf46c3 | 2020-04-22 13:50:45 -0700 | [diff] [blame] | 2566 | } | 
|  | 2567 |  | 
| Wonsik Kim | fb7a767 | 2019-12-27 17:13:33 -0800 | [diff] [blame] | 2568 | static status_t GetCommonAllocatorIds( | 
|  | 2569 | const std::vector<std::string> &names, | 
|  | 2570 | C2Allocator::type_t type, | 
|  | 2571 | std::set<C2Allocator::id_t> *ids) { | 
|  | 2572 | int poolMask = GetCodec2PoolMask(); | 
|  | 2573 | C2PlatformAllocatorStore::id_t preferredLinearId = GetPreferredLinearAllocatorId(poolMask); | 
|  | 2574 | C2Allocator::id_t defaultAllocatorId = | 
|  | 2575 | (type == C2Allocator::LINEAR) ? preferredLinearId : C2PlatformAllocatorStore::GRALLOC; | 
|  | 2576 |  | 
|  | 2577 | ids->clear(); | 
|  | 2578 | if (names.empty()) { | 
|  | 2579 | return OK; | 
|  | 2580 | } | 
| Wonsik Kim | fcf46c3 | 2020-04-22 13:50:45 -0700 | [diff] [blame] | 2581 | bool firstIteration = true; | 
|  | 2582 | for (const std::string &name : names) { | 
| Wonsik Kim | ffb889a | 2020-05-28 11:32:25 -0700 | [diff] [blame] | 2583 | const IntfCache &intfCache = GetIntfCache(name); | 
|  | 2584 | if (intfCache.initCheck() != OK) { | 
| Wonsik Kim | fcf46c3 | 2020-04-22 13:50:45 -0700 | [diff] [blame] | 2585 | continue; | 
| Wonsik Kim | fb7a767 | 2019-12-27 17:13:33 -0800 | [diff] [blame] | 2586 | } | 
| Wonsik Kim | ffb889a | 2020-05-28 11:32:25 -0700 | [diff] [blame] | 2587 | const C2PortAllocatorsTuning::input &allocators = intfCache.getInputAllocators(); | 
| Wonsik Kim | fcf46c3 | 2020-04-22 13:50:45 -0700 | [diff] [blame] | 2588 | if (firstIteration) { | 
|  | 2589 | firstIteration = false; | 
| Wonsik Kim | ffb889a | 2020-05-28 11:32:25 -0700 | [diff] [blame] | 2590 | if (allocators && allocators.flexCount() > 0) { | 
|  | 2591 | ids->insert(allocators.m.values, | 
|  | 2592 | allocators.m.values + allocators.flexCount()); | 
| Wonsik Kim | fcf46c3 | 2020-04-22 13:50:45 -0700 | [diff] [blame] | 2593 | } | 
|  | 2594 | if (ids->empty()) { | 
|  | 2595 | // The component does not advertise allocators. Use default. | 
|  | 2596 | ids->insert(defaultAllocatorId); | 
|  | 2597 | } | 
|  | 2598 | continue; | 
|  | 2599 | } | 
| Wonsik Kim | fb7a767 | 2019-12-27 17:13:33 -0800 | [diff] [blame] | 2600 | bool filtered = false; | 
| Wonsik Kim | ffb889a | 2020-05-28 11:32:25 -0700 | [diff] [blame] | 2601 | if (allocators && allocators.flexCount() > 0) { | 
|  | 2602 | filtered = true; | 
|  | 2603 | for (auto it = ids->begin(); it != ids->end(); ) { | 
|  | 2604 | bool found = false; | 
|  | 2605 | for (size_t j = 0; j < allocators.flexCount(); ++j) { | 
|  | 2606 | if (allocators.m.values[j] == *it) { | 
|  | 2607 | found = true; | 
|  | 2608 | break; | 
| Wonsik Kim | fb7a767 | 2019-12-27 17:13:33 -0800 | [diff] [blame] | 2609 | } | 
| Wonsik Kim | ffb889a | 2020-05-28 11:32:25 -0700 | [diff] [blame] | 2610 | } | 
|  | 2611 | if (found) { | 
|  | 2612 | ++it; | 
|  | 2613 | } else { | 
|  | 2614 | it = ids->erase(it); | 
| Wonsik Kim | fb7a767 | 2019-12-27 17:13:33 -0800 | [diff] [blame] | 2615 | } | 
|  | 2616 | } | 
|  | 2617 | } | 
|  | 2618 | if (!filtered) { | 
|  | 2619 | // The component does not advertise supported allocators. Use default. | 
|  | 2620 | bool containsDefault = (ids->count(defaultAllocatorId) > 0u); | 
|  | 2621 | if (ids->size() != (containsDefault ? 1 : 0)) { | 
|  | 2622 | ids->clear(); | 
|  | 2623 | if (containsDefault) { | 
|  | 2624 | ids->insert(defaultAllocatorId); | 
|  | 2625 | } | 
|  | 2626 | } | 
|  | 2627 | } | 
|  | 2628 | } | 
|  | 2629 | // Finally, filter with pool masks | 
|  | 2630 | for (auto it = ids->begin(); it != ids->end(); ) { | 
|  | 2631 | if ((poolMask >> *it) & 1) { | 
|  | 2632 | ++it; | 
|  | 2633 | } else { | 
|  | 2634 | it = ids->erase(it); | 
|  | 2635 | } | 
|  | 2636 | } | 
|  | 2637 | return OK; | 
|  | 2638 | } | 
|  | 2639 |  | 
|  | 2640 | static status_t CalculateMinMaxUsage( | 
|  | 2641 | const std::vector<std::string> &names, uint64_t *minUsage, uint64_t *maxUsage) { | 
|  | 2642 | static C2StreamUsageTuning::input sUsage{0u /* stream id */}; | 
|  | 2643 | *minUsage = 0; | 
|  | 2644 | *maxUsage = ~0ull; | 
|  | 2645 | for (const std::string &name : names) { | 
| Wonsik Kim | ffb889a | 2020-05-28 11:32:25 -0700 | [diff] [blame] | 2646 | const IntfCache &intfCache = GetIntfCache(name); | 
|  | 2647 | if (intfCache.initCheck() != OK) { | 
| Wonsik Kim | fcf46c3 | 2020-04-22 13:50:45 -0700 | [diff] [blame] | 2648 | continue; | 
|  | 2649 | } | 
| Wonsik Kim | ffb889a | 2020-05-28 11:32:25 -0700 | [diff] [blame] | 2650 | const C2FieldSupportedValuesQuery &usageSupportedValues = | 
|  | 2651 | intfCache.getUsageSupportedValues(); | 
|  | 2652 | if (usageSupportedValues.status != C2_OK) { | 
| Wonsik Kim | fb7a767 | 2019-12-27 17:13:33 -0800 | [diff] [blame] | 2653 | continue; | 
|  | 2654 | } | 
| Wonsik Kim | ffb889a | 2020-05-28 11:32:25 -0700 | [diff] [blame] | 2655 | const C2FieldSupportedValues &supported = usageSupportedValues.values; | 
| Wonsik Kim | fb7a767 | 2019-12-27 17:13:33 -0800 | [diff] [blame] | 2656 | if (supported.type != C2FieldSupportedValues::FLAGS) { | 
|  | 2657 | continue; | 
|  | 2658 | } | 
|  | 2659 | if (supported.values.empty()) { | 
|  | 2660 | *maxUsage = 0; | 
|  | 2661 | continue; | 
|  | 2662 | } | 
| Houxiang Dai | bfb8a72 | 2021-04-13 17:34:40 +0800 | [diff] [blame] | 2663 | if (supported.values.size() > 1) { | 
|  | 2664 | *minUsage |= supported.values[1].u64; | 
|  | 2665 | } else { | 
|  | 2666 | *minUsage |= supported.values[0].u64; | 
|  | 2667 | } | 
| Wonsik Kim | fb7a767 | 2019-12-27 17:13:33 -0800 | [diff] [blame] | 2668 | int64_t currentMaxUsage = 0; | 
|  | 2669 | for (const C2Value::Primitive &flags : supported.values) { | 
|  | 2670 | currentMaxUsage |= flags.u64; | 
|  | 2671 | } | 
|  | 2672 | *maxUsage &= currentMaxUsage; | 
|  | 2673 | } | 
|  | 2674 | return OK; | 
|  | 2675 | } | 
|  | 2676 |  | 
|  | 2677 | // static | 
|  | 2678 | status_t CCodec::CanFetchLinearBlock( | 
|  | 2679 | const std::vector<std::string> &names, const C2MemoryUsage &usage, bool *isCompatible) { | 
| Wonsik Kim | ffb889a | 2020-05-28 11:32:25 -0700 | [diff] [blame] | 2680 | for (const std::string &name : names) { | 
|  | 2681 | const IntfCache &intfCache = GetIntfCache(name); | 
|  | 2682 | if (intfCache.initCheck() != OK) { | 
|  | 2683 | continue; | 
|  | 2684 | } | 
|  | 2685 | const C2ApiFeaturesSetting &features = intfCache.getApiFeatures(); | 
|  | 2686 | if (features && !(features.value & API_SAME_INPUT_BUFFER)) { | 
|  | 2687 | *isCompatible = false; | 
|  | 2688 | return OK; | 
|  | 2689 | } | 
|  | 2690 | } | 
| Wonsik Kim | fb7a767 | 2019-12-27 17:13:33 -0800 | [diff] [blame] | 2691 | uint64_t minUsage = usage.expected; | 
|  | 2692 | uint64_t maxUsage = ~0ull; | 
|  | 2693 | std::set<C2Allocator::id_t> allocators; | 
|  | 2694 | GetCommonAllocatorIds(names, C2Allocator::LINEAR, &allocators); | 
|  | 2695 | if (allocators.empty()) { | 
|  | 2696 | *isCompatible = false; | 
|  | 2697 | return OK; | 
|  | 2698 | } | 
|  | 2699 | CalculateMinMaxUsage(names, &minUsage, &maxUsage); | 
|  | 2700 | *isCompatible = ((maxUsage & minUsage) == minUsage); | 
|  | 2701 | return OK; | 
|  | 2702 | } | 
|  | 2703 |  | 
|  | 2704 | static std::shared_ptr<C2BlockPool> GetPool(C2Allocator::id_t allocId) { | 
|  | 2705 | static std::mutex sMutex{}; | 
|  | 2706 | static std::map<C2Allocator::id_t, std::shared_ptr<C2BlockPool>> sPools; | 
|  | 2707 | std::unique_lock<std::mutex> lock{sMutex}; | 
|  | 2708 | std::shared_ptr<C2BlockPool> pool; | 
|  | 2709 | auto it = sPools.find(allocId); | 
|  | 2710 | if (it == sPools.end()) { | 
|  | 2711 | c2_status_t err = CreateCodec2BlockPool(allocId, nullptr, &pool); | 
|  | 2712 | if (err == OK) { | 
|  | 2713 | sPools.emplace(allocId, pool); | 
|  | 2714 | } else { | 
|  | 2715 | pool.reset(); | 
|  | 2716 | } | 
|  | 2717 | } else { | 
|  | 2718 | pool = it->second; | 
|  | 2719 | } | 
|  | 2720 | return pool; | 
|  | 2721 | } | 
|  | 2722 |  | 
|  | 2723 | // static | 
|  | 2724 | std::shared_ptr<C2LinearBlock> CCodec::FetchLinearBlock( | 
|  | 2725 | size_t capacity, const C2MemoryUsage &usage, const std::vector<std::string> &names) { | 
|  | 2726 | uint64_t minUsage = usage.expected; | 
|  | 2727 | uint64_t maxUsage = ~0ull; | 
|  | 2728 | std::set<C2Allocator::id_t> allocators; | 
|  | 2729 | GetCommonAllocatorIds(names, C2Allocator::LINEAR, &allocators); | 
|  | 2730 | if (allocators.empty()) { | 
|  | 2731 | allocators.insert(C2PlatformAllocatorStore::DEFAULT_LINEAR); | 
|  | 2732 | } | 
|  | 2733 | CalculateMinMaxUsage(names, &minUsage, &maxUsage); | 
|  | 2734 | if ((maxUsage & minUsage) != minUsage) { | 
|  | 2735 | allocators.clear(); | 
|  | 2736 | allocators.insert(C2PlatformAllocatorStore::DEFAULT_LINEAR); | 
|  | 2737 | } | 
|  | 2738 | std::shared_ptr<C2LinearBlock> block; | 
|  | 2739 | for (C2Allocator::id_t allocId : allocators) { | 
|  | 2740 | std::shared_ptr<C2BlockPool> pool = GetPool(allocId); | 
|  | 2741 | if (!pool) { | 
|  | 2742 | continue; | 
|  | 2743 | } | 
|  | 2744 | c2_status_t err = pool->fetchLinearBlock(capacity, C2MemoryUsage{minUsage}, &block); | 
|  | 2745 | if (err != C2_OK || !block) { | 
|  | 2746 | block.reset(); | 
|  | 2747 | continue; | 
|  | 2748 | } | 
|  | 2749 | break; | 
|  | 2750 | } | 
|  | 2751 | return block; | 
|  | 2752 | } | 
|  | 2753 |  | 
|  | 2754 | // static | 
|  | 2755 | status_t CCodec::CanFetchGraphicBlock( | 
|  | 2756 | const std::vector<std::string> &names, bool *isCompatible) { | 
|  | 2757 | uint64_t minUsage = 0; | 
|  | 2758 | uint64_t maxUsage = ~0ull; | 
|  | 2759 | std::set<C2Allocator::id_t> allocators; | 
|  | 2760 | GetCommonAllocatorIds(names, C2Allocator::GRAPHIC, &allocators); | 
|  | 2761 | if (allocators.empty()) { | 
|  | 2762 | *isCompatible = false; | 
|  | 2763 | return OK; | 
|  | 2764 | } | 
|  | 2765 | CalculateMinMaxUsage(names, &minUsage, &maxUsage); | 
|  | 2766 | *isCompatible = ((maxUsage & minUsage) == minUsage); | 
|  | 2767 | return OK; | 
|  | 2768 | } | 
|  | 2769 |  | 
|  | 2770 | // static | 
|  | 2771 | std::shared_ptr<C2GraphicBlock> CCodec::FetchGraphicBlock( | 
|  | 2772 | int32_t width, | 
|  | 2773 | int32_t height, | 
|  | 2774 | int32_t format, | 
|  | 2775 | uint64_t usage, | 
|  | 2776 | const std::vector<std::string> &names) { | 
|  | 2777 | uint32_t halPixelFormat = HAL_PIXEL_FORMAT_YCBCR_420_888; | 
|  | 2778 | if (!C2Mapper::mapPixelFormatFrameworkToCodec(format, &halPixelFormat)) { | 
|  | 2779 | ALOGD("Unrecognized pixel format: %d", format); | 
|  | 2780 | return nullptr; | 
|  | 2781 | } | 
|  | 2782 | uint64_t minUsage = 0; | 
|  | 2783 | uint64_t maxUsage = ~0ull; | 
|  | 2784 | std::set<C2Allocator::id_t> allocators; | 
|  | 2785 | GetCommonAllocatorIds(names, C2Allocator::GRAPHIC, &allocators); | 
|  | 2786 | if (allocators.empty()) { | 
|  | 2787 | allocators.insert(C2PlatformAllocatorStore::DEFAULT_GRAPHIC); | 
|  | 2788 | } | 
|  | 2789 | CalculateMinMaxUsage(names, &minUsage, &maxUsage); | 
|  | 2790 | minUsage |= usage; | 
|  | 2791 | if ((maxUsage & minUsage) != minUsage) { | 
|  | 2792 | allocators.clear(); | 
|  | 2793 | allocators.insert(C2PlatformAllocatorStore::DEFAULT_GRAPHIC); | 
|  | 2794 | } | 
|  | 2795 | std::shared_ptr<C2GraphicBlock> block; | 
|  | 2796 | for (C2Allocator::id_t allocId : allocators) { | 
|  | 2797 | std::shared_ptr<C2BlockPool> pool; | 
|  | 2798 | c2_status_t err = CreateCodec2BlockPool(allocId, nullptr, &pool); | 
|  | 2799 | if (err != C2_OK || !pool) { | 
|  | 2800 | continue; | 
|  | 2801 | } | 
|  | 2802 | err = pool->fetchGraphicBlock( | 
|  | 2803 | width, height, halPixelFormat, C2MemoryUsage{minUsage}, &block); | 
|  | 2804 | if (err != C2_OK || !block) { | 
|  | 2805 | block.reset(); | 
|  | 2806 | continue; | 
|  | 2807 | } | 
|  | 2808 | break; | 
|  | 2809 | } | 
|  | 2810 | return block; | 
|  | 2811 | } | 
|  | 2812 |  | 
| Wonsik Kim | 155d5cb | 2019-10-09 12:49:49 -0700 | [diff] [blame] | 2813 | }  // namespace android |