blob: dd6782a2a829a1110454d52970807638e23bb81e [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
Pawin Vongmasa36653902018-11-15 00:10:25 -08001476status_t CCodecBufferChannel::discardBuffer(const sp<MediaCodecBuffer> &buffer) {
1477 ALOGV("[%s] discardBuffer: %p", mName, buffer.get());
1478 bool released = false;
1479 {
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001480 Mutexed<Input>::Locked input(mInput);
1481 if (input->buffers && input->buffers->releaseBuffer(buffer, nullptr, true)) {
Pawin Vongmasa36653902018-11-15 00:10:25 -08001482 released = true;
Pawin Vongmasa36653902018-11-15 00:10:25 -08001483 }
1484 }
1485 {
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001486 Mutexed<Output>::Locked output(mOutput);
1487 if (output->buffers && output->buffers->releaseBuffer(buffer, nullptr)) {
Pawin Vongmasa36653902018-11-15 00:10:25 -08001488 released = true;
1489 }
1490 }
1491 if (released) {
Pawin Vongmasa36653902018-11-15 00:10:25 -08001492 sendOutputBuffers();
Pawin Vongmasa8be93112018-12-11 14:01:42 -08001493 feedInputBufferIfAvailable();
Pawin Vongmasa36653902018-11-15 00:10:25 -08001494 } else {
1495 ALOGD("[%s] MediaCodec discarded an unknown buffer", mName);
1496 }
1497 return OK;
1498}
1499
1500void CCodecBufferChannel::getInputBufferArray(Vector<sp<MediaCodecBuffer>> *array) {
1501 array->clear();
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001502 Mutexed<Input>::Locked input(mInput);
Pawin Vongmasa36653902018-11-15 00:10:25 -08001503
Arun Johnson3ab32cd2022-06-10 18:58:01 +00001504 if (!input->buffers) {
1505 ALOGE("getInputBufferArray: No Input Buffers allocated");
1506 return;
1507 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001508 if (!input->buffers->isArrayMode()) {
1509 input->buffers = input->buffers->toArrayMode(input->numSlots);
Pawin Vongmasa36653902018-11-15 00:10:25 -08001510 }
1511
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001512 input->buffers->getArray(array);
Pawin Vongmasa36653902018-11-15 00:10:25 -08001513}
1514
1515void CCodecBufferChannel::getOutputBufferArray(Vector<sp<MediaCodecBuffer>> *array) {
1516 array->clear();
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001517 Mutexed<Output>::Locked output(mOutput);
Arun Johnson3ab32cd2022-06-10 18:58:01 +00001518 if (!output->buffers) {
1519 ALOGE("getOutputBufferArray: No Output Buffers allocated");
1520 return;
1521 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001522 if (!output->buffers->isArrayMode()) {
1523 output->buffers = output->buffers->toArrayMode(output->numSlots);
Pawin Vongmasa36653902018-11-15 00:10:25 -08001524 }
1525
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001526 output->buffers->getArray(array);
Pawin Vongmasa36653902018-11-15 00:10:25 -08001527}
1528
1529status_t CCodecBufferChannel::start(
Wonsik Kimfb7a7672019-12-27 17:13:33 -08001530 const sp<AMessage> &inputFormat,
1531 const sp<AMessage> &outputFormat,
1532 bool buffersBoundToCodec) {
Pawin Vongmasa36653902018-11-15 00:10:25 -08001533 C2StreamBufferTypeSetting::input iStreamFormat(0u);
1534 C2StreamBufferTypeSetting::output oStreamFormat(0u);
Wonsik Kime1104ca2020-11-24 15:01:33 -08001535 C2ComponentKindSetting kind;
Pawin Vongmasa36653902018-11-15 00:10:25 -08001536 C2PortReorderBufferDepthTuning::output reorderDepth;
1537 C2PortReorderKeySetting::output reorderKey;
Wonsik Kim078b58e2019-01-09 15:08:06 -08001538 C2PortActualDelayTuning::input inputDelay(0);
1539 C2PortActualDelayTuning::output outputDelay(0);
1540 C2ActualPipelineDelayTuning pipelineDelay(0);
Sungtak Lee04b30352020-07-27 13:57:25 -07001541 C2SecureModeTuning secureMode(C2Config::SM_UNPROTECTED);
Wonsik Kim078b58e2019-01-09 15:08:06 -08001542
Pawin Vongmasa36653902018-11-15 00:10:25 -08001543 c2_status_t err = mComponent->query(
1544 {
1545 &iStreamFormat,
1546 &oStreamFormat,
Wonsik Kime1104ca2020-11-24 15:01:33 -08001547 &kind,
Pawin Vongmasa36653902018-11-15 00:10:25 -08001548 &reorderDepth,
1549 &reorderKey,
Wonsik Kim078b58e2019-01-09 15:08:06 -08001550 &inputDelay,
1551 &pipelineDelay,
1552 &outputDelay,
Sungtak Lee04b30352020-07-27 13:57:25 -07001553 &secureMode,
Pawin Vongmasa36653902018-11-15 00:10:25 -08001554 },
1555 {},
1556 C2_DONT_BLOCK,
1557 nullptr);
1558 if (err == C2_BAD_INDEX) {
Wonsik Kime1104ca2020-11-24 15:01:33 -08001559 if (!iStreamFormat || !oStreamFormat || !kind) {
Pawin Vongmasa36653902018-11-15 00:10:25 -08001560 return UNKNOWN_ERROR;
1561 }
1562 } else if (err != C2_OK) {
1563 return UNKNOWN_ERROR;
1564 }
1565
Wonsik Kim4fa4f2b2019-02-13 11:02:58 -08001566 uint32_t inputDelayValue = inputDelay ? inputDelay.value : 0;
1567 uint32_t pipelineDelayValue = pipelineDelay ? pipelineDelay.value : 0;
1568 uint32_t outputDelayValue = outputDelay ? outputDelay.value : 0;
1569
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001570 size_t numInputSlots = inputDelayValue + pipelineDelayValue + kSmoothnessFactor;
1571 size_t numOutputSlots = outputDelayValue + kSmoothnessFactor;
Wonsik Kim078b58e2019-01-09 15:08:06 -08001572
Pawin Vongmasa36653902018-11-15 00:10:25 -08001573 // TODO: get this from input format
1574 bool secure = mComponent->getName().find(".secure") != std::string::npos;
1575
Sungtak Lee04b30352020-07-27 13:57:25 -07001576 // secure mode is a static parameter (shall not change in the executing state)
1577 mSendEncryptedInfoBuffer = secureMode.value == C2Config::SM_READ_PROTECTED_WITH_ENCRYPTED;
1578
Pawin Vongmasa36653902018-11-15 00:10:25 -08001579 std::shared_ptr<C2AllocatorStore> allocatorStore = GetCodec2PlatformAllocatorStore();
Pin-chih Linaa18ea52019-11-19 18:48:50 +08001580 int poolMask = GetCodec2PoolMask();
1581 C2PlatformAllocatorStore::id_t preferredLinearId = GetPreferredLinearAllocatorId(poolMask);
Pawin Vongmasa36653902018-11-15 00:10:25 -08001582
1583 if (inputFormat != nullptr) {
Lajos Molnar3bb81cd2019-02-20 15:10:30 -08001584 bool graphic = (iStreamFormat.value == C2BufferData::GRAPHIC);
Wonsik Kime1104ca2020-11-24 15:01:33 -08001585 bool audioEncoder = !graphic && (kind.value == C2Component::KIND_ENCODER);
Wonsik Kimffb889a2020-05-28 11:32:25 -07001586 C2Config::api_feature_t apiFeatures = C2Config::api_feature_t(
1587 API_REFLECTION |
1588 API_VALUES |
1589 API_CURRENT_VALUES |
1590 API_DEPENDENCY |
1591 API_SAME_INPUT_BUFFER);
Wonsik Kime1104ca2020-11-24 15:01:33 -08001592 C2StreamAudioFrameSizeInfo::input encoderFrameSize(0u);
1593 C2StreamSampleRateInfo::input sampleRate(0u);
1594 C2StreamChannelCountInfo::input channelCount(0u);
1595 C2StreamPcmEncodingInfo::input pcmEncoding(0u);
Pawin Vongmasa36653902018-11-15 00:10:25 -08001596 std::shared_ptr<C2BlockPool> pool;
1597 {
1598 Mutexed<BlockPools>::Locked pools(mBlockPools);
1599
1600 // set default allocator ID.
1601 pools->inputAllocatorId = (graphic) ? C2PlatformAllocatorStore::GRALLOC
Pin-chih Linaa18ea52019-11-19 18:48:50 +08001602 : preferredLinearId;
Pawin Vongmasa36653902018-11-15 00:10:25 -08001603
1604 // query C2PortAllocatorsTuning::input from component. If an allocator ID is obtained
1605 // from component, create the input block pool with given ID. Otherwise, use default IDs.
1606 std::vector<std::unique_ptr<C2Param>> params;
Wonsik Kimffb889a2020-05-28 11:32:25 -07001607 C2ApiFeaturesSetting featuresSetting{apiFeatures};
Wonsik Kime1104ca2020-11-24 15:01:33 -08001608 std::vector<C2Param *> stackParams({&featuresSetting});
1609 if (audioEncoder) {
1610 stackParams.push_back(&encoderFrameSize);
1611 stackParams.push_back(&sampleRate);
1612 stackParams.push_back(&channelCount);
1613 stackParams.push_back(&pcmEncoding);
1614 } else {
1615 encoderFrameSize.invalidate();
1616 sampleRate.invalidate();
1617 channelCount.invalidate();
1618 pcmEncoding.invalidate();
1619 }
1620 err = mComponent->query(stackParams,
Pawin Vongmasa36653902018-11-15 00:10:25 -08001621 { C2PortAllocatorsTuning::input::PARAM_TYPE },
1622 C2_DONT_BLOCK,
1623 &params);
1624 if ((err != C2_OK && err != C2_BAD_INDEX) || params.size() != 1) {
1625 ALOGD("[%s] Query input allocators returned %zu params => %s (%u)",
1626 mName, params.size(), asString(err), err);
Wonsik Kimffb889a2020-05-28 11:32:25 -07001627 } else if (params.size() == 1) {
Pawin Vongmasa36653902018-11-15 00:10:25 -08001628 C2PortAllocatorsTuning::input *inputAllocators =
1629 C2PortAllocatorsTuning::input::From(params[0].get());
1630 if (inputAllocators && inputAllocators->flexCount() > 0) {
1631 std::shared_ptr<C2Allocator> allocator;
1632 // verify allocator IDs and resolve default allocator
1633 allocatorStore->fetchAllocator(inputAllocators->m.values[0], &allocator);
1634 if (allocator) {
1635 pools->inputAllocatorId = allocator->getId();
1636 } else {
1637 ALOGD("[%s] component requested invalid input allocator ID %u",
1638 mName, inputAllocators->m.values[0]);
1639 }
1640 }
1641 }
Wonsik Kimffb889a2020-05-28 11:32:25 -07001642 if (featuresSetting) {
1643 apiFeatures = featuresSetting.value;
1644 }
Pawin Vongmasa36653902018-11-15 00:10:25 -08001645
1646 // TODO: use C2Component wrapper to associate this pool with ourselves
1647 if ((poolMask >> pools->inputAllocatorId) & 1) {
1648 err = CreateCodec2BlockPool(pools->inputAllocatorId, nullptr, &pool);
1649 ALOGD("[%s] Created input block pool with allocatorID %u => poolID %llu - %s (%d)",
1650 mName, pools->inputAllocatorId,
1651 (unsigned long long)(pool ? pool->getLocalId() : 111000111),
1652 asString(err), err);
1653 } else {
1654 err = C2_NOT_FOUND;
1655 }
1656 if (err != C2_OK) {
1657 C2BlockPool::local_id_t inputPoolId =
1658 graphic ? C2BlockPool::BASIC_GRAPHIC : C2BlockPool::BASIC_LINEAR;
1659 err = GetCodec2BlockPool(inputPoolId, nullptr, &pool);
1660 ALOGD("[%s] Using basic input block pool with poolID %llu => got %llu - %s (%d)",
1661 mName, (unsigned long long)inputPoolId,
1662 (unsigned long long)(pool ? pool->getLocalId() : 111000111),
1663 asString(err), err);
1664 if (err != C2_OK) {
1665 return NO_MEMORY;
1666 }
1667 }
1668 pools->inputPool = pool;
1669 }
1670
Wonsik Kim51051262018-11-28 13:59:05 -08001671 bool forceArrayMode = false;
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001672 Mutexed<Input>::Locked input(mInput);
Wonsik Kimbdffead2019-07-01 12:00:07 -07001673 input->inputDelay = inputDelayValue;
1674 input->pipelineDelay = pipelineDelayValue;
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001675 input->numSlots = numInputSlots;
1676 input->extraBuffers.flush();
1677 input->numExtraSlots = 0u;
Wonsik Kim6b2c8be2021-09-28 05:11:04 -07001678 input->lastFlushIndex = mFrameIndex.load(std::memory_order_relaxed);
Wonsik Kime1104ca2020-11-24 15:01:33 -08001679 if (audioEncoder && encoderFrameSize && sampleRate && channelCount) {
1680 input->frameReassembler.init(
1681 pool,
1682 {C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE},
1683 encoderFrameSize.value,
1684 sampleRate.value,
1685 channelCount.value,
1686 pcmEncoding ? pcmEncoding.value : C2Config::PCM_16);
1687 }
Wonsik Kimffb889a2020-05-28 11:32:25 -07001688 bool conforming = (apiFeatures & API_SAME_INPUT_BUFFER);
1689 // For encrypted content, framework decrypts source buffer (ashmem) into
1690 // C2Buffers. Thus non-conforming codecs can process these.
Wonsik Kime1104ca2020-11-24 15:01:33 -08001691 if (!buffersBoundToCodec
1692 && !input->frameReassembler
1693 && (hasCryptoOrDescrambler() || conforming)) {
Wonsik Kimfb7a7672019-12-27 17:13:33 -08001694 input->buffers.reset(new SlotInputBuffers(mName));
1695 } else if (graphic) {
Wonsik Kimd4ba8462024-07-12 11:05:48 -07001696 if (mInputSurface.lock()->get()) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001697 input->buffers.reset(new DummyInputBuffers(mName));
Pawin Vongmasa36653902018-11-15 00:10:25 -08001698 } else if (mMetaMode == MODE_ANW) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001699 input->buffers.reset(new GraphicMetadataInputBuffers(mName));
Wonsik Kim1221fd12019-07-12 12:52:05 -07001700 // This is to ensure buffers do not get released prematurely.
1701 // TODO: handle this without going into array mode
1702 forceArrayMode = true;
Pawin Vongmasa36653902018-11-15 00:10:25 -08001703 } else {
Wonsik Kim41d83432020-04-27 16:40:49 -07001704 input->buffers.reset(new GraphicInputBuffers(mName));
Pawin Vongmasa36653902018-11-15 00:10:25 -08001705 }
1706 } else {
1707 if (hasCryptoOrDescrambler()) {
1708 int32_t capacity = kLinearBufferSize;
1709 (void)inputFormat->findInt32(KEY_MAX_INPUT_SIZE, &capacity);
1710 if ((size_t)capacity > kMaxLinearBufferSize) {
1711 ALOGD("client requested %d, capped to %zu", capacity, kMaxLinearBufferSize);
1712 capacity = kMaxLinearBufferSize;
1713 }
1714 if (mDealer == nullptr) {
1715 mDealer = new MemoryDealer(
1716 align(capacity, MemoryDealer::getAllocationAlignment())
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001717 * (numInputSlots + 1),
Pawin Vongmasa36653902018-11-15 00:10:25 -08001718 "EncryptedLinearInputBuffers");
1719 mDecryptDestination = mDealer->allocate((size_t)capacity);
1720 }
1721 if (mCrypto != nullptr && mHeapSeqNum < 0) {
Robert Shih895fba92019-07-16 16:29:44 -07001722 sp<HidlMemory> heap = fromHeap(mDealer->getMemoryHeap());
1723 mHeapSeqNum = mCrypto->setHeap(heap);
Pawin Vongmasa36653902018-11-15 00:10:25 -08001724 } else {
1725 mHeapSeqNum = -1;
1726 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001727 input->buffers.reset(new EncryptedLinearInputBuffers(
Wonsik Kim078b58e2019-01-09 15:08:06 -08001728 secure, mDealer, mCrypto, mHeapSeqNum, (size_t)capacity,
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001729 numInputSlots, mName));
Wonsik Kim51051262018-11-28 13:59:05 -08001730 forceArrayMode = true;
Pawin Vongmasa36653902018-11-15 00:10:25 -08001731 } else {
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001732 input->buffers.reset(new LinearInputBuffers(mName));
Pawin Vongmasa36653902018-11-15 00:10:25 -08001733 }
1734 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001735 input->buffers->setFormat(inputFormat);
Pawin Vongmasa36653902018-11-15 00:10:25 -08001736
1737 if (err == C2_OK) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001738 input->buffers->setPool(pool);
Pawin Vongmasa36653902018-11-15 00:10:25 -08001739 } else {
1740 // TODO: error
1741 }
Wonsik Kim51051262018-11-28 13:59:05 -08001742
1743 if (forceArrayMode) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001744 input->buffers = input->buffers->toArrayMode(numInputSlots);
Wonsik Kim51051262018-11-28 13:59:05 -08001745 }
Pawin Vongmasa36653902018-11-15 00:10:25 -08001746 }
1747
1748 if (outputFormat != nullptr) {
1749 sp<IGraphicBufferProducer> outputSurface;
1750 uint32_t outputGeneration;
Sungtak Leea714f112021-03-16 05:40:03 -07001751 int maxDequeueCount = 0;
Pawin Vongmasa36653902018-11-15 00:10:25 -08001752 {
1753 Mutexed<OutputSurface>::Locked output(mOutputSurface);
Sungtak Leea714f112021-03-16 05:40:03 -07001754 maxDequeueCount = output->maxDequeueBuffers = numOutputSlots +
Wonsik Kim3a692e62023-05-19 15:37:22 -07001755 reorderDepth.value + mRenderingDepth;
Pawin Vongmasa36653902018-11-15 00:10:25 -08001756 outputSurface = output->surface ?
1757 output->surface->getIGraphicBufferProducer() : nullptr;
Wonsik Kimf5e5c832019-02-21 11:36:05 -08001758 if (outputSurface) {
1759 output->surface->setMaxDequeuedBufferCount(output->maxDequeueBuffers);
1760 }
Pawin Vongmasa36653902018-11-15 00:10:25 -08001761 outputGeneration = output->generation;
1762 }
1763
Lajos Molnar3bb81cd2019-02-20 15:10:30 -08001764 bool graphic = (oStreamFormat.value == C2BufferData::GRAPHIC);
Pawin Vongmasa36653902018-11-15 00:10:25 -08001765 C2BlockPool::local_id_t outputPoolId_;
David Stevensc3fbb282021-01-18 18:11:20 +09001766 C2BlockPool::local_id_t prevOutputPoolId;
Pawin Vongmasa36653902018-11-15 00:10:25 -08001767
1768 {
1769 Mutexed<BlockPools>::Locked pools(mBlockPools);
1770
David Stevensc3fbb282021-01-18 18:11:20 +09001771 prevOutputPoolId = pools->outputPoolId;
1772
Pawin Vongmasa36653902018-11-15 00:10:25 -08001773 // set default allocator ID.
1774 pools->outputAllocatorId = (graphic) ? C2PlatformAllocatorStore::GRALLOC
Pin-chih Linaa18ea52019-11-19 18:48:50 +08001775 : preferredLinearId;
Pawin Vongmasa36653902018-11-15 00:10:25 -08001776
1777 // query C2PortAllocatorsTuning::output from component, or use default allocator if
1778 // unsuccessful.
1779 std::vector<std::unique_ptr<C2Param>> params;
1780 err = mComponent->query({ },
1781 { C2PortAllocatorsTuning::output::PARAM_TYPE },
1782 C2_DONT_BLOCK,
1783 &params);
1784 if ((err != C2_OK && err != C2_BAD_INDEX) || params.size() != 1) {
1785 ALOGD("[%s] Query output allocators returned %zu params => %s (%u)",
1786 mName, params.size(), asString(err), err);
1787 } else if (err == C2_OK && params.size() == 1) {
1788 C2PortAllocatorsTuning::output *outputAllocators =
1789 C2PortAllocatorsTuning::output::From(params[0].get());
1790 if (outputAllocators && outputAllocators->flexCount() > 0) {
1791 std::shared_ptr<C2Allocator> allocator;
1792 // verify allocator IDs and resolve default allocator
1793 allocatorStore->fetchAllocator(outputAllocators->m.values[0], &allocator);
1794 if (allocator) {
1795 pools->outputAllocatorId = allocator->getId();
1796 } else {
1797 ALOGD("[%s] component requested invalid output allocator ID %u",
1798 mName, outputAllocators->m.values[0]);
1799 }
1800 }
1801 }
1802
1803 // use bufferqueue if outputting to a surface.
1804 // query C2PortSurfaceAllocatorTuning::output from component, or use default allocator
1805 // if unsuccessful.
1806 if (outputSurface) {
1807 params.clear();
1808 err = mComponent->query({ },
1809 { C2PortSurfaceAllocatorTuning::output::PARAM_TYPE },
1810 C2_DONT_BLOCK,
1811 &params);
1812 if ((err != C2_OK && err != C2_BAD_INDEX) || params.size() != 1) {
1813 ALOGD("[%s] Query output surface allocator returned %zu params => %s (%u)",
1814 mName, params.size(), asString(err), err);
1815 } else if (err == C2_OK && params.size() == 1) {
1816 C2PortSurfaceAllocatorTuning::output *surfaceAllocator =
1817 C2PortSurfaceAllocatorTuning::output::From(params[0].get());
1818 if (surfaceAllocator) {
1819 std::shared_ptr<C2Allocator> allocator;
1820 // verify allocator IDs and resolve default allocator
1821 allocatorStore->fetchAllocator(surfaceAllocator->value, &allocator);
1822 if (allocator) {
1823 pools->outputAllocatorId = allocator->getId();
1824 } else {
1825 ALOGD("[%s] component requested invalid surface output allocator ID %u",
1826 mName, surfaceAllocator->value);
1827 err = C2_BAD_VALUE;
1828 }
1829 }
1830 }
1831 if (pools->outputAllocatorId == C2PlatformAllocatorStore::GRALLOC
1832 && err != C2_OK
1833 && ((poolMask >> C2PlatformAllocatorStore::BUFFERQUEUE) & 1)) {
1834 pools->outputAllocatorId = C2PlatformAllocatorStore::BUFFERQUEUE;
1835 }
1836 }
1837
1838 if ((poolMask >> pools->outputAllocatorId) & 1) {
1839 err = mComponent->createBlockPool(
1840 pools->outputAllocatorId, &pools->outputPoolId, &pools->outputPoolIntf);
1841 ALOGI("[%s] Created output block pool with allocatorID %u => poolID %llu - %s",
1842 mName, pools->outputAllocatorId,
1843 (unsigned long long)pools->outputPoolId,
1844 asString(err));
1845 } else {
1846 err = C2_NOT_FOUND;
1847 }
1848 if (err != C2_OK) {
1849 // use basic pool instead
1850 pools->outputPoolId =
1851 graphic ? C2BlockPool::BASIC_GRAPHIC : C2BlockPool::BASIC_LINEAR;
1852 }
1853
1854 // Configure output block pool ID as parameter C2PortBlockPoolsTuning::output to
1855 // component.
1856 std::unique_ptr<C2PortBlockPoolsTuning::output> poolIdsTuning =
1857 C2PortBlockPoolsTuning::output::AllocUnique({ pools->outputPoolId });
1858
1859 std::vector<std::unique_ptr<C2SettingResult>> failures;
1860 err = mComponent->config({ poolIdsTuning.get() }, C2_MAY_BLOCK, &failures);
1861 ALOGD("[%s] Configured output block pool ids %llu => %s",
1862 mName, (unsigned long long)poolIdsTuning->m.values[0], asString(err));
1863 outputPoolId_ = pools->outputPoolId;
1864 }
1865
David Stevensc3fbb282021-01-18 18:11:20 +09001866 if (prevOutputPoolId != C2BlockPool::BASIC_LINEAR
1867 && prevOutputPoolId != C2BlockPool::BASIC_GRAPHIC) {
1868 c2_status_t err = mComponent->destroyBlockPool(prevOutputPoolId);
1869 if (err != C2_OK) {
1870 ALOGW("Failed to clean up previous block pool %llu - %s (%d)\n",
1871 (unsigned long long) prevOutputPoolId, asString(err), err);
1872 }
1873 }
1874
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001875 Mutexed<Output>::Locked output(mOutput);
Wonsik Kimbdffead2019-07-01 12:00:07 -07001876 output->outputDelay = outputDelayValue;
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001877 output->numSlots = numOutputSlots;
Wonsik Kim3722abc2023-05-17 13:26:31 -07001878 output->bounded = bool(outputSurface);
Pawin Vongmasa36653902018-11-15 00:10:25 -08001879 if (graphic) {
Wonsik Kimfb7a7672019-12-27 17:13:33 -08001880 if (outputSurface || !buffersBoundToCodec) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001881 output->buffers.reset(new GraphicOutputBuffers(mName));
Pawin Vongmasa36653902018-11-15 00:10:25 -08001882 } else {
Wonsik Kim41d83432020-04-27 16:40:49 -07001883 output->buffers.reset(new RawGraphicOutputBuffers(mName));
Pawin Vongmasa36653902018-11-15 00:10:25 -08001884 }
1885 } else {
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001886 output->buffers.reset(new LinearOutputBuffers(mName));
Pawin Vongmasa36653902018-11-15 00:10:25 -08001887 }
Wonsik Kime4716c02020-02-28 10:42:21 -08001888 output->buffers->setFormat(outputFormat);
Pawin Vongmasa36653902018-11-15 00:10:25 -08001889
Pawin Vongmasa9b906982020-04-11 05:07:15 -07001890 output->buffers->clearStash();
1891 if (reorderDepth) {
1892 output->buffers->setReorderDepth(reorderDepth.value);
1893 }
1894 if (reorderKey) {
1895 output->buffers->setReorderKey(reorderKey.value);
1896 }
Pawin Vongmasa36653902018-11-15 00:10:25 -08001897
1898 // Try to set output surface to created block pool if given.
1899 if (outputSurface) {
1900 mComponent->setOutputSurface(
1901 outputPoolId_,
1902 outputSurface,
Sungtak Leedb14cba2021-04-10 00:50:23 -07001903 outputGeneration,
1904 maxDequeueCount);
Lajos Molnar78aa7c92021-02-18 21:39:01 -08001905 } else {
1906 // configure CPU read consumer usage
1907 C2StreamUsageTuning::output outputUsage{0u, C2MemoryUsage::CPU_READ};
1908 std::vector<std::unique_ptr<C2SettingResult>> failures;
1909 err = mComponent->config({ &outputUsage }, C2_MAY_BLOCK, &failures);
1910 // do not print error message for now as most components may not yet
1911 // support this setting
1912 ALOGD_IF(err != C2_BAD_INDEX, "[%s] Configured output usage [%#llx]",
1913 mName, (long long)outputUsage.value);
Pawin Vongmasa36653902018-11-15 00:10:25 -08001914 }
1915
Wonsik Kim8ab25aa2019-06-24 16:37:37 -07001916 if (oStreamFormat.value == C2BufferData::LINEAR) {
Wonsik Kim58713302020-01-29 22:25:23 -08001917 if (buffersBoundToCodec) {
1918 // WORKAROUND: if we're using early CSD workaround we convert to
1919 // array mode, to appease apps assuming the output
1920 // buffers to be of the same size.
1921 output->buffers = output->buffers->toArrayMode(numOutputSlots);
1922 }
Pawin Vongmasa36653902018-11-15 00:10:25 -08001923
1924 int32_t channelCount;
1925 int32_t sampleRate;
1926 if (outputFormat->findInt32(KEY_CHANNEL_COUNT, &channelCount)
1927 && outputFormat->findInt32(KEY_SAMPLE_RATE, &sampleRate)) {
1928 int32_t delay = 0;
1929 int32_t padding = 0;;
1930 if (!outputFormat->findInt32("encoder-delay", &delay)) {
1931 delay = 0;
1932 }
1933 if (!outputFormat->findInt32("encoder-padding", &padding)) {
1934 padding = 0;
1935 }
1936 if (delay || padding) {
Arun Johnson52d323e2024-01-05 21:16:56 +00001937 // We need write access to the buffers, so turn them into array mode.
1938 // TODO: b/321930152 - define SkipCutOutputBuffers that takes output from
1939 // component, runs it through SkipCutBuffer and allocate local buffer to be
1940 // used by fwk. Make initSkipCutBuffer() return OutputBuffers similar to
1941 // toArrayMode().
1942 if (!output->buffers->isArrayMode()) {
1943 output->buffers = output->buffers->toArrayMode(numOutputSlots);
1944 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001945 output->buffers->initSkipCutBuffer(delay, padding, sampleRate, channelCount);
Pawin Vongmasa36653902018-11-15 00:10:25 -08001946 }
1947 }
1948 }
Wonsik Kimec585c32021-10-01 01:11:00 -07001949
1950 int32_t tunneled = 0;
1951 if (!outputFormat->findInt32("android._tunneled", &tunneled)) {
1952 tunneled = 0;
1953 }
1954 mTunneled = (tunneled != 0);
Pawin Vongmasa36653902018-11-15 00:10:25 -08001955 }
1956
1957 // Set up pipeline control. This has to be done after mInputBuffers and
1958 // mOutputBuffers are initialized to make sure that lingering callbacks
1959 // about buffers from the previous generation do not interfere with the
1960 // newly initialized pipeline capacity.
1961
Wonsik Kim62545252021-01-20 11:25:41 -08001962 if (inputFormat || outputFormat) {
Wonsik Kimab34ed62019-01-31 15:28:46 -08001963 Mutexed<PipelineWatcher>::Locked watcher(mPipelineWatcher);
Wonsik Kim4fa4f2b2019-02-13 11:02:58 -08001964 watcher->inputDelay(inputDelayValue)
1965 .pipelineDelay(pipelineDelayValue)
1966 .outputDelay(outputDelayValue)
Houxiang Dai0b573282023-03-11 18:31:56 +08001967 .smoothnessFactor(kSmoothnessFactor)
1968 .tunneled(mTunneled);
Wonsik Kimab34ed62019-01-31 15:28:46 -08001969 watcher->flush();
1970 }
Pawin Vongmasa36653902018-11-15 00:10:25 -08001971
1972 mInputMetEos = false;
1973 mSync.start();
1974 return OK;
1975}
1976
Wonsik Kim34b28b42022-05-20 15:49:32 -07001977status_t CCodecBufferChannel::prepareInitialInputBuffers(
Arun Johnson326166e2023-07-28 19:11:52 +00001978 std::map<size_t, sp<MediaCodecBuffer>> *clientInputBuffers, bool retry) {
Wonsik Kimd4ba8462024-07-12 11:05:48 -07001979 if (mInputSurface.lock()->get()) {
Pawin Vongmasa36653902018-11-15 00:10:25 -08001980 return OK;
1981 }
1982
Wonsik Kim34b28b42022-05-20 15:49:32 -07001983 size_t numInputSlots = mInput.lock()->numSlots;
Arun Johnson326166e2023-07-28 19:11:52 +00001984 int retryCount = 1;
1985 for (; clientInputBuffers->empty() && retryCount >= 0; retryCount--) {
1986 {
1987 Mutexed<Input>::Locked input(mInput);
1988 while (clientInputBuffers->size() < numInputSlots) {
1989 size_t index;
1990 sp<MediaCodecBuffer> buffer;
1991 if (!input->buffers->requestNewBuffer(&index, &buffer)) {
1992 break;
1993 }
1994 clientInputBuffers->emplace(index, buffer);
Wonsik Kim34b28b42022-05-20 15:49:32 -07001995 }
Arun Johnson326166e2023-07-28 19:11:52 +00001996 }
1997 if (!retry || (retryCount <= 0)) {
1998 break;
1999 }
2000 if (clientInputBuffers->empty()) {
2001 // wait: buffer may be in transit from component.
2002 std::this_thread::sleep_for(std::chrono::milliseconds(4));
Wonsik Kim34b28b42022-05-20 15:49:32 -07002003 }
2004 }
2005 if (clientInputBuffers->empty()) {
2006 ALOGW("[%s] start: cannot allocate memory at all", mName);
2007 return NO_MEMORY;
2008 } else if (clientInputBuffers->size() < numInputSlots) {
2009 ALOGD("[%s] start: cannot allocate memory for all slots, "
2010 "only %zu buffers allocated",
2011 mName, clientInputBuffers->size());
2012 } else {
2013 ALOGV("[%s] %zu initial input buffers available",
2014 mName, clientInputBuffers->size());
2015 }
2016 return OK;
2017}
2018
2019status_t CCodecBufferChannel::requestInitialInputBuffers(
2020 std::map<size_t, sp<MediaCodecBuffer>> &&clientInputBuffers) {
Lajos Molnar3bb81cd2019-02-20 15:10:30 -08002021 C2StreamBufferTypeSetting::output oStreamFormat(0u);
Wonsik Kim8ab25aa2019-06-24 16:37:37 -07002022 C2PrependHeaderModeSetting prepend(PREPEND_HEADER_TO_NONE);
2023 c2_status_t err = mComponent->query({ &oStreamFormat, &prepend }, {}, C2_DONT_BLOCK, nullptr);
2024 if (err != C2_OK && err != C2_BAD_INDEX) {
Pawin Vongmasa36653902018-11-15 00:10:25 -08002025 return UNKNOWN_ERROR;
2026 }
Pawin Vongmasae7bb8612020-06-04 06:15:22 -07002027
Wonsik Kim5ebfcb22021-01-05 18:58:15 -08002028 std::list<std::unique_ptr<C2Work>> flushedConfigs;
2029 mFlushedConfigs.lock()->swap(flushedConfigs);
2030 if (!flushedConfigs.empty()) {
Wonsik Kim92df7e42021-11-04 16:02:03 -07002031 {
2032 Mutexed<PipelineWatcher>::Locked watcher(mPipelineWatcher);
2033 PipelineWatcher::Clock::time_point now = PipelineWatcher::Clock::now();
2034 for (const std::unique_ptr<C2Work> &work : flushedConfigs) {
2035 watcher->onWorkQueued(
2036 work->input.ordinal.frameIndex.peeku(),
2037 std::vector(work->input.buffers),
2038 now);
2039 }
2040 }
Wonsik Kim5ebfcb22021-01-05 18:58:15 -08002041 err = mComponent->queue(&flushedConfigs);
2042 if (err != C2_OK) {
2043 ALOGW("[%s] Error while queueing a flushed config", mName);
2044 return UNKNOWN_ERROR;
Pawin Vongmasa36653902018-11-15 00:10:25 -08002045 }
2046 }
Wonsik Kim5ebfcb22021-01-05 18:58:15 -08002047 if (oStreamFormat.value == C2BufferData::LINEAR &&
Wonsik Kim34b28b42022-05-20 15:49:32 -07002048 (!prepend || prepend.value == PREPEND_HEADER_TO_NONE) &&
2049 !clientInputBuffers.empty()) {
2050 size_t minIndex = clientInputBuffers.begin()->first;
2051 sp<MediaCodecBuffer> minBuffer = clientInputBuffers.begin()->second;
2052 for (const auto &[index, buffer] : clientInputBuffers) {
2053 if (minBuffer->capacity() > buffer->capacity()) {
2054 minIndex = index;
2055 minBuffer = buffer;
2056 }
2057 }
Wonsik Kim5ebfcb22021-01-05 18:58:15 -08002058 // WORKAROUND: Some apps expect CSD available without queueing
2059 // any input. Queue an empty buffer to get the CSD.
Wonsik Kim34b28b42022-05-20 15:49:32 -07002060 minBuffer->setRange(0, 0);
2061 minBuffer->meta()->clear();
2062 minBuffer->meta()->setInt64("timeUs", 0);
2063 if (queueInputBufferInternal(minBuffer) != OK) {
Wonsik Kim5ebfcb22021-01-05 18:58:15 -08002064 ALOGW("[%s] Error while queueing an empty buffer to get CSD",
2065 mName);
2066 return UNKNOWN_ERROR;
2067 }
Wonsik Kim34b28b42022-05-20 15:49:32 -07002068 clientInputBuffers.erase(minIndex);
Wonsik Kim5ebfcb22021-01-05 18:58:15 -08002069 }
Pawin Vongmasae7bb8612020-06-04 06:15:22 -07002070
Wonsik Kim34b28b42022-05-20 15:49:32 -07002071 for (const auto &[index, buffer] : clientInputBuffers) {
2072 mCallback->onInputBufferAvailable(index, buffer);
Pawin Vongmasa36653902018-11-15 00:10:25 -08002073 }
Pawin Vongmasae7bb8612020-06-04 06:15:22 -07002074
Pawin Vongmasa36653902018-11-15 00:10:25 -08002075 return OK;
2076}
2077
2078void CCodecBufferChannel::stop() {
2079 mSync.stop();
2080 mFirstValidFrameIndex = mFrameIndex.load(std::memory_order_relaxed);
Harish Mahendrakar38a99c22024-02-26 20:28:05 +05302081 mInfoBuffers.clear();
Pawin Vongmasa36653902018-11-15 00:10:25 -08002082}
2083
Sungtak Lee99144332023-01-26 11:03:14 +00002084void CCodecBufferChannel::stopUseOutputSurface(bool pushBlankBuffer) {
2085 sp<Surface> surface = mOutputSurface.lock()->surface;
2086 if (surface) {
Sungtak Leed964e2e2022-07-30 08:43:58 +00002087 C2BlockPool::local_id_t outputPoolId;
2088 {
2089 Mutexed<BlockPools>::Locked pools(mBlockPools);
2090 outputPoolId = pools->outputPoolId;
2091 }
2092 if (mComponent) mComponent->stopUsingOutputSurface(outputPoolId);
Sungtak Lee99144332023-01-26 11:03:14 +00002093
2094 if (pushBlankBuffer) {
2095 sp<ANativeWindow> anw = static_cast<ANativeWindow *>(surface.get());
2096 if (anw) {
2097 pushBlankBuffersToNativeWindow(anw.get());
2098 }
2099 }
Sungtak Leed964e2e2022-07-30 08:43:58 +00002100 }
2101}
2102
Wonsik Kim936a89c2020-05-08 16:07:50 -07002103void CCodecBufferChannel::reset() {
2104 stop();
Wonsik Kimd4ba8462024-07-12 11:05:48 -07002105 mInputSurface.lock()->reset();
Wonsik Kim62545252021-01-20 11:25:41 -08002106 mPipelineWatcher.lock()->flush();
Wonsik Kim936a89c2020-05-08 16:07:50 -07002107 {
2108 Mutexed<Input>::Locked input(mInput);
2109 input->buffers.reset(new DummyInputBuffers(""));
Wonsik Kima2e3cdd2020-05-20 15:14:42 -07002110 input->extraBuffers.flush();
Wonsik Kim936a89c2020-05-08 16:07:50 -07002111 }
2112 {
2113 Mutexed<Output>::Locked output(mOutput);
2114 output->buffers.reset();
2115 }
Brian Lindahl932bf602023-03-09 11:59:48 -07002116 // reset the frames that are being tracked for onFrameRendered callbacks
2117 mTrackedFrames.clear();
Wonsik Kim936a89c2020-05-08 16:07:50 -07002118}
2119
2120void CCodecBufferChannel::release() {
Harish Mahendrakar38a99c22024-02-26 20:28:05 +05302121 mInfoBuffers.clear();
Wonsik Kim936a89c2020-05-08 16:07:50 -07002122 mComponent.reset();
2123 mInputAllocator.reset();
2124 mOutputSurface.lock()->surface.clear();
2125 {
2126 Mutexed<BlockPools>::Locked blockPools{mBlockPools};
2127 blockPools->inputPool.reset();
2128 blockPools->outputPoolIntf.reset();
2129 }
Wonsik Kima2e3cdd2020-05-20 15:14:42 -07002130 setCrypto(nullptr);
2131 setDescrambler(nullptr);
Wonsik Kim936a89c2020-05-08 16:07:50 -07002132}
2133
Pawin Vongmasa36653902018-11-15 00:10:25 -08002134void CCodecBufferChannel::flush(const std::list<std::unique_ptr<C2Work>> &flushedWork) {
2135 ALOGV("[%s] flush", mName);
Wonsik Kim5ebfcb22021-01-05 18:58:15 -08002136 std::list<std::unique_ptr<C2Work>> configs;
Wonsik Kim6b2c8be2021-09-28 05:11:04 -07002137 mInput.lock()->lastFlushIndex = mFrameIndex.load(std::memory_order_relaxed);
Wonsik Kim92df7e42021-11-04 16:02:03 -07002138 {
2139 Mutexed<PipelineWatcher>::Locked watcher(mPipelineWatcher);
2140 for (const std::unique_ptr<C2Work> &work : flushedWork) {
2141 uint64_t frameIndex = work->input.ordinal.frameIndex.peeku();
2142 if (!(work->input.flags & C2FrameData::FLAG_CODEC_CONFIG)) {
2143 watcher->onWorkDone(frameIndex);
2144 continue;
2145 }
2146 if (work->input.buffers.empty()
2147 || work->input.buffers.front() == nullptr
2148 || work->input.buffers.front()->data().linearBlocks().empty()) {
2149 ALOGD("[%s] no linear codec config data found", mName);
2150 watcher->onWorkDone(frameIndex);
2151 continue;
2152 }
2153 std::unique_ptr<C2Work> copy(new C2Work);
2154 copy->input.flags = C2FrameData::flags_t(
2155 work->input.flags | C2FrameData::FLAG_DROP_FRAME);
2156 copy->input.ordinal = work->input.ordinal;
2157 copy->input.ordinal.frameIndex = mFrameIndex++;
2158 for (size_t i = 0; i < work->input.buffers.size(); ++i) {
2159 copy->input.buffers.push_back(watcher->onInputBufferReleased(frameIndex, i));
2160 }
2161 for (const std::unique_ptr<C2Param> &param : work->input.configUpdate) {
2162 copy->input.configUpdate.push_back(C2Param::Copy(*param));
2163 }
2164 copy->input.infoBuffers.insert(
2165 copy->input.infoBuffers.begin(),
2166 work->input.infoBuffers.begin(),
2167 work->input.infoBuffers.end());
2168 copy->worklets.emplace_back(new C2Worklet);
2169 configs.push_back(std::move(copy));
2170 watcher->onWorkDone(frameIndex);
2171 ALOGV("[%s] stashed flushed codec config data", mName);
Pawin Vongmasa36653902018-11-15 00:10:25 -08002172 }
2173 }
Wonsik Kim5ebfcb22021-01-05 18:58:15 -08002174 mFlushedConfigs.lock()->swap(configs);
Pawin Vongmasa36653902018-11-15 00:10:25 -08002175 {
Wonsik Kim5ecf3832019-04-18 10:28:58 -07002176 Mutexed<Input>::Locked input(mInput);
2177 input->buffers->flush();
2178 input->extraBuffers.flush();
Pawin Vongmasa36653902018-11-15 00:10:25 -08002179 }
2180 {
Wonsik Kim5ecf3832019-04-18 10:28:58 -07002181 Mutexed<Output>::Locked output(mOutput);
Wonsik Kim936a89c2020-05-08 16:07:50 -07002182 if (output->buffers) {
2183 output->buffers->flush(flushedWork);
Pawin Vongmasa9b906982020-04-11 05:07:15 -07002184 output->buffers->flushStash();
Wonsik Kim936a89c2020-05-08 16:07:50 -07002185 }
Pawin Vongmasa36653902018-11-15 00:10:25 -08002186 }
Harish Mahendrakar38a99c22024-02-26 20:28:05 +05302187 mInfoBuffers.clear();
Pawin Vongmasa36653902018-11-15 00:10:25 -08002188}
2189
2190void CCodecBufferChannel::onWorkDone(
2191 std::unique_ptr<C2Work> work, const sp<AMessage> &outputFormat,
Wonsik Kimab34ed62019-01-31 15:28:46 -08002192 const C2StreamInitDataInfo::output *initData) {
Pawin Vongmasa36653902018-11-15 00:10:25 -08002193 if (handleWork(std::move(work), outputFormat, initData)) {
Pawin Vongmasa36653902018-11-15 00:10:25 -08002194 feedInputBufferIfAvailable();
2195 }
2196}
2197
2198void CCodecBufferChannel::onInputBufferDone(
Wonsik Kimab34ed62019-01-31 15:28:46 -08002199 uint64_t frameIndex, size_t arrayIndex) {
Wonsik Kimd4ba8462024-07-12 11:05:48 -07002200 if (mInputSurface.lock()->get()) {
Pawin Vongmasa8e2cfb52019-05-15 05:20:52 -07002201 return;
2202 }
Wonsik Kimab34ed62019-01-31 15:28:46 -08002203 std::shared_ptr<C2Buffer> buffer =
2204 mPipelineWatcher.lock()->onInputBufferReleased(frameIndex, arrayIndex);
Wonsik Kim6b2c8be2021-09-28 05:11:04 -07002205 bool newInputSlotAvailable = false;
Pawin Vongmasa36653902018-11-15 00:10:25 -08002206 {
Wonsik Kim5ecf3832019-04-18 10:28:58 -07002207 Mutexed<Input>::Locked input(mInput);
Wonsik Kim6b2c8be2021-09-28 05:11:04 -07002208 if (input->lastFlushIndex >= frameIndex) {
2209 ALOGD("[%s] Ignoring stale input buffer done callback: "
2210 "last flush index = %lld, frameIndex = %lld",
2211 mName, input->lastFlushIndex.peekll(), (long long)frameIndex);
2212 } else {
2213 newInputSlotAvailable = input->buffers->expireComponentBuffer(buffer);
2214 if (!newInputSlotAvailable) {
2215 (void)input->extraBuffers.expireComponentBuffer(buffer);
2216 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -07002217 }
Pawin Vongmasa36653902018-11-15 00:10:25 -08002218 }
2219 if (newInputSlotAvailable) {
2220 feedInputBufferIfAvailable();
2221 }
2222}
2223
2224bool CCodecBufferChannel::handleWork(
2225 std::unique_ptr<C2Work> work,
2226 const sp<AMessage> &outputFormat,
2227 const C2StreamInitDataInfo::output *initData) {
Wonsik Kim936a89c2020-05-08 16:07:50 -07002228 {
Wonsik Kima4e049d2020-04-28 19:42:23 +00002229 Mutexed<Output>::Locked output(mOutput);
Wonsik Kim936a89c2020-05-08 16:07:50 -07002230 if (!output->buffers) {
2231 return false;
2232 }
Wonsik Kime75a5da2020-02-14 17:29:03 -08002233 }
2234
Pawin Vongmasa9b906982020-04-11 05:07:15 -07002235 // Whether the output buffer should be reported to the client or not.
2236 bool notifyClient = false;
2237
2238 if (work->result == C2_OK){
2239 notifyClient = true;
2240 } else if (work->result == C2_NOT_FOUND) {
2241 ALOGD("[%s] flushed work; ignored.", mName);
2242 } else {
2243 // C2_OK and C2_NOT_FOUND are the only results that we accept for processing
2244 // the config update.
2245 ALOGD("[%s] work failed to complete: %d", mName, work->result);
2246 mCCodecCallback->onError(work->result, ACTION_CODE_FATAL);
2247 return false;
2248 }
2249
2250 if ((work->input.ordinal.frameIndex -
2251 mFirstValidFrameIndex.load()).peek() < 0) {
Pawin Vongmasa36653902018-11-15 00:10:25 -08002252 // Discard frames from previous generation.
2253 ALOGD("[%s] Discard frames from previous generation.", mName);
Pawin Vongmasa9b906982020-04-11 05:07:15 -07002254 notifyClient = false;
Pawin Vongmasa36653902018-11-15 00:10:25 -08002255 }
2256
Wonsik Kimd4ba8462024-07-12 11:05:48 -07002257 bool hasInputSurface = (mInputSurface.lock()->get() != nullptr);
2258 if (!hasInputSurface && (work->worklets.size() != 1u
Pawin Vongmasa36653902018-11-15 00:10:25 -08002259 || !work->worklets.front()
Pawin Vongmasa9b906982020-04-11 05:07:15 -07002260 || !(work->worklets.front()->output.flags &
2261 C2FrameData::FLAG_INCOMPLETE))) {
2262 mPipelineWatcher.lock()->onWorkDone(
2263 work->input.ordinal.frameIndex.peeku());
Pawin Vongmasa36653902018-11-15 00:10:25 -08002264 }
2265
2266 // NOTE: MediaCodec usage supposedly have only one worklet
2267 if (work->worklets.size() != 1u) {
2268 ALOGI("[%s] onWorkDone: incorrect number of worklets: %zu",
2269 mName, work->worklets.size());
2270 mCCodecCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL);
2271 return false;
2272 }
2273
2274 const std::unique_ptr<C2Worklet> &worklet = work->worklets.front();
2275
2276 std::shared_ptr<C2Buffer> buffer;
2277 // NOTE: MediaCodec usage supposedly have only one output stream.
2278 if (worklet->output.buffers.size() > 1u) {
2279 ALOGI("[%s] onWorkDone: incorrect number of output buffers: %zu",
2280 mName, worklet->output.buffers.size());
2281 mCCodecCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL);
2282 return false;
2283 } else if (worklet->output.buffers.size() == 1u) {
2284 buffer = worklet->output.buffers[0];
2285 if (!buffer) {
2286 ALOGD("[%s] onWorkDone: nullptr found in buffers; ignored.", mName);
2287 }
2288 }
2289
Wonsik Kim3dedf682021-05-03 10:57:09 -07002290 std::optional<uint32_t> newInputDelay, newPipelineDelay, newOutputDelay, newReorderDepth;
2291 std::optional<C2Config::ordinal_key_t> newReorderKey;
Wonsik Kim315e40a2020-09-09 14:11:50 -07002292 bool needMaxDequeueBufferCountUpdate = false;
Pawin Vongmasa36653902018-11-15 00:10:25 -08002293 while (!worklet->output.configUpdate.empty()) {
2294 std::unique_ptr<C2Param> param;
2295 worklet->output.configUpdate.back().swap(param);
2296 worklet->output.configUpdate.pop_back();
2297 switch (param->coreIndex().coreIndex()) {
2298 case C2PortReorderBufferDepthTuning::CORE_INDEX: {
2299 C2PortReorderBufferDepthTuning::output reorderDepth;
2300 if (reorderDepth.updateFrom(*param)) {
Pawin Vongmasa36653902018-11-15 00:10:25 -08002301 ALOGV("[%s] onWorkDone: updated reorder depth to %u",
2302 mName, reorderDepth.value);
Wonsik Kim3dedf682021-05-03 10:57:09 -07002303 newReorderDepth = reorderDepth.value;
Wonsik Kim315e40a2020-09-09 14:11:50 -07002304 needMaxDequeueBufferCountUpdate = true;
Pawin Vongmasa36653902018-11-15 00:10:25 -08002305 } else {
Pawin Vongmasa9b906982020-04-11 05:07:15 -07002306 ALOGD("[%s] onWorkDone: failed to read reorder depth",
2307 mName);
Pawin Vongmasa36653902018-11-15 00:10:25 -08002308 }
2309 break;
2310 }
2311 case C2PortReorderKeySetting::CORE_INDEX: {
2312 C2PortReorderKeySetting::output reorderKey;
2313 if (reorderKey.updateFrom(*param)) {
Wonsik Kim3dedf682021-05-03 10:57:09 -07002314 newReorderKey = reorderKey.value;
Pawin Vongmasa36653902018-11-15 00:10:25 -08002315 ALOGV("[%s] onWorkDone: updated reorder key to %u",
2316 mName, reorderKey.value);
2317 } else {
2318 ALOGD("[%s] onWorkDone: failed to read reorder key", mName);
2319 }
2320 break;
2321 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -07002322 case C2PortActualDelayTuning::CORE_INDEX: {
2323 if (param->isGlobal()) {
2324 C2ActualPipelineDelayTuning pipelineDelay;
2325 if (pipelineDelay.updateFrom(*param)) {
2326 ALOGV("[%s] onWorkDone: updating pipeline delay %u",
2327 mName, pipelineDelay.value);
2328 newPipelineDelay = pipelineDelay.value;
Pawin Vongmasa9b906982020-04-11 05:07:15 -07002329 (void)mPipelineWatcher.lock()->pipelineDelay(
2330 pipelineDelay.value);
Wonsik Kim5ecf3832019-04-18 10:28:58 -07002331 }
2332 }
2333 if (param->forInput()) {
2334 C2PortActualDelayTuning::input inputDelay;
2335 if (inputDelay.updateFrom(*param)) {
2336 ALOGV("[%s] onWorkDone: updating input delay %u",
2337 mName, inputDelay.value);
2338 newInputDelay = inputDelay.value;
Pawin Vongmasa9b906982020-04-11 05:07:15 -07002339 (void)mPipelineWatcher.lock()->inputDelay(
2340 inputDelay.value);
Wonsik Kim5ecf3832019-04-18 10:28:58 -07002341 }
2342 }
2343 if (param->forOutput()) {
2344 C2PortActualDelayTuning::output outputDelay;
2345 if (outputDelay.updateFrom(*param)) {
2346 ALOGV("[%s] onWorkDone: updating output delay %u",
2347 mName, outputDelay.value);
Wonsik Kim315e40a2020-09-09 14:11:50 -07002348 (void)mPipelineWatcher.lock()->outputDelay(outputDelay.value);
Wonsik Kim3dedf682021-05-03 10:57:09 -07002349 newOutputDelay = outputDelay.value;
Wonsik Kim315e40a2020-09-09 14:11:50 -07002350 needMaxDequeueBufferCountUpdate = true;
Wonsik Kim5ecf3832019-04-18 10:28:58 -07002351
Wonsik Kim5ecf3832019-04-18 10:28:58 -07002352 }
2353 }
2354 break;
2355 }
ted.sunb1fbfdb2020-06-23 14:03:41 +08002356 case C2PortTunnelSystemTime::CORE_INDEX: {
2357 C2PortTunnelSystemTime::output frameRenderTime;
2358 if (frameRenderTime.updateFrom(*param)) {
2359 ALOGV("[%s] onWorkDone: frame rendered (sys:%lld ns, media:%lld us)",
2360 mName, (long long)frameRenderTime.value,
2361 (long long)worklet->output.ordinal.timestamp.peekll());
2362 mCCodecCallback->onOutputFramesRendered(
2363 worklet->output.ordinal.timestamp.peek(), frameRenderTime.value);
2364 }
2365 break;
2366 }
Guillaume Chelfi867d4dd2021-07-01 18:38:45 +02002367 case C2StreamTunnelHoldRender::CORE_INDEX: {
2368 C2StreamTunnelHoldRender::output firstTunnelFrameHoldRender;
2369 if (!(worklet->output.flags & C2FrameData::FLAG_INCOMPLETE)) break;
2370 if (!firstTunnelFrameHoldRender.updateFrom(*param)) break;
2371 if (firstTunnelFrameHoldRender.value != C2_TRUE) break;
2372 ALOGV("[%s] onWorkDone: first tunnel frame ready", mName);
2373 mCCodecCallback->onFirstTunnelFrameReady();
2374 break;
2375 }
Pawin Vongmasa36653902018-11-15 00:10:25 -08002376 default:
2377 ALOGV("[%s] onWorkDone: unrecognized config update (%08X)",
2378 mName, param->index());
2379 break;
2380 }
2381 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -07002382 if (newInputDelay || newPipelineDelay) {
2383 Mutexed<Input>::Locked input(mInput);
2384 size_t newNumSlots =
2385 newInputDelay.value_or(input->inputDelay) +
2386 newPipelineDelay.value_or(input->pipelineDelay) +
2387 kSmoothnessFactor;
Xu Lai5732cab2023-03-16 19:50:18 +08002388 input->inputDelay = newInputDelay.value_or(input->inputDelay);
Wonsik Kim5ecf3832019-04-18 10:28:58 -07002389 if (input->buffers->isArrayMode()) {
2390 if (input->numSlots >= newNumSlots) {
2391 input->numExtraSlots = 0;
2392 } else {
2393 input->numExtraSlots = newNumSlots - input->numSlots;
2394 }
2395 ALOGV("[%s] onWorkDone: updated number of extra slots to %zu (input array mode)",
2396 mName, input->numExtraSlots);
2397 } else {
2398 input->numSlots = newNumSlots;
2399 }
2400 }
Wonsik Kim3dedf682021-05-03 10:57:09 -07002401 size_t numOutputSlots = 0;
2402 uint32_t reorderDepth = 0;
2403 bool outputBuffersChanged = false;
2404 if (newReorderKey || newReorderDepth || needMaxDequeueBufferCountUpdate) {
2405 Mutexed<Output>::Locked output(mOutput);
2406 if (!output->buffers) {
2407 return false;
Wonsik Kim315e40a2020-09-09 14:11:50 -07002408 }
Wonsik Kim3dedf682021-05-03 10:57:09 -07002409 numOutputSlots = output->numSlots;
2410 if (newReorderKey) {
2411 output->buffers->setReorderKey(newReorderKey.value());
2412 }
2413 if (newReorderDepth) {
2414 output->buffers->setReorderDepth(newReorderDepth.value());
2415 }
2416 reorderDepth = output->buffers->getReorderDepth();
2417 if (newOutputDelay) {
2418 output->outputDelay = newOutputDelay.value();
2419 numOutputSlots = newOutputDelay.value() + kSmoothnessFactor;
2420 if (output->numSlots < numOutputSlots) {
2421 output->numSlots = numOutputSlots;
2422 if (output->buffers->isArrayMode()) {
2423 OutputBuffersArray *array =
2424 (OutputBuffersArray *)output->buffers.get();
2425 ALOGV("[%s] onWorkDone: growing output buffer array to %zu",
2426 mName, numOutputSlots);
2427 array->grow(numOutputSlots);
2428 outputBuffersChanged = true;
2429 }
2430 }
2431 }
2432 numOutputSlots = output->numSlots;
2433 }
2434 if (outputBuffersChanged) {
2435 mCCodecCallback->onOutputBuffersChanged();
2436 }
2437 if (needMaxDequeueBufferCountUpdate) {
Wonsik Kim84f439f2021-05-03 10:57:09 -07002438 int maxDequeueCount = 0;
Sungtak Leea714f112021-03-16 05:40:03 -07002439 {
2440 Mutexed<OutputSurface>::Locked output(mOutputSurface);
2441 maxDequeueCount = output->maxDequeueBuffers =
Wonsik Kim3a692e62023-05-19 15:37:22 -07002442 numOutputSlots + reorderDepth + mRenderingDepth;
Sungtak Leea714f112021-03-16 05:40:03 -07002443 if (output->surface) {
2444 output->surface->setMaxDequeuedBufferCount(output->maxDequeueBuffers);
2445 }
2446 }
2447 if (maxDequeueCount > 0) {
2448 mComponent->setOutputSurfaceMaxDequeueCount(maxDequeueCount);
Wonsik Kim315e40a2020-09-09 14:11:50 -07002449 }
2450 }
Pawin Vongmasa36653902018-11-15 00:10:25 -08002451
Pawin Vongmasa36653902018-11-15 00:10:25 -08002452 int32_t flags = 0;
2453 if (worklet->output.flags & C2FrameData::FLAG_END_OF_STREAM) {
My Named4d22242022-03-28 13:53:32 -07002454 flags |= BUFFER_FLAG_END_OF_STREAM;
Pawin Vongmasa36653902018-11-15 00:10:25 -08002455 ALOGV("[%s] onWorkDone: output EOS", mName);
2456 }
2457
Pawin Vongmasa36653902018-11-15 00:10:25 -08002458 // WORKAROUND: adjust output timestamp based on client input timestamp and codec
2459 // input timestamp. Codec output timestamp (in the timestamp field) shall correspond to
2460 // the codec input timestamp, but client output timestamp should (reported in timeUs)
2461 // shall correspond to the client input timesamp (in customOrdinal). By using the
2462 // delta between the two, this allows for some timestamp deviation - e.g. if one input
2463 // produces multiple output.
2464 c2_cntr64_t timestamp =
2465 worklet->output.ordinal.timestamp + work->input.ordinal.customOrdinal
2466 - work->input.ordinal.timestamp;
Wonsik Kimd4ba8462024-07-12 11:05:48 -07002467 if (hasInputSurface) {
Wonsik Kim95ba0162019-03-19 15:51:54 -07002468 // When using input surface we need to restore the original input timestamp.
2469 timestamp = work->input.ordinal.customOrdinal;
2470 }
My Name6bd9a7d2022-03-25 12:37:58 -07002471 ScopedTrace trace(ATRACE_TAG, android::base::StringPrintf(
2472 "CCodecBufferChannel::onWorkDone(%s@ts=%lld)", mName, timestamp.peekll()).c_str());
Pawin Vongmasa36653902018-11-15 00:10:25 -08002473 ALOGV("[%s] onWorkDone: input %lld, codec %lld => output %lld => %lld",
2474 mName,
2475 work->input.ordinal.customOrdinal.peekll(),
2476 work->input.ordinal.timestamp.peekll(),
2477 worklet->output.ordinal.timestamp.peekll(),
2478 timestamp.peekll());
2479
Pawin Vongmasa9b906982020-04-11 05:07:15 -07002480 // csd cannot be re-ordered and will always arrive first.
Pawin Vongmasa36653902018-11-15 00:10:25 -08002481 if (initData != nullptr) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -07002482 Mutexed<Output>::Locked output(mOutput);
Wonsik Kim72a71012023-02-06 17:35:21 -08002483 if (!output->buffers) {
2484 return false;
2485 }
2486 if (outputFormat) {
Pawin Vongmasa9b906982020-04-11 05:07:15 -07002487 output->buffers->updateSkipCutBuffer(outputFormat);
2488 output->buffers->setFormat(outputFormat);
2489 }
2490 if (!notifyClient) {
2491 return false;
2492 }
2493 size_t index;
2494 sp<MediaCodecBuffer> outBuffer;
Wonsik Kim72a71012023-02-06 17:35:21 -08002495 if (output->buffers->registerCsd(initData, &index, &outBuffer) == OK) {
Pawin Vongmasa36653902018-11-15 00:10:25 -08002496 outBuffer->meta()->setInt64("timeUs", timestamp.peek());
My Named4d22242022-03-28 13:53:32 -07002497 outBuffer->meta()->setInt32("flags", BUFFER_FLAG_CODEC_CONFIG);
Pawin Vongmasa36653902018-11-15 00:10:25 -08002498 ALOGV("[%s] onWorkDone: csd index = %zu [%p]", mName, index, outBuffer.get());
2499
Wonsik Kim5c2c8902023-05-09 10:53:15 -07002500 // TRICKY: we want popped buffers reported in order, so sending
2501 // the callback while holding the lock here. This assumes that
2502 // onOutputBufferAvailable() does not block. onOutputBufferAvailable()
2503 // callbacks are always sent with the Output lock held.
Pawin Vongmasa36653902018-11-15 00:10:25 -08002504 mCallback->onOutputBufferAvailable(index, outBuffer);
Pawin Vongmasa36653902018-11-15 00:10:25 -08002505 } else {
2506 ALOGD("[%s] onWorkDone: unable to register csd", mName);
Wonsik Kim5ecf3832019-04-18 10:28:58 -07002507 output.unlock();
Pawin Vongmasa36653902018-11-15 00:10:25 -08002508 mCCodecCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL);
Pawin Vongmasa36653902018-11-15 00:10:25 -08002509 return false;
2510 }
2511 }
2512
Wonsik Kimec585c32021-10-01 01:11:00 -07002513 bool drop = false;
2514 if (worklet->output.flags & C2FrameData::FLAG_DROP_FRAME) {
2515 ALOGV("[%s] onWorkDone: drop buffer but keep metadata", mName);
2516 drop = true;
2517 }
2518
Marc Kassisec910342022-11-25 11:43:05 +01002519 // Workaround: if C2FrameData::FLAG_DROP_FRAME is not implemented in
2520 // HAL, the flag is then removed in the corresponding output buffer.
2521 if (work->input.flags & C2FrameData::FLAG_DROP_FRAME) {
2522 flags |= BUFFER_FLAG_DECODE_ONLY;
2523 }
2524
Pawin Vongmasa9b906982020-04-11 05:07:15 -07002525 if (notifyClient && !buffer && !flags) {
Wonsik Kimec585c32021-10-01 01:11:00 -07002526 if (mTunneled && drop && outputFormat) {
Houxiang Daie74e5062022-05-19 15:32:54 +08002527 if (mOutputFormat != outputFormat) {
2528 ALOGV("[%s] onWorkDone: Keep tunneled, drop frame with format change (%lld)",
2529 mName, work->input.ordinal.frameIndex.peekull());
2530 mOutputFormat = outputFormat;
2531 } else {
2532 ALOGV("[%s] onWorkDone: Not reporting output buffer without format change (%lld)",
2533 mName, work->input.ordinal.frameIndex.peekull());
2534 notifyClient = false;
2535 }
Wonsik Kimec585c32021-10-01 01:11:00 -07002536 } else {
2537 ALOGV("[%s] onWorkDone: Not reporting output buffer (%lld)",
2538 mName, work->input.ordinal.frameIndex.peekull());
2539 notifyClient = false;
2540 }
Pawin Vongmasa36653902018-11-15 00:10:25 -08002541 }
2542
2543 if (buffer) {
2544 for (const std::shared_ptr<const C2Info> &info : buffer->info()) {
2545 // TODO: properly translate these to metadata
2546 switch (info->coreIndex().coreIndex()) {
2547 case C2StreamPictureTypeMaskInfo::CORE_INDEX:
Lajos Molnar3bb81cd2019-02-20 15:10:30 -08002548 if (((C2StreamPictureTypeMaskInfo *)info.get())->value & C2Config::SYNC_FRAME) {
My Named4d22242022-03-28 13:53:32 -07002549 flags |= BUFFER_FLAG_KEY_FRAME;
Pawin Vongmasa36653902018-11-15 00:10:25 -08002550 }
2551 break;
2552 default:
2553 break;
2554 }
2555 }
2556 }
2557
2558 {
Pawin Vongmasa9b906982020-04-11 05:07:15 -07002559 Mutexed<Output>::Locked output(mOutput);
Wonsik Kimc23cc402020-05-28 14:53:40 -07002560 if (!output->buffers) {
2561 return false;
2562 }
Pawin Vongmasa9b906982020-04-11 05:07:15 -07002563 output->buffers->pushToStash(
2564 buffer,
2565 notifyClient,
2566 timestamp.peek(),
2567 flags,
2568 outputFormat,
2569 worklet->output.ordinal);
Pawin Vongmasa36653902018-11-15 00:10:25 -08002570 }
2571 sendOutputBuffers();
2572 return true;
2573}
2574
2575void CCodecBufferChannel::sendOutputBuffers() {
Pawin Vongmasa9b906982020-04-11 05:07:15 -07002576 OutputBuffers::BufferAction action;
Wonsik Kima4e049d2020-04-28 19:42:23 +00002577 size_t index;
Pawin Vongmasa9b906982020-04-11 05:07:15 -07002578 sp<MediaCodecBuffer> outBuffer;
2579 std::shared_ptr<C2Buffer> c2Buffer;
Pawin Vongmasa36653902018-11-15 00:10:25 -08002580
Sungtak Lee8ceef4d2022-06-15 00:49:26 +00002581 constexpr int kMaxReallocTry = 5;
2582 int reallocTryNum = 0;
2583
Pawin Vongmasa36653902018-11-15 00:10:25 -08002584 while (true) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -07002585 Mutexed<Output>::Locked output(mOutput);
Wonsik Kim936a89c2020-05-08 16:07:50 -07002586 if (!output->buffers) {
2587 return;
2588 }
Pawin Vongmasa9b906982020-04-11 05:07:15 -07002589 action = output->buffers->popFromStashAndRegister(
2590 &c2Buffer, &index, &outBuffer);
Sungtak Lee8ceef4d2022-06-15 00:49:26 +00002591 if (action != OutputBuffers::REALLOCATE) {
2592 reallocTryNum = 0;
2593 }
Pawin Vongmasa9b906982020-04-11 05:07:15 -07002594 switch (action) {
2595 case OutputBuffers::SKIP:
2596 return;
2597 case OutputBuffers::DISCARD:
2598 break;
2599 case OutputBuffers::NOTIFY_CLIENT:
Arun Johnsonf4a81f72023-11-09 21:22:48 +00002600 {
Wonsik Kim5c2c8902023-05-09 10:53:15 -07002601 // TRICKY: we want popped buffers reported in order, so sending
2602 // the callback while holding the lock here. This assumes that
2603 // onOutputBufferAvailable() does not block. onOutputBufferAvailable()
2604 // callbacks are always sent with the Output lock held.
Arun Johnsonf4a81f72023-11-09 21:22:48 +00002605 if (c2Buffer) {
2606 std::shared_ptr<const C2AccessUnitInfos::output> bufferMetadata =
2607 std::static_pointer_cast<const C2AccessUnitInfos::output>(
2608 c2Buffer->getInfo(C2AccessUnitInfos::output::PARAM_TYPE));
2609 if (bufferMetadata && bufferMetadata->flexCount() > 0) {
2610 uint32_t flag = 0;
2611 std::vector<AccessUnitInfo> accessUnitInfos;
2612 for (int nMeta = 0; nMeta < bufferMetadata->flexCount(); nMeta++) {
2613 const C2AccessUnitInfosStruct &bufferMetadataStruct =
2614 bufferMetadata->m.values[nMeta];
2615 flag = convertFlags(bufferMetadataStruct.flags, false);
2616 accessUnitInfos.emplace_back(flag,
2617 static_cast<size_t>(bufferMetadataStruct.size),
2618 static_cast<size_t>(bufferMetadataStruct.timestamp));
2619 }
2620 sp<WrapperObject<std::vector<AccessUnitInfo>>> obj{
2621 new WrapperObject<std::vector<AccessUnitInfo>>{accessUnitInfos}};
2622 outBuffer->meta()->setObject("accessUnitInfo", obj);
2623 }
2624 }
Pawin Vongmasa9b906982020-04-11 05:07:15 -07002625 mCallback->onOutputBufferAvailable(index, outBuffer);
2626 break;
Arun Johnsonf4a81f72023-11-09 21:22:48 +00002627 }
Pawin Vongmasa9b906982020-04-11 05:07:15 -07002628 case OutputBuffers::REALLOCATE:
Sungtak Lee8ceef4d2022-06-15 00:49:26 +00002629 if (++reallocTryNum > kMaxReallocTry) {
2630 output.unlock();
2631 ALOGE("[%s] sendOutputBuffers: tried %d realloc and failed",
2632 mName, kMaxReallocTry);
2633 mCCodecCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL);
2634 return;
2635 }
Pawin Vongmasa9b906982020-04-11 05:07:15 -07002636 if (!output->buffers->isArrayMode()) {
2637 output->buffers =
2638 output->buffers->toArrayMode(output->numSlots);
Pawin Vongmasa36653902018-11-15 00:10:25 -08002639 }
Pawin Vongmasa9b906982020-04-11 05:07:15 -07002640 static_cast<OutputBuffersArray*>(output->buffers.get())->
2641 realloc(c2Buffer);
2642 output.unlock();
2643 mCCodecCallback->onOutputBuffersChanged();
Wonsik Kim4ada73d2020-05-26 14:58:07 -07002644 break;
Pawin Vongmasa9b906982020-04-11 05:07:15 -07002645 case OutputBuffers::RETRY:
2646 ALOGV("[%s] sendOutputBuffers: unable to register output buffer",
2647 mName);
2648 return;
2649 default:
2650 LOG_ALWAYS_FATAL("[%s] sendOutputBuffers: "
2651 "corrupted BufferAction value (%d) "
2652 "returned from popFromStashAndRegister.",
2653 mName, int(action));
Pawin Vongmasa36653902018-11-15 00:10:25 -08002654 return;
2655 }
Pawin Vongmasa36653902018-11-15 00:10:25 -08002656 }
2657}
2658
Sungtak Lee214ce612023-11-01 10:01:13 +00002659status_t CCodecBufferChannel::setSurface(const sp<Surface> &newSurface,
2660 uint32_t generation, bool pushBlankBuffer) {
Pawin Vongmasa36653902018-11-15 00:10:25 -08002661 sp<IGraphicBufferProducer> producer;
Sungtak Lee99144332023-01-26 11:03:14 +00002662 int maxDequeueCount;
2663 sp<Surface> oldSurface;
2664 {
2665 Mutexed<OutputSurface>::Locked outputSurface(mOutputSurface);
2666 maxDequeueCount = outputSurface->maxDequeueBuffers;
2667 oldSurface = outputSurface->surface;
2668 }
Pawin Vongmasa36653902018-11-15 00:10:25 -08002669 if (newSurface) {
2670 newSurface->setScalingMode(NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
Sungtak Leeab6f2f32019-02-15 14:43:51 -08002671 newSurface->setDequeueTimeout(kDequeueTimeoutNs);
Sungtak Leedb14cba2021-04-10 00:50:23 -07002672 newSurface->setMaxDequeuedBufferCount(maxDequeueCount);
Pawin Vongmasa36653902018-11-15 00:10:25 -08002673 producer = newSurface->getIGraphicBufferProducer();
Pawin Vongmasa36653902018-11-15 00:10:25 -08002674 } else {
2675 ALOGE("[%s] setting output surface to null", mName);
2676 return INVALID_OPERATION;
2677 }
2678
2679 std::shared_ptr<Codec2Client::Configurable> outputPoolIntf;
2680 C2BlockPool::local_id_t outputPoolId;
2681 {
2682 Mutexed<BlockPools>::Locked pools(mBlockPools);
2683 outputPoolId = pools->outputPoolId;
2684 outputPoolIntf = pools->outputPoolIntf;
2685 }
2686
2687 if (outputPoolIntf) {
2688 if (mComponent->setOutputSurface(
2689 outputPoolId,
2690 producer,
Sungtak Leedb14cba2021-04-10 00:50:23 -07002691 generation,
2692 maxDequeueCount) != C2_OK) {
Pawin Vongmasa36653902018-11-15 00:10:25 -08002693 ALOGI("[%s] setSurface: component setOutputSurface failed", mName);
2694 return INVALID_OPERATION;
2695 }
2696 }
2697
2698 {
2699 Mutexed<OutputSurface>::Locked output(mOutputSurface);
2700 output->surface = newSurface;
2701 output->generation = generation;
Brian Lindahl932bf602023-03-09 11:59:48 -07002702 initializeFrameTrackingFor(static_cast<ANativeWindow *>(newSurface.get()));
Pawin Vongmasa36653902018-11-15 00:10:25 -08002703 }
2704
Sungtak Lee99144332023-01-26 11:03:14 +00002705 if (oldSurface && pushBlankBuffer) {
2706 // When ReleaseSurface was set from MediaCodec,
2707 // pushing a blank buffer at the end might be necessary.
2708 sp<ANativeWindow> anw = static_cast<ANativeWindow *>(oldSurface.get());
2709 if (anw) {
2710 pushBlankBuffersToNativeWindow(anw.get());
2711 }
2712 }
2713
Pawin Vongmasa36653902018-11-15 00:10:25 -08002714 return OK;
2715}
2716
Wonsik Kimab34ed62019-01-31 15:28:46 -08002717PipelineWatcher::Clock::duration CCodecBufferChannel::elapsed() {
Wonsik Kim4fa4f2b2019-02-13 11:02:58 -08002718 // Otherwise, component may have stalled work due to input starvation up to
2719 // the sum of the delay in the pipeline.
Wonsik Kim31512192022-05-02 18:22:37 -07002720 // TODO(b/231253301): When client pushed EOS, the pipeline could have less
2721 // number of frames.
Wonsik Kimf0e7d222019-06-28 12:33:16 -07002722 size_t n = 0;
Wonsik Kim31512192022-05-02 18:22:37 -07002723 size_t outputDelay = mOutput.lock()->outputDelay;
2724 {
Wonsik Kimf0e7d222019-06-28 12:33:16 -07002725 Mutexed<Input>::Locked input(mInput);
2726 n = input->inputDelay + input->pipelineDelay + outputDelay;
2727 }
Wonsik Kim4fa4f2b2019-02-13 11:02:58 -08002728 return mPipelineWatcher.lock()->elapsed(PipelineWatcher::Clock::now(), n);
Wonsik Kimab34ed62019-01-31 15:28:46 -08002729}
2730
Pawin Vongmasa36653902018-11-15 00:10:25 -08002731void CCodecBufferChannel::setMetaMode(MetaMode mode) {
2732 mMetaMode = mode;
2733}
2734
Wonsik Kim596187e2019-10-25 12:44:10 -07002735void CCodecBufferChannel::setCrypto(const sp<ICrypto> &crypto) {
Wonsik Kimfb7a7672019-12-27 17:13:33 -08002736 if (mCrypto != nullptr) {
2737 for (std::pair<wp<HidlMemory>, int32_t> entry : mHeapSeqNumMap) {
2738 mCrypto->unsetHeap(entry.second);
2739 }
2740 mHeapSeqNumMap.clear();
2741 if (mHeapSeqNum >= 0) {
2742 mCrypto->unsetHeap(mHeapSeqNum);
2743 mHeapSeqNum = -1;
2744 }
2745 }
Wonsik Kim596187e2019-10-25 12:44:10 -07002746 mCrypto = crypto;
2747}
2748
2749void CCodecBufferChannel::setDescrambler(const sp<IDescrambler> &descrambler) {
2750 mDescrambler = descrambler;
2751}
2752
Songyue Han1e6769b2023-08-30 18:09:27 +00002753uint32_t CCodecBufferChannel::getBuffersPixelFormat(bool isEncoder) {
2754 if (isEncoder) {
2755 return getInputBuffersPixelFormat();
2756 } else {
2757 return getOutputBuffersPixelFormat();
2758 }
2759}
2760
2761uint32_t CCodecBufferChannel::getInputBuffersPixelFormat() {
2762 Mutexed<Input>::Locked input(mInput);
2763 if (input->buffers == nullptr) {
2764 return PIXEL_FORMAT_UNKNOWN;
2765 }
2766 return input->buffers->getPixelFormatIfApplicable();
2767}
2768
2769uint32_t CCodecBufferChannel::getOutputBuffersPixelFormat() {
2770 Mutexed<Output>::Locked output(mOutput);
2771 if (output->buffers == nullptr) {
2772 return PIXEL_FORMAT_UNKNOWN;
2773 }
2774 return output->buffers->getPixelFormatIfApplicable();
2775}
2776
2777void CCodecBufferChannel::resetBuffersPixelFormat(bool isEncoder) {
2778 if (isEncoder) {
2779 Mutexed<Input>::Locked input(mInput);
2780 if (input->buffers == nullptr) {
2781 return;
2782 }
2783 input->buffers->resetPixelFormatIfApplicable();
2784 } else {
2785 Mutexed<Output>::Locked output(mOutput);
2786 if (output->buffers == nullptr) {
2787 return;
2788 }
2789 output->buffers->resetPixelFormatIfApplicable();
2790 }
2791}
2792
Harish Mahendrakar38a99c22024-02-26 20:28:05 +05302793void CCodecBufferChannel::setInfoBuffer(const std::shared_ptr<C2InfoBuffer> &buffer) {
Wonsik Kimd4ba8462024-07-12 11:05:48 -07002794 if (mInputSurface.lock()->get() == nullptr) {
Harish Mahendrakar2b095d92024-05-13 16:51:15 -07002795 mInfoBuffers.push_back(buffer);
2796 } else {
2797 std::list<std::unique_ptr<C2Work>> items;
2798 std::unique_ptr<C2Work> work(new C2Work);
2799 work->input.infoBuffers.emplace_back(*buffer);
2800 work->worklets.emplace_back(new C2Worklet);
2801 items.push_back(std::move(work));
2802 c2_status_t err = mComponent->queue(&items);
2803 }
Harish Mahendrakar38a99c22024-02-26 20:28:05 +05302804}
2805
Pawin Vongmasa36653902018-11-15 00:10:25 -08002806status_t toStatusT(c2_status_t c2s, c2_operation_t c2op) {
2807 // C2_OK is always translated to OK.
2808 if (c2s == C2_OK) {
2809 return OK;
2810 }
2811
2812 // Operation-dependent translation
2813 // TODO: Add as necessary
2814 switch (c2op) {
2815 case C2_OPERATION_Component_start:
2816 switch (c2s) {
2817 case C2_NO_MEMORY:
2818 return NO_MEMORY;
2819 default:
2820 return UNKNOWN_ERROR;
2821 }
2822 default:
2823 break;
2824 }
2825
2826 // Backup operation-agnostic translation
2827 switch (c2s) {
2828 case C2_BAD_INDEX:
2829 return BAD_INDEX;
2830 case C2_BAD_VALUE:
2831 return BAD_VALUE;
2832 case C2_BLOCKING:
2833 return WOULD_BLOCK;
2834 case C2_DUPLICATE:
2835 return ALREADY_EXISTS;
2836 case C2_NO_INIT:
2837 return NO_INIT;
2838 case C2_NO_MEMORY:
2839 return NO_MEMORY;
2840 case C2_NOT_FOUND:
2841 return NAME_NOT_FOUND;
2842 case C2_TIMED_OUT:
2843 return TIMED_OUT;
2844 case C2_BAD_STATE:
2845 case C2_CANCELED:
2846 case C2_CANNOT_DO:
2847 case C2_CORRUPTED:
2848 case C2_OMITTED:
2849 case C2_REFUSED:
2850 return UNKNOWN_ERROR;
2851 default:
2852 return -static_cast<status_t>(c2s);
2853 }
2854}
2855
Pawin Vongmasa36653902018-11-15 00:10:25 -08002856} // namespace android