blob: 97e1a01a7904f36e3a828f8d7c5b6d2acd297907 [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
37sp<GraphicBlockBuffer> AllocateGraphicBuffer(
38 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
49 std::shared_ptr<C2GraphicBlock> block;
50 c2_status_t err = pool->fetchGraphicBlock(
51 width, height, pixelFormat, usage, &block);
52 if (err != C2_OK) {
53 ALOGD("fetch graphic block failed: %d", err);
54 return nullptr;
55 }
56
57 return GraphicBlockBuffer::Allocate(
58 format,
59 block,
60 [localBufferPool](size_t capacity) {
61 return localBufferPool->newBuffer(capacity);
62 });
63}
64
65} // namespace
66
67// CCodecBuffers
68
69void CCodecBuffers::setFormat(const sp<AMessage> &format) {
70 CHECK(format != nullptr);
71 mFormat = format;
72}
73
74sp<AMessage> CCodecBuffers::dupFormat() {
75 return mFormat != nullptr ? mFormat->dup() : nullptr;
76}
77
78void CCodecBuffers::handleImageData(const sp<Codec2Buffer> &buffer) {
79 sp<ABuffer> imageDataCandidate = buffer->getImageData();
80 if (imageDataCandidate == nullptr) {
Wonsik Kim4a3c0462021-03-09 15:45:05 -080081 if (mFormatWithImageData) {
82 // We previously sent the format with image data, so use the same format.
83 buffer->setFormat(mFormatWithImageData);
84 }
Wonsik Kim469c8342019-04-11 16:46:09 -070085 return;
86 }
Wonsik Kim4a3c0462021-03-09 15:45:05 -080087 if (!mLastImageData
88 || imageDataCandidate->size() != mLastImageData->size()
89 || memcmp(imageDataCandidate->data(),
90 mLastImageData->data(),
91 mLastImageData->size()) != 0) {
Wonsik Kim469c8342019-04-11 16:46:09 -070092 ALOGD("[%s] updating image-data", mName);
Wonsik Kim4a3c0462021-03-09 15:45:05 -080093 mFormatWithImageData = dupFormat();
94 mLastImageData = imageDataCandidate;
95 mFormatWithImageData->setBuffer("image-data", imageDataCandidate);
Wonsik Kim469c8342019-04-11 16:46:09 -070096 MediaImage2 *img = (MediaImage2*)imageDataCandidate->data();
97 if (img->mNumPlanes > 0 && img->mType != img->MEDIA_IMAGE_TYPE_UNKNOWN) {
98 int32_t stride = img->mPlane[0].mRowInc;
Wonsik Kim4a3c0462021-03-09 15:45:05 -080099 mFormatWithImageData->setInt32(KEY_STRIDE, stride);
Vinay Kaliaef5fc712021-09-15 23:59:50 +0000100 mFormatWithImageData->setInt32(KEY_WIDTH, img->mWidth);
101 mFormatWithImageData->setInt32(KEY_HEIGHT, img->mHeight);
102 ALOGD("[%s] updating stride = %d, width: %d, height: %d",
103 mName, stride, img->mWidth, img->mHeight);
Wonsik Kim469c8342019-04-11 16:46:09 -0700104 if (img->mNumPlanes > 1 && stride > 0) {
Taehwan Kimfd9b8092020-09-17 12:26:40 +0900105 int64_t offsetDelta =
106 (int64_t)img->mPlane[1].mOffset - (int64_t)img->mPlane[0].mOffset;
107 int32_t vstride = int32_t(offsetDelta / stride);
Wonsik Kim4a3c0462021-03-09 15:45:05 -0800108 mFormatWithImageData->setInt32(KEY_SLICE_HEIGHT, vstride);
Wonsik Kim469c8342019-04-11 16:46:09 -0700109 ALOGD("[%s] updating vstride = %d", mName, vstride);
Wonsik Kim2eb06312020-12-03 11:07:58 -0800110 buffer->setRange(
111 img->mPlane[0].mOffset,
112 buffer->size() - img->mPlane[0].mOffset);
Wonsik Kim469c8342019-04-11 16:46:09 -0700113 }
114 }
Wonsik Kim469c8342019-04-11 16:46:09 -0700115 }
Wonsik Kim4a3c0462021-03-09 15:45:05 -0800116 buffer->setFormat(mFormatWithImageData);
Wonsik Kim469c8342019-04-11 16:46:09 -0700117}
118
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700119// InputBuffers
120
121sp<Codec2Buffer> InputBuffers::cloneAndReleaseBuffer(const sp<MediaCodecBuffer> &buffer) {
122 sp<Codec2Buffer> copy = createNewBuffer();
123 if (copy == nullptr) {
124 return nullptr;
125 }
126 std::shared_ptr<C2Buffer> c2buffer;
127 if (!releaseBuffer(buffer, &c2buffer, true)) {
128 return nullptr;
129 }
130 if (!copy->canCopy(c2buffer)) {
131 return nullptr;
132 }
133 if (!copy->copy(c2buffer)) {
134 return nullptr;
135 }
Wonsik Kimfb5ca492021-08-11 14:18:19 -0700136 copy->meta()->extend(buffer->meta());
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700137 return copy;
138}
139
Wonsik Kim469c8342019-04-11 16:46:09 -0700140// OutputBuffers
141
Wonsik Kim41d83432020-04-27 16:40:49 -0700142OutputBuffers::OutputBuffers(const char *componentName, const char *name)
143 : CCodecBuffers(componentName, name) { }
144
145OutputBuffers::~OutputBuffers() = default;
146
Wonsik Kim469c8342019-04-11 16:46:09 -0700147void OutputBuffers::initSkipCutBuffer(
148 int32_t delay, int32_t padding, int32_t sampleRate, int32_t channelCount) {
149 CHECK(mSkipCutBuffer == nullptr);
150 mDelay = delay;
151 mPadding = padding;
152 mSampleRate = sampleRate;
Wonsik Kim40b0b1d2020-03-25 15:47:35 -0700153 mChannelCount = channelCount;
154 setSkipCutBuffer(delay, padding);
Wonsik Kim469c8342019-04-11 16:46:09 -0700155}
156
157void OutputBuffers::updateSkipCutBuffer(int32_t sampleRate, int32_t channelCount) {
158 if (mSkipCutBuffer == nullptr) {
159 return;
160 }
Wonsik Kim40b0b1d2020-03-25 15:47:35 -0700161 if (mSampleRate == sampleRate && mChannelCount == channelCount) {
162 return;
163 }
Wonsik Kim469c8342019-04-11 16:46:09 -0700164 int32_t delay = mDelay;
165 int32_t padding = mPadding;
166 if (sampleRate != mSampleRate) {
167 delay = ((int64_t)delay * sampleRate) / mSampleRate;
168 padding = ((int64_t)padding * sampleRate) / mSampleRate;
169 }
Wonsik Kim40b0b1d2020-03-25 15:47:35 -0700170 mSampleRate = sampleRate;
171 mChannelCount = channelCount;
172 setSkipCutBuffer(delay, padding);
Wonsik Kim469c8342019-04-11 16:46:09 -0700173}
174
Wonsik Kim970bf0b2020-11-10 11:54:15 -0800175void OutputBuffers::updateSkipCutBuffer(const sp<AMessage> &format) {
Pawin Vongmasa9b906982020-04-11 05:07:15 -0700176 AString mediaType;
177 if (format->findString(KEY_MIME, &mediaType)
178 && mediaType == MIMETYPE_AUDIO_RAW) {
179 int32_t channelCount;
180 int32_t sampleRate;
181 if (format->findInt32(KEY_CHANNEL_COUNT, &channelCount)
182 && format->findInt32(KEY_SAMPLE_RATE, &sampleRate)) {
183 updateSkipCutBuffer(sampleRate, channelCount);
184 }
185 }
Pawin Vongmasa9b906982020-04-11 05:07:15 -0700186}
187
Wonsik Kim469c8342019-04-11 16:46:09 -0700188void OutputBuffers::submit(const sp<MediaCodecBuffer> &buffer) {
189 if (mSkipCutBuffer != nullptr) {
190 mSkipCutBuffer->submit(buffer);
191 }
192}
193
Wonsik Kim40b0b1d2020-03-25 15:47:35 -0700194void OutputBuffers::setSkipCutBuffer(int32_t skip, int32_t cut) {
Wonsik Kim469c8342019-04-11 16:46:09 -0700195 if (mSkipCutBuffer != nullptr) {
196 size_t prevSize = mSkipCutBuffer->size();
197 if (prevSize != 0u) {
198 ALOGD("[%s] Replacing SkipCutBuffer holding %zu bytes", mName, prevSize);
199 }
200 }
Wonsik Kim40b0b1d2020-03-25 15:47:35 -0700201 mSkipCutBuffer = new SkipCutBuffer(skip, cut, mChannelCount);
Wonsik Kim469c8342019-04-11 16:46:09 -0700202}
203
Wonsik Kim6f23cfc2021-09-24 05:45:52 -0700204bool OutputBuffers::convert(
205 const std::shared_ptr<C2Buffer> &src, sp<Codec2Buffer> *dst) {
206 if (!src || src->data().type() != C2BufferData::LINEAR) {
207 return false;
208 }
209 int32_t configEncoding = kAudioEncodingPcm16bit;
210 int32_t codecEncoding = kAudioEncodingPcm16bit;
211 if (mFormat->findInt32("android._codec-pcm-encoding", &codecEncoding)
212 && mFormat->findInt32("android._config-pcm-encoding", &configEncoding)) {
213 if (mSrcEncoding != codecEncoding || mDstEncoding != configEncoding) {
214 if (codecEncoding != configEncoding) {
215 mDataConverter = AudioConverter::Create(
216 (AudioEncoding)codecEncoding, (AudioEncoding)configEncoding);
217 ALOGD_IF(mDataConverter, "[%s] Converter created from %d to %d",
218 mName, codecEncoding, configEncoding);
219 mFormatWithConverter = mFormat->dup();
220 mFormatWithConverter->setInt32(KEY_PCM_ENCODING, configEncoding);
221 } else {
222 mDataConverter = nullptr;
223 mFormatWithConverter = nullptr;
224 }
225 mSrcEncoding = codecEncoding;
226 mDstEncoding = configEncoding;
227 }
228 if (int encoding; !mFormat->findInt32(KEY_PCM_ENCODING, &encoding)
229 || encoding != mDstEncoding) {
230 }
231 }
232 if (!mDataConverter) {
233 return false;
234 }
235 sp<MediaCodecBuffer> srcBuffer = ConstLinearBlockBuffer::Allocate(mFormat, src);
236 if (!srcBuffer) {
237 return false;
238 }
Greg Kaiser92dc4542021-10-08 06:58:19 -0700239 if (!*dst) {
Wonsik Kim6f23cfc2021-09-24 05:45:52 -0700240 *dst = new Codec2Buffer(
241 mFormat,
242 new ABuffer(mDataConverter->targetSize(srcBuffer->size())));
243 }
244 sp<MediaCodecBuffer> dstBuffer = *dst;
245 status_t err = mDataConverter->convert(srcBuffer, dstBuffer);
246 if (err != OK) {
247 ALOGD("[%s] buffer conversion failed: %d", mName, err);
248 return false;
249 }
250 dstBuffer->setFormat(mFormatWithConverter);
251 return true;
252}
253
Pawin Vongmasa9b906982020-04-11 05:07:15 -0700254void OutputBuffers::clearStash() {
255 mPending.clear();
256 mReorderStash.clear();
257 mDepth = 0;
258 mKey = C2Config::ORDINAL;
Pawin Vongmasa9b906982020-04-11 05:07:15 -0700259}
260
261void OutputBuffers::flushStash() {
262 for (StashEntry& e : mPending) {
263 e.notify = false;
264 }
265 for (StashEntry& e : mReorderStash) {
266 e.notify = false;
267 }
268}
269
270uint32_t OutputBuffers::getReorderDepth() const {
271 return mDepth;
272}
273
274void OutputBuffers::setReorderDepth(uint32_t depth) {
275 mPending.splice(mPending.end(), mReorderStash);
276 mDepth = depth;
277}
278
279void OutputBuffers::setReorderKey(C2Config::ordinal_key_t key) {
280 mPending.splice(mPending.end(), mReorderStash);
281 mKey = key;
282}
283
284void OutputBuffers::pushToStash(
285 const std::shared_ptr<C2Buffer>& buffer,
286 bool notify,
287 int64_t timestamp,
288 int32_t flags,
289 const sp<AMessage>& format,
290 const C2WorkOrdinalStruct& ordinal) {
291 bool eos = flags & MediaCodec::BUFFER_FLAG_EOS;
292 if (!buffer && eos) {
293 // TRICKY: we may be violating ordering of the stash here. Because we
294 // don't expect any more emplace() calls after this, the ordering should
295 // not matter.
296 mReorderStash.emplace_back(
297 buffer, notify, timestamp, flags, format, ordinal);
298 } else {
299 flags = flags & ~MediaCodec::BUFFER_FLAG_EOS;
300 auto it = mReorderStash.begin();
301 for (; it != mReorderStash.end(); ++it) {
302 if (less(ordinal, it->ordinal)) {
303 break;
304 }
305 }
306 mReorderStash.emplace(it,
307 buffer, notify, timestamp, flags, format, ordinal);
308 if (eos) {
309 mReorderStash.back().flags =
310 mReorderStash.back().flags | MediaCodec::BUFFER_FLAG_EOS;
311 }
312 }
313 while (!mReorderStash.empty() && mReorderStash.size() > mDepth) {
314 mPending.push_back(mReorderStash.front());
315 mReorderStash.pop_front();
316 }
317 ALOGV("[%s] %s: pushToStash -- pending size = %zu", mName, __func__, mPending.size());
318}
319
320OutputBuffers::BufferAction OutputBuffers::popFromStashAndRegister(
321 std::shared_ptr<C2Buffer>* c2Buffer,
322 size_t* index,
323 sp<MediaCodecBuffer>* outBuffer) {
324 if (mPending.empty()) {
325 return SKIP;
326 }
327
328 // Retrieve the first entry.
329 StashEntry &entry = mPending.front();
330
331 *c2Buffer = entry.buffer;
332 sp<AMessage> outputFormat = entry.format;
333
Wonsik Kim970bf0b2020-11-10 11:54:15 -0800334 if (entry.notify && mFormat != outputFormat) {
335 updateSkipCutBuffer(outputFormat);
Wonsik Kim4a3c0462021-03-09 15:45:05 -0800336 // Trigger image data processing to the new format
337 mLastImageData.clear();
Wonsik Kim970bf0b2020-11-10 11:54:15 -0800338 ALOGV("[%s] popFromStashAndRegister: output format reference changed: %p -> %p",
339 mName, mFormat.get(), outputFormat.get());
Wonsik Kim4a3c0462021-03-09 15:45:05 -0800340 ALOGD("[%s] popFromStashAndRegister: at %lldus, output format changed to %s",
341 mName, (long long)entry.timestamp, outputFormat->debugString().c_str());
Wonsik Kim970bf0b2020-11-10 11:54:15 -0800342 setFormat(outputFormat);
Pawin Vongmasa9b906982020-04-11 05:07:15 -0700343 }
344
345 // Flushing mReorderStash because no other buffers should come after output
346 // EOS.
347 if (entry.flags & MediaCodec::BUFFER_FLAG_EOS) {
348 // Flush reorder stash
349 setReorderDepth(0);
350 }
351
352 if (!entry.notify) {
353 mPending.pop_front();
354 return DISCARD;
355 }
356
357 // Try to register the buffer.
358 status_t err = registerBuffer(*c2Buffer, index, outBuffer);
359 if (err != OK) {
360 if (err != WOULD_BLOCK) {
361 return REALLOCATE;
362 }
363 return RETRY;
364 }
365
366 // Append information from the front stash entry to outBuffer.
367 (*outBuffer)->meta()->setInt64("timeUs", entry.timestamp);
368 (*outBuffer)->meta()->setInt32("flags", entry.flags);
Byeongjo Park25c3a3d2020-06-12 17:24:21 +0900369 (*outBuffer)->meta()->setInt64("frameIndex", entry.ordinal.frameIndex.peekll());
Pawin Vongmasa9b906982020-04-11 05:07:15 -0700370 ALOGV("[%s] popFromStashAndRegister: "
371 "out buffer index = %zu [%p] => %p + %zu (%lld)",
372 mName, *index, outBuffer->get(),
373 (*outBuffer)->data(), (*outBuffer)->size(),
374 (long long)entry.timestamp);
375
376 // The front entry of mPending will be removed now that the registration
377 // succeeded.
378 mPending.pop_front();
379 return NOTIFY_CLIENT;
380}
381
382bool OutputBuffers::popPending(StashEntry *entry) {
383 if (mPending.empty()) {
384 return false;
385 }
386 *entry = mPending.front();
387 mPending.pop_front();
388 return true;
389}
390
391void OutputBuffers::deferPending(const OutputBuffers::StashEntry &entry) {
392 mPending.push_front(entry);
393}
394
395bool OutputBuffers::hasPending() const {
396 return !mPending.empty();
397}
398
399bool OutputBuffers::less(
400 const C2WorkOrdinalStruct &o1, const C2WorkOrdinalStruct &o2) const {
401 switch (mKey) {
402 case C2Config::ORDINAL: return o1.frameIndex < o2.frameIndex;
403 case C2Config::TIMESTAMP: return o1.timestamp < o2.timestamp;
404 case C2Config::CUSTOM: return o1.customOrdinal < o2.customOrdinal;
405 default:
406 ALOGD("Unrecognized key; default to timestamp");
407 return o1.frameIndex < o2.frameIndex;
408 }
409}
410
Wonsik Kim469c8342019-04-11 16:46:09 -0700411// LocalBufferPool
412
Wonsik Kim41d83432020-04-27 16:40:49 -0700413constexpr size_t kInitialPoolCapacity = kMaxLinearBufferSize;
414constexpr size_t kMaxPoolCapacity = kMaxLinearBufferSize * 32;
415
416std::shared_ptr<LocalBufferPool> LocalBufferPool::Create() {
417 return std::shared_ptr<LocalBufferPool>(new LocalBufferPool(kInitialPoolCapacity));
Wonsik Kim469c8342019-04-11 16:46:09 -0700418}
419
420sp<ABuffer> LocalBufferPool::newBuffer(size_t capacity) {
421 Mutex::Autolock lock(mMutex);
422 auto it = std::find_if(
423 mPool.begin(), mPool.end(),
424 [capacity](const std::vector<uint8_t> &vec) {
425 return vec.capacity() >= capacity;
426 });
427 if (it != mPool.end()) {
428 sp<ABuffer> buffer = new VectorBuffer(std::move(*it), shared_from_this());
429 mPool.erase(it);
430 return buffer;
431 }
432 if (mUsedSize + capacity > mPoolCapacity) {
433 while (!mPool.empty()) {
434 mUsedSize -= mPool.back().capacity();
435 mPool.pop_back();
436 }
Wonsik Kim41d83432020-04-27 16:40:49 -0700437 while (mUsedSize + capacity > mPoolCapacity && mPoolCapacity * 2 <= kMaxPoolCapacity) {
438 ALOGD("Increasing local buffer pool capacity from %zu to %zu",
439 mPoolCapacity, mPoolCapacity * 2);
440 mPoolCapacity *= 2;
441 }
Wonsik Kim469c8342019-04-11 16:46:09 -0700442 if (mUsedSize + capacity > mPoolCapacity) {
443 ALOGD("mUsedSize = %zu, capacity = %zu, mPoolCapacity = %zu",
444 mUsedSize, capacity, mPoolCapacity);
445 return nullptr;
446 }
447 }
448 std::vector<uint8_t> vec(capacity);
449 mUsedSize += vec.capacity();
450 return new VectorBuffer(std::move(vec), shared_from_this());
451}
452
453LocalBufferPool::VectorBuffer::VectorBuffer(
454 std::vector<uint8_t> &&vec, const std::shared_ptr<LocalBufferPool> &pool)
455 : ABuffer(vec.data(), vec.capacity()),
456 mVec(std::move(vec)),
457 mPool(pool) {
458}
459
460LocalBufferPool::VectorBuffer::~VectorBuffer() {
461 std::shared_ptr<LocalBufferPool> pool = mPool.lock();
462 if (pool) {
463 // If pool is alive, return the vector back to the pool so that
464 // it can be recycled.
465 pool->returnVector(std::move(mVec));
466 }
467}
468
469void LocalBufferPool::returnVector(std::vector<uint8_t> &&vec) {
470 Mutex::Autolock lock(mMutex);
471 mPool.push_front(std::move(vec));
472}
473
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700474// FlexBuffersImpl
475
Wonsik Kim469c8342019-04-11 16:46:09 -0700476size_t FlexBuffersImpl::assignSlot(const sp<Codec2Buffer> &buffer) {
477 for (size_t i = 0; i < mBuffers.size(); ++i) {
478 if (mBuffers[i].clientBuffer == nullptr
479 && mBuffers[i].compBuffer.expired()) {
480 mBuffers[i].clientBuffer = buffer;
481 return i;
482 }
483 }
484 mBuffers.push_back({ buffer, std::weak_ptr<C2Buffer>() });
485 return mBuffers.size() - 1;
486}
487
Wonsik Kim469c8342019-04-11 16:46:09 -0700488bool FlexBuffersImpl::releaseSlot(
489 const sp<MediaCodecBuffer> &buffer,
490 std::shared_ptr<C2Buffer> *c2buffer,
491 bool release) {
492 sp<Codec2Buffer> clientBuffer;
493 size_t index = mBuffers.size();
494 for (size_t i = 0; i < mBuffers.size(); ++i) {
495 if (mBuffers[i].clientBuffer == buffer) {
496 clientBuffer = mBuffers[i].clientBuffer;
497 if (release) {
498 mBuffers[i].clientBuffer.clear();
499 }
500 index = i;
501 break;
502 }
503 }
504 if (clientBuffer == nullptr) {
505 ALOGV("[%s] %s: No matching buffer found", mName, __func__);
506 return false;
507 }
508 std::shared_ptr<C2Buffer> result = mBuffers[index].compBuffer.lock();
509 if (!result) {
510 result = clientBuffer->asC2Buffer();
Wonsik Kimf9b32122020-04-02 11:30:17 -0700511 clientBuffer->clearC2BufferRefs();
Wonsik Kim469c8342019-04-11 16:46:09 -0700512 mBuffers[index].compBuffer = result;
513 }
514 if (c2buffer) {
515 *c2buffer = result;
516 }
517 return true;
518}
519
520bool FlexBuffersImpl::expireComponentBuffer(const std::shared_ptr<C2Buffer> &c2buffer) {
521 for (size_t i = 0; i < mBuffers.size(); ++i) {
522 std::shared_ptr<C2Buffer> compBuffer =
523 mBuffers[i].compBuffer.lock();
524 if (!compBuffer || compBuffer != c2buffer) {
525 continue;
526 }
527 mBuffers[i].compBuffer.reset();
528 ALOGV("[%s] codec released buffer #%zu", mName, i);
529 return true;
530 }
531 ALOGV("[%s] codec released an unknown buffer", mName);
532 return false;
533}
534
535void FlexBuffersImpl::flush() {
536 ALOGV("[%s] buffers are flushed %zu", mName, mBuffers.size());
537 mBuffers.clear();
538}
539
Wonsik Kim0487b782020-10-28 11:45:50 -0700540size_t FlexBuffersImpl::numActiveSlots() const {
Wonsik Kim469c8342019-04-11 16:46:09 -0700541 return std::count_if(
542 mBuffers.begin(), mBuffers.end(),
543 [](const Entry &entry) {
Wonsik Kim0487b782020-10-28 11:45:50 -0700544 return (entry.clientBuffer != nullptr
545 || !entry.compBuffer.expired());
Wonsik Kim469c8342019-04-11 16:46:09 -0700546 });
547}
548
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700549size_t FlexBuffersImpl::numComponentBuffers() const {
550 return std::count_if(
551 mBuffers.begin(), mBuffers.end(),
552 [](const Entry &entry) {
553 return !entry.compBuffer.expired();
554 });
555}
556
Wonsik Kim469c8342019-04-11 16:46:09 -0700557// BuffersArrayImpl
558
559void BuffersArrayImpl::initialize(
560 const FlexBuffersImpl &impl,
561 size_t minSize,
562 std::function<sp<Codec2Buffer>()> allocate) {
563 mImplName = impl.mImplName + "[N]";
564 mName = mImplName.c_str();
565 for (size_t i = 0; i < impl.mBuffers.size(); ++i) {
566 sp<Codec2Buffer> clientBuffer = impl.mBuffers[i].clientBuffer;
567 bool ownedByClient = (clientBuffer != nullptr);
568 if (!ownedByClient) {
569 clientBuffer = allocate();
570 }
571 mBuffers.push_back({ clientBuffer, impl.mBuffers[i].compBuffer, ownedByClient });
572 }
573 ALOGV("[%s] converted %zu buffers to array mode of %zu", mName, mBuffers.size(), minSize);
574 for (size_t i = impl.mBuffers.size(); i < minSize; ++i) {
575 mBuffers.push_back({ allocate(), std::weak_ptr<C2Buffer>(), false });
576 }
577}
578
579status_t BuffersArrayImpl::grabBuffer(
580 size_t *index,
581 sp<Codec2Buffer> *buffer,
582 std::function<bool(const sp<Codec2Buffer> &)> match) {
583 // allBuffersDontMatch remains true if all buffers are available but
584 // match() returns false for every buffer.
585 bool allBuffersDontMatch = true;
586 for (size_t i = 0; i < mBuffers.size(); ++i) {
587 if (!mBuffers[i].ownedByClient && mBuffers[i].compBuffer.expired()) {
588 if (match(mBuffers[i].clientBuffer)) {
589 mBuffers[i].ownedByClient = true;
590 *buffer = mBuffers[i].clientBuffer;
591 (*buffer)->meta()->clear();
592 (*buffer)->setRange(0, (*buffer)->capacity());
593 *index = i;
594 return OK;
595 }
596 } else {
597 allBuffersDontMatch = false;
598 }
599 }
600 return allBuffersDontMatch ? NO_MEMORY : WOULD_BLOCK;
601}
602
603bool BuffersArrayImpl::returnBuffer(
604 const sp<MediaCodecBuffer> &buffer,
605 std::shared_ptr<C2Buffer> *c2buffer,
606 bool release) {
607 sp<Codec2Buffer> clientBuffer;
608 size_t index = mBuffers.size();
609 for (size_t i = 0; i < mBuffers.size(); ++i) {
610 if (mBuffers[i].clientBuffer == buffer) {
611 if (!mBuffers[i].ownedByClient) {
612 ALOGD("[%s] Client returned a buffer it does not own according to our record: %zu",
613 mName, i);
614 }
615 clientBuffer = mBuffers[i].clientBuffer;
616 if (release) {
617 mBuffers[i].ownedByClient = false;
618 }
619 index = i;
620 break;
621 }
622 }
623 if (clientBuffer == nullptr) {
624 ALOGV("[%s] %s: No matching buffer found", mName, __func__);
625 return false;
626 }
627 ALOGV("[%s] %s: matching buffer found (index=%zu)", mName, __func__, index);
628 std::shared_ptr<C2Buffer> result = mBuffers[index].compBuffer.lock();
629 if (!result) {
630 result = clientBuffer->asC2Buffer();
Wonsik Kimf9b32122020-04-02 11:30:17 -0700631 clientBuffer->clearC2BufferRefs();
Wonsik Kim469c8342019-04-11 16:46:09 -0700632 mBuffers[index].compBuffer = result;
633 }
634 if (c2buffer) {
635 *c2buffer = result;
636 }
637 return true;
638}
639
640bool BuffersArrayImpl::expireComponentBuffer(const std::shared_ptr<C2Buffer> &c2buffer) {
641 for (size_t i = 0; i < mBuffers.size(); ++i) {
642 std::shared_ptr<C2Buffer> compBuffer =
643 mBuffers[i].compBuffer.lock();
644 if (!compBuffer) {
645 continue;
646 }
647 if (c2buffer == compBuffer) {
648 if (mBuffers[i].ownedByClient) {
649 // This should not happen.
650 ALOGD("[%s] codec released a buffer owned by client "
651 "(index %zu)", mName, i);
652 }
653 mBuffers[i].compBuffer.reset();
654 ALOGV("[%s] codec released buffer #%zu(array mode)", mName, i);
655 return true;
656 }
657 }
658 ALOGV("[%s] codec released an unknown buffer (array mode)", mName);
659 return false;
660}
661
662void BuffersArrayImpl::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
663 array->clear();
664 for (const Entry &entry : mBuffers) {
665 array->push(entry.clientBuffer);
666 }
667}
668
669void BuffersArrayImpl::flush() {
670 for (Entry &entry : mBuffers) {
671 entry.ownedByClient = false;
672 }
673}
674
675void BuffersArrayImpl::realloc(std::function<sp<Codec2Buffer>()> alloc) {
676 size_t size = mBuffers.size();
677 mBuffers.clear();
678 for (size_t i = 0; i < size; ++i) {
679 mBuffers.push_back({ alloc(), std::weak_ptr<C2Buffer>(), false });
680 }
681}
682
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700683void BuffersArrayImpl::grow(
684 size_t newSize, std::function<sp<Codec2Buffer>()> alloc) {
685 CHECK_LT(mBuffers.size(), newSize);
686 while (mBuffers.size() < newSize) {
687 mBuffers.push_back({ alloc(), std::weak_ptr<C2Buffer>(), false });
688 }
689}
690
Wonsik Kim0487b782020-10-28 11:45:50 -0700691size_t BuffersArrayImpl::numActiveSlots() const {
Wonsik Kim469c8342019-04-11 16:46:09 -0700692 return std::count_if(
693 mBuffers.begin(), mBuffers.end(),
694 [](const Entry &entry) {
Wonsik Kim0487b782020-10-28 11:45:50 -0700695 return entry.ownedByClient || !entry.compBuffer.expired();
Wonsik Kim469c8342019-04-11 16:46:09 -0700696 });
697}
698
Wonsik Kima39882b2019-06-20 16:13:56 -0700699size_t BuffersArrayImpl::arraySize() const {
700 return mBuffers.size();
701}
702
Wonsik Kim469c8342019-04-11 16:46:09 -0700703// InputBuffersArray
704
705void InputBuffersArray::initialize(
706 const FlexBuffersImpl &impl,
707 size_t minSize,
708 std::function<sp<Codec2Buffer>()> allocate) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700709 mAllocate = allocate;
Wonsik Kim469c8342019-04-11 16:46:09 -0700710 mImpl.initialize(impl, minSize, allocate);
711}
712
713void InputBuffersArray::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
714 mImpl.getArray(array);
715}
716
717bool InputBuffersArray::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
718 sp<Codec2Buffer> c2Buffer;
719 status_t err = mImpl.grabBuffer(index, &c2Buffer);
720 if (err == OK) {
721 c2Buffer->setFormat(mFormat);
722 handleImageData(c2Buffer);
723 *buffer = c2Buffer;
724 return true;
725 }
726 return false;
727}
728
729bool InputBuffersArray::releaseBuffer(
730 const sp<MediaCodecBuffer> &buffer,
731 std::shared_ptr<C2Buffer> *c2buffer,
732 bool release) {
733 return mImpl.returnBuffer(buffer, c2buffer, release);
734}
735
736bool InputBuffersArray::expireComponentBuffer(
737 const std::shared_ptr<C2Buffer> &c2buffer) {
738 return mImpl.expireComponentBuffer(c2buffer);
739}
740
741void InputBuffersArray::flush() {
742 mImpl.flush();
743}
744
Wonsik Kim0487b782020-10-28 11:45:50 -0700745size_t InputBuffersArray::numActiveSlots() const {
746 return mImpl.numActiveSlots();
Wonsik Kim469c8342019-04-11 16:46:09 -0700747}
748
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700749sp<Codec2Buffer> InputBuffersArray::createNewBuffer() {
750 return mAllocate();
751}
752
Wonsik Kimfb7a7672019-12-27 17:13:33 -0800753// SlotInputBuffers
754
755bool SlotInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
756 sp<Codec2Buffer> newBuffer = createNewBuffer();
757 *index = mImpl.assignSlot(newBuffer);
758 *buffer = newBuffer;
759 return true;
760}
761
762bool SlotInputBuffers::releaseBuffer(
763 const sp<MediaCodecBuffer> &buffer,
764 std::shared_ptr<C2Buffer> *c2buffer,
765 bool release) {
766 return mImpl.releaseSlot(buffer, c2buffer, release);
767}
768
769bool SlotInputBuffers::expireComponentBuffer(
770 const std::shared_ptr<C2Buffer> &c2buffer) {
771 return mImpl.expireComponentBuffer(c2buffer);
772}
773
774void SlotInputBuffers::flush() {
775 mImpl.flush();
776}
777
778std::unique_ptr<InputBuffers> SlotInputBuffers::toArrayMode(size_t) {
779 TRESPASS("Array mode should not be called at non-legacy mode");
780 return nullptr;
781}
782
Wonsik Kim0487b782020-10-28 11:45:50 -0700783size_t SlotInputBuffers::numActiveSlots() const {
784 return mImpl.numActiveSlots();
Wonsik Kimfb7a7672019-12-27 17:13:33 -0800785}
786
787sp<Codec2Buffer> SlotInputBuffers::createNewBuffer() {
788 return new DummyContainerBuffer{mFormat, nullptr};
789}
790
Wonsik Kim469c8342019-04-11 16:46:09 -0700791// LinearInputBuffers
792
793bool LinearInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700794 sp<Codec2Buffer> newBuffer = createNewBuffer();
Wonsik Kim469c8342019-04-11 16:46:09 -0700795 if (newBuffer == nullptr) {
796 return false;
797 }
798 *index = mImpl.assignSlot(newBuffer);
799 *buffer = newBuffer;
800 return true;
801}
802
803bool LinearInputBuffers::releaseBuffer(
804 const sp<MediaCodecBuffer> &buffer,
805 std::shared_ptr<C2Buffer> *c2buffer,
806 bool release) {
807 return mImpl.releaseSlot(buffer, c2buffer, release);
808}
809
810bool LinearInputBuffers::expireComponentBuffer(
811 const std::shared_ptr<C2Buffer> &c2buffer) {
812 return mImpl.expireComponentBuffer(c2buffer);
813}
814
815void LinearInputBuffers::flush() {
816 // This is no-op by default unless we're in array mode where we need to keep
817 // track of the flushed work.
818 mImpl.flush();
819}
820
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700821std::unique_ptr<InputBuffers> LinearInputBuffers::toArrayMode(size_t size) {
Wonsik Kim469c8342019-04-11 16:46:09 -0700822 std::unique_ptr<InputBuffersArray> array(
823 new InputBuffersArray(mComponentName.c_str(), "1D-Input[N]"));
824 array->setPool(mPool);
825 array->setFormat(mFormat);
826 array->initialize(
827 mImpl,
828 size,
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700829 [pool = mPool, format = mFormat] () -> sp<Codec2Buffer> {
830 return Alloc(pool, format);
831 });
Wonsik Kim469c8342019-04-11 16:46:09 -0700832 return std::move(array);
833}
834
Wonsik Kim0487b782020-10-28 11:45:50 -0700835size_t LinearInputBuffers::numActiveSlots() const {
836 return mImpl.numActiveSlots();
Wonsik Kim469c8342019-04-11 16:46:09 -0700837}
838
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700839// static
840sp<Codec2Buffer> LinearInputBuffers::Alloc(
841 const std::shared_ptr<C2BlockPool> &pool, const sp<AMessage> &format) {
842 int32_t capacity = kLinearBufferSize;
843 (void)format->findInt32(KEY_MAX_INPUT_SIZE, &capacity);
844 if ((size_t)capacity > kMaxLinearBufferSize) {
845 ALOGD("client requested %d, capped to %zu", capacity, kMaxLinearBufferSize);
846 capacity = kMaxLinearBufferSize;
847 }
848
Wonsik Kim666604a2020-05-14 16:57:49 -0700849 int64_t usageValue = 0;
850 (void)format->findInt64("android._C2MemoryUsage", &usageValue);
851 C2MemoryUsage usage{usageValue | C2MemoryUsage::CPU_READ | C2MemoryUsage::CPU_WRITE};
Wonsik Kim469c8342019-04-11 16:46:09 -0700852 std::shared_ptr<C2LinearBlock> block;
853
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700854 c2_status_t err = pool->fetchLinearBlock(capacity, usage, &block);
Wonsik Kim469c8342019-04-11 16:46:09 -0700855 if (err != C2_OK) {
856 return nullptr;
857 }
858
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700859 return LinearBlockBuffer::Allocate(format, block);
860}
861
862sp<Codec2Buffer> LinearInputBuffers::createNewBuffer() {
863 return Alloc(mPool, mFormat);
Wonsik Kim469c8342019-04-11 16:46:09 -0700864}
865
866// EncryptedLinearInputBuffers
867
868EncryptedLinearInputBuffers::EncryptedLinearInputBuffers(
869 bool secure,
870 const sp<MemoryDealer> &dealer,
871 const sp<ICrypto> &crypto,
872 int32_t heapSeqNum,
873 size_t capacity,
874 size_t numInputSlots,
875 const char *componentName, const char *name)
876 : LinearInputBuffers(componentName, name),
877 mUsage({0, 0}),
878 mDealer(dealer),
879 mCrypto(crypto),
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700880 mMemoryVector(new std::vector<Entry>){
Wonsik Kim469c8342019-04-11 16:46:09 -0700881 if (secure) {
882 mUsage = { C2MemoryUsage::READ_PROTECTED, 0 };
883 } else {
884 mUsage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
885 }
886 for (size_t i = 0; i < numInputSlots; ++i) {
887 sp<IMemory> memory = mDealer->allocate(capacity);
888 if (memory == nullptr) {
889 ALOGD("[%s] Failed to allocate memory from dealer: only %zu slots allocated",
890 mName, i);
891 break;
892 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700893 mMemoryVector->push_back({std::weak_ptr<C2LinearBlock>(), memory, heapSeqNum});
Wonsik Kim469c8342019-04-11 16:46:09 -0700894 }
895}
896
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700897std::unique_ptr<InputBuffers> EncryptedLinearInputBuffers::toArrayMode(size_t size) {
898 std::unique_ptr<InputBuffersArray> array(
899 new InputBuffersArray(mComponentName.c_str(), "1D-EncryptedInput[N]"));
900 array->setPool(mPool);
901 array->setFormat(mFormat);
902 array->initialize(
903 mImpl,
904 size,
905 [pool = mPool,
906 format = mFormat,
907 usage = mUsage,
908 memoryVector = mMemoryVector] () -> sp<Codec2Buffer> {
909 return Alloc(pool, format, usage, memoryVector);
910 });
911 return std::move(array);
912}
913
914
915// static
916sp<Codec2Buffer> EncryptedLinearInputBuffers::Alloc(
917 const std::shared_ptr<C2BlockPool> &pool,
918 const sp<AMessage> &format,
919 C2MemoryUsage usage,
920 const std::shared_ptr<std::vector<EncryptedLinearInputBuffers::Entry>> &memoryVector) {
921 int32_t capacity = kLinearBufferSize;
922 (void)format->findInt32(KEY_MAX_INPUT_SIZE, &capacity);
923 if ((size_t)capacity > kMaxLinearBufferSize) {
924 ALOGD("client requested %d, capped to %zu", capacity, kMaxLinearBufferSize);
925 capacity = kMaxLinearBufferSize;
926 }
927
Wonsik Kim469c8342019-04-11 16:46:09 -0700928 sp<IMemory> memory;
929 size_t slot = 0;
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700930 int32_t heapSeqNum = -1;
931 for (; slot < memoryVector->size(); ++slot) {
932 if (memoryVector->at(slot).block.expired()) {
933 memory = memoryVector->at(slot).memory;
934 heapSeqNum = memoryVector->at(slot).heapSeqNum;
Wonsik Kim469c8342019-04-11 16:46:09 -0700935 break;
936 }
937 }
938 if (memory == nullptr) {
939 return nullptr;
940 }
941
942 std::shared_ptr<C2LinearBlock> block;
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700943 c2_status_t err = pool->fetchLinearBlock(capacity, usage, &block);
Wonsik Kim469c8342019-04-11 16:46:09 -0700944 if (err != C2_OK || block == nullptr) {
945 return nullptr;
946 }
947
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700948 memoryVector->at(slot).block = block;
949 return new EncryptedLinearBlockBuffer(format, block, memory, heapSeqNum);
950}
951
952sp<Codec2Buffer> EncryptedLinearInputBuffers::createNewBuffer() {
953 // TODO: android_2020
954 return nullptr;
Wonsik Kim469c8342019-04-11 16:46:09 -0700955}
956
957// GraphicMetadataInputBuffers
958
959GraphicMetadataInputBuffers::GraphicMetadataInputBuffers(
960 const char *componentName, const char *name)
961 : InputBuffers(componentName, name),
962 mImpl(mName),
963 mStore(GetCodec2PlatformAllocatorStore()) { }
964
965bool GraphicMetadataInputBuffers::requestNewBuffer(
966 size_t *index, sp<MediaCodecBuffer> *buffer) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700967 sp<Codec2Buffer> newBuffer = createNewBuffer();
Wonsik Kim469c8342019-04-11 16:46:09 -0700968 if (newBuffer == nullptr) {
969 return false;
970 }
971 *index = mImpl.assignSlot(newBuffer);
972 *buffer = newBuffer;
973 return true;
974}
975
976bool GraphicMetadataInputBuffers::releaseBuffer(
977 const sp<MediaCodecBuffer> &buffer,
978 std::shared_ptr<C2Buffer> *c2buffer,
979 bool release) {
980 return mImpl.releaseSlot(buffer, c2buffer, release);
981}
982
983bool GraphicMetadataInputBuffers::expireComponentBuffer(
984 const std::shared_ptr<C2Buffer> &c2buffer) {
985 return mImpl.expireComponentBuffer(c2buffer);
986}
987
988void GraphicMetadataInputBuffers::flush() {
989 // This is no-op by default unless we're in array mode where we need to keep
990 // track of the flushed work.
991}
992
993std::unique_ptr<InputBuffers> GraphicMetadataInputBuffers::toArrayMode(
994 size_t size) {
995 std::shared_ptr<C2Allocator> alloc;
996 c2_status_t err = mStore->fetchAllocator(mPool->getAllocatorId(), &alloc);
997 if (err != C2_OK) {
998 return nullptr;
999 }
1000 std::unique_ptr<InputBuffersArray> array(
1001 new InputBuffersArray(mComponentName.c_str(), "2D-MetaInput[N]"));
1002 array->setPool(mPool);
1003 array->setFormat(mFormat);
1004 array->initialize(
1005 mImpl,
1006 size,
1007 [format = mFormat, alloc]() -> sp<Codec2Buffer> {
1008 return new GraphicMetadataBuffer(format, alloc);
1009 });
1010 return std::move(array);
1011}
1012
Wonsik Kim0487b782020-10-28 11:45:50 -07001013size_t GraphicMetadataInputBuffers::numActiveSlots() const {
1014 return mImpl.numActiveSlots();
Wonsik Kim469c8342019-04-11 16:46:09 -07001015}
1016
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001017sp<Codec2Buffer> GraphicMetadataInputBuffers::createNewBuffer() {
1018 std::shared_ptr<C2Allocator> alloc;
1019 c2_status_t err = mStore->fetchAllocator(mPool->getAllocatorId(), &alloc);
1020 if (err != C2_OK) {
1021 return nullptr;
1022 }
1023 return new GraphicMetadataBuffer(mFormat, alloc);
1024}
1025
Wonsik Kim469c8342019-04-11 16:46:09 -07001026// GraphicInputBuffers
1027
1028GraphicInputBuffers::GraphicInputBuffers(
Wonsik Kim41d83432020-04-27 16:40:49 -07001029 const char *componentName, const char *name)
Wonsik Kim469c8342019-04-11 16:46:09 -07001030 : InputBuffers(componentName, name),
1031 mImpl(mName),
Wonsik Kim41d83432020-04-27 16:40:49 -07001032 mLocalBufferPool(LocalBufferPool::Create()) { }
Wonsik Kim469c8342019-04-11 16:46:09 -07001033
1034bool GraphicInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001035 sp<Codec2Buffer> newBuffer = createNewBuffer();
Wonsik Kim469c8342019-04-11 16:46:09 -07001036 if (newBuffer == nullptr) {
1037 return false;
1038 }
1039 *index = mImpl.assignSlot(newBuffer);
1040 handleImageData(newBuffer);
1041 *buffer = newBuffer;
1042 return true;
1043}
1044
1045bool GraphicInputBuffers::releaseBuffer(
1046 const sp<MediaCodecBuffer> &buffer,
1047 std::shared_ptr<C2Buffer> *c2buffer,
1048 bool release) {
1049 return mImpl.releaseSlot(buffer, c2buffer, release);
1050}
1051
1052bool GraphicInputBuffers::expireComponentBuffer(
1053 const std::shared_ptr<C2Buffer> &c2buffer) {
1054 return mImpl.expireComponentBuffer(c2buffer);
1055}
1056
1057void GraphicInputBuffers::flush() {
1058 // This is no-op by default unless we're in array mode where we need to keep
1059 // track of the flushed work.
1060}
1061
Wonsik Kimd79ee1f2020-08-27 17:41:56 -07001062static uint32_t extractPixelFormat(const sp<AMessage> &format) {
1063 int32_t frameworkColorFormat = 0;
1064 if (!format->findInt32("android._color-format", &frameworkColorFormat)) {
1065 return PIXEL_FORMAT_UNKNOWN;
1066 }
1067 uint32_t pixelFormat = PIXEL_FORMAT_UNKNOWN;
1068 if (C2Mapper::mapPixelFormatFrameworkToCodec(frameworkColorFormat, &pixelFormat)) {
1069 return pixelFormat;
1070 }
1071 return PIXEL_FORMAT_UNKNOWN;
1072}
1073
Wonsik Kim469c8342019-04-11 16:46:09 -07001074std::unique_ptr<InputBuffers> GraphicInputBuffers::toArrayMode(size_t size) {
1075 std::unique_ptr<InputBuffersArray> array(
1076 new InputBuffersArray(mComponentName.c_str(), "2D-BB-Input[N]"));
1077 array->setPool(mPool);
1078 array->setFormat(mFormat);
Wonsik Kimd79ee1f2020-08-27 17:41:56 -07001079 uint32_t pixelFormat = extractPixelFormat(mFormat);
Wonsik Kim469c8342019-04-11 16:46:09 -07001080 array->initialize(
1081 mImpl,
1082 size,
Wonsik Kimd79ee1f2020-08-27 17:41:56 -07001083 [pool = mPool, format = mFormat, lbp = mLocalBufferPool, pixelFormat]()
1084 -> sp<Codec2Buffer> {
Wonsik Kim469c8342019-04-11 16:46:09 -07001085 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
1086 return AllocateGraphicBuffer(
Wonsik Kimd79ee1f2020-08-27 17:41:56 -07001087 pool, format, pixelFormat, usage, lbp);
Wonsik Kim469c8342019-04-11 16:46:09 -07001088 });
1089 return std::move(array);
1090}
1091
Wonsik Kim0487b782020-10-28 11:45:50 -07001092size_t GraphicInputBuffers::numActiveSlots() const {
1093 return mImpl.numActiveSlots();
Wonsik Kim469c8342019-04-11 16:46:09 -07001094}
1095
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001096sp<Codec2Buffer> GraphicInputBuffers::createNewBuffer() {
Wonsik Kim666604a2020-05-14 16:57:49 -07001097 int64_t usageValue = 0;
1098 (void)mFormat->findInt64("android._C2MemoryUsage", &usageValue);
1099 C2MemoryUsage usage{usageValue | C2MemoryUsage::CPU_READ | C2MemoryUsage::CPU_WRITE};
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001100 return AllocateGraphicBuffer(
Wonsik Kimd79ee1f2020-08-27 17:41:56 -07001101 mPool, mFormat, extractPixelFormat(mFormat), usage, mLocalBufferPool);
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001102}
1103
Wonsik Kim469c8342019-04-11 16:46:09 -07001104// OutputBuffersArray
1105
1106void OutputBuffersArray::initialize(
1107 const FlexBuffersImpl &impl,
1108 size_t minSize,
1109 std::function<sp<Codec2Buffer>()> allocate) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001110 mAlloc = allocate;
Wonsik Kim469c8342019-04-11 16:46:09 -07001111 mImpl.initialize(impl, minSize, allocate);
1112}
1113
1114status_t OutputBuffersArray::registerBuffer(
1115 const std::shared_ptr<C2Buffer> &buffer,
1116 size_t *index,
1117 sp<MediaCodecBuffer> *clientBuffer) {
1118 sp<Codec2Buffer> c2Buffer;
1119 status_t err = mImpl.grabBuffer(
1120 index,
1121 &c2Buffer,
1122 [buffer](const sp<Codec2Buffer> &clientBuffer) {
1123 return clientBuffer->canCopy(buffer);
1124 });
1125 if (err == WOULD_BLOCK) {
1126 ALOGV("[%s] buffers temporarily not available", mName);
1127 return err;
1128 } else if (err != OK) {
1129 ALOGD("[%s] grabBuffer failed: %d", mName, err);
1130 return err;
1131 }
1132 c2Buffer->setFormat(mFormat);
Wonsik Kim6f23cfc2021-09-24 05:45:52 -07001133 if (!convert(buffer, &c2Buffer) && !c2Buffer->copy(buffer)) {
Wonsik Kim469c8342019-04-11 16:46:09 -07001134 ALOGD("[%s] copy buffer failed", mName);
1135 return WOULD_BLOCK;
1136 }
1137 submit(c2Buffer);
1138 handleImageData(c2Buffer);
1139 *clientBuffer = c2Buffer;
1140 ALOGV("[%s] grabbed buffer %zu", mName, *index);
1141 return OK;
1142}
1143
1144status_t OutputBuffersArray::registerCsd(
1145 const C2StreamInitDataInfo::output *csd,
1146 size_t *index,
1147 sp<MediaCodecBuffer> *clientBuffer) {
1148 sp<Codec2Buffer> c2Buffer;
1149 status_t err = mImpl.grabBuffer(
1150 index,
1151 &c2Buffer,
1152 [csd](const sp<Codec2Buffer> &clientBuffer) {
1153 return clientBuffer->base() != nullptr
1154 && clientBuffer->capacity() >= csd->flexCount();
1155 });
1156 if (err != OK) {
1157 return err;
1158 }
1159 memcpy(c2Buffer->base(), csd->m.value, csd->flexCount());
1160 c2Buffer->setRange(0, csd->flexCount());
1161 c2Buffer->setFormat(mFormat);
1162 *clientBuffer = c2Buffer;
1163 return OK;
1164}
1165
1166bool OutputBuffersArray::releaseBuffer(
1167 const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) {
1168 return mImpl.returnBuffer(buffer, c2buffer, true);
1169}
1170
1171void OutputBuffersArray::flush(const std::list<std::unique_ptr<C2Work>> &flushedWork) {
1172 (void)flushedWork;
1173 mImpl.flush();
1174 if (mSkipCutBuffer != nullptr) {
1175 mSkipCutBuffer->clear();
1176 }
1177}
1178
1179void OutputBuffersArray::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
1180 mImpl.getArray(array);
1181}
1182
Wonsik Kim0487b782020-10-28 11:45:50 -07001183size_t OutputBuffersArray::numActiveSlots() const {
1184 return mImpl.numActiveSlots();
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001185}
1186
Wonsik Kim469c8342019-04-11 16:46:09 -07001187void OutputBuffersArray::realloc(const std::shared_ptr<C2Buffer> &c2buffer) {
Wonsik Kim469c8342019-04-11 16:46:09 -07001188 switch (c2buffer->data().type()) {
1189 case C2BufferData::LINEAR: {
1190 uint32_t size = kLinearBufferSize;
Nick Desaulniersd09eaea2019-10-07 20:19:39 -07001191 const std::vector<C2ConstLinearBlock> &linear_blocks = c2buffer->data().linearBlocks();
1192 const uint32_t block_size = linear_blocks.front().size();
1193 if (block_size < kMaxLinearBufferSize / 2) {
1194 size = block_size * 2;
Wonsik Kim469c8342019-04-11 16:46:09 -07001195 } else {
1196 size = kMaxLinearBufferSize;
1197 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001198 mAlloc = [format = mFormat, size] {
Wonsik Kim469c8342019-04-11 16:46:09 -07001199 return new LocalLinearBuffer(format, new ABuffer(size));
1200 };
Wonsik Kima39882b2019-06-20 16:13:56 -07001201 ALOGD("[%s] reallocating with linear buffer of size %u", mName, size);
Wonsik Kim469c8342019-04-11 16:46:09 -07001202 break;
1203 }
1204
Wonsik Kima39882b2019-06-20 16:13:56 -07001205 case C2BufferData::GRAPHIC: {
1206 // This is only called for RawGraphicOutputBuffers.
1207 mAlloc = [format = mFormat,
Wonsik Kim41d83432020-04-27 16:40:49 -07001208 lbp = LocalBufferPool::Create()] {
Wonsik Kima39882b2019-06-20 16:13:56 -07001209 return ConstGraphicBlockBuffer::AllocateEmpty(
1210 format,
1211 [lbp](size_t capacity) {
1212 return lbp->newBuffer(capacity);
1213 });
1214 };
1215 ALOGD("[%s] reallocating with graphic buffer: format = %s",
1216 mName, mFormat->debugString().c_str());
1217 break;
1218 }
Wonsik Kim469c8342019-04-11 16:46:09 -07001219
1220 case C2BufferData::INVALID: [[fallthrough]];
1221 case C2BufferData::LINEAR_CHUNKS: [[fallthrough]];
1222 case C2BufferData::GRAPHIC_CHUNKS: [[fallthrough]];
1223 default:
1224 ALOGD("Unsupported type: %d", (int)c2buffer->data().type());
1225 return;
1226 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001227 mImpl.realloc(mAlloc);
Wonsik Kim469c8342019-04-11 16:46:09 -07001228}
1229
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001230void OutputBuffersArray::grow(size_t newSize) {
1231 mImpl.grow(newSize, mAlloc);
Wonsik Kim469c8342019-04-11 16:46:09 -07001232}
1233
Pawin Vongmasa9b906982020-04-11 05:07:15 -07001234void OutputBuffersArray::transferFrom(OutputBuffers* source) {
1235 mFormat = source->mFormat;
1236 mSkipCutBuffer = source->mSkipCutBuffer;
Pawin Vongmasa9b906982020-04-11 05:07:15 -07001237 mPending = std::move(source->mPending);
1238 mReorderStash = std::move(source->mReorderStash);
1239 mDepth = source->mDepth;
1240 mKey = source->mKey;
1241}
1242
Wonsik Kim469c8342019-04-11 16:46:09 -07001243// FlexOutputBuffers
1244
1245status_t FlexOutputBuffers::registerBuffer(
1246 const std::shared_ptr<C2Buffer> &buffer,
1247 size_t *index,
1248 sp<MediaCodecBuffer> *clientBuffer) {
Wonsik Kim6f23cfc2021-09-24 05:45:52 -07001249 sp<Codec2Buffer> newBuffer;
1250 if (!convert(buffer, &newBuffer)) {
1251 newBuffer = wrap(buffer);
1252 if (newBuffer == nullptr) {
1253 return NO_MEMORY;
1254 }
Wonsik Kim469c8342019-04-11 16:46:09 -07001255 }
1256 newBuffer->setFormat(mFormat);
1257 *index = mImpl.assignSlot(newBuffer);
1258 handleImageData(newBuffer);
1259 *clientBuffer = newBuffer;
1260 ALOGV("[%s] registered buffer %zu", mName, *index);
1261 return OK;
1262}
1263
1264status_t FlexOutputBuffers::registerCsd(
1265 const C2StreamInitDataInfo::output *csd,
1266 size_t *index,
1267 sp<MediaCodecBuffer> *clientBuffer) {
1268 sp<Codec2Buffer> newBuffer = new LocalLinearBuffer(
1269 mFormat, ABuffer::CreateAsCopy(csd->m.value, csd->flexCount()));
1270 *index = mImpl.assignSlot(newBuffer);
1271 *clientBuffer = newBuffer;
1272 return OK;
1273}
1274
1275bool FlexOutputBuffers::releaseBuffer(
1276 const sp<MediaCodecBuffer> &buffer,
1277 std::shared_ptr<C2Buffer> *c2buffer) {
1278 return mImpl.releaseSlot(buffer, c2buffer, true);
1279}
1280
1281void FlexOutputBuffers::flush(
1282 const std::list<std::unique_ptr<C2Work>> &flushedWork) {
1283 (void) flushedWork;
1284 // This is no-op by default unless we're in array mode where we need to keep
1285 // track of the flushed work.
1286}
1287
Pawin Vongmasa9b906982020-04-11 05:07:15 -07001288std::unique_ptr<OutputBuffersArray> FlexOutputBuffers::toArrayMode(size_t size) {
Wonsik Kim469c8342019-04-11 16:46:09 -07001289 std::unique_ptr<OutputBuffersArray> array(new OutputBuffersArray(mComponentName.c_str()));
Pawin Vongmasa9b906982020-04-11 05:07:15 -07001290 array->transferFrom(this);
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001291 std::function<sp<Codec2Buffer>()> alloc = getAlloc();
1292 array->initialize(mImpl, size, alloc);
Pawin Vongmasa9b906982020-04-11 05:07:15 -07001293 return array;
Wonsik Kim469c8342019-04-11 16:46:09 -07001294}
1295
Wonsik Kim0487b782020-10-28 11:45:50 -07001296size_t FlexOutputBuffers::numActiveSlots() const {
1297 return mImpl.numActiveSlots();
Wonsik Kim469c8342019-04-11 16:46:09 -07001298}
1299
1300// LinearOutputBuffers
1301
1302void LinearOutputBuffers::flush(
1303 const std::list<std::unique_ptr<C2Work>> &flushedWork) {
1304 if (mSkipCutBuffer != nullptr) {
1305 mSkipCutBuffer->clear();
1306 }
1307 FlexOutputBuffers::flush(flushedWork);
1308}
1309
1310sp<Codec2Buffer> LinearOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
1311 if (buffer == nullptr) {
1312 ALOGV("[%s] using a dummy buffer", mName);
1313 return new LocalLinearBuffer(mFormat, new ABuffer(0));
1314 }
1315 if (buffer->data().type() != C2BufferData::LINEAR) {
1316 ALOGV("[%s] non-linear buffer %d", mName, buffer->data().type());
1317 // We expect linear output buffers from the component.
1318 return nullptr;
1319 }
1320 if (buffer->data().linearBlocks().size() != 1u) {
1321 ALOGV("[%s] no linear buffers", mName);
1322 // We expect one and only one linear block from the component.
1323 return nullptr;
1324 }
1325 sp<Codec2Buffer> clientBuffer = ConstLinearBlockBuffer::Allocate(mFormat, buffer);
1326 if (clientBuffer == nullptr) {
1327 ALOGD("[%s] ConstLinearBlockBuffer::Allocate failed", mName);
1328 return nullptr;
1329 }
1330 submit(clientBuffer);
1331 return clientBuffer;
1332}
1333
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001334std::function<sp<Codec2Buffer>()> LinearOutputBuffers::getAlloc() {
1335 return [format = mFormat]{
1336 // TODO: proper max output size
1337 return new LocalLinearBuffer(format, new ABuffer(kLinearBufferSize));
1338 };
Wonsik Kim469c8342019-04-11 16:46:09 -07001339}
1340
1341// GraphicOutputBuffers
1342
1343sp<Codec2Buffer> GraphicOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
1344 return new DummyContainerBuffer(mFormat, buffer);
1345}
1346
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001347std::function<sp<Codec2Buffer>()> GraphicOutputBuffers::getAlloc() {
1348 return [format = mFormat]{
1349 return new DummyContainerBuffer(format);
1350 };
Wonsik Kim469c8342019-04-11 16:46:09 -07001351}
1352
1353// RawGraphicOutputBuffers
1354
1355RawGraphicOutputBuffers::RawGraphicOutputBuffers(
Wonsik Kim41d83432020-04-27 16:40:49 -07001356 const char *componentName, const char *name)
Wonsik Kim469c8342019-04-11 16:46:09 -07001357 : FlexOutputBuffers(componentName, name),
Wonsik Kim41d83432020-04-27 16:40:49 -07001358 mLocalBufferPool(LocalBufferPool::Create()) { }
Wonsik Kim469c8342019-04-11 16:46:09 -07001359
1360sp<Codec2Buffer> RawGraphicOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
1361 if (buffer == nullptr) {
Wonsik Kim6f116902021-07-14 08:58:07 -07001362 return new Codec2Buffer(mFormat, new ABuffer(nullptr, 0));
Wonsik Kim469c8342019-04-11 16:46:09 -07001363 } else {
1364 return ConstGraphicBlockBuffer::Allocate(
1365 mFormat,
1366 buffer,
1367 [lbp = mLocalBufferPool](size_t capacity) {
1368 return lbp->newBuffer(capacity);
1369 });
1370 }
1371}
1372
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001373std::function<sp<Codec2Buffer>()> RawGraphicOutputBuffers::getAlloc() {
1374 return [format = mFormat, lbp = mLocalBufferPool]{
1375 return ConstGraphicBlockBuffer::AllocateEmpty(
1376 format,
1377 [lbp](size_t capacity) {
1378 return lbp->newBuffer(capacity);
1379 });
1380 };
Wonsik Kim469c8342019-04-11 16:46:09 -07001381}
1382
1383} // namespace android