blob: 7b1721e7f7f2e616827d5a212f123fdde073141f [file] [log] [blame]
Pawin Vongmasa36653902018-11-15 00:10:25 -08001/*
2 * Copyright 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
Guillaume Chelfi2d4c9db2022-03-18 13:43:49 +010018#include <utils/Errors.h>
Pawin Vongmasa36653902018-11-15 00:10:25 -080019#define LOG_TAG "CCodecBufferChannel"
My Name6bd9a7d2022-03-25 12:37:58 -070020#define ATRACE_TAG ATRACE_TAG_VIDEO
Pawin Vongmasa36653902018-11-15 00:10:25 -080021#include <utils/Log.h>
My Name6bd9a7d2022-03-25 12:37:58 -070022#include <utils/Trace.h>
Pawin Vongmasa36653902018-11-15 00:10:25 -080023
Pawin Vongmasae7bb8612020-06-04 06:15:22 -070024#include <algorithm>
Wonsik Kim6b2c8be2021-09-28 05:11:04 -070025#include <atomic>
Pawin Vongmasae7bb8612020-06-04 06:15:22 -070026#include <list>
Pawin Vongmasa36653902018-11-15 00:10:25 -080027#include <numeric>
Arun Johnson326166e2023-07-28 19:11:52 +000028#include <thread>
29#include <chrono>
Pawin Vongmasa36653902018-11-15 00:10:25 -080030
31#include <C2AllocatorGralloc.h>
32#include <C2PlatformSupport.h>
33#include <C2BlockInternal.h>
34#include <C2Config.h>
35#include <C2Debug.h>
36
37#include <android/hardware/cas/native/1.0/IDescrambler.h>
Robert Shih895fba92019-07-16 16:29:44 -070038#include <android/hardware/drm/1.0/types.h>
Wonsik Kim3a692e62023-05-19 15:37:22 -070039#include <android-base/parseint.h>
Josh Hou8eddf4b2021-02-02 16:26:53 +080040#include <android-base/properties.h>
Pawin Vongmasa36653902018-11-15 00:10:25 -080041#include <android-base/stringprintf.h>
Wonsik Kimfb7a7672019-12-27 17:13:33 -080042#include <binder/MemoryBase.h>
Pawin Vongmasa36653902018-11-15 00:10:25 -080043#include <binder/MemoryDealer.h>
Ray Essick18ea0452019-08-27 16:07:27 -070044#include <cutils/properties.h>
Pawin Vongmasa36653902018-11-15 00:10:25 -080045#include <gui/Surface.h>
Robert Shih895fba92019-07-16 16:29:44 -070046#include <hidlmemory/FrameworkUtils.h>
Pawin Vongmasa36653902018-11-15 00:10:25 -080047#include <media/openmax/OMX_Core.h>
48#include <media/stagefright/foundation/ABuffer.h>
49#include <media/stagefright/foundation/ALookup.h>
50#include <media/stagefright/foundation/AMessage.h>
51#include <media/stagefright/foundation/AUtils.h>
52#include <media/stagefright/foundation/hexdump.h>
Pawin Vongmasa36653902018-11-15 00:10:25 -080053#include <media/stagefright/MediaCodecConstants.h>
Wonsik Kim155d5cb2019-10-09 12:49:49 -070054#include <media/stagefright/SkipCutBuffer.h>
Guillaume Chelfi2d4c9db2022-03-18 13:43:49 +010055#include <media/stagefright/SurfaceUtils.h>
Pawin Vongmasa36653902018-11-15 00:10:25 -080056#include <media/MediaCodecBuffer.h>
Wonsik Kim41d83432020-04-27 16:40:49 -070057#include <mediadrm/ICrypto.h>
Wonsik Kim3a692e62023-05-19 15:37:22 -070058#include <server_configurable_flags/get_flags.h>
Pawin Vongmasa36653902018-11-15 00:10:25 -080059#include <system/window.h>
60
61#include "CCodecBufferChannel.h"
62#include "Codec2Buffer.h"
Pawin Vongmasa36653902018-11-15 00:10:25 -080063
64namespace android {
65
66using android::base::StringPrintf;
67using hardware::hidl_handle;
68using hardware::hidl_string;
69using hardware::hidl_vec;
Robert Shih895fba92019-07-16 16:29:44 -070070using hardware::fromHeap;
71using hardware::HidlMemory;
Brian Lindahld7967a92023-08-10 10:12:49 -060072using server_configurable_flags::GetServerConfigurableFlag;
Robert Shih895fba92019-07-16 16:29:44 -070073
Pawin Vongmasa36653902018-11-15 00:10:25 -080074using namespace hardware::cas::V1_0;
75using namespace hardware::cas::native::V1_0;
76
77using CasStatus = hardware::cas::V1_0::Status;
Robert Shih895fba92019-07-16 16:29:44 -070078using DrmBufferType = hardware::drm::V1_0::BufferType;
Pawin Vongmasa36653902018-11-15 00:10:25 -080079
Pawin Vongmasa36653902018-11-15 00:10:25 -080080namespace {
81
Wonsik Kim469c8342019-04-11 16:46:09 -070082constexpr size_t kSmoothnessFactor = 4;
Pawin Vongmasa36653902018-11-15 00:10:25 -080083
Sungtak Leeab6f2f32019-02-15 14:43:51 -080084// This is for keeping IGBP's buffer dropping logic in legacy mode other
85// than making it non-blocking. Do not change this value.
86const static size_t kDequeueTimeoutNs = 0;
87
Brian Lindahld7967a92023-08-10 10:12:49 -060088static bool areRenderMetricsEnabled() {
89 std::string v = GetServerConfigurableFlag("media_native", "render_metrics_enabled", "false");
90 return v == "true";
91}
92
Arun Johnsonf4a81f72023-11-09 21:22:48 +000093// Flags can come with individual BufferInfos
94// when used with large frame audio
95constexpr static std::initializer_list<std::pair<uint32_t, uint32_t>> flagList = {
96 {BUFFER_FLAG_CODEC_CONFIG, C2FrameData::FLAG_CODEC_CONFIG},
97 {BUFFER_FLAG_END_OF_STREAM, C2FrameData::FLAG_END_OF_STREAM},
98 {BUFFER_FLAG_DECODE_ONLY, C2FrameData::FLAG_DROP_FRAME}
99};
100
101static uint32_t convertFlags(uint32_t flags, bool toC2) {
102 return std::transform_reduce(
103 flagList.begin(), flagList.end(),
104 0u,
105 std::bit_or{},
106 [flags, toC2](const std::pair<uint32_t, uint32_t> &entry) {
107 if (toC2) {
108 return (flags & entry.first) ? entry.second : 0;
109 } else {
110 return (flags & entry.second) ? entry.first : 0;
111 }
112 });
113}
114
Pawin Vongmasa36653902018-11-15 00:10:25 -0800115} // namespace
116
117CCodecBufferChannel::QueueGuard::QueueGuard(
118 CCodecBufferChannel::QueueSync &sync) : mSync(sync) {
119 Mutex::Autolock l(mSync.mGuardLock);
120 // At this point it's guaranteed that mSync is not under state transition,
121 // as we are holding its mutex.
122
123 Mutexed<CCodecBufferChannel::QueueSync::Counter>::Locked count(mSync.mCount);
124 if (count->value == -1) {
125 mRunning = false;
126 } else {
127 ++count->value;
128 mRunning = true;
129 }
130}
131
132CCodecBufferChannel::QueueGuard::~QueueGuard() {
133 if (mRunning) {
134 // We are not holding mGuardLock at this point so that QueueSync::stop() can
135 // keep holding the lock until mCount reaches zero.
136 Mutexed<CCodecBufferChannel::QueueSync::Counter>::Locked count(mSync.mCount);
137 --count->value;
138 count->cond.broadcast();
139 }
140}
141
142void CCodecBufferChannel::QueueSync::start() {
143 Mutex::Autolock l(mGuardLock);
144 // If stopped, it goes to running state; otherwise no-op.
145 Mutexed<Counter>::Locked count(mCount);
146 if (count->value == -1) {
147 count->value = 0;
148 }
149}
150
151void CCodecBufferChannel::QueueSync::stop() {
152 Mutex::Autolock l(mGuardLock);
153 Mutexed<Counter>::Locked count(mCount);
154 if (count->value == -1) {
155 // no-op
156 return;
157 }
158 // Holding mGuardLock here blocks creation of additional QueueGuard objects, so
159 // mCount can only decrement. In other words, threads that acquired the lock
160 // are allowed to finish execution but additional threads trying to acquire
161 // the lock at this point will block, and then get QueueGuard at STOPPED
162 // state.
163 while (count->value != 0) {
164 count.waitForCondition(count->cond);
165 }
166 count->value = -1;
167}
168
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700169// Input
170
171CCodecBufferChannel::Input::Input() : extraBuffers("extra") {}
172
Pawin Vongmasa36653902018-11-15 00:10:25 -0800173// CCodecBufferChannel
174
175CCodecBufferChannel::CCodecBufferChannel(
176 const std::shared_ptr<CCodecCallback> &callback)
177 : mHeapSeqNum(-1),
178 mCCodecCallback(callback),
179 mFrameIndex(0u),
180 mFirstValidFrameIndex(0u),
Brian Lindahld7967a92023-08-10 10:12:49 -0600181 mAreRenderMetricsEnabled(areRenderMetricsEnabled()),
Brian Lindahl2048d492023-04-05 08:49:23 -0600182 mIsSurfaceToDisplay(false),
183 mHasPresentFenceTimes(false),
Wonsik Kimb6ee72a2023-06-07 23:59:01 -0700184 mRenderingDepth(3u),
Pawin Vongmasa36653902018-11-15 00:10:25 -0800185 mMetaMode(MODE_NONE),
Sungtak Lee04b30352020-07-27 13:57:25 -0700186 mInputMetEos(false),
187 mSendEncryptedInfoBuffer(false) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700188 {
189 Mutexed<Input>::Locked input(mInput);
190 input->buffers.reset(new DummyInputBuffers(""));
191 input->extraBuffers.flush();
192 input->inputDelay = 0u;
193 input->pipelineDelay = 0u;
194 input->numSlots = kSmoothnessFactor;
195 input->numExtraSlots = 0u;
Wonsik Kim6b2c8be2021-09-28 05:11:04 -0700196 input->lastFlushIndex = 0u;
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700197 }
198 {
199 Mutexed<Output>::Locked output(mOutput);
200 output->outputDelay = 0u;
201 output->numSlots = kSmoothnessFactor;
Wonsik Kim3722abc2023-05-17 13:26:31 -0700202 output->bounded = false;
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700203 }
David Stevensc3fbb282021-01-18 18:11:20 +0900204 {
205 Mutexed<BlockPools>::Locked pools(mBlockPools);
206 pools->outputPoolId = C2BlockPool::BASIC_LINEAR;
207 }
Brian Lindahld7967a92023-08-10 10:12:49 -0600208 std::string value = GetServerConfigurableFlag("media_native", "ccodec_rendering_depth", "3");
Wonsik Kim3a692e62023-05-19 15:37:22 -0700209 android::base::ParseInt(value, &mRenderingDepth);
Wonsik Kimb6ee72a2023-06-07 23:59:01 -0700210 mOutputSurface.lock()->maxDequeueBuffers = kSmoothnessFactor + mRenderingDepth;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800211}
212
213CCodecBufferChannel::~CCodecBufferChannel() {
Wonsik Kimfb7a7672019-12-27 17:13:33 -0800214 if (mCrypto != nullptr && mHeapSeqNum >= 0) {
Pawin Vongmasa36653902018-11-15 00:10:25 -0800215 mCrypto->unsetHeap(mHeapSeqNum);
216 }
217}
218
219void CCodecBufferChannel::setComponent(
220 const std::shared_ptr<Codec2Client::Component> &component) {
221 mComponent = component;
222 mComponentName = component->getName() + StringPrintf("#%d", int(uintptr_t(component.get()) % 997));
223 mName = mComponentName.c_str();
224}
225
226status_t CCodecBufferChannel::setInputSurface(
227 const std::shared_ptr<InputSurfaceWrapper> &surface) {
228 ALOGV("[%s] setInputSurface", mName);
229 mInputSurface = surface;
230 return mInputSurface->connect(mComponent);
231}
232
233status_t CCodecBufferChannel::signalEndOfInputStream() {
234 if (mInputSurface == nullptr) {
235 return INVALID_OPERATION;
236 }
237 return mInputSurface->signalEndOfInputStream();
238}
239
Sungtak Lee04b30352020-07-27 13:57:25 -0700240status_t CCodecBufferChannel::queueInputBufferInternal(
241 sp<MediaCodecBuffer> buffer,
242 std::shared_ptr<C2LinearBlock> encryptedBlock,
243 size_t blockSize) {
Pawin Vongmasa36653902018-11-15 00:10:25 -0800244 int64_t timeUs;
245 CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
246
247 if (mInputMetEos) {
248 ALOGD("[%s] buffers after EOS ignored (%lld us)", mName, (long long)timeUs);
249 return OK;
250 }
251
252 int32_t flags = 0;
253 int32_t tmp = 0;
254 bool eos = false;
Guillaume Chelfi867d4dd2021-07-01 18:38:45 +0200255 bool tunnelFirstFrame = false;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800256 if (buffer->meta()->findInt32("eos", &tmp) && tmp) {
257 eos = true;
258 mInputMetEos = true;
259 ALOGV("[%s] input EOS", mName);
260 }
261 if (buffer->meta()->findInt32("csd", &tmp) && tmp) {
262 flags |= C2FrameData::FLAG_CODEC_CONFIG;
263 }
Guillaume Chelfi867d4dd2021-07-01 18:38:45 +0200264 if (buffer->meta()->findInt32("tunnel-first-frame", &tmp) && tmp) {
265 tunnelFirstFrame = true;
266 }
Marc Kassis96343b42022-12-09 11:49:44 +0100267 if (buffer->meta()->findInt32("decode-only", &tmp) && tmp) {
268 flags |= C2FrameData::FLAG_DROP_FRAME;
269 }
Arun Johnsonf4a81f72023-11-09 21:22:48 +0000270 ALOGV("[%s] queueInputBuffer: buffer->size() = %zu time: %lld",
271 mName, buffer->size(), (long long)timeUs);
Wonsik Kime1104ca2020-11-24 15:01:33 -0800272 std::list<std::unique_ptr<C2Work>> items;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800273 std::unique_ptr<C2Work> work(new C2Work);
274 work->input.ordinal.timestamp = timeUs;
275 work->input.ordinal.frameIndex = mFrameIndex++;
276 // WORKAROUND: until codecs support handling work after EOS and max output sizing, use timestamp
277 // manipulation to achieve image encoding via video codec, and to constrain encoded output.
278 // Keep client timestamp in customOrdinal
279 work->input.ordinal.customOrdinal = timeUs;
280 work->input.buffers.clear();
281
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700282 sp<Codec2Buffer> copy;
Wonsik Kime1104ca2020-11-24 15:01:33 -0800283 bool usesFrameReassembler = false;
Wonsik Kimab34ed62019-01-31 15:28:46 -0800284
Pawin Vongmasa36653902018-11-15 00:10:25 -0800285 if (buffer->size() > 0u) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700286 Mutexed<Input>::Locked input(mInput);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800287 std::shared_ptr<C2Buffer> c2buffer;
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700288 if (!input->buffers->releaseBuffer(buffer, &c2buffer, false)) {
Pawin Vongmasa36653902018-11-15 00:10:25 -0800289 return -ENOENT;
290 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700291 // TODO: we want to delay copying buffers.
292 if (input->extraBuffers.numComponentBuffers() < input->numExtraSlots) {
293 copy = input->buffers->cloneAndReleaseBuffer(buffer);
294 if (copy != nullptr) {
295 (void)input->extraBuffers.assignSlot(copy);
296 if (!input->extraBuffers.releaseSlot(copy, &c2buffer, false)) {
297 return UNKNOWN_ERROR;
298 }
299 bool released = input->buffers->releaseBuffer(buffer, nullptr, true);
300 ALOGV("[%s] queueInputBuffer: buffer copied; %sreleased",
301 mName, released ? "" : "not ");
Wonsik Kimfb5ca492021-08-11 14:18:19 -0700302 buffer = copy;
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700303 } else {
304 ALOGW("[%s] queueInputBuffer: failed to copy a buffer; this may cause input "
305 "buffer starvation on component.", mName);
306 }
307 }
Wonsik Kime1104ca2020-11-24 15:01:33 -0800308 if (input->frameReassembler) {
309 usesFrameReassembler = true;
310 input->frameReassembler.process(buffer, &items);
311 } else {
Byeongjo Park25c3a3d2020-06-12 17:24:21 +0900312 int32_t cvo = 0;
313 if (buffer->meta()->findInt32("cvo", &cvo)) {
314 int32_t rotation = cvo % 360;
315 // change rotation to counter-clock wise.
316 rotation = ((rotation <= 0) ? 0 : 360) - rotation;
317
318 Mutexed<OutputSurface>::Locked output(mOutputSurface);
319 uint64_t frameIndex = work->input.ordinal.frameIndex.peeku();
320 output->rotation[frameIndex] = rotation;
321 }
Arun Johnsonf4a81f72023-11-09 21:22:48 +0000322 sp<RefBase> obj;
323 if (buffer->meta()->findObject("accessUnitInfo", &obj)) {
324 ALOGV("Filling C2Info from multiple access units");
325 sp<WrapperObject<std::vector<AccessUnitInfo>>> infos{
326 (decltype(infos.get()))obj.get()};
327 std::vector<AccessUnitInfo> &accessUnitInfoVec = infos->value;
328 std::vector<C2AccessUnitInfosStruct> multipleAccessUnitInfos;
329 uint32_t outFlags = 0;
330 for (int i = 0; i < accessUnitInfoVec.size(); i++) {
331 outFlags = 0;
332 outFlags = convertFlags(accessUnitInfoVec[i].mFlags, true);
333 if (eos && (outFlags & C2FrameData::FLAG_END_OF_STREAM)) {
334 outFlags &= (~C2FrameData::FLAG_END_OF_STREAM);
335 }
336 multipleAccessUnitInfos.emplace_back(
337 outFlags,
338 accessUnitInfoVec[i].mSize,
339 accessUnitInfoVec[i].mTimestamp);
340 ALOGV("%d) flags: %d, size: %d, time: %llu",
341 i, outFlags, accessUnitInfoVec[i].mSize,
342 (long long)accessUnitInfoVec[i].mTimestamp);
343
344 }
345 const std::shared_ptr<C2AccessUnitInfos::input> c2AccessUnitInfos =
346 C2AccessUnitInfos::input::AllocShared(
347 multipleAccessUnitInfos.size(), 0u, multipleAccessUnitInfos);
348 c2buffer->setInfo(c2AccessUnitInfos);
349 }
Wonsik Kime1104ca2020-11-24 15:01:33 -0800350 work->input.buffers.push_back(c2buffer);
351 if (encryptedBlock) {
352 work->input.infoBuffers.emplace_back(C2InfoBuffer::CreateLinearBuffer(
353 kParamIndexEncryptedBuffer,
354 encryptedBlock->share(0, blockSize, C2Fence())));
355 }
Sungtak Lee04b30352020-07-27 13:57:25 -0700356 }
Wonsik Kimab34ed62019-01-31 15:28:46 -0800357 } else if (eos) {
Wonsik Kimcc59ad82021-08-11 18:15:19 -0700358 Mutexed<Input>::Locked input(mInput);
359 if (input->frameReassembler) {
360 usesFrameReassembler = true;
361 // drain any pending items with eos
362 input->frameReassembler.process(buffer, &items);
363 }
Wonsik Kimab34ed62019-01-31 15:28:46 -0800364 flags |= C2FrameData::FLAG_END_OF_STREAM;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800365 }
Wonsik Kime1104ca2020-11-24 15:01:33 -0800366 if (usesFrameReassembler) {
367 if (!items.empty()) {
368 items.front()->input.configUpdate = std::move(mParamsToBeSet);
369 mFrameIndex = (items.back()->input.ordinal.frameIndex + 1).peek();
370 }
371 } else {
372 work->input.flags = (C2FrameData::flags_t)flags;
373 // TODO: fill info's
Pawin Vongmasa36653902018-11-15 00:10:25 -0800374
Wonsik Kime1104ca2020-11-24 15:01:33 -0800375 work->input.configUpdate = std::move(mParamsToBeSet);
Guillaume Chelfi867d4dd2021-07-01 18:38:45 +0200376 if (tunnelFirstFrame) {
377 C2StreamTunnelHoldRender::input tunnelHoldRender{
378 0u /* stream */,
379 C2_TRUE /* value */
380 };
381 work->input.configUpdate.push_back(C2Param::Copy(tunnelHoldRender));
382 }
Wonsik Kime1104ca2020-11-24 15:01:33 -0800383 work->worklets.clear();
384 work->worklets.emplace_back(new C2Worklet);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800385
Wonsik Kime1104ca2020-11-24 15:01:33 -0800386 items.push_back(std::move(work));
387
388 eos = eos && buffer->size() > 0u;
Wonsik Kimab34ed62019-01-31 15:28:46 -0800389 }
Wonsik Kime1104ca2020-11-24 15:01:33 -0800390 if (eos) {
Pawin Vongmasa36653902018-11-15 00:10:25 -0800391 work.reset(new C2Work);
392 work->input.ordinal.timestamp = timeUs;
393 work->input.ordinal.frameIndex = mFrameIndex++;
394 // WORKAROUND: keep client timestamp in customOrdinal
395 work->input.ordinal.customOrdinal = timeUs;
396 work->input.buffers.clear();
397 work->input.flags = C2FrameData::FLAG_END_OF_STREAM;
Pawin Vongmasa1c75a232019-01-09 04:41:52 -0800398 work->worklets.emplace_back(new C2Worklet);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800399 items.push_back(std::move(work));
Pawin Vongmasa36653902018-11-15 00:10:25 -0800400 }
Wonsik Kime1104ca2020-11-24 15:01:33 -0800401 c2_status_t err = C2_OK;
402 if (!items.empty()) {
My Name6bd9a7d2022-03-25 12:37:58 -0700403 ScopedTrace trace(ATRACE_TAG, android::base::StringPrintf(
404 "CCodecBufferChannel::queue(%s@ts=%lld)", mName, (long long)timeUs).c_str());
Wonsik Kime1104ca2020-11-24 15:01:33 -0800405 {
406 Mutexed<PipelineWatcher>::Locked watcher(mPipelineWatcher);
407 PipelineWatcher::Clock::time_point now = PipelineWatcher::Clock::now();
408 for (const std::unique_ptr<C2Work> &work : items) {
409 watcher->onWorkQueued(
410 work->input.ordinal.frameIndex.peeku(),
411 std::vector(work->input.buffers),
412 now);
413 }
414 }
415 err = mComponent->queue(&items);
416 }
417 if (err != C2_OK) {
418 Mutexed<PipelineWatcher>::Locked watcher(mPipelineWatcher);
419 for (const std::unique_ptr<C2Work> &work : items) {
420 watcher->onWorkDone(work->input.ordinal.frameIndex.peeku());
421 }
422 } else {
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700423 Mutexed<Input>::Locked input(mInput);
424 bool released = false;
Wonsik Kimfb5ca492021-08-11 14:18:19 -0700425 if (copy) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700426 released = input->extraBuffers.releaseSlot(copy, nullptr, true);
Wonsik Kimfb5ca492021-08-11 14:18:19 -0700427 } else if (buffer) {
428 released = input->buffers->releaseBuffer(buffer, nullptr, true);
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700429 }
430 ALOGV("[%s] queueInputBuffer: buffer%s %sreleased",
431 mName, (buffer == nullptr) ? "(copy)" : "", released ? "" : "not ");
Pawin Vongmasa36653902018-11-15 00:10:25 -0800432 }
433
434 feedInputBufferIfAvailableInternal();
435 return err;
436}
437
438status_t CCodecBufferChannel::setParameters(std::vector<std::unique_ptr<C2Param>> &params) {
439 QueueGuard guard(mSync);
440 if (!guard.isRunning()) {
441 ALOGD("[%s] setParameters is only supported in the running state.", mName);
442 return -ENOSYS;
443 }
444 mParamsToBeSet.insert(mParamsToBeSet.end(),
445 std::make_move_iterator(params.begin()),
446 std::make_move_iterator(params.end()));
447 params.clear();
448 return OK;
449}
450
Wonsik Kimfb7a7672019-12-27 17:13:33 -0800451status_t CCodecBufferChannel::attachBuffer(
452 const std::shared_ptr<C2Buffer> &c2Buffer,
453 const sp<MediaCodecBuffer> &buffer) {
454 if (!buffer->copy(c2Buffer)) {
455 return -ENOSYS;
456 }
457 return OK;
458}
459
460void CCodecBufferChannel::ensureDecryptDestination(size_t size) {
461 if (!mDecryptDestination || mDecryptDestination->size() < size) {
462 sp<IMemoryHeap> heap{new MemoryHeapBase(size * 2)};
463 if (mDecryptDestination && mCrypto && mHeapSeqNum >= 0) {
464 mCrypto->unsetHeap(mHeapSeqNum);
465 }
466 mDecryptDestination = new MemoryBase(heap, 0, size * 2);
467 if (mCrypto) {
468 mHeapSeqNum = mCrypto->setHeap(hardware::fromHeap(heap));
469 }
470 }
471}
472
473int32_t CCodecBufferChannel::getHeapSeqNum(const sp<HidlMemory> &memory) {
474 CHECK(mCrypto);
475 auto it = mHeapSeqNumMap.find(memory);
476 int32_t heapSeqNum = -1;
477 if (it == mHeapSeqNumMap.end()) {
478 heapSeqNum = mCrypto->setHeap(memory);
479 mHeapSeqNumMap.emplace(memory, heapSeqNum);
480 } else {
481 heapSeqNum = it->second;
482 }
483 return heapSeqNum;
484}
485
486status_t CCodecBufferChannel::attachEncryptedBuffer(
487 const sp<hardware::HidlMemory> &memory,
488 bool secure,
489 const uint8_t *key,
490 const uint8_t *iv,
491 CryptoPlugin::Mode mode,
492 CryptoPlugin::Pattern pattern,
493 size_t offset,
494 const CryptoPlugin::SubSample *subSamples,
495 size_t numSubSamples,
Arun Johnson634d0802023-02-14 22:07:51 +0000496 const sp<MediaCodecBuffer> &buffer,
497 AString* errorDetailMsg) {
Wonsik Kimfb7a7672019-12-27 17:13:33 -0800498 static const C2MemoryUsage kSecureUsage{C2MemoryUsage::READ_PROTECTED, 0};
499 static const C2MemoryUsage kDefaultReadWriteUsage{
500 C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE};
501
502 size_t size = 0;
503 for (size_t i = 0; i < numSubSamples; ++i) {
504 size += subSamples[i].mNumBytesOfClearData + subSamples[i].mNumBytesOfEncryptedData;
505 }
Wonsik Kim59e65362022-05-24 14:20:50 -0700506 if (size == 0) {
507 buffer->setRange(0, 0);
508 return OK;
509 }
Wonsik Kimfb7a7672019-12-27 17:13:33 -0800510 std::shared_ptr<C2BlockPool> pool = mBlockPools.lock()->inputPool;
511 std::shared_ptr<C2LinearBlock> block;
512 c2_status_t err = pool->fetchLinearBlock(
513 size,
514 secure ? kSecureUsage : kDefaultReadWriteUsage,
515 &block);
516 if (err != C2_OK) {
Wonsik Kim59e65362022-05-24 14:20:50 -0700517 ALOGI("[%s] attachEncryptedBuffer: fetchLinearBlock failed: size = %zu (%s) err = %d",
518 mName, size, secure ? "secure" : "non-secure", err);
Wonsik Kimfb7a7672019-12-27 17:13:33 -0800519 return NO_MEMORY;
520 }
521 if (!secure) {
522 ensureDecryptDestination(size);
523 }
524 ssize_t result = -1;
525 ssize_t codecDataOffset = 0;
526 if (mCrypto) {
Wonsik Kimfb7a7672019-12-27 17:13:33 -0800527 int32_t heapSeqNum = getHeapSeqNum(memory);
528 hardware::drm::V1_0::SharedBuffer src{(uint32_t)heapSeqNum, offset, size};
529 hardware::drm::V1_0::DestinationBuffer dst;
530 if (secure) {
531 dst.type = DrmBufferType::NATIVE_HANDLE;
532 dst.secureMemory = hardware::hidl_handle(block->handle());
533 } else {
534 dst.type = DrmBufferType::SHARED_MEMORY;
535 IMemoryToSharedBuffer(
536 mDecryptDestination, mHeapSeqNum, &dst.nonsecureMemory);
537 }
538 result = mCrypto->decrypt(
539 key, iv, mode, pattern, src, 0, subSamples, numSubSamples,
Arun Johnson634d0802023-02-14 22:07:51 +0000540 dst, errorDetailMsg);
Wonsik Kimfb7a7672019-12-27 17:13:33 -0800541 if (result < 0) {
Wonsik Kim59e65362022-05-24 14:20:50 -0700542 ALOGI("[%s] attachEncryptedBuffer: decrypt failed: result = %zd", mName, result);
Wonsik Kimfb7a7672019-12-27 17:13:33 -0800543 return result;
544 }
Wonsik Kimfb7a7672019-12-27 17:13:33 -0800545 } else {
546 // Here we cast CryptoPlugin::SubSample to hardware::cas::native::V1_0::SubSample
547 // directly, the structure definitions should match as checked in DescramblerImpl.cpp.
548 hidl_vec<SubSample> hidlSubSamples;
549 hidlSubSamples.setToExternal((SubSample *)subSamples, numSubSamples, false /*own*/);
550
551 hardware::cas::native::V1_0::SharedBuffer src{*memory, offset, size};
552 hardware::cas::native::V1_0::DestinationBuffer dst;
553 if (secure) {
554 dst.type = BufferType::NATIVE_HANDLE;
555 dst.secureMemory = hardware::hidl_handle(block->handle());
556 } else {
557 dst.type = BufferType::SHARED_MEMORY;
558 dst.nonsecureMemory = src;
559 }
560
561 CasStatus status = CasStatus::OK;
562 hidl_string detailedError;
563 ScramblingControl sctrl = ScramblingControl::UNSCRAMBLED;
564
565 if (key != nullptr) {
566 sctrl = (ScramblingControl)key[0];
567 // Adjust for the PES offset
568 codecDataOffset = key[2] | (key[3] << 8);
569 }
570
571 auto returnVoid = mDescrambler->descramble(
572 sctrl,
573 hidlSubSamples,
574 src,
575 0,
576 dst,
577 0,
578 [&status, &result, &detailedError] (
579 CasStatus _status, uint32_t _bytesWritten,
580 const hidl_string& _detailedError) {
581 status = _status;
582 result = (ssize_t)_bytesWritten;
583 detailedError = _detailedError;
584 });
Arun Johnson634d0802023-02-14 22:07:51 +0000585 if (errorDetailMsg) {
586 errorDetailMsg->setTo(detailedError.c_str(), detailedError.size());
587 }
Wonsik Kimfb7a7672019-12-27 17:13:33 -0800588 if (!returnVoid.isOk() || status != CasStatus::OK || result < 0) {
589 ALOGI("[%s] descramble failed, trans=%s, status=%d, result=%zd",
590 mName, returnVoid.description().c_str(), status, result);
591 return UNKNOWN_ERROR;
592 }
593
594 if (result < codecDataOffset) {
Wonsik Kim59e65362022-05-24 14:20:50 -0700595 ALOGD("[%s] invalid codec data offset: %zd, result %zd",
596 mName, codecDataOffset, result);
Wonsik Kimfb7a7672019-12-27 17:13:33 -0800597 return BAD_VALUE;
598 }
599 }
600 if (!secure) {
601 C2WriteView view = block->map().get();
602 if (view.error() != C2_OK) {
Wonsik Kim59e65362022-05-24 14:20:50 -0700603 ALOGI("[%s] attachEncryptedBuffer: block map error: %d (non-secure)",
604 mName, view.error());
Wonsik Kimfb7a7672019-12-27 17:13:33 -0800605 return UNKNOWN_ERROR;
606 }
607 if (view.size() < result) {
Wonsik Kim59e65362022-05-24 14:20:50 -0700608 ALOGI("[%s] attachEncryptedBuffer: block size too small: size=%u result=%zd "
609 "(non-secure)",
610 mName, view.size(), result);
Wonsik Kimfb7a7672019-12-27 17:13:33 -0800611 return UNKNOWN_ERROR;
612 }
613 memcpy(view.data(), mDecryptDestination->unsecurePointer(), result);
614 }
615 std::shared_ptr<C2Buffer> c2Buffer{C2Buffer::CreateLinearBuffer(
616 block->share(codecDataOffset, result - codecDataOffset, C2Fence{}))};
617 if (!buffer->copy(c2Buffer)) {
Wonsik Kim59e65362022-05-24 14:20:50 -0700618 ALOGI("[%s] attachEncryptedBuffer: buffer copy failed", mName);
Wonsik Kimfb7a7672019-12-27 17:13:33 -0800619 return -ENOSYS;
620 }
621 return OK;
622}
623
Pawin Vongmasa36653902018-11-15 00:10:25 -0800624status_t CCodecBufferChannel::queueInputBuffer(const sp<MediaCodecBuffer> &buffer) {
625 QueueGuard guard(mSync);
626 if (!guard.isRunning()) {
627 ALOGD("[%s] No more buffers should be queued at current state.", mName);
628 return -ENOSYS;
629 }
630 return queueInputBufferInternal(buffer);
631}
632
633status_t CCodecBufferChannel::queueSecureInputBuffer(
634 const sp<MediaCodecBuffer> &buffer, bool secure, const uint8_t *key,
635 const uint8_t *iv, CryptoPlugin::Mode mode, CryptoPlugin::Pattern pattern,
636 const CryptoPlugin::SubSample *subSamples, size_t numSubSamples,
637 AString *errorDetailMsg) {
638 QueueGuard guard(mSync);
639 if (!guard.isRunning()) {
640 ALOGD("[%s] No more buffers should be queued at current state.", mName);
641 return -ENOSYS;
642 }
643
644 if (!hasCryptoOrDescrambler()) {
645 return -ENOSYS;
646 }
647 sp<EncryptedLinearBlockBuffer> encryptedBuffer((EncryptedLinearBlockBuffer *)buffer.get());
648
Sungtak Lee04b30352020-07-27 13:57:25 -0700649 std::shared_ptr<C2LinearBlock> block;
650 size_t allocSize = buffer->size();
651 size_t bufferSize = 0;
652 c2_status_t blockRes = C2_OK;
653 bool copied = false;
Arun Johnson7ba67072023-11-06 22:23:04 +0000654 ScopedTrace trace(ATRACE_TAG, android::base::StringPrintf(
655 "CCodecBufferChannel::decrypt(%s)", mName).c_str());
Sungtak Lee04b30352020-07-27 13:57:25 -0700656 if (mSendEncryptedInfoBuffer) {
657 static const C2MemoryUsage kDefaultReadWriteUsage{
658 C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE};
659 constexpr int kAllocGranule0 = 1024 * 64;
660 constexpr int kAllocGranule1 = 1024 * 1024;
661 std::shared_ptr<C2BlockPool> pool = mBlockPools.lock()->inputPool;
662 // round up encrypted sizes to limit fragmentation and encourage buffer reuse
663 if (allocSize <= kAllocGranule1) {
664 bufferSize = align(allocSize, kAllocGranule0);
665 } else {
666 bufferSize = align(allocSize, kAllocGranule1);
667 }
668 blockRes = pool->fetchLinearBlock(
669 bufferSize, kDefaultReadWriteUsage, &block);
670
671 if (blockRes == C2_OK) {
672 C2WriteView view = block->map().get();
673 if (view.error() == C2_OK && view.size() == bufferSize) {
674 copied = true;
675 // TODO: only copy clear sections
676 memcpy(view.data(), buffer->data(), allocSize);
677 }
678 }
679 }
680
681 if (!copied) {
682 block.reset();
683 }
684
Pawin Vongmasa36653902018-11-15 00:10:25 -0800685 ssize_t result = -1;
686 ssize_t codecDataOffset = 0;
Wonsik Kim557c88c2020-03-13 11:03:52 -0700687 if (numSubSamples == 1
688 && subSamples[0].mNumBytesOfClearData == 0
689 && subSamples[0].mNumBytesOfEncryptedData == 0) {
690 // We don't need to go through crypto or descrambler if the input is empty.
691 result = 0;
692 } else if (mCrypto != nullptr) {
Robert Shih895fba92019-07-16 16:29:44 -0700693 hardware::drm::V1_0::DestinationBuffer destination;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800694 if (secure) {
Robert Shih895fba92019-07-16 16:29:44 -0700695 destination.type = DrmBufferType::NATIVE_HANDLE;
696 destination.secureMemory = hidl_handle(encryptedBuffer->handle());
Pawin Vongmasa36653902018-11-15 00:10:25 -0800697 } else {
Robert Shih895fba92019-07-16 16:29:44 -0700698 destination.type = DrmBufferType::SHARED_MEMORY;
699 IMemoryToSharedBuffer(
700 mDecryptDestination, mHeapSeqNum, &destination.nonsecureMemory);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800701 }
Robert Shih895fba92019-07-16 16:29:44 -0700702 hardware::drm::V1_0::SharedBuffer source;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800703 encryptedBuffer->fillSourceBuffer(&source);
704 result = mCrypto->decrypt(
705 key, iv, mode, pattern, source, buffer->offset(),
706 subSamples, numSubSamples, destination, errorDetailMsg);
707 if (result < 0) {
Wonsik Kim557c88c2020-03-13 11:03:52 -0700708 ALOGI("[%s] decrypt failed: result=%zd", mName, result);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800709 return result;
710 }
Robert Shih895fba92019-07-16 16:29:44 -0700711 if (destination.type == DrmBufferType::SHARED_MEMORY) {
Pawin Vongmasa36653902018-11-15 00:10:25 -0800712 encryptedBuffer->copyDecryptedContent(mDecryptDestination, result);
713 }
714 } else {
715 // Here we cast CryptoPlugin::SubSample to hardware::cas::native::V1_0::SubSample
716 // directly, the structure definitions should match as checked in DescramblerImpl.cpp.
717 hidl_vec<SubSample> hidlSubSamples;
718 hidlSubSamples.setToExternal((SubSample *)subSamples, numSubSamples, false /*own*/);
719
720 hardware::cas::native::V1_0::SharedBuffer srcBuffer;
721 encryptedBuffer->fillSourceBuffer(&srcBuffer);
722
723 DestinationBuffer dstBuffer;
724 if (secure) {
725 dstBuffer.type = BufferType::NATIVE_HANDLE;
726 dstBuffer.secureMemory = hidl_handle(encryptedBuffer->handle());
727 } else {
728 dstBuffer.type = BufferType::SHARED_MEMORY;
729 dstBuffer.nonsecureMemory = srcBuffer;
730 }
731
732 CasStatus status = CasStatus::OK;
733 hidl_string detailedError;
734 ScramblingControl sctrl = ScramblingControl::UNSCRAMBLED;
735
736 if (key != nullptr) {
737 sctrl = (ScramblingControl)key[0];
738 // Adjust for the PES offset
739 codecDataOffset = key[2] | (key[3] << 8);
740 }
741
742 auto returnVoid = mDescrambler->descramble(
743 sctrl,
744 hidlSubSamples,
745 srcBuffer,
746 0,
747 dstBuffer,
748 0,
749 [&status, &result, &detailedError] (
750 CasStatus _status, uint32_t _bytesWritten,
751 const hidl_string& _detailedError) {
752 status = _status;
753 result = (ssize_t)_bytesWritten;
754 detailedError = _detailedError;
755 });
756
757 if (!returnVoid.isOk() || status != CasStatus::OK || result < 0) {
758 ALOGI("[%s] descramble failed, trans=%s, status=%d, result=%zd",
759 mName, returnVoid.description().c_str(), status, result);
760 return UNKNOWN_ERROR;
761 }
762
763 if (result < codecDataOffset) {
764 ALOGD("invalid codec data offset: %zd, result %zd", codecDataOffset, result);
765 return BAD_VALUE;
766 }
767
768 ALOGV("[%s] descramble succeeded, %zd bytes", mName, result);
769
770 if (dstBuffer.type == BufferType::SHARED_MEMORY) {
771 encryptedBuffer->copyDecryptedContentFromMemory(result);
772 }
773 }
774
775 buffer->setRange(codecDataOffset, result - codecDataOffset);
Sungtak Lee04b30352020-07-27 13:57:25 -0700776
777 return queueInputBufferInternal(buffer, block, bufferSize);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800778}
779
780void CCodecBufferChannel::feedInputBufferIfAvailable() {
781 QueueGuard guard(mSync);
782 if (!guard.isRunning()) {
783 ALOGV("[%s] We're not running --- no input buffer reported", mName);
784 return;
785 }
786 feedInputBufferIfAvailableInternal();
787}
788
789void CCodecBufferChannel::feedInputBufferIfAvailableInternal() {
Taehwan Kimda0517d2020-09-16 17:29:37 +0900790 if (mInputMetEos) {
Wonsik Kimdf5dd142019-02-06 10:15:46 -0800791 return;
Pawin Vongmasac3c536d2020-06-12 04:00:04 -0700792 }
793 {
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700794 Mutexed<Output>::Locked output(mOutput);
Pawin Vongmasac3c536d2020-06-12 04:00:04 -0700795 if (!output->buffers ||
796 output->buffers->hasPending() ||
Wonsik Kim3722abc2023-05-17 13:26:31 -0700797 (!output->bounded && output->buffers->numActiveSlots() >= output->numSlots)) {
Wonsik Kimdf5dd142019-02-06 10:15:46 -0800798 return;
799 }
800 }
Wonsik Kim0487b782020-10-28 11:45:50 -0700801 size_t numActiveSlots = 0;
802 while (!mPipelineWatcher.lock()->pipelineFull()) {
Pawin Vongmasa36653902018-11-15 00:10:25 -0800803 sp<MediaCodecBuffer> inBuffer;
804 size_t index;
805 {
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700806 Mutexed<Input>::Locked input(mInput);
Wonsik Kim0487b782020-10-28 11:45:50 -0700807 numActiveSlots = input->buffers->numActiveSlots();
808 if (numActiveSlots >= input->numSlots) {
809 break;
Wonsik Kimab34ed62019-01-31 15:28:46 -0800810 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700811 if (!input->buffers->requestNewBuffer(&index, &inBuffer)) {
Pawin Vongmasa36653902018-11-15 00:10:25 -0800812 ALOGV("[%s] no new buffer available", mName);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800813 break;
814 }
815 }
816 ALOGV("[%s] new input index = %zu [%p]", mName, index, inBuffer.get());
817 mCallback->onInputBufferAvailable(index, inBuffer);
818 }
Wonsik Kim0487b782020-10-28 11:45:50 -0700819 ALOGV("[%s] # active slots after feedInputBufferIfAvailable = %zu", mName, numActiveSlots);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800820}
821
822status_t CCodecBufferChannel::renderOutputBuffer(
823 const sp<MediaCodecBuffer> &buffer, int64_t timestampNs) {
Pawin Vongmasa8be93112018-12-11 14:01:42 -0800824 ALOGV("[%s] renderOutputBuffer: %p", mName, buffer.get());
Pawin Vongmasa36653902018-11-15 00:10:25 -0800825 std::shared_ptr<C2Buffer> c2Buffer;
Pawin Vongmasa8be93112018-12-11 14:01:42 -0800826 bool released = false;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800827 {
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700828 Mutexed<Output>::Locked output(mOutput);
829 if (output->buffers) {
830 released = output->buffers->releaseBuffer(buffer, &c2Buffer);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800831 }
832 }
Pawin Vongmasa8be93112018-12-11 14:01:42 -0800833 // NOTE: some apps try to releaseOutputBuffer() with timestamp and/or render
834 // set to true.
835 sendOutputBuffers();
836 // input buffer feeding may have been gated by pending output buffers
837 feedInputBufferIfAvailable();
Pawin Vongmasa36653902018-11-15 00:10:25 -0800838 if (!c2Buffer) {
Pawin Vongmasa8be93112018-12-11 14:01:42 -0800839 if (released) {
Wonsik Kimf7529dd2019-04-18 17:35:53 -0700840 std::call_once(mRenderWarningFlag, [this] {
841 ALOGW("[%s] The app is calling releaseOutputBuffer() with "
842 "timestamp or render=true with non-video buffers. Apps should "
843 "call releaseOutputBuffer() with render=false for those.",
844 mName);
845 });
Pawin Vongmasa8be93112018-12-11 14:01:42 -0800846 }
Pawin Vongmasa36653902018-11-15 00:10:25 -0800847 return INVALID_OPERATION;
848 }
Pawin Vongmasa36653902018-11-15 00:10:25 -0800849
850#if 0
851 const std::vector<std::shared_ptr<const C2Info>> infoParams = c2Buffer->info();
852 ALOGV("[%s] queuing gfx buffer with %zu infos", mName, infoParams.size());
853 for (const std::shared_ptr<const C2Info> &info : infoParams) {
854 AString res;
855 for (size_t ix = 0; ix + 3 < info->size(); ix += 4) {
856 if (ix) res.append(", ");
857 res.append(*((int32_t*)info.get() + (ix / 4)));
858 }
859 ALOGV(" [%s]", res.c_str());
860 }
861#endif
862 std::shared_ptr<const C2StreamRotationInfo::output> rotation =
863 std::static_pointer_cast<const C2StreamRotationInfo::output>(
864 c2Buffer->getInfo(C2StreamRotationInfo::output::PARAM_TYPE));
865 bool flip = rotation && (rotation->flip & 1);
866 uint32_t quarters = ((rotation ? rotation->value : 0) / 90) & 3;
Byeongjo Park25c3a3d2020-06-12 17:24:21 +0900867
868 {
869 Mutexed<OutputSurface>::Locked output(mOutputSurface);
870 if (output->surface == nullptr) {
871 ALOGI("[%s] cannot render buffer without surface", mName);
872 return OK;
873 }
874 int64_t frameIndex;
875 buffer->meta()->findInt64("frameIndex", &frameIndex);
876 if (output->rotation.count(frameIndex) != 0) {
877 auto it = output->rotation.find(frameIndex);
878 quarters = (it->second / 90) & 3;
879 output->rotation.erase(it);
880 }
881 }
882
Pawin Vongmasa36653902018-11-15 00:10:25 -0800883 uint32_t transform = 0;
884 switch (quarters) {
885 case 0: // no rotation
886 transform = flip ? HAL_TRANSFORM_FLIP_H : 0;
887 break;
888 case 1: // 90 degrees counter-clockwise
889 transform = flip ? (HAL_TRANSFORM_FLIP_V | HAL_TRANSFORM_ROT_90)
890 : HAL_TRANSFORM_ROT_270;
891 break;
892 case 2: // 180 degrees
893 transform = flip ? HAL_TRANSFORM_FLIP_V : HAL_TRANSFORM_ROT_180;
894 break;
895 case 3: // 90 degrees clockwise
896 transform = flip ? (HAL_TRANSFORM_FLIP_H | HAL_TRANSFORM_ROT_90)
897 : HAL_TRANSFORM_ROT_90;
898 break;
899 }
900
901 std::shared_ptr<const C2StreamSurfaceScalingInfo::output> surfaceScaling =
902 std::static_pointer_cast<const C2StreamSurfaceScalingInfo::output>(
903 c2Buffer->getInfo(C2StreamSurfaceScalingInfo::output::PARAM_TYPE));
904 uint32_t videoScalingMode = NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW;
905 if (surfaceScaling) {
906 videoScalingMode = surfaceScaling->value;
907 }
908
909 // Use dataspace from format as it has the default aspects already applied
910 android_dataspace_t dataSpace = HAL_DATASPACE_UNKNOWN; // this is 0
911 (void)buffer->format()->findInt32("android._dataspace", (int32_t *)&dataSpace);
912
913 // HDR static info
914 std::shared_ptr<const C2StreamHdrStaticInfo::output> hdrStaticInfo =
915 std::static_pointer_cast<const C2StreamHdrStaticInfo::output>(
916 c2Buffer->getInfo(C2StreamHdrStaticInfo::output::PARAM_TYPE));
917
Pawin Vongmasa8be93112018-12-11 14:01:42 -0800918 // HDR10 plus info
919 std::shared_ptr<const C2StreamHdr10PlusInfo::output> hdr10PlusInfo =
920 std::static_pointer_cast<const C2StreamHdr10PlusInfo::output>(
921 c2Buffer->getInfo(C2StreamHdr10PlusInfo::output::PARAM_TYPE));
Yichi Chen54be23c2020-06-15 14:30:53 +0800922 if (hdr10PlusInfo && hdr10PlusInfo->flexCount() == 0) {
923 hdr10PlusInfo.reset();
924 }
Pawin Vongmasa8be93112018-12-11 14:01:42 -0800925
Wonsik Kima79c5522022-01-18 16:29:24 -0800926 // HDR dynamic info
927 std::shared_ptr<const C2StreamHdrDynamicMetadataInfo::output> hdrDynamicInfo =
928 std::static_pointer_cast<const C2StreamHdrDynamicMetadataInfo::output>(
929 c2Buffer->getInfo(C2StreamHdrDynamicMetadataInfo::output::PARAM_TYPE));
930 // TODO: make this sticky & enable unset
931 if (hdrDynamicInfo && hdrDynamicInfo->flexCount() == 0) {
932 hdrDynamicInfo.reset();
933 }
934
935 if (hdr10PlusInfo) {
936 // C2StreamHdr10PlusInfo is deprecated; components should use
937 // C2StreamHdrDynamicMetadataInfo
938 // TODO: #metric
939 if (hdrDynamicInfo) {
940 // It is unexpected that C2StreamHdr10PlusInfo and
941 // C2StreamHdrDynamicMetadataInfo is both present.
942 // C2StreamHdrDynamicMetadataInfo takes priority.
943 // TODO: #metric
944 } else {
945 std::shared_ptr<C2StreamHdrDynamicMetadataInfo::output> info =
946 C2StreamHdrDynamicMetadataInfo::output::AllocShared(
947 hdr10PlusInfo->flexCount(),
948 0u,
949 C2Config::HDR_DYNAMIC_METADATA_TYPE_SMPTE_2094_40);
950 memcpy(info->m.data, hdr10PlusInfo->m.value, hdr10PlusInfo->flexCount());
951 hdrDynamicInfo = info;
952 }
953 }
954
Pawin Vongmasa36653902018-11-15 00:10:25 -0800955 std::vector<C2ConstGraphicBlock> blocks = c2Buffer->data().graphicBlocks();
956 if (blocks.size() != 1u) {
957 ALOGD("[%s] expected 1 graphic block, but got %zu", mName, blocks.size());
958 return UNKNOWN_ERROR;
959 }
960 const C2ConstGraphicBlock &block = blocks.front();
Lubin Yin92427a52022-04-18 16:57:39 -0700961 C2Fence c2fence = block.fence();
962 sp<Fence> fence = Fence::NO_FENCE;
963 // TODO: it's not sufficient to just check isHW() and then construct android::fence from it.
964 // Once C2Fence::type() is added, check the exact C2Fence type
965 if (c2fence.isHW()) {
966 int fenceFd = c2fence.fd();
967 fence = sp<Fence>::make(fenceFd);
968 if (!fence) {
969 ALOGE("[%s] Failed to allocate a fence", mName);
970 close(fenceFd);
971 return NO_MEMORY;
972 }
973 }
Pawin Vongmasa36653902018-11-15 00:10:25 -0800974
975 // TODO: revisit this after C2Fence implementation.
Brian Lindahl932bf602023-03-09 11:59:48 -0700976 IGraphicBufferProducer::QueueBufferInput qbi(
Pawin Vongmasa36653902018-11-15 00:10:25 -0800977 timestampNs,
978 false, // droppable
979 dataSpace,
980 Rect(blocks.front().crop().left,
981 blocks.front().crop().top,
982 blocks.front().crop().right(),
983 blocks.front().crop().bottom()),
984 videoScalingMode,
985 transform,
Lubin Yin92427a52022-04-18 16:57:39 -0700986 fence, 0);
Wonsik Kima79c5522022-01-18 16:29:24 -0800987 if (hdrStaticInfo || hdrDynamicInfo) {
Pawin Vongmasa36653902018-11-15 00:10:25 -0800988 HdrMetadata hdr;
Pawin Vongmasa8be93112018-12-11 14:01:42 -0800989 if (hdrStaticInfo) {
wenchangliuf3f92882020-05-14 00:02:01 +0800990 // If mastering max and min luminance fields are 0, do not use them.
991 // It indicates the value may not be present in the stream.
992 if (hdrStaticInfo->mastering.maxLuminance > 0.0f &&
993 hdrStaticInfo->mastering.minLuminance > 0.0f) {
994 struct android_smpte2086_metadata smpte2086_meta = {
995 .displayPrimaryRed = {
996 hdrStaticInfo->mastering.red.x, hdrStaticInfo->mastering.red.y
997 },
998 .displayPrimaryGreen = {
999 hdrStaticInfo->mastering.green.x, hdrStaticInfo->mastering.green.y
1000 },
1001 .displayPrimaryBlue = {
1002 hdrStaticInfo->mastering.blue.x, hdrStaticInfo->mastering.blue.y
1003 },
1004 .whitePoint = {
1005 hdrStaticInfo->mastering.white.x, hdrStaticInfo->mastering.white.y
1006 },
1007 .maxLuminance = hdrStaticInfo->mastering.maxLuminance,
1008 .minLuminance = hdrStaticInfo->mastering.minLuminance,
1009 };
Yichi Chen54be23c2020-06-15 14:30:53 +08001010 hdr.validTypes |= HdrMetadata::SMPTE2086;
wenchangliuf3f92882020-05-14 00:02:01 +08001011 hdr.smpte2086 = smpte2086_meta;
1012 }
Chong Zhang3bb2a7f2020-04-21 10:35:12 -07001013 // If the content light level fields are 0, do not use them, it
1014 // indicates the value may not be present in the stream.
1015 if (hdrStaticInfo->maxCll > 0.0f && hdrStaticInfo->maxFall > 0.0f) {
1016 struct android_cta861_3_metadata cta861_meta = {
1017 .maxContentLightLevel = hdrStaticInfo->maxCll,
1018 .maxFrameAverageLightLevel = hdrStaticInfo->maxFall,
1019 };
1020 hdr.validTypes |= HdrMetadata::CTA861_3;
1021 hdr.cta8613 = cta861_meta;
1022 }
Taehwan Kim6b85f1e2022-04-07 17:41:44 +09001023
1024 // does not have valid info
1025 if (!(hdr.validTypes & (HdrMetadata::SMPTE2086 | HdrMetadata::CTA861_3))) {
1026 hdrStaticInfo.reset();
1027 }
Pawin Vongmasa8be93112018-12-11 14:01:42 -08001028 }
Wonsik Kima79c5522022-01-18 16:29:24 -08001029 if (hdrDynamicInfo
1030 && hdrDynamicInfo->m.type_ == C2Config::HDR_DYNAMIC_METADATA_TYPE_SMPTE_2094_40) {
Pawin Vongmasa8be93112018-12-11 14:01:42 -08001031 hdr.validTypes |= HdrMetadata::HDR10PLUS;
1032 hdr.hdr10plus.assign(
Wonsik Kima79c5522022-01-18 16:29:24 -08001033 hdrDynamicInfo->m.data,
1034 hdrDynamicInfo->m.data + hdrDynamicInfo->flexCount());
Pawin Vongmasa8be93112018-12-11 14:01:42 -08001035 }
Pawin Vongmasa36653902018-11-15 00:10:25 -08001036 qbi.setHdrMetadata(hdr);
1037 }
Hongguangfc1478a2022-07-20 22:56:06 -07001038 SetMetadataToGralloc4Handle(dataSpace, hdrStaticInfo, hdrDynamicInfo, block.handle());
1039
Brian Lindahl932bf602023-03-09 11:59:48 -07001040 qbi.setSurfaceDamage(Region::INVALID_REGION); // we don't have dirty regions
1041 qbi.getFrameTimestamps = true; // we need to know when a frame is rendered
1042 IGraphicBufferProducer::QueueBufferOutput qbo;
Pawin Vongmasa36653902018-11-15 00:10:25 -08001043 status_t result = mComponent->queueToOutputSurface(block, qbi, &qbo);
1044 if (result != OK) {
1045 ALOGI("[%s] queueBuffer failed: %d", mName, result);
Sungtak Lee47c018a2020-11-07 01:02:49 -08001046 if (result == NO_INIT) {
1047 mCCodecCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL);
1048 }
Pawin Vongmasa36653902018-11-15 00:10:25 -08001049 return result;
1050 }
Josh Hou8eddf4b2021-02-02 16:26:53 +08001051
1052 if(android::base::GetBoolProperty("debug.stagefright.fps", false)) {
1053 ALOGD("[%s] queue buffer successful", mName);
1054 } else {
1055 ALOGV("[%s] queue buffer successful", mName);
1056 }
Pawin Vongmasa36653902018-11-15 00:10:25 -08001057
1058 int64_t mediaTimeUs = 0;
1059 (void)buffer->meta()->findInt64("timeUs", &mediaTimeUs);
Brian Lindahld7967a92023-08-10 10:12:49 -06001060 if (mAreRenderMetricsEnabled && mIsSurfaceToDisplay) {
Brian Lindahl2048d492023-04-05 08:49:23 -06001061 trackReleasedFrame(qbo, mediaTimeUs, timestampNs);
1062 processRenderedFrames(qbo.frameTimestamps);
1063 } else {
1064 // When the surface is an intermediate surface, onFrameRendered is triggered immediately
1065 // when the frame is queued to the non-display surface
1066 mCCodecCallback->onOutputFramesRendered(mediaTimeUs, timestampNs);
1067 }
Pawin Vongmasa36653902018-11-15 00:10:25 -08001068
1069 return OK;
1070}
1071
Brian Lindahl932bf602023-03-09 11:59:48 -07001072void CCodecBufferChannel::initializeFrameTrackingFor(ANativeWindow * window) {
Brian Lindahl2048d492023-04-05 08:49:23 -06001073 mTrackedFrames.clear();
1074
1075 int isSurfaceToDisplay = 0;
1076 window->query(window, NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER, &isSurfaceToDisplay);
1077 mIsSurfaceToDisplay = isSurfaceToDisplay == 1;
1078 // No frame tracking is needed if we're not sending frames to the display
1079 if (!mIsSurfaceToDisplay) {
1080 // Return early so we don't call into SurfaceFlinger (requiring permissions)
1081 return;
1082 }
1083
Brian Lindahl932bf602023-03-09 11:59:48 -07001084 int hasPresentFenceTimes = 0;
1085 window->query(window, NATIVE_WINDOW_FRAME_TIMESTAMPS_SUPPORTS_PRESENT, &hasPresentFenceTimes);
1086 mHasPresentFenceTimes = hasPresentFenceTimes == 1;
Brian Lindahl119e0c22023-05-19 15:42:13 -06001087 if (!mHasPresentFenceTimes) {
Brian Lindahl932bf602023-03-09 11:59:48 -07001088 ALOGI("Using latch times for frame rendered signals - present fences not supported");
1089 }
Brian Lindahl932bf602023-03-09 11:59:48 -07001090}
1091
1092void CCodecBufferChannel::trackReleasedFrame(const IGraphicBufferProducer::QueueBufferOutput& qbo,
1093 int64_t mediaTimeUs, int64_t desiredRenderTimeNs) {
1094 // If the render time is earlier than now, then we're suggesting it should be rendered ASAP,
1095 // so track the frame as if the desired render time is now.
1096 int64_t nowNs = systemTime(SYSTEM_TIME_MONOTONIC);
1097 if (desiredRenderTimeNs < nowNs) {
1098 desiredRenderTimeNs = nowNs;
1099 }
Brian Lindahlc8bd9272023-08-28 09:42:43 -06001100
1101 // If the render time is more than a second from now, then pretend the frame is supposed to be
1102 // rendered immediately, because that's what SurfaceFlinger heuristics will do. This is a tight
1103 // coupling, but is really the only way to optimize away unnecessary present fence checks in
1104 // processRenderedFrames.
1105 if (desiredRenderTimeNs > nowNs + 1*1000*1000*1000LL) {
1106 desiredRenderTimeNs = nowNs;
1107 }
1108
Brian Lindahl932bf602023-03-09 11:59:48 -07001109 // We've just queued a frame to the surface, so keep track of it and later check to see if it is
1110 // actually rendered.
1111 TrackedFrame frame;
1112 frame.number = qbo.nextFrameNumber - 1;
1113 frame.mediaTimeUs = mediaTimeUs;
1114 frame.desiredRenderTimeNs = desiredRenderTimeNs;
1115 frame.latchTime = -1;
1116 frame.presentFence = nullptr;
1117 mTrackedFrames.push_back(frame);
1118}
1119
1120void CCodecBufferChannel::processRenderedFrames(const FrameEventHistoryDelta& deltas) {
1121 // Grab the latch times and present fences from the frame event deltas
1122 for (const auto& delta : deltas) {
1123 for (auto& frame : mTrackedFrames) {
1124 if (delta.getFrameNumber() == frame.number) {
1125 delta.getLatchTime(&frame.latchTime);
1126 delta.getDisplayPresentFence(&frame.presentFence);
1127 }
1128 }
1129 }
1130
1131 // Scan all frames and check to see if the frames that SHOULD have been rendered by now, have,
1132 // in fact, been rendered.
1133 int64_t nowNs = systemTime(SYSTEM_TIME_MONOTONIC);
1134 while (!mTrackedFrames.empty()) {
1135 TrackedFrame & frame = mTrackedFrames.front();
1136 // Frames that should have been rendered at least 100ms in the past are checked
1137 if (frame.desiredRenderTimeNs > nowNs - 100*1000*1000LL) {
1138 break;
1139 }
1140
1141 // If we don't have a render time by now, then consider the frame as dropped
1142 int64_t renderTimeNs = getRenderTimeNs(frame);
1143 if (renderTimeNs != -1) {
1144 mCCodecCallback->onOutputFramesRendered(frame.mediaTimeUs, renderTimeNs);
1145 }
1146 mTrackedFrames.pop_front();
1147 }
1148}
1149
1150int64_t CCodecBufferChannel::getRenderTimeNs(const TrackedFrame& frame) {
1151 // If the device doesn't have accurate present fence times, then use the latch time as a proxy
1152 if (!mHasPresentFenceTimes) {
1153 if (frame.latchTime == -1) {
1154 ALOGD("no latch time for frame %d", (int) frame.number);
1155 return -1;
1156 }
1157 return frame.latchTime;
1158 }
1159
1160 if (frame.presentFence == nullptr) {
1161 ALOGW("no present fence for frame %d", (int) frame.number);
1162 return -1;
1163 }
1164
1165 nsecs_t actualRenderTimeNs = frame.presentFence->getSignalTime();
1166
1167 if (actualRenderTimeNs == Fence::SIGNAL_TIME_INVALID) {
1168 ALOGW("invalid signal time for frame %d", (int) frame.number);
1169 return -1;
1170 }
1171
1172 if (actualRenderTimeNs == Fence::SIGNAL_TIME_PENDING) {
1173 ALOGD("present fence has not fired for frame %d", (int) frame.number);
1174 return -1;
1175 }
1176
1177 return actualRenderTimeNs;
1178}
1179
1180void CCodecBufferChannel::pollForRenderedBuffers() {
1181 FrameEventHistoryDelta delta;
1182 mComponent->pollForRenderedFrames(&delta);
1183 processRenderedFrames(delta);
1184}
1185
Sungtak Lee214ce612023-11-01 10:01:13 +00001186void CCodecBufferChannel::onBufferReleasedFromOutputSurface(uint32_t generation) {
Sungtak Lee6700cc92023-11-22 18:04:05 +00001187 // Note: Since this is called asynchronously from IProducerListener not
1188 // knowing the internal state of CCodec/CCodecBufferChannel,
1189 // prevent mComponent from being destroyed by holding the shared reference
1190 // during this interface being executed.
1191 std::shared_ptr<Codec2Client::Component> comp = mComponent;
1192 if (comp) {
1193 comp->onBufferReleasedFromOutputSurface(generation);
1194 }
Sungtak Lee214ce612023-11-01 10:01:13 +00001195}
1196
Pawin Vongmasa36653902018-11-15 00:10:25 -08001197status_t CCodecBufferChannel::discardBuffer(const sp<MediaCodecBuffer> &buffer) {
1198 ALOGV("[%s] discardBuffer: %p", mName, buffer.get());
1199 bool released = false;
1200 {
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001201 Mutexed<Input>::Locked input(mInput);
1202 if (input->buffers && input->buffers->releaseBuffer(buffer, nullptr, true)) {
Pawin Vongmasa36653902018-11-15 00:10:25 -08001203 released = true;
Pawin Vongmasa36653902018-11-15 00:10:25 -08001204 }
1205 }
1206 {
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001207 Mutexed<Output>::Locked output(mOutput);
1208 if (output->buffers && output->buffers->releaseBuffer(buffer, nullptr)) {
Pawin Vongmasa36653902018-11-15 00:10:25 -08001209 released = true;
1210 }
1211 }
1212 if (released) {
Pawin Vongmasa36653902018-11-15 00:10:25 -08001213 sendOutputBuffers();
Pawin Vongmasa8be93112018-12-11 14:01:42 -08001214 feedInputBufferIfAvailable();
Pawin Vongmasa36653902018-11-15 00:10:25 -08001215 } else {
1216 ALOGD("[%s] MediaCodec discarded an unknown buffer", mName);
1217 }
1218 return OK;
1219}
1220
1221void CCodecBufferChannel::getInputBufferArray(Vector<sp<MediaCodecBuffer>> *array) {
1222 array->clear();
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001223 Mutexed<Input>::Locked input(mInput);
Pawin Vongmasa36653902018-11-15 00:10:25 -08001224
Arun Johnson3ab32cd2022-06-10 18:58:01 +00001225 if (!input->buffers) {
1226 ALOGE("getInputBufferArray: No Input Buffers allocated");
1227 return;
1228 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001229 if (!input->buffers->isArrayMode()) {
1230 input->buffers = input->buffers->toArrayMode(input->numSlots);
Pawin Vongmasa36653902018-11-15 00:10:25 -08001231 }
1232
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001233 input->buffers->getArray(array);
Pawin Vongmasa36653902018-11-15 00:10:25 -08001234}
1235
1236void CCodecBufferChannel::getOutputBufferArray(Vector<sp<MediaCodecBuffer>> *array) {
1237 array->clear();
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001238 Mutexed<Output>::Locked output(mOutput);
Arun Johnson3ab32cd2022-06-10 18:58:01 +00001239 if (!output->buffers) {
1240 ALOGE("getOutputBufferArray: No Output Buffers allocated");
1241 return;
1242 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001243 if (!output->buffers->isArrayMode()) {
1244 output->buffers = output->buffers->toArrayMode(output->numSlots);
Pawin Vongmasa36653902018-11-15 00:10:25 -08001245 }
1246
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001247 output->buffers->getArray(array);
Pawin Vongmasa36653902018-11-15 00:10:25 -08001248}
1249
1250status_t CCodecBufferChannel::start(
Wonsik Kimfb7a7672019-12-27 17:13:33 -08001251 const sp<AMessage> &inputFormat,
1252 const sp<AMessage> &outputFormat,
1253 bool buffersBoundToCodec) {
Pawin Vongmasa36653902018-11-15 00:10:25 -08001254 C2StreamBufferTypeSetting::input iStreamFormat(0u);
1255 C2StreamBufferTypeSetting::output oStreamFormat(0u);
Wonsik Kime1104ca2020-11-24 15:01:33 -08001256 C2ComponentKindSetting kind;
Pawin Vongmasa36653902018-11-15 00:10:25 -08001257 C2PortReorderBufferDepthTuning::output reorderDepth;
1258 C2PortReorderKeySetting::output reorderKey;
Wonsik Kim078b58e2019-01-09 15:08:06 -08001259 C2PortActualDelayTuning::input inputDelay(0);
1260 C2PortActualDelayTuning::output outputDelay(0);
1261 C2ActualPipelineDelayTuning pipelineDelay(0);
Sungtak Lee04b30352020-07-27 13:57:25 -07001262 C2SecureModeTuning secureMode(C2Config::SM_UNPROTECTED);
Wonsik Kim078b58e2019-01-09 15:08:06 -08001263
Pawin Vongmasa36653902018-11-15 00:10:25 -08001264 c2_status_t err = mComponent->query(
1265 {
1266 &iStreamFormat,
1267 &oStreamFormat,
Wonsik Kime1104ca2020-11-24 15:01:33 -08001268 &kind,
Pawin Vongmasa36653902018-11-15 00:10:25 -08001269 &reorderDepth,
1270 &reorderKey,
Wonsik Kim078b58e2019-01-09 15:08:06 -08001271 &inputDelay,
1272 &pipelineDelay,
1273 &outputDelay,
Sungtak Lee04b30352020-07-27 13:57:25 -07001274 &secureMode,
Pawin Vongmasa36653902018-11-15 00:10:25 -08001275 },
1276 {},
1277 C2_DONT_BLOCK,
1278 nullptr);
1279 if (err == C2_BAD_INDEX) {
Wonsik Kime1104ca2020-11-24 15:01:33 -08001280 if (!iStreamFormat || !oStreamFormat || !kind) {
Pawin Vongmasa36653902018-11-15 00:10:25 -08001281 return UNKNOWN_ERROR;
1282 }
1283 } else if (err != C2_OK) {
1284 return UNKNOWN_ERROR;
1285 }
1286
Wonsik Kim4fa4f2b2019-02-13 11:02:58 -08001287 uint32_t inputDelayValue = inputDelay ? inputDelay.value : 0;
1288 uint32_t pipelineDelayValue = pipelineDelay ? pipelineDelay.value : 0;
1289 uint32_t outputDelayValue = outputDelay ? outputDelay.value : 0;
1290
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001291 size_t numInputSlots = inputDelayValue + pipelineDelayValue + kSmoothnessFactor;
1292 size_t numOutputSlots = outputDelayValue + kSmoothnessFactor;
Wonsik Kim078b58e2019-01-09 15:08:06 -08001293
Pawin Vongmasa36653902018-11-15 00:10:25 -08001294 // TODO: get this from input format
1295 bool secure = mComponent->getName().find(".secure") != std::string::npos;
1296
Sungtak Lee04b30352020-07-27 13:57:25 -07001297 // secure mode is a static parameter (shall not change in the executing state)
1298 mSendEncryptedInfoBuffer = secureMode.value == C2Config::SM_READ_PROTECTED_WITH_ENCRYPTED;
1299
Pawin Vongmasa36653902018-11-15 00:10:25 -08001300 std::shared_ptr<C2AllocatorStore> allocatorStore = GetCodec2PlatformAllocatorStore();
Pin-chih Linaa18ea52019-11-19 18:48:50 +08001301 int poolMask = GetCodec2PoolMask();
1302 C2PlatformAllocatorStore::id_t preferredLinearId = GetPreferredLinearAllocatorId(poolMask);
Pawin Vongmasa36653902018-11-15 00:10:25 -08001303
1304 if (inputFormat != nullptr) {
Lajos Molnar3bb81cd2019-02-20 15:10:30 -08001305 bool graphic = (iStreamFormat.value == C2BufferData::GRAPHIC);
Wonsik Kime1104ca2020-11-24 15:01:33 -08001306 bool audioEncoder = !graphic && (kind.value == C2Component::KIND_ENCODER);
Wonsik Kimffb889a2020-05-28 11:32:25 -07001307 C2Config::api_feature_t apiFeatures = C2Config::api_feature_t(
1308 API_REFLECTION |
1309 API_VALUES |
1310 API_CURRENT_VALUES |
1311 API_DEPENDENCY |
1312 API_SAME_INPUT_BUFFER);
Wonsik Kime1104ca2020-11-24 15:01:33 -08001313 C2StreamAudioFrameSizeInfo::input encoderFrameSize(0u);
1314 C2StreamSampleRateInfo::input sampleRate(0u);
1315 C2StreamChannelCountInfo::input channelCount(0u);
1316 C2StreamPcmEncodingInfo::input pcmEncoding(0u);
Pawin Vongmasa36653902018-11-15 00:10:25 -08001317 std::shared_ptr<C2BlockPool> pool;
1318 {
1319 Mutexed<BlockPools>::Locked pools(mBlockPools);
1320
1321 // set default allocator ID.
1322 pools->inputAllocatorId = (graphic) ? C2PlatformAllocatorStore::GRALLOC
Pin-chih Linaa18ea52019-11-19 18:48:50 +08001323 : preferredLinearId;
Pawin Vongmasa36653902018-11-15 00:10:25 -08001324
1325 // query C2PortAllocatorsTuning::input from component. If an allocator ID is obtained
1326 // from component, create the input block pool with given ID. Otherwise, use default IDs.
1327 std::vector<std::unique_ptr<C2Param>> params;
Wonsik Kimffb889a2020-05-28 11:32:25 -07001328 C2ApiFeaturesSetting featuresSetting{apiFeatures};
Wonsik Kime1104ca2020-11-24 15:01:33 -08001329 std::vector<C2Param *> stackParams({&featuresSetting});
1330 if (audioEncoder) {
1331 stackParams.push_back(&encoderFrameSize);
1332 stackParams.push_back(&sampleRate);
1333 stackParams.push_back(&channelCount);
1334 stackParams.push_back(&pcmEncoding);
1335 } else {
1336 encoderFrameSize.invalidate();
1337 sampleRate.invalidate();
1338 channelCount.invalidate();
1339 pcmEncoding.invalidate();
1340 }
1341 err = mComponent->query(stackParams,
Pawin Vongmasa36653902018-11-15 00:10:25 -08001342 { C2PortAllocatorsTuning::input::PARAM_TYPE },
1343 C2_DONT_BLOCK,
1344 &params);
1345 if ((err != C2_OK && err != C2_BAD_INDEX) || params.size() != 1) {
1346 ALOGD("[%s] Query input allocators returned %zu params => %s (%u)",
1347 mName, params.size(), asString(err), err);
Wonsik Kimffb889a2020-05-28 11:32:25 -07001348 } else if (params.size() == 1) {
Pawin Vongmasa36653902018-11-15 00:10:25 -08001349 C2PortAllocatorsTuning::input *inputAllocators =
1350 C2PortAllocatorsTuning::input::From(params[0].get());
1351 if (inputAllocators && inputAllocators->flexCount() > 0) {
1352 std::shared_ptr<C2Allocator> allocator;
1353 // verify allocator IDs and resolve default allocator
1354 allocatorStore->fetchAllocator(inputAllocators->m.values[0], &allocator);
1355 if (allocator) {
1356 pools->inputAllocatorId = allocator->getId();
1357 } else {
1358 ALOGD("[%s] component requested invalid input allocator ID %u",
1359 mName, inputAllocators->m.values[0]);
1360 }
1361 }
1362 }
Wonsik Kimffb889a2020-05-28 11:32:25 -07001363 if (featuresSetting) {
1364 apiFeatures = featuresSetting.value;
1365 }
Pawin Vongmasa36653902018-11-15 00:10:25 -08001366
1367 // TODO: use C2Component wrapper to associate this pool with ourselves
1368 if ((poolMask >> pools->inputAllocatorId) & 1) {
1369 err = CreateCodec2BlockPool(pools->inputAllocatorId, nullptr, &pool);
1370 ALOGD("[%s] Created input block pool with allocatorID %u => poolID %llu - %s (%d)",
1371 mName, pools->inputAllocatorId,
1372 (unsigned long long)(pool ? pool->getLocalId() : 111000111),
1373 asString(err), err);
1374 } else {
1375 err = C2_NOT_FOUND;
1376 }
1377 if (err != C2_OK) {
1378 C2BlockPool::local_id_t inputPoolId =
1379 graphic ? C2BlockPool::BASIC_GRAPHIC : C2BlockPool::BASIC_LINEAR;
1380 err = GetCodec2BlockPool(inputPoolId, nullptr, &pool);
1381 ALOGD("[%s] Using basic input block pool with poolID %llu => got %llu - %s (%d)",
1382 mName, (unsigned long long)inputPoolId,
1383 (unsigned long long)(pool ? pool->getLocalId() : 111000111),
1384 asString(err), err);
1385 if (err != C2_OK) {
1386 return NO_MEMORY;
1387 }
1388 }
1389 pools->inputPool = pool;
1390 }
1391
Wonsik Kim51051262018-11-28 13:59:05 -08001392 bool forceArrayMode = false;
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001393 Mutexed<Input>::Locked input(mInput);
Wonsik Kimbdffead2019-07-01 12:00:07 -07001394 input->inputDelay = inputDelayValue;
1395 input->pipelineDelay = pipelineDelayValue;
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001396 input->numSlots = numInputSlots;
1397 input->extraBuffers.flush();
1398 input->numExtraSlots = 0u;
Wonsik Kim6b2c8be2021-09-28 05:11:04 -07001399 input->lastFlushIndex = mFrameIndex.load(std::memory_order_relaxed);
Wonsik Kime1104ca2020-11-24 15:01:33 -08001400 if (audioEncoder && encoderFrameSize && sampleRate && channelCount) {
1401 input->frameReassembler.init(
1402 pool,
1403 {C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE},
1404 encoderFrameSize.value,
1405 sampleRate.value,
1406 channelCount.value,
1407 pcmEncoding ? pcmEncoding.value : C2Config::PCM_16);
1408 }
Wonsik Kimffb889a2020-05-28 11:32:25 -07001409 bool conforming = (apiFeatures & API_SAME_INPUT_BUFFER);
1410 // For encrypted content, framework decrypts source buffer (ashmem) into
1411 // C2Buffers. Thus non-conforming codecs can process these.
Wonsik Kime1104ca2020-11-24 15:01:33 -08001412 if (!buffersBoundToCodec
1413 && !input->frameReassembler
1414 && (hasCryptoOrDescrambler() || conforming)) {
Wonsik Kimfb7a7672019-12-27 17:13:33 -08001415 input->buffers.reset(new SlotInputBuffers(mName));
1416 } else if (graphic) {
Pawin Vongmasa36653902018-11-15 00:10:25 -08001417 if (mInputSurface) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001418 input->buffers.reset(new DummyInputBuffers(mName));
Pawin Vongmasa36653902018-11-15 00:10:25 -08001419 } else if (mMetaMode == MODE_ANW) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001420 input->buffers.reset(new GraphicMetadataInputBuffers(mName));
Wonsik Kim1221fd12019-07-12 12:52:05 -07001421 // This is to ensure buffers do not get released prematurely.
1422 // TODO: handle this without going into array mode
1423 forceArrayMode = true;
Pawin Vongmasa36653902018-11-15 00:10:25 -08001424 } else {
Wonsik Kim41d83432020-04-27 16:40:49 -07001425 input->buffers.reset(new GraphicInputBuffers(mName));
Pawin Vongmasa36653902018-11-15 00:10:25 -08001426 }
1427 } else {
1428 if (hasCryptoOrDescrambler()) {
1429 int32_t capacity = kLinearBufferSize;
1430 (void)inputFormat->findInt32(KEY_MAX_INPUT_SIZE, &capacity);
1431 if ((size_t)capacity > kMaxLinearBufferSize) {
1432 ALOGD("client requested %d, capped to %zu", capacity, kMaxLinearBufferSize);
1433 capacity = kMaxLinearBufferSize;
1434 }
1435 if (mDealer == nullptr) {
1436 mDealer = new MemoryDealer(
1437 align(capacity, MemoryDealer::getAllocationAlignment())
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001438 * (numInputSlots + 1),
Pawin Vongmasa36653902018-11-15 00:10:25 -08001439 "EncryptedLinearInputBuffers");
1440 mDecryptDestination = mDealer->allocate((size_t)capacity);
1441 }
1442 if (mCrypto != nullptr && mHeapSeqNum < 0) {
Robert Shih895fba92019-07-16 16:29:44 -07001443 sp<HidlMemory> heap = fromHeap(mDealer->getMemoryHeap());
1444 mHeapSeqNum = mCrypto->setHeap(heap);
Pawin Vongmasa36653902018-11-15 00:10:25 -08001445 } else {
1446 mHeapSeqNum = -1;
1447 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001448 input->buffers.reset(new EncryptedLinearInputBuffers(
Wonsik Kim078b58e2019-01-09 15:08:06 -08001449 secure, mDealer, mCrypto, mHeapSeqNum, (size_t)capacity,
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001450 numInputSlots, mName));
Wonsik Kim51051262018-11-28 13:59:05 -08001451 forceArrayMode = true;
Pawin Vongmasa36653902018-11-15 00:10:25 -08001452 } else {
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001453 input->buffers.reset(new LinearInputBuffers(mName));
Pawin Vongmasa36653902018-11-15 00:10:25 -08001454 }
1455 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001456 input->buffers->setFormat(inputFormat);
Pawin Vongmasa36653902018-11-15 00:10:25 -08001457
1458 if (err == C2_OK) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001459 input->buffers->setPool(pool);
Pawin Vongmasa36653902018-11-15 00:10:25 -08001460 } else {
1461 // TODO: error
1462 }
Wonsik Kim51051262018-11-28 13:59:05 -08001463
1464 if (forceArrayMode) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001465 input->buffers = input->buffers->toArrayMode(numInputSlots);
Wonsik Kim51051262018-11-28 13:59:05 -08001466 }
Pawin Vongmasa36653902018-11-15 00:10:25 -08001467 }
1468
1469 if (outputFormat != nullptr) {
1470 sp<IGraphicBufferProducer> outputSurface;
1471 uint32_t outputGeneration;
Sungtak Leea714f112021-03-16 05:40:03 -07001472 int maxDequeueCount = 0;
Pawin Vongmasa36653902018-11-15 00:10:25 -08001473 {
1474 Mutexed<OutputSurface>::Locked output(mOutputSurface);
Sungtak Leea714f112021-03-16 05:40:03 -07001475 maxDequeueCount = output->maxDequeueBuffers = numOutputSlots +
Wonsik Kim3a692e62023-05-19 15:37:22 -07001476 reorderDepth.value + mRenderingDepth;
Pawin Vongmasa36653902018-11-15 00:10:25 -08001477 outputSurface = output->surface ?
1478 output->surface->getIGraphicBufferProducer() : nullptr;
Wonsik Kimf5e5c832019-02-21 11:36:05 -08001479 if (outputSurface) {
1480 output->surface->setMaxDequeuedBufferCount(output->maxDequeueBuffers);
1481 }
Pawin Vongmasa36653902018-11-15 00:10:25 -08001482 outputGeneration = output->generation;
1483 }
1484
Lajos Molnar3bb81cd2019-02-20 15:10:30 -08001485 bool graphic = (oStreamFormat.value == C2BufferData::GRAPHIC);
Pawin Vongmasa36653902018-11-15 00:10:25 -08001486 C2BlockPool::local_id_t outputPoolId_;
David Stevensc3fbb282021-01-18 18:11:20 +09001487 C2BlockPool::local_id_t prevOutputPoolId;
Pawin Vongmasa36653902018-11-15 00:10:25 -08001488
1489 {
1490 Mutexed<BlockPools>::Locked pools(mBlockPools);
1491
David Stevensc3fbb282021-01-18 18:11:20 +09001492 prevOutputPoolId = pools->outputPoolId;
1493
Pawin Vongmasa36653902018-11-15 00:10:25 -08001494 // set default allocator ID.
1495 pools->outputAllocatorId = (graphic) ? C2PlatformAllocatorStore::GRALLOC
Pin-chih Linaa18ea52019-11-19 18:48:50 +08001496 : preferredLinearId;
Pawin Vongmasa36653902018-11-15 00:10:25 -08001497
1498 // query C2PortAllocatorsTuning::output from component, or use default allocator if
1499 // unsuccessful.
1500 std::vector<std::unique_ptr<C2Param>> params;
1501 err = mComponent->query({ },
1502 { C2PortAllocatorsTuning::output::PARAM_TYPE },
1503 C2_DONT_BLOCK,
1504 &params);
1505 if ((err != C2_OK && err != C2_BAD_INDEX) || params.size() != 1) {
1506 ALOGD("[%s] Query output allocators returned %zu params => %s (%u)",
1507 mName, params.size(), asString(err), err);
1508 } else if (err == C2_OK && params.size() == 1) {
1509 C2PortAllocatorsTuning::output *outputAllocators =
1510 C2PortAllocatorsTuning::output::From(params[0].get());
1511 if (outputAllocators && outputAllocators->flexCount() > 0) {
1512 std::shared_ptr<C2Allocator> allocator;
1513 // verify allocator IDs and resolve default allocator
1514 allocatorStore->fetchAllocator(outputAllocators->m.values[0], &allocator);
1515 if (allocator) {
1516 pools->outputAllocatorId = allocator->getId();
1517 } else {
1518 ALOGD("[%s] component requested invalid output allocator ID %u",
1519 mName, outputAllocators->m.values[0]);
1520 }
1521 }
1522 }
1523
1524 // use bufferqueue if outputting to a surface.
1525 // query C2PortSurfaceAllocatorTuning::output from component, or use default allocator
1526 // if unsuccessful.
1527 if (outputSurface) {
1528 params.clear();
1529 err = mComponent->query({ },
1530 { C2PortSurfaceAllocatorTuning::output::PARAM_TYPE },
1531 C2_DONT_BLOCK,
1532 &params);
1533 if ((err != C2_OK && err != C2_BAD_INDEX) || params.size() != 1) {
1534 ALOGD("[%s] Query output surface allocator returned %zu params => %s (%u)",
1535 mName, params.size(), asString(err), err);
1536 } else if (err == C2_OK && params.size() == 1) {
1537 C2PortSurfaceAllocatorTuning::output *surfaceAllocator =
1538 C2PortSurfaceAllocatorTuning::output::From(params[0].get());
1539 if (surfaceAllocator) {
1540 std::shared_ptr<C2Allocator> allocator;
1541 // verify allocator IDs and resolve default allocator
1542 allocatorStore->fetchAllocator(surfaceAllocator->value, &allocator);
1543 if (allocator) {
1544 pools->outputAllocatorId = allocator->getId();
1545 } else {
1546 ALOGD("[%s] component requested invalid surface output allocator ID %u",
1547 mName, surfaceAllocator->value);
1548 err = C2_BAD_VALUE;
1549 }
1550 }
1551 }
1552 if (pools->outputAllocatorId == C2PlatformAllocatorStore::GRALLOC
1553 && err != C2_OK
1554 && ((poolMask >> C2PlatformAllocatorStore::BUFFERQUEUE) & 1)) {
1555 pools->outputAllocatorId = C2PlatformAllocatorStore::BUFFERQUEUE;
1556 }
1557 }
1558
1559 if ((poolMask >> pools->outputAllocatorId) & 1) {
1560 err = mComponent->createBlockPool(
1561 pools->outputAllocatorId, &pools->outputPoolId, &pools->outputPoolIntf);
1562 ALOGI("[%s] Created output block pool with allocatorID %u => poolID %llu - %s",
1563 mName, pools->outputAllocatorId,
1564 (unsigned long long)pools->outputPoolId,
1565 asString(err));
1566 } else {
1567 err = C2_NOT_FOUND;
1568 }
1569 if (err != C2_OK) {
1570 // use basic pool instead
1571 pools->outputPoolId =
1572 graphic ? C2BlockPool::BASIC_GRAPHIC : C2BlockPool::BASIC_LINEAR;
1573 }
1574
1575 // Configure output block pool ID as parameter C2PortBlockPoolsTuning::output to
1576 // component.
1577 std::unique_ptr<C2PortBlockPoolsTuning::output> poolIdsTuning =
1578 C2PortBlockPoolsTuning::output::AllocUnique({ pools->outputPoolId });
1579
1580 std::vector<std::unique_ptr<C2SettingResult>> failures;
1581 err = mComponent->config({ poolIdsTuning.get() }, C2_MAY_BLOCK, &failures);
1582 ALOGD("[%s] Configured output block pool ids %llu => %s",
1583 mName, (unsigned long long)poolIdsTuning->m.values[0], asString(err));
1584 outputPoolId_ = pools->outputPoolId;
1585 }
1586
David Stevensc3fbb282021-01-18 18:11:20 +09001587 if (prevOutputPoolId != C2BlockPool::BASIC_LINEAR
1588 && prevOutputPoolId != C2BlockPool::BASIC_GRAPHIC) {
1589 c2_status_t err = mComponent->destroyBlockPool(prevOutputPoolId);
1590 if (err != C2_OK) {
1591 ALOGW("Failed to clean up previous block pool %llu - %s (%d)\n",
1592 (unsigned long long) prevOutputPoolId, asString(err), err);
1593 }
1594 }
1595
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001596 Mutexed<Output>::Locked output(mOutput);
Wonsik Kimbdffead2019-07-01 12:00:07 -07001597 output->outputDelay = outputDelayValue;
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001598 output->numSlots = numOutputSlots;
Wonsik Kim3722abc2023-05-17 13:26:31 -07001599 output->bounded = bool(outputSurface);
Pawin Vongmasa36653902018-11-15 00:10:25 -08001600 if (graphic) {
Wonsik Kimfb7a7672019-12-27 17:13:33 -08001601 if (outputSurface || !buffersBoundToCodec) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001602 output->buffers.reset(new GraphicOutputBuffers(mName));
Pawin Vongmasa36653902018-11-15 00:10:25 -08001603 } else {
Wonsik Kim41d83432020-04-27 16:40:49 -07001604 output->buffers.reset(new RawGraphicOutputBuffers(mName));
Pawin Vongmasa36653902018-11-15 00:10:25 -08001605 }
1606 } else {
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001607 output->buffers.reset(new LinearOutputBuffers(mName));
Pawin Vongmasa36653902018-11-15 00:10:25 -08001608 }
Wonsik Kime4716c02020-02-28 10:42:21 -08001609 output->buffers->setFormat(outputFormat);
Pawin Vongmasa36653902018-11-15 00:10:25 -08001610
Pawin Vongmasa9b906982020-04-11 05:07:15 -07001611 output->buffers->clearStash();
1612 if (reorderDepth) {
1613 output->buffers->setReorderDepth(reorderDepth.value);
1614 }
1615 if (reorderKey) {
1616 output->buffers->setReorderKey(reorderKey.value);
1617 }
Pawin Vongmasa36653902018-11-15 00:10:25 -08001618
1619 // Try to set output surface to created block pool if given.
1620 if (outputSurface) {
1621 mComponent->setOutputSurface(
1622 outputPoolId_,
1623 outputSurface,
Sungtak Leedb14cba2021-04-10 00:50:23 -07001624 outputGeneration,
1625 maxDequeueCount);
Lajos Molnar78aa7c92021-02-18 21:39:01 -08001626 } else {
1627 // configure CPU read consumer usage
1628 C2StreamUsageTuning::output outputUsage{0u, C2MemoryUsage::CPU_READ};
1629 std::vector<std::unique_ptr<C2SettingResult>> failures;
1630 err = mComponent->config({ &outputUsage }, C2_MAY_BLOCK, &failures);
1631 // do not print error message for now as most components may not yet
1632 // support this setting
1633 ALOGD_IF(err != C2_BAD_INDEX, "[%s] Configured output usage [%#llx]",
1634 mName, (long long)outputUsage.value);
Pawin Vongmasa36653902018-11-15 00:10:25 -08001635 }
1636
Wonsik Kim8ab25aa2019-06-24 16:37:37 -07001637 if (oStreamFormat.value == C2BufferData::LINEAR) {
Wonsik Kim58713302020-01-29 22:25:23 -08001638 if (buffersBoundToCodec) {
1639 // WORKAROUND: if we're using early CSD workaround we convert to
1640 // array mode, to appease apps assuming the output
1641 // buffers to be of the same size.
1642 output->buffers = output->buffers->toArrayMode(numOutputSlots);
1643 }
Pawin Vongmasa36653902018-11-15 00:10:25 -08001644
1645 int32_t channelCount;
1646 int32_t sampleRate;
1647 if (outputFormat->findInt32(KEY_CHANNEL_COUNT, &channelCount)
1648 && outputFormat->findInt32(KEY_SAMPLE_RATE, &sampleRate)) {
1649 int32_t delay = 0;
1650 int32_t padding = 0;;
1651 if (!outputFormat->findInt32("encoder-delay", &delay)) {
1652 delay = 0;
1653 }
1654 if (!outputFormat->findInt32("encoder-padding", &padding)) {
1655 padding = 0;
1656 }
1657 if (delay || padding) {
Arun Johnson52d323e2024-01-05 21:16:56 +00001658 // We need write access to the buffers, so turn them into array mode.
1659 // TODO: b/321930152 - define SkipCutOutputBuffers that takes output from
1660 // component, runs it through SkipCutBuffer and allocate local buffer to be
1661 // used by fwk. Make initSkipCutBuffer() return OutputBuffers similar to
1662 // toArrayMode().
1663 if (!output->buffers->isArrayMode()) {
1664 output->buffers = output->buffers->toArrayMode(numOutputSlots);
1665 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001666 output->buffers->initSkipCutBuffer(delay, padding, sampleRate, channelCount);
Pawin Vongmasa36653902018-11-15 00:10:25 -08001667 }
1668 }
1669 }
Wonsik Kimec585c32021-10-01 01:11:00 -07001670
1671 int32_t tunneled = 0;
1672 if (!outputFormat->findInt32("android._tunneled", &tunneled)) {
1673 tunneled = 0;
1674 }
1675 mTunneled = (tunneled != 0);
Pawin Vongmasa36653902018-11-15 00:10:25 -08001676 }
1677
1678 // Set up pipeline control. This has to be done after mInputBuffers and
1679 // mOutputBuffers are initialized to make sure that lingering callbacks
1680 // about buffers from the previous generation do not interfere with the
1681 // newly initialized pipeline capacity.
1682
Wonsik Kim62545252021-01-20 11:25:41 -08001683 if (inputFormat || outputFormat) {
Wonsik Kimab34ed62019-01-31 15:28:46 -08001684 Mutexed<PipelineWatcher>::Locked watcher(mPipelineWatcher);
Wonsik Kim4fa4f2b2019-02-13 11:02:58 -08001685 watcher->inputDelay(inputDelayValue)
1686 .pipelineDelay(pipelineDelayValue)
1687 .outputDelay(outputDelayValue)
Houxiang Dai0b573282023-03-11 18:31:56 +08001688 .smoothnessFactor(kSmoothnessFactor)
1689 .tunneled(mTunneled);
Wonsik Kimab34ed62019-01-31 15:28:46 -08001690 watcher->flush();
1691 }
Pawin Vongmasa36653902018-11-15 00:10:25 -08001692
1693 mInputMetEos = false;
1694 mSync.start();
1695 return OK;
1696}
1697
Wonsik Kim34b28b42022-05-20 15:49:32 -07001698status_t CCodecBufferChannel::prepareInitialInputBuffers(
Arun Johnson326166e2023-07-28 19:11:52 +00001699 std::map<size_t, sp<MediaCodecBuffer>> *clientInputBuffers, bool retry) {
Pawin Vongmasa36653902018-11-15 00:10:25 -08001700 if (mInputSurface) {
1701 return OK;
1702 }
1703
Wonsik Kim34b28b42022-05-20 15:49:32 -07001704 size_t numInputSlots = mInput.lock()->numSlots;
Arun Johnson326166e2023-07-28 19:11:52 +00001705 int retryCount = 1;
1706 for (; clientInputBuffers->empty() && retryCount >= 0; retryCount--) {
1707 {
1708 Mutexed<Input>::Locked input(mInput);
1709 while (clientInputBuffers->size() < numInputSlots) {
1710 size_t index;
1711 sp<MediaCodecBuffer> buffer;
1712 if (!input->buffers->requestNewBuffer(&index, &buffer)) {
1713 break;
1714 }
1715 clientInputBuffers->emplace(index, buffer);
Wonsik Kim34b28b42022-05-20 15:49:32 -07001716 }
Arun Johnson326166e2023-07-28 19:11:52 +00001717 }
1718 if (!retry || (retryCount <= 0)) {
1719 break;
1720 }
1721 if (clientInputBuffers->empty()) {
1722 // wait: buffer may be in transit from component.
1723 std::this_thread::sleep_for(std::chrono::milliseconds(4));
Wonsik Kim34b28b42022-05-20 15:49:32 -07001724 }
1725 }
1726 if (clientInputBuffers->empty()) {
1727 ALOGW("[%s] start: cannot allocate memory at all", mName);
1728 return NO_MEMORY;
1729 } else if (clientInputBuffers->size() < numInputSlots) {
1730 ALOGD("[%s] start: cannot allocate memory for all slots, "
1731 "only %zu buffers allocated",
1732 mName, clientInputBuffers->size());
1733 } else {
1734 ALOGV("[%s] %zu initial input buffers available",
1735 mName, clientInputBuffers->size());
1736 }
1737 return OK;
1738}
1739
1740status_t CCodecBufferChannel::requestInitialInputBuffers(
1741 std::map<size_t, sp<MediaCodecBuffer>> &&clientInputBuffers) {
Lajos Molnar3bb81cd2019-02-20 15:10:30 -08001742 C2StreamBufferTypeSetting::output oStreamFormat(0u);
Wonsik Kim8ab25aa2019-06-24 16:37:37 -07001743 C2PrependHeaderModeSetting prepend(PREPEND_HEADER_TO_NONE);
1744 c2_status_t err = mComponent->query({ &oStreamFormat, &prepend }, {}, C2_DONT_BLOCK, nullptr);
1745 if (err != C2_OK && err != C2_BAD_INDEX) {
Pawin Vongmasa36653902018-11-15 00:10:25 -08001746 return UNKNOWN_ERROR;
1747 }
Pawin Vongmasae7bb8612020-06-04 06:15:22 -07001748
Wonsik Kim5ebfcb22021-01-05 18:58:15 -08001749 std::list<std::unique_ptr<C2Work>> flushedConfigs;
1750 mFlushedConfigs.lock()->swap(flushedConfigs);
1751 if (!flushedConfigs.empty()) {
Wonsik Kim92df7e42021-11-04 16:02:03 -07001752 {
1753 Mutexed<PipelineWatcher>::Locked watcher(mPipelineWatcher);
1754 PipelineWatcher::Clock::time_point now = PipelineWatcher::Clock::now();
1755 for (const std::unique_ptr<C2Work> &work : flushedConfigs) {
1756 watcher->onWorkQueued(
1757 work->input.ordinal.frameIndex.peeku(),
1758 std::vector(work->input.buffers),
1759 now);
1760 }
1761 }
Wonsik Kim5ebfcb22021-01-05 18:58:15 -08001762 err = mComponent->queue(&flushedConfigs);
1763 if (err != C2_OK) {
1764 ALOGW("[%s] Error while queueing a flushed config", mName);
1765 return UNKNOWN_ERROR;
Pawin Vongmasa36653902018-11-15 00:10:25 -08001766 }
1767 }
Wonsik Kim5ebfcb22021-01-05 18:58:15 -08001768 if (oStreamFormat.value == C2BufferData::LINEAR &&
Wonsik Kim34b28b42022-05-20 15:49:32 -07001769 (!prepend || prepend.value == PREPEND_HEADER_TO_NONE) &&
1770 !clientInputBuffers.empty()) {
1771 size_t minIndex = clientInputBuffers.begin()->first;
1772 sp<MediaCodecBuffer> minBuffer = clientInputBuffers.begin()->second;
1773 for (const auto &[index, buffer] : clientInputBuffers) {
1774 if (minBuffer->capacity() > buffer->capacity()) {
1775 minIndex = index;
1776 minBuffer = buffer;
1777 }
1778 }
Wonsik Kim5ebfcb22021-01-05 18:58:15 -08001779 // WORKAROUND: Some apps expect CSD available without queueing
1780 // any input. Queue an empty buffer to get the CSD.
Wonsik Kim34b28b42022-05-20 15:49:32 -07001781 minBuffer->setRange(0, 0);
1782 minBuffer->meta()->clear();
1783 minBuffer->meta()->setInt64("timeUs", 0);
1784 if (queueInputBufferInternal(minBuffer) != OK) {
Wonsik Kim5ebfcb22021-01-05 18:58:15 -08001785 ALOGW("[%s] Error while queueing an empty buffer to get CSD",
1786 mName);
1787 return UNKNOWN_ERROR;
1788 }
Wonsik Kim34b28b42022-05-20 15:49:32 -07001789 clientInputBuffers.erase(minIndex);
Wonsik Kim5ebfcb22021-01-05 18:58:15 -08001790 }
Pawin Vongmasae7bb8612020-06-04 06:15:22 -07001791
Wonsik Kim34b28b42022-05-20 15:49:32 -07001792 for (const auto &[index, buffer] : clientInputBuffers) {
1793 mCallback->onInputBufferAvailable(index, buffer);
Pawin Vongmasa36653902018-11-15 00:10:25 -08001794 }
Pawin Vongmasae7bb8612020-06-04 06:15:22 -07001795
Pawin Vongmasa36653902018-11-15 00:10:25 -08001796 return OK;
1797}
1798
1799void CCodecBufferChannel::stop() {
1800 mSync.stop();
1801 mFirstValidFrameIndex = mFrameIndex.load(std::memory_order_relaxed);
Pawin Vongmasa36653902018-11-15 00:10:25 -08001802}
1803
Sungtak Lee99144332023-01-26 11:03:14 +00001804void CCodecBufferChannel::stopUseOutputSurface(bool pushBlankBuffer) {
1805 sp<Surface> surface = mOutputSurface.lock()->surface;
1806 if (surface) {
Sungtak Leed964e2e2022-07-30 08:43:58 +00001807 C2BlockPool::local_id_t outputPoolId;
1808 {
1809 Mutexed<BlockPools>::Locked pools(mBlockPools);
1810 outputPoolId = pools->outputPoolId;
1811 }
1812 if (mComponent) mComponent->stopUsingOutputSurface(outputPoolId);
Sungtak Lee99144332023-01-26 11:03:14 +00001813
1814 if (pushBlankBuffer) {
1815 sp<ANativeWindow> anw = static_cast<ANativeWindow *>(surface.get());
1816 if (anw) {
1817 pushBlankBuffersToNativeWindow(anw.get());
1818 }
1819 }
Sungtak Leed964e2e2022-07-30 08:43:58 +00001820 }
1821}
1822
Wonsik Kim936a89c2020-05-08 16:07:50 -07001823void CCodecBufferChannel::reset() {
1824 stop();
Wonsik Kim62545252021-01-20 11:25:41 -08001825 if (mInputSurface != nullptr) {
1826 mInputSurface.reset();
1827 }
1828 mPipelineWatcher.lock()->flush();
Wonsik Kim936a89c2020-05-08 16:07:50 -07001829 {
1830 Mutexed<Input>::Locked input(mInput);
1831 input->buffers.reset(new DummyInputBuffers(""));
Wonsik Kima2e3cdd2020-05-20 15:14:42 -07001832 input->extraBuffers.flush();
Wonsik Kim936a89c2020-05-08 16:07:50 -07001833 }
1834 {
1835 Mutexed<Output>::Locked output(mOutput);
1836 output->buffers.reset();
1837 }
Brian Lindahl932bf602023-03-09 11:59:48 -07001838 // reset the frames that are being tracked for onFrameRendered callbacks
1839 mTrackedFrames.clear();
Wonsik Kim936a89c2020-05-08 16:07:50 -07001840}
1841
1842void CCodecBufferChannel::release() {
1843 mComponent.reset();
1844 mInputAllocator.reset();
1845 mOutputSurface.lock()->surface.clear();
1846 {
1847 Mutexed<BlockPools>::Locked blockPools{mBlockPools};
1848 blockPools->inputPool.reset();
1849 blockPools->outputPoolIntf.reset();
1850 }
Wonsik Kima2e3cdd2020-05-20 15:14:42 -07001851 setCrypto(nullptr);
1852 setDescrambler(nullptr);
Wonsik Kim936a89c2020-05-08 16:07:50 -07001853}
1854
Pawin Vongmasa36653902018-11-15 00:10:25 -08001855void CCodecBufferChannel::flush(const std::list<std::unique_ptr<C2Work>> &flushedWork) {
1856 ALOGV("[%s] flush", mName);
Wonsik Kim5ebfcb22021-01-05 18:58:15 -08001857 std::list<std::unique_ptr<C2Work>> configs;
Wonsik Kim6b2c8be2021-09-28 05:11:04 -07001858 mInput.lock()->lastFlushIndex = mFrameIndex.load(std::memory_order_relaxed);
Wonsik Kim92df7e42021-11-04 16:02:03 -07001859 {
1860 Mutexed<PipelineWatcher>::Locked watcher(mPipelineWatcher);
1861 for (const std::unique_ptr<C2Work> &work : flushedWork) {
1862 uint64_t frameIndex = work->input.ordinal.frameIndex.peeku();
1863 if (!(work->input.flags & C2FrameData::FLAG_CODEC_CONFIG)) {
1864 watcher->onWorkDone(frameIndex);
1865 continue;
1866 }
1867 if (work->input.buffers.empty()
1868 || work->input.buffers.front() == nullptr
1869 || work->input.buffers.front()->data().linearBlocks().empty()) {
1870 ALOGD("[%s] no linear codec config data found", mName);
1871 watcher->onWorkDone(frameIndex);
1872 continue;
1873 }
1874 std::unique_ptr<C2Work> copy(new C2Work);
1875 copy->input.flags = C2FrameData::flags_t(
1876 work->input.flags | C2FrameData::FLAG_DROP_FRAME);
1877 copy->input.ordinal = work->input.ordinal;
1878 copy->input.ordinal.frameIndex = mFrameIndex++;
1879 for (size_t i = 0; i < work->input.buffers.size(); ++i) {
1880 copy->input.buffers.push_back(watcher->onInputBufferReleased(frameIndex, i));
1881 }
1882 for (const std::unique_ptr<C2Param> &param : work->input.configUpdate) {
1883 copy->input.configUpdate.push_back(C2Param::Copy(*param));
1884 }
1885 copy->input.infoBuffers.insert(
1886 copy->input.infoBuffers.begin(),
1887 work->input.infoBuffers.begin(),
1888 work->input.infoBuffers.end());
1889 copy->worklets.emplace_back(new C2Worklet);
1890 configs.push_back(std::move(copy));
1891 watcher->onWorkDone(frameIndex);
1892 ALOGV("[%s] stashed flushed codec config data", mName);
Pawin Vongmasa36653902018-11-15 00:10:25 -08001893 }
1894 }
Wonsik Kim5ebfcb22021-01-05 18:58:15 -08001895 mFlushedConfigs.lock()->swap(configs);
Pawin Vongmasa36653902018-11-15 00:10:25 -08001896 {
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001897 Mutexed<Input>::Locked input(mInput);
1898 input->buffers->flush();
1899 input->extraBuffers.flush();
Pawin Vongmasa36653902018-11-15 00:10:25 -08001900 }
1901 {
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001902 Mutexed<Output>::Locked output(mOutput);
Wonsik Kim936a89c2020-05-08 16:07:50 -07001903 if (output->buffers) {
1904 output->buffers->flush(flushedWork);
Pawin Vongmasa9b906982020-04-11 05:07:15 -07001905 output->buffers->flushStash();
Wonsik Kim936a89c2020-05-08 16:07:50 -07001906 }
Pawin Vongmasa36653902018-11-15 00:10:25 -08001907 }
1908}
1909
1910void CCodecBufferChannel::onWorkDone(
1911 std::unique_ptr<C2Work> work, const sp<AMessage> &outputFormat,
Wonsik Kimab34ed62019-01-31 15:28:46 -08001912 const C2StreamInitDataInfo::output *initData) {
Pawin Vongmasa36653902018-11-15 00:10:25 -08001913 if (handleWork(std::move(work), outputFormat, initData)) {
Pawin Vongmasa36653902018-11-15 00:10:25 -08001914 feedInputBufferIfAvailable();
1915 }
1916}
1917
1918void CCodecBufferChannel::onInputBufferDone(
Wonsik Kimab34ed62019-01-31 15:28:46 -08001919 uint64_t frameIndex, size_t arrayIndex) {
Pawin Vongmasa8e2cfb52019-05-15 05:20:52 -07001920 if (mInputSurface) {
1921 return;
1922 }
Wonsik Kimab34ed62019-01-31 15:28:46 -08001923 std::shared_ptr<C2Buffer> buffer =
1924 mPipelineWatcher.lock()->onInputBufferReleased(frameIndex, arrayIndex);
Wonsik Kim6b2c8be2021-09-28 05:11:04 -07001925 bool newInputSlotAvailable = false;
Pawin Vongmasa36653902018-11-15 00:10:25 -08001926 {
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001927 Mutexed<Input>::Locked input(mInput);
Wonsik Kim6b2c8be2021-09-28 05:11:04 -07001928 if (input->lastFlushIndex >= frameIndex) {
1929 ALOGD("[%s] Ignoring stale input buffer done callback: "
1930 "last flush index = %lld, frameIndex = %lld",
1931 mName, input->lastFlushIndex.peekll(), (long long)frameIndex);
1932 } else {
1933 newInputSlotAvailable = input->buffers->expireComponentBuffer(buffer);
1934 if (!newInputSlotAvailable) {
1935 (void)input->extraBuffers.expireComponentBuffer(buffer);
1936 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001937 }
Pawin Vongmasa36653902018-11-15 00:10:25 -08001938 }
1939 if (newInputSlotAvailable) {
1940 feedInputBufferIfAvailable();
1941 }
1942}
1943
1944bool CCodecBufferChannel::handleWork(
1945 std::unique_ptr<C2Work> work,
1946 const sp<AMessage> &outputFormat,
1947 const C2StreamInitDataInfo::output *initData) {
Wonsik Kim936a89c2020-05-08 16:07:50 -07001948 {
Wonsik Kima4e049d2020-04-28 19:42:23 +00001949 Mutexed<Output>::Locked output(mOutput);
Wonsik Kim936a89c2020-05-08 16:07:50 -07001950 if (!output->buffers) {
1951 return false;
1952 }
Wonsik Kime75a5da2020-02-14 17:29:03 -08001953 }
1954
Pawin Vongmasa9b906982020-04-11 05:07:15 -07001955 // Whether the output buffer should be reported to the client or not.
1956 bool notifyClient = false;
1957
1958 if (work->result == C2_OK){
1959 notifyClient = true;
1960 } else if (work->result == C2_NOT_FOUND) {
1961 ALOGD("[%s] flushed work; ignored.", mName);
1962 } else {
1963 // C2_OK and C2_NOT_FOUND are the only results that we accept for processing
1964 // the config update.
1965 ALOGD("[%s] work failed to complete: %d", mName, work->result);
1966 mCCodecCallback->onError(work->result, ACTION_CODE_FATAL);
1967 return false;
1968 }
1969
1970 if ((work->input.ordinal.frameIndex -
1971 mFirstValidFrameIndex.load()).peek() < 0) {
Pawin Vongmasa36653902018-11-15 00:10:25 -08001972 // Discard frames from previous generation.
1973 ALOGD("[%s] Discard frames from previous generation.", mName);
Pawin Vongmasa9b906982020-04-11 05:07:15 -07001974 notifyClient = false;
Pawin Vongmasa36653902018-11-15 00:10:25 -08001975 }
1976
Wonsik Kim524b0582019-03-12 11:28:57 -07001977 if (mInputSurface == nullptr && (work->worklets.size() != 1u
Pawin Vongmasa36653902018-11-15 00:10:25 -08001978 || !work->worklets.front()
Pawin Vongmasa9b906982020-04-11 05:07:15 -07001979 || !(work->worklets.front()->output.flags &
1980 C2FrameData::FLAG_INCOMPLETE))) {
1981 mPipelineWatcher.lock()->onWorkDone(
1982 work->input.ordinal.frameIndex.peeku());
Pawin Vongmasa36653902018-11-15 00:10:25 -08001983 }
1984
1985 // NOTE: MediaCodec usage supposedly have only one worklet
1986 if (work->worklets.size() != 1u) {
1987 ALOGI("[%s] onWorkDone: incorrect number of worklets: %zu",
1988 mName, work->worklets.size());
1989 mCCodecCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL);
1990 return false;
1991 }
1992
1993 const std::unique_ptr<C2Worklet> &worklet = work->worklets.front();
1994
1995 std::shared_ptr<C2Buffer> buffer;
1996 // NOTE: MediaCodec usage supposedly have only one output stream.
1997 if (worklet->output.buffers.size() > 1u) {
1998 ALOGI("[%s] onWorkDone: incorrect number of output buffers: %zu",
1999 mName, worklet->output.buffers.size());
2000 mCCodecCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL);
2001 return false;
2002 } else if (worklet->output.buffers.size() == 1u) {
2003 buffer = worklet->output.buffers[0];
2004 if (!buffer) {
2005 ALOGD("[%s] onWorkDone: nullptr found in buffers; ignored.", mName);
2006 }
2007 }
2008
Wonsik Kim3dedf682021-05-03 10:57:09 -07002009 std::optional<uint32_t> newInputDelay, newPipelineDelay, newOutputDelay, newReorderDepth;
2010 std::optional<C2Config::ordinal_key_t> newReorderKey;
Wonsik Kim315e40a2020-09-09 14:11:50 -07002011 bool needMaxDequeueBufferCountUpdate = false;
Pawin Vongmasa36653902018-11-15 00:10:25 -08002012 while (!worklet->output.configUpdate.empty()) {
2013 std::unique_ptr<C2Param> param;
2014 worklet->output.configUpdate.back().swap(param);
2015 worklet->output.configUpdate.pop_back();
2016 switch (param->coreIndex().coreIndex()) {
2017 case C2PortReorderBufferDepthTuning::CORE_INDEX: {
2018 C2PortReorderBufferDepthTuning::output reorderDepth;
2019 if (reorderDepth.updateFrom(*param)) {
Pawin Vongmasa36653902018-11-15 00:10:25 -08002020 ALOGV("[%s] onWorkDone: updated reorder depth to %u",
2021 mName, reorderDepth.value);
Wonsik Kim3dedf682021-05-03 10:57:09 -07002022 newReorderDepth = reorderDepth.value;
Wonsik Kim315e40a2020-09-09 14:11:50 -07002023 needMaxDequeueBufferCountUpdate = true;
Pawin Vongmasa36653902018-11-15 00:10:25 -08002024 } else {
Pawin Vongmasa9b906982020-04-11 05:07:15 -07002025 ALOGD("[%s] onWorkDone: failed to read reorder depth",
2026 mName);
Pawin Vongmasa36653902018-11-15 00:10:25 -08002027 }
2028 break;
2029 }
2030 case C2PortReorderKeySetting::CORE_INDEX: {
2031 C2PortReorderKeySetting::output reorderKey;
2032 if (reorderKey.updateFrom(*param)) {
Wonsik Kim3dedf682021-05-03 10:57:09 -07002033 newReorderKey = reorderKey.value;
Pawin Vongmasa36653902018-11-15 00:10:25 -08002034 ALOGV("[%s] onWorkDone: updated reorder key to %u",
2035 mName, reorderKey.value);
2036 } else {
2037 ALOGD("[%s] onWorkDone: failed to read reorder key", mName);
2038 }
2039 break;
2040 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -07002041 case C2PortActualDelayTuning::CORE_INDEX: {
2042 if (param->isGlobal()) {
2043 C2ActualPipelineDelayTuning pipelineDelay;
2044 if (pipelineDelay.updateFrom(*param)) {
2045 ALOGV("[%s] onWorkDone: updating pipeline delay %u",
2046 mName, pipelineDelay.value);
2047 newPipelineDelay = pipelineDelay.value;
Pawin Vongmasa9b906982020-04-11 05:07:15 -07002048 (void)mPipelineWatcher.lock()->pipelineDelay(
2049 pipelineDelay.value);
Wonsik Kim5ecf3832019-04-18 10:28:58 -07002050 }
2051 }
2052 if (param->forInput()) {
2053 C2PortActualDelayTuning::input inputDelay;
2054 if (inputDelay.updateFrom(*param)) {
2055 ALOGV("[%s] onWorkDone: updating input delay %u",
2056 mName, inputDelay.value);
2057 newInputDelay = inputDelay.value;
Pawin Vongmasa9b906982020-04-11 05:07:15 -07002058 (void)mPipelineWatcher.lock()->inputDelay(
2059 inputDelay.value);
Wonsik Kim5ecf3832019-04-18 10:28:58 -07002060 }
2061 }
2062 if (param->forOutput()) {
2063 C2PortActualDelayTuning::output outputDelay;
2064 if (outputDelay.updateFrom(*param)) {
2065 ALOGV("[%s] onWorkDone: updating output delay %u",
2066 mName, outputDelay.value);
Wonsik Kim315e40a2020-09-09 14:11:50 -07002067 (void)mPipelineWatcher.lock()->outputDelay(outputDelay.value);
Wonsik Kim3dedf682021-05-03 10:57:09 -07002068 newOutputDelay = outputDelay.value;
Wonsik Kim315e40a2020-09-09 14:11:50 -07002069 needMaxDequeueBufferCountUpdate = true;
Wonsik Kim5ecf3832019-04-18 10:28:58 -07002070
Wonsik Kim5ecf3832019-04-18 10:28:58 -07002071 }
2072 }
2073 break;
2074 }
ted.sunb1fbfdb2020-06-23 14:03:41 +08002075 case C2PortTunnelSystemTime::CORE_INDEX: {
2076 C2PortTunnelSystemTime::output frameRenderTime;
2077 if (frameRenderTime.updateFrom(*param)) {
2078 ALOGV("[%s] onWorkDone: frame rendered (sys:%lld ns, media:%lld us)",
2079 mName, (long long)frameRenderTime.value,
2080 (long long)worklet->output.ordinal.timestamp.peekll());
2081 mCCodecCallback->onOutputFramesRendered(
2082 worklet->output.ordinal.timestamp.peek(), frameRenderTime.value);
2083 }
2084 break;
2085 }
Guillaume Chelfi867d4dd2021-07-01 18:38:45 +02002086 case C2StreamTunnelHoldRender::CORE_INDEX: {
2087 C2StreamTunnelHoldRender::output firstTunnelFrameHoldRender;
2088 if (!(worklet->output.flags & C2FrameData::FLAG_INCOMPLETE)) break;
2089 if (!firstTunnelFrameHoldRender.updateFrom(*param)) break;
2090 if (firstTunnelFrameHoldRender.value != C2_TRUE) break;
2091 ALOGV("[%s] onWorkDone: first tunnel frame ready", mName);
2092 mCCodecCallback->onFirstTunnelFrameReady();
2093 break;
2094 }
Pawin Vongmasa36653902018-11-15 00:10:25 -08002095 default:
2096 ALOGV("[%s] onWorkDone: unrecognized config update (%08X)",
2097 mName, param->index());
2098 break;
2099 }
2100 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -07002101 if (newInputDelay || newPipelineDelay) {
2102 Mutexed<Input>::Locked input(mInput);
2103 size_t newNumSlots =
2104 newInputDelay.value_or(input->inputDelay) +
2105 newPipelineDelay.value_or(input->pipelineDelay) +
2106 kSmoothnessFactor;
Xu Lai5732cab2023-03-16 19:50:18 +08002107 input->inputDelay = newInputDelay.value_or(input->inputDelay);
Wonsik Kim5ecf3832019-04-18 10:28:58 -07002108 if (input->buffers->isArrayMode()) {
2109 if (input->numSlots >= newNumSlots) {
2110 input->numExtraSlots = 0;
2111 } else {
2112 input->numExtraSlots = newNumSlots - input->numSlots;
2113 }
2114 ALOGV("[%s] onWorkDone: updated number of extra slots to %zu (input array mode)",
2115 mName, input->numExtraSlots);
2116 } else {
2117 input->numSlots = newNumSlots;
2118 }
2119 }
Wonsik Kim3dedf682021-05-03 10:57:09 -07002120 size_t numOutputSlots = 0;
2121 uint32_t reorderDepth = 0;
2122 bool outputBuffersChanged = false;
2123 if (newReorderKey || newReorderDepth || needMaxDequeueBufferCountUpdate) {
2124 Mutexed<Output>::Locked output(mOutput);
2125 if (!output->buffers) {
2126 return false;
Wonsik Kim315e40a2020-09-09 14:11:50 -07002127 }
Wonsik Kim3dedf682021-05-03 10:57:09 -07002128 numOutputSlots = output->numSlots;
2129 if (newReorderKey) {
2130 output->buffers->setReorderKey(newReorderKey.value());
2131 }
2132 if (newReorderDepth) {
2133 output->buffers->setReorderDepth(newReorderDepth.value());
2134 }
2135 reorderDepth = output->buffers->getReorderDepth();
2136 if (newOutputDelay) {
2137 output->outputDelay = newOutputDelay.value();
2138 numOutputSlots = newOutputDelay.value() + kSmoothnessFactor;
2139 if (output->numSlots < numOutputSlots) {
2140 output->numSlots = numOutputSlots;
2141 if (output->buffers->isArrayMode()) {
2142 OutputBuffersArray *array =
2143 (OutputBuffersArray *)output->buffers.get();
2144 ALOGV("[%s] onWorkDone: growing output buffer array to %zu",
2145 mName, numOutputSlots);
2146 array->grow(numOutputSlots);
2147 outputBuffersChanged = true;
2148 }
2149 }
2150 }
2151 numOutputSlots = output->numSlots;
2152 }
2153 if (outputBuffersChanged) {
2154 mCCodecCallback->onOutputBuffersChanged();
2155 }
2156 if (needMaxDequeueBufferCountUpdate) {
Wonsik Kim84f439f2021-05-03 10:57:09 -07002157 int maxDequeueCount = 0;
Sungtak Leea714f112021-03-16 05:40:03 -07002158 {
2159 Mutexed<OutputSurface>::Locked output(mOutputSurface);
2160 maxDequeueCount = output->maxDequeueBuffers =
Wonsik Kim3a692e62023-05-19 15:37:22 -07002161 numOutputSlots + reorderDepth + mRenderingDepth;
Sungtak Leea714f112021-03-16 05:40:03 -07002162 if (output->surface) {
2163 output->surface->setMaxDequeuedBufferCount(output->maxDequeueBuffers);
2164 }
2165 }
2166 if (maxDequeueCount > 0) {
2167 mComponent->setOutputSurfaceMaxDequeueCount(maxDequeueCount);
Wonsik Kim315e40a2020-09-09 14:11:50 -07002168 }
2169 }
Pawin Vongmasa36653902018-11-15 00:10:25 -08002170
Pawin Vongmasa36653902018-11-15 00:10:25 -08002171 int32_t flags = 0;
2172 if (worklet->output.flags & C2FrameData::FLAG_END_OF_STREAM) {
My Named4d22242022-03-28 13:53:32 -07002173 flags |= BUFFER_FLAG_END_OF_STREAM;
Pawin Vongmasa36653902018-11-15 00:10:25 -08002174 ALOGV("[%s] onWorkDone: output EOS", mName);
2175 }
2176
Pawin Vongmasa36653902018-11-15 00:10:25 -08002177 // WORKAROUND: adjust output timestamp based on client input timestamp and codec
2178 // input timestamp. Codec output timestamp (in the timestamp field) shall correspond to
2179 // the codec input timestamp, but client output timestamp should (reported in timeUs)
2180 // shall correspond to the client input timesamp (in customOrdinal). By using the
2181 // delta between the two, this allows for some timestamp deviation - e.g. if one input
2182 // produces multiple output.
2183 c2_cntr64_t timestamp =
2184 worklet->output.ordinal.timestamp + work->input.ordinal.customOrdinal
2185 - work->input.ordinal.timestamp;
Wonsik Kim95ba0162019-03-19 15:51:54 -07002186 if (mInputSurface != nullptr) {
2187 // When using input surface we need to restore the original input timestamp.
2188 timestamp = work->input.ordinal.customOrdinal;
2189 }
My Name6bd9a7d2022-03-25 12:37:58 -07002190 ScopedTrace trace(ATRACE_TAG, android::base::StringPrintf(
2191 "CCodecBufferChannel::onWorkDone(%s@ts=%lld)", mName, timestamp.peekll()).c_str());
Pawin Vongmasa36653902018-11-15 00:10:25 -08002192 ALOGV("[%s] onWorkDone: input %lld, codec %lld => output %lld => %lld",
2193 mName,
2194 work->input.ordinal.customOrdinal.peekll(),
2195 work->input.ordinal.timestamp.peekll(),
2196 worklet->output.ordinal.timestamp.peekll(),
2197 timestamp.peekll());
2198
Pawin Vongmasa9b906982020-04-11 05:07:15 -07002199 // csd cannot be re-ordered and will always arrive first.
Pawin Vongmasa36653902018-11-15 00:10:25 -08002200 if (initData != nullptr) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -07002201 Mutexed<Output>::Locked output(mOutput);
Wonsik Kim72a71012023-02-06 17:35:21 -08002202 if (!output->buffers) {
2203 return false;
2204 }
2205 if (outputFormat) {
Pawin Vongmasa9b906982020-04-11 05:07:15 -07002206 output->buffers->updateSkipCutBuffer(outputFormat);
2207 output->buffers->setFormat(outputFormat);
2208 }
2209 if (!notifyClient) {
2210 return false;
2211 }
2212 size_t index;
2213 sp<MediaCodecBuffer> outBuffer;
Wonsik Kim72a71012023-02-06 17:35:21 -08002214 if (output->buffers->registerCsd(initData, &index, &outBuffer) == OK) {
Pawin Vongmasa36653902018-11-15 00:10:25 -08002215 outBuffer->meta()->setInt64("timeUs", timestamp.peek());
My Named4d22242022-03-28 13:53:32 -07002216 outBuffer->meta()->setInt32("flags", BUFFER_FLAG_CODEC_CONFIG);
Pawin Vongmasa36653902018-11-15 00:10:25 -08002217 ALOGV("[%s] onWorkDone: csd index = %zu [%p]", mName, index, outBuffer.get());
2218
Wonsik Kim5c2c8902023-05-09 10:53:15 -07002219 // TRICKY: we want popped buffers reported in order, so sending
2220 // the callback while holding the lock here. This assumes that
2221 // onOutputBufferAvailable() does not block. onOutputBufferAvailable()
2222 // callbacks are always sent with the Output lock held.
Pawin Vongmasa36653902018-11-15 00:10:25 -08002223 mCallback->onOutputBufferAvailable(index, outBuffer);
Pawin Vongmasa36653902018-11-15 00:10:25 -08002224 } else {
2225 ALOGD("[%s] onWorkDone: unable to register csd", mName);
Wonsik Kim5ecf3832019-04-18 10:28:58 -07002226 output.unlock();
Pawin Vongmasa36653902018-11-15 00:10:25 -08002227 mCCodecCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL);
Pawin Vongmasa36653902018-11-15 00:10:25 -08002228 return false;
2229 }
2230 }
2231
Wonsik Kimec585c32021-10-01 01:11:00 -07002232 bool drop = false;
2233 if (worklet->output.flags & C2FrameData::FLAG_DROP_FRAME) {
2234 ALOGV("[%s] onWorkDone: drop buffer but keep metadata", mName);
2235 drop = true;
2236 }
2237
Marc Kassisec910342022-11-25 11:43:05 +01002238 // Workaround: if C2FrameData::FLAG_DROP_FRAME is not implemented in
2239 // HAL, the flag is then removed in the corresponding output buffer.
2240 if (work->input.flags & C2FrameData::FLAG_DROP_FRAME) {
2241 flags |= BUFFER_FLAG_DECODE_ONLY;
2242 }
2243
Pawin Vongmasa9b906982020-04-11 05:07:15 -07002244 if (notifyClient && !buffer && !flags) {
Wonsik Kimec585c32021-10-01 01:11:00 -07002245 if (mTunneled && drop && outputFormat) {
Houxiang Daie74e5062022-05-19 15:32:54 +08002246 if (mOutputFormat != outputFormat) {
2247 ALOGV("[%s] onWorkDone: Keep tunneled, drop frame with format change (%lld)",
2248 mName, work->input.ordinal.frameIndex.peekull());
2249 mOutputFormat = outputFormat;
2250 } else {
2251 ALOGV("[%s] onWorkDone: Not reporting output buffer without format change (%lld)",
2252 mName, work->input.ordinal.frameIndex.peekull());
2253 notifyClient = false;
2254 }
Wonsik Kimec585c32021-10-01 01:11:00 -07002255 } else {
2256 ALOGV("[%s] onWorkDone: Not reporting output buffer (%lld)",
2257 mName, work->input.ordinal.frameIndex.peekull());
2258 notifyClient = false;
2259 }
Pawin Vongmasa36653902018-11-15 00:10:25 -08002260 }
2261
2262 if (buffer) {
2263 for (const std::shared_ptr<const C2Info> &info : buffer->info()) {
2264 // TODO: properly translate these to metadata
2265 switch (info->coreIndex().coreIndex()) {
2266 case C2StreamPictureTypeMaskInfo::CORE_INDEX:
Lajos Molnar3bb81cd2019-02-20 15:10:30 -08002267 if (((C2StreamPictureTypeMaskInfo *)info.get())->value & C2Config::SYNC_FRAME) {
My Named4d22242022-03-28 13:53:32 -07002268 flags |= BUFFER_FLAG_KEY_FRAME;
Pawin Vongmasa36653902018-11-15 00:10:25 -08002269 }
2270 break;
2271 default:
2272 break;
2273 }
2274 }
2275 }
2276
2277 {
Pawin Vongmasa9b906982020-04-11 05:07:15 -07002278 Mutexed<Output>::Locked output(mOutput);
Wonsik Kimc23cc402020-05-28 14:53:40 -07002279 if (!output->buffers) {
2280 return false;
2281 }
Pawin Vongmasa9b906982020-04-11 05:07:15 -07002282 output->buffers->pushToStash(
2283 buffer,
2284 notifyClient,
2285 timestamp.peek(),
2286 flags,
2287 outputFormat,
2288 worklet->output.ordinal);
Pawin Vongmasa36653902018-11-15 00:10:25 -08002289 }
2290 sendOutputBuffers();
2291 return true;
2292}
2293
2294void CCodecBufferChannel::sendOutputBuffers() {
Pawin Vongmasa9b906982020-04-11 05:07:15 -07002295 OutputBuffers::BufferAction action;
Wonsik Kima4e049d2020-04-28 19:42:23 +00002296 size_t index;
Pawin Vongmasa9b906982020-04-11 05:07:15 -07002297 sp<MediaCodecBuffer> outBuffer;
2298 std::shared_ptr<C2Buffer> c2Buffer;
Pawin Vongmasa36653902018-11-15 00:10:25 -08002299
Sungtak Lee8ceef4d2022-06-15 00:49:26 +00002300 constexpr int kMaxReallocTry = 5;
2301 int reallocTryNum = 0;
2302
Pawin Vongmasa36653902018-11-15 00:10:25 -08002303 while (true) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -07002304 Mutexed<Output>::Locked output(mOutput);
Wonsik Kim936a89c2020-05-08 16:07:50 -07002305 if (!output->buffers) {
2306 return;
2307 }
Pawin Vongmasa9b906982020-04-11 05:07:15 -07002308 action = output->buffers->popFromStashAndRegister(
2309 &c2Buffer, &index, &outBuffer);
Sungtak Lee8ceef4d2022-06-15 00:49:26 +00002310 if (action != OutputBuffers::REALLOCATE) {
2311 reallocTryNum = 0;
2312 }
Pawin Vongmasa9b906982020-04-11 05:07:15 -07002313 switch (action) {
2314 case OutputBuffers::SKIP:
2315 return;
2316 case OutputBuffers::DISCARD:
2317 break;
2318 case OutputBuffers::NOTIFY_CLIENT:
Arun Johnsonf4a81f72023-11-09 21:22:48 +00002319 {
Wonsik Kim5c2c8902023-05-09 10:53:15 -07002320 // TRICKY: we want popped buffers reported in order, so sending
2321 // the callback while holding the lock here. This assumes that
2322 // onOutputBufferAvailable() does not block. onOutputBufferAvailable()
2323 // callbacks are always sent with the Output lock held.
Arun Johnsonf4a81f72023-11-09 21:22:48 +00002324 if (c2Buffer) {
2325 std::shared_ptr<const C2AccessUnitInfos::output> bufferMetadata =
2326 std::static_pointer_cast<const C2AccessUnitInfos::output>(
2327 c2Buffer->getInfo(C2AccessUnitInfos::output::PARAM_TYPE));
2328 if (bufferMetadata && bufferMetadata->flexCount() > 0) {
2329 uint32_t flag = 0;
2330 std::vector<AccessUnitInfo> accessUnitInfos;
2331 for (int nMeta = 0; nMeta < bufferMetadata->flexCount(); nMeta++) {
2332 const C2AccessUnitInfosStruct &bufferMetadataStruct =
2333 bufferMetadata->m.values[nMeta];
2334 flag = convertFlags(bufferMetadataStruct.flags, false);
2335 accessUnitInfos.emplace_back(flag,
2336 static_cast<size_t>(bufferMetadataStruct.size),
2337 static_cast<size_t>(bufferMetadataStruct.timestamp));
2338 }
2339 sp<WrapperObject<std::vector<AccessUnitInfo>>> obj{
2340 new WrapperObject<std::vector<AccessUnitInfo>>{accessUnitInfos}};
2341 outBuffer->meta()->setObject("accessUnitInfo", obj);
2342 }
2343 }
Pawin Vongmasa9b906982020-04-11 05:07:15 -07002344 mCallback->onOutputBufferAvailable(index, outBuffer);
2345 break;
Arun Johnsonf4a81f72023-11-09 21:22:48 +00002346 }
Pawin Vongmasa9b906982020-04-11 05:07:15 -07002347 case OutputBuffers::REALLOCATE:
Sungtak Lee8ceef4d2022-06-15 00:49:26 +00002348 if (++reallocTryNum > kMaxReallocTry) {
2349 output.unlock();
2350 ALOGE("[%s] sendOutputBuffers: tried %d realloc and failed",
2351 mName, kMaxReallocTry);
2352 mCCodecCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL);
2353 return;
2354 }
Pawin Vongmasa9b906982020-04-11 05:07:15 -07002355 if (!output->buffers->isArrayMode()) {
2356 output->buffers =
2357 output->buffers->toArrayMode(output->numSlots);
Pawin Vongmasa36653902018-11-15 00:10:25 -08002358 }
Pawin Vongmasa9b906982020-04-11 05:07:15 -07002359 static_cast<OutputBuffersArray*>(output->buffers.get())->
2360 realloc(c2Buffer);
2361 output.unlock();
2362 mCCodecCallback->onOutputBuffersChanged();
Wonsik Kim4ada73d2020-05-26 14:58:07 -07002363 break;
Pawin Vongmasa9b906982020-04-11 05:07:15 -07002364 case OutputBuffers::RETRY:
2365 ALOGV("[%s] sendOutputBuffers: unable to register output buffer",
2366 mName);
2367 return;
2368 default:
2369 LOG_ALWAYS_FATAL("[%s] sendOutputBuffers: "
2370 "corrupted BufferAction value (%d) "
2371 "returned from popFromStashAndRegister.",
2372 mName, int(action));
Pawin Vongmasa36653902018-11-15 00:10:25 -08002373 return;
2374 }
Pawin Vongmasa36653902018-11-15 00:10:25 -08002375 }
2376}
2377
Sungtak Lee214ce612023-11-01 10:01:13 +00002378status_t CCodecBufferChannel::setSurface(const sp<Surface> &newSurface,
2379 uint32_t generation, bool pushBlankBuffer) {
Pawin Vongmasa36653902018-11-15 00:10:25 -08002380 sp<IGraphicBufferProducer> producer;
Sungtak Lee99144332023-01-26 11:03:14 +00002381 int maxDequeueCount;
2382 sp<Surface> oldSurface;
2383 {
2384 Mutexed<OutputSurface>::Locked outputSurface(mOutputSurface);
2385 maxDequeueCount = outputSurface->maxDequeueBuffers;
2386 oldSurface = outputSurface->surface;
2387 }
Pawin Vongmasa36653902018-11-15 00:10:25 -08002388 if (newSurface) {
2389 newSurface->setScalingMode(NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
Sungtak Leeab6f2f32019-02-15 14:43:51 -08002390 newSurface->setDequeueTimeout(kDequeueTimeoutNs);
Sungtak Leedb14cba2021-04-10 00:50:23 -07002391 newSurface->setMaxDequeuedBufferCount(maxDequeueCount);
Pawin Vongmasa36653902018-11-15 00:10:25 -08002392 producer = newSurface->getIGraphicBufferProducer();
Pawin Vongmasa36653902018-11-15 00:10:25 -08002393 } else {
2394 ALOGE("[%s] setting output surface to null", mName);
2395 return INVALID_OPERATION;
2396 }
2397
2398 std::shared_ptr<Codec2Client::Configurable> outputPoolIntf;
2399 C2BlockPool::local_id_t outputPoolId;
2400 {
2401 Mutexed<BlockPools>::Locked pools(mBlockPools);
2402 outputPoolId = pools->outputPoolId;
2403 outputPoolIntf = pools->outputPoolIntf;
2404 }
2405
2406 if (outputPoolIntf) {
2407 if (mComponent->setOutputSurface(
2408 outputPoolId,
2409 producer,
Sungtak Leedb14cba2021-04-10 00:50:23 -07002410 generation,
2411 maxDequeueCount) != C2_OK) {
Pawin Vongmasa36653902018-11-15 00:10:25 -08002412 ALOGI("[%s] setSurface: component setOutputSurface failed", mName);
2413 return INVALID_OPERATION;
2414 }
2415 }
2416
2417 {
2418 Mutexed<OutputSurface>::Locked output(mOutputSurface);
2419 output->surface = newSurface;
2420 output->generation = generation;
Brian Lindahl932bf602023-03-09 11:59:48 -07002421 initializeFrameTrackingFor(static_cast<ANativeWindow *>(newSurface.get()));
Pawin Vongmasa36653902018-11-15 00:10:25 -08002422 }
2423
Sungtak Lee99144332023-01-26 11:03:14 +00002424 if (oldSurface && pushBlankBuffer) {
2425 // When ReleaseSurface was set from MediaCodec,
2426 // pushing a blank buffer at the end might be necessary.
2427 sp<ANativeWindow> anw = static_cast<ANativeWindow *>(oldSurface.get());
2428 if (anw) {
2429 pushBlankBuffersToNativeWindow(anw.get());
2430 }
2431 }
2432
Pawin Vongmasa36653902018-11-15 00:10:25 -08002433 return OK;
2434}
2435
Wonsik Kimab34ed62019-01-31 15:28:46 -08002436PipelineWatcher::Clock::duration CCodecBufferChannel::elapsed() {
Wonsik Kim4fa4f2b2019-02-13 11:02:58 -08002437 // Otherwise, component may have stalled work due to input starvation up to
2438 // the sum of the delay in the pipeline.
Wonsik Kim31512192022-05-02 18:22:37 -07002439 // TODO(b/231253301): When client pushed EOS, the pipeline could have less
2440 // number of frames.
Wonsik Kimf0e7d222019-06-28 12:33:16 -07002441 size_t n = 0;
Wonsik Kim31512192022-05-02 18:22:37 -07002442 size_t outputDelay = mOutput.lock()->outputDelay;
2443 {
Wonsik Kimf0e7d222019-06-28 12:33:16 -07002444 Mutexed<Input>::Locked input(mInput);
2445 n = input->inputDelay + input->pipelineDelay + outputDelay;
2446 }
Wonsik Kim4fa4f2b2019-02-13 11:02:58 -08002447 return mPipelineWatcher.lock()->elapsed(PipelineWatcher::Clock::now(), n);
Wonsik Kimab34ed62019-01-31 15:28:46 -08002448}
2449
Pawin Vongmasa36653902018-11-15 00:10:25 -08002450void CCodecBufferChannel::setMetaMode(MetaMode mode) {
2451 mMetaMode = mode;
2452}
2453
Wonsik Kim596187e2019-10-25 12:44:10 -07002454void CCodecBufferChannel::setCrypto(const sp<ICrypto> &crypto) {
Wonsik Kimfb7a7672019-12-27 17:13:33 -08002455 if (mCrypto != nullptr) {
2456 for (std::pair<wp<HidlMemory>, int32_t> entry : mHeapSeqNumMap) {
2457 mCrypto->unsetHeap(entry.second);
2458 }
2459 mHeapSeqNumMap.clear();
2460 if (mHeapSeqNum >= 0) {
2461 mCrypto->unsetHeap(mHeapSeqNum);
2462 mHeapSeqNum = -1;
2463 }
2464 }
Wonsik Kim596187e2019-10-25 12:44:10 -07002465 mCrypto = crypto;
2466}
2467
2468void CCodecBufferChannel::setDescrambler(const sp<IDescrambler> &descrambler) {
2469 mDescrambler = descrambler;
2470}
2471
Songyue Han1e6769b2023-08-30 18:09:27 +00002472uint32_t CCodecBufferChannel::getBuffersPixelFormat(bool isEncoder) {
2473 if (isEncoder) {
2474 return getInputBuffersPixelFormat();
2475 } else {
2476 return getOutputBuffersPixelFormat();
2477 }
2478}
2479
2480uint32_t CCodecBufferChannel::getInputBuffersPixelFormat() {
2481 Mutexed<Input>::Locked input(mInput);
2482 if (input->buffers == nullptr) {
2483 return PIXEL_FORMAT_UNKNOWN;
2484 }
2485 return input->buffers->getPixelFormatIfApplicable();
2486}
2487
2488uint32_t CCodecBufferChannel::getOutputBuffersPixelFormat() {
2489 Mutexed<Output>::Locked output(mOutput);
2490 if (output->buffers == nullptr) {
2491 return PIXEL_FORMAT_UNKNOWN;
2492 }
2493 return output->buffers->getPixelFormatIfApplicable();
2494}
2495
2496void CCodecBufferChannel::resetBuffersPixelFormat(bool isEncoder) {
2497 if (isEncoder) {
2498 Mutexed<Input>::Locked input(mInput);
2499 if (input->buffers == nullptr) {
2500 return;
2501 }
2502 input->buffers->resetPixelFormatIfApplicable();
2503 } else {
2504 Mutexed<Output>::Locked output(mOutput);
2505 if (output->buffers == nullptr) {
2506 return;
2507 }
2508 output->buffers->resetPixelFormatIfApplicable();
2509 }
2510}
2511
Pawin Vongmasa36653902018-11-15 00:10:25 -08002512status_t toStatusT(c2_status_t c2s, c2_operation_t c2op) {
2513 // C2_OK is always translated to OK.
2514 if (c2s == C2_OK) {
2515 return OK;
2516 }
2517
2518 // Operation-dependent translation
2519 // TODO: Add as necessary
2520 switch (c2op) {
2521 case C2_OPERATION_Component_start:
2522 switch (c2s) {
2523 case C2_NO_MEMORY:
2524 return NO_MEMORY;
2525 default:
2526 return UNKNOWN_ERROR;
2527 }
2528 default:
2529 break;
2530 }
2531
2532 // Backup operation-agnostic translation
2533 switch (c2s) {
2534 case C2_BAD_INDEX:
2535 return BAD_INDEX;
2536 case C2_BAD_VALUE:
2537 return BAD_VALUE;
2538 case C2_BLOCKING:
2539 return WOULD_BLOCK;
2540 case C2_DUPLICATE:
2541 return ALREADY_EXISTS;
2542 case C2_NO_INIT:
2543 return NO_INIT;
2544 case C2_NO_MEMORY:
2545 return NO_MEMORY;
2546 case C2_NOT_FOUND:
2547 return NAME_NOT_FOUND;
2548 case C2_TIMED_OUT:
2549 return TIMED_OUT;
2550 case C2_BAD_STATE:
2551 case C2_CANCELED:
2552 case C2_CANNOT_DO:
2553 case C2_CORRUPTED:
2554 case C2_OMITTED:
2555 case C2_REFUSED:
2556 return UNKNOWN_ERROR;
2557 default:
2558 return -static_cast<status_t>(c2s);
2559 }
2560}
2561
Pawin Vongmasa36653902018-11-15 00:10:25 -08002562} // namespace android