blob: 2b9ec7d6e28313e0da557a5567edca6698b396ce [file] [log] [blame]
Pawin Vongmasa36653902018-11-15 00:10:25 -08001/*
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 Vongmasa36653902018-11-15 00:10:25 -080029#include <android/IOMXBufferSource.h>
Pawin Vongmasabf69de92019-10-29 06:21:27 -070030#include <android/hardware/media/c2/1.0/IInputSurface.h>
Pawin Vongmasa36653902018-11-15 00:10:25 -080031#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 Kim9917d4a2019-10-24 12:56:38 -070038#include <media/omx/1.0/WOmxNode.h>
39#include <media/openmax/OMX_Core.h>
Pawin Vongmasa36653902018-11-15 00:10:25 -080040#include <media/openmax/OMX_IndexExt.h>
Wonsik Kim1f5063d2021-05-03 15:41:17 -070041#include <media/stagefright/foundation/avc_utils.h>
Wonsik Kim9917d4a2019-10-24 12:56:38 -070042#include <media/stagefright/omx/1.0/WGraphicBufferSource.h>
43#include <media/stagefright/omx/OmxGraphicBufferSource.h>
Wonsik Kim155d5cb2019-10-09 12:49:49 -070044#include <media/stagefright/CCodec.h>
Pawin Vongmasa36653902018-11-15 00:10:25 -080045#include <media/stagefright/BufferProducerWrapper.h>
46#include <media/stagefright/MediaCodecConstants.h>
47#include <media/stagefright/PersistentSurface.h>
ted.sun765db4d2020-06-23 14:03:41 +080048#include <utils/NativeHandle.h>
Pawin Vongmasa36653902018-11-15 00:10:25 -080049
50#include "C2OMXNode.h"
Pawin Vongmasa36653902018-11-15 00:10:25 -080051#include "CCodecBufferChannel.h"
Wonsik Kim155d5cb2019-10-09 12:49:49 -070052#include "CCodecConfig.h"
Wonsik Kimfb7a7672019-12-27 17:13:33 -080053#include "Codec2Mapper.h"
Pawin Vongmasa36653902018-11-15 00:10:25 -080054#include "InputSurfaceWrapper.h"
55
56extern "C" android::PersistentSurface *CreateInputSurface();
57
58namespace android {
59
60using namespace std::chrono_literals;
61using ::android::hardware::graphics::bufferqueue::V1_0::utils::H2BGraphicBufferProducer;
62using android::base::StringPrintf;
Pawin Vongmasad0f0e142018-11-15 03:36:28 -080063using ::android::hardware::media::c2::V1_0::IInputSurface;
Pawin Vongmasa36653902018-11-15 00:10:25 -080064
Wonsik Kim9917d4a2019-10-24 12:56:38 -070065typedef hardware::media::omx::V1_0::IGraphicBufferSource HGraphicBufferSource;
Wonsik Kim155d5cb2019-10-09 12:49:49 -070066typedef CCodecConfig Config;
Wonsik Kim9917d4a2019-10-24 12:56:38 -070067
Pawin Vongmasa36653902018-11-15 00:10:25 -080068namespace {
69
70class CCodecWatchdog : public AHandler {
71private:
72 enum {
73 kWhatWatch,
74 };
75 constexpr static int64_t kWatchIntervalUs = 3300000; // 3.3 secs
76
77public:
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
103protected:
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
126private:
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
141class C2InputSurfaceWrapper : public InputSurfaceWrapper {
142public:
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 Vongmasa1c75a232019-01-09 04:41:52 -0800154 return toStatusT(comp->connectToInputSurface(mSurface, &mConnection));
Pawin Vongmasa36653902018-11-15 00:10:25 -0800155 }
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 Vongmasa1c75a232019-01-09 04:41:52 -0800172 c2_status_t err = mSurface->config({&eos}, C2_MAY_BLOCK, &failures);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800173 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
184private:
185 std::shared_ptr<Codec2Client::InputSurface> mSurface;
186 std::shared_ptr<Codec2Client::InputSurfaceConnection> mConnection;
187};
188
189class GraphicBufferSourceWrapper : public InputSurfaceWrapper {
190public:
Wonsik Kim9917d4a2019-10-24 12:56:38 -0700191 typedef hardware::media::omx::V1_0::Status OmxStatus;
192
Pawin Vongmasa36653902018-11-15 00:10:25 -0800193 GraphicBufferSourceWrapper(
Wonsik Kim9917d4a2019-10-24 12:56:38 -0700194 const sp<HGraphicBufferSource> &source,
Pawin Vongmasa36653902018-11-15 00:10:25 -0800195 uint32_t width,
Wonsik Kim9eac4d12019-05-23 12:58:48 -0700196 uint32_t height,
197 uint64_t usage)
Pawin Vongmasa36653902018-11-15 00:10:25 -0800198 : mSource(source), mWidth(width), mHeight(height) {
199 mDataSpace = HAL_DATASPACE_BT709;
Wonsik Kim9eac4d12019-05-23 12:58:48 -0700200 mConfig.mUsage = usage;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800201 }
202 ~GraphicBufferSourceWrapper() override = default;
203
204 status_t connect(const std::shared_ptr<Codec2Client::Component> &comp) override {
205 mNode = new C2OMXNode(comp);
Wonsik Kim9917d4a2019-10-24 12:56:38 -0700206 mOmxNode = new hardware::media::omx::V1_0::utils::TWOmxNode(mNode);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800207 mNode->setFrameSize(mWidth, mHeight);
208
Wonsik Kim9eac4d12019-05-23 12:58:48 -0700209 // 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
Yanqiang Fanc56f3e62021-09-28 16:54:07 +0800215 return GetStatus(mSource->configure(
216 mOmxNode, static_cast<hardware::graphics::common::V1_0::Dataspace>(mDataSpace)));
Pawin Vongmasa36653902018-11-15 00:10:25 -0800217 }
218
219 void disconnect() override {
220 if (mNode == nullptr) {
221 return;
222 }
223 sp<IOMXBufferSource> source = mNode->getSource();
224 if (source == nullptr) {
225 ALOGD("GBSWrapper::disconnect: node is not configured with OMXBufferSource.");
226 return;
227 }
228 source->onOmxIdle();
229 source->onOmxLoaded();
230 mNode.clear();
Wonsik Kim9917d4a2019-10-24 12:56:38 -0700231 mOmxNode.clear();
Pawin Vongmasa36653902018-11-15 00:10:25 -0800232 }
233
Wonsik Kim9917d4a2019-10-24 12:56:38 -0700234 status_t GetStatus(hardware::Return<OmxStatus> &&status) {
235 if (status.isOk()) {
236 return static_cast<status_t>(status.withDefault(OmxStatus::UNKNOWN_ERROR));
237 } else if (status.isDeadObject()) {
238 return DEAD_OBJECT;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800239 }
Wonsik Kim9917d4a2019-10-24 12:56:38 -0700240 return UNKNOWN_ERROR;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800241 }
242
243 status_t start() override {
244 sp<IOMXBufferSource> source = mNode->getSource();
245 if (source == nullptr) {
246 return NO_INIT;
247 }
Taehwan Kim8b3bcdd2020-11-26 22:40:40 +0900248
Wonsik Kim0f6b61d2021-01-05 18:55:22 -0800249 size_t numSlots = 16;
Wonsik Kim34d66012021-03-01 16:40:33 -0800250 constexpr OMX_U32 kPortIndexInput = 0;
Taehwan Kim8b3bcdd2020-11-26 22:40:40 +0900251
Wonsik Kim34d66012021-03-01 16:40:33 -0800252 OMX_PARAM_PORTDEFINITIONTYPE param;
253 param.nPortIndex = kPortIndexInput;
254 status_t err = mNode->getParameter(OMX_IndexParamPortDefinition,
255 &param, sizeof(param));
256 if (err == OK) {
257 numSlots = param.nBufferCountActual;
Taehwan Kim8b3bcdd2020-11-26 22:40:40 +0900258 }
259
260 for (size_t i = 0; i < numSlots; ++i) {
Pawin Vongmasa36653902018-11-15 00:10:25 -0800261 source->onInputBufferAdded(i);
262 }
263
264 source->onOmxExecuting();
265 return OK;
266 }
267
268 status_t signalEndOfInputStream() override {
269 return GetStatus(mSource->signalEndOfInputStream());
270 }
271
272 status_t configure(Config &config) {
273 std::stringstream status;
274 status_t err = OK;
275
276 // handle each configuration granually, in case we need to handle part of the configuration
277 // elsewhere
278
279 // TRICKY: we do not unset frame delay repeating
280 if (config.mMinFps > 0 && config.mMinFps != mConfig.mMinFps) {
281 int64_t us = 1e6 / config.mMinFps + 0.5;
282 status_t res = GetStatus(mSource->setRepeatPreviousFrameDelayUs(us));
283 status << " minFps=" << config.mMinFps << " => repeatDelayUs=" << us;
284 if (res != OK) {
285 status << " (=> " << asString(res) << ")";
286 err = res;
287 }
288 mConfig.mMinFps = config.mMinFps;
289 }
290
291 // pts gap
292 if (config.mMinAdjustedFps > 0 || config.mFixedAdjustedFps > 0) {
293 if (mNode != nullptr) {
294 OMX_PARAM_U32TYPE ptrGapParam = {};
295 ptrGapParam.nSize = sizeof(OMX_PARAM_U32TYPE);
Wonsik Kim95ba0162019-03-19 15:51:54 -0700296 float gap = (config.mMinAdjustedFps > 0)
Pawin Vongmasa36653902018-11-15 00:10:25 -0800297 ? c2_min(INT32_MAX + 0., 1e6 / config.mMinAdjustedFps + 0.5)
298 : c2_max(0. - INT32_MAX, -1e6 / config.mFixedAdjustedFps - 0.5);
Wonsik Kim95ba0162019-03-19 15:51:54 -0700299 // float -> uint32_t is undefined if the value is negative.
300 // First convert to int32_t to ensure the expected behavior.
301 ptrGapParam.nU32 = int32_t(gap);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800302 (void)mNode->setParameter(
303 (OMX_INDEXTYPE)OMX_IndexParamMaxFrameDurationForBitrateControl,
304 &ptrGapParam, sizeof(ptrGapParam));
305 }
306 }
307
308 // max fps
309 // TRICKY: we do not unset max fps to 0 unless using fixed fps
Wonsik Kim95ba0162019-03-19 15:51:54 -0700310 if ((config.mMaxFps > 0 || (config.mFixedAdjustedFps > 0 && config.mMaxFps == -1))
Pawin Vongmasa36653902018-11-15 00:10:25 -0800311 && config.mMaxFps != mConfig.mMaxFps) {
312 status_t res = GetStatus(mSource->setMaxFps(config.mMaxFps));
313 status << " maxFps=" << config.mMaxFps;
314 if (res != OK) {
315 status << " (=> " << asString(res) << ")";
316 err = res;
317 }
318 mConfig.mMaxFps = config.mMaxFps;
319 }
320
321 if (config.mTimeOffsetUs != mConfig.mTimeOffsetUs) {
322 status_t res = GetStatus(mSource->setTimeOffsetUs(config.mTimeOffsetUs));
323 status << " timeOffset " << config.mTimeOffsetUs << "us";
324 if (res != OK) {
325 status << " (=> " << asString(res) << ")";
326 err = res;
327 }
328 mConfig.mTimeOffsetUs = config.mTimeOffsetUs;
329 }
330
331 if (config.mCaptureFps != mConfig.mCaptureFps || config.mCodedFps != mConfig.mCodedFps) {
332 status_t res =
333 GetStatus(mSource->setTimeLapseConfig(config.mCodedFps, config.mCaptureFps));
334 status << " timeLapse " << config.mCaptureFps << "fps as " << config.mCodedFps << "fps";
335 if (res != OK) {
336 status << " (=> " << asString(res) << ")";
337 err = res;
338 }
339 mConfig.mCaptureFps = config.mCaptureFps;
340 mConfig.mCodedFps = config.mCodedFps;
341 }
342
343 if (config.mStartAtUs != mConfig.mStartAtUs
344 || (config.mStopped != mConfig.mStopped && !config.mStopped)) {
345 status_t res = GetStatus(mSource->setStartTimeUs(config.mStartAtUs));
346 status << " start at " << config.mStartAtUs << "us";
347 if (res != OK) {
348 status << " (=> " << asString(res) << ")";
349 err = res;
350 }
351 mConfig.mStartAtUs = config.mStartAtUs;
352 mConfig.mStopped = config.mStopped;
353 }
354
355 // suspend-resume
356 if (config.mSuspended != mConfig.mSuspended) {
357 status_t res = GetStatus(mSource->setSuspend(config.mSuspended, config.mSuspendAtUs));
358 status << " " << (config.mSuspended ? "suspend" : "resume")
359 << " at " << config.mSuspendAtUs << "us";
360 if (res != OK) {
361 status << " (=> " << asString(res) << ")";
362 err = res;
363 }
364 mConfig.mSuspended = config.mSuspended;
365 mConfig.mSuspendAtUs = config.mSuspendAtUs;
366 }
367
368 if (config.mStopped != mConfig.mStopped && config.mStopped) {
369 status_t res = GetStatus(mSource->setStopTimeUs(config.mStopAtUs));
370 status << " stop at " << config.mStopAtUs << "us";
371 if (res != OK) {
372 status << " (=> " << asString(res) << ")";
373 err = res;
374 } else {
375 status << " delayUs";
Wonsik Kim9917d4a2019-10-24 12:56:38 -0700376 hardware::Return<void> trans = mSource->getStopTimeOffsetUs(
377 [&res, &delayUs = config.mInputDelayUs](
378 auto status, auto stopTimeOffsetUs) {
379 res = static_cast<status_t>(status);
380 delayUs = stopTimeOffsetUs;
381 });
382 if (!trans.isOk()) {
383 res = trans.isDeadObject() ? DEAD_OBJECT : UNKNOWN_ERROR;
384 }
Pawin Vongmasa36653902018-11-15 00:10:25 -0800385 if (res != OK) {
386 status << " (=> " << asString(res) << ")";
387 } else {
388 status << "=" << config.mInputDelayUs << "us";
389 }
390 mConfig.mInputDelayUs = config.mInputDelayUs;
391 }
392 mConfig.mStopAtUs = config.mStopAtUs;
393 mConfig.mStopped = config.mStopped;
394 }
395
396 // color aspects (android._color-aspects)
397
Wonsik Kim9eac4d12019-05-23 12:58:48 -0700398 // consumer usage is queried earlier.
399
Wonsik Kima1335e12021-04-22 16:28:29 -0700400 // priority
401 if (mConfig.mPriority != config.mPriority) {
402 if (config.mPriority != INT_MAX) {
403 mNode->setPriority(config.mPriority);
404 }
405 mConfig.mPriority = config.mPriority;
406 }
407
Wonsik Kimbd557932019-07-02 15:51:20 -0700408 if (status.str().empty()) {
409 ALOGD("ISConfig not changed");
410 } else {
411 ALOGD("ISConfig%s", status.str().c_str());
412 }
Pawin Vongmasa36653902018-11-15 00:10:25 -0800413 return err;
414 }
415
Wonsik Kim4f3314d2019-03-26 17:00:34 -0700416 void onInputBufferDone(c2_cntr64_t index) override {
417 mNode->onInputBufferDone(index);
418 }
419
Wonsik Kim673dd192021-01-29 14:58:12 -0800420 android_dataspace getDataspace() override {
421 return mNode->getDataspace();
422 }
423
Pawin Vongmasa36653902018-11-15 00:10:25 -0800424private:
Wonsik Kim9917d4a2019-10-24 12:56:38 -0700425 sp<HGraphicBufferSource> mSource;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800426 sp<C2OMXNode> mNode;
Wonsik Kim9917d4a2019-10-24 12:56:38 -0700427 sp<hardware::media::omx::V1_0::IOmxNode> mOmxNode;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800428 uint32_t mWidth;
429 uint32_t mHeight;
430 Config mConfig;
431};
432
433class Codec2ClientInterfaceWrapper : public C2ComponentStore {
434 std::shared_ptr<Codec2Client> mClient;
435
436public:
437 Codec2ClientInterfaceWrapper(std::shared_ptr<Codec2Client> client)
438 : mClient(client) { }
439
440 virtual ~Codec2ClientInterfaceWrapper() = default;
441
442 virtual c2_status_t config_sm(
443 const std::vector<C2Param *> &params,
444 std::vector<std::unique_ptr<C2SettingResult>> *const failures) {
445 return mClient->config(params, C2_MAY_BLOCK, failures);
446 };
447
448 virtual c2_status_t copyBuffer(
449 std::shared_ptr<C2GraphicBuffer>,
450 std::shared_ptr<C2GraphicBuffer>) {
451 return C2_OMITTED;
452 }
453
454 virtual c2_status_t createComponent(
455 C2String, std::shared_ptr<C2Component> *const component) {
456 component->reset();
457 return C2_OMITTED;
458 }
459
460 virtual c2_status_t createInterface(
461 C2String, std::shared_ptr<C2ComponentInterface> *const interface) {
462 interface->reset();
463 return C2_OMITTED;
464 }
465
466 virtual c2_status_t query_sm(
467 const std::vector<C2Param *> &stackParams,
468 const std::vector<C2Param::Index> &heapParamIndices,
469 std::vector<std::unique_ptr<C2Param>> *const heapParams) const {
470 return mClient->query(stackParams, heapParamIndices, C2_MAY_BLOCK, heapParams);
471 }
472
473 virtual c2_status_t querySupportedParams_nb(
474 std::vector<std::shared_ptr<C2ParamDescriptor>> *const params) const {
475 return mClient->querySupportedParams(params);
476 }
477
478 virtual c2_status_t querySupportedValues_sm(
479 std::vector<C2FieldSupportedValuesQuery> &fields) const {
480 return mClient->querySupportedValues(fields, C2_MAY_BLOCK);
481 }
482
483 virtual C2String getName() const {
484 return mClient->getName();
485 }
486
487 virtual std::shared_ptr<C2ParamReflector> getParamReflector() const {
488 return mClient->getParamReflector();
489 }
490
491 virtual std::vector<std::shared_ptr<const C2Component::Traits>> listComponents() {
492 return std::vector<std::shared_ptr<const C2Component::Traits>>();
493 }
494};
495
Wonsik Kim3b4349a2020-11-10 11:54:15 -0800496void RevertOutputFormatIfNeeded(
497 const sp<AMessage> &oldFormat, sp<AMessage> &currentFormat) {
498 // We used to not report changes to these keys to the client.
499 const static std::set<std::string> sIgnoredKeys({
500 KEY_BIT_RATE,
Harish Mahendrakar8c537502021-02-23 21:20:22 -0800501 KEY_FRAME_RATE,
Wonsik Kim3b4349a2020-11-10 11:54:15 -0800502 KEY_MAX_BIT_RATE,
Harish Mahendrakar8c537502021-02-23 21:20:22 -0800503 KEY_MAX_WIDTH,
504 KEY_MAX_HEIGHT,
Wonsik Kim3b4349a2020-11-10 11:54:15 -0800505 "csd-0",
506 "csd-1",
507 "csd-2",
508 });
509 if (currentFormat == oldFormat) {
510 return;
511 }
512 sp<AMessage> diff = currentFormat->changesFrom(oldFormat);
513 AMessage::Type type;
514 for (size_t i = diff->countEntries(); i > 0; --i) {
515 if (sIgnoredKeys.count(diff->getEntryNameAt(i - 1, &type)) > 0) {
516 diff->removeEntryAt(i - 1);
517 }
518 }
519 if (diff->countEntries() == 0) {
520 currentFormat = oldFormat;
521 }
522}
523
Wonsik Kim1f5063d2021-05-03 15:41:17 -0700524void AmendOutputFormatWithCodecSpecificData(
Greg Kaiserf2572aa2021-05-10 12:50:27 -0700525 const uint8_t *data, size_t size, const std::string &mediaType,
Wonsik Kim1f5063d2021-05-03 15:41:17 -0700526 const sp<AMessage> &outputFormat) {
527 if (mediaType == MIMETYPE_VIDEO_AVC) {
528 // Codec specific data should be SPS and PPS in a single buffer,
529 // each prefixed by a startcode (0x00 0x00 0x00 0x01).
530 // We separate the two and put them into the output format
531 // under the keys "csd-0" and "csd-1".
532
533 unsigned csdIndex = 0;
534
535 const uint8_t *nalStart;
536 size_t nalSize;
537 while (getNextNALUnit(&data, &size, &nalStart, &nalSize, true) == OK) {
538 sp<ABuffer> csd = new ABuffer(nalSize + 4);
539 memcpy(csd->data(), "\x00\x00\x00\x01", 4);
540 memcpy(csd->data() + 4, nalStart, nalSize);
541
542 outputFormat->setBuffer(
543 AStringPrintf("csd-%u", csdIndex).c_str(), csd);
544
545 ++csdIndex;
546 }
547
548 if (csdIndex != 2) {
549 ALOGW("Expected two NAL units from AVC codec config, but %u found",
550 csdIndex);
551 }
552 } else {
553 // For everything else we just stash the codec specific data into
554 // the output format as a single piece of csd under "csd-0".
555 sp<ABuffer> csd = new ABuffer(size);
556 memcpy(csd->data(), data, size);
557 csd->setRange(0, size);
558 outputFormat->setBuffer("csd-0", csd);
559 }
560}
561
Pawin Vongmasa36653902018-11-15 00:10:25 -0800562} // namespace
563
564// CCodec::ClientListener
565
566struct CCodec::ClientListener : public Codec2Client::Listener {
567
568 explicit ClientListener(const wp<CCodec> &codec) : mCodec(codec) {}
569
570 virtual void onWorkDone(
571 const std::weak_ptr<Codec2Client::Component>& component,
Wonsik Kimab34ed62019-01-31 15:28:46 -0800572 std::list<std::unique_ptr<C2Work>>& workItems) override {
Pawin Vongmasa36653902018-11-15 00:10:25 -0800573 (void)component;
574 sp<CCodec> codec(mCodec.promote());
575 if (!codec) {
576 return;
577 }
Wonsik Kimab34ed62019-01-31 15:28:46 -0800578 codec->onWorkDone(workItems);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800579 }
580
581 virtual void onTripped(
582 const std::weak_ptr<Codec2Client::Component>& component,
583 const std::vector<std::shared_ptr<C2SettingResult>>& settingResult
584 ) override {
585 // TODO
586 (void)component;
587 (void)settingResult;
588 }
589
590 virtual void onError(
591 const std::weak_ptr<Codec2Client::Component>& component,
592 uint32_t errorCode) override {
Praveen Chavan72eff012020-11-20 23:20:28 -0800593 {
594 // Component is only used for reporting as we use a separate listener for each instance
595 std::shared_ptr<Codec2Client::Component> comp = component.lock();
596 if (!comp) {
597 ALOGD("Component died with error: 0x%x", errorCode);
598 } else {
599 ALOGD("Component \"%s\" returned error: 0x%x", comp->getName().c_str(), errorCode);
600 }
601 }
602
603 // Report to MediaCodec
Wonsik Kim10f33c02021-03-04 15:04:14 -0800604 // Note: for now we do not propagate the error code to MediaCodec
605 // except for C2_NO_MEMORY, as we would need to translate to a MediaCodec error.
Praveen Chavan72eff012020-11-20 23:20:28 -0800606 sp<CCodec> codec(mCodec.promote());
607 if (!codec || !codec->mCallback) {
608 return;
609 }
Wonsik Kim10f33c02021-03-04 15:04:14 -0800610 codec->mCallback->onError(
611 errorCode == C2_NO_MEMORY ? NO_MEMORY : UNKNOWN_ERROR,
612 ACTION_CODE_FATAL);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800613 }
614
615 virtual void onDeath(
616 const std::weak_ptr<Codec2Client::Component>& component) override {
617 { // Log the death of the component.
618 std::shared_ptr<Codec2Client::Component> comp = component.lock();
619 if (!comp) {
620 ALOGE("Codec2 component died.");
621 } else {
622 ALOGE("Codec2 component \"%s\" died.", comp->getName().c_str());
623 }
624 }
625
626 // Report to MediaCodec.
627 sp<CCodec> codec(mCodec.promote());
628 if (!codec || !codec->mCallback) {
629 return;
630 }
631 codec->mCallback->onError(DEAD_OBJECT, ACTION_CODE_FATAL);
632 }
633
Pawin Vongmasa1c75a232019-01-09 04:41:52 -0800634 virtual void onFrameRendered(uint64_t bufferQueueId,
635 int32_t slotId,
636 int64_t timestampNs) override {
637 // TODO: implement
638 (void)bufferQueueId;
639 (void)slotId;
640 (void)timestampNs;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800641 }
642
643 virtual void onInputBufferDone(
Wonsik Kimab34ed62019-01-31 15:28:46 -0800644 uint64_t frameIndex, size_t arrayIndex) override {
Pawin Vongmasa36653902018-11-15 00:10:25 -0800645 sp<CCodec> codec(mCodec.promote());
646 if (codec) {
Wonsik Kimab34ed62019-01-31 15:28:46 -0800647 codec->onInputBufferDone(frameIndex, arrayIndex);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800648 }
649 }
650
651private:
652 wp<CCodec> mCodec;
653};
654
655// CCodecCallbackImpl
656
657class CCodecCallbackImpl : public CCodecCallback {
658public:
659 explicit CCodecCallbackImpl(CCodec *codec) : mCodec(codec) {}
660 ~CCodecCallbackImpl() override = default;
661
662 void onError(status_t err, enum ActionCode actionCode) override {
663 mCodec->mCallback->onError(err, actionCode);
664 }
665
666 void onOutputFramesRendered(int64_t mediaTimeUs, nsecs_t renderTimeNs) override {
667 mCodec->mCallback->onOutputFramesRendered(
668 {RenderedFrameInfo(mediaTimeUs, renderTimeNs)});
669 }
670
Pawin Vongmasa36653902018-11-15 00:10:25 -0800671 void onOutputBuffersChanged() override {
672 mCodec->mCallback->onOutputBuffersChanged();
673 }
674
Guillaume Chelfi5ffbcb32021-04-12 14:23:43 +0200675 void onFirstTunnelFrameReady() override {
676 mCodec->mCallback->onFirstTunnelFrameReady();
677 }
678
Pawin Vongmasa36653902018-11-15 00:10:25 -0800679private:
680 CCodec *mCodec;
681};
682
683// CCodec
684
685CCodec::CCodec()
Wonsik Kim155d5cb2019-10-09 12:49:49 -0700686 : mChannel(new CCodecBufferChannel(std::make_shared<CCodecCallbackImpl>(this))),
687 mConfig(new CCodecConfig) {
Pawin Vongmasa36653902018-11-15 00:10:25 -0800688}
689
690CCodec::~CCodec() {
691}
692
693std::shared_ptr<BufferChannelBase> CCodec::getBufferChannel() {
694 return mChannel;
695}
696
697status_t CCodec::tryAndReportOnError(std::function<status_t()> job) {
698 status_t err = job();
699 if (err != C2_OK) {
700 mCallback->onError(err, ACTION_CODE_FATAL);
701 }
702 return err;
703}
704
705void CCodec::initiateAllocateComponent(const sp<AMessage> &msg) {
706 auto setAllocating = [this] {
707 Mutexed<State>::Locked state(mState);
708 if (state->get() != RELEASED) {
709 return INVALID_OPERATION;
710 }
711 state->set(ALLOCATING);
712 return OK;
713 };
714 if (tryAndReportOnError(setAllocating) != OK) {
715 return;
716 }
717
718 sp<RefBase> codecInfo;
719 CHECK(msg->findObject("codecInfo", &codecInfo));
720 // For Codec 2.0 components, componentName == codecInfo->getCodecName().
721
722 sp<AMessage> allocMsg(new AMessage(kWhatAllocate, this));
723 allocMsg->setObject("codecInfo", codecInfo);
724 allocMsg->post();
725}
726
727void CCodec::allocate(const sp<MediaCodecInfo> &codecInfo) {
728 if (codecInfo == nullptr) {
729 mCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL);
730 return;
731 }
732 ALOGD("allocate(%s)", codecInfo->getCodecName());
733 mClientListener.reset(new ClientListener(this));
734
735 AString componentName = codecInfo->getCodecName();
736 std::shared_ptr<Codec2Client> client;
737
738 // set up preferred component store to access vendor store parameters
Pawin Vongmasa892c81d2019-03-12 00:56:50 -0700739 client = Codec2Client::CreateFromService("default");
Pawin Vongmasa36653902018-11-15 00:10:25 -0800740 if (client) {
Pawin Vongmasa1c75a232019-01-09 04:41:52 -0800741 ALOGI("setting up '%s' as default (vendor) store", client->getServiceName().c_str());
Pawin Vongmasa36653902018-11-15 00:10:25 -0800742 SetPreferredCodec2ComponentStore(
743 std::make_shared<Codec2ClientInterfaceWrapper>(client));
744 }
745
Chih-Yu Huangb8fe0792020-12-07 17:14:55 +0900746 std::shared_ptr<Codec2Client::Component> comp;
747 c2_status_t status = Codec2Client::CreateComponentByName(
Pawin Vongmasa36653902018-11-15 00:10:25 -0800748 componentName.c_str(),
749 mClientListener,
Chih-Yu Huangb8fe0792020-12-07 17:14:55 +0900750 &comp,
Pawin Vongmasa36653902018-11-15 00:10:25 -0800751 &client);
Chih-Yu Huangb8fe0792020-12-07 17:14:55 +0900752 if (status != C2_OK) {
753 ALOGE("Failed Create component: %s, error=%d", componentName.c_str(), status);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800754 Mutexed<State>::Locked state(mState);
755 state->set(RELEASED);
756 state.unlock();
Chih-Yu Huangb8fe0792020-12-07 17:14:55 +0900757 mCallback->onError((status == C2_NO_MEMORY ? NO_MEMORY : UNKNOWN_ERROR), ACTION_CODE_FATAL);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800758 state.lock();
759 return;
760 }
761 ALOGI("Created component [%s]", componentName.c_str());
762 mChannel->setComponent(comp);
763 auto setAllocated = [this, comp, client] {
764 Mutexed<State>::Locked state(mState);
765 if (state->get() != ALLOCATING) {
766 state->set(RELEASED);
767 return UNKNOWN_ERROR;
768 }
769 state->set(ALLOCATED);
770 state->comp = comp;
771 mClient = client;
772 return OK;
773 };
774 if (tryAndReportOnError(setAllocated) != OK) {
775 return;
776 }
777
778 // initialize config here in case setParameters is called prior to configure
Wonsik Kim155d5cb2019-10-09 12:49:49 -0700779 Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig);
780 const std::unique_ptr<Config> &config = *configLocked;
Wonsik Kim8a6ed372019-12-03 16:05:51 -0800781 status_t err = config->initialize(mClient->getParamReflector(), comp);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800782 if (err != OK) {
783 ALOGW("Failed to initialize configuration support");
784 // TODO: report error once we complete implementation.
785 }
786 config->queryConfiguration(comp);
787
788 mCallback->onComponentAllocated(componentName.c_str());
789}
790
791void CCodec::initiateConfigureComponent(const sp<AMessage> &format) {
792 auto checkAllocated = [this] {
793 Mutexed<State>::Locked state(mState);
794 return (state->get() != ALLOCATED) ? UNKNOWN_ERROR : OK;
795 };
796 if (tryAndReportOnError(checkAllocated) != OK) {
797 return;
798 }
799
800 sp<AMessage> msg(new AMessage(kWhatConfigure, this));
801 msg->setMessage("format", format);
802 msg->post();
803}
804
805void CCodec::configure(const sp<AMessage> &msg) {
806 std::shared_ptr<Codec2Client::Component> comp;
807 auto checkAllocated = [this, &comp] {
808 Mutexed<State>::Locked state(mState);
809 if (state->get() != ALLOCATED) {
810 state->set(RELEASED);
811 return UNKNOWN_ERROR;
812 }
813 comp = state->comp;
814 return OK;
815 };
816 if (tryAndReportOnError(checkAllocated) != OK) {
817 return;
818 }
819
820 auto doConfig = [msg, comp, this]() -> status_t {
821 AString mime;
822 if (!msg->findString("mime", &mime)) {
823 return BAD_VALUE;
824 }
825
826 int32_t encoder;
827 if (!msg->findInt32("encoder", &encoder)) {
828 encoder = false;
829 }
830
Wonsik Kimfb7a7672019-12-27 17:13:33 -0800831 int32_t flags;
832 if (!msg->findInt32("flags", &flags)) {
833 return BAD_VALUE;
834 }
835
Pawin Vongmasa36653902018-11-15 00:10:25 -0800836 // TODO: read from intf()
837 if ((!encoder) != (comp->getName().find("encoder") == std::string::npos)) {
838 return UNKNOWN_ERROR;
839 }
840
841 int32_t storeMeta;
842 if (encoder
843 && msg->findInt32("android._input-metadata-buffer-type", &storeMeta)
844 && storeMeta != kMetadataBufferTypeInvalid) {
845 if (storeMeta != kMetadataBufferTypeANWBuffer) {
846 ALOGD("Only ANW buffers are supported for legacy metadata mode");
847 return BAD_VALUE;
848 }
849 mChannel->setMetaMode(CCodecBufferChannel::MODE_ANW);
850 }
851
ted.sun765db4d2020-06-23 14:03:41 +0800852 status_t err = OK;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800853 sp<RefBase> obj;
854 sp<Surface> surface;
855 if (msg->findObject("native-window", &obj)) {
856 surface = static_cast<Surface *>(obj.get());
ted.sun765db4d2020-06-23 14:03:41 +0800857 // setup tunneled playback
858 if (surface != nullptr) {
859 Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig);
860 const std::unique_ptr<Config> &config = *configLocked;
861 if ((config->mDomain & Config::IS_DECODER)
862 && (config->mDomain & Config::IS_VIDEO)) {
863 int32_t tunneled;
864 if (msg->findInt32("feature-tunneled-playback", &tunneled) && tunneled != 0) {
865 ALOGI("Configuring TUNNELED video playback.");
866
867 err = configureTunneledVideoPlayback(comp, &config->mSidebandHandle, msg);
868 if (err != OK) {
869 ALOGE("configureTunneledVideoPlayback failed!");
870 return err;
871 }
872 config->mTunneled = true;
873 }
874 }
875 }
Pawin Vongmasa36653902018-11-15 00:10:25 -0800876 setSurface(surface);
877 }
878
Wonsik Kim155d5cb2019-10-09 12:49:49 -0700879 Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig);
880 const std::unique_ptr<Config> &config = *configLocked;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800881 config->mUsingSurface = surface != nullptr;
Wonsik Kimfb7a7672019-12-27 17:13:33 -0800882 config->mBuffersBoundToCodec = ((flags & CONFIGURE_FLAG_USE_BLOCK_MODEL) == 0);
883 ALOGD("[%s] buffers are %sbound to CCodec for this session",
884 comp->getName().c_str(), config->mBuffersBoundToCodec ? "" : "not ");
Pawin Vongmasa36653902018-11-15 00:10:25 -0800885
Wonsik Kim1114eea2019-02-25 14:35:24 -0800886 // Enforce required parameters
887 int32_t i32;
888 float flt;
889 if (config->mDomain & Config::IS_AUDIO) {
890 if (!msg->findInt32(KEY_SAMPLE_RATE, &i32)) {
891 ALOGD("sample rate is missing, which is required for audio components.");
892 return BAD_VALUE;
893 }
894 if (!msg->findInt32(KEY_CHANNEL_COUNT, &i32)) {
895 ALOGD("channel count is missing, which is required for audio components.");
896 return BAD_VALUE;
897 }
898 if ((config->mDomain & Config::IS_ENCODER)
899 && !mime.equalsIgnoreCase(MEDIA_MIMETYPE_AUDIO_FLAC)
900 && !msg->findInt32(KEY_BIT_RATE, &i32)
901 && !msg->findFloat(KEY_BIT_RATE, &flt)) {
902 ALOGD("bitrate is missing, which is required for audio encoders.");
903 return BAD_VALUE;
904 }
905 }
Wonsik Kimd91f3fb2021-02-24 12:35:31 -0800906 int32_t width = 0;
907 int32_t height = 0;
Wonsik Kim1114eea2019-02-25 14:35:24 -0800908 if (config->mDomain & (Config::IS_IMAGE | Config::IS_VIDEO)) {
Wonsik Kimd91f3fb2021-02-24 12:35:31 -0800909 if (!msg->findInt32(KEY_WIDTH, &width)) {
Wonsik Kim1114eea2019-02-25 14:35:24 -0800910 ALOGD("width is missing, which is required for image/video components.");
911 return BAD_VALUE;
912 }
Wonsik Kimd91f3fb2021-02-24 12:35:31 -0800913 if (!msg->findInt32(KEY_HEIGHT, &height)) {
Wonsik Kim1114eea2019-02-25 14:35:24 -0800914 ALOGD("height is missing, which is required for image/video components.");
915 return BAD_VALUE;
916 }
917 if ((config->mDomain & Config::IS_ENCODER) && (config->mDomain & Config::IS_VIDEO)) {
Harish Mahendrakar71cbb9d2019-05-21 11:21:27 -0700918 int32_t mode = BITRATE_MODE_VBR;
919 if (msg->findInt32(KEY_BITRATE_MODE, &mode) && mode == BITRATE_MODE_CQ) {
Harish Mahendrakar817d3182019-03-11 16:37:47 -0700920 if (!msg->findInt32(KEY_QUALITY, &i32)) {
921 ALOGD("quality is missing, which is required for video encoders in CQ.");
922 return BAD_VALUE;
923 }
924 } else {
925 if (!msg->findInt32(KEY_BIT_RATE, &i32)
926 && !msg->findFloat(KEY_BIT_RATE, &flt)) {
927 ALOGD("bitrate is missing, which is required for video encoders.");
928 return BAD_VALUE;
929 }
Wonsik Kim1114eea2019-02-25 14:35:24 -0800930 }
931 if (!msg->findInt32(KEY_I_FRAME_INTERVAL, &i32)
932 && !msg->findFloat(KEY_I_FRAME_INTERVAL, &flt)) {
933 ALOGD("I frame interval is missing, which is required for video encoders.");
934 return BAD_VALUE;
935 }
Wonsik Kimaab2eea2019-05-22 10:37:58 -0700936 if (!msg->findInt32(KEY_FRAME_RATE, &i32)
937 && !msg->findFloat(KEY_FRAME_RATE, &flt)) {
938 ALOGD("frame rate is missing, which is required for video encoders.");
939 return BAD_VALUE;
940 }
Wonsik Kim1114eea2019-02-25 14:35:24 -0800941 }
942 }
943
Pawin Vongmasa36653902018-11-15 00:10:25 -0800944 /*
945 * Handle input surface configuration
946 */
947 if ((config->mDomain & (Config::IS_VIDEO | Config::IS_IMAGE))
948 && (config->mDomain & Config::IS_ENCODER)) {
949 config->mISConfig.reset(new InputSurfaceWrapper::Config{});
950 {
951 config->mISConfig->mMinFps = 0;
952 int64_t value;
Chong Zhang038e8f82019-02-06 19:05:14 -0800953 if (msg->findInt64(KEY_REPEAT_PREVIOUS_FRAME_AFTER, &value) && value > 0) {
Pawin Vongmasa36653902018-11-15 00:10:25 -0800954 config->mISConfig->mMinFps = 1e6 / value;
955 }
Wonsik Kim95ba0162019-03-19 15:51:54 -0700956 if (!msg->findFloat(
957 KEY_MAX_FPS_TO_ENCODER, &config->mISConfig->mMaxFps)) {
958 config->mISConfig->mMaxFps = -1;
959 }
Pawin Vongmasa36653902018-11-15 00:10:25 -0800960 config->mISConfig->mMinAdjustedFps = 0;
961 config->mISConfig->mFixedAdjustedFps = 0;
Chong Zhang038e8f82019-02-06 19:05:14 -0800962 if (msg->findInt64(KEY_MAX_PTS_GAP_TO_ENCODER, &value)) {
Pawin Vongmasa36653902018-11-15 00:10:25 -0800963 if (value < 0 && value >= INT32_MIN) {
964 config->mISConfig->mFixedAdjustedFps = -1e6 / value;
Wonsik Kim95ba0162019-03-19 15:51:54 -0700965 config->mISConfig->mMaxFps = -1;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800966 } else if (value > 0 && value <= INT32_MAX) {
967 config->mISConfig->mMinAdjustedFps = 1e6 / value;
968 }
969 }
970 }
971
972 {
Wonsik Kim8e55f3a2019-09-03 14:10:37 -0700973 bool captureFpsFound = false;
974 double timeLapseFps;
975 float captureRate;
976 if (msg->findDouble("time-lapse-fps", &timeLapseFps)) {
977 config->mISConfig->mCaptureFps = timeLapseFps;
978 captureFpsFound = true;
979 } else if (msg->findAsFloat(KEY_CAPTURE_RATE, &captureRate)) {
980 config->mISConfig->mCaptureFps = captureRate;
981 captureFpsFound = true;
982 }
983 if (captureFpsFound) {
Pawin Vongmasa36653902018-11-15 00:10:25 -0800984 (void)msg->findAsFloat(KEY_FRAME_RATE, &config->mISConfig->mCodedFps);
985 }
986 }
987
988 {
989 config->mISConfig->mSuspended = false;
990 config->mISConfig->mSuspendAtUs = -1;
991 int32_t value;
Chong Zhang038e8f82019-02-06 19:05:14 -0800992 if (msg->findInt32(KEY_CREATE_INPUT_SURFACE_SUSPENDED, &value) && value) {
Pawin Vongmasa36653902018-11-15 00:10:25 -0800993 config->mISConfig->mSuspended = true;
994 }
995 }
Wonsik Kim9eac4d12019-05-23 12:58:48 -0700996 config->mISConfig->mUsage = 0;
Wonsik Kima1335e12021-04-22 16:28:29 -0700997 config->mISConfig->mPriority = INT_MAX;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800998 }
999
1000 /*
1001 * Handle desired color format.
1002 */
Wonsik Kimd79ee1f2020-08-27 17:41:56 -07001003 int32_t defaultColorFormat = COLOR_FormatYUV420Flexible;
Pawin Vongmasa36653902018-11-15 00:10:25 -08001004 if ((config->mDomain & (Config::IS_VIDEO | Config::IS_IMAGE))) {
Wonsik Kimd79ee1f2020-08-27 17:41:56 -07001005 int32_t format = 0;
1006 // Query vendor format for Flexible YUV
1007 std::vector<std::unique_ptr<C2Param>> heapParams;
1008 C2StoreFlexiblePixelFormatDescriptorsInfo *pixelFormatInfo = nullptr;
1009 if (mClient->query(
1010 {},
1011 {C2StoreFlexiblePixelFormatDescriptorsInfo::PARAM_TYPE},
1012 C2_MAY_BLOCK,
1013 &heapParams) == C2_OK
1014 && heapParams.size() == 1u) {
1015 pixelFormatInfo = C2StoreFlexiblePixelFormatDescriptorsInfo::From(
1016 heapParams[0].get());
1017 } else {
1018 pixelFormatInfo = nullptr;
1019 }
Wonsik Kim08a8a2b2021-05-10 19:03:47 -07001020 // bit depth -> format
1021 std::map<uint32_t, uint32_t> flexPixelFormat;
1022 std::map<uint32_t, uint32_t> flexPlanarPixelFormat;
1023 std::map<uint32_t, uint32_t> flexSemiPlanarPixelFormat;
Wonsik Kimd79ee1f2020-08-27 17:41:56 -07001024 if (pixelFormatInfo && *pixelFormatInfo) {
1025 for (size_t i = 0; i < pixelFormatInfo->flexCount(); ++i) {
1026 const C2FlexiblePixelFormatDescriptorStruct &desc =
1027 pixelFormatInfo->m.values[i];
Wonsik Kim08a8a2b2021-05-10 19:03:47 -07001028 if (desc.subsampling != C2Color::YUV_420
Wonsik Kimd79ee1f2020-08-27 17:41:56 -07001029 // TODO(b/180076105): some device report wrong layout
1030 // || desc.layout == C2Color::INTERLEAVED_PACKED
1031 // || desc.layout == C2Color::INTERLEAVED_ALIGNED
1032 || desc.layout == C2Color::UNKNOWN_LAYOUT) {
1033 continue;
1034 }
Wonsik Kim08a8a2b2021-05-10 19:03:47 -07001035 if (flexPixelFormat.count(desc.bitDepth) == 0) {
1036 flexPixelFormat.emplace(desc.bitDepth, desc.pixelFormat);
Wonsik Kimd79ee1f2020-08-27 17:41:56 -07001037 }
Wonsik Kim08a8a2b2021-05-10 19:03:47 -07001038 if (desc.layout == C2Color::PLANAR_PACKED
1039 && flexPlanarPixelFormat.count(desc.bitDepth) == 0) {
1040 flexPlanarPixelFormat.emplace(desc.bitDepth, desc.pixelFormat);
Wonsik Kimd79ee1f2020-08-27 17:41:56 -07001041 }
Wonsik Kim08a8a2b2021-05-10 19:03:47 -07001042 if (desc.layout == C2Color::SEMIPLANAR_PACKED
1043 && flexSemiPlanarPixelFormat.count(desc.bitDepth) == 0) {
1044 flexSemiPlanarPixelFormat.emplace(desc.bitDepth, desc.pixelFormat);
Wonsik Kimd79ee1f2020-08-27 17:41:56 -07001045 }
1046 }
1047 }
Pawin Vongmasa36653902018-11-15 00:10:25 -08001048 if (!msg->findInt32(KEY_COLOR_FORMAT, &format)) {
Wonsik Kimd79ee1f2020-08-27 17:41:56 -07001049 // Also handle default color format (encoders require color format, so this is only
1050 // needed for decoders.
Pawin Vongmasa36653902018-11-15 00:10:25 -08001051 if (!(config->mDomain & Config::IS_ENCODER)) {
Wonsik Kimd79ee1f2020-08-27 17:41:56 -07001052 if (surface == nullptr) {
Wonsik Kim1eb88a92021-03-29 20:44:04 -07001053 const char *prefix = "";
Wonsik Kim08a8a2b2021-05-10 19:03:47 -07001054 if (flexSemiPlanarPixelFormat.count(8) != 0) {
Wonsik Kim1eb88a92021-03-29 20:44:04 -07001055 format = COLOR_FormatYUV420SemiPlanar;
1056 prefix = "semi-";
1057 } else {
1058 format = COLOR_FormatYUV420Planar;
1059 }
1060 ALOGD("Client requested ByteBuffer mode decoder w/o color format set: "
1061 "using default %splanar color format", prefix);
Wonsik Kimd79ee1f2020-08-27 17:41:56 -07001062 } else {
1063 format = COLOR_FormatSurface;
1064 }
1065 defaultColorFormat = format;
1066 }
1067 } else {
1068 if ((config->mDomain & Config::IS_ENCODER) || !surface) {
1069 switch (format) {
1070 case COLOR_FormatYUV420Flexible:
Wonsik Kim08a8a2b2021-05-10 19:03:47 -07001071 format = COLOR_FormatYUV420Planar;
1072 if (flexPixelFormat.count(8) != 0) {
1073 format = flexPixelFormat[8];
1074 }
Wonsik Kimd79ee1f2020-08-27 17:41:56 -07001075 break;
1076 case COLOR_FormatYUV420Planar:
1077 case COLOR_FormatYUV420PackedPlanar:
Wonsik Kim08a8a2b2021-05-10 19:03:47 -07001078 if (flexPlanarPixelFormat.count(8) != 0) {
1079 format = flexPlanarPixelFormat[8];
1080 } else if (flexPixelFormat.count(8) != 0) {
1081 format = flexPixelFormat[8];
1082 }
Wonsik Kimd79ee1f2020-08-27 17:41:56 -07001083 break;
1084 case COLOR_FormatYUV420SemiPlanar:
1085 case COLOR_FormatYUV420PackedSemiPlanar:
Wonsik Kim08a8a2b2021-05-10 19:03:47 -07001086 if (flexSemiPlanarPixelFormat.count(8) != 0) {
1087 format = flexSemiPlanarPixelFormat[8];
1088 } else if (flexPixelFormat.count(8) != 0) {
1089 format = flexPixelFormat[8];
1090 }
1091 break;
1092 case COLOR_FormatYUVP010:
1093 format = COLOR_FormatYUVP010;
1094 if (flexSemiPlanarPixelFormat.count(10) != 0) {
1095 format = flexSemiPlanarPixelFormat[10];
1096 } else if (flexPixelFormat.count(10) != 0) {
1097 format = flexPixelFormat[10];
1098 }
Wonsik Kimd79ee1f2020-08-27 17:41:56 -07001099 break;
1100 default:
1101 // No-op
1102 break;
1103 }
Pawin Vongmasa36653902018-11-15 00:10:25 -08001104 }
1105 }
1106
Wonsik Kimd79ee1f2020-08-27 17:41:56 -07001107 if (format != 0) {
Pawin Vongmasa36653902018-11-15 00:10:25 -08001108 msg->setInt32("android._color-format", format);
1109 }
1110 }
1111
Wonsik Kim77e97c72021-01-20 10:33:22 -08001112 /*
1113 * Handle dataspace
1114 */
1115 int32_t usingRecorder;
1116 if (msg->findInt32("android._using-recorder", &usingRecorder) && usingRecorder) {
1117 android_dataspace dataSpace = HAL_DATASPACE_BT709;
1118 int32_t width, height;
1119 if (msg->findInt32("width", &width)
1120 && msg->findInt32("height", &height)) {
Wonsik Kim4f13d112021-03-17 04:37:46 +00001121 ColorAspects aspects;
1122 getColorAspectsFromFormat(msg, aspects);
1123 setDefaultCodecColorAspectsIfNeeded(aspects, width, height);
Wonsik Kim77e97c72021-01-20 10:33:22 -08001124 // TODO: read dataspace / color aspect from the component
Wonsik Kim4f13d112021-03-17 04:37:46 +00001125 setColorAspectsIntoFormat(aspects, const_cast<sp<AMessage> &>(msg));
1126 dataSpace = getDataSpaceForColorAspects(aspects, true /* mayexpand */);
Wonsik Kim77e97c72021-01-20 10:33:22 -08001127 }
1128 msg->setInt32("android._dataspace", (int32_t)dataSpace);
1129 ALOGD("setting dataspace to %x", dataSpace);
1130 }
1131
Wonsik Kim8a6ed372019-12-03 16:05:51 -08001132 int32_t subscribeToAllVendorParams;
1133 if (msg->findInt32("x-*", &subscribeToAllVendorParams) && subscribeToAllVendorParams) {
1134 if (config->subscribeToAllVendorParams(comp, C2_MAY_BLOCK) != OK) {
1135 ALOGD("[%s] Failed to subscribe to all vendor params", comp->getName().c_str());
1136 }
1137 }
1138
Pawin Vongmasa36653902018-11-15 00:10:25 -08001139 std::vector<std::unique_ptr<C2Param>> configUpdate;
Wonsik Kimaa484ac2019-02-13 16:54:02 -08001140 // NOTE: We used to ignore "video-bitrate" at configure; replicate
1141 // the behavior here.
1142 sp<AMessage> sdkParams = msg;
1143 int32_t videoBitrate;
1144 if (sdkParams->findInt32(PARAMETER_KEY_VIDEO_BITRATE, &videoBitrate)) {
1145 sdkParams = msg->dup();
1146 sdkParams->removeEntryAt(sdkParams->findEntryByName(PARAMETER_KEY_VIDEO_BITRATE));
1147 }
ted.sun765db4d2020-06-23 14:03:41 +08001148 err = config->getConfigUpdateFromSdkParams(
Wonsik Kimaa484ac2019-02-13 16:54:02 -08001149 comp, sdkParams, Config::IS_CONFIG, C2_DONT_BLOCK, &configUpdate);
Pawin Vongmasa36653902018-11-15 00:10:25 -08001150 if (err != OK) {
1151 ALOGW("failed to convert configuration to c2 params");
1152 }
Wonsik Kimaab2eea2019-05-22 10:37:58 -07001153
1154 int32_t maxBframes = 0;
1155 if ((config->mDomain & Config::IS_ENCODER)
1156 && (config->mDomain & Config::IS_VIDEO)
1157 && sdkParams->findInt32(KEY_MAX_B_FRAMES, &maxBframes)
1158 && maxBframes > 0) {
1159 std::unique_ptr<C2StreamGopTuning::output> gop =
1160 C2StreamGopTuning::output::AllocUnique(2 /* flexCount */, 0u /* stream */);
1161 gop->m.values[0] = { P_FRAME, UINT32_MAX };
1162 gop->m.values[1] = {
1163 C2Config::picture_type_t(P_FRAME | B_FRAME),
1164 uint32_t(maxBframes)
1165 };
1166 configUpdate.push_back(std::move(gop));
1167 }
1168
Ray Essicka0ae6972021-03-10 19:40:01 -08001169 if ((config->mDomain & Config::IS_ENCODER)
1170 && (config->mDomain & Config::IS_VIDEO)) {
1171 // we may not use all 3 of these entries
1172 std::unique_ptr<C2StreamPictureQuantizationTuning::output> qp =
1173 C2StreamPictureQuantizationTuning::output::AllocUnique(3 /* flexCount */,
1174 0u /* stream */);
1175
1176 int ix = 0;
1177
1178 int32_t iMax = INT32_MAX;
1179 int32_t iMin = INT32_MIN;
1180 (void) sdkParams->findInt32(KEY_VIDEO_QP_I_MAX, &iMax);
1181 (void) sdkParams->findInt32(KEY_VIDEO_QP_I_MIN, &iMin);
1182 if (iMax != INT32_MAX || iMin != INT32_MIN) {
1183 qp->m.values[ix++] = {I_FRAME, iMin, iMax};
1184 }
1185
1186 int32_t pMax = INT32_MAX;
1187 int32_t pMin = INT32_MIN;
1188 (void) sdkParams->findInt32(KEY_VIDEO_QP_P_MAX, &pMax);
1189 (void) sdkParams->findInt32(KEY_VIDEO_QP_P_MIN, &pMin);
1190 if (pMax != INT32_MAX || pMin != INT32_MIN) {
1191 qp->m.values[ix++] = {P_FRAME, pMin, pMax};
1192 }
1193
1194 int32_t bMax = INT32_MAX;
1195 int32_t bMin = INT32_MIN;
1196 (void) sdkParams->findInt32(KEY_VIDEO_QP_B_MAX, &bMax);
1197 (void) sdkParams->findInt32(KEY_VIDEO_QP_B_MIN, &bMin);
1198 if (bMax != INT32_MAX || bMin != INT32_MIN) {
1199 qp->m.values[ix++] = {B_FRAME, bMin, bMax};
1200 }
1201
1202 // adjust to reflect actual use.
1203 qp->setFlexCount(ix);
1204
1205 configUpdate.push_back(std::move(qp));
1206 }
1207
Wonsik Kima1335e12021-04-22 16:28:29 -07001208 int32_t background = 0;
1209 if ((config->mDomain & Config::IS_VIDEO)
1210 && msg->findInt32("android._background-mode", &background)
1211 && background) {
1212 androidSetThreadPriority(gettid(), ANDROID_PRIORITY_BACKGROUND);
1213 if (config->mISConfig) {
1214 config->mISConfig->mPriority = ANDROID_PRIORITY_BACKGROUND;
1215 }
1216 }
1217
Pawin Vongmasa36653902018-11-15 00:10:25 -08001218 err = config->setParameters(comp, configUpdate, C2_DONT_BLOCK);
1219 if (err != OK) {
1220 ALOGW("failed to configure c2 params");
1221 return err;
1222 }
1223
1224 std::vector<std::unique_ptr<C2Param>> params;
1225 C2StreamUsageTuning::input usage(0u, 0u);
1226 C2StreamMaxBufferSizeInfo::input maxInputSize(0u, 0u);
Wonsik Kim9ca01d32019-04-01 14:45:47 -07001227 C2PrependHeaderModeSetting prepend(PREPEND_HEADER_TO_NONE);
Pawin Vongmasa36653902018-11-15 00:10:25 -08001228
Wonsik Kim3baecda2021-02-07 22:19:56 -08001229 C2Param::Index colorAspectsRequestIndex =
1230 C2StreamColorAspectsInfo::output::PARAM_TYPE | C2Param::CoreIndex::IS_REQUEST_FLAG;
Pawin Vongmasa36653902018-11-15 00:10:25 -08001231 std::initializer_list<C2Param::Index> indices {
Wonsik Kim3baecda2021-02-07 22:19:56 -08001232 colorAspectsRequestIndex.withStream(0u),
Pawin Vongmasa36653902018-11-15 00:10:25 -08001233 };
Chaejung Lim86c22dc2021-12-23 00:41:05 -08001234 int32_t colorTransferRequest = 0;
1235 if (config->mDomain & (Config::IS_IMAGE | Config::IS_VIDEO)
1236 && !sdkParams->findInt32("color-transfer-request", &colorTransferRequest)) {
1237 colorTransferRequest = 0;
1238 }
1239 c2_status_t c2err = C2_OK;
1240 if (colorTransferRequest != 0) {
1241 c2err = comp->query(
1242 { &usage, &maxInputSize, &prepend },
1243 indices,
1244 C2_DONT_BLOCK,
1245 &params);
1246 } else {
1247 c2err = comp->query(
1248 { &usage, &maxInputSize, &prepend },
1249 {},
1250 C2_DONT_BLOCK,
1251 &params);
1252 }
Pawin Vongmasa36653902018-11-15 00:10:25 -08001253 if (c2err != C2_OK && c2err != C2_BAD_INDEX) {
1254 ALOGE("Failed to query component interface: %d", c2err);
1255 return UNKNOWN_ERROR;
1256 }
Wonsik Kim9eac4d12019-05-23 12:58:48 -07001257 if (usage) {
1258 if (usage.value & C2MemoryUsage::CPU_READ) {
1259 config->mInputFormat->setInt32("using-sw-read-often", true);
1260 }
1261 if (config->mISConfig) {
1262 C2AndroidMemoryUsage androidUsage(C2MemoryUsage(usage.value));
1263 config->mISConfig->mUsage = androidUsage.asGrallocUsage();
1264 }
Wonsik Kim666604a2020-05-14 16:57:49 -07001265 config->mInputFormat->setInt64("android._C2MemoryUsage", usage.value);
Pawin Vongmasa36653902018-11-15 00:10:25 -08001266 }
1267
1268 // NOTE: we don't blindly use client specified input size if specified as clients
1269 // at times specify too small size. Instead, mimic the behavior from OMX, where the
1270 // client specified size is only used to ask for bigger buffers than component suggested
1271 // size.
1272 int32_t clientInputSize = 0;
1273 bool clientSpecifiedInputSize =
1274 msg->findInt32(KEY_MAX_INPUT_SIZE, &clientInputSize) && clientInputSize > 0;
1275 // TEMP: enforce minimum buffer size of 1MB for video decoders
1276 // and 16K / 4K for audio encoders/decoders
1277 if (maxInputSize.value == 0) {
1278 if (config->mDomain & Config::IS_AUDIO) {
1279 maxInputSize.value = encoder ? 16384 : 4096;
1280 } else if (!encoder) {
1281 maxInputSize.value = 1048576u;
1282 }
1283 }
1284
1285 // verify that CSD fits into this size (if defined)
1286 if ((config->mDomain & Config::IS_DECODER) && maxInputSize.value > 0) {
1287 sp<ABuffer> csd;
1288 for (size_t ix = 0; msg->findBuffer(StringPrintf("csd-%zu", ix).c_str(), &csd); ++ix) {
1289 if (csd && csd->size() > maxInputSize.value) {
1290 maxInputSize.value = csd->size();
1291 }
1292 }
1293 }
1294
1295 // TODO: do this based on component requiring linear allocator for input
1296 if ((config->mDomain & Config::IS_DECODER) || (config->mDomain & Config::IS_AUDIO)) {
1297 if (clientSpecifiedInputSize) {
1298 // Warn that we're overriding client's max input size if necessary.
1299 if ((uint32_t)clientInputSize < maxInputSize.value) {
1300 ALOGD("client requested max input size %d, which is smaller than "
1301 "what component recommended (%u); overriding with component "
1302 "recommendation.", clientInputSize, maxInputSize.value);
1303 ALOGW("This behavior is subject to change. It is recommended that "
1304 "app developers double check whether the requested "
1305 "max input size is in reasonable range.");
1306 } else {
1307 maxInputSize.value = clientInputSize;
1308 }
1309 }
1310 // Pass max input size on input format to the buffer channel (if supplied by the
1311 // component or by a default)
1312 if (maxInputSize.value) {
1313 config->mInputFormat->setInt32(
1314 KEY_MAX_INPUT_SIZE,
1315 (int32_t)(c2_min(maxInputSize.value, uint32_t(INT32_MAX))));
1316 }
1317 }
1318
Wonsik Kim9ca01d32019-04-01 14:45:47 -07001319 int32_t clientPrepend;
1320 if ((config->mDomain & Config::IS_VIDEO)
1321 && (config->mDomain & Config::IS_ENCODER)
Lajos Molnara2b5f5a2020-10-14 16:36:18 -07001322 && msg->findInt32(KEY_PREPEND_HEADER_TO_SYNC_FRAMES, &clientPrepend)
Wonsik Kim9ca01d32019-04-01 14:45:47 -07001323 && clientPrepend
1324 && (!prepend || prepend.value != PREPEND_HEADER_TO_ALL_SYNC)) {
Lajos Molnara2b5f5a2020-10-14 16:36:18 -07001325 ALOGE("Failed to set KEY_PREPEND_HEADER_TO_SYNC_FRAMES");
Wonsik Kim9ca01d32019-04-01 14:45:47 -07001326 return BAD_VALUE;
1327 }
1328
Wonsik Kimd91f3fb2021-02-24 12:35:31 -08001329 int32_t componentColorFormat = 0;
Pawin Vongmasa36653902018-11-15 00:10:25 -08001330 if ((config->mDomain & (Config::IS_VIDEO | Config::IS_IMAGE))) {
1331 // propagate HDR static info to output format for both encoders and decoders
1332 // if component supports this info, we will update from component, but only the raw port,
1333 // so don't propagate if component already filled it in.
1334 sp<ABuffer> hdrInfo;
1335 if (msg->findBuffer(KEY_HDR_STATIC_INFO, &hdrInfo)
1336 && !config->mOutputFormat->findBuffer(KEY_HDR_STATIC_INFO, &hdrInfo)) {
1337 config->mOutputFormat->setBuffer(KEY_HDR_STATIC_INFO, hdrInfo);
1338 }
1339
1340 // Set desired color format from configuration parameter
1341 int32_t format;
Wonsik Kimd79ee1f2020-08-27 17:41:56 -07001342 if (!msg->findInt32(KEY_COLOR_FORMAT, &format)) {
1343 format = defaultColorFormat;
1344 }
1345 if (config->mDomain & Config::IS_ENCODER) {
1346 config->mInputFormat->setInt32(KEY_COLOR_FORMAT, format);
Wonsik Kimd91f3fb2021-02-24 12:35:31 -08001347 if (msg->findInt32("android._color-format", &componentColorFormat)) {
1348 config->mInputFormat->setInt32("android._color-format", componentColorFormat);
Pawin Vongmasa36653902018-11-15 00:10:25 -08001349 }
Wonsik Kimd79ee1f2020-08-27 17:41:56 -07001350 } else {
1351 config->mOutputFormat->setInt32(KEY_COLOR_FORMAT, format);
Pawin Vongmasa36653902018-11-15 00:10:25 -08001352 }
1353 }
1354
1355 // propagate encoder delay and padding to output format
1356 if ((config->mDomain & Config::IS_DECODER) && (config->mDomain & Config::IS_AUDIO)) {
1357 int delay = 0;
1358 if (msg->findInt32("encoder-delay", &delay)) {
1359 config->mOutputFormat->setInt32("encoder-delay", delay);
1360 }
1361 int padding = 0;
1362 if (msg->findInt32("encoder-padding", &padding)) {
1363 config->mOutputFormat->setInt32("encoder-padding", padding);
1364 }
1365 }
1366
Pawin Vongmasa36653902018-11-15 00:10:25 -08001367 if (config->mDomain & Config::IS_AUDIO) {
Wonsik Kim6f23cfc2021-09-24 05:45:52 -07001368 // set channel-mask
Pawin Vongmasa36653902018-11-15 00:10:25 -08001369 int32_t mask;
1370 if (msg->findInt32(KEY_CHANNEL_MASK, &mask)) {
1371 if (config->mDomain & Config::IS_ENCODER) {
1372 config->mInputFormat->setInt32(KEY_CHANNEL_MASK, mask);
1373 } else {
1374 config->mOutputFormat->setInt32(KEY_CHANNEL_MASK, mask);
1375 }
1376 }
Wonsik Kim6f23cfc2021-09-24 05:45:52 -07001377
1378 // set PCM encoding
1379 int32_t pcmEncoding = kAudioEncodingPcm16bit;
1380 msg->findInt32(KEY_PCM_ENCODING, &pcmEncoding);
1381 if (encoder) {
1382 config->mInputFormat->setInt32("android._config-pcm-encoding", pcmEncoding);
1383 } else {
1384 config->mOutputFormat->setInt32("android._config-pcm-encoding", pcmEncoding);
1385 }
Pawin Vongmasa36653902018-11-15 00:10:25 -08001386 }
1387
Wonsik Kim3baecda2021-02-07 22:19:56 -08001388 std::unique_ptr<C2Param> colorTransferRequestParam;
1389 for (std::unique_ptr<C2Param> &param : params) {
1390 if (param->index() == colorAspectsRequestIndex.withStream(0u)) {
1391 ALOGI("found color transfer request param");
1392 colorTransferRequestParam = std::move(param);
1393 }
1394 }
Wonsik Kim3baecda2021-02-07 22:19:56 -08001395
1396 if (colorTransferRequest != 0) {
1397 if (colorTransferRequestParam && *colorTransferRequestParam) {
1398 C2StreamColorAspectsInfo::output *info =
1399 static_cast<C2StreamColorAspectsInfo::output *>(
1400 colorTransferRequestParam.get());
1401 if (!C2Mapper::map(info->transfer, &colorTransferRequest)) {
1402 colorTransferRequest = 0;
1403 }
1404 } else {
1405 colorTransferRequest = 0;
1406 }
1407 config->mInputFormat->setInt32("color-transfer-request", colorTransferRequest);
1408 }
1409
Wonsik Kimd91f3fb2021-02-24 12:35:31 -08001410 if (componentColorFormat != 0 && componentColorFormat != COLOR_FormatSurface) {
1411 // Need to get stride/vstride
1412 uint32_t pixelFormat = PIXEL_FORMAT_UNKNOWN;
1413 if (C2Mapper::mapPixelFormatFrameworkToCodec(componentColorFormat, &pixelFormat)) {
1414 // TODO: retrieve these values without allocating a buffer.
1415 // Currently allocating a buffer is necessary to retrieve the layout.
1416 int64_t blockUsage =
1417 usage.value | C2MemoryUsage::CPU_READ | C2MemoryUsage::CPU_WRITE;
1418 std::shared_ptr<C2GraphicBlock> block = FetchGraphicBlock(
1419 width, height, pixelFormat, blockUsage, {comp->getName()});
1420 sp<GraphicBlockBuffer> buffer;
1421 if (block) {
1422 buffer = GraphicBlockBuffer::Allocate(
1423 config->mInputFormat,
1424 block,
1425 [](size_t size) -> sp<ABuffer> { return new ABuffer(size); });
1426 } else {
1427 ALOGD("Failed to allocate a graphic block "
1428 "(width=%d height=%d pixelFormat=%u usage=%llx)",
1429 width, height, pixelFormat, (long long)blockUsage);
1430 // This means that byte buffer mode is not supported in this configuration
1431 // anyway. Skip setting stride/vstride to input format.
1432 }
1433 if (buffer) {
1434 sp<ABuffer> imageData = buffer->getImageData();
1435 MediaImage2 *img = nullptr;
1436 if (imageData && imageData->data()
1437 && imageData->size() >= sizeof(MediaImage2)) {
1438 img = (MediaImage2*)imageData->data();
1439 }
1440 if (img && img->mNumPlanes > 0 && img->mType != img->MEDIA_IMAGE_TYPE_UNKNOWN) {
1441 int32_t stride = img->mPlane[0].mRowInc;
1442 config->mInputFormat->setInt32(KEY_STRIDE, stride);
1443 if (img->mNumPlanes > 1 && stride > 0) {
1444 int64_t offsetDelta =
1445 (int64_t)img->mPlane[1].mOffset - (int64_t)img->mPlane[0].mOffset;
1446 if (offsetDelta % stride == 0) {
1447 int32_t vstride = int32_t(offsetDelta / stride);
1448 config->mInputFormat->setInt32(KEY_SLICE_HEIGHT, vstride);
1449 } else {
1450 ALOGD("Cannot report accurate slice height: "
1451 "offsetDelta = %lld stride = %d",
1452 (long long)offsetDelta, stride);
1453 }
1454 }
1455 }
1456 }
1457 }
1458 }
1459
Wonsik Kimec585c32021-10-01 01:11:00 -07001460 if (config->mTunneled) {
1461 config->mOutputFormat->setInt32("android._tunneled", 1);
1462 }
1463
Yushin Cho91873b52021-12-21 04:08:35 -08001464 // Convert an encoding statistics level to corresponding encoding statistics
1465 // kinds
1466 int32_t encodingStatisticsLevel = VIDEO_ENCODING_STATISTICS_LEVEL_NONE;
1467 if ((config->mDomain & Config::IS_ENCODER)
1468 && (config->mDomain & Config::IS_VIDEO)
1469 && msg->findInt32(KEY_VIDEO_ENCODING_STATISTICS_LEVEL, &encodingStatisticsLevel)) {
1470 // Higher level include all the enc stats belong to lower level.
1471 switch (encodingStatisticsLevel) {
1472 // case VIDEO_ENCODING_STATISTICS_LEVEL_2: // reserved for the future level 2
1473 // with more enc stat kinds
1474 // Future extended encoding statistics for the level 2 should be added here
1475 case VIDEO_ENCODING_STATISTICS_LEVEL_1:
1476 config->subscribeToConfigUpdate(comp,
1477 {kParamIndexAverageBlockQuantization, kParamIndexPictureType});
1478 break;
1479 case VIDEO_ENCODING_STATISTICS_LEVEL_NONE:
1480 break;
1481 }
1482 }
1483 ALOGD("encoding statistics level = %d", encodingStatisticsLevel);
1484
Wonsik Kimd91f3fb2021-02-24 12:35:31 -08001485 ALOGD("setup formats input: %s",
1486 config->mInputFormat->debugString().c_str());
1487 ALOGD("setup formats output: %s",
Pawin Vongmasa36653902018-11-15 00:10:25 -08001488 config->mOutputFormat->debugString().c_str());
1489 return OK;
1490 };
1491 if (tryAndReportOnError(doConfig) != OK) {
1492 return;
1493 }
1494
Wonsik Kim155d5cb2019-10-09 12:49:49 -07001495 Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig);
1496 const std::unique_ptr<Config> &config = *configLocked;
Pawin Vongmasa36653902018-11-15 00:10:25 -08001497
Houxiang Dai183ca3d2021-02-04 14:20:11 +08001498 config->queryConfiguration(comp);
1499
Pawin Vongmasa36653902018-11-15 00:10:25 -08001500 mCallback->onComponentConfigured(config->mInputFormat, config->mOutputFormat);
1501}
1502
1503void CCodec::initiateCreateInputSurface() {
1504 status_t err = [this] {
1505 Mutexed<State>::Locked state(mState);
1506 if (state->get() != ALLOCATED) {
1507 return UNKNOWN_ERROR;
1508 }
1509 // TODO: read it from intf() properly.
1510 if (state->comp->getName().find("encoder") == std::string::npos) {
1511 return INVALID_OPERATION;
1512 }
1513 return OK;
1514 }();
1515 if (err != OK) {
1516 mCallback->onInputSurfaceCreationFailed(err);
1517 return;
1518 }
1519
1520 (new AMessage(kWhatCreateInputSurface, this))->post();
1521}
1522
Lajos Molnar47118272019-01-31 16:28:04 -08001523sp<PersistentSurface> CCodec::CreateOmxInputSurface() {
1524 using namespace android::hardware::media::omx::V1_0;
1525 using namespace android::hardware::media::omx::V1_0::utils;
1526 using namespace android::hardware::graphics::bufferqueue::V1_0::utils;
1527 typedef android::hardware::media::omx::V1_0::Status OmxStatus;
1528 android::sp<IOmx> omx = IOmx::getService();
1529 typedef android::hardware::graphics::bufferqueue::V1_0::
1530 IGraphicBufferProducer HGraphicBufferProducer;
1531 typedef android::hardware::media::omx::V1_0::
1532 IGraphicBufferSource HGraphicBufferSource;
1533 OmxStatus s;
1534 android::sp<HGraphicBufferProducer> gbp;
1535 android::sp<HGraphicBufferSource> gbs;
Pawin Vongmasa18588322019-05-18 01:52:13 -07001536
Chong Zhangc8ce1d82019-03-27 10:18:38 -07001537 using ::android::hardware::Return;
1538 Return<void> transStatus = omx->createInputSurface(
Lajos Molnar47118272019-01-31 16:28:04 -08001539 [&s, &gbp, &gbs](
1540 OmxStatus status,
1541 const android::sp<HGraphicBufferProducer>& producer,
1542 const android::sp<HGraphicBufferSource>& source) {
1543 s = status;
1544 gbp = producer;
1545 gbs = source;
1546 });
1547 if (transStatus.isOk() && s == OmxStatus::OK) {
Wonsik Kim9917d4a2019-10-24 12:56:38 -07001548 return new PersistentSurface(new H2BGraphicBufferProducer(gbp), gbs);
Lajos Molnar47118272019-01-31 16:28:04 -08001549 }
1550
1551 return nullptr;
1552}
1553
1554sp<PersistentSurface> CCodec::CreateCompatibleInputSurface() {
1555 sp<PersistentSurface> surface(CreateInputSurface());
1556
1557 if (surface == nullptr) {
1558 surface = CreateOmxInputSurface();
1559 }
1560
1561 return surface;
1562}
1563
Pawin Vongmasa36653902018-11-15 00:10:25 -08001564void CCodec::createInputSurface() {
1565 status_t err;
1566 sp<IGraphicBufferProducer> bufferProducer;
1567
Pawin Vongmasa36653902018-11-15 00:10:25 -08001568 sp<AMessage> outputFormat;
Wonsik Kim9eac4d12019-05-23 12:58:48 -07001569 uint64_t usage = 0;
Pawin Vongmasa36653902018-11-15 00:10:25 -08001570 {
Wonsik Kim155d5cb2019-10-09 12:49:49 -07001571 Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig);
1572 const std::unique_ptr<Config> &config = *configLocked;
Pawin Vongmasa36653902018-11-15 00:10:25 -08001573 outputFormat = config->mOutputFormat;
Wonsik Kim9eac4d12019-05-23 12:58:48 -07001574 usage = config->mISConfig ? config->mISConfig->mUsage : 0;
Pawin Vongmasa36653902018-11-15 00:10:25 -08001575 }
1576
Lajos Molnar47118272019-01-31 16:28:04 -08001577 sp<PersistentSurface> persistentSurface = CreateCompatibleInputSurface();
Wonsik Kim9917d4a2019-10-24 12:56:38 -07001578 sp<hidl::base::V1_0::IBase> hidlTarget = persistentSurface->getHidlTarget();
1579 sp<IInputSurface> hidlInputSurface = IInputSurface::castFrom(hidlTarget);
1580 sp<HGraphicBufferSource> gbs = HGraphicBufferSource::castFrom(hidlTarget);
Pawin Vongmasa36653902018-11-15 00:10:25 -08001581
Wonsik Kim9917d4a2019-10-24 12:56:38 -07001582 if (hidlInputSurface) {
Pawin Vongmasa1c75a232019-01-09 04:41:52 -08001583 std::shared_ptr<Codec2Client::InputSurface> inputSurface =
1584 std::make_shared<Codec2Client::InputSurface>(hidlInputSurface);
Pawin Vongmasa36653902018-11-15 00:10:25 -08001585 err = setupInputSurface(std::make_shared<C2InputSurfaceWrapper>(
Pawin Vongmasa1c75a232019-01-09 04:41:52 -08001586 inputSurface));
1587 bufferProducer = inputSurface->getGraphicBufferProducer();
Wonsik Kim9917d4a2019-10-24 12:56:38 -07001588 } else if (gbs) {
Pawin Vongmasa36653902018-11-15 00:10:25 -08001589 int32_t width = 0;
1590 (void)outputFormat->findInt32("width", &width);
1591 int32_t height = 0;
1592 (void)outputFormat->findInt32("height", &height);
1593 err = setupInputSurface(std::make_shared<GraphicBufferSourceWrapper>(
Wonsik Kim9917d4a2019-10-24 12:56:38 -07001594 gbs, width, height, usage));
Pawin Vongmasa36653902018-11-15 00:10:25 -08001595 bufferProducer = persistentSurface->getBufferProducer();
Wonsik Kim9917d4a2019-10-24 12:56:38 -07001596 } else {
1597 ALOGE("Corrupted input surface");
1598 mCallback->onInputSurfaceCreationFailed(UNKNOWN_ERROR);
1599 return;
Pawin Vongmasa36653902018-11-15 00:10:25 -08001600 }
1601
1602 if (err != OK) {
1603 ALOGE("Failed to set up input surface: %d", err);
1604 mCallback->onInputSurfaceCreationFailed(err);
1605 return;
1606 }
1607
Wonsik Kim7b9e6db2021-05-10 13:31:40 -07001608 // Formats can change after setupInputSurface
1609 sp<AMessage> inputFormat;
1610 {
1611 Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig);
1612 const std::unique_ptr<Config> &config = *configLocked;
1613 inputFormat = config->mInputFormat;
1614 outputFormat = config->mOutputFormat;
1615 }
Pawin Vongmasa36653902018-11-15 00:10:25 -08001616 mCallback->onInputSurfaceCreated(
1617 inputFormat,
1618 outputFormat,
1619 new BufferProducerWrapper(bufferProducer));
1620}
1621
1622status_t CCodec::setupInputSurface(const std::shared_ptr<InputSurfaceWrapper> &surface) {
Wonsik Kim155d5cb2019-10-09 12:49:49 -07001623 Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig);
1624 const std::unique_ptr<Config> &config = *configLocked;
Pawin Vongmasa36653902018-11-15 00:10:25 -08001625 config->mUsingSurface = true;
1626
1627 // we are now using surface - apply default color aspects to input format - as well as
1628 // get dataspace
Wonsik Kim8a6ed372019-12-03 16:05:51 -08001629 bool inputFormatChanged = config->updateFormats(Config::IS_INPUT);
Pawin Vongmasa36653902018-11-15 00:10:25 -08001630
1631 // configure dataspace
1632 static_assert(sizeof(int32_t) == sizeof(android_dataspace), "dataspace size mismatch");
Wonsik Kim66b19552021-08-02 16:07:49 -07001633
1634 // The output format contains app-configured color aspects, and the input format
1635 // has the default color aspects. Use the default for the unspecified params.
1636 ColorAspects inputColorAspects, colorAspects;
1637 getColorAspectsFromFormat(config->mOutputFormat, colorAspects);
1638 getColorAspectsFromFormat(config->mInputFormat, inputColorAspects);
1639 if (colorAspects.mRange == ColorAspects::RangeUnspecified) {
1640 colorAspects.mRange = inputColorAspects.mRange;
1641 }
1642 if (colorAspects.mPrimaries == ColorAspects::PrimariesUnspecified) {
1643 colorAspects.mPrimaries = inputColorAspects.mPrimaries;
1644 }
1645 if (colorAspects.mTransfer == ColorAspects::TransferUnspecified) {
1646 colorAspects.mTransfer = inputColorAspects.mTransfer;
1647 }
1648 if (colorAspects.mMatrixCoeffs == ColorAspects::MatrixUnspecified) {
1649 colorAspects.mMatrixCoeffs = inputColorAspects.mMatrixCoeffs;
1650 }
1651 android_dataspace dataSpace = getDataSpaceForColorAspects(
1652 colorAspects, /* mayExtend = */ false);
Pawin Vongmasa36653902018-11-15 00:10:25 -08001653 surface->setDataSpace(dataSpace);
Wonsik Kim66b19552021-08-02 16:07:49 -07001654 setColorAspectsIntoFormat(colorAspects, config->mInputFormat, /* force = */ true);
1655 config->mInputFormat->setInt32("android._dataspace", int32_t(dataSpace));
1656
1657 ALOGD("input format %s to %s",
1658 inputFormatChanged ? "changed" : "unchanged",
1659 config->mInputFormat->debugString().c_str());
Pawin Vongmasa36653902018-11-15 00:10:25 -08001660
1661 status_t err = mChannel->setInputSurface(surface);
1662 if (err != OK) {
1663 // undo input format update
1664 config->mUsingSurface = false;
Wonsik Kim8a6ed372019-12-03 16:05:51 -08001665 (void)config->updateFormats(Config::IS_INPUT);
Pawin Vongmasa36653902018-11-15 00:10:25 -08001666 return err;
1667 }
1668 config->mInputSurface = surface;
1669
1670 if (config->mISConfig) {
1671 surface->configure(*config->mISConfig);
1672 } else {
1673 ALOGD("ISConfig: no configuration");
1674 }
1675
Pawin Vongmasa1f213362019-01-24 06:59:16 -08001676 return OK;
Pawin Vongmasa36653902018-11-15 00:10:25 -08001677}
1678
1679void CCodec::initiateSetInputSurface(const sp<PersistentSurface> &surface) {
1680 sp<AMessage> msg = new AMessage(kWhatSetInputSurface, this);
1681 msg->setObject("surface", surface);
1682 msg->post();
1683}
1684
1685void CCodec::setInputSurface(const sp<PersistentSurface> &surface) {
Pawin Vongmasa36653902018-11-15 00:10:25 -08001686 sp<AMessage> outputFormat;
Wonsik Kim9eac4d12019-05-23 12:58:48 -07001687 uint64_t usage = 0;
Pawin Vongmasa36653902018-11-15 00:10:25 -08001688 {
Wonsik Kim155d5cb2019-10-09 12:49:49 -07001689 Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig);
1690 const std::unique_ptr<Config> &config = *configLocked;
Pawin Vongmasa36653902018-11-15 00:10:25 -08001691 outputFormat = config->mOutputFormat;
Wonsik Kim9eac4d12019-05-23 12:58:48 -07001692 usage = config->mISConfig ? config->mISConfig->mUsage : 0;
Pawin Vongmasa36653902018-11-15 00:10:25 -08001693 }
Wonsik Kim9917d4a2019-10-24 12:56:38 -07001694 sp<hidl::base::V1_0::IBase> hidlTarget = surface->getHidlTarget();
1695 sp<IInputSurface> inputSurface = IInputSurface::castFrom(hidlTarget);
1696 sp<HGraphicBufferSource> gbs = HGraphicBufferSource::castFrom(hidlTarget);
1697 if (inputSurface) {
Pawin Vongmasa36653902018-11-15 00:10:25 -08001698 status_t err = setupInputSurface(std::make_shared<C2InputSurfaceWrapper>(
1699 std::make_shared<Codec2Client::InputSurface>(inputSurface)));
1700 if (err != OK) {
1701 ALOGE("Failed to set up input surface: %d", err);
1702 mCallback->onInputSurfaceDeclined(err);
1703 return;
1704 }
Wonsik Kim9917d4a2019-10-24 12:56:38 -07001705 } else if (gbs) {
Pawin Vongmasa36653902018-11-15 00:10:25 -08001706 int32_t width = 0;
1707 (void)outputFormat->findInt32("width", &width);
1708 int32_t height = 0;
1709 (void)outputFormat->findInt32("height", &height);
1710 status_t err = setupInputSurface(std::make_shared<GraphicBufferSourceWrapper>(
Wonsik Kim9917d4a2019-10-24 12:56:38 -07001711 gbs, width, height, usage));
Pawin Vongmasa36653902018-11-15 00:10:25 -08001712 if (err != OK) {
1713 ALOGE("Failed to set up input surface: %d", err);
1714 mCallback->onInputSurfaceDeclined(err);
1715 return;
1716 }
Wonsik Kim9917d4a2019-10-24 12:56:38 -07001717 } else {
1718 ALOGE("Failed to set input surface: Corrupted surface.");
1719 mCallback->onInputSurfaceDeclined(UNKNOWN_ERROR);
1720 return;
Pawin Vongmasa36653902018-11-15 00:10:25 -08001721 }
Wonsik Kim7b9e6db2021-05-10 13:31:40 -07001722 // Formats can change after setupInputSurface
1723 sp<AMessage> inputFormat;
1724 {
1725 Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig);
1726 const std::unique_ptr<Config> &config = *configLocked;
1727 inputFormat = config->mInputFormat;
1728 outputFormat = config->mOutputFormat;
1729 }
Pawin Vongmasa36653902018-11-15 00:10:25 -08001730 mCallback->onInputSurfaceAccepted(inputFormat, outputFormat);
1731}
1732
1733void CCodec::initiateStart() {
1734 auto setStarting = [this] {
1735 Mutexed<State>::Locked state(mState);
1736 if (state->get() != ALLOCATED) {
1737 return UNKNOWN_ERROR;
1738 }
1739 state->set(STARTING);
1740 return OK;
1741 };
1742 if (tryAndReportOnError(setStarting) != OK) {
1743 return;
1744 }
1745
1746 (new AMessage(kWhatStart, this))->post();
1747}
1748
1749void CCodec::start() {
1750 std::shared_ptr<Codec2Client::Component> comp;
1751 auto checkStarting = [this, &comp] {
1752 Mutexed<State>::Locked state(mState);
1753 if (state->get() != STARTING) {
1754 return UNKNOWN_ERROR;
1755 }
1756 comp = state->comp;
1757 return OK;
1758 };
1759 if (tryAndReportOnError(checkStarting) != OK) {
1760 return;
1761 }
1762
1763 c2_status_t err = comp->start();
1764 if (err != C2_OK) {
1765 mCallback->onError(toStatusT(err, C2_OPERATION_Component_start),
1766 ACTION_CODE_FATAL);
1767 return;
1768 }
1769 sp<AMessage> inputFormat;
1770 sp<AMessage> outputFormat;
Pawin Vongmasa1f213362019-01-24 06:59:16 -08001771 status_t err2 = OK;
Wonsik Kimfb7a7672019-12-27 17:13:33 -08001772 bool buffersBoundToCodec = false;
Pawin Vongmasa36653902018-11-15 00:10:25 -08001773 {
Wonsik Kim155d5cb2019-10-09 12:49:49 -07001774 Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig);
1775 const std::unique_ptr<Config> &config = *configLocked;
Pawin Vongmasa36653902018-11-15 00:10:25 -08001776 inputFormat = config->mInputFormat;
Wonsik Kim274c8322020-02-28 10:42:21 -08001777 // start triggers format dup
1778 outputFormat = config->mOutputFormat = config->mOutputFormat->dup();
Pawin Vongmasa1f213362019-01-24 06:59:16 -08001779 if (config->mInputSurface) {
1780 err2 = config->mInputSurface->start();
Wonsik Kim673dd192021-01-29 14:58:12 -08001781 config->mInputSurfaceDataspace = config->mInputSurface->getDataspace();
Pawin Vongmasa1f213362019-01-24 06:59:16 -08001782 }
Wonsik Kimfb7a7672019-12-27 17:13:33 -08001783 buffersBoundToCodec = config->mBuffersBoundToCodec;
Pawin Vongmasa36653902018-11-15 00:10:25 -08001784 }
Pawin Vongmasa1f213362019-01-24 06:59:16 -08001785 if (err2 != OK) {
1786 mCallback->onError(err2, ACTION_CODE_FATAL);
1787 return;
1788 }
Wonsik Kimfb7a7672019-12-27 17:13:33 -08001789 err2 = mChannel->start(inputFormat, outputFormat, buffersBoundToCodec);
Pawin Vongmasa36653902018-11-15 00:10:25 -08001790 if (err2 != OK) {
1791 mCallback->onError(err2, ACTION_CODE_FATAL);
1792 return;
1793 }
1794
1795 auto setRunning = [this] {
1796 Mutexed<State>::Locked state(mState);
1797 if (state->get() != STARTING) {
1798 return UNKNOWN_ERROR;
1799 }
1800 state->set(RUNNING);
1801 return OK;
1802 };
1803 if (tryAndReportOnError(setRunning) != OK) {
1804 return;
1805 }
1806 mCallback->onStartCompleted();
1807
1808 (void)mChannel->requestInitialInputBuffers();
1809}
1810
1811void CCodec::initiateShutdown(bool keepComponentAllocated) {
1812 if (keepComponentAllocated) {
1813 initiateStop();
1814 } else {
1815 initiateRelease();
1816 }
1817}
1818
1819void CCodec::initiateStop() {
1820 {
1821 Mutexed<State>::Locked state(mState);
1822 if (state->get() == ALLOCATED
1823 || state->get() == RELEASED
1824 || state->get() == STOPPING
1825 || state->get() == RELEASING) {
1826 // We're already stopped, released, or doing it right now.
1827 state.unlock();
1828 mCallback->onStopCompleted();
1829 state.lock();
1830 return;
1831 }
1832 state->set(STOPPING);
1833 }
1834
Wonsik Kim936a89c2020-05-08 16:07:50 -07001835 mChannel->reset();
Pawin Vongmasa36653902018-11-15 00:10:25 -08001836 (new AMessage(kWhatStop, this))->post();
1837}
1838
1839void CCodec::stop() {
1840 std::shared_ptr<Codec2Client::Component> comp;
1841 {
1842 Mutexed<State>::Locked state(mState);
1843 if (state->get() == RELEASING) {
1844 state.unlock();
1845 // We're already stopped or release is in progress.
1846 mCallback->onStopCompleted();
1847 state.lock();
1848 return;
1849 } else if (state->get() != STOPPING) {
1850 state.unlock();
1851 mCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL);
1852 state.lock();
1853 return;
1854 }
1855 comp = state->comp;
1856 }
1857 status_t err = comp->stop();
1858 if (err != C2_OK) {
1859 // TODO: convert err into status_t
1860 mCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL);
1861 }
1862
1863 {
Wonsik Kim155d5cb2019-10-09 12:49:49 -07001864 Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig);
1865 const std::unique_ptr<Config> &config = *configLocked;
Pawin Vongmasa1f213362019-01-24 06:59:16 -08001866 if (config->mInputSurface) {
1867 config->mInputSurface->disconnect();
1868 config->mInputSurface = nullptr;
Wonsik Kim673dd192021-01-29 14:58:12 -08001869 config->mInputSurfaceDataspace = HAL_DATASPACE_UNKNOWN;
Pawin Vongmasa1f213362019-01-24 06:59:16 -08001870 }
1871 }
1872 {
Pawin Vongmasa36653902018-11-15 00:10:25 -08001873 Mutexed<State>::Locked state(mState);
1874 if (state->get() == STOPPING) {
1875 state->set(ALLOCATED);
1876 }
1877 }
1878 mCallback->onStopCompleted();
1879}
1880
1881void CCodec::initiateRelease(bool sendCallback /* = true */) {
Pawin Vongmasa1f213362019-01-24 06:59:16 -08001882 bool clearInputSurfaceIfNeeded = false;
Pawin Vongmasa36653902018-11-15 00:10:25 -08001883 {
1884 Mutexed<State>::Locked state(mState);
1885 if (state->get() == RELEASED || state->get() == RELEASING) {
1886 // We're already released or doing it right now.
1887 if (sendCallback) {
1888 state.unlock();
1889 mCallback->onReleaseCompleted();
1890 state.lock();
1891 }
1892 return;
1893 }
1894 if (state->get() == ALLOCATING) {
1895 state->set(RELEASING);
1896 // With the altered state allocate() would fail and clean up.
1897 if (sendCallback) {
1898 state.unlock();
1899 mCallback->onReleaseCompleted();
1900 state.lock();
1901 }
1902 return;
1903 }
Pawin Vongmasa1f213362019-01-24 06:59:16 -08001904 if (state->get() == STARTING
1905 || state->get() == RUNNING
1906 || state->get() == STOPPING) {
1907 // Input surface may have been started, so clean up is needed.
1908 clearInputSurfaceIfNeeded = true;
1909 }
Pawin Vongmasa36653902018-11-15 00:10:25 -08001910 state->set(RELEASING);
1911 }
1912
Pawin Vongmasa1f213362019-01-24 06:59:16 -08001913 if (clearInputSurfaceIfNeeded) {
Wonsik Kim155d5cb2019-10-09 12:49:49 -07001914 Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig);
1915 const std::unique_ptr<Config> &config = *configLocked;
Pawin Vongmasa1f213362019-01-24 06:59:16 -08001916 if (config->mInputSurface) {
1917 config->mInputSurface->disconnect();
1918 config->mInputSurface = nullptr;
Wonsik Kim673dd192021-01-29 14:58:12 -08001919 config->mInputSurfaceDataspace = HAL_DATASPACE_UNKNOWN;
Pawin Vongmasa1f213362019-01-24 06:59:16 -08001920 }
1921 }
1922
Wonsik Kim936a89c2020-05-08 16:07:50 -07001923 mChannel->reset();
Pawin Vongmasa36653902018-11-15 00:10:25 -08001924 // thiz holds strong ref to this while the thread is running.
1925 sp<CCodec> thiz(this);
1926 std::thread([thiz, sendCallback] { thiz->release(sendCallback); }).detach();
1927}
1928
1929void CCodec::release(bool sendCallback) {
1930 std::shared_ptr<Codec2Client::Component> comp;
1931 {
1932 Mutexed<State>::Locked state(mState);
1933 if (state->get() == RELEASED) {
1934 if (sendCallback) {
1935 state.unlock();
1936 mCallback->onReleaseCompleted();
1937 state.lock();
1938 }
1939 return;
1940 }
1941 comp = state->comp;
1942 }
1943 comp->release();
1944
1945 {
1946 Mutexed<State>::Locked state(mState);
1947 state->set(RELEASED);
1948 state->comp.reset();
1949 }
Wonsik Kim936a89c2020-05-08 16:07:50 -07001950 (new AMessage(kWhatRelease, this))->post();
Pawin Vongmasa36653902018-11-15 00:10:25 -08001951 if (sendCallback) {
1952 mCallback->onReleaseCompleted();
1953 }
1954}
1955
1956status_t CCodec::setSurface(const sp<Surface> &surface) {
Wonsik Kim75e22f42021-04-14 23:34:51 -07001957 {
1958 Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig);
1959 const std::unique_ptr<Config> &config = *configLocked;
Houxiang Dai7ab7ee62021-09-30 16:08:51 +08001960 sp<ANativeWindow> nativeWindow = static_cast<ANativeWindow *>(surface.get());
1961 status_t err = OK;
1962
Wonsik Kim75e22f42021-04-14 23:34:51 -07001963 if (config->mTunneled && config->mSidebandHandle != nullptr) {
Houxiang Dai7ab7ee62021-09-30 16:08:51 +08001964 err = native_window_set_sideband_stream(
Wonsik Kim75e22f42021-04-14 23:34:51 -07001965 nativeWindow.get(),
1966 const_cast<native_handle_t *>(config->mSidebandHandle->handle()));
1967 if (err != OK) {
1968 ALOGE("NativeWindow(%p) native_window_set_sideband_stream(%p) failed! (err %d).",
1969 nativeWindow.get(), config->mSidebandHandle->handle(), err);
1970 return err;
1971 }
Houxiang Dai7ab7ee62021-09-30 16:08:51 +08001972 } else {
1973 // Explicitly reset the sideband handle of the window for
1974 // non-tunneled video in case the window was previously used
1975 // for a tunneled video playback.
1976 err = native_window_set_sideband_stream(nativeWindow.get(), nullptr);
1977 if (err != OK) {
1978 ALOGE("native_window_set_sideband_stream(nullptr) failed! (err %d).", err);
1979 return err;
1980 }
ted.sun765db4d2020-06-23 14:03:41 +08001981 }
1982 }
Pawin Vongmasa36653902018-11-15 00:10:25 -08001983 return mChannel->setSurface(surface);
1984}
1985
1986void CCodec::signalFlush() {
1987 status_t err = [this] {
1988 Mutexed<State>::Locked state(mState);
1989 if (state->get() == FLUSHED) {
1990 return ALREADY_EXISTS;
1991 }
1992 if (state->get() != RUNNING) {
1993 return UNKNOWN_ERROR;
1994 }
1995 state->set(FLUSHING);
1996 return OK;
1997 }();
1998 switch (err) {
1999 case ALREADY_EXISTS:
2000 mCallback->onFlushCompleted();
2001 return;
2002 case OK:
2003 break;
2004 default:
2005 mCallback->onError(err, ACTION_CODE_FATAL);
2006 return;
2007 }
2008
2009 mChannel->stop();
2010 (new AMessage(kWhatFlush, this))->post();
2011}
2012
2013void CCodec::flush() {
2014 std::shared_ptr<Codec2Client::Component> comp;
2015 auto checkFlushing = [this, &comp] {
2016 Mutexed<State>::Locked state(mState);
2017 if (state->get() != FLUSHING) {
2018 return UNKNOWN_ERROR;
2019 }
2020 comp = state->comp;
2021 return OK;
2022 };
2023 if (tryAndReportOnError(checkFlushing) != OK) {
2024 return;
2025 }
2026
2027 std::list<std::unique_ptr<C2Work>> flushedWork;
2028 c2_status_t err = comp->flush(C2Component::FLUSH_COMPONENT, &flushedWork);
2029 {
2030 Mutexed<std::list<std::unique_ptr<C2Work>>>::Locked queue(mWorkDoneQueue);
2031 flushedWork.splice(flushedWork.end(), *queue);
2032 }
2033 if (err != C2_OK) {
2034 // TODO: convert err into status_t
2035 mCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL);
2036 }
2037
2038 mChannel->flush(flushedWork);
Pawin Vongmasa36653902018-11-15 00:10:25 -08002039
2040 {
2041 Mutexed<State>::Locked state(mState);
Iris Changce521ee2019-07-05 16:18:54 +08002042 if (state->get() == FLUSHING) {
2043 state->set(FLUSHED);
2044 }
Pawin Vongmasa36653902018-11-15 00:10:25 -08002045 }
2046 mCallback->onFlushCompleted();
2047}
2048
2049void CCodec::signalResume() {
Wonsik Kime75a5da2020-02-14 17:29:03 -08002050 std::shared_ptr<Codec2Client::Component> comp;
2051 auto setResuming = [this, &comp] {
Pawin Vongmasa36653902018-11-15 00:10:25 -08002052 Mutexed<State>::Locked state(mState);
2053 if (state->get() != FLUSHED) {
2054 return UNKNOWN_ERROR;
2055 }
2056 state->set(RESUMING);
Wonsik Kime75a5da2020-02-14 17:29:03 -08002057 comp = state->comp;
Pawin Vongmasa36653902018-11-15 00:10:25 -08002058 return OK;
2059 };
2060 if (tryAndReportOnError(setResuming) != OK) {
2061 return;
2062 }
2063
Wonsik Kime75a5da2020-02-14 17:29:03 -08002064 {
2065 Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig);
2066 const std::unique_ptr<Config> &config = *configLocked;
Harish Mahendrakar8c537502021-02-23 21:20:22 -08002067 sp<AMessage> outputFormat = config->mOutputFormat;
Wonsik Kime75a5da2020-02-14 17:29:03 -08002068 config->queryConfiguration(comp);
Harish Mahendrakar8c537502021-02-23 21:20:22 -08002069 RevertOutputFormatIfNeeded(outputFormat, config->mOutputFormat);
Wonsik Kime75a5da2020-02-14 17:29:03 -08002070 }
2071
Wonsik Kimfb7a7672019-12-27 17:13:33 -08002072 (void)mChannel->start(nullptr, nullptr, [&]{
2073 Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig);
2074 const std::unique_ptr<Config> &config = *configLocked;
2075 return config->mBuffersBoundToCodec;
2076 }());
Pawin Vongmasa36653902018-11-15 00:10:25 -08002077
2078 {
2079 Mutexed<State>::Locked state(mState);
2080 if (state->get() != RESUMING) {
2081 state.unlock();
2082 mCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL);
2083 state.lock();
2084 return;
2085 }
2086 state->set(RUNNING);
2087 }
2088
2089 (void)mChannel->requestInitialInputBuffers();
2090}
2091
Wonsik Kimaa484ac2019-02-13 16:54:02 -08002092void CCodec::signalSetParameters(const sp<AMessage> &msg) {
Pawin Vongmasa36653902018-11-15 00:10:25 -08002093 std::shared_ptr<Codec2Client::Component> comp;
2094 auto checkState = [this, &comp] {
2095 Mutexed<State>::Locked state(mState);
2096 if (state->get() == RELEASED) {
2097 return INVALID_OPERATION;
2098 }
2099 comp = state->comp;
2100 return OK;
2101 };
2102 if (tryAndReportOnError(checkState) != OK) {
2103 return;
2104 }
2105
Wonsik Kimaa484ac2019-02-13 16:54:02 -08002106 // NOTE: We used to ignore "bitrate" at setParameters; replicate
2107 // the behavior here.
2108 sp<AMessage> params = msg;
2109 int32_t bitrate;
2110 if (params->findInt32(KEY_BIT_RATE, &bitrate)) {
2111 params = msg->dup();
2112 params->removeEntryAt(params->findEntryByName(KEY_BIT_RATE));
2113 }
2114
Houxiang Dai5a97b472021-03-22 17:56:04 +08002115 int32_t syncId = 0;
2116 if (params->findInt32("audio-hw-sync", &syncId)
2117 || params->findInt32("hw-av-sync-id", &syncId)) {
2118 configureTunneledVideoPlayback(comp, nullptr, params);
2119 }
2120
Wonsik Kim155d5cb2019-10-09 12:49:49 -07002121 Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig);
2122 const std::unique_ptr<Config> &config = *configLocked;
Pawin Vongmasa36653902018-11-15 00:10:25 -08002123
2124 /**
2125 * Handle input surface parameters
2126 */
2127 if ((config->mDomain & (Config::IS_VIDEO | Config::IS_IMAGE))
Wonsik Kim8a6ed372019-12-03 16:05:51 -08002128 && (config->mDomain & Config::IS_ENCODER)
2129 && config->mInputSurface && config->mISConfig) {
Chong Zhang038e8f82019-02-06 19:05:14 -08002130 (void)params->findInt64(PARAMETER_KEY_OFFSET_TIME, &config->mISConfig->mTimeOffsetUs);
Pawin Vongmasa36653902018-11-15 00:10:25 -08002131
2132 if (params->findInt64("skip-frames-before", &config->mISConfig->mStartAtUs)) {
2133 config->mISConfig->mStopped = false;
2134 } else if (params->findInt64("stop-time-us", &config->mISConfig->mStopAtUs)) {
2135 config->mISConfig->mStopped = true;
2136 }
2137
2138 int32_t value;
Chong Zhang038e8f82019-02-06 19:05:14 -08002139 if (params->findInt32(PARAMETER_KEY_SUSPEND, &value)) {
Pawin Vongmasa36653902018-11-15 00:10:25 -08002140 config->mISConfig->mSuspended = value;
2141 config->mISConfig->mSuspendAtUs = -1;
Chong Zhang038e8f82019-02-06 19:05:14 -08002142 (void)params->findInt64(PARAMETER_KEY_SUSPEND_TIME, &config->mISConfig->mSuspendAtUs);
Pawin Vongmasa36653902018-11-15 00:10:25 -08002143 }
2144
2145 (void)config->mInputSurface->configure(*config->mISConfig);
2146 if (config->mISConfig->mStopped) {
2147 config->mInputFormat->setInt64(
2148 "android._stop-time-offset-us", config->mISConfig->mInputDelayUs);
2149 }
2150 }
2151
2152 std::vector<std::unique_ptr<C2Param>> configUpdate;
2153 (void)config->getConfigUpdateFromSdkParams(
2154 comp, params, Config::IS_PARAM, C2_MAY_BLOCK, &configUpdate);
2155 // Prefer to pass parameters to the buffer channel, so they can be synchronized with the frames.
2156 // Parameter synchronization is not defined when using input surface. For now, route
2157 // these directly to the component.
2158 if (config->mInputSurface == nullptr
2159 && (property_get_bool("debug.stagefright.ccodec_delayed_params", false)
2160 || comp->getName().find("c2.android.") == 0)) {
2161 mChannel->setParameters(configUpdate);
2162 } else {
Wonsik Kim3b4349a2020-11-10 11:54:15 -08002163 sp<AMessage> outputFormat = config->mOutputFormat;
Pawin Vongmasa36653902018-11-15 00:10:25 -08002164 (void)config->setParameters(comp, configUpdate, C2_MAY_BLOCK);
Wonsik Kim3b4349a2020-11-10 11:54:15 -08002165 RevertOutputFormatIfNeeded(outputFormat, config->mOutputFormat);
Pawin Vongmasa36653902018-11-15 00:10:25 -08002166 }
2167}
2168
2169void CCodec::signalEndOfInputStream() {
2170 mCallback->onSignaledInputEOS(mChannel->signalEndOfInputStream());
2171}
2172
2173void CCodec::signalRequestIDRFrame() {
2174 std::shared_ptr<Codec2Client::Component> comp;
2175 {
2176 Mutexed<State>::Locked state(mState);
2177 if (state->get() == RELEASED) {
2178 ALOGD("no IDR request sent since component is released");
2179 return;
2180 }
2181 comp = state->comp;
2182 }
2183 ALOGV("request IDR");
Wonsik Kim155d5cb2019-10-09 12:49:49 -07002184 Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig);
2185 const std::unique_ptr<Config> &config = *configLocked;
Pawin Vongmasa36653902018-11-15 00:10:25 -08002186 std::vector<std::unique_ptr<C2Param>> params;
2187 params.push_back(
2188 std::make_unique<C2StreamRequestSyncFrameTuning::output>(0u, true));
2189 config->setParameters(comp, params, C2_MAY_BLOCK);
2190}
2191
Wonsik Kim874ad382021-03-12 09:59:36 -08002192status_t CCodec::querySupportedParameters(std::vector<std::string> *names) {
2193 Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig);
2194 const std::unique_ptr<Config> &config = *configLocked;
2195 return config->querySupportedParameters(names);
2196}
2197
2198status_t CCodec::describeParameter(
2199 const std::string &name, CodecParameterDescriptor *desc) {
2200 Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig);
2201 const std::unique_ptr<Config> &config = *configLocked;
2202 return config->describe(name, desc);
2203}
2204
2205status_t CCodec::subscribeToParameters(const std::vector<std::string> &names) {
2206 std::shared_ptr<Codec2Client::Component> comp = mState.lock()->comp;
2207 if (!comp) {
2208 return INVALID_OPERATION;
2209 }
2210 Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig);
2211 const std::unique_ptr<Config> &config = *configLocked;
2212 return config->subscribeToVendorConfigUpdate(comp, names);
2213}
2214
2215status_t CCodec::unsubscribeFromParameters(const std::vector<std::string> &names) {
2216 std::shared_ptr<Codec2Client::Component> comp = mState.lock()->comp;
2217 if (!comp) {
2218 return INVALID_OPERATION;
2219 }
2220 Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig);
2221 const std::unique_ptr<Config> &config = *configLocked;
2222 return config->unsubscribeFromVendorConfigUpdate(comp, names);
2223}
2224
Wonsik Kimab34ed62019-01-31 15:28:46 -08002225void CCodec::onWorkDone(std::list<std::unique_ptr<C2Work>> &workItems) {
Pawin Vongmasa36653902018-11-15 00:10:25 -08002226 if (!workItems.empty()) {
Wonsik Kimab34ed62019-01-31 15:28:46 -08002227 Mutexed<std::list<std::unique_ptr<C2Work>>>::Locked queue(mWorkDoneQueue);
2228 queue->splice(queue->end(), workItems);
Pawin Vongmasa36653902018-11-15 00:10:25 -08002229 }
2230 (new AMessage(kWhatWorkDone, this))->post();
2231}
2232
Wonsik Kimab34ed62019-01-31 15:28:46 -08002233void CCodec::onInputBufferDone(uint64_t frameIndex, size_t arrayIndex) {
2234 mChannel->onInputBufferDone(frameIndex, arrayIndex);
Wonsik Kim4f3314d2019-03-26 17:00:34 -07002235 if (arrayIndex == 0) {
2236 // We always put no more than one buffer per work, if we use an input surface.
Wonsik Kim155d5cb2019-10-09 12:49:49 -07002237 Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig);
2238 const std::unique_ptr<Config> &config = *configLocked;
Wonsik Kim4f3314d2019-03-26 17:00:34 -07002239 if (config->mInputSurface) {
2240 config->mInputSurface->onInputBufferDone(frameIndex);
2241 }
2242 }
Pawin Vongmasa36653902018-11-15 00:10:25 -08002243}
2244
2245void CCodec::onMessageReceived(const sp<AMessage> &msg) {
2246 TimePoint now = std::chrono::steady_clock::now();
2247 CCodecWatchdog::getInstance()->watch(this);
2248 switch (msg->what()) {
2249 case kWhatAllocate: {
2250 // C2ComponentStore::createComponent() should return within 100ms.
Wonsik Kim9ee5a7c2019-06-17 11:33:24 -07002251 setDeadline(now, 1500ms, "allocate");
Pawin Vongmasa36653902018-11-15 00:10:25 -08002252 sp<RefBase> obj;
2253 CHECK(msg->findObject("codecInfo", &obj));
2254 allocate((MediaCodecInfo *)obj.get());
2255 break;
2256 }
2257 case kWhatConfigure: {
2258 // C2Component::commit_sm() should return within 5ms.
Wonsik Kim9ee5a7c2019-06-17 11:33:24 -07002259 setDeadline(now, 1500ms, "configure");
Pawin Vongmasa36653902018-11-15 00:10:25 -08002260 sp<AMessage> format;
2261 CHECK(msg->findMessage("format", &format));
2262 configure(format);
2263 break;
2264 }
2265 case kWhatStart: {
2266 // C2Component::start() should return within 500ms.
Wonsik Kim9ee5a7c2019-06-17 11:33:24 -07002267 setDeadline(now, 1500ms, "start");
Pawin Vongmasa36653902018-11-15 00:10:25 -08002268 start();
2269 break;
2270 }
2271 case kWhatStop: {
2272 // C2Component::stop() should return within 500ms.
Wonsik Kim9ee5a7c2019-06-17 11:33:24 -07002273 setDeadline(now, 1500ms, "stop");
Pawin Vongmasa36653902018-11-15 00:10:25 -08002274 stop();
Pawin Vongmasa36653902018-11-15 00:10:25 -08002275 break;
2276 }
2277 case kWhatFlush: {
2278 // C2Component::flush_sm() should return within 5ms.
Wonsik Kim9ee5a7c2019-06-17 11:33:24 -07002279 setDeadline(now, 1500ms, "flush");
Pawin Vongmasa36653902018-11-15 00:10:25 -08002280 flush();
2281 break;
2282 }
Wonsik Kim936a89c2020-05-08 16:07:50 -07002283 case kWhatRelease: {
2284 mChannel->release();
2285 mClient.reset();
2286 mClientListener.reset();
2287 break;
2288 }
Pawin Vongmasa36653902018-11-15 00:10:25 -08002289 case kWhatCreateInputSurface: {
2290 // Surface operations may be briefly blocking.
Wonsik Kim9ee5a7c2019-06-17 11:33:24 -07002291 setDeadline(now, 1500ms, "createInputSurface");
Pawin Vongmasa36653902018-11-15 00:10:25 -08002292 createInputSurface();
2293 break;
2294 }
2295 case kWhatSetInputSurface: {
2296 // Surface operations may be briefly blocking.
Wonsik Kim9ee5a7c2019-06-17 11:33:24 -07002297 setDeadline(now, 1500ms, "setInputSurface");
Pawin Vongmasa36653902018-11-15 00:10:25 -08002298 sp<RefBase> obj;
2299 CHECK(msg->findObject("surface", &obj));
2300 sp<PersistentSurface> surface(static_cast<PersistentSurface *>(obj.get()));
2301 setInputSurface(surface);
2302 break;
2303 }
Pawin Vongmasa36653902018-11-15 00:10:25 -08002304 case kWhatWorkDone: {
2305 std::unique_ptr<C2Work> work;
Pawin Vongmasa36653902018-11-15 00:10:25 -08002306 bool shouldPost = false;
2307 {
2308 Mutexed<std::list<std::unique_ptr<C2Work>>>::Locked queue(mWorkDoneQueue);
2309 if (queue->empty()) {
2310 break;
2311 }
2312 work.swap(queue->front());
2313 queue->pop_front();
2314 shouldPost = !queue->empty();
2315 }
Pawin Vongmasa36653902018-11-15 00:10:25 -08002316 if (shouldPost) {
2317 (new AMessage(kWhatWorkDone, this))->post();
2318 }
2319
Pawin Vongmasa36653902018-11-15 00:10:25 -08002320 // handle configuration changes in work done
Wonsik Kim1f5063d2021-05-03 15:41:17 -07002321 std::shared_ptr<const C2StreamInitDataInfo::output> initData;
Wonsik Kim75e22f42021-04-14 23:34:51 -07002322 sp<AMessage> outputFormat = nullptr;
2323 {
2324 Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig);
2325 const std::unique_ptr<Config> &config = *configLocked;
2326 Config::Watcher<C2StreamInitDataInfo::output> initDataWatcher =
2327 config->watch<C2StreamInitDataInfo::output>();
2328 if (!work->worklets.empty()
2329 && (work->worklets.front()->output.flags
2330 & C2FrameData::FLAG_DISCARD_FRAME) == 0) {
Pawin Vongmasa36653902018-11-15 00:10:25 -08002331
Wonsik Kim75e22f42021-04-14 23:34:51 -07002332 // copy buffer info to config
2333 std::vector<std::unique_ptr<C2Param>> updates;
2334 for (const std::unique_ptr<C2Param> &param
2335 : work->worklets.front()->output.configUpdate) {
2336 updates.push_back(C2Param::Copy(*param));
2337 }
2338 unsigned stream = 0;
2339 std::vector<std::shared_ptr<C2Buffer>> &outputBuffers =
2340 work->worklets.front()->output.buffers;
2341 for (const std::shared_ptr<C2Buffer> &buf : outputBuffers) {
2342 for (const std::shared_ptr<const C2Info> &info : buf->info()) {
2343 // move all info into output-stream #0 domain
2344 updates.emplace_back(
2345 C2Param::CopyAsStream(*info, true /* output */, stream));
2346 }
2347
2348 const std::vector<C2ConstGraphicBlock> blocks = buf->data().graphicBlocks();
2349 // for now only do the first block
2350 if (!blocks.empty()) {
2351 // ALOGV("got output buffer with crop %u,%u+%u,%u and size %u,%u",
2352 // block.crop().left, block.crop().top,
2353 // block.crop().width, block.crop().height,
2354 // block.width(), block.height());
2355 const C2ConstGraphicBlock &block = blocks[0];
2356 updates.emplace_back(new C2StreamCropRectInfo::output(
2357 stream, block.crop()));
Wonsik Kim75e22f42021-04-14 23:34:51 -07002358 }
2359 ++stream;
Pawin Vongmasa36653902018-11-15 00:10:25 -08002360 }
George Burgess IVc813a592020-02-22 22:54:44 -08002361
Wonsik Kim75e22f42021-04-14 23:34:51 -07002362 sp<AMessage> oldFormat = config->mOutputFormat;
2363 config->updateConfiguration(updates, config->mOutputDomain);
2364 RevertOutputFormatIfNeeded(oldFormat, config->mOutputFormat);
Pawin Vongmasa36653902018-11-15 00:10:25 -08002365
Wonsik Kim75e22f42021-04-14 23:34:51 -07002366 // copy standard infos to graphic buffers if not already present (otherwise, we
2367 // may overwrite the actual intermediate value with a final value)
2368 stream = 0;
2369 const static C2Param::Index stdGfxInfos[] = {
2370 C2StreamRotationInfo::output::PARAM_TYPE,
2371 C2StreamColorAspectsInfo::output::PARAM_TYPE,
2372 C2StreamDataSpaceInfo::output::PARAM_TYPE,
2373 C2StreamHdrStaticInfo::output::PARAM_TYPE,
2374 C2StreamHdr10PlusInfo::output::PARAM_TYPE,
2375 C2StreamPixelAspectRatioInfo::output::PARAM_TYPE,
2376 C2StreamSurfaceScalingInfo::output::PARAM_TYPE
2377 };
2378 for (const std::shared_ptr<C2Buffer> &buf : outputBuffers) {
2379 if (buf->data().graphicBlocks().size()) {
2380 for (C2Param::Index ix : stdGfxInfos) {
2381 if (!buf->hasInfo(ix)) {
2382 const C2Param *param =
2383 config->getConfigParameterValue(ix.withStream(stream));
2384 if (param) {
2385 std::shared_ptr<C2Param> info(C2Param::Copy(*param));
2386 buf->setInfo(std::static_pointer_cast<C2Info>(info));
2387 }
Pawin Vongmasa36653902018-11-15 00:10:25 -08002388 }
2389 }
2390 }
Wonsik Kim75e22f42021-04-14 23:34:51 -07002391 ++stream;
Pawin Vongmasa36653902018-11-15 00:10:25 -08002392 }
Pawin Vongmasa36653902018-11-15 00:10:25 -08002393 }
Wonsik Kim75e22f42021-04-14 23:34:51 -07002394 if (config->mInputSurface) {
Brijesh Patelab463672020-11-25 15:38:28 +05302395 if (work->worklets.empty()
2396 || !work->worklets.back()
2397 || (work->worklets.back()->output.flags
2398 & C2FrameData::FLAG_INCOMPLETE) == 0) {
2399 config->mInputSurface->onInputBufferDone(work->input.ordinal.frameIndex);
2400 }
Wonsik Kim75e22f42021-04-14 23:34:51 -07002401 }
2402 if (initDataWatcher.hasChanged()) {
Wonsik Kim1f5063d2021-05-03 15:41:17 -07002403 initData = initDataWatcher.update();
2404 AmendOutputFormatWithCodecSpecificData(
2405 initData->m.value, initData->flexCount(), config->mCodingMediaType,
2406 config->mOutputFormat);
Wonsik Kim75e22f42021-04-14 23:34:51 -07002407 }
2408 outputFormat = config->mOutputFormat;
Wonsik Kim9c387412021-04-19 21:03:53 +00002409 }
2410 mChannel->onWorkDone(
Wonsik Kim1f5063d2021-05-03 15:41:17 -07002411 std::move(work), outputFormat, initData ? initData.get() : nullptr);
Pawin Vongmasa36653902018-11-15 00:10:25 -08002412 break;
2413 }
2414 case kWhatWatch: {
2415 // watch message already posted; no-op.
2416 break;
2417 }
2418 default: {
2419 ALOGE("unrecognized message");
2420 break;
2421 }
2422 }
2423 setDeadline(TimePoint::max(), 0ms, "none");
2424}
2425
2426void CCodec::setDeadline(
2427 const TimePoint &now,
2428 const std::chrono::milliseconds &timeout,
2429 const char *name) {
2430 int32_t mult = std::max(1, property_get_int32("debug.stagefright.ccodec_timeout_mult", 1));
2431 Mutexed<NamedTimePoint>::Locked deadline(mDeadline);
2432 deadline->set(now + (timeout * mult), name);
2433}
2434
ted.sun765db4d2020-06-23 14:03:41 +08002435status_t CCodec::configureTunneledVideoPlayback(
2436 std::shared_ptr<Codec2Client::Component> comp,
2437 sp<NativeHandle> *sidebandHandle,
2438 const sp<AMessage> &msg) {
2439 std::vector<std::unique_ptr<C2SettingResult>> failures;
2440
2441 std::unique_ptr<C2PortTunneledModeTuning::output> tunneledPlayback =
2442 C2PortTunneledModeTuning::output::AllocUnique(
2443 1,
2444 C2PortTunneledModeTuning::Struct::SIDEBAND,
2445 C2PortTunneledModeTuning::Struct::REALTIME,
2446 0);
2447 // TODO: use KEY_AUDIO_HW_SYNC, KEY_HARDWARE_AV_SYNC_ID when they are in MediaCodecConstants.h
2448 if (msg->findInt32("audio-hw-sync", &tunneledPlayback->m.syncId[0])) {
2449 tunneledPlayback->m.syncType = C2PortTunneledModeTuning::Struct::sync_type_t::AUDIO_HW_SYNC;
2450 } else if (msg->findInt32("hw-av-sync-id", &tunneledPlayback->m.syncId[0])) {
2451 tunneledPlayback->m.syncType = C2PortTunneledModeTuning::Struct::sync_type_t::HW_AV_SYNC;
2452 } else {
2453 tunneledPlayback->m.syncType = C2PortTunneledModeTuning::Struct::sync_type_t::REALTIME;
2454 tunneledPlayback->setFlexCount(0);
2455 }
2456 c2_status_t c2err = comp->config({ tunneledPlayback.get() }, C2_MAY_BLOCK, &failures);
2457 if (c2err != C2_OK) {
2458 return UNKNOWN_ERROR;
2459 }
2460
Houxiang Dai5a97b472021-03-22 17:56:04 +08002461 if (sidebandHandle == nullptr) {
2462 return OK;
2463 }
2464
ted.sun765db4d2020-06-23 14:03:41 +08002465 std::vector<std::unique_ptr<C2Param>> params;
2466 c2err = comp->query({}, {C2PortTunnelHandleTuning::output::PARAM_TYPE}, C2_DONT_BLOCK, &params);
2467 if (c2err == C2_OK && params.size() == 1u) {
2468 C2PortTunnelHandleTuning::output *videoTunnelSideband =
2469 C2PortTunnelHandleTuning::output::From(params[0].get());
2470 // Currently, Codec2 only supports non-fd case for sideband native_handle.
2471 native_handle_t *handle = native_handle_create(0, videoTunnelSideband->flexCount());
2472 *sidebandHandle = NativeHandle::create(handle, true /* ownsHandle */);
2473 if (handle != nullptr && videoTunnelSideband->flexCount()) {
2474 memcpy(handle->data, videoTunnelSideband->m.values,
2475 sizeof(int32_t) * videoTunnelSideband->flexCount());
2476 return OK;
2477 } else {
2478 return NO_MEMORY;
2479 }
2480 }
2481 return UNKNOWN_ERROR;
2482}
2483
Pawin Vongmasa36653902018-11-15 00:10:25 -08002484void CCodec::initiateReleaseIfStuck() {
2485 std::string name;
2486 bool pendingDeadline = false;
Wonsik Kimab34ed62019-01-31 15:28:46 -08002487 {
2488 Mutexed<NamedTimePoint>::Locked deadline(mDeadline);
Pawin Vongmasa36653902018-11-15 00:10:25 -08002489 if (deadline->get() < std::chrono::steady_clock::now()) {
2490 name = deadline->getName();
Pawin Vongmasa36653902018-11-15 00:10:25 -08002491 }
2492 if (deadline->get() != TimePoint::max()) {
2493 pendingDeadline = true;
2494 }
2495 }
Wonsik Kim75e22f42021-04-14 23:34:51 -07002496 bool tunneled = false;
Wonsik Kimabca11e2021-04-30 13:11:41 -07002497 bool isMediaTypeKnown = false;
Wonsik Kim75e22f42021-04-14 23:34:51 -07002498 {
Wonsik Kimabca11e2021-04-30 13:11:41 -07002499 static const std::set<std::string> kKnownMediaTypes{
2500 MIMETYPE_VIDEO_VP8,
2501 MIMETYPE_VIDEO_VP9,
2502 MIMETYPE_VIDEO_AV1,
2503 MIMETYPE_VIDEO_AVC,
2504 MIMETYPE_VIDEO_HEVC,
2505 MIMETYPE_VIDEO_MPEG4,
2506 MIMETYPE_VIDEO_H263,
2507 MIMETYPE_VIDEO_MPEG2,
2508 MIMETYPE_VIDEO_RAW,
2509 MIMETYPE_VIDEO_DOLBY_VISION,
2510
2511 MIMETYPE_AUDIO_AMR_NB,
2512 MIMETYPE_AUDIO_AMR_WB,
2513 MIMETYPE_AUDIO_MPEG,
2514 MIMETYPE_AUDIO_AAC,
2515 MIMETYPE_AUDIO_QCELP,
2516 MIMETYPE_AUDIO_VORBIS,
2517 MIMETYPE_AUDIO_OPUS,
2518 MIMETYPE_AUDIO_G711_ALAW,
2519 MIMETYPE_AUDIO_G711_MLAW,
2520 MIMETYPE_AUDIO_RAW,
2521 MIMETYPE_AUDIO_FLAC,
2522 MIMETYPE_AUDIO_MSGSM,
2523 MIMETYPE_AUDIO_AC3,
2524 MIMETYPE_AUDIO_EAC3,
2525
2526 MIMETYPE_IMAGE_ANDROID_HEIC,
2527 };
Wonsik Kim75e22f42021-04-14 23:34:51 -07002528 Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig);
2529 const std::unique_ptr<Config> &config = *configLocked;
2530 tunneled = config->mTunneled;
Wonsik Kimabca11e2021-04-30 13:11:41 -07002531 isMediaTypeKnown = (kKnownMediaTypes.count(config->mCodingMediaType) != 0);
Wonsik Kim75e22f42021-04-14 23:34:51 -07002532 }
Wonsik Kimabca11e2021-04-30 13:11:41 -07002533 if (!tunneled && isMediaTypeKnown && name.empty()) {
Wonsik Kimab34ed62019-01-31 15:28:46 -08002534 constexpr std::chrono::steady_clock::duration kWorkDurationThreshold = 3s;
2535 std::chrono::steady_clock::duration elapsed = mChannel->elapsed();
2536 if (elapsed >= kWorkDurationThreshold) {
2537 name = "queue";
2538 }
2539 if (elapsed > 0s) {
2540 pendingDeadline = true;
2541 }
2542 }
2543 if (name.empty()) {
Pawin Vongmasa36653902018-11-15 00:10:25 -08002544 // We're not stuck.
2545 if (pendingDeadline) {
2546 // If we are not stuck yet but still has deadline coming up,
2547 // post watch message to check back later.
2548 (new AMessage(kWhatWatch, this))->post();
2549 }
2550 return;
2551 }
2552
Chih-Yu Huang82e5ab32021-02-17 16:27:08 +09002553 C2String compName;
2554 {
2555 Mutexed<State>::Locked state(mState);
Wonsik Kim12380072021-05-11 09:59:20 -07002556 if (!state->comp) {
2557 ALOGD("previous call to %s exceeded timeout "
2558 "and the component is already released", name.c_str());
2559 return;
2560 }
Chih-Yu Huang82e5ab32021-02-17 16:27:08 +09002561 compName = state->comp->getName();
2562 }
2563 ALOGW("[%s] previous call to %s exceeded timeout", compName.c_str(), name.c_str());
2564
Pawin Vongmasa36653902018-11-15 00:10:25 -08002565 initiateRelease(false);
2566 mCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL);
2567}
2568
Wonsik Kim155d5cb2019-10-09 12:49:49 -07002569// static
2570PersistentSurface *CCodec::CreateInputSurface() {
Pawin Vongmasa18588322019-05-18 01:52:13 -07002571 using namespace android;
Wonsik Kim9917d4a2019-10-24 12:56:38 -07002572 using ::android::hardware::media::omx::V1_0::implementation::TWGraphicBufferSource;
Pawin Vongmasa36653902018-11-15 00:10:25 -08002573 // Attempt to create a Codec2's input surface.
Pawin Vongmasa18588322019-05-18 01:52:13 -07002574 std::shared_ptr<Codec2Client::InputSurface> inputSurface =
2575 Codec2Client::CreateInputSurface();
Lajos Molnar47118272019-01-31 16:28:04 -08002576 if (!inputSurface) {
Pawin Vongmasa18588322019-05-18 01:52:13 -07002577 if (property_get_int32("debug.stagefright.c2inputsurface", 0) == -1) {
2578 sp<IGraphicBufferProducer> gbp;
2579 sp<OmxGraphicBufferSource> gbs = new OmxGraphicBufferSource();
2580 status_t err = gbs->initCheck();
2581 if (err != OK) {
2582 ALOGE("Failed to create persistent input surface: error %d", err);
2583 return nullptr;
2584 }
2585 return new PersistentSurface(
Wonsik Kim9917d4a2019-10-24 12:56:38 -07002586 gbs->getIGraphicBufferProducer(), new TWGraphicBufferSource(gbs));
Pawin Vongmasa18588322019-05-18 01:52:13 -07002587 } else {
2588 return nullptr;
2589 }
Pawin Vongmasa36653902018-11-15 00:10:25 -08002590 }
Pawin Vongmasa18588322019-05-18 01:52:13 -07002591 return new PersistentSurface(
Lajos Molnar47118272019-01-31 16:28:04 -08002592 inputSurface->getGraphicBufferProducer(),
Pawin Vongmasa18588322019-05-18 01:52:13 -07002593 static_cast<sp<android::hidl::base::V1_0::IBase>>(
Lajos Molnar47118272019-01-31 16:28:04 -08002594 inputSurface->getHalInterface()));
Pawin Vongmasa36653902018-11-15 00:10:25 -08002595}
2596
Wonsik Kimffb889a2020-05-28 11:32:25 -07002597class IntfCache {
2598public:
2599 IntfCache() = default;
2600
2601 status_t init(const std::string &name) {
2602 std::shared_ptr<Codec2Client::Interface> intf{
2603 Codec2Client::CreateInterfaceByName(name.c_str())};
2604 if (!intf) {
2605 ALOGW("IntfCache [%s]: Unrecognized interface name", name.c_str());
2606 mInitStatus = NO_INIT;
2607 return NO_INIT;
2608 }
2609 const static C2StreamUsageTuning::input sUsage{0u /* stream id */};
2610 mFields.push_back(C2FieldSupportedValuesQuery::Possible(
2611 C2ParamField{&sUsage, &sUsage.value}));
2612 c2_status_t err = intf->querySupportedValues(mFields, C2_MAY_BLOCK);
2613 if (err != C2_OK) {
2614 ALOGW("IntfCache [%s]: failed to query usage supported value (err=%d)",
2615 name.c_str(), err);
2616 mFields[0].status = err;
2617 }
2618 std::vector<std::unique_ptr<C2Param>> params;
2619 err = intf->query(
2620 {&mApiFeatures},
Taehwan Kim900b49c2021-12-13 11:16:22 +09002621 {
2622 C2StreamBufferTypeSetting::input::PARAM_TYPE,
2623 C2PortAllocatorsTuning::input::PARAM_TYPE
2624 },
Wonsik Kimffb889a2020-05-28 11:32:25 -07002625 C2_MAY_BLOCK,
2626 &params);
2627 if (err != C2_OK && err != C2_BAD_INDEX) {
2628 ALOGW("IntfCache [%s]: failed to query api features (err=%d)",
2629 name.c_str(), err);
2630 }
2631 while (!params.empty()) {
2632 C2Param *param = params.back().release();
2633 params.pop_back();
2634 if (!param) {
2635 continue;
2636 }
Taehwan Kim900b49c2021-12-13 11:16:22 +09002637 if (param->type() == C2StreamBufferTypeSetting::input::PARAM_TYPE) {
2638 mInputStreamFormat.reset(
2639 C2StreamBufferTypeSetting::input::From(param));
2640 } else if (param->type() == C2PortAllocatorsTuning::input::PARAM_TYPE) {
Wonsik Kimffb889a2020-05-28 11:32:25 -07002641 mInputAllocators.reset(
Wonsik Kimd79ee1f2020-08-27 17:41:56 -07002642 C2PortAllocatorsTuning::input::From(param));
Wonsik Kimffb889a2020-05-28 11:32:25 -07002643 }
2644 }
2645 mInitStatus = OK;
2646 return OK;
Wonsik Kimfcf46c32020-04-22 13:50:45 -07002647 }
Wonsik Kimffb889a2020-05-28 11:32:25 -07002648
2649 status_t initCheck() const { return mInitStatus; }
2650
2651 const C2FieldSupportedValuesQuery &getUsageSupportedValues() const {
2652 CHECK_EQ(1u, mFields.size());
2653 return mFields[0];
2654 }
2655
2656 const C2ApiFeaturesSetting &getApiFeatures() const {
2657 return mApiFeatures;
2658 }
2659
Taehwan Kim900b49c2021-12-13 11:16:22 +09002660 const C2StreamBufferTypeSetting::input &getInputStreamFormat() const {
2661 static std::unique_ptr<C2StreamBufferTypeSetting::input> sInvalidated = []{
2662 std::unique_ptr<C2StreamBufferTypeSetting::input> param;
2663 param.reset(new C2StreamBufferTypeSetting::input(0u, C2BufferData::INVALID));
2664 param->invalidate();
2665 return param;
2666 }();
2667 return mInputStreamFormat ? *mInputStreamFormat : *sInvalidated;
2668 }
2669
Wonsik Kimffb889a2020-05-28 11:32:25 -07002670 const C2PortAllocatorsTuning::input &getInputAllocators() const {
2671 static std::unique_ptr<C2PortAllocatorsTuning::input> sInvalidated = []{
2672 std::unique_ptr<C2PortAllocatorsTuning::input> param =
2673 C2PortAllocatorsTuning::input::AllocUnique(0);
2674 param->invalidate();
2675 return param;
2676 }();
2677 return mInputAllocators ? *mInputAllocators : *sInvalidated;
2678 }
2679
2680private:
2681 status_t mInitStatus{NO_INIT};
2682
2683 std::vector<C2FieldSupportedValuesQuery> mFields;
2684 C2ApiFeaturesSetting mApiFeatures;
Taehwan Kim900b49c2021-12-13 11:16:22 +09002685 std::unique_ptr<C2StreamBufferTypeSetting::input> mInputStreamFormat;
Wonsik Kimffb889a2020-05-28 11:32:25 -07002686 std::unique_ptr<C2PortAllocatorsTuning::input> mInputAllocators;
2687};
2688
2689static const IntfCache &GetIntfCache(const std::string &name) {
2690 static IntfCache sNullIntfCache;
2691 static std::mutex sMutex;
2692 static std::map<std::string, IntfCache> sCache;
2693 std::unique_lock<std::mutex> lock{sMutex};
2694 auto it = sCache.find(name);
2695 if (it == sCache.end()) {
2696 lock.unlock();
2697 IntfCache intfCache;
2698 status_t err = intfCache.init(name);
2699 if (err != OK) {
2700 return sNullIntfCache;
2701 }
2702 lock.lock();
2703 it = sCache.insert({name, std::move(intfCache)}).first;
2704 }
2705 return it->second;
Wonsik Kimfcf46c32020-04-22 13:50:45 -07002706}
2707
Wonsik Kimfb7a7672019-12-27 17:13:33 -08002708static status_t GetCommonAllocatorIds(
2709 const std::vector<std::string> &names,
2710 C2Allocator::type_t type,
2711 std::set<C2Allocator::id_t> *ids) {
2712 int poolMask = GetCodec2PoolMask();
2713 C2PlatformAllocatorStore::id_t preferredLinearId = GetPreferredLinearAllocatorId(poolMask);
2714 C2Allocator::id_t defaultAllocatorId =
2715 (type == C2Allocator::LINEAR) ? preferredLinearId : C2PlatformAllocatorStore::GRALLOC;
2716
2717 ids->clear();
2718 if (names.empty()) {
2719 return OK;
2720 }
Wonsik Kimfcf46c32020-04-22 13:50:45 -07002721 bool firstIteration = true;
2722 for (const std::string &name : names) {
Wonsik Kimffb889a2020-05-28 11:32:25 -07002723 const IntfCache &intfCache = GetIntfCache(name);
2724 if (intfCache.initCheck() != OK) {
Wonsik Kimfcf46c32020-04-22 13:50:45 -07002725 continue;
Wonsik Kimfb7a7672019-12-27 17:13:33 -08002726 }
Taehwan Kim900b49c2021-12-13 11:16:22 +09002727 const C2StreamBufferTypeSetting::input &streamFormat = intfCache.getInputStreamFormat();
2728 if (streamFormat) {
2729 C2Allocator::type_t allocatorType = C2Allocator::LINEAR;
2730 if (streamFormat.value == C2BufferData::GRAPHIC
2731 || streamFormat.value == C2BufferData::GRAPHIC_CHUNKS) {
2732 allocatorType = C2Allocator::GRAPHIC;
2733 }
2734
2735 if (type != allocatorType) {
2736 // requested type is not supported at input allocators
2737 ids->clear();
2738 ids->insert(defaultAllocatorId);
2739 ALOGV("name(%s) does not support a type(0x%x) as input allocator."
2740 " uses default allocator id(%d)", name.c_str(), type, defaultAllocatorId);
2741 break;
2742 }
2743 }
2744
Wonsik Kimffb889a2020-05-28 11:32:25 -07002745 const C2PortAllocatorsTuning::input &allocators = intfCache.getInputAllocators();
Wonsik Kimfcf46c32020-04-22 13:50:45 -07002746 if (firstIteration) {
2747 firstIteration = false;
Wonsik Kimffb889a2020-05-28 11:32:25 -07002748 if (allocators && allocators.flexCount() > 0) {
2749 ids->insert(allocators.m.values,
2750 allocators.m.values + allocators.flexCount());
Wonsik Kimfcf46c32020-04-22 13:50:45 -07002751 }
2752 if (ids->empty()) {
2753 // The component does not advertise allocators. Use default.
2754 ids->insert(defaultAllocatorId);
2755 }
2756 continue;
2757 }
Wonsik Kimfb7a7672019-12-27 17:13:33 -08002758 bool filtered = false;
Wonsik Kimffb889a2020-05-28 11:32:25 -07002759 if (allocators && allocators.flexCount() > 0) {
2760 filtered = true;
2761 for (auto it = ids->begin(); it != ids->end(); ) {
2762 bool found = false;
2763 for (size_t j = 0; j < allocators.flexCount(); ++j) {
2764 if (allocators.m.values[j] == *it) {
2765 found = true;
2766 break;
Wonsik Kimfb7a7672019-12-27 17:13:33 -08002767 }
Wonsik Kimffb889a2020-05-28 11:32:25 -07002768 }
2769 if (found) {
2770 ++it;
2771 } else {
2772 it = ids->erase(it);
Wonsik Kimfb7a7672019-12-27 17:13:33 -08002773 }
2774 }
2775 }
2776 if (!filtered) {
2777 // The component does not advertise supported allocators. Use default.
2778 bool containsDefault = (ids->count(defaultAllocatorId) > 0u);
2779 if (ids->size() != (containsDefault ? 1 : 0)) {
2780 ids->clear();
2781 if (containsDefault) {
2782 ids->insert(defaultAllocatorId);
2783 }
2784 }
2785 }
2786 }
2787 // Finally, filter with pool masks
2788 for (auto it = ids->begin(); it != ids->end(); ) {
2789 if ((poolMask >> *it) & 1) {
2790 ++it;
2791 } else {
2792 it = ids->erase(it);
2793 }
2794 }
2795 return OK;
2796}
2797
2798static status_t CalculateMinMaxUsage(
2799 const std::vector<std::string> &names, uint64_t *minUsage, uint64_t *maxUsage) {
2800 static C2StreamUsageTuning::input sUsage{0u /* stream id */};
2801 *minUsage = 0;
2802 *maxUsage = ~0ull;
2803 for (const std::string &name : names) {
Wonsik Kimffb889a2020-05-28 11:32:25 -07002804 const IntfCache &intfCache = GetIntfCache(name);
2805 if (intfCache.initCheck() != OK) {
Wonsik Kimfcf46c32020-04-22 13:50:45 -07002806 continue;
2807 }
Wonsik Kimffb889a2020-05-28 11:32:25 -07002808 const C2FieldSupportedValuesQuery &usageSupportedValues =
2809 intfCache.getUsageSupportedValues();
2810 if (usageSupportedValues.status != C2_OK) {
Wonsik Kimfb7a7672019-12-27 17:13:33 -08002811 continue;
2812 }
Wonsik Kimffb889a2020-05-28 11:32:25 -07002813 const C2FieldSupportedValues &supported = usageSupportedValues.values;
Wonsik Kimfb7a7672019-12-27 17:13:33 -08002814 if (supported.type != C2FieldSupportedValues::FLAGS) {
2815 continue;
2816 }
2817 if (supported.values.empty()) {
2818 *maxUsage = 0;
2819 continue;
2820 }
Houxiang Daibfb8a722021-04-13 17:34:40 +08002821 if (supported.values.size() > 1) {
2822 *minUsage |= supported.values[1].u64;
2823 } else {
2824 *minUsage |= supported.values[0].u64;
2825 }
Wonsik Kimfb7a7672019-12-27 17:13:33 -08002826 int64_t currentMaxUsage = 0;
2827 for (const C2Value::Primitive &flags : supported.values) {
2828 currentMaxUsage |= flags.u64;
2829 }
2830 *maxUsage &= currentMaxUsage;
2831 }
2832 return OK;
2833}
2834
2835// static
2836status_t CCodec::CanFetchLinearBlock(
2837 const std::vector<std::string> &names, const C2MemoryUsage &usage, bool *isCompatible) {
Wonsik Kimffb889a2020-05-28 11:32:25 -07002838 for (const std::string &name : names) {
2839 const IntfCache &intfCache = GetIntfCache(name);
2840 if (intfCache.initCheck() != OK) {
2841 continue;
2842 }
2843 const C2ApiFeaturesSetting &features = intfCache.getApiFeatures();
2844 if (features && !(features.value & API_SAME_INPUT_BUFFER)) {
2845 *isCompatible = false;
2846 return OK;
2847 }
2848 }
Wonsik Kimfb7a7672019-12-27 17:13:33 -08002849 std::set<C2Allocator::id_t> allocators;
2850 GetCommonAllocatorIds(names, C2Allocator::LINEAR, &allocators);
2851 if (allocators.empty()) {
2852 *isCompatible = false;
2853 return OK;
2854 }
Chih-Yu Huang990b5622020-10-13 14:53:37 +09002855
2856 uint64_t minUsage = 0;
2857 uint64_t maxUsage = ~0ull;
Wonsik Kimfb7a7672019-12-27 17:13:33 -08002858 CalculateMinMaxUsage(names, &minUsage, &maxUsage);
Chih-Yu Huang990b5622020-10-13 14:53:37 +09002859 minUsage |= usage.expected;
Wonsik Kimfb7a7672019-12-27 17:13:33 -08002860 *isCompatible = ((maxUsage & minUsage) == minUsage);
2861 return OK;
2862}
2863
2864static std::shared_ptr<C2BlockPool> GetPool(C2Allocator::id_t allocId) {
2865 static std::mutex sMutex{};
2866 static std::map<C2Allocator::id_t, std::shared_ptr<C2BlockPool>> sPools;
2867 std::unique_lock<std::mutex> lock{sMutex};
2868 std::shared_ptr<C2BlockPool> pool;
2869 auto it = sPools.find(allocId);
2870 if (it == sPools.end()) {
2871 c2_status_t err = CreateCodec2BlockPool(allocId, nullptr, &pool);
2872 if (err == OK) {
2873 sPools.emplace(allocId, pool);
2874 } else {
2875 pool.reset();
2876 }
2877 } else {
2878 pool = it->second;
2879 }
2880 return pool;
2881}
2882
2883// static
2884std::shared_ptr<C2LinearBlock> CCodec::FetchLinearBlock(
2885 size_t capacity, const C2MemoryUsage &usage, const std::vector<std::string> &names) {
Wonsik Kimfb7a7672019-12-27 17:13:33 -08002886 std::set<C2Allocator::id_t> allocators;
2887 GetCommonAllocatorIds(names, C2Allocator::LINEAR, &allocators);
2888 if (allocators.empty()) {
2889 allocators.insert(C2PlatformAllocatorStore::DEFAULT_LINEAR);
2890 }
Chih-Yu Huang990b5622020-10-13 14:53:37 +09002891
2892 uint64_t minUsage = 0;
2893 uint64_t maxUsage = ~0ull;
Wonsik Kimfb7a7672019-12-27 17:13:33 -08002894 CalculateMinMaxUsage(names, &minUsage, &maxUsage);
Chih-Yu Huang990b5622020-10-13 14:53:37 +09002895 minUsage |= usage.expected;
Wonsik Kimfb7a7672019-12-27 17:13:33 -08002896 if ((maxUsage & minUsage) != minUsage) {
2897 allocators.clear();
2898 allocators.insert(C2PlatformAllocatorStore::DEFAULT_LINEAR);
2899 }
2900 std::shared_ptr<C2LinearBlock> block;
2901 for (C2Allocator::id_t allocId : allocators) {
2902 std::shared_ptr<C2BlockPool> pool = GetPool(allocId);
2903 if (!pool) {
2904 continue;
2905 }
2906 c2_status_t err = pool->fetchLinearBlock(capacity, C2MemoryUsage{minUsage}, &block);
2907 if (err != C2_OK || !block) {
2908 block.reset();
2909 continue;
2910 }
2911 break;
2912 }
2913 return block;
2914}
2915
2916// static
2917status_t CCodec::CanFetchGraphicBlock(
2918 const std::vector<std::string> &names, bool *isCompatible) {
2919 uint64_t minUsage = 0;
2920 uint64_t maxUsage = ~0ull;
2921 std::set<C2Allocator::id_t> allocators;
2922 GetCommonAllocatorIds(names, C2Allocator::GRAPHIC, &allocators);
2923 if (allocators.empty()) {
2924 *isCompatible = false;
2925 return OK;
2926 }
2927 CalculateMinMaxUsage(names, &minUsage, &maxUsage);
2928 *isCompatible = ((maxUsage & minUsage) == minUsage);
2929 return OK;
2930}
2931
2932// static
2933std::shared_ptr<C2GraphicBlock> CCodec::FetchGraphicBlock(
2934 int32_t width,
2935 int32_t height,
2936 int32_t format,
2937 uint64_t usage,
2938 const std::vector<std::string> &names) {
2939 uint32_t halPixelFormat = HAL_PIXEL_FORMAT_YCBCR_420_888;
2940 if (!C2Mapper::mapPixelFormatFrameworkToCodec(format, &halPixelFormat)) {
2941 ALOGD("Unrecognized pixel format: %d", format);
2942 return nullptr;
2943 }
2944 uint64_t minUsage = 0;
2945 uint64_t maxUsage = ~0ull;
2946 std::set<C2Allocator::id_t> allocators;
2947 GetCommonAllocatorIds(names, C2Allocator::GRAPHIC, &allocators);
2948 if (allocators.empty()) {
2949 allocators.insert(C2PlatformAllocatorStore::DEFAULT_GRAPHIC);
2950 }
2951 CalculateMinMaxUsage(names, &minUsage, &maxUsage);
2952 minUsage |= usage;
2953 if ((maxUsage & minUsage) != minUsage) {
2954 allocators.clear();
2955 allocators.insert(C2PlatformAllocatorStore::DEFAULT_GRAPHIC);
2956 }
2957 std::shared_ptr<C2GraphicBlock> block;
2958 for (C2Allocator::id_t allocId : allocators) {
2959 std::shared_ptr<C2BlockPool> pool;
2960 c2_status_t err = CreateCodec2BlockPool(allocId, nullptr, &pool);
2961 if (err != C2_OK || !pool) {
2962 continue;
2963 }
2964 err = pool->fetchGraphicBlock(
2965 width, height, halPixelFormat, C2MemoryUsage{minUsage}, &block);
2966 if (err != C2_OK || !block) {
2967 block.reset();
2968 continue;
2969 }
2970 break;
2971 }
2972 return block;
2973}
2974
Wonsik Kim155d5cb2019-10-09 12:49:49 -07002975} // namespace android