blob: 3e74d8f70a0cd0244423eae603e754bbbf4144fc [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
Harish Mahendrakar38a99c22024-02-26 20:28:05 +053031#include <android_media_codec.h>
32
Pawin Vongmasa36653902018-11-15 00:10:25 -080033#include <C2AllocatorGralloc.h>
34#include <C2PlatformSupport.h>
35#include <C2BlockInternal.h>
36#include <C2Config.h>
37#include <C2Debug.h>
38
39#include <android/hardware/cas/native/1.0/IDescrambler.h>
Robert Shih895fba92019-07-16 16:29:44 -070040#include <android/hardware/drm/1.0/types.h>
Wonsik Kim3a692e62023-05-19 15:37:22 -070041#include <android-base/parseint.h>
Josh Hou8eddf4b2021-02-02 16:26:53 +080042#include <android-base/properties.h>
Pawin Vongmasa36653902018-11-15 00:10:25 -080043#include <android-base/stringprintf.h>
Wonsik Kimfb7a7672019-12-27 17:13:33 -080044#include <binder/MemoryBase.h>
Pawin Vongmasa36653902018-11-15 00:10:25 -080045#include <binder/MemoryDealer.h>
Ray Essick18ea0452019-08-27 16:07:27 -070046#include <cutils/properties.h>
Pawin Vongmasa36653902018-11-15 00:10:25 -080047#include <gui/Surface.h>
Robert Shih895fba92019-07-16 16:29:44 -070048#include <hidlmemory/FrameworkUtils.h>
Pawin Vongmasa36653902018-11-15 00:10:25 -080049#include <media/openmax/OMX_Core.h>
50#include <media/stagefright/foundation/ABuffer.h>
51#include <media/stagefright/foundation/ALookup.h>
52#include <media/stagefright/foundation/AMessage.h>
53#include <media/stagefright/foundation/AUtils.h>
54#include <media/stagefright/foundation/hexdump.h>
Pawin Vongmasa36653902018-11-15 00:10:25 -080055#include <media/stagefright/MediaCodecConstants.h>
Wonsik Kim155d5cb2019-10-09 12:49:49 -070056#include <media/stagefright/SkipCutBuffer.h>
Guillaume Chelfi2d4c9db2022-03-18 13:43:49 +010057#include <media/stagefright/SurfaceUtils.h>
Pawin Vongmasa36653902018-11-15 00:10:25 -080058#include <media/MediaCodecBuffer.h>
Wonsik Kim41d83432020-04-27 16:40:49 -070059#include <mediadrm/ICrypto.h>
Wonsik Kim3a692e62023-05-19 15:37:22 -070060#include <server_configurable_flags/get_flags.h>
Pawin Vongmasa36653902018-11-15 00:10:25 -080061#include <system/window.h>
62
63#include "CCodecBufferChannel.h"
64#include "Codec2Buffer.h"
Pawin Vongmasa36653902018-11-15 00:10:25 -080065
66namespace android {
67
68using android::base::StringPrintf;
69using hardware::hidl_handle;
70using hardware::hidl_string;
71using hardware::hidl_vec;
Robert Shih895fba92019-07-16 16:29:44 -070072using hardware::fromHeap;
73using hardware::HidlMemory;
Brian Lindahld7967a92023-08-10 10:12:49 -060074using server_configurable_flags::GetServerConfigurableFlag;
Robert Shih895fba92019-07-16 16:29:44 -070075
Pawin Vongmasa36653902018-11-15 00:10:25 -080076using namespace hardware::cas::V1_0;
77using namespace hardware::cas::native::V1_0;
78
79using CasStatus = hardware::cas::V1_0::Status;
Robert Shih895fba92019-07-16 16:29:44 -070080using DrmBufferType = hardware::drm::V1_0::BufferType;
Pawin Vongmasa36653902018-11-15 00:10:25 -080081
Pawin Vongmasa36653902018-11-15 00:10:25 -080082namespace {
83
Wonsik Kim469c8342019-04-11 16:46:09 -070084constexpr size_t kSmoothnessFactor = 4;
Pawin Vongmasa36653902018-11-15 00:10:25 -080085
Sungtak Leeab6f2f32019-02-15 14:43:51 -080086// This is for keeping IGBP's buffer dropping logic in legacy mode other
87// than making it non-blocking. Do not change this value.
88const static size_t kDequeueTimeoutNs = 0;
89
Brian Lindahld7967a92023-08-10 10:12:49 -060090static bool areRenderMetricsEnabled() {
91 std::string v = GetServerConfigurableFlag("media_native", "render_metrics_enabled", "false");
92 return v == "true";
93}
94
Arun Johnsonf4a81f72023-11-09 21:22:48 +000095// Flags can come with individual BufferInfos
96// when used with large frame audio
97constexpr static std::initializer_list<std::pair<uint32_t, uint32_t>> flagList = {
98 {BUFFER_FLAG_CODEC_CONFIG, C2FrameData::FLAG_CODEC_CONFIG},
99 {BUFFER_FLAG_END_OF_STREAM, C2FrameData::FLAG_END_OF_STREAM},
100 {BUFFER_FLAG_DECODE_ONLY, C2FrameData::FLAG_DROP_FRAME}
101};
102
103static uint32_t convertFlags(uint32_t flags, bool toC2) {
104 return std::transform_reduce(
105 flagList.begin(), flagList.end(),
106 0u,
107 std::bit_or{},
108 [flags, toC2](const std::pair<uint32_t, uint32_t> &entry) {
109 if (toC2) {
110 return (flags & entry.first) ? entry.second : 0;
111 } else {
112 return (flags & entry.second) ? entry.first : 0;
113 }
114 });
115}
116
Pawin Vongmasa36653902018-11-15 00:10:25 -0800117} // namespace
118
119CCodecBufferChannel::QueueGuard::QueueGuard(
120 CCodecBufferChannel::QueueSync &sync) : mSync(sync) {
121 Mutex::Autolock l(mSync.mGuardLock);
122 // At this point it's guaranteed that mSync is not under state transition,
123 // as we are holding its mutex.
124
125 Mutexed<CCodecBufferChannel::QueueSync::Counter>::Locked count(mSync.mCount);
126 if (count->value == -1) {
127 mRunning = false;
128 } else {
129 ++count->value;
130 mRunning = true;
131 }
132}
133
134CCodecBufferChannel::QueueGuard::~QueueGuard() {
135 if (mRunning) {
136 // We are not holding mGuardLock at this point so that QueueSync::stop() can
137 // keep holding the lock until mCount reaches zero.
138 Mutexed<CCodecBufferChannel::QueueSync::Counter>::Locked count(mSync.mCount);
139 --count->value;
140 count->cond.broadcast();
141 }
142}
143
144void CCodecBufferChannel::QueueSync::start() {
145 Mutex::Autolock l(mGuardLock);
146 // If stopped, it goes to running state; otherwise no-op.
147 Mutexed<Counter>::Locked count(mCount);
148 if (count->value == -1) {
149 count->value = 0;
150 }
151}
152
153void CCodecBufferChannel::QueueSync::stop() {
154 Mutex::Autolock l(mGuardLock);
155 Mutexed<Counter>::Locked count(mCount);
156 if (count->value == -1) {
157 // no-op
158 return;
159 }
160 // Holding mGuardLock here blocks creation of additional QueueGuard objects, so
161 // mCount can only decrement. In other words, threads that acquired the lock
162 // are allowed to finish execution but additional threads trying to acquire
163 // the lock at this point will block, and then get QueueGuard at STOPPED
164 // state.
165 while (count->value != 0) {
166 count.waitForCondition(count->cond);
167 }
168 count->value = -1;
169}
170
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700171// Input
172
173CCodecBufferChannel::Input::Input() : extraBuffers("extra") {}
174
Pawin Vongmasa36653902018-11-15 00:10:25 -0800175// CCodecBufferChannel
176
177CCodecBufferChannel::CCodecBufferChannel(
178 const std::shared_ptr<CCodecCallback> &callback)
179 : mHeapSeqNum(-1),
180 mCCodecCallback(callback),
181 mFrameIndex(0u),
182 mFirstValidFrameIndex(0u),
Brian Lindahld7967a92023-08-10 10:12:49 -0600183 mAreRenderMetricsEnabled(areRenderMetricsEnabled()),
Brian Lindahl2048d492023-04-05 08:49:23 -0600184 mIsSurfaceToDisplay(false),
185 mHasPresentFenceTimes(false),
Wonsik Kimb6ee72a2023-06-07 23:59:01 -0700186 mRenderingDepth(3u),
Pawin Vongmasa36653902018-11-15 00:10:25 -0800187 mMetaMode(MODE_NONE),
Sungtak Lee04b30352020-07-27 13:57:25 -0700188 mInputMetEos(false),
189 mSendEncryptedInfoBuffer(false) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700190 {
191 Mutexed<Input>::Locked input(mInput);
192 input->buffers.reset(new DummyInputBuffers(""));
193 input->extraBuffers.flush();
194 input->inputDelay = 0u;
195 input->pipelineDelay = 0u;
196 input->numSlots = kSmoothnessFactor;
197 input->numExtraSlots = 0u;
Wonsik Kim6b2c8be2021-09-28 05:11:04 -0700198 input->lastFlushIndex = 0u;
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700199 }
200 {
201 Mutexed<Output>::Locked output(mOutput);
202 output->outputDelay = 0u;
203 output->numSlots = kSmoothnessFactor;
Wonsik Kim3722abc2023-05-17 13:26:31 -0700204 output->bounded = false;
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700205 }
David Stevensc3fbb282021-01-18 18:11:20 +0900206 {
207 Mutexed<BlockPools>::Locked pools(mBlockPools);
208 pools->outputPoolId = C2BlockPool::BASIC_LINEAR;
209 }
Brian Lindahld7967a92023-08-10 10:12:49 -0600210 std::string value = GetServerConfigurableFlag("media_native", "ccodec_rendering_depth", "3");
Wonsik Kim3a692e62023-05-19 15:37:22 -0700211 android::base::ParseInt(value, &mRenderingDepth);
Wonsik Kimb6ee72a2023-06-07 23:59:01 -0700212 mOutputSurface.lock()->maxDequeueBuffers = kSmoothnessFactor + mRenderingDepth;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800213}
214
215CCodecBufferChannel::~CCodecBufferChannel() {
Wonsik Kimfb7a7672019-12-27 17:13:33 -0800216 if (mCrypto != nullptr && mHeapSeqNum >= 0) {
Pawin Vongmasa36653902018-11-15 00:10:25 -0800217 mCrypto->unsetHeap(mHeapSeqNum);
218 }
219}
220
221void CCodecBufferChannel::setComponent(
222 const std::shared_ptr<Codec2Client::Component> &component) {
223 mComponent = component;
224 mComponentName = component->getName() + StringPrintf("#%d", int(uintptr_t(component.get()) % 997));
225 mName = mComponentName.c_str();
226}
227
228status_t CCodecBufferChannel::setInputSurface(
229 const std::shared_ptr<InputSurfaceWrapper> &surface) {
230 ALOGV("[%s] setInputSurface", mName);
Wonsik Kimd4ba8462024-07-12 11:05:48 -0700231 Mutexed<std::shared_ptr<InputSurfaceWrapper>>::Locked inputSurface(mInputSurface);
232 *inputSurface = surface;
233 return (*inputSurface)->connect(mComponent);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800234}
235
236status_t CCodecBufferChannel::signalEndOfInputStream() {
Wonsik Kimd4ba8462024-07-12 11:05:48 -0700237 Mutexed<std::shared_ptr<InputSurfaceWrapper>>::Locked inputSurface(mInputSurface);
238 if ((*inputSurface) == nullptr) {
Pawin Vongmasa36653902018-11-15 00:10:25 -0800239 return INVALID_OPERATION;
240 }
Wonsik Kimd4ba8462024-07-12 11:05:48 -0700241 return (*inputSurface)->signalEndOfInputStream();
Pawin Vongmasa36653902018-11-15 00:10:25 -0800242}
243
Sungtak Lee04b30352020-07-27 13:57:25 -0700244status_t CCodecBufferChannel::queueInputBufferInternal(
245 sp<MediaCodecBuffer> buffer,
246 std::shared_ptr<C2LinearBlock> encryptedBlock,
247 size_t blockSize) {
Pawin Vongmasa36653902018-11-15 00:10:25 -0800248 int64_t timeUs;
249 CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
250
251 if (mInputMetEos) {
252 ALOGD("[%s] buffers after EOS ignored (%lld us)", mName, (long long)timeUs);
253 return OK;
254 }
255
256 int32_t flags = 0;
257 int32_t tmp = 0;
258 bool eos = false;
Guillaume Chelfi867d4dd2021-07-01 18:38:45 +0200259 bool tunnelFirstFrame = false;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800260 if (buffer->meta()->findInt32("eos", &tmp) && tmp) {
261 eos = true;
262 mInputMetEos = true;
263 ALOGV("[%s] input EOS", mName);
264 }
265 if (buffer->meta()->findInt32("csd", &tmp) && tmp) {
266 flags |= C2FrameData::FLAG_CODEC_CONFIG;
267 }
Guillaume Chelfi867d4dd2021-07-01 18:38:45 +0200268 if (buffer->meta()->findInt32("tunnel-first-frame", &tmp) && tmp) {
269 tunnelFirstFrame = true;
270 }
Marc Kassis96343b42022-12-09 11:49:44 +0100271 if (buffer->meta()->findInt32("decode-only", &tmp) && tmp) {
272 flags |= C2FrameData::FLAG_DROP_FRAME;
273 }
Arun Johnsonf4a81f72023-11-09 21:22:48 +0000274 ALOGV("[%s] queueInputBuffer: buffer->size() = %zu time: %lld",
275 mName, buffer->size(), (long long)timeUs);
Wonsik Kime1104ca2020-11-24 15:01:33 -0800276 std::list<std::unique_ptr<C2Work>> items;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800277 std::unique_ptr<C2Work> work(new C2Work);
278 work->input.ordinal.timestamp = timeUs;
279 work->input.ordinal.frameIndex = mFrameIndex++;
280 // WORKAROUND: until codecs support handling work after EOS and max output sizing, use timestamp
281 // manipulation to achieve image encoding via video codec, and to constrain encoded output.
282 // Keep client timestamp in customOrdinal
283 work->input.ordinal.customOrdinal = timeUs;
284 work->input.buffers.clear();
285
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700286 sp<Codec2Buffer> copy;
Wonsik Kime1104ca2020-11-24 15:01:33 -0800287 bool usesFrameReassembler = false;
Wonsik Kimab34ed62019-01-31 15:28:46 -0800288
Pawin Vongmasa36653902018-11-15 00:10:25 -0800289 if (buffer->size() > 0u) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700290 Mutexed<Input>::Locked input(mInput);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800291 std::shared_ptr<C2Buffer> c2buffer;
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700292 if (!input->buffers->releaseBuffer(buffer, &c2buffer, false)) {
Pawin Vongmasa36653902018-11-15 00:10:25 -0800293 return -ENOENT;
294 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700295 // TODO: we want to delay copying buffers.
296 if (input->extraBuffers.numComponentBuffers() < input->numExtraSlots) {
297 copy = input->buffers->cloneAndReleaseBuffer(buffer);
298 if (copy != nullptr) {
299 (void)input->extraBuffers.assignSlot(copy);
300 if (!input->extraBuffers.releaseSlot(copy, &c2buffer, false)) {
301 return UNKNOWN_ERROR;
302 }
303 bool released = input->buffers->releaseBuffer(buffer, nullptr, true);
304 ALOGV("[%s] queueInputBuffer: buffer copied; %sreleased",
305 mName, released ? "" : "not ");
Wonsik Kimfb5ca492021-08-11 14:18:19 -0700306 buffer = copy;
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700307 } else {
308 ALOGW("[%s] queueInputBuffer: failed to copy a buffer; this may cause input "
309 "buffer starvation on component.", mName);
310 }
311 }
Wonsik Kime1104ca2020-11-24 15:01:33 -0800312 if (input->frameReassembler) {
313 usesFrameReassembler = true;
314 input->frameReassembler.process(buffer, &items);
315 } else {
Byeongjo Park25c3a3d2020-06-12 17:24:21 +0900316 int32_t cvo = 0;
317 if (buffer->meta()->findInt32("cvo", &cvo)) {
318 int32_t rotation = cvo % 360;
319 // change rotation to counter-clock wise.
320 rotation = ((rotation <= 0) ? 0 : 360) - rotation;
321
322 Mutexed<OutputSurface>::Locked output(mOutputSurface);
323 uint64_t frameIndex = work->input.ordinal.frameIndex.peeku();
324 output->rotation[frameIndex] = rotation;
325 }
Arun Johnsonf4a81f72023-11-09 21:22:48 +0000326 sp<RefBase> obj;
327 if (buffer->meta()->findObject("accessUnitInfo", &obj)) {
328 ALOGV("Filling C2Info from multiple access units");
329 sp<WrapperObject<std::vector<AccessUnitInfo>>> infos{
330 (decltype(infos.get()))obj.get()};
331 std::vector<AccessUnitInfo> &accessUnitInfoVec = infos->value;
332 std::vector<C2AccessUnitInfosStruct> multipleAccessUnitInfos;
333 uint32_t outFlags = 0;
334 for (int i = 0; i < accessUnitInfoVec.size(); i++) {
335 outFlags = 0;
336 outFlags = convertFlags(accessUnitInfoVec[i].mFlags, true);
337 if (eos && (outFlags & C2FrameData::FLAG_END_OF_STREAM)) {
338 outFlags &= (~C2FrameData::FLAG_END_OF_STREAM);
339 }
340 multipleAccessUnitInfos.emplace_back(
341 outFlags,
342 accessUnitInfoVec[i].mSize,
343 accessUnitInfoVec[i].mTimestamp);
344 ALOGV("%d) flags: %d, size: %d, time: %llu",
345 i, outFlags, accessUnitInfoVec[i].mSize,
346 (long long)accessUnitInfoVec[i].mTimestamp);
347
348 }
349 const std::shared_ptr<C2AccessUnitInfos::input> c2AccessUnitInfos =
350 C2AccessUnitInfos::input::AllocShared(
351 multipleAccessUnitInfos.size(), 0u, multipleAccessUnitInfos);
352 c2buffer->setInfo(c2AccessUnitInfos);
353 }
Wonsik Kime1104ca2020-11-24 15:01:33 -0800354 work->input.buffers.push_back(c2buffer);
355 if (encryptedBlock) {
356 work->input.infoBuffers.emplace_back(C2InfoBuffer::CreateLinearBuffer(
357 kParamIndexEncryptedBuffer,
358 encryptedBlock->share(0, blockSize, C2Fence())));
359 }
Sungtak Lee04b30352020-07-27 13:57:25 -0700360 }
Wonsik Kimab34ed62019-01-31 15:28:46 -0800361 } else if (eos) {
Wonsik Kimcc59ad82021-08-11 18:15:19 -0700362 Mutexed<Input>::Locked input(mInput);
363 if (input->frameReassembler) {
364 usesFrameReassembler = true;
365 // drain any pending items with eos
366 input->frameReassembler.process(buffer, &items);
367 }
Wonsik Kimab34ed62019-01-31 15:28:46 -0800368 flags |= C2FrameData::FLAG_END_OF_STREAM;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800369 }
Wonsik Kime1104ca2020-11-24 15:01:33 -0800370 if (usesFrameReassembler) {
371 if (!items.empty()) {
372 items.front()->input.configUpdate = std::move(mParamsToBeSet);
373 mFrameIndex = (items.back()->input.ordinal.frameIndex + 1).peek();
374 }
375 } else {
376 work->input.flags = (C2FrameData::flags_t)flags;
Harish Mahendrakar38a99c22024-02-26 20:28:05 +0530377
Wonsik Kime1104ca2020-11-24 15:01:33 -0800378 // TODO: fill info's
Harish Mahendrakar38a99c22024-02-26 20:28:05 +0530379 if (android::media::codec::provider_->region_of_interest()
380 && android::media::codec::provider_->region_of_interest_support()) {
381 if (mInfoBuffers.size()) {
382 for (auto infoBuffer : mInfoBuffers) {
383 work->input.infoBuffers.emplace_back(*infoBuffer);
384 }
385 mInfoBuffers.clear();
386 }
387 }
Pawin Vongmasa36653902018-11-15 00:10:25 -0800388
Wonsik Kime1104ca2020-11-24 15:01:33 -0800389 work->input.configUpdate = std::move(mParamsToBeSet);
Guillaume Chelfi867d4dd2021-07-01 18:38:45 +0200390 if (tunnelFirstFrame) {
391 C2StreamTunnelHoldRender::input tunnelHoldRender{
392 0u /* stream */,
393 C2_TRUE /* value */
394 };
395 work->input.configUpdate.push_back(C2Param::Copy(tunnelHoldRender));
396 }
Wonsik Kime1104ca2020-11-24 15:01:33 -0800397 work->worklets.clear();
398 work->worklets.emplace_back(new C2Worklet);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800399
Wonsik Kime1104ca2020-11-24 15:01:33 -0800400 items.push_back(std::move(work));
401
402 eos = eos && buffer->size() > 0u;
Wonsik Kimab34ed62019-01-31 15:28:46 -0800403 }
Wonsik Kime1104ca2020-11-24 15:01:33 -0800404 if (eos) {
Pawin Vongmasa36653902018-11-15 00:10:25 -0800405 work.reset(new C2Work);
406 work->input.ordinal.timestamp = timeUs;
407 work->input.ordinal.frameIndex = mFrameIndex++;
408 // WORKAROUND: keep client timestamp in customOrdinal
409 work->input.ordinal.customOrdinal = timeUs;
410 work->input.buffers.clear();
411 work->input.flags = C2FrameData::FLAG_END_OF_STREAM;
Pawin Vongmasa1c75a232019-01-09 04:41:52 -0800412 work->worklets.emplace_back(new C2Worklet);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800413 items.push_back(std::move(work));
Pawin Vongmasa36653902018-11-15 00:10:25 -0800414 }
Wonsik Kime1104ca2020-11-24 15:01:33 -0800415 c2_status_t err = C2_OK;
416 if (!items.empty()) {
My Name6bd9a7d2022-03-25 12:37:58 -0700417 ScopedTrace trace(ATRACE_TAG, android::base::StringPrintf(
418 "CCodecBufferChannel::queue(%s@ts=%lld)", mName, (long long)timeUs).c_str());
Wonsik Kime1104ca2020-11-24 15:01:33 -0800419 {
420 Mutexed<PipelineWatcher>::Locked watcher(mPipelineWatcher);
421 PipelineWatcher::Clock::time_point now = PipelineWatcher::Clock::now();
422 for (const std::unique_ptr<C2Work> &work : items) {
423 watcher->onWorkQueued(
424 work->input.ordinal.frameIndex.peeku(),
425 std::vector(work->input.buffers),
426 now);
427 }
428 }
429 err = mComponent->queue(&items);
430 }
431 if (err != C2_OK) {
432 Mutexed<PipelineWatcher>::Locked watcher(mPipelineWatcher);
433 for (const std::unique_ptr<C2Work> &work : items) {
434 watcher->onWorkDone(work->input.ordinal.frameIndex.peeku());
435 }
436 } else {
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700437 Mutexed<Input>::Locked input(mInput);
438 bool released = false;
Wonsik Kimfb5ca492021-08-11 14:18:19 -0700439 if (copy) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700440 released = input->extraBuffers.releaseSlot(copy, nullptr, true);
Wonsik Kimfb5ca492021-08-11 14:18:19 -0700441 } else if (buffer) {
442 released = input->buffers->releaseBuffer(buffer, nullptr, true);
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700443 }
444 ALOGV("[%s] queueInputBuffer: buffer%s %sreleased",
445 mName, (buffer == nullptr) ? "(copy)" : "", released ? "" : "not ");
Pawin Vongmasa36653902018-11-15 00:10:25 -0800446 }
447
448 feedInputBufferIfAvailableInternal();
449 return err;
450}
451
452status_t CCodecBufferChannel::setParameters(std::vector<std::unique_ptr<C2Param>> &params) {
453 QueueGuard guard(mSync);
454 if (!guard.isRunning()) {
455 ALOGD("[%s] setParameters is only supported in the running state.", mName);
456 return -ENOSYS;
457 }
458 mParamsToBeSet.insert(mParamsToBeSet.end(),
459 std::make_move_iterator(params.begin()),
460 std::make_move_iterator(params.end()));
461 params.clear();
462 return OK;
463}
464
Wonsik Kimfb7a7672019-12-27 17:13:33 -0800465status_t CCodecBufferChannel::attachBuffer(
466 const std::shared_ptr<C2Buffer> &c2Buffer,
467 const sp<MediaCodecBuffer> &buffer) {
468 if (!buffer->copy(c2Buffer)) {
469 return -ENOSYS;
470 }
471 return OK;
472}
473
474void CCodecBufferChannel::ensureDecryptDestination(size_t size) {
475 if (!mDecryptDestination || mDecryptDestination->size() < size) {
476 sp<IMemoryHeap> heap{new MemoryHeapBase(size * 2)};
477 if (mDecryptDestination && mCrypto && mHeapSeqNum >= 0) {
478 mCrypto->unsetHeap(mHeapSeqNum);
479 }
480 mDecryptDestination = new MemoryBase(heap, 0, size * 2);
481 if (mCrypto) {
482 mHeapSeqNum = mCrypto->setHeap(hardware::fromHeap(heap));
483 }
484 }
485}
486
487int32_t CCodecBufferChannel::getHeapSeqNum(const sp<HidlMemory> &memory) {
488 CHECK(mCrypto);
489 auto it = mHeapSeqNumMap.find(memory);
490 int32_t heapSeqNum = -1;
491 if (it == mHeapSeqNumMap.end()) {
492 heapSeqNum = mCrypto->setHeap(memory);
493 mHeapSeqNumMap.emplace(memory, heapSeqNum);
494 } else {
495 heapSeqNum = it->second;
496 }
497 return heapSeqNum;
498}
499
Arun Johnson564f3a92024-02-01 19:09:45 +0000500typedef WrapperObject<std::vector<AccessUnitInfo>> BufferInfosWrapper;
501typedef WrapperObject<std::vector<std::unique_ptr<CodecCryptoInfo>>> CryptoInfosWrapper;
502status_t CCodecBufferChannel::attachEncryptedBuffers(
503 const sp<hardware::HidlMemory> &memory,
504 size_t offset,
505 const sp<MediaCodecBuffer> &buffer,
506 bool secure,
507 AString* errorDetailMsg) {
508 static const C2MemoryUsage kDefaultReadWriteUsage{
509 C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE};
510 if (!hasCryptoOrDescrambler()) {
511 ALOGE("attachEncryptedBuffers requires Crypto/descrambler object");
512 return -ENOSYS;
513 }
514 size_t size = 0;
515 CHECK(buffer->meta()->findSize("ssize", &size));
516 if (size == 0) {
517 buffer->setRange(0, 0);
518 return OK;
519 }
520 sp<RefBase> obj;
521 CHECK(buffer->meta()->findObject("cryptoInfos", &obj));
522 sp<CryptoInfosWrapper> cryptoInfos{(CryptoInfosWrapper *)obj.get()};
523 CHECK(buffer->meta()->findObject("accessUnitInfo", &obj));
524 sp<BufferInfosWrapper> bufferInfos{(BufferInfosWrapper *)obj.get()};
525 if (secure || (mCrypto == nullptr)) {
526 if (cryptoInfos->value.size() != 1) {
527 ALOGE("Cannot decrypt multiple access units");
528 return -ENOSYS;
529 }
530 // we are dealing with just one cryptoInfo or descrambler.
531 std::unique_ptr<CodecCryptoInfo> info = std::move(cryptoInfos->value[0]);
532 if (info == nullptr) {
533 ALOGE("Cannot decrypt, CryptoInfos are null.");
534 return -ENOSYS;
535 }
536 return attachEncryptedBuffer(
537 memory,
538 secure,
539 info->mKey,
540 info->mIv,
541 info->mMode,
542 info->mPattern,
543 offset,
544 info->mSubSamples,
545 info->mNumSubSamples,
546 buffer,
547 errorDetailMsg);
548 }
549 std::shared_ptr<C2BlockPool> pool = mBlockPools.lock()->inputPool;
550 std::shared_ptr<C2LinearBlock> block;
551 c2_status_t err = pool->fetchLinearBlock(
552 size,
553 kDefaultReadWriteUsage,
554 &block);
555 if (err != C2_OK) {
556 ALOGI("[%s] attachEncryptedBuffers: fetchLinearBlock failed: size = %zu (%s) err = %d",
557 mName, size, secure ? "secure" : "non-secure", err);
558 return NO_MEMORY;
559 }
560 ensureDecryptDestination(size);
561 C2WriteView wView = block->map().get();
562 if (wView.error() != C2_OK) {
563 ALOGI("[%s] attachEncryptedBuffers: block map error: %d (non-secure)",
564 mName, wView.error());
565 return UNKNOWN_ERROR;
566 }
567
568 ssize_t result = -1;
Arun Johnson82174a12024-02-27 04:53:59 +0000569 size_t srcOffset = offset;
Arun Johnson564f3a92024-02-01 19:09:45 +0000570 size_t outBufferSize = 0;
571 uint32_t cryptoInfoIdx = 0;
572 int32_t heapSeqNum = getHeapSeqNum(memory);
573 hardware::drm::V1_0::SharedBuffer src{(uint32_t)heapSeqNum, offset, size};
574 hardware::drm::V1_0::DestinationBuffer dst;
575 dst.type = DrmBufferType::SHARED_MEMORY;
576 IMemoryToSharedBuffer(
577 mDecryptDestination, mHeapSeqNum, &dst.nonsecureMemory);
578 for (int i = 0; i < bufferInfos->value.size(); i++) {
579 if (bufferInfos->value[i].mSize > 0) {
580 std::unique_ptr<CodecCryptoInfo> info = std::move(cryptoInfos->value[cryptoInfoIdx++]);
Arun Johnson82174a12024-02-27 04:53:59 +0000581 src.offset = srcOffset;
582 src.size = bufferInfos->value[i].mSize;
Arun Johnson564f3a92024-02-01 19:09:45 +0000583 result = mCrypto->decrypt(
584 (uint8_t*)info->mKey,
585 (uint8_t*)info->mIv,
586 info->mMode,
587 info->mPattern,
588 src,
Arun Johnson82174a12024-02-27 04:53:59 +0000589 0,
Arun Johnson564f3a92024-02-01 19:09:45 +0000590 info->mSubSamples,
591 info->mNumSubSamples,
592 dst,
593 errorDetailMsg);
Arun Johnson82174a12024-02-27 04:53:59 +0000594 srcOffset += bufferInfos->value[i].mSize;
Arun Johnson564f3a92024-02-01 19:09:45 +0000595 if (result < 0) {
596 ALOGI("[%s] attachEncryptedBuffers: decrypt failed: result = %zd",
597 mName, result);
598 return result;
599 }
600 if (wView.error() == C2_OK) {
601 if (wView.size() < result) {
602 ALOGI("[%s] attachEncryptedBuffers: block size too small:"
603 "size=%u result=%zd (non-secure)", mName, wView.size(), result);
604 return UNKNOWN_ERROR;
605 }
606 memcpy(wView.data(), mDecryptDestination->unsecurePointer(), result);
607 bufferInfos->value[i].mSize = result;
608 wView.setOffset(wView.offset() + result);
609 }
610 outBufferSize += result;
611 }
612 }
613 if (wView.error() == C2_OK) {
614 wView.setOffset(0);
615 }
616 std::shared_ptr<C2Buffer> c2Buffer{C2Buffer::CreateLinearBuffer(
Arun Johnson82174a12024-02-27 04:53:59 +0000617 block->share(0, outBufferSize, C2Fence{}))};
Arun Johnson564f3a92024-02-01 19:09:45 +0000618 if (!buffer->copy(c2Buffer)) {
619 ALOGI("[%s] attachEncryptedBuffers: buffer copy failed", mName);
620 return -ENOSYS;
621 }
622 return OK;
623}
624
Wonsik Kimfb7a7672019-12-27 17:13:33 -0800625status_t CCodecBufferChannel::attachEncryptedBuffer(
626 const sp<hardware::HidlMemory> &memory,
627 bool secure,
628 const uint8_t *key,
629 const uint8_t *iv,
630 CryptoPlugin::Mode mode,
631 CryptoPlugin::Pattern pattern,
632 size_t offset,
633 const CryptoPlugin::SubSample *subSamples,
634 size_t numSubSamples,
Arun Johnson634d0802023-02-14 22:07:51 +0000635 const sp<MediaCodecBuffer> &buffer,
636 AString* errorDetailMsg) {
Wonsik Kimfb7a7672019-12-27 17:13:33 -0800637 static const C2MemoryUsage kSecureUsage{C2MemoryUsage::READ_PROTECTED, 0};
638 static const C2MemoryUsage kDefaultReadWriteUsage{
639 C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE};
640
641 size_t size = 0;
642 for (size_t i = 0; i < numSubSamples; ++i) {
643 size += subSamples[i].mNumBytesOfClearData + subSamples[i].mNumBytesOfEncryptedData;
644 }
Wonsik Kim59e65362022-05-24 14:20:50 -0700645 if (size == 0) {
646 buffer->setRange(0, 0);
647 return OK;
648 }
Wonsik Kimfb7a7672019-12-27 17:13:33 -0800649 std::shared_ptr<C2BlockPool> pool = mBlockPools.lock()->inputPool;
650 std::shared_ptr<C2LinearBlock> block;
651 c2_status_t err = pool->fetchLinearBlock(
652 size,
653 secure ? kSecureUsage : kDefaultReadWriteUsage,
654 &block);
655 if (err != C2_OK) {
Wonsik Kim59e65362022-05-24 14:20:50 -0700656 ALOGI("[%s] attachEncryptedBuffer: fetchLinearBlock failed: size = %zu (%s) err = %d",
657 mName, size, secure ? "secure" : "non-secure", err);
Wonsik Kimfb7a7672019-12-27 17:13:33 -0800658 return NO_MEMORY;
659 }
660 if (!secure) {
661 ensureDecryptDestination(size);
662 }
663 ssize_t result = -1;
664 ssize_t codecDataOffset = 0;
665 if (mCrypto) {
Wonsik Kimfb7a7672019-12-27 17:13:33 -0800666 int32_t heapSeqNum = getHeapSeqNum(memory);
667 hardware::drm::V1_0::SharedBuffer src{(uint32_t)heapSeqNum, offset, size};
668 hardware::drm::V1_0::DestinationBuffer dst;
669 if (secure) {
670 dst.type = DrmBufferType::NATIVE_HANDLE;
671 dst.secureMemory = hardware::hidl_handle(block->handle());
672 } else {
673 dst.type = DrmBufferType::SHARED_MEMORY;
674 IMemoryToSharedBuffer(
675 mDecryptDestination, mHeapSeqNum, &dst.nonsecureMemory);
676 }
677 result = mCrypto->decrypt(
678 key, iv, mode, pattern, src, 0, subSamples, numSubSamples,
Arun Johnson634d0802023-02-14 22:07:51 +0000679 dst, errorDetailMsg);
Wonsik Kimfb7a7672019-12-27 17:13:33 -0800680 if (result < 0) {
Wonsik Kim59e65362022-05-24 14:20:50 -0700681 ALOGI("[%s] attachEncryptedBuffer: decrypt failed: result = %zd", mName, result);
Wonsik Kimfb7a7672019-12-27 17:13:33 -0800682 return result;
683 }
Wonsik Kimfb7a7672019-12-27 17:13:33 -0800684 } else {
685 // Here we cast CryptoPlugin::SubSample to hardware::cas::native::V1_0::SubSample
686 // directly, the structure definitions should match as checked in DescramblerImpl.cpp.
687 hidl_vec<SubSample> hidlSubSamples;
688 hidlSubSamples.setToExternal((SubSample *)subSamples, numSubSamples, false /*own*/);
689
690 hardware::cas::native::V1_0::SharedBuffer src{*memory, offset, size};
691 hardware::cas::native::V1_0::DestinationBuffer dst;
692 if (secure) {
693 dst.type = BufferType::NATIVE_HANDLE;
694 dst.secureMemory = hardware::hidl_handle(block->handle());
695 } else {
696 dst.type = BufferType::SHARED_MEMORY;
697 dst.nonsecureMemory = src;
698 }
699
700 CasStatus status = CasStatus::OK;
701 hidl_string detailedError;
702 ScramblingControl sctrl = ScramblingControl::UNSCRAMBLED;
703
704 if (key != nullptr) {
705 sctrl = (ScramblingControl)key[0];
706 // Adjust for the PES offset
707 codecDataOffset = key[2] | (key[3] << 8);
708 }
709
710 auto returnVoid = mDescrambler->descramble(
711 sctrl,
712 hidlSubSamples,
713 src,
714 0,
715 dst,
716 0,
717 [&status, &result, &detailedError] (
718 CasStatus _status, uint32_t _bytesWritten,
719 const hidl_string& _detailedError) {
720 status = _status;
721 result = (ssize_t)_bytesWritten;
722 detailedError = _detailedError;
723 });
Arun Johnson634d0802023-02-14 22:07:51 +0000724 if (errorDetailMsg) {
725 errorDetailMsg->setTo(detailedError.c_str(), detailedError.size());
726 }
Wonsik Kimfb7a7672019-12-27 17:13:33 -0800727 if (!returnVoid.isOk() || status != CasStatus::OK || result < 0) {
728 ALOGI("[%s] descramble failed, trans=%s, status=%d, result=%zd",
729 mName, returnVoid.description().c_str(), status, result);
730 return UNKNOWN_ERROR;
731 }
732
733 if (result < codecDataOffset) {
Wonsik Kim59e65362022-05-24 14:20:50 -0700734 ALOGD("[%s] invalid codec data offset: %zd, result %zd",
735 mName, codecDataOffset, result);
Wonsik Kimfb7a7672019-12-27 17:13:33 -0800736 return BAD_VALUE;
737 }
738 }
739 if (!secure) {
740 C2WriteView view = block->map().get();
741 if (view.error() != C2_OK) {
Wonsik Kim59e65362022-05-24 14:20:50 -0700742 ALOGI("[%s] attachEncryptedBuffer: block map error: %d (non-secure)",
743 mName, view.error());
Wonsik Kimfb7a7672019-12-27 17:13:33 -0800744 return UNKNOWN_ERROR;
745 }
746 if (view.size() < result) {
Wonsik Kim59e65362022-05-24 14:20:50 -0700747 ALOGI("[%s] attachEncryptedBuffer: block size too small: size=%u result=%zd "
748 "(non-secure)",
749 mName, view.size(), result);
Wonsik Kimfb7a7672019-12-27 17:13:33 -0800750 return UNKNOWN_ERROR;
751 }
752 memcpy(view.data(), mDecryptDestination->unsecurePointer(), result);
753 }
754 std::shared_ptr<C2Buffer> c2Buffer{C2Buffer::CreateLinearBuffer(
755 block->share(codecDataOffset, result - codecDataOffset, C2Fence{}))};
756 if (!buffer->copy(c2Buffer)) {
Wonsik Kim59e65362022-05-24 14:20:50 -0700757 ALOGI("[%s] attachEncryptedBuffer: buffer copy failed", mName);
Wonsik Kimfb7a7672019-12-27 17:13:33 -0800758 return -ENOSYS;
759 }
760 return OK;
761}
762
Pawin Vongmasa36653902018-11-15 00:10:25 -0800763status_t CCodecBufferChannel::queueInputBuffer(const sp<MediaCodecBuffer> &buffer) {
764 QueueGuard guard(mSync);
765 if (!guard.isRunning()) {
766 ALOGD("[%s] No more buffers should be queued at current state.", mName);
767 return -ENOSYS;
768 }
769 return queueInputBufferInternal(buffer);
770}
771
772status_t CCodecBufferChannel::queueSecureInputBuffer(
773 const sp<MediaCodecBuffer> &buffer, bool secure, const uint8_t *key,
774 const uint8_t *iv, CryptoPlugin::Mode mode, CryptoPlugin::Pattern pattern,
775 const CryptoPlugin::SubSample *subSamples, size_t numSubSamples,
776 AString *errorDetailMsg) {
777 QueueGuard guard(mSync);
778 if (!guard.isRunning()) {
779 ALOGD("[%s] No more buffers should be queued at current state.", mName);
780 return -ENOSYS;
781 }
782
783 if (!hasCryptoOrDescrambler()) {
784 return -ENOSYS;
785 }
786 sp<EncryptedLinearBlockBuffer> encryptedBuffer((EncryptedLinearBlockBuffer *)buffer.get());
787
Sungtak Lee04b30352020-07-27 13:57:25 -0700788 std::shared_ptr<C2LinearBlock> block;
789 size_t allocSize = buffer->size();
790 size_t bufferSize = 0;
791 c2_status_t blockRes = C2_OK;
792 bool copied = false;
Arun Johnson7ba67072023-11-06 22:23:04 +0000793 ScopedTrace trace(ATRACE_TAG, android::base::StringPrintf(
794 "CCodecBufferChannel::decrypt(%s)", mName).c_str());
Sungtak Lee04b30352020-07-27 13:57:25 -0700795 if (mSendEncryptedInfoBuffer) {
796 static const C2MemoryUsage kDefaultReadWriteUsage{
797 C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE};
798 constexpr int kAllocGranule0 = 1024 * 64;
799 constexpr int kAllocGranule1 = 1024 * 1024;
800 std::shared_ptr<C2BlockPool> pool = mBlockPools.lock()->inputPool;
801 // round up encrypted sizes to limit fragmentation and encourage buffer reuse
802 if (allocSize <= kAllocGranule1) {
803 bufferSize = align(allocSize, kAllocGranule0);
804 } else {
805 bufferSize = align(allocSize, kAllocGranule1);
806 }
807 blockRes = pool->fetchLinearBlock(
808 bufferSize, kDefaultReadWriteUsage, &block);
809
810 if (blockRes == C2_OK) {
811 C2WriteView view = block->map().get();
812 if (view.error() == C2_OK && view.size() == bufferSize) {
813 copied = true;
814 // TODO: only copy clear sections
815 memcpy(view.data(), buffer->data(), allocSize);
816 }
817 }
818 }
819
820 if (!copied) {
821 block.reset();
822 }
823
Pawin Vongmasa36653902018-11-15 00:10:25 -0800824 ssize_t result = -1;
825 ssize_t codecDataOffset = 0;
Wonsik Kim557c88c2020-03-13 11:03:52 -0700826 if (numSubSamples == 1
827 && subSamples[0].mNumBytesOfClearData == 0
828 && subSamples[0].mNumBytesOfEncryptedData == 0) {
829 // We don't need to go through crypto or descrambler if the input is empty.
830 result = 0;
831 } else if (mCrypto != nullptr) {
Robert Shih895fba92019-07-16 16:29:44 -0700832 hardware::drm::V1_0::DestinationBuffer destination;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800833 if (secure) {
Robert Shih895fba92019-07-16 16:29:44 -0700834 destination.type = DrmBufferType::NATIVE_HANDLE;
835 destination.secureMemory = hidl_handle(encryptedBuffer->handle());
Pawin Vongmasa36653902018-11-15 00:10:25 -0800836 } else {
Robert Shih895fba92019-07-16 16:29:44 -0700837 destination.type = DrmBufferType::SHARED_MEMORY;
838 IMemoryToSharedBuffer(
839 mDecryptDestination, mHeapSeqNum, &destination.nonsecureMemory);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800840 }
Robert Shih895fba92019-07-16 16:29:44 -0700841 hardware::drm::V1_0::SharedBuffer source;
Pawin Vongmasa36653902018-11-15 00:10:25 -0800842 encryptedBuffer->fillSourceBuffer(&source);
843 result = mCrypto->decrypt(
844 key, iv, mode, pattern, source, buffer->offset(),
845 subSamples, numSubSamples, destination, errorDetailMsg);
846 if (result < 0) {
Wonsik Kim557c88c2020-03-13 11:03:52 -0700847 ALOGI("[%s] decrypt failed: result=%zd", mName, result);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800848 return result;
849 }
Robert Shih895fba92019-07-16 16:29:44 -0700850 if (destination.type == DrmBufferType::SHARED_MEMORY) {
Pawin Vongmasa36653902018-11-15 00:10:25 -0800851 encryptedBuffer->copyDecryptedContent(mDecryptDestination, result);
852 }
853 } else {
854 // Here we cast CryptoPlugin::SubSample to hardware::cas::native::V1_0::SubSample
855 // directly, the structure definitions should match as checked in DescramblerImpl.cpp.
856 hidl_vec<SubSample> hidlSubSamples;
857 hidlSubSamples.setToExternal((SubSample *)subSamples, numSubSamples, false /*own*/);
858
859 hardware::cas::native::V1_0::SharedBuffer srcBuffer;
860 encryptedBuffer->fillSourceBuffer(&srcBuffer);
861
862 DestinationBuffer dstBuffer;
863 if (secure) {
864 dstBuffer.type = BufferType::NATIVE_HANDLE;
865 dstBuffer.secureMemory = hidl_handle(encryptedBuffer->handle());
866 } else {
867 dstBuffer.type = BufferType::SHARED_MEMORY;
868 dstBuffer.nonsecureMemory = srcBuffer;
869 }
870
871 CasStatus status = CasStatus::OK;
872 hidl_string detailedError;
873 ScramblingControl sctrl = ScramblingControl::UNSCRAMBLED;
874
875 if (key != nullptr) {
876 sctrl = (ScramblingControl)key[0];
877 // Adjust for the PES offset
878 codecDataOffset = key[2] | (key[3] << 8);
879 }
880
881 auto returnVoid = mDescrambler->descramble(
882 sctrl,
883 hidlSubSamples,
884 srcBuffer,
885 0,
886 dstBuffer,
887 0,
888 [&status, &result, &detailedError] (
889 CasStatus _status, uint32_t _bytesWritten,
890 const hidl_string& _detailedError) {
891 status = _status;
892 result = (ssize_t)_bytesWritten;
893 detailedError = _detailedError;
894 });
895
896 if (!returnVoid.isOk() || status != CasStatus::OK || result < 0) {
897 ALOGI("[%s] descramble failed, trans=%s, status=%d, result=%zd",
898 mName, returnVoid.description().c_str(), status, result);
899 return UNKNOWN_ERROR;
900 }
901
902 if (result < codecDataOffset) {
903 ALOGD("invalid codec data offset: %zd, result %zd", codecDataOffset, result);
904 return BAD_VALUE;
905 }
906
907 ALOGV("[%s] descramble succeeded, %zd bytes", mName, result);
908
909 if (dstBuffer.type == BufferType::SHARED_MEMORY) {
910 encryptedBuffer->copyDecryptedContentFromMemory(result);
911 }
912 }
913
914 buffer->setRange(codecDataOffset, result - codecDataOffset);
Sungtak Lee04b30352020-07-27 13:57:25 -0700915
916 return queueInputBufferInternal(buffer, block, bufferSize);
Pawin Vongmasa36653902018-11-15 00:10:25 -0800917}
918
Arun Johnson564f3a92024-02-01 19:09:45 +0000919status_t CCodecBufferChannel::queueSecureInputBuffers(
920 const sp<MediaCodecBuffer> &buffer,
921 bool secure,
922 AString *errorDetailMsg) {
923 QueueGuard guard(mSync);
924 if (!guard.isRunning()) {
925 ALOGD("[%s] No more buffers should be queued at current state.", mName);
926 return -ENOSYS;
927 }
928
929 if (!hasCryptoOrDescrambler()) {
930 ALOGE("queueSecureInputBuffers requires a Crypto/descrambler Object");
931 return -ENOSYS;
932 }
933 sp<RefBase> obj;
934 CHECK(buffer->meta()->findObject("cryptoInfos", &obj));
935 sp<CryptoInfosWrapper> cryptoInfos{(CryptoInfosWrapper *)obj.get()};
936 CHECK(buffer->meta()->findObject("accessUnitInfo", &obj));
937 sp<BufferInfosWrapper> bufferInfos{(BufferInfosWrapper *)obj.get()};
938 if (secure || mCrypto == nullptr) {
939 if (cryptoInfos->value.size() != 1) {
940 ALOGE("Cannot decrypt multiple access units on native handles");
941 return -ENOSYS;
942 }
943 std::unique_ptr<CodecCryptoInfo> info = std::move(cryptoInfos->value[0]);
944 if (info == nullptr) {
945 ALOGE("Cannot decrypt, CryptoInfos are null");
946 return -ENOSYS;
947 }
948 return queueSecureInputBuffer(
949 buffer,
950 secure,
951 info->mKey,
952 info->mIv,
953 info->mMode,
954 info->mPattern,
955 info->mSubSamples,
956 info->mNumSubSamples,
957 errorDetailMsg);
958 }
959 sp<EncryptedLinearBlockBuffer> encryptedBuffer((EncryptedLinearBlockBuffer *)buffer.get());
960
961 std::shared_ptr<C2LinearBlock> block;
962 size_t allocSize = buffer->size();
963 size_t bufferSize = 0;
964 c2_status_t blockRes = C2_OK;
965 bool copied = false;
966 ScopedTrace trace(ATRACE_TAG, android::base::StringPrintf(
967 "CCodecBufferChannel::decrypt(%s)", mName).c_str());
968 if (mSendEncryptedInfoBuffer) {
969 static const C2MemoryUsage kDefaultReadWriteUsage{
970 C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE};
971 constexpr int kAllocGranule0 = 1024 * 64;
972 constexpr int kAllocGranule1 = 1024 * 1024;
973 std::shared_ptr<C2BlockPool> pool = mBlockPools.lock()->inputPool;
974 // round up encrypted sizes to limit fragmentation and encourage buffer reuse
975 if (allocSize <= kAllocGranule1) {
976 bufferSize = align(allocSize, kAllocGranule0);
977 } else {
978 bufferSize = align(allocSize, kAllocGranule1);
979 }
980 blockRes = pool->fetchLinearBlock(
981 bufferSize, kDefaultReadWriteUsage, &block);
982
983 if (blockRes == C2_OK) {
984 C2WriteView view = block->map().get();
985 if (view.error() == C2_OK && view.size() == bufferSize) {
986 copied = true;
987 // TODO: only copy clear sections
988 memcpy(view.data(), buffer->data(), allocSize);
989 }
990 }
991 }
992
993 if (!copied) {
994 block.reset();
995 }
996 // size of cryptoInfo and accessUnitInfo should be the same?
997 ssize_t result = -1;
Arun Johnson82174a12024-02-27 04:53:59 +0000998 size_t srcOffset = 0;
Arun Johnson564f3a92024-02-01 19:09:45 +0000999 size_t outBufferSize = 0;
1000 uint32_t cryptoInfoIdx = 0;
1001 {
1002 // scoped this block to enable destruction of mappedBlock
1003 std::unique_ptr<EncryptedLinearBlockBuffer::MappedBlock> mappedBlock = nullptr;
1004 hardware::drm::V1_0::DestinationBuffer destination;
1005 destination.type = DrmBufferType::SHARED_MEMORY;
1006 IMemoryToSharedBuffer(
1007 mDecryptDestination, mHeapSeqNum, &destination.nonsecureMemory);
1008 encryptedBuffer->getMappedBlock(&mappedBlock);
1009 hardware::drm::V1_0::SharedBuffer source;
1010 encryptedBuffer->fillSourceBuffer(&source);
Arun Johnson82174a12024-02-27 04:53:59 +00001011 srcOffset = source.offset;
Arun Johnson564f3a92024-02-01 19:09:45 +00001012 for (int i = 0 ; i < bufferInfos->value.size(); i++) {
1013 if (bufferInfos->value[i].mSize > 0) {
1014 std::unique_ptr<CodecCryptoInfo> info =
1015 std::move(cryptoInfos->value[cryptoInfoIdx++]);
1016 if (info->mNumSubSamples == 1
1017 && info->mSubSamples[0].mNumBytesOfClearData == 0
1018 && info->mSubSamples[0].mNumBytesOfEncryptedData == 0) {
1019 // no data so we only populate the bufferInfo
1020 result = 0;
1021 } else {
Arun Johnson82174a12024-02-27 04:53:59 +00001022 source.offset = srcOffset;
1023 source.size = bufferInfos->value[i].mSize;
Arun Johnson564f3a92024-02-01 19:09:45 +00001024 result = mCrypto->decrypt(
1025 (uint8_t*)info->mKey,
1026 (uint8_t*)info->mIv,
1027 info->mMode,
1028 info->mPattern,
1029 source,
Arun Johnson82174a12024-02-27 04:53:59 +00001030 buffer->offset(),
Arun Johnson564f3a92024-02-01 19:09:45 +00001031 info->mSubSamples,
1032 info->mNumSubSamples,
1033 destination,
1034 errorDetailMsg);
Arun Johnson82174a12024-02-27 04:53:59 +00001035 srcOffset += bufferInfos->value[i].mSize;
Arun Johnson564f3a92024-02-01 19:09:45 +00001036 if (result < 0) {
1037 ALOGI("[%s] decrypt failed: result=%zd", mName, result);
1038 return result;
1039 }
1040 if (destination.type == DrmBufferType::SHARED_MEMORY && mappedBlock) {
1041 mappedBlock->copyDecryptedContent(mDecryptDestination, result);
1042 }
1043 bufferInfos->value[i].mSize = result;
1044 outBufferSize += result;
1045 }
1046 }
1047 }
Arun Johnson82174a12024-02-27 04:53:59 +00001048 buffer->setRange(0, outBufferSize);
Arun Johnson564f3a92024-02-01 19:09:45 +00001049 }
1050 return queueInputBufferInternal(buffer, block, bufferSize);
1051}
1052
Pawin Vongmasa36653902018-11-15 00:10:25 -08001053void CCodecBufferChannel::feedInputBufferIfAvailable() {
1054 QueueGuard guard(mSync);
1055 if (!guard.isRunning()) {
1056 ALOGV("[%s] We're not running --- no input buffer reported", mName);
1057 return;
1058 }
1059 feedInputBufferIfAvailableInternal();
1060}
1061
1062void CCodecBufferChannel::feedInputBufferIfAvailableInternal() {
Taehwan Kimda0517d2020-09-16 17:29:37 +09001063 if (mInputMetEos) {
Wonsik Kimdf5dd142019-02-06 10:15:46 -08001064 return;
Pawin Vongmasac3c536d2020-06-12 04:00:04 -07001065 }
1066 {
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001067 Mutexed<Output>::Locked output(mOutput);
Pawin Vongmasac3c536d2020-06-12 04:00:04 -07001068 if (!output->buffers ||
1069 output->buffers->hasPending() ||
Wonsik Kim3722abc2023-05-17 13:26:31 -07001070 (!output->bounded && output->buffers->numActiveSlots() >= output->numSlots)) {
Wonsik Kimdf5dd142019-02-06 10:15:46 -08001071 return;
1072 }
1073 }
Wonsik Kimd4ba8462024-07-12 11:05:48 -07001074 if (android::media::codec::provider_->input_surface_throttle()) {
1075 Mutexed<std::shared_ptr<InputSurfaceWrapper>>::Locked inputSurface(mInputSurface);
1076 if ((*inputSurface) != nullptr) {
1077 (*inputSurface)->onInputBufferEmptied();
1078 }
Wonsik Kim1951d932024-05-23 22:59:00 +00001079 }
Wonsik Kim0487b782020-10-28 11:45:50 -07001080 size_t numActiveSlots = 0;
1081 while (!mPipelineWatcher.lock()->pipelineFull()) {
Pawin Vongmasa36653902018-11-15 00:10:25 -08001082 sp<MediaCodecBuffer> inBuffer;
1083 size_t index;
1084 {
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001085 Mutexed<Input>::Locked input(mInput);
Wonsik Kim0487b782020-10-28 11:45:50 -07001086 numActiveSlots = input->buffers->numActiveSlots();
1087 if (numActiveSlots >= input->numSlots) {
1088 break;
Wonsik Kimab34ed62019-01-31 15:28:46 -08001089 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001090 if (!input->buffers->requestNewBuffer(&index, &inBuffer)) {
Pawin Vongmasa36653902018-11-15 00:10:25 -08001091 ALOGV("[%s] no new buffer available", mName);
Pawin Vongmasa36653902018-11-15 00:10:25 -08001092 break;
1093 }
1094 }
1095 ALOGV("[%s] new input index = %zu [%p]", mName, index, inBuffer.get());
1096 mCallback->onInputBufferAvailable(index, inBuffer);
1097 }
Wonsik Kim0487b782020-10-28 11:45:50 -07001098 ALOGV("[%s] # active slots after feedInputBufferIfAvailable = %zu", mName, numActiveSlots);
Pawin Vongmasa36653902018-11-15 00:10:25 -08001099}
1100
1101status_t CCodecBufferChannel::renderOutputBuffer(
1102 const sp<MediaCodecBuffer> &buffer, int64_t timestampNs) {
Pawin Vongmasa8be93112018-12-11 14:01:42 -08001103 ALOGV("[%s] renderOutputBuffer: %p", mName, buffer.get());
Pawin Vongmasa36653902018-11-15 00:10:25 -08001104 std::shared_ptr<C2Buffer> c2Buffer;
Pawin Vongmasa8be93112018-12-11 14:01:42 -08001105 bool released = false;
Pawin Vongmasa36653902018-11-15 00:10:25 -08001106 {
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001107 Mutexed<Output>::Locked output(mOutput);
1108 if (output->buffers) {
1109 released = output->buffers->releaseBuffer(buffer, &c2Buffer);
Pawin Vongmasa36653902018-11-15 00:10:25 -08001110 }
1111 }
Pawin Vongmasa8be93112018-12-11 14:01:42 -08001112 // NOTE: some apps try to releaseOutputBuffer() with timestamp and/or render
1113 // set to true.
1114 sendOutputBuffers();
1115 // input buffer feeding may have been gated by pending output buffers
1116 feedInputBufferIfAvailable();
Pawin Vongmasa36653902018-11-15 00:10:25 -08001117 if (!c2Buffer) {
Pawin Vongmasa8be93112018-12-11 14:01:42 -08001118 if (released) {
Wonsik Kimf7529dd2019-04-18 17:35:53 -07001119 std::call_once(mRenderWarningFlag, [this] {
1120 ALOGW("[%s] The app is calling releaseOutputBuffer() with "
1121 "timestamp or render=true with non-video buffers. Apps should "
1122 "call releaseOutputBuffer() with render=false for those.",
1123 mName);
1124 });
Pawin Vongmasa8be93112018-12-11 14:01:42 -08001125 }
Pawin Vongmasa36653902018-11-15 00:10:25 -08001126 return INVALID_OPERATION;
1127 }
Pawin Vongmasa36653902018-11-15 00:10:25 -08001128
1129#if 0
1130 const std::vector<std::shared_ptr<const C2Info>> infoParams = c2Buffer->info();
1131 ALOGV("[%s] queuing gfx buffer with %zu infos", mName, infoParams.size());
1132 for (const std::shared_ptr<const C2Info> &info : infoParams) {
1133 AString res;
1134 for (size_t ix = 0; ix + 3 < info->size(); ix += 4) {
1135 if (ix) res.append(", ");
1136 res.append(*((int32_t*)info.get() + (ix / 4)));
1137 }
1138 ALOGV(" [%s]", res.c_str());
1139 }
1140#endif
1141 std::shared_ptr<const C2StreamRotationInfo::output> rotation =
1142 std::static_pointer_cast<const C2StreamRotationInfo::output>(
1143 c2Buffer->getInfo(C2StreamRotationInfo::output::PARAM_TYPE));
1144 bool flip = rotation && (rotation->flip & 1);
1145 uint32_t quarters = ((rotation ? rotation->value : 0) / 90) & 3;
Byeongjo Park25c3a3d2020-06-12 17:24:21 +09001146
1147 {
1148 Mutexed<OutputSurface>::Locked output(mOutputSurface);
1149 if (output->surface == nullptr) {
1150 ALOGI("[%s] cannot render buffer without surface", mName);
1151 return OK;
1152 }
1153 int64_t frameIndex;
1154 buffer->meta()->findInt64("frameIndex", &frameIndex);
1155 if (output->rotation.count(frameIndex) != 0) {
1156 auto it = output->rotation.find(frameIndex);
1157 quarters = (it->second / 90) & 3;
1158 output->rotation.erase(it);
1159 }
1160 }
1161
Pawin Vongmasa36653902018-11-15 00:10:25 -08001162 uint32_t transform = 0;
1163 switch (quarters) {
1164 case 0: // no rotation
1165 transform = flip ? HAL_TRANSFORM_FLIP_H : 0;
1166 break;
1167 case 1: // 90 degrees counter-clockwise
1168 transform = flip ? (HAL_TRANSFORM_FLIP_V | HAL_TRANSFORM_ROT_90)
1169 : HAL_TRANSFORM_ROT_270;
1170 break;
1171 case 2: // 180 degrees
1172 transform = flip ? HAL_TRANSFORM_FLIP_V : HAL_TRANSFORM_ROT_180;
1173 break;
1174 case 3: // 90 degrees clockwise
1175 transform = flip ? (HAL_TRANSFORM_FLIP_H | HAL_TRANSFORM_ROT_90)
1176 : HAL_TRANSFORM_ROT_90;
1177 break;
1178 }
1179
1180 std::shared_ptr<const C2StreamSurfaceScalingInfo::output> surfaceScaling =
1181 std::static_pointer_cast<const C2StreamSurfaceScalingInfo::output>(
1182 c2Buffer->getInfo(C2StreamSurfaceScalingInfo::output::PARAM_TYPE));
1183 uint32_t videoScalingMode = NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW;
1184 if (surfaceScaling) {
1185 videoScalingMode = surfaceScaling->value;
1186 }
1187
1188 // Use dataspace from format as it has the default aspects already applied
1189 android_dataspace_t dataSpace = HAL_DATASPACE_UNKNOWN; // this is 0
1190 (void)buffer->format()->findInt32("android._dataspace", (int32_t *)&dataSpace);
1191
1192 // HDR static info
1193 std::shared_ptr<const C2StreamHdrStaticInfo::output> hdrStaticInfo =
1194 std::static_pointer_cast<const C2StreamHdrStaticInfo::output>(
1195 c2Buffer->getInfo(C2StreamHdrStaticInfo::output::PARAM_TYPE));
1196
Pawin Vongmasa8be93112018-12-11 14:01:42 -08001197 // HDR10 plus info
1198 std::shared_ptr<const C2StreamHdr10PlusInfo::output> hdr10PlusInfo =
1199 std::static_pointer_cast<const C2StreamHdr10PlusInfo::output>(
1200 c2Buffer->getInfo(C2StreamHdr10PlusInfo::output::PARAM_TYPE));
Yichi Chen54be23c2020-06-15 14:30:53 +08001201 if (hdr10PlusInfo && hdr10PlusInfo->flexCount() == 0) {
1202 hdr10PlusInfo.reset();
1203 }
Pawin Vongmasa8be93112018-12-11 14:01:42 -08001204
Wonsik Kima79c5522022-01-18 16:29:24 -08001205 // HDR dynamic info
1206 std::shared_ptr<const C2StreamHdrDynamicMetadataInfo::output> hdrDynamicInfo =
1207 std::static_pointer_cast<const C2StreamHdrDynamicMetadataInfo::output>(
1208 c2Buffer->getInfo(C2StreamHdrDynamicMetadataInfo::output::PARAM_TYPE));
1209 // TODO: make this sticky & enable unset
1210 if (hdrDynamicInfo && hdrDynamicInfo->flexCount() == 0) {
1211 hdrDynamicInfo.reset();
1212 }
1213
1214 if (hdr10PlusInfo) {
1215 // C2StreamHdr10PlusInfo is deprecated; components should use
1216 // C2StreamHdrDynamicMetadataInfo
1217 // TODO: #metric
1218 if (hdrDynamicInfo) {
1219 // It is unexpected that C2StreamHdr10PlusInfo and
1220 // C2StreamHdrDynamicMetadataInfo is both present.
1221 // C2StreamHdrDynamicMetadataInfo takes priority.
1222 // TODO: #metric
1223 } else {
1224 std::shared_ptr<C2StreamHdrDynamicMetadataInfo::output> info =
1225 C2StreamHdrDynamicMetadataInfo::output::AllocShared(
1226 hdr10PlusInfo->flexCount(),
1227 0u,
1228 C2Config::HDR_DYNAMIC_METADATA_TYPE_SMPTE_2094_40);
1229 memcpy(info->m.data, hdr10PlusInfo->m.value, hdr10PlusInfo->flexCount());
1230 hdrDynamicInfo = info;
1231 }
1232 }
1233
Pawin Vongmasa36653902018-11-15 00:10:25 -08001234 std::vector<C2ConstGraphicBlock> blocks = c2Buffer->data().graphicBlocks();
1235 if (blocks.size() != 1u) {
1236 ALOGD("[%s] expected 1 graphic block, but got %zu", mName, blocks.size());
1237 return UNKNOWN_ERROR;
1238 }
1239 const C2ConstGraphicBlock &block = blocks.front();
Lubin Yin92427a52022-04-18 16:57:39 -07001240 C2Fence c2fence = block.fence();
1241 sp<Fence> fence = Fence::NO_FENCE;
1242 // TODO: it's not sufficient to just check isHW() and then construct android::fence from it.
1243 // Once C2Fence::type() is added, check the exact C2Fence type
1244 if (c2fence.isHW()) {
1245 int fenceFd = c2fence.fd();
1246 fence = sp<Fence>::make(fenceFd);
1247 if (!fence) {
1248 ALOGE("[%s] Failed to allocate a fence", mName);
1249 close(fenceFd);
1250 return NO_MEMORY;
1251 }
1252 }
Pawin Vongmasa36653902018-11-15 00:10:25 -08001253
1254 // TODO: revisit this after C2Fence implementation.
Brian Lindahl932bf602023-03-09 11:59:48 -07001255 IGraphicBufferProducer::QueueBufferInput qbi(
Pawin Vongmasa36653902018-11-15 00:10:25 -08001256 timestampNs,
1257 false, // droppable
1258 dataSpace,
1259 Rect(blocks.front().crop().left,
1260 blocks.front().crop().top,
1261 blocks.front().crop().right(),
1262 blocks.front().crop().bottom()),
1263 videoScalingMode,
1264 transform,
Lubin Yin92427a52022-04-18 16:57:39 -07001265 fence, 0);
Wonsik Kima79c5522022-01-18 16:29:24 -08001266 if (hdrStaticInfo || hdrDynamicInfo) {
Pawin Vongmasa36653902018-11-15 00:10:25 -08001267 HdrMetadata hdr;
Pawin Vongmasa8be93112018-12-11 14:01:42 -08001268 if (hdrStaticInfo) {
wenchangliuf3f92882020-05-14 00:02:01 +08001269 // If mastering max and min luminance fields are 0, do not use them.
1270 // It indicates the value may not be present in the stream.
1271 if (hdrStaticInfo->mastering.maxLuminance > 0.0f &&
1272 hdrStaticInfo->mastering.minLuminance > 0.0f) {
1273 struct android_smpte2086_metadata smpte2086_meta = {
1274 .displayPrimaryRed = {
1275 hdrStaticInfo->mastering.red.x, hdrStaticInfo->mastering.red.y
1276 },
1277 .displayPrimaryGreen = {
1278 hdrStaticInfo->mastering.green.x, hdrStaticInfo->mastering.green.y
1279 },
1280 .displayPrimaryBlue = {
1281 hdrStaticInfo->mastering.blue.x, hdrStaticInfo->mastering.blue.y
1282 },
1283 .whitePoint = {
1284 hdrStaticInfo->mastering.white.x, hdrStaticInfo->mastering.white.y
1285 },
1286 .maxLuminance = hdrStaticInfo->mastering.maxLuminance,
1287 .minLuminance = hdrStaticInfo->mastering.minLuminance,
1288 };
Yichi Chen54be23c2020-06-15 14:30:53 +08001289 hdr.validTypes |= HdrMetadata::SMPTE2086;
wenchangliuf3f92882020-05-14 00:02:01 +08001290 hdr.smpte2086 = smpte2086_meta;
1291 }
Chong Zhang3bb2a7f2020-04-21 10:35:12 -07001292 // If the content light level fields are 0, do not use them, it
1293 // indicates the value may not be present in the stream.
1294 if (hdrStaticInfo->maxCll > 0.0f && hdrStaticInfo->maxFall > 0.0f) {
1295 struct android_cta861_3_metadata cta861_meta = {
1296 .maxContentLightLevel = hdrStaticInfo->maxCll,
1297 .maxFrameAverageLightLevel = hdrStaticInfo->maxFall,
1298 };
1299 hdr.validTypes |= HdrMetadata::CTA861_3;
1300 hdr.cta8613 = cta861_meta;
1301 }
Taehwan Kim6b85f1e2022-04-07 17:41:44 +09001302
1303 // does not have valid info
1304 if (!(hdr.validTypes & (HdrMetadata::SMPTE2086 | HdrMetadata::CTA861_3))) {
1305 hdrStaticInfo.reset();
1306 }
Pawin Vongmasa8be93112018-12-11 14:01:42 -08001307 }
Wonsik Kima79c5522022-01-18 16:29:24 -08001308 if (hdrDynamicInfo
1309 && hdrDynamicInfo->m.type_ == C2Config::HDR_DYNAMIC_METADATA_TYPE_SMPTE_2094_40) {
Pawin Vongmasa8be93112018-12-11 14:01:42 -08001310 hdr.validTypes |= HdrMetadata::HDR10PLUS;
1311 hdr.hdr10plus.assign(
Wonsik Kima79c5522022-01-18 16:29:24 -08001312 hdrDynamicInfo->m.data,
1313 hdrDynamicInfo->m.data + hdrDynamicInfo->flexCount());
Pawin Vongmasa8be93112018-12-11 14:01:42 -08001314 }
Pawin Vongmasa36653902018-11-15 00:10:25 -08001315 qbi.setHdrMetadata(hdr);
1316 }
Hongguangfc1478a2022-07-20 22:56:06 -07001317 SetMetadataToGralloc4Handle(dataSpace, hdrStaticInfo, hdrDynamicInfo, block.handle());
1318
Brian Lindahl932bf602023-03-09 11:59:48 -07001319 qbi.setSurfaceDamage(Region::INVALID_REGION); // we don't have dirty regions
1320 qbi.getFrameTimestamps = true; // we need to know when a frame is rendered
1321 IGraphicBufferProducer::QueueBufferOutput qbo;
Pawin Vongmasa36653902018-11-15 00:10:25 -08001322 status_t result = mComponent->queueToOutputSurface(block, qbi, &qbo);
1323 if (result != OK) {
1324 ALOGI("[%s] queueBuffer failed: %d", mName, result);
Sungtak Lee47c018a2020-11-07 01:02:49 -08001325 if (result == NO_INIT) {
1326 mCCodecCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL);
1327 }
Pawin Vongmasa36653902018-11-15 00:10:25 -08001328 return result;
1329 }
Josh Hou8eddf4b2021-02-02 16:26:53 +08001330
1331 if(android::base::GetBoolProperty("debug.stagefright.fps", false)) {
1332 ALOGD("[%s] queue buffer successful", mName);
1333 } else {
1334 ALOGV("[%s] queue buffer successful", mName);
1335 }
Pawin Vongmasa36653902018-11-15 00:10:25 -08001336
1337 int64_t mediaTimeUs = 0;
1338 (void)buffer->meta()->findInt64("timeUs", &mediaTimeUs);
Brian Lindahld7967a92023-08-10 10:12:49 -06001339 if (mAreRenderMetricsEnabled && mIsSurfaceToDisplay) {
Brian Lindahl2048d492023-04-05 08:49:23 -06001340 trackReleasedFrame(qbo, mediaTimeUs, timestampNs);
1341 processRenderedFrames(qbo.frameTimestamps);
1342 } else {
1343 // When the surface is an intermediate surface, onFrameRendered is triggered immediately
1344 // when the frame is queued to the non-display surface
1345 mCCodecCallback->onOutputFramesRendered(mediaTimeUs, timestampNs);
1346 }
Pawin Vongmasa36653902018-11-15 00:10:25 -08001347
1348 return OK;
1349}
1350
Brian Lindahl932bf602023-03-09 11:59:48 -07001351void CCodecBufferChannel::initializeFrameTrackingFor(ANativeWindow * window) {
Brian Lindahl2048d492023-04-05 08:49:23 -06001352 mTrackedFrames.clear();
1353
1354 int isSurfaceToDisplay = 0;
1355 window->query(window, NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER, &isSurfaceToDisplay);
1356 mIsSurfaceToDisplay = isSurfaceToDisplay == 1;
1357 // No frame tracking is needed if we're not sending frames to the display
1358 if (!mIsSurfaceToDisplay) {
1359 // Return early so we don't call into SurfaceFlinger (requiring permissions)
1360 return;
1361 }
1362
Brian Lindahl932bf602023-03-09 11:59:48 -07001363 int hasPresentFenceTimes = 0;
1364 window->query(window, NATIVE_WINDOW_FRAME_TIMESTAMPS_SUPPORTS_PRESENT, &hasPresentFenceTimes);
1365 mHasPresentFenceTimes = hasPresentFenceTimes == 1;
Brian Lindahl119e0c22023-05-19 15:42:13 -06001366 if (!mHasPresentFenceTimes) {
Brian Lindahl932bf602023-03-09 11:59:48 -07001367 ALOGI("Using latch times for frame rendered signals - present fences not supported");
1368 }
Brian Lindahl932bf602023-03-09 11:59:48 -07001369}
1370
1371void CCodecBufferChannel::trackReleasedFrame(const IGraphicBufferProducer::QueueBufferOutput& qbo,
1372 int64_t mediaTimeUs, int64_t desiredRenderTimeNs) {
1373 // If the render time is earlier than now, then we're suggesting it should be rendered ASAP,
1374 // so track the frame as if the desired render time is now.
1375 int64_t nowNs = systemTime(SYSTEM_TIME_MONOTONIC);
1376 if (desiredRenderTimeNs < nowNs) {
1377 desiredRenderTimeNs = nowNs;
1378 }
Brian Lindahlc8bd9272023-08-28 09:42:43 -06001379
1380 // If the render time is more than a second from now, then pretend the frame is supposed to be
1381 // rendered immediately, because that's what SurfaceFlinger heuristics will do. This is a tight
1382 // coupling, but is really the only way to optimize away unnecessary present fence checks in
1383 // processRenderedFrames.
1384 if (desiredRenderTimeNs > nowNs + 1*1000*1000*1000LL) {
1385 desiredRenderTimeNs = nowNs;
1386 }
1387
Brian Lindahl932bf602023-03-09 11:59:48 -07001388 // We've just queued a frame to the surface, so keep track of it and later check to see if it is
1389 // actually rendered.
1390 TrackedFrame frame;
1391 frame.number = qbo.nextFrameNumber - 1;
1392 frame.mediaTimeUs = mediaTimeUs;
1393 frame.desiredRenderTimeNs = desiredRenderTimeNs;
1394 frame.latchTime = -1;
1395 frame.presentFence = nullptr;
1396 mTrackedFrames.push_back(frame);
1397}
1398
1399void CCodecBufferChannel::processRenderedFrames(const FrameEventHistoryDelta& deltas) {
1400 // Grab the latch times and present fences from the frame event deltas
1401 for (const auto& delta : deltas) {
1402 for (auto& frame : mTrackedFrames) {
1403 if (delta.getFrameNumber() == frame.number) {
1404 delta.getLatchTime(&frame.latchTime);
1405 delta.getDisplayPresentFence(&frame.presentFence);
1406 }
1407 }
1408 }
1409
1410 // Scan all frames and check to see if the frames that SHOULD have been rendered by now, have,
1411 // in fact, been rendered.
1412 int64_t nowNs = systemTime(SYSTEM_TIME_MONOTONIC);
1413 while (!mTrackedFrames.empty()) {
1414 TrackedFrame & frame = mTrackedFrames.front();
1415 // Frames that should have been rendered at least 100ms in the past are checked
1416 if (frame.desiredRenderTimeNs > nowNs - 100*1000*1000LL) {
1417 break;
1418 }
1419
1420 // If we don't have a render time by now, then consider the frame as dropped
1421 int64_t renderTimeNs = getRenderTimeNs(frame);
1422 if (renderTimeNs != -1) {
1423 mCCodecCallback->onOutputFramesRendered(frame.mediaTimeUs, renderTimeNs);
1424 }
1425 mTrackedFrames.pop_front();
1426 }
1427}
1428
1429int64_t CCodecBufferChannel::getRenderTimeNs(const TrackedFrame& frame) {
1430 // If the device doesn't have accurate present fence times, then use the latch time as a proxy
1431 if (!mHasPresentFenceTimes) {
1432 if (frame.latchTime == -1) {
1433 ALOGD("no latch time for frame %d", (int) frame.number);
1434 return -1;
1435 }
1436 return frame.latchTime;
1437 }
1438
1439 if (frame.presentFence == nullptr) {
1440 ALOGW("no present fence for frame %d", (int) frame.number);
1441 return -1;
1442 }
1443
1444 nsecs_t actualRenderTimeNs = frame.presentFence->getSignalTime();
1445
1446 if (actualRenderTimeNs == Fence::SIGNAL_TIME_INVALID) {
1447 ALOGW("invalid signal time for frame %d", (int) frame.number);
1448 return -1;
1449 }
1450
1451 if (actualRenderTimeNs == Fence::SIGNAL_TIME_PENDING) {
1452 ALOGD("present fence has not fired for frame %d", (int) frame.number);
1453 return -1;
1454 }
1455
1456 return actualRenderTimeNs;
1457}
1458
1459void CCodecBufferChannel::pollForRenderedBuffers() {
1460 FrameEventHistoryDelta delta;
1461 mComponent->pollForRenderedFrames(&delta);
1462 processRenderedFrames(delta);
1463}
1464
Sungtak Lee214ce612023-11-01 10:01:13 +00001465void CCodecBufferChannel::onBufferReleasedFromOutputSurface(uint32_t generation) {
Sungtak Lee6700cc92023-11-22 18:04:05 +00001466 // Note: Since this is called asynchronously from IProducerListener not
1467 // knowing the internal state of CCodec/CCodecBufferChannel,
1468 // prevent mComponent from being destroyed by holding the shared reference
1469 // during this interface being executed.
1470 std::shared_ptr<Codec2Client::Component> comp = mComponent;
1471 if (comp) {
1472 comp->onBufferReleasedFromOutputSurface(generation);
1473 }
Sungtak Lee214ce612023-11-01 10:01:13 +00001474}
1475
Sungtak Lee1720e4c2024-07-31 21:15:26 +00001476void CCodecBufferChannel::onBufferAttachedToOutputSurface(uint32_t generation) {
1477 // Note: Since this is called asynchronously from IProducerListener not
1478 // knowing the internal state of CCodec/CCodecBufferChannel,
1479 // prevent mComponent from being destroyed by holding the shared reference
1480 // during this interface being executed.
1481 std::shared_ptr<Codec2Client::Component> comp = mComponent;
1482 if (comp) {
1483 comp->onBufferAttachedToOutputSurface(generation);
1484 }
1485}
1486
Pawin Vongmasa36653902018-11-15 00:10:25 -08001487status_t CCodecBufferChannel::discardBuffer(const sp<MediaCodecBuffer> &buffer) {
1488 ALOGV("[%s] discardBuffer: %p", mName, buffer.get());
1489 bool released = false;
1490 {
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001491 Mutexed<Input>::Locked input(mInput);
1492 if (input->buffers && input->buffers->releaseBuffer(buffer, nullptr, true)) {
Pawin Vongmasa36653902018-11-15 00:10:25 -08001493 released = true;
Pawin Vongmasa36653902018-11-15 00:10:25 -08001494 }
1495 }
1496 {
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001497 Mutexed<Output>::Locked output(mOutput);
1498 if (output->buffers && output->buffers->releaseBuffer(buffer, nullptr)) {
Pawin Vongmasa36653902018-11-15 00:10:25 -08001499 released = true;
1500 }
1501 }
1502 if (released) {
Pawin Vongmasa36653902018-11-15 00:10:25 -08001503 sendOutputBuffers();
Pawin Vongmasa8be93112018-12-11 14:01:42 -08001504 feedInputBufferIfAvailable();
Pawin Vongmasa36653902018-11-15 00:10:25 -08001505 } else {
1506 ALOGD("[%s] MediaCodec discarded an unknown buffer", mName);
1507 }
1508 return OK;
1509}
1510
1511void CCodecBufferChannel::getInputBufferArray(Vector<sp<MediaCodecBuffer>> *array) {
1512 array->clear();
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001513 Mutexed<Input>::Locked input(mInput);
Pawin Vongmasa36653902018-11-15 00:10:25 -08001514
Arun Johnson3ab32cd2022-06-10 18:58:01 +00001515 if (!input->buffers) {
1516 ALOGE("getInputBufferArray: No Input Buffers allocated");
1517 return;
1518 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001519 if (!input->buffers->isArrayMode()) {
1520 input->buffers = input->buffers->toArrayMode(input->numSlots);
Pawin Vongmasa36653902018-11-15 00:10:25 -08001521 }
1522
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001523 input->buffers->getArray(array);
Pawin Vongmasa36653902018-11-15 00:10:25 -08001524}
1525
1526void CCodecBufferChannel::getOutputBufferArray(Vector<sp<MediaCodecBuffer>> *array) {
1527 array->clear();
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001528 Mutexed<Output>::Locked output(mOutput);
Arun Johnson3ab32cd2022-06-10 18:58:01 +00001529 if (!output->buffers) {
1530 ALOGE("getOutputBufferArray: No Output Buffers allocated");
1531 return;
1532 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001533 if (!output->buffers->isArrayMode()) {
1534 output->buffers = output->buffers->toArrayMode(output->numSlots);
Pawin Vongmasa36653902018-11-15 00:10:25 -08001535 }
1536
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001537 output->buffers->getArray(array);
Pawin Vongmasa36653902018-11-15 00:10:25 -08001538}
1539
1540status_t CCodecBufferChannel::start(
Wonsik Kimfb7a7672019-12-27 17:13:33 -08001541 const sp<AMessage> &inputFormat,
1542 const sp<AMessage> &outputFormat,
1543 bool buffersBoundToCodec) {
Pawin Vongmasa36653902018-11-15 00:10:25 -08001544 C2StreamBufferTypeSetting::input iStreamFormat(0u);
1545 C2StreamBufferTypeSetting::output oStreamFormat(0u);
Wonsik Kime1104ca2020-11-24 15:01:33 -08001546 C2ComponentKindSetting kind;
Pawin Vongmasa36653902018-11-15 00:10:25 -08001547 C2PortReorderBufferDepthTuning::output reorderDepth;
1548 C2PortReorderKeySetting::output reorderKey;
Wonsik Kim078b58e2019-01-09 15:08:06 -08001549 C2PortActualDelayTuning::input inputDelay(0);
1550 C2PortActualDelayTuning::output outputDelay(0);
1551 C2ActualPipelineDelayTuning pipelineDelay(0);
Sungtak Lee04b30352020-07-27 13:57:25 -07001552 C2SecureModeTuning secureMode(C2Config::SM_UNPROTECTED);
Wonsik Kim078b58e2019-01-09 15:08:06 -08001553
Pawin Vongmasa36653902018-11-15 00:10:25 -08001554 c2_status_t err = mComponent->query(
1555 {
1556 &iStreamFormat,
1557 &oStreamFormat,
Wonsik Kime1104ca2020-11-24 15:01:33 -08001558 &kind,
Pawin Vongmasa36653902018-11-15 00:10:25 -08001559 &reorderDepth,
1560 &reorderKey,
Wonsik Kim078b58e2019-01-09 15:08:06 -08001561 &inputDelay,
1562 &pipelineDelay,
1563 &outputDelay,
Sungtak Lee04b30352020-07-27 13:57:25 -07001564 &secureMode,
Pawin Vongmasa36653902018-11-15 00:10:25 -08001565 },
1566 {},
1567 C2_DONT_BLOCK,
1568 nullptr);
1569 if (err == C2_BAD_INDEX) {
Wonsik Kime1104ca2020-11-24 15:01:33 -08001570 if (!iStreamFormat || !oStreamFormat || !kind) {
Pawin Vongmasa36653902018-11-15 00:10:25 -08001571 return UNKNOWN_ERROR;
1572 }
1573 } else if (err != C2_OK) {
1574 return UNKNOWN_ERROR;
1575 }
1576
Wonsik Kim4fa4f2b2019-02-13 11:02:58 -08001577 uint32_t inputDelayValue = inputDelay ? inputDelay.value : 0;
1578 uint32_t pipelineDelayValue = pipelineDelay ? pipelineDelay.value : 0;
1579 uint32_t outputDelayValue = outputDelay ? outputDelay.value : 0;
1580
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001581 size_t numInputSlots = inputDelayValue + pipelineDelayValue + kSmoothnessFactor;
1582 size_t numOutputSlots = outputDelayValue + kSmoothnessFactor;
Wonsik Kim078b58e2019-01-09 15:08:06 -08001583
Pawin Vongmasa36653902018-11-15 00:10:25 -08001584 // TODO: get this from input format
1585 bool secure = mComponent->getName().find(".secure") != std::string::npos;
1586
Sungtak Lee04b30352020-07-27 13:57:25 -07001587 // secure mode is a static parameter (shall not change in the executing state)
1588 mSendEncryptedInfoBuffer = secureMode.value == C2Config::SM_READ_PROTECTED_WITH_ENCRYPTED;
1589
Pawin Vongmasa36653902018-11-15 00:10:25 -08001590 std::shared_ptr<C2AllocatorStore> allocatorStore = GetCodec2PlatformAllocatorStore();
Pin-chih Linaa18ea52019-11-19 18:48:50 +08001591 int poolMask = GetCodec2PoolMask();
1592 C2PlatformAllocatorStore::id_t preferredLinearId = GetPreferredLinearAllocatorId(poolMask);
Pawin Vongmasa36653902018-11-15 00:10:25 -08001593
1594 if (inputFormat != nullptr) {
Lajos Molnar3bb81cd2019-02-20 15:10:30 -08001595 bool graphic = (iStreamFormat.value == C2BufferData::GRAPHIC);
Wonsik Kime1104ca2020-11-24 15:01:33 -08001596 bool audioEncoder = !graphic && (kind.value == C2Component::KIND_ENCODER);
Wonsik Kimffb889a2020-05-28 11:32:25 -07001597 C2Config::api_feature_t apiFeatures = C2Config::api_feature_t(
1598 API_REFLECTION |
1599 API_VALUES |
1600 API_CURRENT_VALUES |
1601 API_DEPENDENCY |
1602 API_SAME_INPUT_BUFFER);
Wonsik Kime1104ca2020-11-24 15:01:33 -08001603 C2StreamAudioFrameSizeInfo::input encoderFrameSize(0u);
1604 C2StreamSampleRateInfo::input sampleRate(0u);
1605 C2StreamChannelCountInfo::input channelCount(0u);
1606 C2StreamPcmEncodingInfo::input pcmEncoding(0u);
Pawin Vongmasa36653902018-11-15 00:10:25 -08001607 std::shared_ptr<C2BlockPool> pool;
1608 {
1609 Mutexed<BlockPools>::Locked pools(mBlockPools);
1610
1611 // set default allocator ID.
1612 pools->inputAllocatorId = (graphic) ? C2PlatformAllocatorStore::GRALLOC
Pin-chih Linaa18ea52019-11-19 18:48:50 +08001613 : preferredLinearId;
Pawin Vongmasa36653902018-11-15 00:10:25 -08001614
1615 // query C2PortAllocatorsTuning::input from component. If an allocator ID is obtained
1616 // from component, create the input block pool with given ID. Otherwise, use default IDs.
1617 std::vector<std::unique_ptr<C2Param>> params;
Wonsik Kimffb889a2020-05-28 11:32:25 -07001618 C2ApiFeaturesSetting featuresSetting{apiFeatures};
Wonsik Kime1104ca2020-11-24 15:01:33 -08001619 std::vector<C2Param *> stackParams({&featuresSetting});
1620 if (audioEncoder) {
1621 stackParams.push_back(&encoderFrameSize);
1622 stackParams.push_back(&sampleRate);
1623 stackParams.push_back(&channelCount);
1624 stackParams.push_back(&pcmEncoding);
1625 } else {
1626 encoderFrameSize.invalidate();
1627 sampleRate.invalidate();
1628 channelCount.invalidate();
1629 pcmEncoding.invalidate();
1630 }
1631 err = mComponent->query(stackParams,
Pawin Vongmasa36653902018-11-15 00:10:25 -08001632 { C2PortAllocatorsTuning::input::PARAM_TYPE },
1633 C2_DONT_BLOCK,
1634 &params);
1635 if ((err != C2_OK && err != C2_BAD_INDEX) || params.size() != 1) {
1636 ALOGD("[%s] Query input allocators returned %zu params => %s (%u)",
1637 mName, params.size(), asString(err), err);
Wonsik Kimffb889a2020-05-28 11:32:25 -07001638 } else if (params.size() == 1) {
Pawin Vongmasa36653902018-11-15 00:10:25 -08001639 C2PortAllocatorsTuning::input *inputAllocators =
1640 C2PortAllocatorsTuning::input::From(params[0].get());
1641 if (inputAllocators && inputAllocators->flexCount() > 0) {
1642 std::shared_ptr<C2Allocator> allocator;
1643 // verify allocator IDs and resolve default allocator
1644 allocatorStore->fetchAllocator(inputAllocators->m.values[0], &allocator);
1645 if (allocator) {
1646 pools->inputAllocatorId = allocator->getId();
1647 } else {
1648 ALOGD("[%s] component requested invalid input allocator ID %u",
1649 mName, inputAllocators->m.values[0]);
1650 }
1651 }
1652 }
Wonsik Kimffb889a2020-05-28 11:32:25 -07001653 if (featuresSetting) {
1654 apiFeatures = featuresSetting.value;
1655 }
Pawin Vongmasa36653902018-11-15 00:10:25 -08001656
1657 // TODO: use C2Component wrapper to associate this pool with ourselves
1658 if ((poolMask >> pools->inputAllocatorId) & 1) {
1659 err = CreateCodec2BlockPool(pools->inputAllocatorId, nullptr, &pool);
1660 ALOGD("[%s] Created input block pool with allocatorID %u => poolID %llu - %s (%d)",
1661 mName, pools->inputAllocatorId,
1662 (unsigned long long)(pool ? pool->getLocalId() : 111000111),
1663 asString(err), err);
1664 } else {
1665 err = C2_NOT_FOUND;
1666 }
1667 if (err != C2_OK) {
1668 C2BlockPool::local_id_t inputPoolId =
1669 graphic ? C2BlockPool::BASIC_GRAPHIC : C2BlockPool::BASIC_LINEAR;
1670 err = GetCodec2BlockPool(inputPoolId, nullptr, &pool);
1671 ALOGD("[%s] Using basic input block pool with poolID %llu => got %llu - %s (%d)",
1672 mName, (unsigned long long)inputPoolId,
1673 (unsigned long long)(pool ? pool->getLocalId() : 111000111),
1674 asString(err), err);
1675 if (err != C2_OK) {
1676 return NO_MEMORY;
1677 }
1678 }
1679 pools->inputPool = pool;
1680 }
1681
Wonsik Kim51051262018-11-28 13:59:05 -08001682 bool forceArrayMode = false;
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001683 Mutexed<Input>::Locked input(mInput);
Wonsik Kimbdffead2019-07-01 12:00:07 -07001684 input->inputDelay = inputDelayValue;
1685 input->pipelineDelay = pipelineDelayValue;
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001686 input->numSlots = numInputSlots;
1687 input->extraBuffers.flush();
1688 input->numExtraSlots = 0u;
Wonsik Kim6b2c8be2021-09-28 05:11:04 -07001689 input->lastFlushIndex = mFrameIndex.load(std::memory_order_relaxed);
Wonsik Kime1104ca2020-11-24 15:01:33 -08001690 if (audioEncoder && encoderFrameSize && sampleRate && channelCount) {
1691 input->frameReassembler.init(
1692 pool,
1693 {C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE},
1694 encoderFrameSize.value,
1695 sampleRate.value,
1696 channelCount.value,
1697 pcmEncoding ? pcmEncoding.value : C2Config::PCM_16);
1698 }
Wonsik Kimffb889a2020-05-28 11:32:25 -07001699 bool conforming = (apiFeatures & API_SAME_INPUT_BUFFER);
1700 // For encrypted content, framework decrypts source buffer (ashmem) into
1701 // C2Buffers. Thus non-conforming codecs can process these.
Wonsik Kime1104ca2020-11-24 15:01:33 -08001702 if (!buffersBoundToCodec
1703 && !input->frameReassembler
1704 && (hasCryptoOrDescrambler() || conforming)) {
Wonsik Kimfb7a7672019-12-27 17:13:33 -08001705 input->buffers.reset(new SlotInputBuffers(mName));
1706 } else if (graphic) {
Wonsik Kimd4ba8462024-07-12 11:05:48 -07001707 if (mInputSurface.lock()->get()) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001708 input->buffers.reset(new DummyInputBuffers(mName));
Pawin Vongmasa36653902018-11-15 00:10:25 -08001709 } else if (mMetaMode == MODE_ANW) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001710 input->buffers.reset(new GraphicMetadataInputBuffers(mName));
Wonsik Kim1221fd12019-07-12 12:52:05 -07001711 // This is to ensure buffers do not get released prematurely.
1712 // TODO: handle this without going into array mode
1713 forceArrayMode = true;
Pawin Vongmasa36653902018-11-15 00:10:25 -08001714 } else {
Wonsik Kim41d83432020-04-27 16:40:49 -07001715 input->buffers.reset(new GraphicInputBuffers(mName));
Pawin Vongmasa36653902018-11-15 00:10:25 -08001716 }
1717 } else {
1718 if (hasCryptoOrDescrambler()) {
1719 int32_t capacity = kLinearBufferSize;
1720 (void)inputFormat->findInt32(KEY_MAX_INPUT_SIZE, &capacity);
1721 if ((size_t)capacity > kMaxLinearBufferSize) {
1722 ALOGD("client requested %d, capped to %zu", capacity, kMaxLinearBufferSize);
1723 capacity = kMaxLinearBufferSize;
1724 }
1725 if (mDealer == nullptr) {
1726 mDealer = new MemoryDealer(
1727 align(capacity, MemoryDealer::getAllocationAlignment())
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001728 * (numInputSlots + 1),
Pawin Vongmasa36653902018-11-15 00:10:25 -08001729 "EncryptedLinearInputBuffers");
1730 mDecryptDestination = mDealer->allocate((size_t)capacity);
1731 }
1732 if (mCrypto != nullptr && mHeapSeqNum < 0) {
Robert Shih895fba92019-07-16 16:29:44 -07001733 sp<HidlMemory> heap = fromHeap(mDealer->getMemoryHeap());
1734 mHeapSeqNum = mCrypto->setHeap(heap);
Pawin Vongmasa36653902018-11-15 00:10:25 -08001735 } else {
1736 mHeapSeqNum = -1;
1737 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001738 input->buffers.reset(new EncryptedLinearInputBuffers(
Wonsik Kim078b58e2019-01-09 15:08:06 -08001739 secure, mDealer, mCrypto, mHeapSeqNum, (size_t)capacity,
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001740 numInputSlots, mName));
Wonsik Kim51051262018-11-28 13:59:05 -08001741 forceArrayMode = true;
Pawin Vongmasa36653902018-11-15 00:10:25 -08001742 } else {
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001743 input->buffers.reset(new LinearInputBuffers(mName));
Pawin Vongmasa36653902018-11-15 00:10:25 -08001744 }
1745 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001746 input->buffers->setFormat(inputFormat);
Pawin Vongmasa36653902018-11-15 00:10:25 -08001747
1748 if (err == C2_OK) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001749 input->buffers->setPool(pool);
Pawin Vongmasa36653902018-11-15 00:10:25 -08001750 } else {
1751 // TODO: error
1752 }
Wonsik Kim51051262018-11-28 13:59:05 -08001753
1754 if (forceArrayMode) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001755 input->buffers = input->buffers->toArrayMode(numInputSlots);
Wonsik Kim51051262018-11-28 13:59:05 -08001756 }
Pawin Vongmasa36653902018-11-15 00:10:25 -08001757 }
1758
1759 if (outputFormat != nullptr) {
1760 sp<IGraphicBufferProducer> outputSurface;
1761 uint32_t outputGeneration;
Sungtak Leea714f112021-03-16 05:40:03 -07001762 int maxDequeueCount = 0;
Pawin Vongmasa36653902018-11-15 00:10:25 -08001763 {
1764 Mutexed<OutputSurface>::Locked output(mOutputSurface);
Sungtak Leea714f112021-03-16 05:40:03 -07001765 maxDequeueCount = output->maxDequeueBuffers = numOutputSlots +
Wonsik Kim3a692e62023-05-19 15:37:22 -07001766 reorderDepth.value + mRenderingDepth;
Pawin Vongmasa36653902018-11-15 00:10:25 -08001767 outputSurface = output->surface ?
1768 output->surface->getIGraphicBufferProducer() : nullptr;
Wonsik Kimf5e5c832019-02-21 11:36:05 -08001769 if (outputSurface) {
1770 output->surface->setMaxDequeuedBufferCount(output->maxDequeueBuffers);
1771 }
Pawin Vongmasa36653902018-11-15 00:10:25 -08001772 outputGeneration = output->generation;
1773 }
1774
Lajos Molnar3bb81cd2019-02-20 15:10:30 -08001775 bool graphic = (oStreamFormat.value == C2BufferData::GRAPHIC);
Pawin Vongmasa36653902018-11-15 00:10:25 -08001776 C2BlockPool::local_id_t outputPoolId_;
David Stevensc3fbb282021-01-18 18:11:20 +09001777 C2BlockPool::local_id_t prevOutputPoolId;
Pawin Vongmasa36653902018-11-15 00:10:25 -08001778
1779 {
1780 Mutexed<BlockPools>::Locked pools(mBlockPools);
1781
David Stevensc3fbb282021-01-18 18:11:20 +09001782 prevOutputPoolId = pools->outputPoolId;
1783
Pawin Vongmasa36653902018-11-15 00:10:25 -08001784 // set default allocator ID.
1785 pools->outputAllocatorId = (graphic) ? C2PlatformAllocatorStore::GRALLOC
Pin-chih Linaa18ea52019-11-19 18:48:50 +08001786 : preferredLinearId;
Pawin Vongmasa36653902018-11-15 00:10:25 -08001787
1788 // query C2PortAllocatorsTuning::output from component, or use default allocator if
1789 // unsuccessful.
1790 std::vector<std::unique_ptr<C2Param>> params;
1791 err = mComponent->query({ },
1792 { C2PortAllocatorsTuning::output::PARAM_TYPE },
1793 C2_DONT_BLOCK,
1794 &params);
1795 if ((err != C2_OK && err != C2_BAD_INDEX) || params.size() != 1) {
1796 ALOGD("[%s] Query output allocators returned %zu params => %s (%u)",
1797 mName, params.size(), asString(err), err);
1798 } else if (err == C2_OK && params.size() == 1) {
1799 C2PortAllocatorsTuning::output *outputAllocators =
1800 C2PortAllocatorsTuning::output::From(params[0].get());
1801 if (outputAllocators && outputAllocators->flexCount() > 0) {
1802 std::shared_ptr<C2Allocator> allocator;
1803 // verify allocator IDs and resolve default allocator
1804 allocatorStore->fetchAllocator(outputAllocators->m.values[0], &allocator);
1805 if (allocator) {
1806 pools->outputAllocatorId = allocator->getId();
1807 } else {
1808 ALOGD("[%s] component requested invalid output allocator ID %u",
1809 mName, outputAllocators->m.values[0]);
1810 }
1811 }
1812 }
1813
1814 // use bufferqueue if outputting to a surface.
1815 // query C2PortSurfaceAllocatorTuning::output from component, or use default allocator
1816 // if unsuccessful.
1817 if (outputSurface) {
1818 params.clear();
1819 err = mComponent->query({ },
1820 { C2PortSurfaceAllocatorTuning::output::PARAM_TYPE },
1821 C2_DONT_BLOCK,
1822 &params);
1823 if ((err != C2_OK && err != C2_BAD_INDEX) || params.size() != 1) {
1824 ALOGD("[%s] Query output surface allocator returned %zu params => %s (%u)",
1825 mName, params.size(), asString(err), err);
1826 } else if (err == C2_OK && params.size() == 1) {
1827 C2PortSurfaceAllocatorTuning::output *surfaceAllocator =
1828 C2PortSurfaceAllocatorTuning::output::From(params[0].get());
1829 if (surfaceAllocator) {
1830 std::shared_ptr<C2Allocator> allocator;
1831 // verify allocator IDs and resolve default allocator
1832 allocatorStore->fetchAllocator(surfaceAllocator->value, &allocator);
1833 if (allocator) {
1834 pools->outputAllocatorId = allocator->getId();
1835 } else {
1836 ALOGD("[%s] component requested invalid surface output allocator ID %u",
1837 mName, surfaceAllocator->value);
1838 err = C2_BAD_VALUE;
1839 }
1840 }
1841 }
1842 if (pools->outputAllocatorId == C2PlatformAllocatorStore::GRALLOC
1843 && err != C2_OK
1844 && ((poolMask >> C2PlatformAllocatorStore::BUFFERQUEUE) & 1)) {
1845 pools->outputAllocatorId = C2PlatformAllocatorStore::BUFFERQUEUE;
1846 }
1847 }
1848
1849 if ((poolMask >> pools->outputAllocatorId) & 1) {
1850 err = mComponent->createBlockPool(
1851 pools->outputAllocatorId, &pools->outputPoolId, &pools->outputPoolIntf);
1852 ALOGI("[%s] Created output block pool with allocatorID %u => poolID %llu - %s",
1853 mName, pools->outputAllocatorId,
1854 (unsigned long long)pools->outputPoolId,
1855 asString(err));
1856 } else {
1857 err = C2_NOT_FOUND;
1858 }
1859 if (err != C2_OK) {
1860 // use basic pool instead
1861 pools->outputPoolId =
1862 graphic ? C2BlockPool::BASIC_GRAPHIC : C2BlockPool::BASIC_LINEAR;
1863 }
1864
1865 // Configure output block pool ID as parameter C2PortBlockPoolsTuning::output to
1866 // component.
1867 std::unique_ptr<C2PortBlockPoolsTuning::output> poolIdsTuning =
1868 C2PortBlockPoolsTuning::output::AllocUnique({ pools->outputPoolId });
1869
1870 std::vector<std::unique_ptr<C2SettingResult>> failures;
1871 err = mComponent->config({ poolIdsTuning.get() }, C2_MAY_BLOCK, &failures);
1872 ALOGD("[%s] Configured output block pool ids %llu => %s",
1873 mName, (unsigned long long)poolIdsTuning->m.values[0], asString(err));
1874 outputPoolId_ = pools->outputPoolId;
1875 }
1876
David Stevensc3fbb282021-01-18 18:11:20 +09001877 if (prevOutputPoolId != C2BlockPool::BASIC_LINEAR
1878 && prevOutputPoolId != C2BlockPool::BASIC_GRAPHIC) {
1879 c2_status_t err = mComponent->destroyBlockPool(prevOutputPoolId);
1880 if (err != C2_OK) {
1881 ALOGW("Failed to clean up previous block pool %llu - %s (%d)\n",
1882 (unsigned long long) prevOutputPoolId, asString(err), err);
1883 }
1884 }
1885
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001886 Mutexed<Output>::Locked output(mOutput);
Wonsik Kimbdffead2019-07-01 12:00:07 -07001887 output->outputDelay = outputDelayValue;
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001888 output->numSlots = numOutputSlots;
Wonsik Kim3722abc2023-05-17 13:26:31 -07001889 output->bounded = bool(outputSurface);
Pawin Vongmasa36653902018-11-15 00:10:25 -08001890 if (graphic) {
Wonsik Kimfb7a7672019-12-27 17:13:33 -08001891 if (outputSurface || !buffersBoundToCodec) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001892 output->buffers.reset(new GraphicOutputBuffers(mName));
Pawin Vongmasa36653902018-11-15 00:10:25 -08001893 } else {
Wonsik Kim41d83432020-04-27 16:40:49 -07001894 output->buffers.reset(new RawGraphicOutputBuffers(mName));
Pawin Vongmasa36653902018-11-15 00:10:25 -08001895 }
1896 } else {
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001897 output->buffers.reset(new LinearOutputBuffers(mName));
Pawin Vongmasa36653902018-11-15 00:10:25 -08001898 }
Wonsik Kime4716c02020-02-28 10:42:21 -08001899 output->buffers->setFormat(outputFormat);
Pawin Vongmasa36653902018-11-15 00:10:25 -08001900
Pawin Vongmasa9b906982020-04-11 05:07:15 -07001901 output->buffers->clearStash();
1902 if (reorderDepth) {
1903 output->buffers->setReorderDepth(reorderDepth.value);
1904 }
1905 if (reorderKey) {
1906 output->buffers->setReorderKey(reorderKey.value);
1907 }
Pawin Vongmasa36653902018-11-15 00:10:25 -08001908
1909 // Try to set output surface to created block pool if given.
1910 if (outputSurface) {
1911 mComponent->setOutputSurface(
1912 outputPoolId_,
1913 outputSurface,
Sungtak Leedb14cba2021-04-10 00:50:23 -07001914 outputGeneration,
1915 maxDequeueCount);
Lajos Molnar78aa7c92021-02-18 21:39:01 -08001916 } else {
1917 // configure CPU read consumer usage
1918 C2StreamUsageTuning::output outputUsage{0u, C2MemoryUsage::CPU_READ};
1919 std::vector<std::unique_ptr<C2SettingResult>> failures;
1920 err = mComponent->config({ &outputUsage }, C2_MAY_BLOCK, &failures);
1921 // do not print error message for now as most components may not yet
1922 // support this setting
1923 ALOGD_IF(err != C2_BAD_INDEX, "[%s] Configured output usage [%#llx]",
1924 mName, (long long)outputUsage.value);
Pawin Vongmasa36653902018-11-15 00:10:25 -08001925 }
1926
Wonsik Kim8ab25aa2019-06-24 16:37:37 -07001927 if (oStreamFormat.value == C2BufferData::LINEAR) {
Wonsik Kim58713302020-01-29 22:25:23 -08001928 if (buffersBoundToCodec) {
1929 // WORKAROUND: if we're using early CSD workaround we convert to
1930 // array mode, to appease apps assuming the output
1931 // buffers to be of the same size.
1932 output->buffers = output->buffers->toArrayMode(numOutputSlots);
1933 }
Pawin Vongmasa36653902018-11-15 00:10:25 -08001934
1935 int32_t channelCount;
1936 int32_t sampleRate;
1937 if (outputFormat->findInt32(KEY_CHANNEL_COUNT, &channelCount)
1938 && outputFormat->findInt32(KEY_SAMPLE_RATE, &sampleRate)) {
1939 int32_t delay = 0;
1940 int32_t padding = 0;;
1941 if (!outputFormat->findInt32("encoder-delay", &delay)) {
1942 delay = 0;
1943 }
1944 if (!outputFormat->findInt32("encoder-padding", &padding)) {
1945 padding = 0;
1946 }
1947 if (delay || padding) {
Arun Johnson52d323e2024-01-05 21:16:56 +00001948 // We need write access to the buffers, so turn them into array mode.
1949 // TODO: b/321930152 - define SkipCutOutputBuffers that takes output from
1950 // component, runs it through SkipCutBuffer and allocate local buffer to be
1951 // used by fwk. Make initSkipCutBuffer() return OutputBuffers similar to
1952 // toArrayMode().
1953 if (!output->buffers->isArrayMode()) {
1954 output->buffers = output->buffers->toArrayMode(numOutputSlots);
1955 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001956 output->buffers->initSkipCutBuffer(delay, padding, sampleRate, channelCount);
Pawin Vongmasa36653902018-11-15 00:10:25 -08001957 }
1958 }
1959 }
Wonsik Kimec585c32021-10-01 01:11:00 -07001960
1961 int32_t tunneled = 0;
1962 if (!outputFormat->findInt32("android._tunneled", &tunneled)) {
1963 tunneled = 0;
1964 }
1965 mTunneled = (tunneled != 0);
Pawin Vongmasa36653902018-11-15 00:10:25 -08001966 }
1967
1968 // Set up pipeline control. This has to be done after mInputBuffers and
1969 // mOutputBuffers are initialized to make sure that lingering callbacks
1970 // about buffers from the previous generation do not interfere with the
1971 // newly initialized pipeline capacity.
1972
Wonsik Kim62545252021-01-20 11:25:41 -08001973 if (inputFormat || outputFormat) {
Wonsik Kimab34ed62019-01-31 15:28:46 -08001974 Mutexed<PipelineWatcher>::Locked watcher(mPipelineWatcher);
Wonsik Kim4fa4f2b2019-02-13 11:02:58 -08001975 watcher->inputDelay(inputDelayValue)
1976 .pipelineDelay(pipelineDelayValue)
1977 .outputDelay(outputDelayValue)
Houxiang Dai0b573282023-03-11 18:31:56 +08001978 .smoothnessFactor(kSmoothnessFactor)
1979 .tunneled(mTunneled);
Wonsik Kimab34ed62019-01-31 15:28:46 -08001980 watcher->flush();
1981 }
Pawin Vongmasa36653902018-11-15 00:10:25 -08001982
1983 mInputMetEos = false;
1984 mSync.start();
1985 return OK;
1986}
1987
Wonsik Kim34b28b42022-05-20 15:49:32 -07001988status_t CCodecBufferChannel::prepareInitialInputBuffers(
Arun Johnson326166e2023-07-28 19:11:52 +00001989 std::map<size_t, sp<MediaCodecBuffer>> *clientInputBuffers, bool retry) {
Wonsik Kimd4ba8462024-07-12 11:05:48 -07001990 if (mInputSurface.lock()->get()) {
Pawin Vongmasa36653902018-11-15 00:10:25 -08001991 return OK;
1992 }
1993
Wonsik Kim34b28b42022-05-20 15:49:32 -07001994 size_t numInputSlots = mInput.lock()->numSlots;
Arun Johnson326166e2023-07-28 19:11:52 +00001995 int retryCount = 1;
1996 for (; clientInputBuffers->empty() && retryCount >= 0; retryCount--) {
1997 {
1998 Mutexed<Input>::Locked input(mInput);
1999 while (clientInputBuffers->size() < numInputSlots) {
2000 size_t index;
2001 sp<MediaCodecBuffer> buffer;
2002 if (!input->buffers->requestNewBuffer(&index, &buffer)) {
2003 break;
2004 }
2005 clientInputBuffers->emplace(index, buffer);
Wonsik Kim34b28b42022-05-20 15:49:32 -07002006 }
Arun Johnson326166e2023-07-28 19:11:52 +00002007 }
2008 if (!retry || (retryCount <= 0)) {
2009 break;
2010 }
2011 if (clientInputBuffers->empty()) {
2012 // wait: buffer may be in transit from component.
2013 std::this_thread::sleep_for(std::chrono::milliseconds(4));
Wonsik Kim34b28b42022-05-20 15:49:32 -07002014 }
2015 }
2016 if (clientInputBuffers->empty()) {
2017 ALOGW("[%s] start: cannot allocate memory at all", mName);
2018 return NO_MEMORY;
2019 } else if (clientInputBuffers->size() < numInputSlots) {
2020 ALOGD("[%s] start: cannot allocate memory for all slots, "
2021 "only %zu buffers allocated",
2022 mName, clientInputBuffers->size());
2023 } else {
2024 ALOGV("[%s] %zu initial input buffers available",
2025 mName, clientInputBuffers->size());
2026 }
2027 return OK;
2028}
2029
2030status_t CCodecBufferChannel::requestInitialInputBuffers(
2031 std::map<size_t, sp<MediaCodecBuffer>> &&clientInputBuffers) {
Lajos Molnar3bb81cd2019-02-20 15:10:30 -08002032 C2StreamBufferTypeSetting::output oStreamFormat(0u);
Wonsik Kim8ab25aa2019-06-24 16:37:37 -07002033 C2PrependHeaderModeSetting prepend(PREPEND_HEADER_TO_NONE);
2034 c2_status_t err = mComponent->query({ &oStreamFormat, &prepend }, {}, C2_DONT_BLOCK, nullptr);
2035 if (err != C2_OK && err != C2_BAD_INDEX) {
Pawin Vongmasa36653902018-11-15 00:10:25 -08002036 return UNKNOWN_ERROR;
2037 }
Pawin Vongmasae7bb8612020-06-04 06:15:22 -07002038
Wonsik Kim5ebfcb22021-01-05 18:58:15 -08002039 std::list<std::unique_ptr<C2Work>> flushedConfigs;
2040 mFlushedConfigs.lock()->swap(flushedConfigs);
2041 if (!flushedConfigs.empty()) {
Wonsik Kim92df7e42021-11-04 16:02:03 -07002042 {
2043 Mutexed<PipelineWatcher>::Locked watcher(mPipelineWatcher);
2044 PipelineWatcher::Clock::time_point now = PipelineWatcher::Clock::now();
2045 for (const std::unique_ptr<C2Work> &work : flushedConfigs) {
2046 watcher->onWorkQueued(
2047 work->input.ordinal.frameIndex.peeku(),
2048 std::vector(work->input.buffers),
2049 now);
2050 }
2051 }
Wonsik Kim5ebfcb22021-01-05 18:58:15 -08002052 err = mComponent->queue(&flushedConfigs);
2053 if (err != C2_OK) {
2054 ALOGW("[%s] Error while queueing a flushed config", mName);
2055 return UNKNOWN_ERROR;
Pawin Vongmasa36653902018-11-15 00:10:25 -08002056 }
2057 }
Wonsik Kim5ebfcb22021-01-05 18:58:15 -08002058 if (oStreamFormat.value == C2BufferData::LINEAR &&
Wonsik Kim34b28b42022-05-20 15:49:32 -07002059 (!prepend || prepend.value == PREPEND_HEADER_TO_NONE) &&
2060 !clientInputBuffers.empty()) {
2061 size_t minIndex = clientInputBuffers.begin()->first;
2062 sp<MediaCodecBuffer> minBuffer = clientInputBuffers.begin()->second;
2063 for (const auto &[index, buffer] : clientInputBuffers) {
2064 if (minBuffer->capacity() > buffer->capacity()) {
2065 minIndex = index;
2066 minBuffer = buffer;
2067 }
2068 }
Wonsik Kim5ebfcb22021-01-05 18:58:15 -08002069 // WORKAROUND: Some apps expect CSD available without queueing
2070 // any input. Queue an empty buffer to get the CSD.
Wonsik Kim34b28b42022-05-20 15:49:32 -07002071 minBuffer->setRange(0, 0);
2072 minBuffer->meta()->clear();
2073 minBuffer->meta()->setInt64("timeUs", 0);
2074 if (queueInputBufferInternal(minBuffer) != OK) {
Wonsik Kim5ebfcb22021-01-05 18:58:15 -08002075 ALOGW("[%s] Error while queueing an empty buffer to get CSD",
2076 mName);
2077 return UNKNOWN_ERROR;
2078 }
Wonsik Kim34b28b42022-05-20 15:49:32 -07002079 clientInputBuffers.erase(minIndex);
Wonsik Kim5ebfcb22021-01-05 18:58:15 -08002080 }
Pawin Vongmasae7bb8612020-06-04 06:15:22 -07002081
Wonsik Kim34b28b42022-05-20 15:49:32 -07002082 for (const auto &[index, buffer] : clientInputBuffers) {
2083 mCallback->onInputBufferAvailable(index, buffer);
Pawin Vongmasa36653902018-11-15 00:10:25 -08002084 }
Pawin Vongmasae7bb8612020-06-04 06:15:22 -07002085
Pawin Vongmasa36653902018-11-15 00:10:25 -08002086 return OK;
2087}
2088
2089void CCodecBufferChannel::stop() {
2090 mSync.stop();
2091 mFirstValidFrameIndex = mFrameIndex.load(std::memory_order_relaxed);
Harish Mahendrakar38a99c22024-02-26 20:28:05 +05302092 mInfoBuffers.clear();
Pawin Vongmasa36653902018-11-15 00:10:25 -08002093}
2094
Sungtak Lee99144332023-01-26 11:03:14 +00002095void CCodecBufferChannel::stopUseOutputSurface(bool pushBlankBuffer) {
2096 sp<Surface> surface = mOutputSurface.lock()->surface;
2097 if (surface) {
Sungtak Leed964e2e2022-07-30 08:43:58 +00002098 C2BlockPool::local_id_t outputPoolId;
2099 {
2100 Mutexed<BlockPools>::Locked pools(mBlockPools);
2101 outputPoolId = pools->outputPoolId;
2102 }
2103 if (mComponent) mComponent->stopUsingOutputSurface(outputPoolId);
Sungtak Lee99144332023-01-26 11:03:14 +00002104
2105 if (pushBlankBuffer) {
2106 sp<ANativeWindow> anw = static_cast<ANativeWindow *>(surface.get());
2107 if (anw) {
2108 pushBlankBuffersToNativeWindow(anw.get());
2109 }
2110 }
Sungtak Leed964e2e2022-07-30 08:43:58 +00002111 }
2112}
2113
Wonsik Kim936a89c2020-05-08 16:07:50 -07002114void CCodecBufferChannel::reset() {
2115 stop();
Wonsik Kimd4ba8462024-07-12 11:05:48 -07002116 mInputSurface.lock()->reset();
Wonsik Kim62545252021-01-20 11:25:41 -08002117 mPipelineWatcher.lock()->flush();
Wonsik Kim936a89c2020-05-08 16:07:50 -07002118 {
2119 Mutexed<Input>::Locked input(mInput);
2120 input->buffers.reset(new DummyInputBuffers(""));
Wonsik Kima2e3cdd2020-05-20 15:14:42 -07002121 input->extraBuffers.flush();
Wonsik Kim936a89c2020-05-08 16:07:50 -07002122 }
2123 {
2124 Mutexed<Output>::Locked output(mOutput);
2125 output->buffers.reset();
2126 }
Brian Lindahl932bf602023-03-09 11:59:48 -07002127 // reset the frames that are being tracked for onFrameRendered callbacks
2128 mTrackedFrames.clear();
Wonsik Kim936a89c2020-05-08 16:07:50 -07002129}
2130
2131void CCodecBufferChannel::release() {
Harish Mahendrakar38a99c22024-02-26 20:28:05 +05302132 mInfoBuffers.clear();
Wonsik Kim936a89c2020-05-08 16:07:50 -07002133 mComponent.reset();
2134 mInputAllocator.reset();
2135 mOutputSurface.lock()->surface.clear();
2136 {
2137 Mutexed<BlockPools>::Locked blockPools{mBlockPools};
2138 blockPools->inputPool.reset();
2139 blockPools->outputPoolIntf.reset();
2140 }
Wonsik Kima2e3cdd2020-05-20 15:14:42 -07002141 setCrypto(nullptr);
2142 setDescrambler(nullptr);
Wonsik Kim936a89c2020-05-08 16:07:50 -07002143}
2144
Pawin Vongmasa36653902018-11-15 00:10:25 -08002145void CCodecBufferChannel::flush(const std::list<std::unique_ptr<C2Work>> &flushedWork) {
2146 ALOGV("[%s] flush", mName);
Wonsik Kim5ebfcb22021-01-05 18:58:15 -08002147 std::list<std::unique_ptr<C2Work>> configs;
Wonsik Kim6b2c8be2021-09-28 05:11:04 -07002148 mInput.lock()->lastFlushIndex = mFrameIndex.load(std::memory_order_relaxed);
Wonsik Kim92df7e42021-11-04 16:02:03 -07002149 {
2150 Mutexed<PipelineWatcher>::Locked watcher(mPipelineWatcher);
2151 for (const std::unique_ptr<C2Work> &work : flushedWork) {
2152 uint64_t frameIndex = work->input.ordinal.frameIndex.peeku();
2153 if (!(work->input.flags & C2FrameData::FLAG_CODEC_CONFIG)) {
2154 watcher->onWorkDone(frameIndex);
2155 continue;
2156 }
2157 if (work->input.buffers.empty()
2158 || work->input.buffers.front() == nullptr
2159 || work->input.buffers.front()->data().linearBlocks().empty()) {
2160 ALOGD("[%s] no linear codec config data found", mName);
2161 watcher->onWorkDone(frameIndex);
2162 continue;
2163 }
2164 std::unique_ptr<C2Work> copy(new C2Work);
2165 copy->input.flags = C2FrameData::flags_t(
2166 work->input.flags | C2FrameData::FLAG_DROP_FRAME);
2167 copy->input.ordinal = work->input.ordinal;
2168 copy->input.ordinal.frameIndex = mFrameIndex++;
2169 for (size_t i = 0; i < work->input.buffers.size(); ++i) {
2170 copy->input.buffers.push_back(watcher->onInputBufferReleased(frameIndex, i));
2171 }
2172 for (const std::unique_ptr<C2Param> &param : work->input.configUpdate) {
2173 copy->input.configUpdate.push_back(C2Param::Copy(*param));
2174 }
2175 copy->input.infoBuffers.insert(
2176 copy->input.infoBuffers.begin(),
2177 work->input.infoBuffers.begin(),
2178 work->input.infoBuffers.end());
2179 copy->worklets.emplace_back(new C2Worklet);
2180 configs.push_back(std::move(copy));
2181 watcher->onWorkDone(frameIndex);
2182 ALOGV("[%s] stashed flushed codec config data", mName);
Pawin Vongmasa36653902018-11-15 00:10:25 -08002183 }
2184 }
Wonsik Kim5ebfcb22021-01-05 18:58:15 -08002185 mFlushedConfigs.lock()->swap(configs);
Pawin Vongmasa36653902018-11-15 00:10:25 -08002186 {
Wonsik Kim5ecf3832019-04-18 10:28:58 -07002187 Mutexed<Input>::Locked input(mInput);
2188 input->buffers->flush();
2189 input->extraBuffers.flush();
Pawin Vongmasa36653902018-11-15 00:10:25 -08002190 }
2191 {
Wonsik Kim5ecf3832019-04-18 10:28:58 -07002192 Mutexed<Output>::Locked output(mOutput);
Wonsik Kim936a89c2020-05-08 16:07:50 -07002193 if (output->buffers) {
2194 output->buffers->flush(flushedWork);
Pawin Vongmasa9b906982020-04-11 05:07:15 -07002195 output->buffers->flushStash();
Wonsik Kim936a89c2020-05-08 16:07:50 -07002196 }
Pawin Vongmasa36653902018-11-15 00:10:25 -08002197 }
Harish Mahendrakar38a99c22024-02-26 20:28:05 +05302198 mInfoBuffers.clear();
Pawin Vongmasa36653902018-11-15 00:10:25 -08002199}
2200
2201void CCodecBufferChannel::onWorkDone(
2202 std::unique_ptr<C2Work> work, const sp<AMessage> &outputFormat,
Wonsik Kimab34ed62019-01-31 15:28:46 -08002203 const C2StreamInitDataInfo::output *initData) {
Pawin Vongmasa36653902018-11-15 00:10:25 -08002204 if (handleWork(std::move(work), outputFormat, initData)) {
Pawin Vongmasa36653902018-11-15 00:10:25 -08002205 feedInputBufferIfAvailable();
2206 }
2207}
2208
2209void CCodecBufferChannel::onInputBufferDone(
Wonsik Kimab34ed62019-01-31 15:28:46 -08002210 uint64_t frameIndex, size_t arrayIndex) {
Wonsik Kimd4ba8462024-07-12 11:05:48 -07002211 if (mInputSurface.lock()->get()) {
Pawin Vongmasa8e2cfb52019-05-15 05:20:52 -07002212 return;
2213 }
Wonsik Kimab34ed62019-01-31 15:28:46 -08002214 std::shared_ptr<C2Buffer> buffer =
2215 mPipelineWatcher.lock()->onInputBufferReleased(frameIndex, arrayIndex);
Wonsik Kim6b2c8be2021-09-28 05:11:04 -07002216 bool newInputSlotAvailable = false;
Pawin Vongmasa36653902018-11-15 00:10:25 -08002217 {
Wonsik Kim5ecf3832019-04-18 10:28:58 -07002218 Mutexed<Input>::Locked input(mInput);
Wonsik Kim6b2c8be2021-09-28 05:11:04 -07002219 if (input->lastFlushIndex >= frameIndex) {
2220 ALOGD("[%s] Ignoring stale input buffer done callback: "
2221 "last flush index = %lld, frameIndex = %lld",
2222 mName, input->lastFlushIndex.peekll(), (long long)frameIndex);
2223 } else {
2224 newInputSlotAvailable = input->buffers->expireComponentBuffer(buffer);
2225 if (!newInputSlotAvailable) {
2226 (void)input->extraBuffers.expireComponentBuffer(buffer);
2227 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -07002228 }
Pawin Vongmasa36653902018-11-15 00:10:25 -08002229 }
2230 if (newInputSlotAvailable) {
2231 feedInputBufferIfAvailable();
2232 }
2233}
2234
2235bool CCodecBufferChannel::handleWork(
2236 std::unique_ptr<C2Work> work,
2237 const sp<AMessage> &outputFormat,
2238 const C2StreamInitDataInfo::output *initData) {
Wonsik Kim936a89c2020-05-08 16:07:50 -07002239 {
Wonsik Kima4e049d2020-04-28 19:42:23 +00002240 Mutexed<Output>::Locked output(mOutput);
Wonsik Kim936a89c2020-05-08 16:07:50 -07002241 if (!output->buffers) {
2242 return false;
2243 }
Wonsik Kime75a5da2020-02-14 17:29:03 -08002244 }
2245
Pawin Vongmasa9b906982020-04-11 05:07:15 -07002246 // Whether the output buffer should be reported to the client or not.
2247 bool notifyClient = false;
2248
2249 if (work->result == C2_OK){
2250 notifyClient = true;
2251 } else if (work->result == C2_NOT_FOUND) {
2252 ALOGD("[%s] flushed work; ignored.", mName);
2253 } else {
2254 // C2_OK and C2_NOT_FOUND are the only results that we accept for processing
2255 // the config update.
2256 ALOGD("[%s] work failed to complete: %d", mName, work->result);
2257 mCCodecCallback->onError(work->result, ACTION_CODE_FATAL);
2258 return false;
2259 }
2260
2261 if ((work->input.ordinal.frameIndex -
2262 mFirstValidFrameIndex.load()).peek() < 0) {
Pawin Vongmasa36653902018-11-15 00:10:25 -08002263 // Discard frames from previous generation.
2264 ALOGD("[%s] Discard frames from previous generation.", mName);
Pawin Vongmasa9b906982020-04-11 05:07:15 -07002265 notifyClient = false;
Pawin Vongmasa36653902018-11-15 00:10:25 -08002266 }
2267
Wonsik Kimd4ba8462024-07-12 11:05:48 -07002268 bool hasInputSurface = (mInputSurface.lock()->get() != nullptr);
2269 if (!hasInputSurface && (work->worklets.size() != 1u
Pawin Vongmasa36653902018-11-15 00:10:25 -08002270 || !work->worklets.front()
Pawin Vongmasa9b906982020-04-11 05:07:15 -07002271 || !(work->worklets.front()->output.flags &
2272 C2FrameData::FLAG_INCOMPLETE))) {
2273 mPipelineWatcher.lock()->onWorkDone(
2274 work->input.ordinal.frameIndex.peeku());
Pawin Vongmasa36653902018-11-15 00:10:25 -08002275 }
2276
2277 // NOTE: MediaCodec usage supposedly have only one worklet
2278 if (work->worklets.size() != 1u) {
2279 ALOGI("[%s] onWorkDone: incorrect number of worklets: %zu",
2280 mName, work->worklets.size());
2281 mCCodecCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL);
2282 return false;
2283 }
2284
2285 const std::unique_ptr<C2Worklet> &worklet = work->worklets.front();
2286
2287 std::shared_ptr<C2Buffer> buffer;
2288 // NOTE: MediaCodec usage supposedly have only one output stream.
2289 if (worklet->output.buffers.size() > 1u) {
2290 ALOGI("[%s] onWorkDone: incorrect number of output buffers: %zu",
2291 mName, worklet->output.buffers.size());
2292 mCCodecCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL);
2293 return false;
2294 } else if (worklet->output.buffers.size() == 1u) {
2295 buffer = worklet->output.buffers[0];
2296 if (!buffer) {
2297 ALOGD("[%s] onWorkDone: nullptr found in buffers; ignored.", mName);
2298 }
2299 }
2300
Wonsik Kim3dedf682021-05-03 10:57:09 -07002301 std::optional<uint32_t> newInputDelay, newPipelineDelay, newOutputDelay, newReorderDepth;
2302 std::optional<C2Config::ordinal_key_t> newReorderKey;
Wonsik Kim315e40a2020-09-09 14:11:50 -07002303 bool needMaxDequeueBufferCountUpdate = false;
Pawin Vongmasa36653902018-11-15 00:10:25 -08002304 while (!worklet->output.configUpdate.empty()) {
2305 std::unique_ptr<C2Param> param;
2306 worklet->output.configUpdate.back().swap(param);
2307 worklet->output.configUpdate.pop_back();
2308 switch (param->coreIndex().coreIndex()) {
2309 case C2PortReorderBufferDepthTuning::CORE_INDEX: {
2310 C2PortReorderBufferDepthTuning::output reorderDepth;
2311 if (reorderDepth.updateFrom(*param)) {
Pawin Vongmasa36653902018-11-15 00:10:25 -08002312 ALOGV("[%s] onWorkDone: updated reorder depth to %u",
2313 mName, reorderDepth.value);
Wonsik Kim3dedf682021-05-03 10:57:09 -07002314 newReorderDepth = reorderDepth.value;
Wonsik Kim315e40a2020-09-09 14:11:50 -07002315 needMaxDequeueBufferCountUpdate = true;
Pawin Vongmasa36653902018-11-15 00:10:25 -08002316 } else {
Pawin Vongmasa9b906982020-04-11 05:07:15 -07002317 ALOGD("[%s] onWorkDone: failed to read reorder depth",
2318 mName);
Pawin Vongmasa36653902018-11-15 00:10:25 -08002319 }
2320 break;
2321 }
2322 case C2PortReorderKeySetting::CORE_INDEX: {
2323 C2PortReorderKeySetting::output reorderKey;
2324 if (reorderKey.updateFrom(*param)) {
Wonsik Kim3dedf682021-05-03 10:57:09 -07002325 newReorderKey = reorderKey.value;
Pawin Vongmasa36653902018-11-15 00:10:25 -08002326 ALOGV("[%s] onWorkDone: updated reorder key to %u",
2327 mName, reorderKey.value);
2328 } else {
2329 ALOGD("[%s] onWorkDone: failed to read reorder key", mName);
2330 }
2331 break;
2332 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -07002333 case C2PortActualDelayTuning::CORE_INDEX: {
2334 if (param->isGlobal()) {
2335 C2ActualPipelineDelayTuning pipelineDelay;
2336 if (pipelineDelay.updateFrom(*param)) {
2337 ALOGV("[%s] onWorkDone: updating pipeline delay %u",
2338 mName, pipelineDelay.value);
2339 newPipelineDelay = pipelineDelay.value;
Pawin Vongmasa9b906982020-04-11 05:07:15 -07002340 (void)mPipelineWatcher.lock()->pipelineDelay(
2341 pipelineDelay.value);
Wonsik Kim5ecf3832019-04-18 10:28:58 -07002342 }
2343 }
2344 if (param->forInput()) {
2345 C2PortActualDelayTuning::input inputDelay;
2346 if (inputDelay.updateFrom(*param)) {
2347 ALOGV("[%s] onWorkDone: updating input delay %u",
2348 mName, inputDelay.value);
2349 newInputDelay = inputDelay.value;
Pawin Vongmasa9b906982020-04-11 05:07:15 -07002350 (void)mPipelineWatcher.lock()->inputDelay(
2351 inputDelay.value);
Wonsik Kim5ecf3832019-04-18 10:28:58 -07002352 }
2353 }
2354 if (param->forOutput()) {
2355 C2PortActualDelayTuning::output outputDelay;
2356 if (outputDelay.updateFrom(*param)) {
2357 ALOGV("[%s] onWorkDone: updating output delay %u",
2358 mName, outputDelay.value);
Wonsik Kim315e40a2020-09-09 14:11:50 -07002359 (void)mPipelineWatcher.lock()->outputDelay(outputDelay.value);
Wonsik Kim3dedf682021-05-03 10:57:09 -07002360 newOutputDelay = outputDelay.value;
Wonsik Kim315e40a2020-09-09 14:11:50 -07002361 needMaxDequeueBufferCountUpdate = true;
Wonsik Kim5ecf3832019-04-18 10:28:58 -07002362
Wonsik Kim5ecf3832019-04-18 10:28:58 -07002363 }
2364 }
2365 break;
2366 }
ted.sunb1fbfdb2020-06-23 14:03:41 +08002367 case C2PortTunnelSystemTime::CORE_INDEX: {
2368 C2PortTunnelSystemTime::output frameRenderTime;
2369 if (frameRenderTime.updateFrom(*param)) {
2370 ALOGV("[%s] onWorkDone: frame rendered (sys:%lld ns, media:%lld us)",
2371 mName, (long long)frameRenderTime.value,
2372 (long long)worklet->output.ordinal.timestamp.peekll());
2373 mCCodecCallback->onOutputFramesRendered(
2374 worklet->output.ordinal.timestamp.peek(), frameRenderTime.value);
2375 }
2376 break;
2377 }
Guillaume Chelfi867d4dd2021-07-01 18:38:45 +02002378 case C2StreamTunnelHoldRender::CORE_INDEX: {
2379 C2StreamTunnelHoldRender::output firstTunnelFrameHoldRender;
2380 if (!(worklet->output.flags & C2FrameData::FLAG_INCOMPLETE)) break;
2381 if (!firstTunnelFrameHoldRender.updateFrom(*param)) break;
2382 if (firstTunnelFrameHoldRender.value != C2_TRUE) break;
2383 ALOGV("[%s] onWorkDone: first tunnel frame ready", mName);
2384 mCCodecCallback->onFirstTunnelFrameReady();
2385 break;
2386 }
Pawin Vongmasa36653902018-11-15 00:10:25 -08002387 default:
2388 ALOGV("[%s] onWorkDone: unrecognized config update (%08X)",
2389 mName, param->index());
2390 break;
2391 }
2392 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -07002393 if (newInputDelay || newPipelineDelay) {
2394 Mutexed<Input>::Locked input(mInput);
2395 size_t newNumSlots =
2396 newInputDelay.value_or(input->inputDelay) +
2397 newPipelineDelay.value_or(input->pipelineDelay) +
2398 kSmoothnessFactor;
Xu Lai5732cab2023-03-16 19:50:18 +08002399 input->inputDelay = newInputDelay.value_or(input->inputDelay);
Wonsik Kim5ecf3832019-04-18 10:28:58 -07002400 if (input->buffers->isArrayMode()) {
2401 if (input->numSlots >= newNumSlots) {
2402 input->numExtraSlots = 0;
2403 } else {
2404 input->numExtraSlots = newNumSlots - input->numSlots;
2405 }
2406 ALOGV("[%s] onWorkDone: updated number of extra slots to %zu (input array mode)",
2407 mName, input->numExtraSlots);
2408 } else {
2409 input->numSlots = newNumSlots;
2410 }
2411 }
Wonsik Kim3dedf682021-05-03 10:57:09 -07002412 size_t numOutputSlots = 0;
2413 uint32_t reorderDepth = 0;
2414 bool outputBuffersChanged = false;
2415 if (newReorderKey || newReorderDepth || needMaxDequeueBufferCountUpdate) {
2416 Mutexed<Output>::Locked output(mOutput);
2417 if (!output->buffers) {
2418 return false;
Wonsik Kim315e40a2020-09-09 14:11:50 -07002419 }
Wonsik Kim3dedf682021-05-03 10:57:09 -07002420 numOutputSlots = output->numSlots;
2421 if (newReorderKey) {
2422 output->buffers->setReorderKey(newReorderKey.value());
2423 }
2424 if (newReorderDepth) {
2425 output->buffers->setReorderDepth(newReorderDepth.value());
2426 }
2427 reorderDepth = output->buffers->getReorderDepth();
2428 if (newOutputDelay) {
2429 output->outputDelay = newOutputDelay.value();
2430 numOutputSlots = newOutputDelay.value() + kSmoothnessFactor;
2431 if (output->numSlots < numOutputSlots) {
2432 output->numSlots = numOutputSlots;
2433 if (output->buffers->isArrayMode()) {
2434 OutputBuffersArray *array =
2435 (OutputBuffersArray *)output->buffers.get();
2436 ALOGV("[%s] onWorkDone: growing output buffer array to %zu",
2437 mName, numOutputSlots);
2438 array->grow(numOutputSlots);
2439 outputBuffersChanged = true;
2440 }
2441 }
2442 }
2443 numOutputSlots = output->numSlots;
2444 }
2445 if (outputBuffersChanged) {
2446 mCCodecCallback->onOutputBuffersChanged();
2447 }
2448 if (needMaxDequeueBufferCountUpdate) {
Wonsik Kim84f439f2021-05-03 10:57:09 -07002449 int maxDequeueCount = 0;
Sungtak Leea714f112021-03-16 05:40:03 -07002450 {
2451 Mutexed<OutputSurface>::Locked output(mOutputSurface);
2452 maxDequeueCount = output->maxDequeueBuffers =
Wonsik Kim3a692e62023-05-19 15:37:22 -07002453 numOutputSlots + reorderDepth + mRenderingDepth;
Sungtak Leea714f112021-03-16 05:40:03 -07002454 if (output->surface) {
2455 output->surface->setMaxDequeuedBufferCount(output->maxDequeueBuffers);
2456 }
2457 }
2458 if (maxDequeueCount > 0) {
2459 mComponent->setOutputSurfaceMaxDequeueCount(maxDequeueCount);
Wonsik Kim315e40a2020-09-09 14:11:50 -07002460 }
2461 }
Pawin Vongmasa36653902018-11-15 00:10:25 -08002462
Pawin Vongmasa36653902018-11-15 00:10:25 -08002463 int32_t flags = 0;
2464 if (worklet->output.flags & C2FrameData::FLAG_END_OF_STREAM) {
My Named4d22242022-03-28 13:53:32 -07002465 flags |= BUFFER_FLAG_END_OF_STREAM;
Pawin Vongmasa36653902018-11-15 00:10:25 -08002466 ALOGV("[%s] onWorkDone: output EOS", mName);
2467 }
2468
Pawin Vongmasa36653902018-11-15 00:10:25 -08002469 // WORKAROUND: adjust output timestamp based on client input timestamp and codec
2470 // input timestamp. Codec output timestamp (in the timestamp field) shall correspond to
2471 // the codec input timestamp, but client output timestamp should (reported in timeUs)
2472 // shall correspond to the client input timesamp (in customOrdinal). By using the
2473 // delta between the two, this allows for some timestamp deviation - e.g. if one input
2474 // produces multiple output.
2475 c2_cntr64_t timestamp =
2476 worklet->output.ordinal.timestamp + work->input.ordinal.customOrdinal
2477 - work->input.ordinal.timestamp;
Wonsik Kimd4ba8462024-07-12 11:05:48 -07002478 if (hasInputSurface) {
Wonsik Kim95ba0162019-03-19 15:51:54 -07002479 // When using input surface we need to restore the original input timestamp.
2480 timestamp = work->input.ordinal.customOrdinal;
2481 }
My Name6bd9a7d2022-03-25 12:37:58 -07002482 ScopedTrace trace(ATRACE_TAG, android::base::StringPrintf(
2483 "CCodecBufferChannel::onWorkDone(%s@ts=%lld)", mName, timestamp.peekll()).c_str());
Pawin Vongmasa36653902018-11-15 00:10:25 -08002484 ALOGV("[%s] onWorkDone: input %lld, codec %lld => output %lld => %lld",
2485 mName,
2486 work->input.ordinal.customOrdinal.peekll(),
2487 work->input.ordinal.timestamp.peekll(),
2488 worklet->output.ordinal.timestamp.peekll(),
2489 timestamp.peekll());
2490
Pawin Vongmasa9b906982020-04-11 05:07:15 -07002491 // csd cannot be re-ordered and will always arrive first.
Pawin Vongmasa36653902018-11-15 00:10:25 -08002492 if (initData != nullptr) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -07002493 Mutexed<Output>::Locked output(mOutput);
Wonsik Kim72a71012023-02-06 17:35:21 -08002494 if (!output->buffers) {
2495 return false;
2496 }
2497 if (outputFormat) {
Pawin Vongmasa9b906982020-04-11 05:07:15 -07002498 output->buffers->updateSkipCutBuffer(outputFormat);
2499 output->buffers->setFormat(outputFormat);
2500 }
2501 if (!notifyClient) {
2502 return false;
2503 }
2504 size_t index;
2505 sp<MediaCodecBuffer> outBuffer;
Wonsik Kim72a71012023-02-06 17:35:21 -08002506 if (output->buffers->registerCsd(initData, &index, &outBuffer) == OK) {
Pawin Vongmasa36653902018-11-15 00:10:25 -08002507 outBuffer->meta()->setInt64("timeUs", timestamp.peek());
My Named4d22242022-03-28 13:53:32 -07002508 outBuffer->meta()->setInt32("flags", BUFFER_FLAG_CODEC_CONFIG);
Pawin Vongmasa36653902018-11-15 00:10:25 -08002509 ALOGV("[%s] onWorkDone: csd index = %zu [%p]", mName, index, outBuffer.get());
2510
Wonsik Kim5c2c8902023-05-09 10:53:15 -07002511 // TRICKY: we want popped buffers reported in order, so sending
2512 // the callback while holding the lock here. This assumes that
2513 // onOutputBufferAvailable() does not block. onOutputBufferAvailable()
2514 // callbacks are always sent with the Output lock held.
Pawin Vongmasa36653902018-11-15 00:10:25 -08002515 mCallback->onOutputBufferAvailable(index, outBuffer);
Pawin Vongmasa36653902018-11-15 00:10:25 -08002516 } else {
2517 ALOGD("[%s] onWorkDone: unable to register csd", mName);
Wonsik Kim5ecf3832019-04-18 10:28:58 -07002518 output.unlock();
Pawin Vongmasa36653902018-11-15 00:10:25 -08002519 mCCodecCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL);
Pawin Vongmasa36653902018-11-15 00:10:25 -08002520 return false;
2521 }
2522 }
2523
Wonsik Kimec585c32021-10-01 01:11:00 -07002524 bool drop = false;
2525 if (worklet->output.flags & C2FrameData::FLAG_DROP_FRAME) {
2526 ALOGV("[%s] onWorkDone: drop buffer but keep metadata", mName);
2527 drop = true;
2528 }
2529
Marc Kassisec910342022-11-25 11:43:05 +01002530 // Workaround: if C2FrameData::FLAG_DROP_FRAME is not implemented in
2531 // HAL, the flag is then removed in the corresponding output buffer.
2532 if (work->input.flags & C2FrameData::FLAG_DROP_FRAME) {
2533 flags |= BUFFER_FLAG_DECODE_ONLY;
2534 }
2535
Pawin Vongmasa9b906982020-04-11 05:07:15 -07002536 if (notifyClient && !buffer && !flags) {
Wonsik Kimec585c32021-10-01 01:11:00 -07002537 if (mTunneled && drop && outputFormat) {
Houxiang Daie74e5062022-05-19 15:32:54 +08002538 if (mOutputFormat != outputFormat) {
2539 ALOGV("[%s] onWorkDone: Keep tunneled, drop frame with format change (%lld)",
2540 mName, work->input.ordinal.frameIndex.peekull());
2541 mOutputFormat = outputFormat;
2542 } else {
2543 ALOGV("[%s] onWorkDone: Not reporting output buffer without format change (%lld)",
2544 mName, work->input.ordinal.frameIndex.peekull());
2545 notifyClient = false;
2546 }
Wonsik Kimec585c32021-10-01 01:11:00 -07002547 } else {
2548 ALOGV("[%s] onWorkDone: Not reporting output buffer (%lld)",
2549 mName, work->input.ordinal.frameIndex.peekull());
2550 notifyClient = false;
2551 }
Pawin Vongmasa36653902018-11-15 00:10:25 -08002552 }
2553
2554 if (buffer) {
2555 for (const std::shared_ptr<const C2Info> &info : buffer->info()) {
2556 // TODO: properly translate these to metadata
2557 switch (info->coreIndex().coreIndex()) {
2558 case C2StreamPictureTypeMaskInfo::CORE_INDEX:
Lajos Molnar3bb81cd2019-02-20 15:10:30 -08002559 if (((C2StreamPictureTypeMaskInfo *)info.get())->value & C2Config::SYNC_FRAME) {
My Named4d22242022-03-28 13:53:32 -07002560 flags |= BUFFER_FLAG_KEY_FRAME;
Pawin Vongmasa36653902018-11-15 00:10:25 -08002561 }
2562 break;
2563 default:
2564 break;
2565 }
2566 }
2567 }
2568
2569 {
Pawin Vongmasa9b906982020-04-11 05:07:15 -07002570 Mutexed<Output>::Locked output(mOutput);
Wonsik Kimc23cc402020-05-28 14:53:40 -07002571 if (!output->buffers) {
2572 return false;
2573 }
Pawin Vongmasa9b906982020-04-11 05:07:15 -07002574 output->buffers->pushToStash(
2575 buffer,
2576 notifyClient,
2577 timestamp.peek(),
2578 flags,
2579 outputFormat,
2580 worklet->output.ordinal);
Pawin Vongmasa36653902018-11-15 00:10:25 -08002581 }
2582 sendOutputBuffers();
2583 return true;
2584}
2585
2586void CCodecBufferChannel::sendOutputBuffers() {
Pawin Vongmasa9b906982020-04-11 05:07:15 -07002587 OutputBuffers::BufferAction action;
Wonsik Kima4e049d2020-04-28 19:42:23 +00002588 size_t index;
Pawin Vongmasa9b906982020-04-11 05:07:15 -07002589 sp<MediaCodecBuffer> outBuffer;
2590 std::shared_ptr<C2Buffer> c2Buffer;
Pawin Vongmasa36653902018-11-15 00:10:25 -08002591
Sungtak Lee8ceef4d2022-06-15 00:49:26 +00002592 constexpr int kMaxReallocTry = 5;
2593 int reallocTryNum = 0;
2594
Pawin Vongmasa36653902018-11-15 00:10:25 -08002595 while (true) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -07002596 Mutexed<Output>::Locked output(mOutput);
Wonsik Kim936a89c2020-05-08 16:07:50 -07002597 if (!output->buffers) {
2598 return;
2599 }
Pawin Vongmasa9b906982020-04-11 05:07:15 -07002600 action = output->buffers->popFromStashAndRegister(
2601 &c2Buffer, &index, &outBuffer);
Sungtak Lee8ceef4d2022-06-15 00:49:26 +00002602 if (action != OutputBuffers::REALLOCATE) {
2603 reallocTryNum = 0;
2604 }
Pawin Vongmasa9b906982020-04-11 05:07:15 -07002605 switch (action) {
2606 case OutputBuffers::SKIP:
2607 return;
2608 case OutputBuffers::DISCARD:
2609 break;
2610 case OutputBuffers::NOTIFY_CLIENT:
Arun Johnsonf4a81f72023-11-09 21:22:48 +00002611 {
Wonsik Kim5c2c8902023-05-09 10:53:15 -07002612 // TRICKY: we want popped buffers reported in order, so sending
2613 // the callback while holding the lock here. This assumes that
2614 // onOutputBufferAvailable() does not block. onOutputBufferAvailable()
2615 // callbacks are always sent with the Output lock held.
Arun Johnsonf4a81f72023-11-09 21:22:48 +00002616 if (c2Buffer) {
2617 std::shared_ptr<const C2AccessUnitInfos::output> bufferMetadata =
2618 std::static_pointer_cast<const C2AccessUnitInfos::output>(
2619 c2Buffer->getInfo(C2AccessUnitInfos::output::PARAM_TYPE));
2620 if (bufferMetadata && bufferMetadata->flexCount() > 0) {
2621 uint32_t flag = 0;
2622 std::vector<AccessUnitInfo> accessUnitInfos;
2623 for (int nMeta = 0; nMeta < bufferMetadata->flexCount(); nMeta++) {
2624 const C2AccessUnitInfosStruct &bufferMetadataStruct =
2625 bufferMetadata->m.values[nMeta];
2626 flag = convertFlags(bufferMetadataStruct.flags, false);
2627 accessUnitInfos.emplace_back(flag,
Arun Johnson9c6e91e2024-09-10 18:46:02 +00002628 bufferMetadataStruct.size,
2629 bufferMetadataStruct.timestamp);
Arun Johnsonf4a81f72023-11-09 21:22:48 +00002630 }
2631 sp<WrapperObject<std::vector<AccessUnitInfo>>> obj{
2632 new WrapperObject<std::vector<AccessUnitInfo>>{accessUnitInfos}};
2633 outBuffer->meta()->setObject("accessUnitInfo", obj);
2634 }
2635 }
Pawin Vongmasa9b906982020-04-11 05:07:15 -07002636 mCallback->onOutputBufferAvailable(index, outBuffer);
2637 break;
Arun Johnsonf4a81f72023-11-09 21:22:48 +00002638 }
Pawin Vongmasa9b906982020-04-11 05:07:15 -07002639 case OutputBuffers::REALLOCATE:
Sungtak Lee8ceef4d2022-06-15 00:49:26 +00002640 if (++reallocTryNum > kMaxReallocTry) {
2641 output.unlock();
2642 ALOGE("[%s] sendOutputBuffers: tried %d realloc and failed",
2643 mName, kMaxReallocTry);
2644 mCCodecCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL);
2645 return;
2646 }
Pawin Vongmasa9b906982020-04-11 05:07:15 -07002647 if (!output->buffers->isArrayMode()) {
2648 output->buffers =
2649 output->buffers->toArrayMode(output->numSlots);
Pawin Vongmasa36653902018-11-15 00:10:25 -08002650 }
Pawin Vongmasa9b906982020-04-11 05:07:15 -07002651 static_cast<OutputBuffersArray*>(output->buffers.get())->
2652 realloc(c2Buffer);
2653 output.unlock();
2654 mCCodecCallback->onOutputBuffersChanged();
Wonsik Kim4ada73d2020-05-26 14:58:07 -07002655 break;
Pawin Vongmasa9b906982020-04-11 05:07:15 -07002656 case OutputBuffers::RETRY:
2657 ALOGV("[%s] sendOutputBuffers: unable to register output buffer",
2658 mName);
2659 return;
2660 default:
2661 LOG_ALWAYS_FATAL("[%s] sendOutputBuffers: "
2662 "corrupted BufferAction value (%d) "
2663 "returned from popFromStashAndRegister.",
2664 mName, int(action));
Pawin Vongmasa36653902018-11-15 00:10:25 -08002665 return;
2666 }
Pawin Vongmasa36653902018-11-15 00:10:25 -08002667 }
2668}
2669
Sungtak Lee214ce612023-11-01 10:01:13 +00002670status_t CCodecBufferChannel::setSurface(const sp<Surface> &newSurface,
2671 uint32_t generation, bool pushBlankBuffer) {
Pawin Vongmasa36653902018-11-15 00:10:25 -08002672 sp<IGraphicBufferProducer> producer;
Sungtak Lee99144332023-01-26 11:03:14 +00002673 int maxDequeueCount;
2674 sp<Surface> oldSurface;
2675 {
2676 Mutexed<OutputSurface>::Locked outputSurface(mOutputSurface);
2677 maxDequeueCount = outputSurface->maxDequeueBuffers;
2678 oldSurface = outputSurface->surface;
2679 }
Pawin Vongmasa36653902018-11-15 00:10:25 -08002680 if (newSurface) {
2681 newSurface->setScalingMode(NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
Sungtak Leeab6f2f32019-02-15 14:43:51 -08002682 newSurface->setDequeueTimeout(kDequeueTimeoutNs);
Sungtak Leedb14cba2021-04-10 00:50:23 -07002683 newSurface->setMaxDequeuedBufferCount(maxDequeueCount);
Pawin Vongmasa36653902018-11-15 00:10:25 -08002684 producer = newSurface->getIGraphicBufferProducer();
Pawin Vongmasa36653902018-11-15 00:10:25 -08002685 } else {
2686 ALOGE("[%s] setting output surface to null", mName);
2687 return INVALID_OPERATION;
2688 }
2689
2690 std::shared_ptr<Codec2Client::Configurable> outputPoolIntf;
2691 C2BlockPool::local_id_t outputPoolId;
2692 {
2693 Mutexed<BlockPools>::Locked pools(mBlockPools);
2694 outputPoolId = pools->outputPoolId;
2695 outputPoolIntf = pools->outputPoolIntf;
2696 }
2697
2698 if (outputPoolIntf) {
2699 if (mComponent->setOutputSurface(
2700 outputPoolId,
2701 producer,
Sungtak Leedb14cba2021-04-10 00:50:23 -07002702 generation,
2703 maxDequeueCount) != C2_OK) {
Pawin Vongmasa36653902018-11-15 00:10:25 -08002704 ALOGI("[%s] setSurface: component setOutputSurface failed", mName);
2705 return INVALID_OPERATION;
2706 }
2707 }
2708
2709 {
2710 Mutexed<OutputSurface>::Locked output(mOutputSurface);
2711 output->surface = newSurface;
2712 output->generation = generation;
Brian Lindahl932bf602023-03-09 11:59:48 -07002713 initializeFrameTrackingFor(static_cast<ANativeWindow *>(newSurface.get()));
Pawin Vongmasa36653902018-11-15 00:10:25 -08002714 }
2715
Sungtak Lee99144332023-01-26 11:03:14 +00002716 if (oldSurface && pushBlankBuffer) {
2717 // When ReleaseSurface was set from MediaCodec,
2718 // pushing a blank buffer at the end might be necessary.
2719 sp<ANativeWindow> anw = static_cast<ANativeWindow *>(oldSurface.get());
2720 if (anw) {
2721 pushBlankBuffersToNativeWindow(anw.get());
2722 }
2723 }
2724
Pawin Vongmasa36653902018-11-15 00:10:25 -08002725 return OK;
2726}
2727
Wonsik Kimab34ed62019-01-31 15:28:46 -08002728PipelineWatcher::Clock::duration CCodecBufferChannel::elapsed() {
Wonsik Kim4fa4f2b2019-02-13 11:02:58 -08002729 // Otherwise, component may have stalled work due to input starvation up to
2730 // the sum of the delay in the pipeline.
Wonsik Kim31512192022-05-02 18:22:37 -07002731 // TODO(b/231253301): When client pushed EOS, the pipeline could have less
2732 // number of frames.
Wonsik Kimf0e7d222019-06-28 12:33:16 -07002733 size_t n = 0;
Wonsik Kim31512192022-05-02 18:22:37 -07002734 size_t outputDelay = mOutput.lock()->outputDelay;
2735 {
Wonsik Kimf0e7d222019-06-28 12:33:16 -07002736 Mutexed<Input>::Locked input(mInput);
2737 n = input->inputDelay + input->pipelineDelay + outputDelay;
2738 }
Wonsik Kim4fa4f2b2019-02-13 11:02:58 -08002739 return mPipelineWatcher.lock()->elapsed(PipelineWatcher::Clock::now(), n);
Wonsik Kimab34ed62019-01-31 15:28:46 -08002740}
2741
Pawin Vongmasa36653902018-11-15 00:10:25 -08002742void CCodecBufferChannel::setMetaMode(MetaMode mode) {
2743 mMetaMode = mode;
2744}
2745
Wonsik Kim596187e2019-10-25 12:44:10 -07002746void CCodecBufferChannel::setCrypto(const sp<ICrypto> &crypto) {
Wonsik Kimfb7a7672019-12-27 17:13:33 -08002747 if (mCrypto != nullptr) {
2748 for (std::pair<wp<HidlMemory>, int32_t> entry : mHeapSeqNumMap) {
2749 mCrypto->unsetHeap(entry.second);
2750 }
2751 mHeapSeqNumMap.clear();
2752 if (mHeapSeqNum >= 0) {
2753 mCrypto->unsetHeap(mHeapSeqNum);
2754 mHeapSeqNum = -1;
2755 }
2756 }
Wonsik Kim596187e2019-10-25 12:44:10 -07002757 mCrypto = crypto;
2758}
2759
2760void CCodecBufferChannel::setDescrambler(const sp<IDescrambler> &descrambler) {
2761 mDescrambler = descrambler;
2762}
2763
Songyue Han1e6769b2023-08-30 18:09:27 +00002764uint32_t CCodecBufferChannel::getBuffersPixelFormat(bool isEncoder) {
2765 if (isEncoder) {
2766 return getInputBuffersPixelFormat();
2767 } else {
2768 return getOutputBuffersPixelFormat();
2769 }
2770}
2771
2772uint32_t CCodecBufferChannel::getInputBuffersPixelFormat() {
2773 Mutexed<Input>::Locked input(mInput);
2774 if (input->buffers == nullptr) {
2775 return PIXEL_FORMAT_UNKNOWN;
2776 }
2777 return input->buffers->getPixelFormatIfApplicable();
2778}
2779
2780uint32_t CCodecBufferChannel::getOutputBuffersPixelFormat() {
2781 Mutexed<Output>::Locked output(mOutput);
2782 if (output->buffers == nullptr) {
2783 return PIXEL_FORMAT_UNKNOWN;
2784 }
2785 return output->buffers->getPixelFormatIfApplicable();
2786}
2787
2788void CCodecBufferChannel::resetBuffersPixelFormat(bool isEncoder) {
2789 if (isEncoder) {
2790 Mutexed<Input>::Locked input(mInput);
2791 if (input->buffers == nullptr) {
2792 return;
2793 }
2794 input->buffers->resetPixelFormatIfApplicable();
2795 } else {
2796 Mutexed<Output>::Locked output(mOutput);
2797 if (output->buffers == nullptr) {
2798 return;
2799 }
2800 output->buffers->resetPixelFormatIfApplicable();
2801 }
2802}
2803
Harish Mahendrakar38a99c22024-02-26 20:28:05 +05302804void CCodecBufferChannel::setInfoBuffer(const std::shared_ptr<C2InfoBuffer> &buffer) {
Wonsik Kimd4ba8462024-07-12 11:05:48 -07002805 if (mInputSurface.lock()->get() == nullptr) {
Harish Mahendrakar2b095d92024-05-13 16:51:15 -07002806 mInfoBuffers.push_back(buffer);
2807 } else {
2808 std::list<std::unique_ptr<C2Work>> items;
2809 std::unique_ptr<C2Work> work(new C2Work);
2810 work->input.infoBuffers.emplace_back(*buffer);
2811 work->worklets.emplace_back(new C2Worklet);
2812 items.push_back(std::move(work));
Harish Mahendrakar2b095d92024-05-13 16:51:15 -07002813 }
Harish Mahendrakar38a99c22024-02-26 20:28:05 +05302814}
2815
Pawin Vongmasa36653902018-11-15 00:10:25 -08002816status_t toStatusT(c2_status_t c2s, c2_operation_t c2op) {
2817 // C2_OK is always translated to OK.
2818 if (c2s == C2_OK) {
2819 return OK;
2820 }
2821
2822 // Operation-dependent translation
2823 // TODO: Add as necessary
2824 switch (c2op) {
2825 case C2_OPERATION_Component_start:
2826 switch (c2s) {
2827 case C2_NO_MEMORY:
2828 return NO_MEMORY;
2829 default:
2830 return UNKNOWN_ERROR;
2831 }
2832 default:
2833 break;
2834 }
2835
2836 // Backup operation-agnostic translation
2837 switch (c2s) {
2838 case C2_BAD_INDEX:
2839 return BAD_INDEX;
2840 case C2_BAD_VALUE:
2841 return BAD_VALUE;
2842 case C2_BLOCKING:
2843 return WOULD_BLOCK;
2844 case C2_DUPLICATE:
2845 return ALREADY_EXISTS;
2846 case C2_NO_INIT:
2847 return NO_INIT;
2848 case C2_NO_MEMORY:
2849 return NO_MEMORY;
2850 case C2_NOT_FOUND:
2851 return NAME_NOT_FOUND;
2852 case C2_TIMED_OUT:
2853 return TIMED_OUT;
2854 case C2_BAD_STATE:
2855 case C2_CANCELED:
2856 case C2_CANNOT_DO:
2857 case C2_CORRUPTED:
2858 case C2_OMITTED:
2859 case C2_REFUSED:
2860 return UNKNOWN_ERROR;
2861 default:
2862 return -static_cast<status_t>(c2s);
2863 }
2864}
2865
Pawin Vongmasa36653902018-11-15 00:10:25 -08002866} // namespace android