blob: 20f2ecf080bf937e32e72570a3dd9adc29bcaec1 [file] [log] [blame]
Wonsik Kim469c8342019-04-11 16:46:09 -07001/*
2 * Copyright 2019, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17//#define LOG_NDEBUG 0
18#define LOG_TAG "CCodecBuffers"
19#include <utils/Log.h>
20
21#include <C2PlatformSupport.h>
22
23#include <media/stagefright/foundation/ADebug.h>
Wonsik Kim6f23cfc2021-09-24 05:45:52 -070024#include <media/stagefright/foundation/MediaDefs.h>
Pawin Vongmasa9b906982020-04-11 05:07:15 -070025#include <media/stagefright/MediaCodec.h>
Wonsik Kim469c8342019-04-11 16:46:09 -070026#include <media/stagefright/MediaCodecConstants.h>
Wonsik Kim155d5cb2019-10-09 12:49:49 -070027#include <media/stagefright/SkipCutBuffer.h>
Wonsik Kim41d83432020-04-27 16:40:49 -070028#include <mediadrm/ICrypto.h>
Wonsik Kim469c8342019-04-11 16:46:09 -070029
30#include "CCodecBuffers.h"
Wonsik Kimd79ee1f2020-08-27 17:41:56 -070031#include "Codec2Mapper.h"
Wonsik Kim469c8342019-04-11 16:46:09 -070032
33namespace android {
34
35namespace {
36
David Stevens94b608f2021-07-29 15:04:14 +090037sp<GraphicBlockBuffer> AllocateInputGraphicBuffer(
Wonsik Kim469c8342019-04-11 16:46:09 -070038 const std::shared_ptr<C2BlockPool> &pool,
39 const sp<AMessage> &format,
40 uint32_t pixelFormat,
41 const C2MemoryUsage &usage,
42 const std::shared_ptr<LocalBufferPool> &localBufferPool) {
43 int32_t width, height;
44 if (!format->findInt32("width", &width) || !format->findInt32("height", &height)) {
45 ALOGD("format lacks width or height");
46 return nullptr;
47 }
48
David Stevens94b608f2021-07-29 15:04:14 +090049 int64_t usageValue = 0;
50 (void)format->findInt64("android._C2MemoryUsage", &usageValue);
51 C2MemoryUsage fullUsage{usageValue | usage.expected};
52
Wonsik Kim469c8342019-04-11 16:46:09 -070053 std::shared_ptr<C2GraphicBlock> block;
54 c2_status_t err = pool->fetchGraphicBlock(
David Stevens94b608f2021-07-29 15:04:14 +090055 width, height, pixelFormat, fullUsage, &block);
Wonsik Kim469c8342019-04-11 16:46:09 -070056 if (err != C2_OK) {
57 ALOGD("fetch graphic block failed: %d", err);
58 return nullptr;
59 }
60
61 return GraphicBlockBuffer::Allocate(
62 format,
63 block,
64 [localBufferPool](size_t capacity) {
65 return localBufferPool->newBuffer(capacity);
66 });
67}
68
69} // namespace
70
71// CCodecBuffers
72
73void CCodecBuffers::setFormat(const sp<AMessage> &format) {
74 CHECK(format != nullptr);
75 mFormat = format;
76}
77
78sp<AMessage> CCodecBuffers::dupFormat() {
79 return mFormat != nullptr ? mFormat->dup() : nullptr;
80}
81
82void CCodecBuffers::handleImageData(const sp<Codec2Buffer> &buffer) {
83 sp<ABuffer> imageDataCandidate = buffer->getImageData();
84 if (imageDataCandidate == nullptr) {
Wonsik Kim4a3c0462021-03-09 15:45:05 -080085 if (mFormatWithImageData) {
86 // We previously sent the format with image data, so use the same format.
87 buffer->setFormat(mFormatWithImageData);
88 }
Wonsik Kim469c8342019-04-11 16:46:09 -070089 return;
90 }
Wonsik Kim4a3c0462021-03-09 15:45:05 -080091 if (!mLastImageData
92 || imageDataCandidate->size() != mLastImageData->size()
93 || memcmp(imageDataCandidate->data(),
94 mLastImageData->data(),
95 mLastImageData->size()) != 0) {
Wonsik Kim469c8342019-04-11 16:46:09 -070096 ALOGD("[%s] updating image-data", mName);
Wonsik Kim4a3c0462021-03-09 15:45:05 -080097 mFormatWithImageData = dupFormat();
98 mLastImageData = imageDataCandidate;
99 mFormatWithImageData->setBuffer("image-data", imageDataCandidate);
Wonsik Kim469c8342019-04-11 16:46:09 -0700100 MediaImage2 *img = (MediaImage2*)imageDataCandidate->data();
101 if (img->mNumPlanes > 0 && img->mType != img->MEDIA_IMAGE_TYPE_UNKNOWN) {
102 int32_t stride = img->mPlane[0].mRowInc;
Wonsik Kim4a3c0462021-03-09 15:45:05 -0800103 mFormatWithImageData->setInt32(KEY_STRIDE, stride);
Vinay Kaliaef5fc712021-09-15 23:59:50 +0000104 mFormatWithImageData->setInt32(KEY_WIDTH, img->mWidth);
105 mFormatWithImageData->setInt32(KEY_HEIGHT, img->mHeight);
106 ALOGD("[%s] updating stride = %d, width: %d, height: %d",
107 mName, stride, img->mWidth, img->mHeight);
Wonsik Kim469c8342019-04-11 16:46:09 -0700108 if (img->mNumPlanes > 1 && stride > 0) {
Taehwan Kimfd9b8092020-09-17 12:26:40 +0900109 int64_t offsetDelta =
110 (int64_t)img->mPlane[1].mOffset - (int64_t)img->mPlane[0].mOffset;
111 int32_t vstride = int32_t(offsetDelta / stride);
Wonsik Kim4a3c0462021-03-09 15:45:05 -0800112 mFormatWithImageData->setInt32(KEY_SLICE_HEIGHT, vstride);
Wonsik Kim469c8342019-04-11 16:46:09 -0700113 ALOGD("[%s] updating vstride = %d", mName, vstride);
Wonsik Kim2eb06312020-12-03 11:07:58 -0800114 buffer->setRange(
115 img->mPlane[0].mOffset,
116 buffer->size() - img->mPlane[0].mOffset);
Wonsik Kim469c8342019-04-11 16:46:09 -0700117 }
118 }
Wonsik Kim469c8342019-04-11 16:46:09 -0700119 }
Wonsik Kim4a3c0462021-03-09 15:45:05 -0800120 buffer->setFormat(mFormatWithImageData);
Wonsik Kim469c8342019-04-11 16:46:09 -0700121}
122
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700123// InputBuffers
124
125sp<Codec2Buffer> InputBuffers::cloneAndReleaseBuffer(const sp<MediaCodecBuffer> &buffer) {
126 sp<Codec2Buffer> copy = createNewBuffer();
127 if (copy == nullptr) {
128 return nullptr;
129 }
130 std::shared_ptr<C2Buffer> c2buffer;
131 if (!releaseBuffer(buffer, &c2buffer, true)) {
132 return nullptr;
133 }
134 if (!copy->canCopy(c2buffer)) {
135 return nullptr;
136 }
137 if (!copy->copy(c2buffer)) {
138 return nullptr;
139 }
Wonsik Kimfb5ca492021-08-11 14:18:19 -0700140 copy->meta()->extend(buffer->meta());
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700141 return copy;
142}
143
Wonsik Kim469c8342019-04-11 16:46:09 -0700144// OutputBuffers
145
Wonsik Kim41d83432020-04-27 16:40:49 -0700146OutputBuffers::OutputBuffers(const char *componentName, const char *name)
147 : CCodecBuffers(componentName, name) { }
148
149OutputBuffers::~OutputBuffers() = default;
150
Wonsik Kim469c8342019-04-11 16:46:09 -0700151void OutputBuffers::initSkipCutBuffer(
152 int32_t delay, int32_t padding, int32_t sampleRate, int32_t channelCount) {
153 CHECK(mSkipCutBuffer == nullptr);
154 mDelay = delay;
155 mPadding = padding;
156 mSampleRate = sampleRate;
Wonsik Kim40b0b1d2020-03-25 15:47:35 -0700157 mChannelCount = channelCount;
158 setSkipCutBuffer(delay, padding);
Wonsik Kim469c8342019-04-11 16:46:09 -0700159}
160
161void OutputBuffers::updateSkipCutBuffer(int32_t sampleRate, int32_t channelCount) {
162 if (mSkipCutBuffer == nullptr) {
163 return;
164 }
Wonsik Kim40b0b1d2020-03-25 15:47:35 -0700165 if (mSampleRate == sampleRate && mChannelCount == channelCount) {
166 return;
167 }
Wonsik Kim469c8342019-04-11 16:46:09 -0700168 int32_t delay = mDelay;
169 int32_t padding = mPadding;
170 if (sampleRate != mSampleRate) {
171 delay = ((int64_t)delay * sampleRate) / mSampleRate;
172 padding = ((int64_t)padding * sampleRate) / mSampleRate;
173 }
Wonsik Kim40b0b1d2020-03-25 15:47:35 -0700174 mSampleRate = sampleRate;
175 mChannelCount = channelCount;
176 setSkipCutBuffer(delay, padding);
Wonsik Kim469c8342019-04-11 16:46:09 -0700177}
178
Wonsik Kim3b4349a2020-11-10 11:54:15 -0800179void OutputBuffers::updateSkipCutBuffer(const sp<AMessage> &format) {
Pawin Vongmasa9b906982020-04-11 05:07:15 -0700180 AString mediaType;
181 if (format->findString(KEY_MIME, &mediaType)
182 && mediaType == MIMETYPE_AUDIO_RAW) {
183 int32_t channelCount;
184 int32_t sampleRate;
185 if (format->findInt32(KEY_CHANNEL_COUNT, &channelCount)
186 && format->findInt32(KEY_SAMPLE_RATE, &sampleRate)) {
187 updateSkipCutBuffer(sampleRate, channelCount);
188 }
189 }
Pawin Vongmasa9b906982020-04-11 05:07:15 -0700190}
191
Wonsik Kim469c8342019-04-11 16:46:09 -0700192void OutputBuffers::submit(const sp<MediaCodecBuffer> &buffer) {
193 if (mSkipCutBuffer != nullptr) {
194 mSkipCutBuffer->submit(buffer);
195 }
196}
197
Wonsik Kim40b0b1d2020-03-25 15:47:35 -0700198void OutputBuffers::setSkipCutBuffer(int32_t skip, int32_t cut) {
Wonsik Kim469c8342019-04-11 16:46:09 -0700199 if (mSkipCutBuffer != nullptr) {
200 size_t prevSize = mSkipCutBuffer->size();
201 if (prevSize != 0u) {
202 ALOGD("[%s] Replacing SkipCutBuffer holding %zu bytes", mName, prevSize);
203 }
204 }
Wonsik Kim40b0b1d2020-03-25 15:47:35 -0700205 mSkipCutBuffer = new SkipCutBuffer(skip, cut, mChannelCount);
Wonsik Kim469c8342019-04-11 16:46:09 -0700206}
207
Wonsik Kim6f23cfc2021-09-24 05:45:52 -0700208bool OutputBuffers::convert(
209 const std::shared_ptr<C2Buffer> &src, sp<Codec2Buffer> *dst) {
210 if (!src || src->data().type() != C2BufferData::LINEAR) {
211 return false;
212 }
213 int32_t configEncoding = kAudioEncodingPcm16bit;
214 int32_t codecEncoding = kAudioEncodingPcm16bit;
215 if (mFormat->findInt32("android._codec-pcm-encoding", &codecEncoding)
216 && mFormat->findInt32("android._config-pcm-encoding", &configEncoding)) {
217 if (mSrcEncoding != codecEncoding || mDstEncoding != configEncoding) {
218 if (codecEncoding != configEncoding) {
219 mDataConverter = AudioConverter::Create(
220 (AudioEncoding)codecEncoding, (AudioEncoding)configEncoding);
221 ALOGD_IF(mDataConverter, "[%s] Converter created from %d to %d",
222 mName, codecEncoding, configEncoding);
223 mFormatWithConverter = mFormat->dup();
224 mFormatWithConverter->setInt32(KEY_PCM_ENCODING, configEncoding);
225 } else {
226 mDataConverter = nullptr;
227 mFormatWithConverter = nullptr;
228 }
229 mSrcEncoding = codecEncoding;
230 mDstEncoding = configEncoding;
231 }
232 if (int encoding; !mFormat->findInt32(KEY_PCM_ENCODING, &encoding)
233 || encoding != mDstEncoding) {
234 }
235 }
236 if (!mDataConverter) {
237 return false;
238 }
239 sp<MediaCodecBuffer> srcBuffer = ConstLinearBlockBuffer::Allocate(mFormat, src);
240 if (!srcBuffer) {
241 return false;
242 }
Greg Kaiser92dc4542021-10-08 06:58:19 -0700243 if (!*dst) {
Wonsik Kim6f23cfc2021-09-24 05:45:52 -0700244 *dst = new Codec2Buffer(
245 mFormat,
246 new ABuffer(mDataConverter->targetSize(srcBuffer->size())));
247 }
248 sp<MediaCodecBuffer> dstBuffer = *dst;
249 status_t err = mDataConverter->convert(srcBuffer, dstBuffer);
250 if (err != OK) {
251 ALOGD("[%s] buffer conversion failed: %d", mName, err);
252 return false;
253 }
254 dstBuffer->setFormat(mFormatWithConverter);
255 return true;
256}
257
Pawin Vongmasa9b906982020-04-11 05:07:15 -0700258void OutputBuffers::clearStash() {
259 mPending.clear();
260 mReorderStash.clear();
261 mDepth = 0;
262 mKey = C2Config::ORDINAL;
Pawin Vongmasa9b906982020-04-11 05:07:15 -0700263}
264
265void OutputBuffers::flushStash() {
266 for (StashEntry& e : mPending) {
267 e.notify = false;
268 }
269 for (StashEntry& e : mReorderStash) {
270 e.notify = false;
271 }
272}
273
274uint32_t OutputBuffers::getReorderDepth() const {
275 return mDepth;
276}
277
278void OutputBuffers::setReorderDepth(uint32_t depth) {
279 mPending.splice(mPending.end(), mReorderStash);
280 mDepth = depth;
281}
282
283void OutputBuffers::setReorderKey(C2Config::ordinal_key_t key) {
284 mPending.splice(mPending.end(), mReorderStash);
285 mKey = key;
286}
287
288void OutputBuffers::pushToStash(
289 const std::shared_ptr<C2Buffer>& buffer,
290 bool notify,
291 int64_t timestamp,
292 int32_t flags,
293 const sp<AMessage>& format,
294 const C2WorkOrdinalStruct& ordinal) {
295 bool eos = flags & MediaCodec::BUFFER_FLAG_EOS;
296 if (!buffer && eos) {
297 // TRICKY: we may be violating ordering of the stash here. Because we
298 // don't expect any more emplace() calls after this, the ordering should
299 // not matter.
300 mReorderStash.emplace_back(
301 buffer, notify, timestamp, flags, format, ordinal);
302 } else {
303 flags = flags & ~MediaCodec::BUFFER_FLAG_EOS;
304 auto it = mReorderStash.begin();
305 for (; it != mReorderStash.end(); ++it) {
306 if (less(ordinal, it->ordinal)) {
307 break;
308 }
309 }
310 mReorderStash.emplace(it,
311 buffer, notify, timestamp, flags, format, ordinal);
312 if (eos) {
313 mReorderStash.back().flags =
314 mReorderStash.back().flags | MediaCodec::BUFFER_FLAG_EOS;
315 }
316 }
317 while (!mReorderStash.empty() && mReorderStash.size() > mDepth) {
318 mPending.push_back(mReorderStash.front());
319 mReorderStash.pop_front();
320 }
321 ALOGV("[%s] %s: pushToStash -- pending size = %zu", mName, __func__, mPending.size());
322}
323
324OutputBuffers::BufferAction OutputBuffers::popFromStashAndRegister(
325 std::shared_ptr<C2Buffer>* c2Buffer,
326 size_t* index,
327 sp<MediaCodecBuffer>* outBuffer) {
328 if (mPending.empty()) {
329 return SKIP;
330 }
331
332 // Retrieve the first entry.
333 StashEntry &entry = mPending.front();
334
335 *c2Buffer = entry.buffer;
336 sp<AMessage> outputFormat = entry.format;
337
Wonsik Kim3b4349a2020-11-10 11:54:15 -0800338 if (entry.notify && mFormat != outputFormat) {
339 updateSkipCutBuffer(outputFormat);
Wonsik Kim4a3c0462021-03-09 15:45:05 -0800340 // Trigger image data processing to the new format
341 mLastImageData.clear();
Wonsik Kim3b4349a2020-11-10 11:54:15 -0800342 ALOGV("[%s] popFromStashAndRegister: output format reference changed: %p -> %p",
343 mName, mFormat.get(), outputFormat.get());
Wonsik Kim4a3c0462021-03-09 15:45:05 -0800344 ALOGD("[%s] popFromStashAndRegister: at %lldus, output format changed to %s",
345 mName, (long long)entry.timestamp, outputFormat->debugString().c_str());
Wonsik Kim3b4349a2020-11-10 11:54:15 -0800346 setFormat(outputFormat);
Pawin Vongmasa9b906982020-04-11 05:07:15 -0700347 }
348
349 // Flushing mReorderStash because no other buffers should come after output
350 // EOS.
351 if (entry.flags & MediaCodec::BUFFER_FLAG_EOS) {
352 // Flush reorder stash
353 setReorderDepth(0);
354 }
355
356 if (!entry.notify) {
357 mPending.pop_front();
358 return DISCARD;
359 }
360
361 // Try to register the buffer.
362 status_t err = registerBuffer(*c2Buffer, index, outBuffer);
363 if (err != OK) {
364 if (err != WOULD_BLOCK) {
365 return REALLOCATE;
366 }
367 return RETRY;
368 }
369
370 // Append information from the front stash entry to outBuffer.
371 (*outBuffer)->meta()->setInt64("timeUs", entry.timestamp);
372 (*outBuffer)->meta()->setInt32("flags", entry.flags);
Byeongjo Park2eef13e2020-06-12 17:24:21 +0900373 (*outBuffer)->meta()->setInt64("frameIndex", entry.ordinal.frameIndex.peekll());
Pawin Vongmasa9b906982020-04-11 05:07:15 -0700374 ALOGV("[%s] popFromStashAndRegister: "
375 "out buffer index = %zu [%p] => %p + %zu (%lld)",
376 mName, *index, outBuffer->get(),
377 (*outBuffer)->data(), (*outBuffer)->size(),
378 (long long)entry.timestamp);
379
380 // The front entry of mPending will be removed now that the registration
381 // succeeded.
382 mPending.pop_front();
383 return NOTIFY_CLIENT;
384}
385
386bool OutputBuffers::popPending(StashEntry *entry) {
387 if (mPending.empty()) {
388 return false;
389 }
390 *entry = mPending.front();
391 mPending.pop_front();
392 return true;
393}
394
395void OutputBuffers::deferPending(const OutputBuffers::StashEntry &entry) {
396 mPending.push_front(entry);
397}
398
399bool OutputBuffers::hasPending() const {
400 return !mPending.empty();
401}
402
403bool OutputBuffers::less(
404 const C2WorkOrdinalStruct &o1, const C2WorkOrdinalStruct &o2) const {
405 switch (mKey) {
406 case C2Config::ORDINAL: return o1.frameIndex < o2.frameIndex;
407 case C2Config::TIMESTAMP: return o1.timestamp < o2.timestamp;
408 case C2Config::CUSTOM: return o1.customOrdinal < o2.customOrdinal;
409 default:
410 ALOGD("Unrecognized key; default to timestamp");
411 return o1.frameIndex < o2.frameIndex;
412 }
413}
414
Wonsik Kim469c8342019-04-11 16:46:09 -0700415// LocalBufferPool
416
Wonsik Kim41d83432020-04-27 16:40:49 -0700417constexpr size_t kInitialPoolCapacity = kMaxLinearBufferSize;
418constexpr size_t kMaxPoolCapacity = kMaxLinearBufferSize * 32;
419
420std::shared_ptr<LocalBufferPool> LocalBufferPool::Create() {
421 return std::shared_ptr<LocalBufferPool>(new LocalBufferPool(kInitialPoolCapacity));
Wonsik Kim469c8342019-04-11 16:46:09 -0700422}
423
424sp<ABuffer> LocalBufferPool::newBuffer(size_t capacity) {
425 Mutex::Autolock lock(mMutex);
426 auto it = std::find_if(
427 mPool.begin(), mPool.end(),
428 [capacity](const std::vector<uint8_t> &vec) {
429 return vec.capacity() >= capacity;
430 });
431 if (it != mPool.end()) {
432 sp<ABuffer> buffer = new VectorBuffer(std::move(*it), shared_from_this());
433 mPool.erase(it);
434 return buffer;
435 }
436 if (mUsedSize + capacity > mPoolCapacity) {
437 while (!mPool.empty()) {
438 mUsedSize -= mPool.back().capacity();
439 mPool.pop_back();
440 }
Wonsik Kim41d83432020-04-27 16:40:49 -0700441 while (mUsedSize + capacity > mPoolCapacity && mPoolCapacity * 2 <= kMaxPoolCapacity) {
442 ALOGD("Increasing local buffer pool capacity from %zu to %zu",
443 mPoolCapacity, mPoolCapacity * 2);
444 mPoolCapacity *= 2;
445 }
Wonsik Kim469c8342019-04-11 16:46:09 -0700446 if (mUsedSize + capacity > mPoolCapacity) {
447 ALOGD("mUsedSize = %zu, capacity = %zu, mPoolCapacity = %zu",
448 mUsedSize, capacity, mPoolCapacity);
449 return nullptr;
450 }
451 }
452 std::vector<uint8_t> vec(capacity);
453 mUsedSize += vec.capacity();
454 return new VectorBuffer(std::move(vec), shared_from_this());
455}
456
457LocalBufferPool::VectorBuffer::VectorBuffer(
458 std::vector<uint8_t> &&vec, const std::shared_ptr<LocalBufferPool> &pool)
459 : ABuffer(vec.data(), vec.capacity()),
460 mVec(std::move(vec)),
461 mPool(pool) {
462}
463
464LocalBufferPool::VectorBuffer::~VectorBuffer() {
465 std::shared_ptr<LocalBufferPool> pool = mPool.lock();
466 if (pool) {
467 // If pool is alive, return the vector back to the pool so that
468 // it can be recycled.
469 pool->returnVector(std::move(mVec));
470 }
471}
472
473void LocalBufferPool::returnVector(std::vector<uint8_t> &&vec) {
474 Mutex::Autolock lock(mMutex);
475 mPool.push_front(std::move(vec));
476}
477
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700478// FlexBuffersImpl
479
Wonsik Kim469c8342019-04-11 16:46:09 -0700480size_t FlexBuffersImpl::assignSlot(const sp<Codec2Buffer> &buffer) {
481 for (size_t i = 0; i < mBuffers.size(); ++i) {
482 if (mBuffers[i].clientBuffer == nullptr
483 && mBuffers[i].compBuffer.expired()) {
484 mBuffers[i].clientBuffer = buffer;
485 return i;
486 }
487 }
488 mBuffers.push_back({ buffer, std::weak_ptr<C2Buffer>() });
489 return mBuffers.size() - 1;
490}
491
Wonsik Kim469c8342019-04-11 16:46:09 -0700492bool FlexBuffersImpl::releaseSlot(
493 const sp<MediaCodecBuffer> &buffer,
494 std::shared_ptr<C2Buffer> *c2buffer,
495 bool release) {
496 sp<Codec2Buffer> clientBuffer;
497 size_t index = mBuffers.size();
498 for (size_t i = 0; i < mBuffers.size(); ++i) {
499 if (mBuffers[i].clientBuffer == buffer) {
500 clientBuffer = mBuffers[i].clientBuffer;
501 if (release) {
502 mBuffers[i].clientBuffer.clear();
503 }
504 index = i;
505 break;
506 }
507 }
508 if (clientBuffer == nullptr) {
509 ALOGV("[%s] %s: No matching buffer found", mName, __func__);
510 return false;
511 }
512 std::shared_ptr<C2Buffer> result = mBuffers[index].compBuffer.lock();
513 if (!result) {
514 result = clientBuffer->asC2Buffer();
Wonsik Kimf9b32122020-04-02 11:30:17 -0700515 clientBuffer->clearC2BufferRefs();
Wonsik Kim469c8342019-04-11 16:46:09 -0700516 mBuffers[index].compBuffer = result;
517 }
518 if (c2buffer) {
519 *c2buffer = result;
520 }
521 return true;
522}
523
524bool FlexBuffersImpl::expireComponentBuffer(const std::shared_ptr<C2Buffer> &c2buffer) {
525 for (size_t i = 0; i < mBuffers.size(); ++i) {
526 std::shared_ptr<C2Buffer> compBuffer =
527 mBuffers[i].compBuffer.lock();
528 if (!compBuffer || compBuffer != c2buffer) {
529 continue;
530 }
531 mBuffers[i].compBuffer.reset();
532 ALOGV("[%s] codec released buffer #%zu", mName, i);
533 return true;
534 }
535 ALOGV("[%s] codec released an unknown buffer", mName);
536 return false;
537}
538
539void FlexBuffersImpl::flush() {
540 ALOGV("[%s] buffers are flushed %zu", mName, mBuffers.size());
541 mBuffers.clear();
542}
543
Wonsik Kim0487b782020-10-28 11:45:50 -0700544size_t FlexBuffersImpl::numActiveSlots() const {
Wonsik Kim469c8342019-04-11 16:46:09 -0700545 return std::count_if(
546 mBuffers.begin(), mBuffers.end(),
547 [](const Entry &entry) {
Wonsik Kim0487b782020-10-28 11:45:50 -0700548 return (entry.clientBuffer != nullptr
549 || !entry.compBuffer.expired());
Wonsik Kim469c8342019-04-11 16:46:09 -0700550 });
551}
552
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700553size_t FlexBuffersImpl::numComponentBuffers() const {
554 return std::count_if(
555 mBuffers.begin(), mBuffers.end(),
556 [](const Entry &entry) {
557 return !entry.compBuffer.expired();
558 });
559}
560
Wonsik Kim469c8342019-04-11 16:46:09 -0700561// BuffersArrayImpl
562
563void BuffersArrayImpl::initialize(
564 const FlexBuffersImpl &impl,
565 size_t minSize,
566 std::function<sp<Codec2Buffer>()> allocate) {
567 mImplName = impl.mImplName + "[N]";
568 mName = mImplName.c_str();
569 for (size_t i = 0; i < impl.mBuffers.size(); ++i) {
570 sp<Codec2Buffer> clientBuffer = impl.mBuffers[i].clientBuffer;
571 bool ownedByClient = (clientBuffer != nullptr);
572 if (!ownedByClient) {
573 clientBuffer = allocate();
574 }
575 mBuffers.push_back({ clientBuffer, impl.mBuffers[i].compBuffer, ownedByClient });
576 }
577 ALOGV("[%s] converted %zu buffers to array mode of %zu", mName, mBuffers.size(), minSize);
578 for (size_t i = impl.mBuffers.size(); i < minSize; ++i) {
579 mBuffers.push_back({ allocate(), std::weak_ptr<C2Buffer>(), false });
580 }
581}
582
583status_t BuffersArrayImpl::grabBuffer(
584 size_t *index,
585 sp<Codec2Buffer> *buffer,
586 std::function<bool(const sp<Codec2Buffer> &)> match) {
587 // allBuffersDontMatch remains true if all buffers are available but
588 // match() returns false for every buffer.
589 bool allBuffersDontMatch = true;
590 for (size_t i = 0; i < mBuffers.size(); ++i) {
591 if (!mBuffers[i].ownedByClient && mBuffers[i].compBuffer.expired()) {
592 if (match(mBuffers[i].clientBuffer)) {
593 mBuffers[i].ownedByClient = true;
594 *buffer = mBuffers[i].clientBuffer;
595 (*buffer)->meta()->clear();
596 (*buffer)->setRange(0, (*buffer)->capacity());
597 *index = i;
598 return OK;
599 }
600 } else {
601 allBuffersDontMatch = false;
602 }
603 }
604 return allBuffersDontMatch ? NO_MEMORY : WOULD_BLOCK;
605}
606
607bool BuffersArrayImpl::returnBuffer(
608 const sp<MediaCodecBuffer> &buffer,
609 std::shared_ptr<C2Buffer> *c2buffer,
610 bool release) {
611 sp<Codec2Buffer> clientBuffer;
612 size_t index = mBuffers.size();
613 for (size_t i = 0; i < mBuffers.size(); ++i) {
614 if (mBuffers[i].clientBuffer == buffer) {
615 if (!mBuffers[i].ownedByClient) {
616 ALOGD("[%s] Client returned a buffer it does not own according to our record: %zu",
617 mName, i);
618 }
619 clientBuffer = mBuffers[i].clientBuffer;
620 if (release) {
621 mBuffers[i].ownedByClient = false;
622 }
623 index = i;
624 break;
625 }
626 }
627 if (clientBuffer == nullptr) {
628 ALOGV("[%s] %s: No matching buffer found", mName, __func__);
629 return false;
630 }
631 ALOGV("[%s] %s: matching buffer found (index=%zu)", mName, __func__, index);
632 std::shared_ptr<C2Buffer> result = mBuffers[index].compBuffer.lock();
633 if (!result) {
634 result = clientBuffer->asC2Buffer();
Wonsik Kimf9b32122020-04-02 11:30:17 -0700635 clientBuffer->clearC2BufferRefs();
Wonsik Kim469c8342019-04-11 16:46:09 -0700636 mBuffers[index].compBuffer = result;
637 }
638 if (c2buffer) {
639 *c2buffer = result;
640 }
641 return true;
642}
643
644bool BuffersArrayImpl::expireComponentBuffer(const std::shared_ptr<C2Buffer> &c2buffer) {
645 for (size_t i = 0; i < mBuffers.size(); ++i) {
646 std::shared_ptr<C2Buffer> compBuffer =
647 mBuffers[i].compBuffer.lock();
648 if (!compBuffer) {
649 continue;
650 }
651 if (c2buffer == compBuffer) {
652 if (mBuffers[i].ownedByClient) {
653 // This should not happen.
654 ALOGD("[%s] codec released a buffer owned by client "
655 "(index %zu)", mName, i);
656 }
657 mBuffers[i].compBuffer.reset();
658 ALOGV("[%s] codec released buffer #%zu(array mode)", mName, i);
659 return true;
660 }
661 }
662 ALOGV("[%s] codec released an unknown buffer (array mode)", mName);
663 return false;
664}
665
666void BuffersArrayImpl::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
667 array->clear();
668 for (const Entry &entry : mBuffers) {
669 array->push(entry.clientBuffer);
670 }
671}
672
673void BuffersArrayImpl::flush() {
674 for (Entry &entry : mBuffers) {
675 entry.ownedByClient = false;
676 }
677}
678
679void BuffersArrayImpl::realloc(std::function<sp<Codec2Buffer>()> alloc) {
680 size_t size = mBuffers.size();
681 mBuffers.clear();
682 for (size_t i = 0; i < size; ++i) {
683 mBuffers.push_back({ alloc(), std::weak_ptr<C2Buffer>(), false });
684 }
685}
686
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700687void BuffersArrayImpl::grow(
688 size_t newSize, std::function<sp<Codec2Buffer>()> alloc) {
689 CHECK_LT(mBuffers.size(), newSize);
690 while (mBuffers.size() < newSize) {
691 mBuffers.push_back({ alloc(), std::weak_ptr<C2Buffer>(), false });
692 }
693}
694
Wonsik Kim0487b782020-10-28 11:45:50 -0700695size_t BuffersArrayImpl::numActiveSlots() const {
Wonsik Kim469c8342019-04-11 16:46:09 -0700696 return std::count_if(
697 mBuffers.begin(), mBuffers.end(),
698 [](const Entry &entry) {
Wonsik Kim0487b782020-10-28 11:45:50 -0700699 return entry.ownedByClient || !entry.compBuffer.expired();
Wonsik Kim469c8342019-04-11 16:46:09 -0700700 });
701}
702
Wonsik Kima39882b2019-06-20 16:13:56 -0700703size_t BuffersArrayImpl::arraySize() const {
704 return mBuffers.size();
705}
706
Wonsik Kim469c8342019-04-11 16:46:09 -0700707// InputBuffersArray
708
709void InputBuffersArray::initialize(
710 const FlexBuffersImpl &impl,
711 size_t minSize,
712 std::function<sp<Codec2Buffer>()> allocate) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700713 mAllocate = allocate;
Wonsik Kim469c8342019-04-11 16:46:09 -0700714 mImpl.initialize(impl, minSize, allocate);
715}
716
717void InputBuffersArray::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
718 mImpl.getArray(array);
719}
720
721bool InputBuffersArray::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
722 sp<Codec2Buffer> c2Buffer;
723 status_t err = mImpl.grabBuffer(index, &c2Buffer);
724 if (err == OK) {
725 c2Buffer->setFormat(mFormat);
726 handleImageData(c2Buffer);
727 *buffer = c2Buffer;
728 return true;
729 }
730 return false;
731}
732
733bool InputBuffersArray::releaseBuffer(
734 const sp<MediaCodecBuffer> &buffer,
735 std::shared_ptr<C2Buffer> *c2buffer,
736 bool release) {
737 return mImpl.returnBuffer(buffer, c2buffer, release);
738}
739
740bool InputBuffersArray::expireComponentBuffer(
741 const std::shared_ptr<C2Buffer> &c2buffer) {
742 return mImpl.expireComponentBuffer(c2buffer);
743}
744
745void InputBuffersArray::flush() {
746 mImpl.flush();
747}
748
Wonsik Kim0487b782020-10-28 11:45:50 -0700749size_t InputBuffersArray::numActiveSlots() const {
750 return mImpl.numActiveSlots();
Wonsik Kim469c8342019-04-11 16:46:09 -0700751}
752
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700753sp<Codec2Buffer> InputBuffersArray::createNewBuffer() {
754 return mAllocate();
755}
756
Wonsik Kimfb7a7672019-12-27 17:13:33 -0800757// SlotInputBuffers
758
759bool SlotInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
760 sp<Codec2Buffer> newBuffer = createNewBuffer();
761 *index = mImpl.assignSlot(newBuffer);
762 *buffer = newBuffer;
763 return true;
764}
765
766bool SlotInputBuffers::releaseBuffer(
767 const sp<MediaCodecBuffer> &buffer,
768 std::shared_ptr<C2Buffer> *c2buffer,
769 bool release) {
770 return mImpl.releaseSlot(buffer, c2buffer, release);
771}
772
773bool SlotInputBuffers::expireComponentBuffer(
774 const std::shared_ptr<C2Buffer> &c2buffer) {
775 return mImpl.expireComponentBuffer(c2buffer);
776}
777
778void SlotInputBuffers::flush() {
779 mImpl.flush();
780}
781
782std::unique_ptr<InputBuffers> SlotInputBuffers::toArrayMode(size_t) {
783 TRESPASS("Array mode should not be called at non-legacy mode");
784 return nullptr;
785}
786
Wonsik Kim0487b782020-10-28 11:45:50 -0700787size_t SlotInputBuffers::numActiveSlots() const {
788 return mImpl.numActiveSlots();
Wonsik Kimfb7a7672019-12-27 17:13:33 -0800789}
790
791sp<Codec2Buffer> SlotInputBuffers::createNewBuffer() {
792 return new DummyContainerBuffer{mFormat, nullptr};
793}
794
Wonsik Kim469c8342019-04-11 16:46:09 -0700795// LinearInputBuffers
796
797bool LinearInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700798 sp<Codec2Buffer> newBuffer = createNewBuffer();
Wonsik Kim469c8342019-04-11 16:46:09 -0700799 if (newBuffer == nullptr) {
800 return false;
801 }
802 *index = mImpl.assignSlot(newBuffer);
803 *buffer = newBuffer;
804 return true;
805}
806
807bool LinearInputBuffers::releaseBuffer(
808 const sp<MediaCodecBuffer> &buffer,
809 std::shared_ptr<C2Buffer> *c2buffer,
810 bool release) {
811 return mImpl.releaseSlot(buffer, c2buffer, release);
812}
813
814bool LinearInputBuffers::expireComponentBuffer(
815 const std::shared_ptr<C2Buffer> &c2buffer) {
816 return mImpl.expireComponentBuffer(c2buffer);
817}
818
819void LinearInputBuffers::flush() {
820 // This is no-op by default unless we're in array mode where we need to keep
821 // track of the flushed work.
822 mImpl.flush();
823}
824
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700825std::unique_ptr<InputBuffers> LinearInputBuffers::toArrayMode(size_t size) {
Wonsik Kim469c8342019-04-11 16:46:09 -0700826 std::unique_ptr<InputBuffersArray> array(
827 new InputBuffersArray(mComponentName.c_str(), "1D-Input[N]"));
828 array->setPool(mPool);
829 array->setFormat(mFormat);
830 array->initialize(
831 mImpl,
832 size,
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700833 [pool = mPool, format = mFormat] () -> sp<Codec2Buffer> {
834 return Alloc(pool, format);
835 });
Wonsik Kim469c8342019-04-11 16:46:09 -0700836 return std::move(array);
837}
838
Wonsik Kim0487b782020-10-28 11:45:50 -0700839size_t LinearInputBuffers::numActiveSlots() const {
840 return mImpl.numActiveSlots();
Wonsik Kim469c8342019-04-11 16:46:09 -0700841}
842
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700843// static
844sp<Codec2Buffer> LinearInputBuffers::Alloc(
845 const std::shared_ptr<C2BlockPool> &pool, const sp<AMessage> &format) {
846 int32_t capacity = kLinearBufferSize;
847 (void)format->findInt32(KEY_MAX_INPUT_SIZE, &capacity);
848 if ((size_t)capacity > kMaxLinearBufferSize) {
849 ALOGD("client requested %d, capped to %zu", capacity, kMaxLinearBufferSize);
850 capacity = kMaxLinearBufferSize;
851 }
852
Wonsik Kim666604a2020-05-14 16:57:49 -0700853 int64_t usageValue = 0;
854 (void)format->findInt64("android._C2MemoryUsage", &usageValue);
855 C2MemoryUsage usage{usageValue | C2MemoryUsage::CPU_READ | C2MemoryUsage::CPU_WRITE};
Wonsik Kim469c8342019-04-11 16:46:09 -0700856 std::shared_ptr<C2LinearBlock> block;
857
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700858 c2_status_t err = pool->fetchLinearBlock(capacity, usage, &block);
Wonsik Kim469c8342019-04-11 16:46:09 -0700859 if (err != C2_OK) {
860 return nullptr;
861 }
862
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700863 return LinearBlockBuffer::Allocate(format, block);
864}
865
866sp<Codec2Buffer> LinearInputBuffers::createNewBuffer() {
867 return Alloc(mPool, mFormat);
Wonsik Kim469c8342019-04-11 16:46:09 -0700868}
869
870// EncryptedLinearInputBuffers
871
872EncryptedLinearInputBuffers::EncryptedLinearInputBuffers(
873 bool secure,
874 const sp<MemoryDealer> &dealer,
875 const sp<ICrypto> &crypto,
876 int32_t heapSeqNum,
877 size_t capacity,
878 size_t numInputSlots,
879 const char *componentName, const char *name)
880 : LinearInputBuffers(componentName, name),
881 mUsage({0, 0}),
882 mDealer(dealer),
883 mCrypto(crypto),
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700884 mMemoryVector(new std::vector<Entry>){
Wonsik Kim469c8342019-04-11 16:46:09 -0700885 if (secure) {
886 mUsage = { C2MemoryUsage::READ_PROTECTED, 0 };
887 } else {
888 mUsage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
889 }
890 for (size_t i = 0; i < numInputSlots; ++i) {
891 sp<IMemory> memory = mDealer->allocate(capacity);
892 if (memory == nullptr) {
893 ALOGD("[%s] Failed to allocate memory from dealer: only %zu slots allocated",
894 mName, i);
895 break;
896 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700897 mMemoryVector->push_back({std::weak_ptr<C2LinearBlock>(), memory, heapSeqNum});
Wonsik Kim469c8342019-04-11 16:46:09 -0700898 }
899}
900
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700901std::unique_ptr<InputBuffers> EncryptedLinearInputBuffers::toArrayMode(size_t size) {
902 std::unique_ptr<InputBuffersArray> array(
903 new InputBuffersArray(mComponentName.c_str(), "1D-EncryptedInput[N]"));
904 array->setPool(mPool);
905 array->setFormat(mFormat);
906 array->initialize(
907 mImpl,
908 size,
909 [pool = mPool,
910 format = mFormat,
911 usage = mUsage,
912 memoryVector = mMemoryVector] () -> sp<Codec2Buffer> {
913 return Alloc(pool, format, usage, memoryVector);
914 });
915 return std::move(array);
916}
917
918
919// static
920sp<Codec2Buffer> EncryptedLinearInputBuffers::Alloc(
921 const std::shared_ptr<C2BlockPool> &pool,
922 const sp<AMessage> &format,
923 C2MemoryUsage usage,
924 const std::shared_ptr<std::vector<EncryptedLinearInputBuffers::Entry>> &memoryVector) {
925 int32_t capacity = kLinearBufferSize;
926 (void)format->findInt32(KEY_MAX_INPUT_SIZE, &capacity);
927 if ((size_t)capacity > kMaxLinearBufferSize) {
928 ALOGD("client requested %d, capped to %zu", capacity, kMaxLinearBufferSize);
929 capacity = kMaxLinearBufferSize;
930 }
931
Wonsik Kim469c8342019-04-11 16:46:09 -0700932 sp<IMemory> memory;
933 size_t slot = 0;
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700934 int32_t heapSeqNum = -1;
935 for (; slot < memoryVector->size(); ++slot) {
936 if (memoryVector->at(slot).block.expired()) {
937 memory = memoryVector->at(slot).memory;
938 heapSeqNum = memoryVector->at(slot).heapSeqNum;
Wonsik Kim469c8342019-04-11 16:46:09 -0700939 break;
940 }
941 }
942 if (memory == nullptr) {
943 return nullptr;
944 }
945
David Stevens94b608f2021-07-29 15:04:14 +0900946 int64_t usageValue = 0;
947 (void)format->findInt64("android._C2MemoryUsage", &usageValue);
948 usage = C2MemoryUsage(usage.expected | usageValue);
949
Wonsik Kim469c8342019-04-11 16:46:09 -0700950 std::shared_ptr<C2LinearBlock> block;
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700951 c2_status_t err = pool->fetchLinearBlock(capacity, usage, &block);
Wonsik Kim469c8342019-04-11 16:46:09 -0700952 if (err != C2_OK || block == nullptr) {
953 return nullptr;
954 }
955
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700956 memoryVector->at(slot).block = block;
957 return new EncryptedLinearBlockBuffer(format, block, memory, heapSeqNum);
958}
959
960sp<Codec2Buffer> EncryptedLinearInputBuffers::createNewBuffer() {
961 // TODO: android_2020
962 return nullptr;
Wonsik Kim469c8342019-04-11 16:46:09 -0700963}
964
965// GraphicMetadataInputBuffers
966
967GraphicMetadataInputBuffers::GraphicMetadataInputBuffers(
968 const char *componentName, const char *name)
969 : InputBuffers(componentName, name),
970 mImpl(mName),
971 mStore(GetCodec2PlatformAllocatorStore()) { }
972
973bool GraphicMetadataInputBuffers::requestNewBuffer(
974 size_t *index, sp<MediaCodecBuffer> *buffer) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700975 sp<Codec2Buffer> newBuffer = createNewBuffer();
Wonsik Kim469c8342019-04-11 16:46:09 -0700976 if (newBuffer == nullptr) {
977 return false;
978 }
979 *index = mImpl.assignSlot(newBuffer);
980 *buffer = newBuffer;
981 return true;
982}
983
984bool GraphicMetadataInputBuffers::releaseBuffer(
985 const sp<MediaCodecBuffer> &buffer,
986 std::shared_ptr<C2Buffer> *c2buffer,
987 bool release) {
988 return mImpl.releaseSlot(buffer, c2buffer, release);
989}
990
991bool GraphicMetadataInputBuffers::expireComponentBuffer(
992 const std::shared_ptr<C2Buffer> &c2buffer) {
993 return mImpl.expireComponentBuffer(c2buffer);
994}
995
996void GraphicMetadataInputBuffers::flush() {
997 // This is no-op by default unless we're in array mode where we need to keep
998 // track of the flushed work.
999}
1000
1001std::unique_ptr<InputBuffers> GraphicMetadataInputBuffers::toArrayMode(
1002 size_t size) {
1003 std::shared_ptr<C2Allocator> alloc;
1004 c2_status_t err = mStore->fetchAllocator(mPool->getAllocatorId(), &alloc);
1005 if (err != C2_OK) {
1006 return nullptr;
1007 }
1008 std::unique_ptr<InputBuffersArray> array(
1009 new InputBuffersArray(mComponentName.c_str(), "2D-MetaInput[N]"));
1010 array->setPool(mPool);
1011 array->setFormat(mFormat);
1012 array->initialize(
1013 mImpl,
1014 size,
1015 [format = mFormat, alloc]() -> sp<Codec2Buffer> {
1016 return new GraphicMetadataBuffer(format, alloc);
1017 });
1018 return std::move(array);
1019}
1020
Wonsik Kim0487b782020-10-28 11:45:50 -07001021size_t GraphicMetadataInputBuffers::numActiveSlots() const {
1022 return mImpl.numActiveSlots();
Wonsik Kim469c8342019-04-11 16:46:09 -07001023}
1024
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001025sp<Codec2Buffer> GraphicMetadataInputBuffers::createNewBuffer() {
1026 std::shared_ptr<C2Allocator> alloc;
1027 c2_status_t err = mStore->fetchAllocator(mPool->getAllocatorId(), &alloc);
1028 if (err != C2_OK) {
1029 return nullptr;
1030 }
1031 return new GraphicMetadataBuffer(mFormat, alloc);
1032}
1033
Wonsik Kim469c8342019-04-11 16:46:09 -07001034// GraphicInputBuffers
1035
1036GraphicInputBuffers::GraphicInputBuffers(
Wonsik Kim41d83432020-04-27 16:40:49 -07001037 const char *componentName, const char *name)
Wonsik Kim469c8342019-04-11 16:46:09 -07001038 : InputBuffers(componentName, name),
1039 mImpl(mName),
Wonsik Kim41d83432020-04-27 16:40:49 -07001040 mLocalBufferPool(LocalBufferPool::Create()) { }
Wonsik Kim469c8342019-04-11 16:46:09 -07001041
1042bool GraphicInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001043 sp<Codec2Buffer> newBuffer = createNewBuffer();
Wonsik Kim469c8342019-04-11 16:46:09 -07001044 if (newBuffer == nullptr) {
1045 return false;
1046 }
1047 *index = mImpl.assignSlot(newBuffer);
1048 handleImageData(newBuffer);
1049 *buffer = newBuffer;
1050 return true;
1051}
1052
1053bool GraphicInputBuffers::releaseBuffer(
1054 const sp<MediaCodecBuffer> &buffer,
1055 std::shared_ptr<C2Buffer> *c2buffer,
1056 bool release) {
1057 return mImpl.releaseSlot(buffer, c2buffer, release);
1058}
1059
1060bool GraphicInputBuffers::expireComponentBuffer(
1061 const std::shared_ptr<C2Buffer> &c2buffer) {
1062 return mImpl.expireComponentBuffer(c2buffer);
1063}
1064
1065void GraphicInputBuffers::flush() {
1066 // This is no-op by default unless we're in array mode where we need to keep
1067 // track of the flushed work.
1068}
1069
Wonsik Kimd79ee1f2020-08-27 17:41:56 -07001070static uint32_t extractPixelFormat(const sp<AMessage> &format) {
1071 int32_t frameworkColorFormat = 0;
1072 if (!format->findInt32("android._color-format", &frameworkColorFormat)) {
1073 return PIXEL_FORMAT_UNKNOWN;
1074 }
1075 uint32_t pixelFormat = PIXEL_FORMAT_UNKNOWN;
1076 if (C2Mapper::mapPixelFormatFrameworkToCodec(frameworkColorFormat, &pixelFormat)) {
1077 return pixelFormat;
1078 }
1079 return PIXEL_FORMAT_UNKNOWN;
1080}
1081
Wonsik Kim469c8342019-04-11 16:46:09 -07001082std::unique_ptr<InputBuffers> GraphicInputBuffers::toArrayMode(size_t size) {
1083 std::unique_ptr<InputBuffersArray> array(
1084 new InputBuffersArray(mComponentName.c_str(), "2D-BB-Input[N]"));
1085 array->setPool(mPool);
1086 array->setFormat(mFormat);
Wonsik Kimd79ee1f2020-08-27 17:41:56 -07001087 uint32_t pixelFormat = extractPixelFormat(mFormat);
Wonsik Kim469c8342019-04-11 16:46:09 -07001088 array->initialize(
1089 mImpl,
1090 size,
Wonsik Kimd79ee1f2020-08-27 17:41:56 -07001091 [pool = mPool, format = mFormat, lbp = mLocalBufferPool, pixelFormat]()
1092 -> sp<Codec2Buffer> {
Wonsik Kim469c8342019-04-11 16:46:09 -07001093 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
David Stevens94b608f2021-07-29 15:04:14 +09001094 return AllocateInputGraphicBuffer(
Wonsik Kimd79ee1f2020-08-27 17:41:56 -07001095 pool, format, pixelFormat, usage, lbp);
Wonsik Kim469c8342019-04-11 16:46:09 -07001096 });
1097 return std::move(array);
1098}
1099
Wonsik Kim0487b782020-10-28 11:45:50 -07001100size_t GraphicInputBuffers::numActiveSlots() const {
1101 return mImpl.numActiveSlots();
Wonsik Kim469c8342019-04-11 16:46:09 -07001102}
1103
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001104sp<Codec2Buffer> GraphicInputBuffers::createNewBuffer() {
David Stevens94b608f2021-07-29 15:04:14 +09001105 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
1106 return AllocateInputGraphicBuffer(
Wonsik Kimd79ee1f2020-08-27 17:41:56 -07001107 mPool, mFormat, extractPixelFormat(mFormat), usage, mLocalBufferPool);
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001108}
1109
Wonsik Kim469c8342019-04-11 16:46:09 -07001110// OutputBuffersArray
1111
1112void OutputBuffersArray::initialize(
1113 const FlexBuffersImpl &impl,
1114 size_t minSize,
1115 std::function<sp<Codec2Buffer>()> allocate) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001116 mAlloc = allocate;
Wonsik Kim469c8342019-04-11 16:46:09 -07001117 mImpl.initialize(impl, minSize, allocate);
1118}
1119
1120status_t OutputBuffersArray::registerBuffer(
1121 const std::shared_ptr<C2Buffer> &buffer,
1122 size_t *index,
1123 sp<MediaCodecBuffer> *clientBuffer) {
1124 sp<Codec2Buffer> c2Buffer;
1125 status_t err = mImpl.grabBuffer(
1126 index,
1127 &c2Buffer,
1128 [buffer](const sp<Codec2Buffer> &clientBuffer) {
1129 return clientBuffer->canCopy(buffer);
1130 });
1131 if (err == WOULD_BLOCK) {
1132 ALOGV("[%s] buffers temporarily not available", mName);
1133 return err;
1134 } else if (err != OK) {
1135 ALOGD("[%s] grabBuffer failed: %d", mName, err);
1136 return err;
1137 }
1138 c2Buffer->setFormat(mFormat);
Wonsik Kim6f23cfc2021-09-24 05:45:52 -07001139 if (!convert(buffer, &c2Buffer) && !c2Buffer->copy(buffer)) {
Wonsik Kim469c8342019-04-11 16:46:09 -07001140 ALOGD("[%s] copy buffer failed", mName);
1141 return WOULD_BLOCK;
1142 }
1143 submit(c2Buffer);
1144 handleImageData(c2Buffer);
1145 *clientBuffer = c2Buffer;
1146 ALOGV("[%s] grabbed buffer %zu", mName, *index);
1147 return OK;
1148}
1149
1150status_t OutputBuffersArray::registerCsd(
1151 const C2StreamInitDataInfo::output *csd,
1152 size_t *index,
1153 sp<MediaCodecBuffer> *clientBuffer) {
1154 sp<Codec2Buffer> c2Buffer;
1155 status_t err = mImpl.grabBuffer(
1156 index,
1157 &c2Buffer,
1158 [csd](const sp<Codec2Buffer> &clientBuffer) {
1159 return clientBuffer->base() != nullptr
1160 && clientBuffer->capacity() >= csd->flexCount();
1161 });
1162 if (err != OK) {
1163 return err;
1164 }
1165 memcpy(c2Buffer->base(), csd->m.value, csd->flexCount());
1166 c2Buffer->setRange(0, csd->flexCount());
1167 c2Buffer->setFormat(mFormat);
1168 *clientBuffer = c2Buffer;
1169 return OK;
1170}
1171
1172bool OutputBuffersArray::releaseBuffer(
1173 const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) {
1174 return mImpl.returnBuffer(buffer, c2buffer, true);
1175}
1176
1177void OutputBuffersArray::flush(const std::list<std::unique_ptr<C2Work>> &flushedWork) {
1178 (void)flushedWork;
1179 mImpl.flush();
1180 if (mSkipCutBuffer != nullptr) {
1181 mSkipCutBuffer->clear();
1182 }
1183}
1184
1185void OutputBuffersArray::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
1186 mImpl.getArray(array);
1187}
1188
Wonsik Kim0487b782020-10-28 11:45:50 -07001189size_t OutputBuffersArray::numActiveSlots() const {
1190 return mImpl.numActiveSlots();
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001191}
1192
Wonsik Kim469c8342019-04-11 16:46:09 -07001193void OutputBuffersArray::realloc(const std::shared_ptr<C2Buffer> &c2buffer) {
Wonsik Kim469c8342019-04-11 16:46:09 -07001194 switch (c2buffer->data().type()) {
1195 case C2BufferData::LINEAR: {
1196 uint32_t size = kLinearBufferSize;
Nick Desaulniersd09eaea2019-10-07 20:19:39 -07001197 const std::vector<C2ConstLinearBlock> &linear_blocks = c2buffer->data().linearBlocks();
1198 const uint32_t block_size = linear_blocks.front().size();
1199 if (block_size < kMaxLinearBufferSize / 2) {
1200 size = block_size * 2;
Wonsik Kim469c8342019-04-11 16:46:09 -07001201 } else {
1202 size = kMaxLinearBufferSize;
1203 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001204 mAlloc = [format = mFormat, size] {
Wonsik Kim469c8342019-04-11 16:46:09 -07001205 return new LocalLinearBuffer(format, new ABuffer(size));
1206 };
Wonsik Kima39882b2019-06-20 16:13:56 -07001207 ALOGD("[%s] reallocating with linear buffer of size %u", mName, size);
Wonsik Kim469c8342019-04-11 16:46:09 -07001208 break;
1209 }
1210
Wonsik Kima39882b2019-06-20 16:13:56 -07001211 case C2BufferData::GRAPHIC: {
1212 // This is only called for RawGraphicOutputBuffers.
1213 mAlloc = [format = mFormat,
Wonsik Kim41d83432020-04-27 16:40:49 -07001214 lbp = LocalBufferPool::Create()] {
Wonsik Kima39882b2019-06-20 16:13:56 -07001215 return ConstGraphicBlockBuffer::AllocateEmpty(
1216 format,
1217 [lbp](size_t capacity) {
1218 return lbp->newBuffer(capacity);
1219 });
1220 };
1221 ALOGD("[%s] reallocating with graphic buffer: format = %s",
1222 mName, mFormat->debugString().c_str());
1223 break;
1224 }
Wonsik Kim469c8342019-04-11 16:46:09 -07001225
1226 case C2BufferData::INVALID: [[fallthrough]];
1227 case C2BufferData::LINEAR_CHUNKS: [[fallthrough]];
1228 case C2BufferData::GRAPHIC_CHUNKS: [[fallthrough]];
1229 default:
1230 ALOGD("Unsupported type: %d", (int)c2buffer->data().type());
1231 return;
1232 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001233 mImpl.realloc(mAlloc);
Wonsik Kim469c8342019-04-11 16:46:09 -07001234}
1235
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001236void OutputBuffersArray::grow(size_t newSize) {
1237 mImpl.grow(newSize, mAlloc);
Wonsik Kim469c8342019-04-11 16:46:09 -07001238}
1239
Pawin Vongmasa9b906982020-04-11 05:07:15 -07001240void OutputBuffersArray::transferFrom(OutputBuffers* source) {
1241 mFormat = source->mFormat;
1242 mSkipCutBuffer = source->mSkipCutBuffer;
Pawin Vongmasa9b906982020-04-11 05:07:15 -07001243 mPending = std::move(source->mPending);
1244 mReorderStash = std::move(source->mReorderStash);
1245 mDepth = source->mDepth;
1246 mKey = source->mKey;
1247}
1248
Wonsik Kim469c8342019-04-11 16:46:09 -07001249// FlexOutputBuffers
1250
1251status_t FlexOutputBuffers::registerBuffer(
1252 const std::shared_ptr<C2Buffer> &buffer,
1253 size_t *index,
1254 sp<MediaCodecBuffer> *clientBuffer) {
Wonsik Kim6f23cfc2021-09-24 05:45:52 -07001255 sp<Codec2Buffer> newBuffer;
1256 if (!convert(buffer, &newBuffer)) {
1257 newBuffer = wrap(buffer);
1258 if (newBuffer == nullptr) {
1259 return NO_MEMORY;
1260 }
Wonsik Kim469c8342019-04-11 16:46:09 -07001261 }
1262 newBuffer->setFormat(mFormat);
1263 *index = mImpl.assignSlot(newBuffer);
1264 handleImageData(newBuffer);
1265 *clientBuffer = newBuffer;
1266 ALOGV("[%s] registered buffer %zu", mName, *index);
1267 return OK;
1268}
1269
1270status_t FlexOutputBuffers::registerCsd(
1271 const C2StreamInitDataInfo::output *csd,
1272 size_t *index,
1273 sp<MediaCodecBuffer> *clientBuffer) {
1274 sp<Codec2Buffer> newBuffer = new LocalLinearBuffer(
1275 mFormat, ABuffer::CreateAsCopy(csd->m.value, csd->flexCount()));
1276 *index = mImpl.assignSlot(newBuffer);
1277 *clientBuffer = newBuffer;
1278 return OK;
1279}
1280
1281bool FlexOutputBuffers::releaseBuffer(
1282 const sp<MediaCodecBuffer> &buffer,
1283 std::shared_ptr<C2Buffer> *c2buffer) {
1284 return mImpl.releaseSlot(buffer, c2buffer, true);
1285}
1286
1287void FlexOutputBuffers::flush(
1288 const std::list<std::unique_ptr<C2Work>> &flushedWork) {
1289 (void) flushedWork;
1290 // This is no-op by default unless we're in array mode where we need to keep
1291 // track of the flushed work.
1292}
1293
Pawin Vongmasa9b906982020-04-11 05:07:15 -07001294std::unique_ptr<OutputBuffersArray> FlexOutputBuffers::toArrayMode(size_t size) {
Wonsik Kim469c8342019-04-11 16:46:09 -07001295 std::unique_ptr<OutputBuffersArray> array(new OutputBuffersArray(mComponentName.c_str()));
Pawin Vongmasa9b906982020-04-11 05:07:15 -07001296 array->transferFrom(this);
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001297 std::function<sp<Codec2Buffer>()> alloc = getAlloc();
1298 array->initialize(mImpl, size, alloc);
Pawin Vongmasa9b906982020-04-11 05:07:15 -07001299 return array;
Wonsik Kim469c8342019-04-11 16:46:09 -07001300}
1301
Wonsik Kim0487b782020-10-28 11:45:50 -07001302size_t FlexOutputBuffers::numActiveSlots() const {
1303 return mImpl.numActiveSlots();
Wonsik Kim469c8342019-04-11 16:46:09 -07001304}
1305
1306// LinearOutputBuffers
1307
1308void LinearOutputBuffers::flush(
1309 const std::list<std::unique_ptr<C2Work>> &flushedWork) {
1310 if (mSkipCutBuffer != nullptr) {
1311 mSkipCutBuffer->clear();
1312 }
1313 FlexOutputBuffers::flush(flushedWork);
1314}
1315
1316sp<Codec2Buffer> LinearOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
1317 if (buffer == nullptr) {
1318 ALOGV("[%s] using a dummy buffer", mName);
1319 return new LocalLinearBuffer(mFormat, new ABuffer(0));
1320 }
1321 if (buffer->data().type() != C2BufferData::LINEAR) {
1322 ALOGV("[%s] non-linear buffer %d", mName, buffer->data().type());
1323 // We expect linear output buffers from the component.
1324 return nullptr;
1325 }
1326 if (buffer->data().linearBlocks().size() != 1u) {
1327 ALOGV("[%s] no linear buffers", mName);
1328 // We expect one and only one linear block from the component.
1329 return nullptr;
1330 }
1331 sp<Codec2Buffer> clientBuffer = ConstLinearBlockBuffer::Allocate(mFormat, buffer);
1332 if (clientBuffer == nullptr) {
1333 ALOGD("[%s] ConstLinearBlockBuffer::Allocate failed", mName);
1334 return nullptr;
1335 }
1336 submit(clientBuffer);
1337 return clientBuffer;
1338}
1339
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001340std::function<sp<Codec2Buffer>()> LinearOutputBuffers::getAlloc() {
1341 return [format = mFormat]{
1342 // TODO: proper max output size
1343 return new LocalLinearBuffer(format, new ABuffer(kLinearBufferSize));
1344 };
Wonsik Kim469c8342019-04-11 16:46:09 -07001345}
1346
1347// GraphicOutputBuffers
1348
1349sp<Codec2Buffer> GraphicOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
1350 return new DummyContainerBuffer(mFormat, buffer);
1351}
1352
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001353std::function<sp<Codec2Buffer>()> GraphicOutputBuffers::getAlloc() {
1354 return [format = mFormat]{
1355 return new DummyContainerBuffer(format);
1356 };
Wonsik Kim469c8342019-04-11 16:46:09 -07001357}
1358
1359// RawGraphicOutputBuffers
1360
1361RawGraphicOutputBuffers::RawGraphicOutputBuffers(
Wonsik Kim41d83432020-04-27 16:40:49 -07001362 const char *componentName, const char *name)
Wonsik Kim469c8342019-04-11 16:46:09 -07001363 : FlexOutputBuffers(componentName, name),
Wonsik Kim41d83432020-04-27 16:40:49 -07001364 mLocalBufferPool(LocalBufferPool::Create()) { }
Wonsik Kim469c8342019-04-11 16:46:09 -07001365
1366sp<Codec2Buffer> RawGraphicOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
1367 if (buffer == nullptr) {
Wonsik Kim6f116902021-07-14 08:58:07 -07001368 return new Codec2Buffer(mFormat, new ABuffer(nullptr, 0));
Wonsik Kim469c8342019-04-11 16:46:09 -07001369 } else {
1370 return ConstGraphicBlockBuffer::Allocate(
1371 mFormat,
1372 buffer,
1373 [lbp = mLocalBufferPool](size_t capacity) {
1374 return lbp->newBuffer(capacity);
1375 });
1376 }
1377}
1378
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001379std::function<sp<Codec2Buffer>()> RawGraphicOutputBuffers::getAlloc() {
1380 return [format = mFormat, lbp = mLocalBufferPool]{
1381 return ConstGraphicBlockBuffer::AllocateEmpty(
1382 format,
1383 [lbp](size_t capacity) {
1384 return lbp->newBuffer(capacity);
1385 });
1386 };
Wonsik Kim469c8342019-04-11 16:46:09 -07001387}
1388
1389} // namespace android