blob: 8a4877725d63705daaa888d72358fc782a6de39b [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 }
163
164 virtual ~MultiAccessUnitSkipCutBuffer() {
165
166 }
167
168 void submitMultiAccessUnits(
169 const sp<MediaCodecBuffer>& buffer,
170 int32_t sampleRate, size_t num16BitChannels,
171 std::shared_ptr<const C2AccessUnitInfos::output> &infos) {
172 if (infos == nullptr) {
173 // there is nothing to do more.
174 SkipCutBuffer::submit(buffer);
175 return;
176 }
177 typedef WrapperObject<std::vector<AccessUnitInfo>> BufferInfosWrapper;
178 CHECK_EQ(mSize, SkipCutBuffer::size());
179 sp<BufferInfosWrapper> bufferInfos{new BufferInfosWrapper(decltype(bufferInfos->value)())};
180 uint32_t availableSize = buffer->size() + SkipCutBuffer::size();
181 uint32_t frontPadding = mFrontPadding;
182 int32_t lastEmptyAccessUnitIndex = -1;
183 int64_t byteInUs = 0;
184 if (sampleRate > 0 && num16BitChannels > 0) {
185 byteInUs = (1000000u / (sampleRate * num16BitChannels * 2));
186 }
187 if (frontPadding > 0) {
188 mInfos.clear();
189 mSize = 0;
190 }
191 for (int i = 0 ; i < infos->flexCount() && frontPadding > 0; i++) {
192 uint32_t flagsInPadding = 0;
193 int64_t timeInPadding = 0;
194 if (infos->m.values[i].size <= frontPadding) {
195 // we have more front padding so this buffer is not going to be used.
196 int32_t consumed = infos->m.values[i].size;
197 frontPadding -= consumed;
198 mFrontPaddingDelay += byteInUs * (consumed);
199 availableSize -= consumed;
200 flagsInPadding |= toMediaCodecFlags(infos->m.values[i].flags);
201 timeInPadding = infos->m.values[i].timestamp;
202 } else {
203 C2AccessUnitInfosStruct info = infos->m.values[i];
204 mFrontPaddingDelay += byteInUs * (frontPadding);
205 info.size -= frontPadding;
206 info.timestamp -= mFrontPaddingDelay;
207 availableSize -= frontPadding;
208 flagsInPadding |= toMediaCodecFlags(infos->m.values[i].flags);
209 timeInPadding = infos->m.values[i].timestamp;
210 frontPadding = 0;
211 mInfos.push_back(info);
212 mSize += info.size;
213 }
214 if (flagsInPadding != 0) {
215 bufferInfos->value.emplace_back(
216 flagsInPadding, 0, timeInPadding);
217 }
218 lastEmptyAccessUnitIndex = i;
219 }
220 if (frontPadding <= 0) {
221 // process what's already in the buffer first
222 auto it = mInfos.begin();
223 while (it != mInfos.end() && availableSize > mBackPadding) {
224 // we have samples to send out.
225 if ((availableSize - it->size) >= mBackPadding) {
226 // this is totally used here.
227 int32_t consumed = it->size;
228 bufferInfos->value.emplace_back(
229 toMediaCodecFlags(it->flags), consumed, it->timestamp);
230 availableSize -= consumed;
231 mSize -= consumed;
232 it = mInfos.erase(it);
233 } else {
234 int32_t consumed = availableSize - mBackPadding;
235 bufferInfos->value.emplace_back(
236 toMediaCodecFlags(it->flags),
237 consumed,
238 it->timestamp);
239 it->size -= consumed;
240 it->timestamp += consumed * byteInUs;
241 availableSize -= consumed;
242 mSize -= consumed;
243 it++;
244 }
245 }
246 // if buffer has more process all of it and keep the remaining info.
247 for (int i = (lastEmptyAccessUnitIndex + 1) ; i < infos->flexCount() ; i++) {
248 // upddate updatedInfo and mInfos
249 if (availableSize > mBackPadding) {
250 // we have to take data from the new buffer.
251 if (availableSize - infos->m.values[i].size >= mBackPadding) {
252 // we are using this info
253 int32_t consumed = infos->m.values[i].size;
254 bufferInfos->value.emplace_back(
255 toMediaCodecFlags(infos->m.values[i].flags),
256 consumed,
257 infos->m.values[i].timestamp - mFrontPaddingDelay);
258 availableSize -= consumed;
259 } else {
260 // if we need to update the size
261 C2AccessUnitInfosStruct info = infos->m.values[i];
262 int32_t consumed = availableSize - mBackPadding;
263 bufferInfos->value.emplace_back(
264 toMediaCodecFlags(infos->m.values[i].flags),
265 consumed,
266 infos->m.values[i].timestamp - mFrontPaddingDelay);
267 info.size -= consumed;
268 info.timestamp = info.timestamp - mFrontPaddingDelay +
269 consumed * byteInUs;
270 mInfos.push_back(info);
271 availableSize -= consumed;
272 mSize += info.size;
273 }
274 } else {
275 // we have to maintain infos
276 C2AccessUnitInfosStruct info = infos->m.values[i];
277 info.timestamp -= mFrontPaddingDelay;
278 mInfos.push_back(info);
279 mSize += info.size;
280 }
281 }
282 }
283 SkipCutBuffer::submit(buffer);
284 infos = nullptr;
285 if (!bufferInfos->value.empty()) {
286 buffer->meta()->setObject("accessUnitInfo", bufferInfos);
287 }
288 }
289protected:
290 // Flags can come with individual BufferInfos
291 // when used with large frame audio
292 constexpr static std::initializer_list<std::pair<uint32_t, uint32_t>> flagList = {
293 {BUFFER_FLAG_CODEC_CONFIG, C2FrameData::FLAG_CODEC_CONFIG},
294 {BUFFER_FLAG_END_OF_STREAM, C2FrameData::FLAG_END_OF_STREAM},
295 {BUFFER_FLAG_DECODE_ONLY, C2FrameData::FLAG_DROP_FRAME}
296 };
297
298 static uint32_t toMediaCodecFlags(uint32_t flags) {
299 return std::transform_reduce(
300 flagList.begin(), flagList.end(),
301 0u,
302 std::bit_or{},
303 [flags](const std::pair<uint32_t, uint32_t> &entry) {
304 return (flags & entry.second) ? entry.first : 0;
305 });
306 }
307 std::list<C2AccessUnitInfosStruct> mInfos;
308 int64_t mFrontPaddingDelay;
309 size_t mSize;
310};
311
Wonsik Kim469c8342019-04-11 16:46:09 -0700312// OutputBuffers
313
Wonsik Kim41d83432020-04-27 16:40:49 -0700314OutputBuffers::OutputBuffers(const char *componentName, const char *name)
315 : CCodecBuffers(componentName, name) { }
316
317OutputBuffers::~OutputBuffers() = default;
318
Wonsik Kim469c8342019-04-11 16:46:09 -0700319void OutputBuffers::initSkipCutBuffer(
320 int32_t delay, int32_t padding, int32_t sampleRate, int32_t channelCount) {
321 CHECK(mSkipCutBuffer == nullptr);
322 mDelay = delay;
323 mPadding = padding;
324 mSampleRate = sampleRate;
Wonsik Kim40b0b1d2020-03-25 15:47:35 -0700325 mChannelCount = channelCount;
326 setSkipCutBuffer(delay, padding);
Wonsik Kim469c8342019-04-11 16:46:09 -0700327}
328
329void OutputBuffers::updateSkipCutBuffer(int32_t sampleRate, int32_t channelCount) {
330 if (mSkipCutBuffer == nullptr) {
331 return;
332 }
Wonsik Kim40b0b1d2020-03-25 15:47:35 -0700333 if (mSampleRate == sampleRate && mChannelCount == channelCount) {
334 return;
335 }
Wonsik Kim469c8342019-04-11 16:46:09 -0700336 int32_t delay = mDelay;
337 int32_t padding = mPadding;
338 if (sampleRate != mSampleRate) {
339 delay = ((int64_t)delay * sampleRate) / mSampleRate;
340 padding = ((int64_t)padding * sampleRate) / mSampleRate;
341 }
Wonsik Kim40b0b1d2020-03-25 15:47:35 -0700342 mSampleRate = sampleRate;
343 mChannelCount = channelCount;
344 setSkipCutBuffer(delay, padding);
Wonsik Kim469c8342019-04-11 16:46:09 -0700345}
346
Wonsik Kim3b4349a2020-11-10 11:54:15 -0800347void OutputBuffers::updateSkipCutBuffer(const sp<AMessage> &format) {
Pawin Vongmasa9b906982020-04-11 05:07:15 -0700348 AString mediaType;
349 if (format->findString(KEY_MIME, &mediaType)
350 && mediaType == MIMETYPE_AUDIO_RAW) {
351 int32_t channelCount;
352 int32_t sampleRate;
353 if (format->findInt32(KEY_CHANNEL_COUNT, &channelCount)
354 && format->findInt32(KEY_SAMPLE_RATE, &sampleRate)) {
355 updateSkipCutBuffer(sampleRate, channelCount);
356 }
357 }
Pawin Vongmasa9b906982020-04-11 05:07:15 -0700358}
359
Wonsik Kim469c8342019-04-11 16:46:09 -0700360void OutputBuffers::submit(const sp<MediaCodecBuffer> &buffer) {
361 if (mSkipCutBuffer != nullptr) {
362 mSkipCutBuffer->submit(buffer);
363 }
364}
365
Arun Johnsonf4a81f72023-11-09 21:22:48 +0000366bool OutputBuffers::submit(const sp<MediaCodecBuffer> &buffer, int32_t sampleRate,
367 int32_t channelCount, std::shared_ptr<const C2AccessUnitInfos::output> &infos) {
368 if (mSkipCutBuffer == nullptr) {
369 return false;
370 }
371 mSkipCutBuffer->submitMultiAccessUnits(buffer, sampleRate, channelCount, infos);
372 return true;
373}
374
Wonsik Kim40b0b1d2020-03-25 15:47:35 -0700375void OutputBuffers::setSkipCutBuffer(int32_t skip, int32_t cut) {
Wonsik Kim469c8342019-04-11 16:46:09 -0700376 if (mSkipCutBuffer != nullptr) {
377 size_t prevSize = mSkipCutBuffer->size();
378 if (prevSize != 0u) {
379 ALOGD("[%s] Replacing SkipCutBuffer holding %zu bytes", mName, prevSize);
380 }
381 }
Arun Johnsonf4a81f72023-11-09 21:22:48 +0000382 mSkipCutBuffer = new MultiAccessUnitSkipCutBuffer(skip, cut, mChannelCount);
Wonsik Kim469c8342019-04-11 16:46:09 -0700383}
384
Wonsik Kim6f23cfc2021-09-24 05:45:52 -0700385bool OutputBuffers::convert(
386 const std::shared_ptr<C2Buffer> &src, sp<Codec2Buffer> *dst) {
Wonsik Kim360ba0a2022-05-23 15:38:21 -0700387 if (src && src->data().type() != C2BufferData::LINEAR) {
Wonsik Kim6f23cfc2021-09-24 05:45:52 -0700388 return false;
389 }
390 int32_t configEncoding = kAudioEncodingPcm16bit;
391 int32_t codecEncoding = kAudioEncodingPcm16bit;
392 if (mFormat->findInt32("android._codec-pcm-encoding", &codecEncoding)
393 && mFormat->findInt32("android._config-pcm-encoding", &configEncoding)) {
394 if (mSrcEncoding != codecEncoding || mDstEncoding != configEncoding) {
395 if (codecEncoding != configEncoding) {
396 mDataConverter = AudioConverter::Create(
397 (AudioEncoding)codecEncoding, (AudioEncoding)configEncoding);
398 ALOGD_IF(mDataConverter, "[%s] Converter created from %d to %d",
399 mName, codecEncoding, configEncoding);
400 mFormatWithConverter = mFormat->dup();
401 mFormatWithConverter->setInt32(KEY_PCM_ENCODING, configEncoding);
402 } else {
403 mDataConverter = nullptr;
404 mFormatWithConverter = nullptr;
405 }
406 mSrcEncoding = codecEncoding;
407 mDstEncoding = configEncoding;
408 }
409 if (int encoding; !mFormat->findInt32(KEY_PCM_ENCODING, &encoding)
410 || encoding != mDstEncoding) {
411 }
412 }
413 if (!mDataConverter) {
414 return false;
415 }
Wonsik Kim360ba0a2022-05-23 15:38:21 -0700416 sp<MediaCodecBuffer> srcBuffer;
417 if (src) {
418 srcBuffer = ConstLinearBlockBuffer::Allocate(mFormat, src);
419 } else {
420 srcBuffer = new MediaCodecBuffer(mFormat, new ABuffer(0));
421 }
Wonsik Kim6f23cfc2021-09-24 05:45:52 -0700422 if (!srcBuffer) {
423 return false;
424 }
Greg Kaiser92dc4542021-10-08 06:58:19 -0700425 if (!*dst) {
Wonsik Kim6f23cfc2021-09-24 05:45:52 -0700426 *dst = new Codec2Buffer(
427 mFormat,
428 new ABuffer(mDataConverter->targetSize(srcBuffer->size())));
429 }
430 sp<MediaCodecBuffer> dstBuffer = *dst;
431 status_t err = mDataConverter->convert(srcBuffer, dstBuffer);
432 if (err != OK) {
433 ALOGD("[%s] buffer conversion failed: %d", mName, err);
434 return false;
435 }
436 dstBuffer->setFormat(mFormatWithConverter);
437 return true;
438}
439
Pawin Vongmasa9b906982020-04-11 05:07:15 -0700440void OutputBuffers::clearStash() {
441 mPending.clear();
442 mReorderStash.clear();
443 mDepth = 0;
444 mKey = C2Config::ORDINAL;
Pawin Vongmasa9b906982020-04-11 05:07:15 -0700445}
446
447void OutputBuffers::flushStash() {
448 for (StashEntry& e : mPending) {
449 e.notify = false;
450 }
451 for (StashEntry& e : mReorderStash) {
452 e.notify = false;
453 }
454}
455
456uint32_t OutputBuffers::getReorderDepth() const {
457 return mDepth;
458}
459
460void OutputBuffers::setReorderDepth(uint32_t depth) {
461 mPending.splice(mPending.end(), mReorderStash);
462 mDepth = depth;
463}
464
465void OutputBuffers::setReorderKey(C2Config::ordinal_key_t key) {
466 mPending.splice(mPending.end(), mReorderStash);
467 mKey = key;
468}
469
470void OutputBuffers::pushToStash(
471 const std::shared_ptr<C2Buffer>& buffer,
472 bool notify,
473 int64_t timestamp,
474 int32_t flags,
475 const sp<AMessage>& format,
476 const C2WorkOrdinalStruct& ordinal) {
My Nameac29e592022-03-28 13:53:32 -0700477 bool eos = flags & BUFFER_FLAG_END_OF_STREAM;
Pawin Vongmasa9b906982020-04-11 05:07:15 -0700478 if (!buffer && eos) {
479 // TRICKY: we may be violating ordering of the stash here. Because we
480 // don't expect any more emplace() calls after this, the ordering should
481 // not matter.
482 mReorderStash.emplace_back(
483 buffer, notify, timestamp, flags, format, ordinal);
484 } else {
My Nameac29e592022-03-28 13:53:32 -0700485 flags = flags & ~BUFFER_FLAG_END_OF_STREAM;
Pawin Vongmasa9b906982020-04-11 05:07:15 -0700486 auto it = mReorderStash.begin();
487 for (; it != mReorderStash.end(); ++it) {
488 if (less(ordinal, it->ordinal)) {
489 break;
490 }
491 }
492 mReorderStash.emplace(it,
493 buffer, notify, timestamp, flags, format, ordinal);
494 if (eos) {
495 mReorderStash.back().flags =
My Nameac29e592022-03-28 13:53:32 -0700496 mReorderStash.back().flags | BUFFER_FLAG_END_OF_STREAM;
Pawin Vongmasa9b906982020-04-11 05:07:15 -0700497 }
498 }
499 while (!mReorderStash.empty() && mReorderStash.size() > mDepth) {
500 mPending.push_back(mReorderStash.front());
501 mReorderStash.pop_front();
502 }
503 ALOGV("[%s] %s: pushToStash -- pending size = %zu", mName, __func__, mPending.size());
504}
505
506OutputBuffers::BufferAction OutputBuffers::popFromStashAndRegister(
507 std::shared_ptr<C2Buffer>* c2Buffer,
508 size_t* index,
509 sp<MediaCodecBuffer>* outBuffer) {
510 if (mPending.empty()) {
511 return SKIP;
512 }
513
514 // Retrieve the first entry.
515 StashEntry &entry = mPending.front();
516
517 *c2Buffer = entry.buffer;
518 sp<AMessage> outputFormat = entry.format;
519
Wonsik Kim3b4349a2020-11-10 11:54:15 -0800520 if (entry.notify && mFormat != outputFormat) {
521 updateSkipCutBuffer(outputFormat);
Wonsik Kim4a3c0462021-03-09 15:45:05 -0800522 // Trigger image data processing to the new format
523 mLastImageData.clear();
Wonsik Kim3b4349a2020-11-10 11:54:15 -0800524 ALOGV("[%s] popFromStashAndRegister: output format reference changed: %p -> %p",
525 mName, mFormat.get(), outputFormat.get());
Wonsik Kim4a3c0462021-03-09 15:45:05 -0800526 ALOGD("[%s] popFromStashAndRegister: at %lldus, output format changed to %s",
527 mName, (long long)entry.timestamp, outputFormat->debugString().c_str());
Wonsik Kim3b4349a2020-11-10 11:54:15 -0800528 setFormat(outputFormat);
Pawin Vongmasa9b906982020-04-11 05:07:15 -0700529 }
530
531 // Flushing mReorderStash because no other buffers should come after output
532 // EOS.
My Nameac29e592022-03-28 13:53:32 -0700533 if (entry.flags & BUFFER_FLAG_END_OF_STREAM) {
Pawin Vongmasa9b906982020-04-11 05:07:15 -0700534 // Flush reorder stash
535 setReorderDepth(0);
536 }
537
538 if (!entry.notify) {
539 mPending.pop_front();
540 return DISCARD;
541 }
542
543 // Try to register the buffer.
544 status_t err = registerBuffer(*c2Buffer, index, outBuffer);
545 if (err != OK) {
546 if (err != WOULD_BLOCK) {
547 return REALLOCATE;
548 }
549 return RETRY;
550 }
551
552 // Append information from the front stash entry to outBuffer.
553 (*outBuffer)->meta()->setInt64("timeUs", entry.timestamp);
554 (*outBuffer)->meta()->setInt32("flags", entry.flags);
Byeongjo Park2eef13e2020-06-12 17:24:21 +0900555 (*outBuffer)->meta()->setInt64("frameIndex", entry.ordinal.frameIndex.peekll());
Pawin Vongmasa9b906982020-04-11 05:07:15 -0700556 ALOGV("[%s] popFromStashAndRegister: "
557 "out buffer index = %zu [%p] => %p + %zu (%lld)",
558 mName, *index, outBuffer->get(),
559 (*outBuffer)->data(), (*outBuffer)->size(),
560 (long long)entry.timestamp);
561
562 // The front entry of mPending will be removed now that the registration
563 // succeeded.
564 mPending.pop_front();
565 return NOTIFY_CLIENT;
566}
567
568bool OutputBuffers::popPending(StashEntry *entry) {
569 if (mPending.empty()) {
570 return false;
571 }
572 *entry = mPending.front();
573 mPending.pop_front();
574 return true;
575}
576
577void OutputBuffers::deferPending(const OutputBuffers::StashEntry &entry) {
578 mPending.push_front(entry);
579}
580
581bool OutputBuffers::hasPending() const {
582 return !mPending.empty();
583}
584
585bool OutputBuffers::less(
586 const C2WorkOrdinalStruct &o1, const C2WorkOrdinalStruct &o2) const {
587 switch (mKey) {
588 case C2Config::ORDINAL: return o1.frameIndex < o2.frameIndex;
589 case C2Config::TIMESTAMP: return o1.timestamp < o2.timestamp;
590 case C2Config::CUSTOM: return o1.customOrdinal < o2.customOrdinal;
591 default:
592 ALOGD("Unrecognized key; default to timestamp");
593 return o1.frameIndex < o2.frameIndex;
594 }
595}
596
Wonsik Kim469c8342019-04-11 16:46:09 -0700597// LocalBufferPool
598
Wonsik Kim41d83432020-04-27 16:40:49 -0700599constexpr size_t kInitialPoolCapacity = kMaxLinearBufferSize;
600constexpr size_t kMaxPoolCapacity = kMaxLinearBufferSize * 32;
601
602std::shared_ptr<LocalBufferPool> LocalBufferPool::Create() {
603 return std::shared_ptr<LocalBufferPool>(new LocalBufferPool(kInitialPoolCapacity));
Wonsik Kim469c8342019-04-11 16:46:09 -0700604}
605
606sp<ABuffer> LocalBufferPool::newBuffer(size_t capacity) {
607 Mutex::Autolock lock(mMutex);
608 auto it = std::find_if(
609 mPool.begin(), mPool.end(),
610 [capacity](const std::vector<uint8_t> &vec) {
611 return vec.capacity() >= capacity;
612 });
613 if (it != mPool.end()) {
614 sp<ABuffer> buffer = new VectorBuffer(std::move(*it), shared_from_this());
615 mPool.erase(it);
616 return buffer;
617 }
618 if (mUsedSize + capacity > mPoolCapacity) {
619 while (!mPool.empty()) {
620 mUsedSize -= mPool.back().capacity();
621 mPool.pop_back();
622 }
Wonsik Kim41d83432020-04-27 16:40:49 -0700623 while (mUsedSize + capacity > mPoolCapacity && mPoolCapacity * 2 <= kMaxPoolCapacity) {
624 ALOGD("Increasing local buffer pool capacity from %zu to %zu",
625 mPoolCapacity, mPoolCapacity * 2);
626 mPoolCapacity *= 2;
627 }
Wonsik Kim469c8342019-04-11 16:46:09 -0700628 if (mUsedSize + capacity > mPoolCapacity) {
629 ALOGD("mUsedSize = %zu, capacity = %zu, mPoolCapacity = %zu",
630 mUsedSize, capacity, mPoolCapacity);
631 return nullptr;
632 }
633 }
634 std::vector<uint8_t> vec(capacity);
635 mUsedSize += vec.capacity();
636 return new VectorBuffer(std::move(vec), shared_from_this());
637}
638
639LocalBufferPool::VectorBuffer::VectorBuffer(
640 std::vector<uint8_t> &&vec, const std::shared_ptr<LocalBufferPool> &pool)
641 : ABuffer(vec.data(), vec.capacity()),
642 mVec(std::move(vec)),
643 mPool(pool) {
644}
645
646LocalBufferPool::VectorBuffer::~VectorBuffer() {
647 std::shared_ptr<LocalBufferPool> pool = mPool.lock();
648 if (pool) {
649 // If pool is alive, return the vector back to the pool so that
650 // it can be recycled.
651 pool->returnVector(std::move(mVec));
652 }
653}
654
655void LocalBufferPool::returnVector(std::vector<uint8_t> &&vec) {
656 Mutex::Autolock lock(mMutex);
657 mPool.push_front(std::move(vec));
658}
659
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700660// FlexBuffersImpl
661
Wonsik Kim469c8342019-04-11 16:46:09 -0700662size_t FlexBuffersImpl::assignSlot(const sp<Codec2Buffer> &buffer) {
663 for (size_t i = 0; i < mBuffers.size(); ++i) {
664 if (mBuffers[i].clientBuffer == nullptr
665 && mBuffers[i].compBuffer.expired()) {
666 mBuffers[i].clientBuffer = buffer;
667 return i;
668 }
669 }
670 mBuffers.push_back({ buffer, std::weak_ptr<C2Buffer>() });
671 return mBuffers.size() - 1;
672}
673
Wonsik Kim469c8342019-04-11 16:46:09 -0700674bool FlexBuffersImpl::releaseSlot(
675 const sp<MediaCodecBuffer> &buffer,
676 std::shared_ptr<C2Buffer> *c2buffer,
677 bool release) {
678 sp<Codec2Buffer> clientBuffer;
679 size_t index = mBuffers.size();
680 for (size_t i = 0; i < mBuffers.size(); ++i) {
681 if (mBuffers[i].clientBuffer == buffer) {
682 clientBuffer = mBuffers[i].clientBuffer;
683 if (release) {
684 mBuffers[i].clientBuffer.clear();
685 }
686 index = i;
687 break;
688 }
689 }
690 if (clientBuffer == nullptr) {
691 ALOGV("[%s] %s: No matching buffer found", mName, __func__);
692 return false;
693 }
694 std::shared_ptr<C2Buffer> result = mBuffers[index].compBuffer.lock();
695 if (!result) {
696 result = clientBuffer->asC2Buffer();
Wonsik Kimf9b32122020-04-02 11:30:17 -0700697 clientBuffer->clearC2BufferRefs();
Wonsik Kim469c8342019-04-11 16:46:09 -0700698 mBuffers[index].compBuffer = result;
699 }
700 if (c2buffer) {
701 *c2buffer = result;
702 }
703 return true;
704}
705
706bool FlexBuffersImpl::expireComponentBuffer(const std::shared_ptr<C2Buffer> &c2buffer) {
707 for (size_t i = 0; i < mBuffers.size(); ++i) {
708 std::shared_ptr<C2Buffer> compBuffer =
709 mBuffers[i].compBuffer.lock();
710 if (!compBuffer || compBuffer != c2buffer) {
711 continue;
712 }
713 mBuffers[i].compBuffer.reset();
714 ALOGV("[%s] codec released buffer #%zu", mName, i);
715 return true;
716 }
717 ALOGV("[%s] codec released an unknown buffer", mName);
718 return false;
719}
720
721void FlexBuffersImpl::flush() {
722 ALOGV("[%s] buffers are flushed %zu", mName, mBuffers.size());
723 mBuffers.clear();
724}
725
Wonsik Kim0487b782020-10-28 11:45:50 -0700726size_t FlexBuffersImpl::numActiveSlots() const {
Wonsik Kim469c8342019-04-11 16:46:09 -0700727 return std::count_if(
728 mBuffers.begin(), mBuffers.end(),
729 [](const Entry &entry) {
Wonsik Kim0487b782020-10-28 11:45:50 -0700730 return (entry.clientBuffer != nullptr
731 || !entry.compBuffer.expired());
Wonsik Kim469c8342019-04-11 16:46:09 -0700732 });
733}
734
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700735size_t FlexBuffersImpl::numComponentBuffers() const {
736 return std::count_if(
737 mBuffers.begin(), mBuffers.end(),
738 [](const Entry &entry) {
739 return !entry.compBuffer.expired();
740 });
741}
742
Wonsik Kim469c8342019-04-11 16:46:09 -0700743// BuffersArrayImpl
744
745void BuffersArrayImpl::initialize(
746 const FlexBuffersImpl &impl,
747 size_t minSize,
748 std::function<sp<Codec2Buffer>()> allocate) {
749 mImplName = impl.mImplName + "[N]";
750 mName = mImplName.c_str();
751 for (size_t i = 0; i < impl.mBuffers.size(); ++i) {
752 sp<Codec2Buffer> clientBuffer = impl.mBuffers[i].clientBuffer;
753 bool ownedByClient = (clientBuffer != nullptr);
754 if (!ownedByClient) {
755 clientBuffer = allocate();
756 }
757 mBuffers.push_back({ clientBuffer, impl.mBuffers[i].compBuffer, ownedByClient });
758 }
759 ALOGV("[%s] converted %zu buffers to array mode of %zu", mName, mBuffers.size(), minSize);
760 for (size_t i = impl.mBuffers.size(); i < minSize; ++i) {
761 mBuffers.push_back({ allocate(), std::weak_ptr<C2Buffer>(), false });
762 }
763}
764
765status_t BuffersArrayImpl::grabBuffer(
766 size_t *index,
767 sp<Codec2Buffer> *buffer,
768 std::function<bool(const sp<Codec2Buffer> &)> match) {
769 // allBuffersDontMatch remains true if all buffers are available but
770 // match() returns false for every buffer.
771 bool allBuffersDontMatch = true;
772 for (size_t i = 0; i < mBuffers.size(); ++i) {
773 if (!mBuffers[i].ownedByClient && mBuffers[i].compBuffer.expired()) {
774 if (match(mBuffers[i].clientBuffer)) {
775 mBuffers[i].ownedByClient = true;
776 *buffer = mBuffers[i].clientBuffer;
777 (*buffer)->meta()->clear();
778 (*buffer)->setRange(0, (*buffer)->capacity());
779 *index = i;
780 return OK;
781 }
782 } else {
783 allBuffersDontMatch = false;
784 }
785 }
786 return allBuffersDontMatch ? NO_MEMORY : WOULD_BLOCK;
787}
788
789bool BuffersArrayImpl::returnBuffer(
790 const sp<MediaCodecBuffer> &buffer,
791 std::shared_ptr<C2Buffer> *c2buffer,
792 bool release) {
793 sp<Codec2Buffer> clientBuffer;
794 size_t index = mBuffers.size();
795 for (size_t i = 0; i < mBuffers.size(); ++i) {
796 if (mBuffers[i].clientBuffer == buffer) {
797 if (!mBuffers[i].ownedByClient) {
798 ALOGD("[%s] Client returned a buffer it does not own according to our record: %zu",
799 mName, i);
800 }
801 clientBuffer = mBuffers[i].clientBuffer;
802 if (release) {
803 mBuffers[i].ownedByClient = false;
804 }
805 index = i;
806 break;
807 }
808 }
809 if (clientBuffer == nullptr) {
810 ALOGV("[%s] %s: No matching buffer found", mName, __func__);
811 return false;
812 }
813 ALOGV("[%s] %s: matching buffer found (index=%zu)", mName, __func__, index);
814 std::shared_ptr<C2Buffer> result = mBuffers[index].compBuffer.lock();
815 if (!result) {
816 result = clientBuffer->asC2Buffer();
Wonsik Kimf9b32122020-04-02 11:30:17 -0700817 clientBuffer->clearC2BufferRefs();
Wonsik Kim469c8342019-04-11 16:46:09 -0700818 mBuffers[index].compBuffer = result;
819 }
820 if (c2buffer) {
821 *c2buffer = result;
822 }
823 return true;
824}
825
826bool BuffersArrayImpl::expireComponentBuffer(const std::shared_ptr<C2Buffer> &c2buffer) {
827 for (size_t i = 0; i < mBuffers.size(); ++i) {
828 std::shared_ptr<C2Buffer> compBuffer =
829 mBuffers[i].compBuffer.lock();
830 if (!compBuffer) {
831 continue;
832 }
833 if (c2buffer == compBuffer) {
834 if (mBuffers[i].ownedByClient) {
835 // This should not happen.
836 ALOGD("[%s] codec released a buffer owned by client "
837 "(index %zu)", mName, i);
838 }
839 mBuffers[i].compBuffer.reset();
840 ALOGV("[%s] codec released buffer #%zu(array mode)", mName, i);
841 return true;
842 }
843 }
844 ALOGV("[%s] codec released an unknown buffer (array mode)", mName);
845 return false;
846}
847
848void BuffersArrayImpl::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
849 array->clear();
850 for (const Entry &entry : mBuffers) {
851 array->push(entry.clientBuffer);
852 }
853}
854
855void BuffersArrayImpl::flush() {
856 for (Entry &entry : mBuffers) {
857 entry.ownedByClient = false;
858 }
859}
860
861void BuffersArrayImpl::realloc(std::function<sp<Codec2Buffer>()> alloc) {
862 size_t size = mBuffers.size();
863 mBuffers.clear();
864 for (size_t i = 0; i < size; ++i) {
865 mBuffers.push_back({ alloc(), std::weak_ptr<C2Buffer>(), false });
866 }
867}
868
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700869void BuffersArrayImpl::grow(
870 size_t newSize, std::function<sp<Codec2Buffer>()> alloc) {
871 CHECK_LT(mBuffers.size(), newSize);
872 while (mBuffers.size() < newSize) {
873 mBuffers.push_back({ alloc(), std::weak_ptr<C2Buffer>(), false });
874 }
875}
876
Wonsik Kim0487b782020-10-28 11:45:50 -0700877size_t BuffersArrayImpl::numActiveSlots() const {
Wonsik Kim469c8342019-04-11 16:46:09 -0700878 return std::count_if(
879 mBuffers.begin(), mBuffers.end(),
880 [](const Entry &entry) {
Wonsik Kim0487b782020-10-28 11:45:50 -0700881 return entry.ownedByClient || !entry.compBuffer.expired();
Wonsik Kim469c8342019-04-11 16:46:09 -0700882 });
883}
884
Wonsik Kima39882b2019-06-20 16:13:56 -0700885size_t BuffersArrayImpl::arraySize() const {
886 return mBuffers.size();
887}
888
Wonsik Kim469c8342019-04-11 16:46:09 -0700889// InputBuffersArray
890
891void InputBuffersArray::initialize(
892 const FlexBuffersImpl &impl,
893 size_t minSize,
894 std::function<sp<Codec2Buffer>()> allocate) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700895 mAllocate = allocate;
Wonsik Kim469c8342019-04-11 16:46:09 -0700896 mImpl.initialize(impl, minSize, allocate);
897}
898
899void InputBuffersArray::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
900 mImpl.getArray(array);
901}
902
903bool InputBuffersArray::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
904 sp<Codec2Buffer> c2Buffer;
905 status_t err = mImpl.grabBuffer(index, &c2Buffer);
906 if (err == OK) {
907 c2Buffer->setFormat(mFormat);
908 handleImageData(c2Buffer);
909 *buffer = c2Buffer;
910 return true;
911 }
912 return false;
913}
914
915bool InputBuffersArray::releaseBuffer(
916 const sp<MediaCodecBuffer> &buffer,
917 std::shared_ptr<C2Buffer> *c2buffer,
918 bool release) {
919 return mImpl.returnBuffer(buffer, c2buffer, release);
920}
921
922bool InputBuffersArray::expireComponentBuffer(
923 const std::shared_ptr<C2Buffer> &c2buffer) {
924 return mImpl.expireComponentBuffer(c2buffer);
925}
926
927void InputBuffersArray::flush() {
928 mImpl.flush();
929}
930
Wonsik Kim0487b782020-10-28 11:45:50 -0700931size_t InputBuffersArray::numActiveSlots() const {
932 return mImpl.numActiveSlots();
Wonsik Kim469c8342019-04-11 16:46:09 -0700933}
934
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700935sp<Codec2Buffer> InputBuffersArray::createNewBuffer() {
936 return mAllocate();
937}
938
Wonsik Kimfb7a7672019-12-27 17:13:33 -0800939// SlotInputBuffers
940
941bool SlotInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
942 sp<Codec2Buffer> newBuffer = createNewBuffer();
943 *index = mImpl.assignSlot(newBuffer);
944 *buffer = newBuffer;
945 return true;
946}
947
948bool SlotInputBuffers::releaseBuffer(
949 const sp<MediaCodecBuffer> &buffer,
950 std::shared_ptr<C2Buffer> *c2buffer,
951 bool release) {
952 return mImpl.releaseSlot(buffer, c2buffer, release);
953}
954
955bool SlotInputBuffers::expireComponentBuffer(
956 const std::shared_ptr<C2Buffer> &c2buffer) {
957 return mImpl.expireComponentBuffer(c2buffer);
958}
959
960void SlotInputBuffers::flush() {
961 mImpl.flush();
962}
963
964std::unique_ptr<InputBuffers> SlotInputBuffers::toArrayMode(size_t) {
965 TRESPASS("Array mode should not be called at non-legacy mode");
966 return nullptr;
967}
968
Wonsik Kim0487b782020-10-28 11:45:50 -0700969size_t SlotInputBuffers::numActiveSlots() const {
970 return mImpl.numActiveSlots();
Wonsik Kimfb7a7672019-12-27 17:13:33 -0800971}
972
973sp<Codec2Buffer> SlotInputBuffers::createNewBuffer() {
974 return new DummyContainerBuffer{mFormat, nullptr};
975}
976
Wonsik Kim469c8342019-04-11 16:46:09 -0700977// LinearInputBuffers
978
979bool LinearInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700980 sp<Codec2Buffer> newBuffer = createNewBuffer();
Wonsik Kim469c8342019-04-11 16:46:09 -0700981 if (newBuffer == nullptr) {
982 return false;
983 }
984 *index = mImpl.assignSlot(newBuffer);
985 *buffer = newBuffer;
986 return true;
987}
988
989bool LinearInputBuffers::releaseBuffer(
990 const sp<MediaCodecBuffer> &buffer,
991 std::shared_ptr<C2Buffer> *c2buffer,
992 bool release) {
993 return mImpl.releaseSlot(buffer, c2buffer, release);
994}
995
996bool LinearInputBuffers::expireComponentBuffer(
997 const std::shared_ptr<C2Buffer> &c2buffer) {
998 return mImpl.expireComponentBuffer(c2buffer);
999}
1000
1001void LinearInputBuffers::flush() {
1002 // This is no-op by default unless we're in array mode where we need to keep
1003 // track of the flushed work.
1004 mImpl.flush();
1005}
1006
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001007std::unique_ptr<InputBuffers> LinearInputBuffers::toArrayMode(size_t size) {
Wonsik Kim469c8342019-04-11 16:46:09 -07001008 std::unique_ptr<InputBuffersArray> array(
1009 new InputBuffersArray(mComponentName.c_str(), "1D-Input[N]"));
1010 array->setPool(mPool);
1011 array->setFormat(mFormat);
1012 array->initialize(
1013 mImpl,
1014 size,
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001015 [pool = mPool, format = mFormat] () -> sp<Codec2Buffer> {
1016 return Alloc(pool, format);
1017 });
Wonsik Kim469c8342019-04-11 16:46:09 -07001018 return std::move(array);
1019}
1020
Wonsik Kim0487b782020-10-28 11:45:50 -07001021size_t LinearInputBuffers::numActiveSlots() const {
1022 return mImpl.numActiveSlots();
Wonsik Kim469c8342019-04-11 16:46:09 -07001023}
1024
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001025// static
1026sp<Codec2Buffer> LinearInputBuffers::Alloc(
1027 const std::shared_ptr<C2BlockPool> &pool, const sp<AMessage> &format) {
1028 int32_t capacity = kLinearBufferSize;
1029 (void)format->findInt32(KEY_MAX_INPUT_SIZE, &capacity);
1030 if ((size_t)capacity > kMaxLinearBufferSize) {
1031 ALOGD("client requested %d, capped to %zu", capacity, kMaxLinearBufferSize);
1032 capacity = kMaxLinearBufferSize;
1033 }
1034
Wonsik Kim666604a2020-05-14 16:57:49 -07001035 int64_t usageValue = 0;
1036 (void)format->findInt64("android._C2MemoryUsage", &usageValue);
1037 C2MemoryUsage usage{usageValue | C2MemoryUsage::CPU_READ | C2MemoryUsage::CPU_WRITE};
Wonsik Kim469c8342019-04-11 16:46:09 -07001038 std::shared_ptr<C2LinearBlock> block;
1039
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001040 c2_status_t err = pool->fetchLinearBlock(capacity, usage, &block);
Wonsik Kim469c8342019-04-11 16:46:09 -07001041 if (err != C2_OK) {
1042 return nullptr;
1043 }
1044
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001045 return LinearBlockBuffer::Allocate(format, block);
1046}
1047
1048sp<Codec2Buffer> LinearInputBuffers::createNewBuffer() {
1049 return Alloc(mPool, mFormat);
Wonsik Kim469c8342019-04-11 16:46:09 -07001050}
1051
1052// EncryptedLinearInputBuffers
1053
1054EncryptedLinearInputBuffers::EncryptedLinearInputBuffers(
1055 bool secure,
1056 const sp<MemoryDealer> &dealer,
1057 const sp<ICrypto> &crypto,
1058 int32_t heapSeqNum,
1059 size_t capacity,
1060 size_t numInputSlots,
1061 const char *componentName, const char *name)
1062 : LinearInputBuffers(componentName, name),
1063 mUsage({0, 0}),
1064 mDealer(dealer),
1065 mCrypto(crypto),
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001066 mMemoryVector(new std::vector<Entry>){
Wonsik Kim469c8342019-04-11 16:46:09 -07001067 if (secure) {
1068 mUsage = { C2MemoryUsage::READ_PROTECTED, 0 };
1069 } else {
1070 mUsage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
1071 }
1072 for (size_t i = 0; i < numInputSlots; ++i) {
1073 sp<IMemory> memory = mDealer->allocate(capacity);
1074 if (memory == nullptr) {
1075 ALOGD("[%s] Failed to allocate memory from dealer: only %zu slots allocated",
1076 mName, i);
1077 break;
1078 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001079 mMemoryVector->push_back({std::weak_ptr<C2LinearBlock>(), memory, heapSeqNum});
Wonsik Kim469c8342019-04-11 16:46:09 -07001080 }
1081}
1082
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001083std::unique_ptr<InputBuffers> EncryptedLinearInputBuffers::toArrayMode(size_t size) {
1084 std::unique_ptr<InputBuffersArray> array(
1085 new InputBuffersArray(mComponentName.c_str(), "1D-EncryptedInput[N]"));
1086 array->setPool(mPool);
1087 array->setFormat(mFormat);
1088 array->initialize(
1089 mImpl,
1090 size,
1091 [pool = mPool,
1092 format = mFormat,
1093 usage = mUsage,
1094 memoryVector = mMemoryVector] () -> sp<Codec2Buffer> {
1095 return Alloc(pool, format, usage, memoryVector);
1096 });
1097 return std::move(array);
1098}
1099
1100
1101// static
1102sp<Codec2Buffer> EncryptedLinearInputBuffers::Alloc(
1103 const std::shared_ptr<C2BlockPool> &pool,
1104 const sp<AMessage> &format,
1105 C2MemoryUsage usage,
1106 const std::shared_ptr<std::vector<EncryptedLinearInputBuffers::Entry>> &memoryVector) {
1107 int32_t capacity = kLinearBufferSize;
1108 (void)format->findInt32(KEY_MAX_INPUT_SIZE, &capacity);
1109 if ((size_t)capacity > kMaxLinearBufferSize) {
1110 ALOGD("client requested %d, capped to %zu", capacity, kMaxLinearBufferSize);
1111 capacity = kMaxLinearBufferSize;
1112 }
1113
Wonsik Kim469c8342019-04-11 16:46:09 -07001114 sp<IMemory> memory;
1115 size_t slot = 0;
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001116 int32_t heapSeqNum = -1;
1117 for (; slot < memoryVector->size(); ++slot) {
1118 if (memoryVector->at(slot).block.expired()) {
1119 memory = memoryVector->at(slot).memory;
1120 heapSeqNum = memoryVector->at(slot).heapSeqNum;
Wonsik Kim469c8342019-04-11 16:46:09 -07001121 break;
1122 }
1123 }
1124 if (memory == nullptr) {
1125 return nullptr;
1126 }
1127
David Stevens94b608f2021-07-29 15:04:14 +09001128 int64_t usageValue = 0;
1129 (void)format->findInt64("android._C2MemoryUsage", &usageValue);
1130 usage = C2MemoryUsage(usage.expected | usageValue);
1131
Wonsik Kim469c8342019-04-11 16:46:09 -07001132 std::shared_ptr<C2LinearBlock> block;
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001133 c2_status_t err = pool->fetchLinearBlock(capacity, usage, &block);
Wonsik Kim469c8342019-04-11 16:46:09 -07001134 if (err != C2_OK || block == nullptr) {
1135 return nullptr;
1136 }
1137
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001138 memoryVector->at(slot).block = block;
1139 return new EncryptedLinearBlockBuffer(format, block, memory, heapSeqNum);
1140}
1141
1142sp<Codec2Buffer> EncryptedLinearInputBuffers::createNewBuffer() {
1143 // TODO: android_2020
1144 return nullptr;
Wonsik Kim469c8342019-04-11 16:46:09 -07001145}
1146
1147// GraphicMetadataInputBuffers
1148
1149GraphicMetadataInputBuffers::GraphicMetadataInputBuffers(
1150 const char *componentName, const char *name)
1151 : InputBuffers(componentName, name),
1152 mImpl(mName),
1153 mStore(GetCodec2PlatformAllocatorStore()) { }
1154
1155bool GraphicMetadataInputBuffers::requestNewBuffer(
1156 size_t *index, sp<MediaCodecBuffer> *buffer) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001157 sp<Codec2Buffer> newBuffer = createNewBuffer();
Wonsik Kim469c8342019-04-11 16:46:09 -07001158 if (newBuffer == nullptr) {
1159 return false;
1160 }
1161 *index = mImpl.assignSlot(newBuffer);
1162 *buffer = newBuffer;
1163 return true;
1164}
1165
1166bool GraphicMetadataInputBuffers::releaseBuffer(
1167 const sp<MediaCodecBuffer> &buffer,
1168 std::shared_ptr<C2Buffer> *c2buffer,
1169 bool release) {
1170 return mImpl.releaseSlot(buffer, c2buffer, release);
1171}
1172
1173bool GraphicMetadataInputBuffers::expireComponentBuffer(
1174 const std::shared_ptr<C2Buffer> &c2buffer) {
1175 return mImpl.expireComponentBuffer(c2buffer);
1176}
1177
1178void GraphicMetadataInputBuffers::flush() {
1179 // This is no-op by default unless we're in array mode where we need to keep
1180 // track of the flushed work.
1181}
1182
1183std::unique_ptr<InputBuffers> GraphicMetadataInputBuffers::toArrayMode(
1184 size_t size) {
1185 std::shared_ptr<C2Allocator> alloc;
1186 c2_status_t err = mStore->fetchAllocator(mPool->getAllocatorId(), &alloc);
1187 if (err != C2_OK) {
1188 return nullptr;
1189 }
1190 std::unique_ptr<InputBuffersArray> array(
1191 new InputBuffersArray(mComponentName.c_str(), "2D-MetaInput[N]"));
1192 array->setPool(mPool);
1193 array->setFormat(mFormat);
1194 array->initialize(
1195 mImpl,
1196 size,
1197 [format = mFormat, alloc]() -> sp<Codec2Buffer> {
1198 return new GraphicMetadataBuffer(format, alloc);
1199 });
1200 return std::move(array);
1201}
1202
Wonsik Kim0487b782020-10-28 11:45:50 -07001203size_t GraphicMetadataInputBuffers::numActiveSlots() const {
1204 return mImpl.numActiveSlots();
Wonsik Kim469c8342019-04-11 16:46:09 -07001205}
1206
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001207sp<Codec2Buffer> GraphicMetadataInputBuffers::createNewBuffer() {
1208 std::shared_ptr<C2Allocator> alloc;
1209 c2_status_t err = mStore->fetchAllocator(mPool->getAllocatorId(), &alloc);
1210 if (err != C2_OK) {
1211 return nullptr;
1212 }
1213 return new GraphicMetadataBuffer(mFormat, alloc);
1214}
1215
Wonsik Kim469c8342019-04-11 16:46:09 -07001216// GraphicInputBuffers
1217
1218GraphicInputBuffers::GraphicInputBuffers(
Wonsik Kim41d83432020-04-27 16:40:49 -07001219 const char *componentName, const char *name)
Wonsik Kim469c8342019-04-11 16:46:09 -07001220 : InputBuffers(componentName, name),
1221 mImpl(mName),
Songyue Han1e6769b2023-08-30 18:09:27 +00001222 mLocalBufferPool(LocalBufferPool::Create()),
1223 mPixelFormat(PIXEL_FORMAT_UNKNOWN) { }
Wonsik Kim469c8342019-04-11 16:46:09 -07001224
1225bool GraphicInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001226 sp<Codec2Buffer> newBuffer = createNewBuffer();
Wonsik Kim469c8342019-04-11 16:46:09 -07001227 if (newBuffer == nullptr) {
1228 return false;
1229 }
1230 *index = mImpl.assignSlot(newBuffer);
1231 handleImageData(newBuffer);
1232 *buffer = newBuffer;
1233 return true;
1234}
1235
1236bool GraphicInputBuffers::releaseBuffer(
1237 const sp<MediaCodecBuffer> &buffer,
1238 std::shared_ptr<C2Buffer> *c2buffer,
1239 bool release) {
1240 return mImpl.releaseSlot(buffer, c2buffer, release);
1241}
1242
1243bool GraphicInputBuffers::expireComponentBuffer(
1244 const std::shared_ptr<C2Buffer> &c2buffer) {
1245 return mImpl.expireComponentBuffer(c2buffer);
1246}
1247
1248void GraphicInputBuffers::flush() {
1249 // This is no-op by default unless we're in array mode where we need to keep
1250 // track of the flushed work.
1251}
1252
Wonsik Kimd79ee1f2020-08-27 17:41:56 -07001253static uint32_t extractPixelFormat(const sp<AMessage> &format) {
1254 int32_t frameworkColorFormat = 0;
1255 if (!format->findInt32("android._color-format", &frameworkColorFormat)) {
1256 return PIXEL_FORMAT_UNKNOWN;
1257 }
1258 uint32_t pixelFormat = PIXEL_FORMAT_UNKNOWN;
1259 if (C2Mapper::mapPixelFormatFrameworkToCodec(frameworkColorFormat, &pixelFormat)) {
1260 return pixelFormat;
1261 }
1262 return PIXEL_FORMAT_UNKNOWN;
1263}
1264
Wonsik Kim469c8342019-04-11 16:46:09 -07001265std::unique_ptr<InputBuffers> GraphicInputBuffers::toArrayMode(size_t size) {
1266 std::unique_ptr<InputBuffersArray> array(
1267 new InputBuffersArray(mComponentName.c_str(), "2D-BB-Input[N]"));
1268 array->setPool(mPool);
1269 array->setFormat(mFormat);
Wonsik Kimd79ee1f2020-08-27 17:41:56 -07001270 uint32_t pixelFormat = extractPixelFormat(mFormat);
Wonsik Kim469c8342019-04-11 16:46:09 -07001271 array->initialize(
1272 mImpl,
1273 size,
Wonsik Kimd79ee1f2020-08-27 17:41:56 -07001274 [pool = mPool, format = mFormat, lbp = mLocalBufferPool, pixelFormat]()
1275 -> sp<Codec2Buffer> {
Wonsik Kim469c8342019-04-11 16:46:09 -07001276 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
David Stevens94b608f2021-07-29 15:04:14 +09001277 return AllocateInputGraphicBuffer(
Wonsik Kimd79ee1f2020-08-27 17:41:56 -07001278 pool, format, pixelFormat, usage, lbp);
Wonsik Kim469c8342019-04-11 16:46:09 -07001279 });
1280 return std::move(array);
1281}
1282
Wonsik Kim0487b782020-10-28 11:45:50 -07001283size_t GraphicInputBuffers::numActiveSlots() const {
1284 return mImpl.numActiveSlots();
Wonsik Kim469c8342019-04-11 16:46:09 -07001285}
1286
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001287sp<Codec2Buffer> GraphicInputBuffers::createNewBuffer() {
David Stevens94b608f2021-07-29 15:04:14 +09001288 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
Songyue Han1e6769b2023-08-30 18:09:27 +00001289 mPixelFormat = extractPixelFormat(mFormat);
David Stevens94b608f2021-07-29 15:04:14 +09001290 return AllocateInputGraphicBuffer(
Songyue Han1e6769b2023-08-30 18:09:27 +00001291 mPool, mFormat, mPixelFormat, usage, mLocalBufferPool);
1292}
1293
1294uint32_t GraphicInputBuffers::getPixelFormatIfApplicable() { return mPixelFormat; }
1295
1296bool GraphicInputBuffers::resetPixelFormatIfApplicable() {
1297 mPixelFormat = PIXEL_FORMAT_UNKNOWN;
1298 return true;
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001299}
1300
Wonsik Kim469c8342019-04-11 16:46:09 -07001301// OutputBuffersArray
1302
1303void OutputBuffersArray::initialize(
1304 const FlexBuffersImpl &impl,
1305 size_t minSize,
1306 std::function<sp<Codec2Buffer>()> allocate) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001307 mAlloc = allocate;
Wonsik Kim469c8342019-04-11 16:46:09 -07001308 mImpl.initialize(impl, minSize, allocate);
1309}
1310
1311status_t OutputBuffersArray::registerBuffer(
1312 const std::shared_ptr<C2Buffer> &buffer,
1313 size_t *index,
1314 sp<MediaCodecBuffer> *clientBuffer) {
1315 sp<Codec2Buffer> c2Buffer;
1316 status_t err = mImpl.grabBuffer(
1317 index,
1318 &c2Buffer,
1319 [buffer](const sp<Codec2Buffer> &clientBuffer) {
1320 return clientBuffer->canCopy(buffer);
1321 });
1322 if (err == WOULD_BLOCK) {
1323 ALOGV("[%s] buffers temporarily not available", mName);
1324 return err;
1325 } else if (err != OK) {
1326 ALOGD("[%s] grabBuffer failed: %d", mName, err);
1327 return err;
1328 }
1329 c2Buffer->setFormat(mFormat);
Wonsik Kim6f23cfc2021-09-24 05:45:52 -07001330 if (!convert(buffer, &c2Buffer) && !c2Buffer->copy(buffer)) {
Wonsik Kim469c8342019-04-11 16:46:09 -07001331 ALOGD("[%s] copy buffer failed", mName);
1332 return WOULD_BLOCK;
1333 }
Arun Johnsonf4a81f72023-11-09 21:22:48 +00001334 if (buffer && buffer->hasInfo(C2AccessUnitInfos::output::PARAM_TYPE)) {
1335 std::shared_ptr<const C2AccessUnitInfos::output> bufferMetadata =
1336 std::static_pointer_cast<const C2AccessUnitInfos::output>(
1337 buffer->getInfo(C2AccessUnitInfos::output::PARAM_TYPE));
1338 if (submit(c2Buffer, mSampleRate, mChannelCount, bufferMetadata)) {
1339 buffer->removeInfo(C2AccessUnitInfos::output::PARAM_TYPE);
1340 }
1341 } else {
1342 submit(c2Buffer);
1343 }
Wonsik Kim469c8342019-04-11 16:46:09 -07001344 handleImageData(c2Buffer);
1345 *clientBuffer = c2Buffer;
1346 ALOGV("[%s] grabbed buffer %zu", mName, *index);
1347 return OK;
1348}
1349
1350status_t OutputBuffersArray::registerCsd(
1351 const C2StreamInitDataInfo::output *csd,
1352 size_t *index,
1353 sp<MediaCodecBuffer> *clientBuffer) {
1354 sp<Codec2Buffer> c2Buffer;
1355 status_t err = mImpl.grabBuffer(
1356 index,
1357 &c2Buffer,
1358 [csd](const sp<Codec2Buffer> &clientBuffer) {
1359 return clientBuffer->base() != nullptr
1360 && clientBuffer->capacity() >= csd->flexCount();
1361 });
1362 if (err != OK) {
1363 return err;
1364 }
1365 memcpy(c2Buffer->base(), csd->m.value, csd->flexCount());
1366 c2Buffer->setRange(0, csd->flexCount());
1367 c2Buffer->setFormat(mFormat);
1368 *clientBuffer = c2Buffer;
1369 return OK;
1370}
1371
1372bool OutputBuffersArray::releaseBuffer(
1373 const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) {
1374 return mImpl.returnBuffer(buffer, c2buffer, true);
1375}
1376
1377void OutputBuffersArray::flush(const std::list<std::unique_ptr<C2Work>> &flushedWork) {
1378 (void)flushedWork;
1379 mImpl.flush();
1380 if (mSkipCutBuffer != nullptr) {
1381 mSkipCutBuffer->clear();
1382 }
1383}
1384
1385void OutputBuffersArray::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
1386 mImpl.getArray(array);
1387}
1388
Wonsik Kim0487b782020-10-28 11:45:50 -07001389size_t OutputBuffersArray::numActiveSlots() const {
1390 return mImpl.numActiveSlots();
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001391}
1392
Wonsik Kim469c8342019-04-11 16:46:09 -07001393void OutputBuffersArray::realloc(const std::shared_ptr<C2Buffer> &c2buffer) {
Wonsik Kim469c8342019-04-11 16:46:09 -07001394 switch (c2buffer->data().type()) {
1395 case C2BufferData::LINEAR: {
1396 uint32_t size = kLinearBufferSize;
Nick Desaulniersd09eaea2019-10-07 20:19:39 -07001397 const std::vector<C2ConstLinearBlock> &linear_blocks = c2buffer->data().linearBlocks();
1398 const uint32_t block_size = linear_blocks.front().size();
1399 if (block_size < kMaxLinearBufferSize / 2) {
1400 size = block_size * 2;
Wonsik Kim469c8342019-04-11 16:46:09 -07001401 } else {
1402 size = kMaxLinearBufferSize;
1403 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001404 mAlloc = [format = mFormat, size] {
Wonsik Kim469c8342019-04-11 16:46:09 -07001405 return new LocalLinearBuffer(format, new ABuffer(size));
1406 };
Wonsik Kima39882b2019-06-20 16:13:56 -07001407 ALOGD("[%s] reallocating with linear buffer of size %u", mName, size);
Wonsik Kim469c8342019-04-11 16:46:09 -07001408 break;
1409 }
1410
Wonsik Kima39882b2019-06-20 16:13:56 -07001411 case C2BufferData::GRAPHIC: {
1412 // This is only called for RawGraphicOutputBuffers.
1413 mAlloc = [format = mFormat,
Wonsik Kim41d83432020-04-27 16:40:49 -07001414 lbp = LocalBufferPool::Create()] {
Wonsik Kima39882b2019-06-20 16:13:56 -07001415 return ConstGraphicBlockBuffer::AllocateEmpty(
1416 format,
1417 [lbp](size_t capacity) {
1418 return lbp->newBuffer(capacity);
1419 });
1420 };
1421 ALOGD("[%s] reallocating with graphic buffer: format = %s",
1422 mName, mFormat->debugString().c_str());
1423 break;
1424 }
Wonsik Kim469c8342019-04-11 16:46:09 -07001425
1426 case C2BufferData::INVALID: [[fallthrough]];
1427 case C2BufferData::LINEAR_CHUNKS: [[fallthrough]];
1428 case C2BufferData::GRAPHIC_CHUNKS: [[fallthrough]];
1429 default:
1430 ALOGD("Unsupported type: %d", (int)c2buffer->data().type());
1431 return;
1432 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001433 mImpl.realloc(mAlloc);
Wonsik Kim469c8342019-04-11 16:46:09 -07001434}
1435
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001436void OutputBuffersArray::grow(size_t newSize) {
1437 mImpl.grow(newSize, mAlloc);
Wonsik Kim469c8342019-04-11 16:46:09 -07001438}
1439
Pawin Vongmasa9b906982020-04-11 05:07:15 -07001440void OutputBuffersArray::transferFrom(OutputBuffers* source) {
1441 mFormat = source->mFormat;
1442 mSkipCutBuffer = source->mSkipCutBuffer;
Pawin Vongmasa9b906982020-04-11 05:07:15 -07001443 mPending = std::move(source->mPending);
1444 mReorderStash = std::move(source->mReorderStash);
1445 mDepth = source->mDepth;
1446 mKey = source->mKey;
1447}
1448
Wonsik Kim469c8342019-04-11 16:46:09 -07001449// FlexOutputBuffers
1450
1451status_t FlexOutputBuffers::registerBuffer(
1452 const std::shared_ptr<C2Buffer> &buffer,
1453 size_t *index,
1454 sp<MediaCodecBuffer> *clientBuffer) {
Wonsik Kim6f23cfc2021-09-24 05:45:52 -07001455 sp<Codec2Buffer> newBuffer;
1456 if (!convert(buffer, &newBuffer)) {
1457 newBuffer = wrap(buffer);
1458 if (newBuffer == nullptr) {
1459 return NO_MEMORY;
1460 }
Wonsik Kim360ba0a2022-05-23 15:38:21 -07001461 newBuffer->setFormat(mFormat);
Wonsik Kim469c8342019-04-11 16:46:09 -07001462 }
Wonsik Kim469c8342019-04-11 16:46:09 -07001463 *index = mImpl.assignSlot(newBuffer);
1464 handleImageData(newBuffer);
1465 *clientBuffer = newBuffer;
Songyue Han1e6769b2023-08-30 18:09:27 +00001466
1467 extractPixelFormatFromC2Buffer(buffer);
Wonsik Kim469c8342019-04-11 16:46:09 -07001468 ALOGV("[%s] registered buffer %zu", mName, *index);
1469 return OK;
1470}
1471
1472status_t FlexOutputBuffers::registerCsd(
1473 const C2StreamInitDataInfo::output *csd,
1474 size_t *index,
1475 sp<MediaCodecBuffer> *clientBuffer) {
1476 sp<Codec2Buffer> newBuffer = new LocalLinearBuffer(
1477 mFormat, ABuffer::CreateAsCopy(csd->m.value, csd->flexCount()));
1478 *index = mImpl.assignSlot(newBuffer);
1479 *clientBuffer = newBuffer;
1480 return OK;
1481}
1482
1483bool FlexOutputBuffers::releaseBuffer(
1484 const sp<MediaCodecBuffer> &buffer,
1485 std::shared_ptr<C2Buffer> *c2buffer) {
1486 return mImpl.releaseSlot(buffer, c2buffer, true);
1487}
1488
1489void FlexOutputBuffers::flush(
1490 const std::list<std::unique_ptr<C2Work>> &flushedWork) {
1491 (void) flushedWork;
1492 // This is no-op by default unless we're in array mode where we need to keep
1493 // track of the flushed work.
1494}
1495
Pawin Vongmasa9b906982020-04-11 05:07:15 -07001496std::unique_ptr<OutputBuffersArray> FlexOutputBuffers::toArrayMode(size_t size) {
Wonsik Kim469c8342019-04-11 16:46:09 -07001497 std::unique_ptr<OutputBuffersArray> array(new OutputBuffersArray(mComponentName.c_str()));
Pawin Vongmasa9b906982020-04-11 05:07:15 -07001498 array->transferFrom(this);
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001499 std::function<sp<Codec2Buffer>()> alloc = getAlloc();
1500 array->initialize(mImpl, size, alloc);
Pawin Vongmasa9b906982020-04-11 05:07:15 -07001501 return array;
Wonsik Kim469c8342019-04-11 16:46:09 -07001502}
1503
Wonsik Kim0487b782020-10-28 11:45:50 -07001504size_t FlexOutputBuffers::numActiveSlots() const {
1505 return mImpl.numActiveSlots();
Wonsik Kim469c8342019-04-11 16:46:09 -07001506}
1507
Songyue Han1e6769b2023-08-30 18:09:27 +00001508bool FlexOutputBuffers::extractPixelFormatFromC2Buffer(const std::shared_ptr<C2Buffer> &buffer) {
1509 if (buffer == nullptr) {
1510 return false;
1511 }
1512 const C2BufferData &data = buffer->data();
1513 // only extract the first pixel format in a metric session.
1514 if (mPixelFormat != PIXEL_FORMAT_UNKNOWN || data.type() != C2BufferData::GRAPHIC
1515 || data.graphicBlocks().empty()) {
1516 return false;
1517 }
1518 const C2Handle *const handle = data.graphicBlocks().front().handle();
1519 uint32_t pf = ExtractFormatFromCodec2GrallocHandle(handle);
1520 if (pf == PIXEL_FORMAT_UNKNOWN) {
1521 return false;
1522 }
1523 mPixelFormat = pf;
1524 return true;
1525}
1526
1527bool FlexOutputBuffers::resetPixelFormatIfApplicable() {
1528 mPixelFormat = PIXEL_FORMAT_UNKNOWN;
1529 return true;
1530}
1531
1532uint32_t FlexOutputBuffers::getPixelFormatIfApplicable() { return mPixelFormat; }
1533
Wonsik Kim469c8342019-04-11 16:46:09 -07001534// LinearOutputBuffers
1535
1536void LinearOutputBuffers::flush(
1537 const std::list<std::unique_ptr<C2Work>> &flushedWork) {
1538 if (mSkipCutBuffer != nullptr) {
1539 mSkipCutBuffer->clear();
1540 }
1541 FlexOutputBuffers::flush(flushedWork);
1542}
1543
1544sp<Codec2Buffer> LinearOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
1545 if (buffer == nullptr) {
1546 ALOGV("[%s] using a dummy buffer", mName);
1547 return new LocalLinearBuffer(mFormat, new ABuffer(0));
1548 }
1549 if (buffer->data().type() != C2BufferData::LINEAR) {
1550 ALOGV("[%s] non-linear buffer %d", mName, buffer->data().type());
1551 // We expect linear output buffers from the component.
1552 return nullptr;
1553 }
1554 if (buffer->data().linearBlocks().size() != 1u) {
1555 ALOGV("[%s] no linear buffers", mName);
1556 // We expect one and only one linear block from the component.
1557 return nullptr;
1558 }
1559 sp<Codec2Buffer> clientBuffer = ConstLinearBlockBuffer::Allocate(mFormat, buffer);
1560 if (clientBuffer == nullptr) {
1561 ALOGD("[%s] ConstLinearBlockBuffer::Allocate failed", mName);
1562 return nullptr;
1563 }
1564 submit(clientBuffer);
1565 return clientBuffer;
1566}
1567
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001568std::function<sp<Codec2Buffer>()> LinearOutputBuffers::getAlloc() {
1569 return [format = mFormat]{
1570 // TODO: proper max output size
1571 return new LocalLinearBuffer(format, new ABuffer(kLinearBufferSize));
1572 };
Wonsik Kim469c8342019-04-11 16:46:09 -07001573}
1574
1575// GraphicOutputBuffers
1576
1577sp<Codec2Buffer> GraphicOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
1578 return new DummyContainerBuffer(mFormat, buffer);
1579}
1580
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001581std::function<sp<Codec2Buffer>()> GraphicOutputBuffers::getAlloc() {
1582 return [format = mFormat]{
1583 return new DummyContainerBuffer(format);
1584 };
Wonsik Kim469c8342019-04-11 16:46:09 -07001585}
1586
1587// RawGraphicOutputBuffers
1588
1589RawGraphicOutputBuffers::RawGraphicOutputBuffers(
Wonsik Kim41d83432020-04-27 16:40:49 -07001590 const char *componentName, const char *name)
Wonsik Kim469c8342019-04-11 16:46:09 -07001591 : FlexOutputBuffers(componentName, name),
Wonsik Kim41d83432020-04-27 16:40:49 -07001592 mLocalBufferPool(LocalBufferPool::Create()) { }
Wonsik Kim469c8342019-04-11 16:46:09 -07001593
1594sp<Codec2Buffer> RawGraphicOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
1595 if (buffer == nullptr) {
Wonsik Kim6f116902021-07-14 08:58:07 -07001596 return new Codec2Buffer(mFormat, new ABuffer(nullptr, 0));
Wonsik Kim469c8342019-04-11 16:46:09 -07001597 } else {
1598 return ConstGraphicBlockBuffer::Allocate(
1599 mFormat,
1600 buffer,
1601 [lbp = mLocalBufferPool](size_t capacity) {
1602 return lbp->newBuffer(capacity);
1603 });
1604 }
1605}
1606
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001607std::function<sp<Codec2Buffer>()> RawGraphicOutputBuffers::getAlloc() {
1608 return [format = mFormat, lbp = mLocalBufferPool]{
1609 return ConstGraphicBlockBuffer::AllocateEmpty(
1610 format,
1611 [lbp](size_t capacity) {
1612 return lbp->newBuffer(capacity);
1613 });
1614 };
Wonsik Kim469c8342019-04-11 16:46:09 -07001615}
1616
1617} // namespace android