blob: d313f33a45c2e5b45960f29b76b5f18efb286151 [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
Arun Johnsonf4a81f72023-11-09 21:22:48 +000021#include <numeric>
22
Songyue Han1e6769b2023-08-30 18:09:27 +000023#include <C2AllocatorGralloc.h>
Wonsik Kim469c8342019-04-11 16:46:09 -070024#include <C2PlatformSupport.h>
25
26#include <media/stagefright/foundation/ADebug.h>
Wonsik Kim6f23cfc2021-09-24 05:45:52 -070027#include <media/stagefright/foundation/MediaDefs.h>
Arun Johnsonf4a81f72023-11-09 21:22:48 +000028#include <media/stagefright/CodecBase.h>
Wonsik Kim469c8342019-04-11 16:46:09 -070029#include <media/stagefright/MediaCodecConstants.h>
Wonsik Kim155d5cb2019-10-09 12:49:49 -070030#include <media/stagefright/SkipCutBuffer.h>
Wonsik Kim41d83432020-04-27 16:40:49 -070031#include <mediadrm/ICrypto.h>
Wonsik Kim469c8342019-04-11 16:46:09 -070032
33#include "CCodecBuffers.h"
Wonsik Kimd79ee1f2020-08-27 17:41:56 -070034#include "Codec2Mapper.h"
Wonsik Kim469c8342019-04-11 16:46:09 -070035
36namespace android {
37
38namespace {
39
My Nameac29e592022-03-28 13:53:32 -070040constexpr uint32_t PIXEL_FORMAT_UNKNOWN = 0;
41
David Stevens94b608f2021-07-29 15:04:14 +090042sp<GraphicBlockBuffer> AllocateInputGraphicBuffer(
Wonsik Kim469c8342019-04-11 16:46:09 -070043 const std::shared_ptr<C2BlockPool> &pool,
44 const sp<AMessage> &format,
45 uint32_t pixelFormat,
46 const C2MemoryUsage &usage,
47 const std::shared_ptr<LocalBufferPool> &localBufferPool) {
48 int32_t width, height;
49 if (!format->findInt32("width", &width) || !format->findInt32("height", &height)) {
50 ALOGD("format lacks width or height");
51 return nullptr;
52 }
53
David Stevens94b608f2021-07-29 15:04:14 +090054 int64_t usageValue = 0;
55 (void)format->findInt64("android._C2MemoryUsage", &usageValue);
56 C2MemoryUsage fullUsage{usageValue | usage.expected};
57
Wonsik Kim469c8342019-04-11 16:46:09 -070058 std::shared_ptr<C2GraphicBlock> block;
59 c2_status_t err = pool->fetchGraphicBlock(
David Stevens94b608f2021-07-29 15:04:14 +090060 width, height, pixelFormat, fullUsage, &block);
Wonsik Kim469c8342019-04-11 16:46:09 -070061 if (err != C2_OK) {
62 ALOGD("fetch graphic block failed: %d", err);
63 return nullptr;
64 }
65
66 return GraphicBlockBuffer::Allocate(
67 format,
68 block,
69 [localBufferPool](size_t capacity) {
70 return localBufferPool->newBuffer(capacity);
71 });
72}
73
74} // namespace
75
76// CCodecBuffers
77
78void CCodecBuffers::setFormat(const sp<AMessage> &format) {
79 CHECK(format != nullptr);
80 mFormat = format;
81}
82
83sp<AMessage> CCodecBuffers::dupFormat() {
84 return mFormat != nullptr ? mFormat->dup() : nullptr;
85}
86
87void CCodecBuffers::handleImageData(const sp<Codec2Buffer> &buffer) {
88 sp<ABuffer> imageDataCandidate = buffer->getImageData();
89 if (imageDataCandidate == nullptr) {
Wonsik Kim4a3c0462021-03-09 15:45:05 -080090 if (mFormatWithImageData) {
91 // We previously sent the format with image data, so use the same format.
92 buffer->setFormat(mFormatWithImageData);
93 }
Wonsik Kim469c8342019-04-11 16:46:09 -070094 return;
95 }
Wonsik Kim4a3c0462021-03-09 15:45:05 -080096 if (!mLastImageData
97 || imageDataCandidate->size() != mLastImageData->size()
98 || memcmp(imageDataCandidate->data(),
99 mLastImageData->data(),
100 mLastImageData->size()) != 0) {
Wonsik Kim469c8342019-04-11 16:46:09 -0700101 ALOGD("[%s] updating image-data", mName);
Wonsik Kim4a3c0462021-03-09 15:45:05 -0800102 mFormatWithImageData = dupFormat();
103 mLastImageData = imageDataCandidate;
104 mFormatWithImageData->setBuffer("image-data", imageDataCandidate);
Wonsik Kim469c8342019-04-11 16:46:09 -0700105 MediaImage2 *img = (MediaImage2*)imageDataCandidate->data();
106 if (img->mNumPlanes > 0 && img->mType != img->MEDIA_IMAGE_TYPE_UNKNOWN) {
107 int32_t stride = img->mPlane[0].mRowInc;
Wonsik Kim4a3c0462021-03-09 15:45:05 -0800108 mFormatWithImageData->setInt32(KEY_STRIDE, stride);
Vinay Kaliaef5fc712021-09-15 23:59:50 +0000109 mFormatWithImageData->setInt32(KEY_WIDTH, img->mWidth);
110 mFormatWithImageData->setInt32(KEY_HEIGHT, img->mHeight);
111 ALOGD("[%s] updating stride = %d, width: %d, height: %d",
112 mName, stride, img->mWidth, img->mHeight);
Wonsik Kim469c8342019-04-11 16:46:09 -0700113 if (img->mNumPlanes > 1 && stride > 0) {
Taehwan Kimfd9b8092020-09-17 12:26:40 +0900114 int64_t offsetDelta =
115 (int64_t)img->mPlane[1].mOffset - (int64_t)img->mPlane[0].mOffset;
116 int32_t vstride = int32_t(offsetDelta / stride);
Wonsik Kim4a3c0462021-03-09 15:45:05 -0800117 mFormatWithImageData->setInt32(KEY_SLICE_HEIGHT, vstride);
Wonsik Kim469c8342019-04-11 16:46:09 -0700118 ALOGD("[%s] updating vstride = %d", mName, vstride);
Wonsik Kim2eb06312020-12-03 11:07:58 -0800119 buffer->setRange(
120 img->mPlane[0].mOffset,
121 buffer->size() - img->mPlane[0].mOffset);
Wonsik Kim469c8342019-04-11 16:46:09 -0700122 }
123 }
Wonsik Kim469c8342019-04-11 16:46:09 -0700124 }
Wonsik Kim4a3c0462021-03-09 15:45:05 -0800125 buffer->setFormat(mFormatWithImageData);
Wonsik Kim469c8342019-04-11 16:46:09 -0700126}
127
Songyue Han1e6769b2023-08-30 18:09:27 +0000128uint32_t CCodecBuffers::getPixelFormatIfApplicable() { return PIXEL_FORMAT_UNKNOWN; }
129
130bool CCodecBuffers::resetPixelFormatIfApplicable() { return false; }
131
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700132// InputBuffers
133
134sp<Codec2Buffer> InputBuffers::cloneAndReleaseBuffer(const sp<MediaCodecBuffer> &buffer) {
135 sp<Codec2Buffer> copy = createNewBuffer();
136 if (copy == nullptr) {
137 return nullptr;
138 }
139 std::shared_ptr<C2Buffer> c2buffer;
140 if (!releaseBuffer(buffer, &c2buffer, true)) {
141 return nullptr;
142 }
143 if (!copy->canCopy(c2buffer)) {
144 return nullptr;
145 }
146 if (!copy->copy(c2buffer)) {
147 return nullptr;
148 }
Wonsik Kimfb5ca492021-08-11 14:18:19 -0700149 copy->meta()->extend(buffer->meta());
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700150 return copy;
151}
152
Arun Johnsonf4a81f72023-11-09 21:22:48 +0000153// MultiAccessUnitSkipCutBuffer for buffer and bufferInfos
154
155class MultiAccessUnitSkipCutBuffer : public SkipCutBuffer {
156
157public:
158 explicit MultiAccessUnitSkipCutBuffer(
159 int32_t skip, int32_t cut, size_t num16BitChannels):
160 SkipCutBuffer(skip, cut, num16BitChannels),
161 mFrontPaddingDelay(0), mSize(0) {
162 }
Arun Johnsond43dc8c2024-02-07 01:14:15 +0000163 void clearAll() {
164 mInfos.clear();
165 mFrontPaddingDelay = 0;
166 mSize = 0;
167 SkipCutBuffer::clear();
168 }
Arun Johnsonf4a81f72023-11-09 21:22:48 +0000169
170 virtual ~MultiAccessUnitSkipCutBuffer() {
171
172 }
173
174 void submitMultiAccessUnits(
175 const sp<MediaCodecBuffer>& buffer,
176 int32_t sampleRate, size_t num16BitChannels,
177 std::shared_ptr<const C2AccessUnitInfos::output> &infos) {
178 if (infos == nullptr) {
179 // there is nothing to do more.
180 SkipCutBuffer::submit(buffer);
181 return;
182 }
183 typedef WrapperObject<std::vector<AccessUnitInfo>> BufferInfosWrapper;
184 CHECK_EQ(mSize, SkipCutBuffer::size());
185 sp<BufferInfosWrapper> bufferInfos{new BufferInfosWrapper(decltype(bufferInfos->value)())};
186 uint32_t availableSize = buffer->size() + SkipCutBuffer::size();
187 uint32_t frontPadding = mFrontPadding;
188 int32_t lastEmptyAccessUnitIndex = -1;
189 int64_t byteInUs = 0;
190 if (sampleRate > 0 && num16BitChannels > 0) {
191 byteInUs = (1000000u / (sampleRate * num16BitChannels * 2));
192 }
193 if (frontPadding > 0) {
194 mInfos.clear();
195 mSize = 0;
196 }
197 for (int i = 0 ; i < infos->flexCount() && frontPadding > 0; i++) {
198 uint32_t flagsInPadding = 0;
199 int64_t timeInPadding = 0;
200 if (infos->m.values[i].size <= frontPadding) {
201 // we have more front padding so this buffer is not going to be used.
202 int32_t consumed = infos->m.values[i].size;
203 frontPadding -= consumed;
204 mFrontPaddingDelay += byteInUs * (consumed);
205 availableSize -= consumed;
206 flagsInPadding |= toMediaCodecFlags(infos->m.values[i].flags);
207 timeInPadding = infos->m.values[i].timestamp;
208 } else {
209 C2AccessUnitInfosStruct info = infos->m.values[i];
210 mFrontPaddingDelay += byteInUs * (frontPadding);
211 info.size -= frontPadding;
212 info.timestamp -= mFrontPaddingDelay;
213 availableSize -= frontPadding;
214 flagsInPadding |= toMediaCodecFlags(infos->m.values[i].flags);
215 timeInPadding = infos->m.values[i].timestamp;
216 frontPadding = 0;
217 mInfos.push_back(info);
218 mSize += info.size;
219 }
220 if (flagsInPadding != 0) {
221 bufferInfos->value.emplace_back(
222 flagsInPadding, 0, timeInPadding);
223 }
224 lastEmptyAccessUnitIndex = i;
225 }
226 if (frontPadding <= 0) {
227 // process what's already in the buffer first
228 auto it = mInfos.begin();
229 while (it != mInfos.end() && availableSize > mBackPadding) {
230 // we have samples to send out.
231 if ((availableSize - it->size) >= mBackPadding) {
232 // this is totally used here.
233 int32_t consumed = it->size;
234 bufferInfos->value.emplace_back(
235 toMediaCodecFlags(it->flags), consumed, it->timestamp);
236 availableSize -= consumed;
237 mSize -= consumed;
238 it = mInfos.erase(it);
239 } else {
240 int32_t consumed = availableSize - mBackPadding;
241 bufferInfos->value.emplace_back(
242 toMediaCodecFlags(it->flags),
243 consumed,
244 it->timestamp);
245 it->size -= consumed;
246 it->timestamp += consumed * byteInUs;
247 availableSize -= consumed;
248 mSize -= consumed;
249 it++;
250 }
251 }
252 // if buffer has more process all of it and keep the remaining info.
253 for (int i = (lastEmptyAccessUnitIndex + 1) ; i < infos->flexCount() ; i++) {
254 // upddate updatedInfo and mInfos
255 if (availableSize > mBackPadding) {
256 // we have to take data from the new buffer.
257 if (availableSize - infos->m.values[i].size >= mBackPadding) {
258 // we are using this info
259 int32_t consumed = infos->m.values[i].size;
260 bufferInfos->value.emplace_back(
261 toMediaCodecFlags(infos->m.values[i].flags),
262 consumed,
263 infos->m.values[i].timestamp - mFrontPaddingDelay);
264 availableSize -= consumed;
265 } else {
266 // if we need to update the size
267 C2AccessUnitInfosStruct info = infos->m.values[i];
268 int32_t consumed = availableSize - mBackPadding;
269 bufferInfos->value.emplace_back(
270 toMediaCodecFlags(infos->m.values[i].flags),
271 consumed,
272 infos->m.values[i].timestamp - mFrontPaddingDelay);
273 info.size -= consumed;
274 info.timestamp = info.timestamp - mFrontPaddingDelay +
275 consumed * byteInUs;
276 mInfos.push_back(info);
277 availableSize -= consumed;
278 mSize += info.size;
279 }
280 } else {
281 // we have to maintain infos
282 C2AccessUnitInfosStruct info = infos->m.values[i];
283 info.timestamp -= mFrontPaddingDelay;
284 mInfos.push_back(info);
285 mSize += info.size;
286 }
287 }
288 }
289 SkipCutBuffer::submit(buffer);
290 infos = nullptr;
291 if (!bufferInfos->value.empty()) {
292 buffer->meta()->setObject("accessUnitInfo", bufferInfos);
293 }
294 }
295protected:
296 // Flags can come with individual BufferInfos
297 // when used with large frame audio
298 constexpr static std::initializer_list<std::pair<uint32_t, uint32_t>> flagList = {
299 {BUFFER_FLAG_CODEC_CONFIG, C2FrameData::FLAG_CODEC_CONFIG},
300 {BUFFER_FLAG_END_OF_STREAM, C2FrameData::FLAG_END_OF_STREAM},
301 {BUFFER_FLAG_DECODE_ONLY, C2FrameData::FLAG_DROP_FRAME}
302 };
303
304 static uint32_t toMediaCodecFlags(uint32_t flags) {
305 return std::transform_reduce(
306 flagList.begin(), flagList.end(),
307 0u,
308 std::bit_or{},
309 [flags](const std::pair<uint32_t, uint32_t> &entry) {
310 return (flags & entry.second) ? entry.first : 0;
311 });
312 }
313 std::list<C2AccessUnitInfosStruct> mInfos;
314 int64_t mFrontPaddingDelay;
315 size_t mSize;
316};
317
Wonsik Kim469c8342019-04-11 16:46:09 -0700318// OutputBuffers
319
Wonsik Kim41d83432020-04-27 16:40:49 -0700320OutputBuffers::OutputBuffers(const char *componentName, const char *name)
321 : CCodecBuffers(componentName, name) { }
322
323OutputBuffers::~OutputBuffers() = default;
324
Wonsik Kim469c8342019-04-11 16:46:09 -0700325void OutputBuffers::initSkipCutBuffer(
326 int32_t delay, int32_t padding, int32_t sampleRate, int32_t channelCount) {
327 CHECK(mSkipCutBuffer == nullptr);
328 mDelay = delay;
329 mPadding = padding;
330 mSampleRate = sampleRate;
Wonsik Kim40b0b1d2020-03-25 15:47:35 -0700331 mChannelCount = channelCount;
332 setSkipCutBuffer(delay, padding);
Wonsik Kim469c8342019-04-11 16:46:09 -0700333}
334
335void OutputBuffers::updateSkipCutBuffer(int32_t sampleRate, int32_t channelCount) {
336 if (mSkipCutBuffer == nullptr) {
337 return;
338 }
Wonsik Kim40b0b1d2020-03-25 15:47:35 -0700339 if (mSampleRate == sampleRate && mChannelCount == channelCount) {
340 return;
341 }
Wonsik Kim469c8342019-04-11 16:46:09 -0700342 int32_t delay = mDelay;
343 int32_t padding = mPadding;
344 if (sampleRate != mSampleRate) {
345 delay = ((int64_t)delay * sampleRate) / mSampleRate;
346 padding = ((int64_t)padding * sampleRate) / mSampleRate;
347 }
Wonsik Kim40b0b1d2020-03-25 15:47:35 -0700348 mSampleRate = sampleRate;
349 mChannelCount = channelCount;
350 setSkipCutBuffer(delay, padding);
Wonsik Kim469c8342019-04-11 16:46:09 -0700351}
352
Wonsik Kim3b4349a2020-11-10 11:54:15 -0800353void OutputBuffers::updateSkipCutBuffer(const sp<AMessage> &format) {
Pawin Vongmasa9b906982020-04-11 05:07:15 -0700354 AString mediaType;
355 if (format->findString(KEY_MIME, &mediaType)
356 && mediaType == MIMETYPE_AUDIO_RAW) {
357 int32_t channelCount;
358 int32_t sampleRate;
359 if (format->findInt32(KEY_CHANNEL_COUNT, &channelCount)
360 && format->findInt32(KEY_SAMPLE_RATE, &sampleRate)) {
361 updateSkipCutBuffer(sampleRate, channelCount);
362 }
363 }
Pawin Vongmasa9b906982020-04-11 05:07:15 -0700364}
365
Wonsik Kim469c8342019-04-11 16:46:09 -0700366void OutputBuffers::submit(const sp<MediaCodecBuffer> &buffer) {
367 if (mSkipCutBuffer != nullptr) {
368 mSkipCutBuffer->submit(buffer);
369 }
370}
371
Arun Johnsonf4a81f72023-11-09 21:22:48 +0000372bool OutputBuffers::submit(const sp<MediaCodecBuffer> &buffer, int32_t sampleRate,
373 int32_t channelCount, std::shared_ptr<const C2AccessUnitInfos::output> &infos) {
374 if (mSkipCutBuffer == nullptr) {
375 return false;
376 }
377 mSkipCutBuffer->submitMultiAccessUnits(buffer, sampleRate, channelCount, infos);
378 return true;
379}
380
Wonsik Kim40b0b1d2020-03-25 15:47:35 -0700381void OutputBuffers::setSkipCutBuffer(int32_t skip, int32_t cut) {
Wonsik Kim469c8342019-04-11 16:46:09 -0700382 if (mSkipCutBuffer != nullptr) {
383 size_t prevSize = mSkipCutBuffer->size();
384 if (prevSize != 0u) {
385 ALOGD("[%s] Replacing SkipCutBuffer holding %zu bytes", mName, prevSize);
386 }
387 }
Arun Johnsonf4a81f72023-11-09 21:22:48 +0000388 mSkipCutBuffer = new MultiAccessUnitSkipCutBuffer(skip, cut, mChannelCount);
Wonsik Kim469c8342019-04-11 16:46:09 -0700389}
390
Wonsik Kim6f23cfc2021-09-24 05:45:52 -0700391bool OutputBuffers::convert(
392 const std::shared_ptr<C2Buffer> &src, sp<Codec2Buffer> *dst) {
Wonsik Kim360ba0a2022-05-23 15:38:21 -0700393 if (src && src->data().type() != C2BufferData::LINEAR) {
Wonsik Kim6f23cfc2021-09-24 05:45:52 -0700394 return false;
395 }
396 int32_t configEncoding = kAudioEncodingPcm16bit;
397 int32_t codecEncoding = kAudioEncodingPcm16bit;
398 if (mFormat->findInt32("android._codec-pcm-encoding", &codecEncoding)
399 && mFormat->findInt32("android._config-pcm-encoding", &configEncoding)) {
400 if (mSrcEncoding != codecEncoding || mDstEncoding != configEncoding) {
401 if (codecEncoding != configEncoding) {
402 mDataConverter = AudioConverter::Create(
403 (AudioEncoding)codecEncoding, (AudioEncoding)configEncoding);
404 ALOGD_IF(mDataConverter, "[%s] Converter created from %d to %d",
405 mName, codecEncoding, configEncoding);
406 mFormatWithConverter = mFormat->dup();
407 mFormatWithConverter->setInt32(KEY_PCM_ENCODING, configEncoding);
408 } else {
409 mDataConverter = nullptr;
410 mFormatWithConverter = nullptr;
411 }
412 mSrcEncoding = codecEncoding;
413 mDstEncoding = configEncoding;
414 }
415 if (int encoding; !mFormat->findInt32(KEY_PCM_ENCODING, &encoding)
416 || encoding != mDstEncoding) {
417 }
418 }
419 if (!mDataConverter) {
420 return false;
421 }
Wonsik Kim360ba0a2022-05-23 15:38:21 -0700422 sp<MediaCodecBuffer> srcBuffer;
423 if (src) {
424 srcBuffer = ConstLinearBlockBuffer::Allocate(mFormat, src);
425 } else {
426 srcBuffer = new MediaCodecBuffer(mFormat, new ABuffer(0));
427 }
Wonsik Kim6f23cfc2021-09-24 05:45:52 -0700428 if (!srcBuffer) {
429 return false;
430 }
Greg Kaiser92dc4542021-10-08 06:58:19 -0700431 if (!*dst) {
Wonsik Kim6f23cfc2021-09-24 05:45:52 -0700432 *dst = new Codec2Buffer(
433 mFormat,
434 new ABuffer(mDataConverter->targetSize(srcBuffer->size())));
435 }
436 sp<MediaCodecBuffer> dstBuffer = *dst;
437 status_t err = mDataConverter->convert(srcBuffer, dstBuffer);
438 if (err != OK) {
439 ALOGD("[%s] buffer conversion failed: %d", mName, err);
440 return false;
441 }
442 dstBuffer->setFormat(mFormatWithConverter);
443 return true;
444}
445
Pawin Vongmasa9b906982020-04-11 05:07:15 -0700446void OutputBuffers::clearStash() {
447 mPending.clear();
448 mReorderStash.clear();
449 mDepth = 0;
450 mKey = C2Config::ORDINAL;
Pawin Vongmasa9b906982020-04-11 05:07:15 -0700451}
452
453void OutputBuffers::flushStash() {
454 for (StashEntry& e : mPending) {
455 e.notify = false;
456 }
457 for (StashEntry& e : mReorderStash) {
458 e.notify = false;
459 }
460}
461
462uint32_t OutputBuffers::getReorderDepth() const {
463 return mDepth;
464}
465
466void OutputBuffers::setReorderDepth(uint32_t depth) {
467 mPending.splice(mPending.end(), mReorderStash);
468 mDepth = depth;
469}
470
471void OutputBuffers::setReorderKey(C2Config::ordinal_key_t key) {
472 mPending.splice(mPending.end(), mReorderStash);
473 mKey = key;
474}
475
476void OutputBuffers::pushToStash(
477 const std::shared_ptr<C2Buffer>& buffer,
478 bool notify,
479 int64_t timestamp,
480 int32_t flags,
481 const sp<AMessage>& format,
482 const C2WorkOrdinalStruct& ordinal) {
My Nameac29e592022-03-28 13:53:32 -0700483 bool eos = flags & BUFFER_FLAG_END_OF_STREAM;
Pawin Vongmasa9b906982020-04-11 05:07:15 -0700484 if (!buffer && eos) {
485 // TRICKY: we may be violating ordering of the stash here. Because we
486 // don't expect any more emplace() calls after this, the ordering should
487 // not matter.
488 mReorderStash.emplace_back(
489 buffer, notify, timestamp, flags, format, ordinal);
490 } else {
My Nameac29e592022-03-28 13:53:32 -0700491 flags = flags & ~BUFFER_FLAG_END_OF_STREAM;
Pawin Vongmasa9b906982020-04-11 05:07:15 -0700492 auto it = mReorderStash.begin();
493 for (; it != mReorderStash.end(); ++it) {
494 if (less(ordinal, it->ordinal)) {
495 break;
496 }
497 }
498 mReorderStash.emplace(it,
499 buffer, notify, timestamp, flags, format, ordinal);
500 if (eos) {
501 mReorderStash.back().flags =
My Nameac29e592022-03-28 13:53:32 -0700502 mReorderStash.back().flags | BUFFER_FLAG_END_OF_STREAM;
Pawin Vongmasa9b906982020-04-11 05:07:15 -0700503 }
504 }
505 while (!mReorderStash.empty() && mReorderStash.size() > mDepth) {
506 mPending.push_back(mReorderStash.front());
507 mReorderStash.pop_front();
508 }
509 ALOGV("[%s] %s: pushToStash -- pending size = %zu", mName, __func__, mPending.size());
510}
511
512OutputBuffers::BufferAction OutputBuffers::popFromStashAndRegister(
513 std::shared_ptr<C2Buffer>* c2Buffer,
514 size_t* index,
515 sp<MediaCodecBuffer>* outBuffer) {
516 if (mPending.empty()) {
517 return SKIP;
518 }
519
520 // Retrieve the first entry.
521 StashEntry &entry = mPending.front();
522
523 *c2Buffer = entry.buffer;
524 sp<AMessage> outputFormat = entry.format;
525
Wonsik Kim3b4349a2020-11-10 11:54:15 -0800526 if (entry.notify && mFormat != outputFormat) {
527 updateSkipCutBuffer(outputFormat);
Wonsik Kim4a3c0462021-03-09 15:45:05 -0800528 // Trigger image data processing to the new format
529 mLastImageData.clear();
Wonsik Kim3b4349a2020-11-10 11:54:15 -0800530 ALOGV("[%s] popFromStashAndRegister: output format reference changed: %p -> %p",
531 mName, mFormat.get(), outputFormat.get());
Wonsik Kim4a3c0462021-03-09 15:45:05 -0800532 ALOGD("[%s] popFromStashAndRegister: at %lldus, output format changed to %s",
533 mName, (long long)entry.timestamp, outputFormat->debugString().c_str());
Wonsik Kim3b4349a2020-11-10 11:54:15 -0800534 setFormat(outputFormat);
Pawin Vongmasa9b906982020-04-11 05:07:15 -0700535 }
536
537 // Flushing mReorderStash because no other buffers should come after output
538 // EOS.
My Nameac29e592022-03-28 13:53:32 -0700539 if (entry.flags & BUFFER_FLAG_END_OF_STREAM) {
Pawin Vongmasa9b906982020-04-11 05:07:15 -0700540 // Flush reorder stash
541 setReorderDepth(0);
542 }
543
544 if (!entry.notify) {
545 mPending.pop_front();
546 return DISCARD;
547 }
548
549 // Try to register the buffer.
550 status_t err = registerBuffer(*c2Buffer, index, outBuffer);
551 if (err != OK) {
552 if (err != WOULD_BLOCK) {
553 return REALLOCATE;
554 }
555 return RETRY;
556 }
557
558 // Append information from the front stash entry to outBuffer.
559 (*outBuffer)->meta()->setInt64("timeUs", entry.timestamp);
560 (*outBuffer)->meta()->setInt32("flags", entry.flags);
Byeongjo Park2eef13e2020-06-12 17:24:21 +0900561 (*outBuffer)->meta()->setInt64("frameIndex", entry.ordinal.frameIndex.peekll());
Pawin Vongmasa9b906982020-04-11 05:07:15 -0700562 ALOGV("[%s] popFromStashAndRegister: "
563 "out buffer index = %zu [%p] => %p + %zu (%lld)",
564 mName, *index, outBuffer->get(),
565 (*outBuffer)->data(), (*outBuffer)->size(),
566 (long long)entry.timestamp);
567
568 // The front entry of mPending will be removed now that the registration
569 // succeeded.
570 mPending.pop_front();
571 return NOTIFY_CLIENT;
572}
573
574bool OutputBuffers::popPending(StashEntry *entry) {
575 if (mPending.empty()) {
576 return false;
577 }
578 *entry = mPending.front();
579 mPending.pop_front();
580 return true;
581}
582
583void OutputBuffers::deferPending(const OutputBuffers::StashEntry &entry) {
584 mPending.push_front(entry);
585}
586
587bool OutputBuffers::hasPending() const {
588 return !mPending.empty();
589}
590
591bool OutputBuffers::less(
592 const C2WorkOrdinalStruct &o1, const C2WorkOrdinalStruct &o2) const {
593 switch (mKey) {
594 case C2Config::ORDINAL: return o1.frameIndex < o2.frameIndex;
595 case C2Config::TIMESTAMP: return o1.timestamp < o2.timestamp;
596 case C2Config::CUSTOM: return o1.customOrdinal < o2.customOrdinal;
597 default:
598 ALOGD("Unrecognized key; default to timestamp");
599 return o1.frameIndex < o2.frameIndex;
600 }
601}
602
Wonsik Kim469c8342019-04-11 16:46:09 -0700603// LocalBufferPool
604
Wonsik Kim41d83432020-04-27 16:40:49 -0700605constexpr size_t kInitialPoolCapacity = kMaxLinearBufferSize;
606constexpr size_t kMaxPoolCapacity = kMaxLinearBufferSize * 32;
607
608std::shared_ptr<LocalBufferPool> LocalBufferPool::Create() {
609 return std::shared_ptr<LocalBufferPool>(new LocalBufferPool(kInitialPoolCapacity));
Wonsik Kim469c8342019-04-11 16:46:09 -0700610}
611
612sp<ABuffer> LocalBufferPool::newBuffer(size_t capacity) {
613 Mutex::Autolock lock(mMutex);
614 auto it = std::find_if(
615 mPool.begin(), mPool.end(),
616 [capacity](const std::vector<uint8_t> &vec) {
617 return vec.capacity() >= capacity;
618 });
619 if (it != mPool.end()) {
620 sp<ABuffer> buffer = new VectorBuffer(std::move(*it), shared_from_this());
621 mPool.erase(it);
622 return buffer;
623 }
624 if (mUsedSize + capacity > mPoolCapacity) {
625 while (!mPool.empty()) {
626 mUsedSize -= mPool.back().capacity();
627 mPool.pop_back();
628 }
Wonsik Kim41d83432020-04-27 16:40:49 -0700629 while (mUsedSize + capacity > mPoolCapacity && mPoolCapacity * 2 <= kMaxPoolCapacity) {
630 ALOGD("Increasing local buffer pool capacity from %zu to %zu",
631 mPoolCapacity, mPoolCapacity * 2);
632 mPoolCapacity *= 2;
633 }
Wonsik Kim469c8342019-04-11 16:46:09 -0700634 if (mUsedSize + capacity > mPoolCapacity) {
635 ALOGD("mUsedSize = %zu, capacity = %zu, mPoolCapacity = %zu",
636 mUsedSize, capacity, mPoolCapacity);
637 return nullptr;
638 }
639 }
640 std::vector<uint8_t> vec(capacity);
641 mUsedSize += vec.capacity();
642 return new VectorBuffer(std::move(vec), shared_from_this());
643}
644
645LocalBufferPool::VectorBuffer::VectorBuffer(
646 std::vector<uint8_t> &&vec, const std::shared_ptr<LocalBufferPool> &pool)
647 : ABuffer(vec.data(), vec.capacity()),
648 mVec(std::move(vec)),
649 mPool(pool) {
650}
651
652LocalBufferPool::VectorBuffer::~VectorBuffer() {
653 std::shared_ptr<LocalBufferPool> pool = mPool.lock();
654 if (pool) {
655 // If pool is alive, return the vector back to the pool so that
656 // it can be recycled.
657 pool->returnVector(std::move(mVec));
658 }
659}
660
661void LocalBufferPool::returnVector(std::vector<uint8_t> &&vec) {
662 Mutex::Autolock lock(mMutex);
663 mPool.push_front(std::move(vec));
664}
665
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700666// FlexBuffersImpl
667
Wonsik Kim469c8342019-04-11 16:46:09 -0700668size_t FlexBuffersImpl::assignSlot(const sp<Codec2Buffer> &buffer) {
669 for (size_t i = 0; i < mBuffers.size(); ++i) {
670 if (mBuffers[i].clientBuffer == nullptr
671 && mBuffers[i].compBuffer.expired()) {
672 mBuffers[i].clientBuffer = buffer;
673 return i;
674 }
675 }
676 mBuffers.push_back({ buffer, std::weak_ptr<C2Buffer>() });
677 return mBuffers.size() - 1;
678}
679
Wonsik Kim469c8342019-04-11 16:46:09 -0700680bool FlexBuffersImpl::releaseSlot(
681 const sp<MediaCodecBuffer> &buffer,
682 std::shared_ptr<C2Buffer> *c2buffer,
683 bool release) {
684 sp<Codec2Buffer> clientBuffer;
685 size_t index = mBuffers.size();
686 for (size_t i = 0; i < mBuffers.size(); ++i) {
687 if (mBuffers[i].clientBuffer == buffer) {
688 clientBuffer = mBuffers[i].clientBuffer;
689 if (release) {
690 mBuffers[i].clientBuffer.clear();
691 }
692 index = i;
693 break;
694 }
695 }
696 if (clientBuffer == nullptr) {
697 ALOGV("[%s] %s: No matching buffer found", mName, __func__);
698 return false;
699 }
700 std::shared_ptr<C2Buffer> result = mBuffers[index].compBuffer.lock();
701 if (!result) {
702 result = clientBuffer->asC2Buffer();
Wonsik Kimf9b32122020-04-02 11:30:17 -0700703 clientBuffer->clearC2BufferRefs();
Wonsik Kim469c8342019-04-11 16:46:09 -0700704 mBuffers[index].compBuffer = result;
705 }
706 if (c2buffer) {
707 *c2buffer = result;
708 }
709 return true;
710}
711
712bool FlexBuffersImpl::expireComponentBuffer(const std::shared_ptr<C2Buffer> &c2buffer) {
713 for (size_t i = 0; i < mBuffers.size(); ++i) {
714 std::shared_ptr<C2Buffer> compBuffer =
715 mBuffers[i].compBuffer.lock();
716 if (!compBuffer || compBuffer != c2buffer) {
717 continue;
718 }
719 mBuffers[i].compBuffer.reset();
720 ALOGV("[%s] codec released buffer #%zu", mName, i);
721 return true;
722 }
723 ALOGV("[%s] codec released an unknown buffer", mName);
724 return false;
725}
726
727void FlexBuffersImpl::flush() {
728 ALOGV("[%s] buffers are flushed %zu", mName, mBuffers.size());
729 mBuffers.clear();
730}
731
Wonsik Kim0487b782020-10-28 11:45:50 -0700732size_t FlexBuffersImpl::numActiveSlots() const {
Wonsik Kim469c8342019-04-11 16:46:09 -0700733 return std::count_if(
734 mBuffers.begin(), mBuffers.end(),
735 [](const Entry &entry) {
Wonsik Kim0487b782020-10-28 11:45:50 -0700736 return (entry.clientBuffer != nullptr
737 || !entry.compBuffer.expired());
Wonsik Kim469c8342019-04-11 16:46:09 -0700738 });
739}
740
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700741size_t FlexBuffersImpl::numComponentBuffers() const {
742 return std::count_if(
743 mBuffers.begin(), mBuffers.end(),
744 [](const Entry &entry) {
745 return !entry.compBuffer.expired();
746 });
747}
748
Wonsik Kim469c8342019-04-11 16:46:09 -0700749// BuffersArrayImpl
750
751void BuffersArrayImpl::initialize(
752 const FlexBuffersImpl &impl,
753 size_t minSize,
754 std::function<sp<Codec2Buffer>()> allocate) {
755 mImplName = impl.mImplName + "[N]";
756 mName = mImplName.c_str();
757 for (size_t i = 0; i < impl.mBuffers.size(); ++i) {
758 sp<Codec2Buffer> clientBuffer = impl.mBuffers[i].clientBuffer;
759 bool ownedByClient = (clientBuffer != nullptr);
760 if (!ownedByClient) {
761 clientBuffer = allocate();
762 }
763 mBuffers.push_back({ clientBuffer, impl.mBuffers[i].compBuffer, ownedByClient });
764 }
765 ALOGV("[%s] converted %zu buffers to array mode of %zu", mName, mBuffers.size(), minSize);
766 for (size_t i = impl.mBuffers.size(); i < minSize; ++i) {
767 mBuffers.push_back({ allocate(), std::weak_ptr<C2Buffer>(), false });
768 }
769}
770
771status_t BuffersArrayImpl::grabBuffer(
772 size_t *index,
773 sp<Codec2Buffer> *buffer,
774 std::function<bool(const sp<Codec2Buffer> &)> match) {
775 // allBuffersDontMatch remains true if all buffers are available but
776 // match() returns false for every buffer.
777 bool allBuffersDontMatch = true;
778 for (size_t i = 0; i < mBuffers.size(); ++i) {
779 if (!mBuffers[i].ownedByClient && mBuffers[i].compBuffer.expired()) {
780 if (match(mBuffers[i].clientBuffer)) {
781 mBuffers[i].ownedByClient = true;
782 *buffer = mBuffers[i].clientBuffer;
783 (*buffer)->meta()->clear();
784 (*buffer)->setRange(0, (*buffer)->capacity());
785 *index = i;
786 return OK;
787 }
788 } else {
789 allBuffersDontMatch = false;
790 }
791 }
792 return allBuffersDontMatch ? NO_MEMORY : WOULD_BLOCK;
793}
794
795bool BuffersArrayImpl::returnBuffer(
796 const sp<MediaCodecBuffer> &buffer,
797 std::shared_ptr<C2Buffer> *c2buffer,
798 bool release) {
799 sp<Codec2Buffer> clientBuffer;
800 size_t index = mBuffers.size();
801 for (size_t i = 0; i < mBuffers.size(); ++i) {
802 if (mBuffers[i].clientBuffer == buffer) {
803 if (!mBuffers[i].ownedByClient) {
804 ALOGD("[%s] Client returned a buffer it does not own according to our record: %zu",
805 mName, i);
806 }
807 clientBuffer = mBuffers[i].clientBuffer;
808 if (release) {
809 mBuffers[i].ownedByClient = false;
810 }
811 index = i;
812 break;
813 }
814 }
815 if (clientBuffer == nullptr) {
816 ALOGV("[%s] %s: No matching buffer found", mName, __func__);
817 return false;
818 }
819 ALOGV("[%s] %s: matching buffer found (index=%zu)", mName, __func__, index);
820 std::shared_ptr<C2Buffer> result = mBuffers[index].compBuffer.lock();
821 if (!result) {
822 result = clientBuffer->asC2Buffer();
Wonsik Kimf9b32122020-04-02 11:30:17 -0700823 clientBuffer->clearC2BufferRefs();
Wonsik Kim469c8342019-04-11 16:46:09 -0700824 mBuffers[index].compBuffer = result;
825 }
826 if (c2buffer) {
827 *c2buffer = result;
828 }
829 return true;
830}
831
832bool BuffersArrayImpl::expireComponentBuffer(const std::shared_ptr<C2Buffer> &c2buffer) {
833 for (size_t i = 0; i < mBuffers.size(); ++i) {
834 std::shared_ptr<C2Buffer> compBuffer =
835 mBuffers[i].compBuffer.lock();
836 if (!compBuffer) {
837 continue;
838 }
839 if (c2buffer == compBuffer) {
840 if (mBuffers[i].ownedByClient) {
841 // This should not happen.
842 ALOGD("[%s] codec released a buffer owned by client "
843 "(index %zu)", mName, i);
844 }
845 mBuffers[i].compBuffer.reset();
846 ALOGV("[%s] codec released buffer #%zu(array mode)", mName, i);
847 return true;
848 }
849 }
850 ALOGV("[%s] codec released an unknown buffer (array mode)", mName);
851 return false;
852}
853
854void BuffersArrayImpl::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
855 array->clear();
856 for (const Entry &entry : mBuffers) {
857 array->push(entry.clientBuffer);
858 }
859}
860
861void BuffersArrayImpl::flush() {
862 for (Entry &entry : mBuffers) {
863 entry.ownedByClient = false;
864 }
865}
866
867void BuffersArrayImpl::realloc(std::function<sp<Codec2Buffer>()> alloc) {
868 size_t size = mBuffers.size();
869 mBuffers.clear();
870 for (size_t i = 0; i < size; ++i) {
871 mBuffers.push_back({ alloc(), std::weak_ptr<C2Buffer>(), false });
872 }
873}
874
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700875void BuffersArrayImpl::grow(
876 size_t newSize, std::function<sp<Codec2Buffer>()> alloc) {
877 CHECK_LT(mBuffers.size(), newSize);
878 while (mBuffers.size() < newSize) {
879 mBuffers.push_back({ alloc(), std::weak_ptr<C2Buffer>(), false });
880 }
881}
882
Wonsik Kim0487b782020-10-28 11:45:50 -0700883size_t BuffersArrayImpl::numActiveSlots() const {
Wonsik Kim469c8342019-04-11 16:46:09 -0700884 return std::count_if(
885 mBuffers.begin(), mBuffers.end(),
886 [](const Entry &entry) {
Wonsik Kim0487b782020-10-28 11:45:50 -0700887 return entry.ownedByClient || !entry.compBuffer.expired();
Wonsik Kim469c8342019-04-11 16:46:09 -0700888 });
889}
890
Wonsik Kima39882b2019-06-20 16:13:56 -0700891size_t BuffersArrayImpl::arraySize() const {
892 return mBuffers.size();
893}
894
Wonsik Kim469c8342019-04-11 16:46:09 -0700895// InputBuffersArray
896
897void InputBuffersArray::initialize(
898 const FlexBuffersImpl &impl,
899 size_t minSize,
900 std::function<sp<Codec2Buffer>()> allocate) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700901 mAllocate = allocate;
Wonsik Kim469c8342019-04-11 16:46:09 -0700902 mImpl.initialize(impl, minSize, allocate);
903}
904
905void InputBuffersArray::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
906 mImpl.getArray(array);
907}
908
909bool InputBuffersArray::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
910 sp<Codec2Buffer> c2Buffer;
911 status_t err = mImpl.grabBuffer(index, &c2Buffer);
912 if (err == OK) {
913 c2Buffer->setFormat(mFormat);
914 handleImageData(c2Buffer);
915 *buffer = c2Buffer;
916 return true;
917 }
918 return false;
919}
920
921bool InputBuffersArray::releaseBuffer(
922 const sp<MediaCodecBuffer> &buffer,
923 std::shared_ptr<C2Buffer> *c2buffer,
924 bool release) {
925 return mImpl.returnBuffer(buffer, c2buffer, release);
926}
927
928bool InputBuffersArray::expireComponentBuffer(
929 const std::shared_ptr<C2Buffer> &c2buffer) {
930 return mImpl.expireComponentBuffer(c2buffer);
931}
932
933void InputBuffersArray::flush() {
934 mImpl.flush();
935}
936
Wonsik Kim0487b782020-10-28 11:45:50 -0700937size_t InputBuffersArray::numActiveSlots() const {
938 return mImpl.numActiveSlots();
Wonsik Kim469c8342019-04-11 16:46:09 -0700939}
940
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700941sp<Codec2Buffer> InputBuffersArray::createNewBuffer() {
942 return mAllocate();
943}
944
Wonsik Kimfb7a7672019-12-27 17:13:33 -0800945// SlotInputBuffers
946
947bool SlotInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
948 sp<Codec2Buffer> newBuffer = createNewBuffer();
949 *index = mImpl.assignSlot(newBuffer);
950 *buffer = newBuffer;
951 return true;
952}
953
954bool SlotInputBuffers::releaseBuffer(
955 const sp<MediaCodecBuffer> &buffer,
956 std::shared_ptr<C2Buffer> *c2buffer,
957 bool release) {
958 return mImpl.releaseSlot(buffer, c2buffer, release);
959}
960
961bool SlotInputBuffers::expireComponentBuffer(
962 const std::shared_ptr<C2Buffer> &c2buffer) {
963 return mImpl.expireComponentBuffer(c2buffer);
964}
965
966void SlotInputBuffers::flush() {
967 mImpl.flush();
968}
969
970std::unique_ptr<InputBuffers> SlotInputBuffers::toArrayMode(size_t) {
971 TRESPASS("Array mode should not be called at non-legacy mode");
972 return nullptr;
973}
974
Wonsik Kim0487b782020-10-28 11:45:50 -0700975size_t SlotInputBuffers::numActiveSlots() const {
976 return mImpl.numActiveSlots();
Wonsik Kimfb7a7672019-12-27 17:13:33 -0800977}
978
979sp<Codec2Buffer> SlotInputBuffers::createNewBuffer() {
980 return new DummyContainerBuffer{mFormat, nullptr};
981}
982
Wonsik Kim469c8342019-04-11 16:46:09 -0700983// LinearInputBuffers
984
985bool LinearInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700986 sp<Codec2Buffer> newBuffer = createNewBuffer();
Wonsik Kim469c8342019-04-11 16:46:09 -0700987 if (newBuffer == nullptr) {
988 return false;
989 }
990 *index = mImpl.assignSlot(newBuffer);
991 *buffer = newBuffer;
992 return true;
993}
994
995bool LinearInputBuffers::releaseBuffer(
996 const sp<MediaCodecBuffer> &buffer,
997 std::shared_ptr<C2Buffer> *c2buffer,
998 bool release) {
999 return mImpl.releaseSlot(buffer, c2buffer, release);
1000}
1001
1002bool LinearInputBuffers::expireComponentBuffer(
1003 const std::shared_ptr<C2Buffer> &c2buffer) {
1004 return mImpl.expireComponentBuffer(c2buffer);
1005}
1006
1007void LinearInputBuffers::flush() {
1008 // This is no-op by default unless we're in array mode where we need to keep
1009 // track of the flushed work.
1010 mImpl.flush();
1011}
1012
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001013std::unique_ptr<InputBuffers> LinearInputBuffers::toArrayMode(size_t size) {
Wonsik Kim469c8342019-04-11 16:46:09 -07001014 std::unique_ptr<InputBuffersArray> array(
1015 new InputBuffersArray(mComponentName.c_str(), "1D-Input[N]"));
1016 array->setPool(mPool);
1017 array->setFormat(mFormat);
1018 array->initialize(
1019 mImpl,
1020 size,
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001021 [pool = mPool, format = mFormat] () -> sp<Codec2Buffer> {
1022 return Alloc(pool, format);
1023 });
Wonsik Kim469c8342019-04-11 16:46:09 -07001024 return std::move(array);
1025}
1026
Wonsik Kim0487b782020-10-28 11:45:50 -07001027size_t LinearInputBuffers::numActiveSlots() const {
1028 return mImpl.numActiveSlots();
Wonsik Kim469c8342019-04-11 16:46:09 -07001029}
1030
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001031// static
1032sp<Codec2Buffer> LinearInputBuffers::Alloc(
1033 const std::shared_ptr<C2BlockPool> &pool, const sp<AMessage> &format) {
1034 int32_t capacity = kLinearBufferSize;
1035 (void)format->findInt32(KEY_MAX_INPUT_SIZE, &capacity);
1036 if ((size_t)capacity > kMaxLinearBufferSize) {
1037 ALOGD("client requested %d, capped to %zu", capacity, kMaxLinearBufferSize);
1038 capacity = kMaxLinearBufferSize;
1039 }
1040
Wonsik Kim666604a2020-05-14 16:57:49 -07001041 int64_t usageValue = 0;
1042 (void)format->findInt64("android._C2MemoryUsage", &usageValue);
1043 C2MemoryUsage usage{usageValue | C2MemoryUsage::CPU_READ | C2MemoryUsage::CPU_WRITE};
Wonsik Kim469c8342019-04-11 16:46:09 -07001044 std::shared_ptr<C2LinearBlock> block;
1045
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001046 c2_status_t err = pool->fetchLinearBlock(capacity, usage, &block);
Wonsik Kim469c8342019-04-11 16:46:09 -07001047 if (err != C2_OK) {
1048 return nullptr;
1049 }
1050
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001051 return LinearBlockBuffer::Allocate(format, block);
1052}
1053
1054sp<Codec2Buffer> LinearInputBuffers::createNewBuffer() {
1055 return Alloc(mPool, mFormat);
Wonsik Kim469c8342019-04-11 16:46:09 -07001056}
1057
1058// EncryptedLinearInputBuffers
1059
1060EncryptedLinearInputBuffers::EncryptedLinearInputBuffers(
1061 bool secure,
1062 const sp<MemoryDealer> &dealer,
1063 const sp<ICrypto> &crypto,
1064 int32_t heapSeqNum,
1065 size_t capacity,
1066 size_t numInputSlots,
1067 const char *componentName, const char *name)
1068 : LinearInputBuffers(componentName, name),
1069 mUsage({0, 0}),
1070 mDealer(dealer),
1071 mCrypto(crypto),
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001072 mMemoryVector(new std::vector<Entry>){
Wonsik Kim469c8342019-04-11 16:46:09 -07001073 if (secure) {
1074 mUsage = { C2MemoryUsage::READ_PROTECTED, 0 };
1075 } else {
1076 mUsage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
1077 }
1078 for (size_t i = 0; i < numInputSlots; ++i) {
1079 sp<IMemory> memory = mDealer->allocate(capacity);
1080 if (memory == nullptr) {
1081 ALOGD("[%s] Failed to allocate memory from dealer: only %zu slots allocated",
1082 mName, i);
1083 break;
1084 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001085 mMemoryVector->push_back({std::weak_ptr<C2LinearBlock>(), memory, heapSeqNum});
Wonsik Kim469c8342019-04-11 16:46:09 -07001086 }
1087}
1088
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001089std::unique_ptr<InputBuffers> EncryptedLinearInputBuffers::toArrayMode(size_t size) {
1090 std::unique_ptr<InputBuffersArray> array(
1091 new InputBuffersArray(mComponentName.c_str(), "1D-EncryptedInput[N]"));
1092 array->setPool(mPool);
1093 array->setFormat(mFormat);
1094 array->initialize(
1095 mImpl,
1096 size,
1097 [pool = mPool,
1098 format = mFormat,
1099 usage = mUsage,
1100 memoryVector = mMemoryVector] () -> sp<Codec2Buffer> {
1101 return Alloc(pool, format, usage, memoryVector);
1102 });
1103 return std::move(array);
1104}
1105
1106
1107// static
1108sp<Codec2Buffer> EncryptedLinearInputBuffers::Alloc(
1109 const std::shared_ptr<C2BlockPool> &pool,
1110 const sp<AMessage> &format,
1111 C2MemoryUsage usage,
1112 const std::shared_ptr<std::vector<EncryptedLinearInputBuffers::Entry>> &memoryVector) {
1113 int32_t capacity = kLinearBufferSize;
1114 (void)format->findInt32(KEY_MAX_INPUT_SIZE, &capacity);
1115 if ((size_t)capacity > kMaxLinearBufferSize) {
1116 ALOGD("client requested %d, capped to %zu", capacity, kMaxLinearBufferSize);
1117 capacity = kMaxLinearBufferSize;
1118 }
1119
Wonsik Kim469c8342019-04-11 16:46:09 -07001120 sp<IMemory> memory;
1121 size_t slot = 0;
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001122 int32_t heapSeqNum = -1;
1123 for (; slot < memoryVector->size(); ++slot) {
1124 if (memoryVector->at(slot).block.expired()) {
1125 memory = memoryVector->at(slot).memory;
1126 heapSeqNum = memoryVector->at(slot).heapSeqNum;
Wonsik Kim469c8342019-04-11 16:46:09 -07001127 break;
1128 }
1129 }
1130 if (memory == nullptr) {
1131 return nullptr;
1132 }
1133
David Stevens94b608f2021-07-29 15:04:14 +09001134 int64_t usageValue = 0;
1135 (void)format->findInt64("android._C2MemoryUsage", &usageValue);
1136 usage = C2MemoryUsage(usage.expected | usageValue);
1137
Wonsik Kim469c8342019-04-11 16:46:09 -07001138 std::shared_ptr<C2LinearBlock> block;
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001139 c2_status_t err = pool->fetchLinearBlock(capacity, usage, &block);
Wonsik Kim469c8342019-04-11 16:46:09 -07001140 if (err != C2_OK || block == nullptr) {
1141 return nullptr;
1142 }
1143
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001144 memoryVector->at(slot).block = block;
1145 return new EncryptedLinearBlockBuffer(format, block, memory, heapSeqNum);
1146}
1147
1148sp<Codec2Buffer> EncryptedLinearInputBuffers::createNewBuffer() {
1149 // TODO: android_2020
1150 return nullptr;
Wonsik Kim469c8342019-04-11 16:46:09 -07001151}
1152
1153// GraphicMetadataInputBuffers
1154
1155GraphicMetadataInputBuffers::GraphicMetadataInputBuffers(
1156 const char *componentName, const char *name)
1157 : InputBuffers(componentName, name),
1158 mImpl(mName),
1159 mStore(GetCodec2PlatformAllocatorStore()) { }
1160
1161bool GraphicMetadataInputBuffers::requestNewBuffer(
1162 size_t *index, sp<MediaCodecBuffer> *buffer) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001163 sp<Codec2Buffer> newBuffer = createNewBuffer();
Wonsik Kim469c8342019-04-11 16:46:09 -07001164 if (newBuffer == nullptr) {
1165 return false;
1166 }
1167 *index = mImpl.assignSlot(newBuffer);
1168 *buffer = newBuffer;
1169 return true;
1170}
1171
1172bool GraphicMetadataInputBuffers::releaseBuffer(
1173 const sp<MediaCodecBuffer> &buffer,
1174 std::shared_ptr<C2Buffer> *c2buffer,
1175 bool release) {
1176 return mImpl.releaseSlot(buffer, c2buffer, release);
1177}
1178
1179bool GraphicMetadataInputBuffers::expireComponentBuffer(
1180 const std::shared_ptr<C2Buffer> &c2buffer) {
1181 return mImpl.expireComponentBuffer(c2buffer);
1182}
1183
1184void GraphicMetadataInputBuffers::flush() {
1185 // This is no-op by default unless we're in array mode where we need to keep
1186 // track of the flushed work.
1187}
1188
1189std::unique_ptr<InputBuffers> GraphicMetadataInputBuffers::toArrayMode(
1190 size_t size) {
1191 std::shared_ptr<C2Allocator> alloc;
1192 c2_status_t err = mStore->fetchAllocator(mPool->getAllocatorId(), &alloc);
1193 if (err != C2_OK) {
1194 return nullptr;
1195 }
1196 std::unique_ptr<InputBuffersArray> array(
1197 new InputBuffersArray(mComponentName.c_str(), "2D-MetaInput[N]"));
1198 array->setPool(mPool);
1199 array->setFormat(mFormat);
1200 array->initialize(
1201 mImpl,
1202 size,
1203 [format = mFormat, alloc]() -> sp<Codec2Buffer> {
1204 return new GraphicMetadataBuffer(format, alloc);
1205 });
1206 return std::move(array);
1207}
1208
Wonsik Kim0487b782020-10-28 11:45:50 -07001209size_t GraphicMetadataInputBuffers::numActiveSlots() const {
1210 return mImpl.numActiveSlots();
Wonsik Kim469c8342019-04-11 16:46:09 -07001211}
1212
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001213sp<Codec2Buffer> GraphicMetadataInputBuffers::createNewBuffer() {
1214 std::shared_ptr<C2Allocator> alloc;
1215 c2_status_t err = mStore->fetchAllocator(mPool->getAllocatorId(), &alloc);
1216 if (err != C2_OK) {
1217 return nullptr;
1218 }
1219 return new GraphicMetadataBuffer(mFormat, alloc);
1220}
1221
Wonsik Kim469c8342019-04-11 16:46:09 -07001222// GraphicInputBuffers
1223
1224GraphicInputBuffers::GraphicInputBuffers(
Wonsik Kim41d83432020-04-27 16:40:49 -07001225 const char *componentName, const char *name)
Wonsik Kim469c8342019-04-11 16:46:09 -07001226 : InputBuffers(componentName, name),
1227 mImpl(mName),
Songyue Han1e6769b2023-08-30 18:09:27 +00001228 mLocalBufferPool(LocalBufferPool::Create()),
1229 mPixelFormat(PIXEL_FORMAT_UNKNOWN) { }
Wonsik Kim469c8342019-04-11 16:46:09 -07001230
1231bool GraphicInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001232 sp<Codec2Buffer> newBuffer = createNewBuffer();
Wonsik Kim469c8342019-04-11 16:46:09 -07001233 if (newBuffer == nullptr) {
1234 return false;
1235 }
1236 *index = mImpl.assignSlot(newBuffer);
1237 handleImageData(newBuffer);
1238 *buffer = newBuffer;
1239 return true;
1240}
1241
1242bool GraphicInputBuffers::releaseBuffer(
1243 const sp<MediaCodecBuffer> &buffer,
1244 std::shared_ptr<C2Buffer> *c2buffer,
1245 bool release) {
1246 return mImpl.releaseSlot(buffer, c2buffer, release);
1247}
1248
1249bool GraphicInputBuffers::expireComponentBuffer(
1250 const std::shared_ptr<C2Buffer> &c2buffer) {
1251 return mImpl.expireComponentBuffer(c2buffer);
1252}
1253
1254void GraphicInputBuffers::flush() {
1255 // This is no-op by default unless we're in array mode where we need to keep
1256 // track of the flushed work.
1257}
1258
Wonsik Kimd79ee1f2020-08-27 17:41:56 -07001259static uint32_t extractPixelFormat(const sp<AMessage> &format) {
1260 int32_t frameworkColorFormat = 0;
1261 if (!format->findInt32("android._color-format", &frameworkColorFormat)) {
1262 return PIXEL_FORMAT_UNKNOWN;
1263 }
1264 uint32_t pixelFormat = PIXEL_FORMAT_UNKNOWN;
1265 if (C2Mapper::mapPixelFormatFrameworkToCodec(frameworkColorFormat, &pixelFormat)) {
1266 return pixelFormat;
1267 }
1268 return PIXEL_FORMAT_UNKNOWN;
1269}
1270
Wonsik Kim469c8342019-04-11 16:46:09 -07001271std::unique_ptr<InputBuffers> GraphicInputBuffers::toArrayMode(size_t size) {
1272 std::unique_ptr<InputBuffersArray> array(
1273 new InputBuffersArray(mComponentName.c_str(), "2D-BB-Input[N]"));
1274 array->setPool(mPool);
1275 array->setFormat(mFormat);
Wonsik Kimd79ee1f2020-08-27 17:41:56 -07001276 uint32_t pixelFormat = extractPixelFormat(mFormat);
Wonsik Kim469c8342019-04-11 16:46:09 -07001277 array->initialize(
1278 mImpl,
1279 size,
Wonsik Kimd79ee1f2020-08-27 17:41:56 -07001280 [pool = mPool, format = mFormat, lbp = mLocalBufferPool, pixelFormat]()
1281 -> sp<Codec2Buffer> {
Wonsik Kim469c8342019-04-11 16:46:09 -07001282 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
David Stevens94b608f2021-07-29 15:04:14 +09001283 return AllocateInputGraphicBuffer(
Wonsik Kimd79ee1f2020-08-27 17:41:56 -07001284 pool, format, pixelFormat, usage, lbp);
Wonsik Kim469c8342019-04-11 16:46:09 -07001285 });
1286 return std::move(array);
1287}
1288
Wonsik Kim0487b782020-10-28 11:45:50 -07001289size_t GraphicInputBuffers::numActiveSlots() const {
1290 return mImpl.numActiveSlots();
Wonsik Kim469c8342019-04-11 16:46:09 -07001291}
1292
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001293sp<Codec2Buffer> GraphicInputBuffers::createNewBuffer() {
David Stevens94b608f2021-07-29 15:04:14 +09001294 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
Songyue Han1e6769b2023-08-30 18:09:27 +00001295 mPixelFormat = extractPixelFormat(mFormat);
David Stevens94b608f2021-07-29 15:04:14 +09001296 return AllocateInputGraphicBuffer(
Songyue Han1e6769b2023-08-30 18:09:27 +00001297 mPool, mFormat, mPixelFormat, usage, mLocalBufferPool);
1298}
1299
1300uint32_t GraphicInputBuffers::getPixelFormatIfApplicable() { return mPixelFormat; }
1301
1302bool GraphicInputBuffers::resetPixelFormatIfApplicable() {
1303 mPixelFormat = PIXEL_FORMAT_UNKNOWN;
1304 return true;
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001305}
1306
Wonsik Kim469c8342019-04-11 16:46:09 -07001307// OutputBuffersArray
1308
1309void OutputBuffersArray::initialize(
1310 const FlexBuffersImpl &impl,
1311 size_t minSize,
1312 std::function<sp<Codec2Buffer>()> allocate) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001313 mAlloc = allocate;
Wonsik Kim469c8342019-04-11 16:46:09 -07001314 mImpl.initialize(impl, minSize, allocate);
1315}
1316
1317status_t OutputBuffersArray::registerBuffer(
1318 const std::shared_ptr<C2Buffer> &buffer,
1319 size_t *index,
1320 sp<MediaCodecBuffer> *clientBuffer) {
1321 sp<Codec2Buffer> c2Buffer;
1322 status_t err = mImpl.grabBuffer(
1323 index,
1324 &c2Buffer,
1325 [buffer](const sp<Codec2Buffer> &clientBuffer) {
1326 return clientBuffer->canCopy(buffer);
1327 });
1328 if (err == WOULD_BLOCK) {
1329 ALOGV("[%s] buffers temporarily not available", mName);
1330 return err;
1331 } else if (err != OK) {
1332 ALOGD("[%s] grabBuffer failed: %d", mName, err);
1333 return err;
1334 }
1335 c2Buffer->setFormat(mFormat);
Wonsik Kim6f23cfc2021-09-24 05:45:52 -07001336 if (!convert(buffer, &c2Buffer) && !c2Buffer->copy(buffer)) {
Wonsik Kim469c8342019-04-11 16:46:09 -07001337 ALOGD("[%s] copy buffer failed", mName);
1338 return WOULD_BLOCK;
1339 }
Arun Johnsonf4a81f72023-11-09 21:22:48 +00001340 if (buffer && buffer->hasInfo(C2AccessUnitInfos::output::PARAM_TYPE)) {
1341 std::shared_ptr<const C2AccessUnitInfos::output> bufferMetadata =
1342 std::static_pointer_cast<const C2AccessUnitInfos::output>(
1343 buffer->getInfo(C2AccessUnitInfos::output::PARAM_TYPE));
1344 if (submit(c2Buffer, mSampleRate, mChannelCount, bufferMetadata)) {
1345 buffer->removeInfo(C2AccessUnitInfos::output::PARAM_TYPE);
1346 }
1347 } else {
1348 submit(c2Buffer);
1349 }
Wonsik Kim469c8342019-04-11 16:46:09 -07001350 handleImageData(c2Buffer);
1351 *clientBuffer = c2Buffer;
1352 ALOGV("[%s] grabbed buffer %zu", mName, *index);
1353 return OK;
1354}
1355
1356status_t OutputBuffersArray::registerCsd(
1357 const C2StreamInitDataInfo::output *csd,
1358 size_t *index,
1359 sp<MediaCodecBuffer> *clientBuffer) {
1360 sp<Codec2Buffer> c2Buffer;
1361 status_t err = mImpl.grabBuffer(
1362 index,
1363 &c2Buffer,
1364 [csd](const sp<Codec2Buffer> &clientBuffer) {
1365 return clientBuffer->base() != nullptr
1366 && clientBuffer->capacity() >= csd->flexCount();
1367 });
1368 if (err != OK) {
1369 return err;
1370 }
1371 memcpy(c2Buffer->base(), csd->m.value, csd->flexCount());
1372 c2Buffer->setRange(0, csd->flexCount());
1373 c2Buffer->setFormat(mFormat);
1374 *clientBuffer = c2Buffer;
1375 return OK;
1376}
1377
1378bool OutputBuffersArray::releaseBuffer(
1379 const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) {
1380 return mImpl.returnBuffer(buffer, c2buffer, true);
1381}
1382
1383void OutputBuffersArray::flush(const std::list<std::unique_ptr<C2Work>> &flushedWork) {
1384 (void)flushedWork;
1385 mImpl.flush();
1386 if (mSkipCutBuffer != nullptr) {
Arun Johnsond43dc8c2024-02-07 01:14:15 +00001387 mSkipCutBuffer->clearAll();
Wonsik Kim469c8342019-04-11 16:46:09 -07001388 }
1389}
1390
1391void OutputBuffersArray::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
1392 mImpl.getArray(array);
1393}
1394
Wonsik Kim0487b782020-10-28 11:45:50 -07001395size_t OutputBuffersArray::numActiveSlots() const {
1396 return mImpl.numActiveSlots();
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001397}
1398
Wonsik Kim469c8342019-04-11 16:46:09 -07001399void OutputBuffersArray::realloc(const std::shared_ptr<C2Buffer> &c2buffer) {
Wonsik Kim469c8342019-04-11 16:46:09 -07001400 switch (c2buffer->data().type()) {
1401 case C2BufferData::LINEAR: {
1402 uint32_t size = kLinearBufferSize;
Nick Desaulniersd09eaea2019-10-07 20:19:39 -07001403 const std::vector<C2ConstLinearBlock> &linear_blocks = c2buffer->data().linearBlocks();
1404 const uint32_t block_size = linear_blocks.front().size();
1405 if (block_size < kMaxLinearBufferSize / 2) {
1406 size = block_size * 2;
Wonsik Kim469c8342019-04-11 16:46:09 -07001407 } else {
1408 size = kMaxLinearBufferSize;
1409 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001410 mAlloc = [format = mFormat, size] {
Wonsik Kim469c8342019-04-11 16:46:09 -07001411 return new LocalLinearBuffer(format, new ABuffer(size));
1412 };
Wonsik Kima39882b2019-06-20 16:13:56 -07001413 ALOGD("[%s] reallocating with linear buffer of size %u", mName, size);
Wonsik Kim469c8342019-04-11 16:46:09 -07001414 break;
1415 }
1416
Wonsik Kima39882b2019-06-20 16:13:56 -07001417 case C2BufferData::GRAPHIC: {
1418 // This is only called for RawGraphicOutputBuffers.
1419 mAlloc = [format = mFormat,
Wonsik Kim41d83432020-04-27 16:40:49 -07001420 lbp = LocalBufferPool::Create()] {
Wonsik Kima39882b2019-06-20 16:13:56 -07001421 return ConstGraphicBlockBuffer::AllocateEmpty(
1422 format,
1423 [lbp](size_t capacity) {
1424 return lbp->newBuffer(capacity);
1425 });
1426 };
1427 ALOGD("[%s] reallocating with graphic buffer: format = %s",
1428 mName, mFormat->debugString().c_str());
1429 break;
1430 }
Wonsik Kim469c8342019-04-11 16:46:09 -07001431
1432 case C2BufferData::INVALID: [[fallthrough]];
1433 case C2BufferData::LINEAR_CHUNKS: [[fallthrough]];
1434 case C2BufferData::GRAPHIC_CHUNKS: [[fallthrough]];
1435 default:
1436 ALOGD("Unsupported type: %d", (int)c2buffer->data().type());
1437 return;
1438 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001439 mImpl.realloc(mAlloc);
Wonsik Kim469c8342019-04-11 16:46:09 -07001440}
1441
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001442void OutputBuffersArray::grow(size_t newSize) {
1443 mImpl.grow(newSize, mAlloc);
Wonsik Kim469c8342019-04-11 16:46:09 -07001444}
1445
Pawin Vongmasa9b906982020-04-11 05:07:15 -07001446void OutputBuffersArray::transferFrom(OutputBuffers* source) {
1447 mFormat = source->mFormat;
1448 mSkipCutBuffer = source->mSkipCutBuffer;
Pawin Vongmasa9b906982020-04-11 05:07:15 -07001449 mPending = std::move(source->mPending);
1450 mReorderStash = std::move(source->mReorderStash);
1451 mDepth = source->mDepth;
1452 mKey = source->mKey;
1453}
1454
Wonsik Kim469c8342019-04-11 16:46:09 -07001455// FlexOutputBuffers
1456
1457status_t FlexOutputBuffers::registerBuffer(
1458 const std::shared_ptr<C2Buffer> &buffer,
1459 size_t *index,
1460 sp<MediaCodecBuffer> *clientBuffer) {
Wonsik Kim6f23cfc2021-09-24 05:45:52 -07001461 sp<Codec2Buffer> newBuffer;
1462 if (!convert(buffer, &newBuffer)) {
1463 newBuffer = wrap(buffer);
1464 if (newBuffer == nullptr) {
1465 return NO_MEMORY;
1466 }
Wonsik Kim360ba0a2022-05-23 15:38:21 -07001467 newBuffer->setFormat(mFormat);
Wonsik Kim469c8342019-04-11 16:46:09 -07001468 }
Wonsik Kim469c8342019-04-11 16:46:09 -07001469 *index = mImpl.assignSlot(newBuffer);
1470 handleImageData(newBuffer);
1471 *clientBuffer = newBuffer;
Songyue Han1e6769b2023-08-30 18:09:27 +00001472
1473 extractPixelFormatFromC2Buffer(buffer);
Wonsik Kim469c8342019-04-11 16:46:09 -07001474 ALOGV("[%s] registered buffer %zu", mName, *index);
1475 return OK;
1476}
1477
1478status_t FlexOutputBuffers::registerCsd(
1479 const C2StreamInitDataInfo::output *csd,
1480 size_t *index,
1481 sp<MediaCodecBuffer> *clientBuffer) {
1482 sp<Codec2Buffer> newBuffer = new LocalLinearBuffer(
1483 mFormat, ABuffer::CreateAsCopy(csd->m.value, csd->flexCount()));
1484 *index = mImpl.assignSlot(newBuffer);
1485 *clientBuffer = newBuffer;
1486 return OK;
1487}
1488
1489bool FlexOutputBuffers::releaseBuffer(
1490 const sp<MediaCodecBuffer> &buffer,
1491 std::shared_ptr<C2Buffer> *c2buffer) {
1492 return mImpl.releaseSlot(buffer, c2buffer, true);
1493}
1494
1495void FlexOutputBuffers::flush(
1496 const std::list<std::unique_ptr<C2Work>> &flushedWork) {
1497 (void) flushedWork;
1498 // This is no-op by default unless we're in array mode where we need to keep
1499 // track of the flushed work.
1500}
1501
Pawin Vongmasa9b906982020-04-11 05:07:15 -07001502std::unique_ptr<OutputBuffersArray> FlexOutputBuffers::toArrayMode(size_t size) {
Wonsik Kim469c8342019-04-11 16:46:09 -07001503 std::unique_ptr<OutputBuffersArray> array(new OutputBuffersArray(mComponentName.c_str()));
Pawin Vongmasa9b906982020-04-11 05:07:15 -07001504 array->transferFrom(this);
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001505 std::function<sp<Codec2Buffer>()> alloc = getAlloc();
1506 array->initialize(mImpl, size, alloc);
Pawin Vongmasa9b906982020-04-11 05:07:15 -07001507 return array;
Wonsik Kim469c8342019-04-11 16:46:09 -07001508}
1509
Wonsik Kim0487b782020-10-28 11:45:50 -07001510size_t FlexOutputBuffers::numActiveSlots() const {
1511 return mImpl.numActiveSlots();
Wonsik Kim469c8342019-04-11 16:46:09 -07001512}
1513
Songyue Han1e6769b2023-08-30 18:09:27 +00001514bool FlexOutputBuffers::extractPixelFormatFromC2Buffer(const std::shared_ptr<C2Buffer> &buffer) {
1515 if (buffer == nullptr) {
1516 return false;
1517 }
1518 const C2BufferData &data = buffer->data();
1519 // only extract the first pixel format in a metric session.
1520 if (mPixelFormat != PIXEL_FORMAT_UNKNOWN || data.type() != C2BufferData::GRAPHIC
1521 || data.graphicBlocks().empty()) {
1522 return false;
1523 }
1524 const C2Handle *const handle = data.graphicBlocks().front().handle();
1525 uint32_t pf = ExtractFormatFromCodec2GrallocHandle(handle);
1526 if (pf == PIXEL_FORMAT_UNKNOWN) {
1527 return false;
1528 }
1529 mPixelFormat = pf;
1530 return true;
1531}
1532
1533bool FlexOutputBuffers::resetPixelFormatIfApplicable() {
1534 mPixelFormat = PIXEL_FORMAT_UNKNOWN;
1535 return true;
1536}
1537
1538uint32_t FlexOutputBuffers::getPixelFormatIfApplicable() { return mPixelFormat; }
1539
Wonsik Kim469c8342019-04-11 16:46:09 -07001540// LinearOutputBuffers
1541
1542void LinearOutputBuffers::flush(
1543 const std::list<std::unique_ptr<C2Work>> &flushedWork) {
1544 if (mSkipCutBuffer != nullptr) {
Arun Johnsond43dc8c2024-02-07 01:14:15 +00001545 mSkipCutBuffer->clearAll();
Wonsik Kim469c8342019-04-11 16:46:09 -07001546 }
1547 FlexOutputBuffers::flush(flushedWork);
1548}
1549
1550sp<Codec2Buffer> LinearOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
1551 if (buffer == nullptr) {
1552 ALOGV("[%s] using a dummy buffer", mName);
1553 return new LocalLinearBuffer(mFormat, new ABuffer(0));
1554 }
1555 if (buffer->data().type() != C2BufferData::LINEAR) {
1556 ALOGV("[%s] non-linear buffer %d", mName, buffer->data().type());
1557 // We expect linear output buffers from the component.
1558 return nullptr;
1559 }
1560 if (buffer->data().linearBlocks().size() != 1u) {
1561 ALOGV("[%s] no linear buffers", mName);
1562 // We expect one and only one linear block from the component.
1563 return nullptr;
1564 }
1565 sp<Codec2Buffer> clientBuffer = ConstLinearBlockBuffer::Allocate(mFormat, buffer);
1566 if (clientBuffer == nullptr) {
1567 ALOGD("[%s] ConstLinearBlockBuffer::Allocate failed", mName);
1568 return nullptr;
1569 }
1570 submit(clientBuffer);
1571 return clientBuffer;
1572}
1573
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001574std::function<sp<Codec2Buffer>()> LinearOutputBuffers::getAlloc() {
1575 return [format = mFormat]{
1576 // TODO: proper max output size
1577 return new LocalLinearBuffer(format, new ABuffer(kLinearBufferSize));
1578 };
Wonsik Kim469c8342019-04-11 16:46:09 -07001579}
1580
1581// GraphicOutputBuffers
1582
1583sp<Codec2Buffer> GraphicOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
1584 return new DummyContainerBuffer(mFormat, buffer);
1585}
1586
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001587std::function<sp<Codec2Buffer>()> GraphicOutputBuffers::getAlloc() {
1588 return [format = mFormat]{
1589 return new DummyContainerBuffer(format);
1590 };
Wonsik Kim469c8342019-04-11 16:46:09 -07001591}
1592
1593// RawGraphicOutputBuffers
1594
1595RawGraphicOutputBuffers::RawGraphicOutputBuffers(
Wonsik Kim41d83432020-04-27 16:40:49 -07001596 const char *componentName, const char *name)
Wonsik Kim469c8342019-04-11 16:46:09 -07001597 : FlexOutputBuffers(componentName, name),
Wonsik Kim41d83432020-04-27 16:40:49 -07001598 mLocalBufferPool(LocalBufferPool::Create()) { }
Wonsik Kim469c8342019-04-11 16:46:09 -07001599
1600sp<Codec2Buffer> RawGraphicOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
1601 if (buffer == nullptr) {
Wonsik Kim6f116902021-07-14 08:58:07 -07001602 return new Codec2Buffer(mFormat, new ABuffer(nullptr, 0));
Wonsik Kim469c8342019-04-11 16:46:09 -07001603 } else {
1604 return ConstGraphicBlockBuffer::Allocate(
1605 mFormat,
1606 buffer,
1607 [lbp = mLocalBufferPool](size_t capacity) {
1608 return lbp->newBuffer(capacity);
1609 });
1610 }
1611}
1612
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001613std::function<sp<Codec2Buffer>()> RawGraphicOutputBuffers::getAlloc() {
1614 return [format = mFormat, lbp = mLocalBufferPool]{
1615 return ConstGraphicBlockBuffer::AllocateEmpty(
1616 format,
1617 [lbp](size_t capacity) {
1618 return lbp->newBuffer(capacity);
1619 });
1620 };
Wonsik Kim469c8342019-04-11 16:46:09 -07001621}
1622
1623} // namespace android