blob: 3eec0f3fb734af693850a628fb4d41ea177932d7 [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>
Harish Mahendrakarf6b3e5e2024-03-21 21:04:28 +000027#include <media/stagefright/foundation/AUtils.h>
Wonsik Kim6f23cfc2021-09-24 05:45:52 -070028#include <media/stagefright/foundation/MediaDefs.h>
Arun Johnsonf4a81f72023-11-09 21:22:48 +000029#include <media/stagefright/CodecBase.h>
Wonsik Kim469c8342019-04-11 16:46:09 -070030#include <media/stagefright/MediaCodecConstants.h>
Wonsik Kim155d5cb2019-10-09 12:49:49 -070031#include <media/stagefright/SkipCutBuffer.h>
Wonsik Kim41d83432020-04-27 16:40:49 -070032#include <mediadrm/ICrypto.h>
Wonsik Kim469c8342019-04-11 16:46:09 -070033
34#include "CCodecBuffers.h"
Wonsik Kimd79ee1f2020-08-27 17:41:56 -070035#include "Codec2Mapper.h"
Wonsik Kim469c8342019-04-11 16:46:09 -070036
37namespace android {
38
39namespace {
40
My Nameac29e592022-03-28 13:53:32 -070041constexpr uint32_t PIXEL_FORMAT_UNKNOWN = 0;
42
David Stevens94b608f2021-07-29 15:04:14 +090043sp<GraphicBlockBuffer> AllocateInputGraphicBuffer(
Wonsik Kim469c8342019-04-11 16:46:09 -070044 const std::shared_ptr<C2BlockPool> &pool,
45 const sp<AMessage> &format,
46 uint32_t pixelFormat,
47 const C2MemoryUsage &usage,
48 const std::shared_ptr<LocalBufferPool> &localBufferPool) {
49 int32_t width, height;
50 if (!format->findInt32("width", &width) || !format->findInt32("height", &height)) {
51 ALOGD("format lacks width or height");
52 return nullptr;
53 }
54
David Stevens94b608f2021-07-29 15:04:14 +090055 int64_t usageValue = 0;
56 (void)format->findInt64("android._C2MemoryUsage", &usageValue);
57 C2MemoryUsage fullUsage{usageValue | usage.expected};
58
Wonsik Kim469c8342019-04-11 16:46:09 -070059 std::shared_ptr<C2GraphicBlock> block;
60 c2_status_t err = pool->fetchGraphicBlock(
Harish Mahendrakarf6b3e5e2024-03-21 21:04:28 +000061 align(width, 2), align(height, 2), pixelFormat, fullUsage, &block);
Wonsik Kim469c8342019-04-11 16:46:09 -070062 if (err != C2_OK) {
63 ALOGD("fetch graphic block failed: %d", err);
64 return nullptr;
65 }
66
67 return GraphicBlockBuffer::Allocate(
68 format,
69 block,
70 [localBufferPool](size_t capacity) {
71 return localBufferPool->newBuffer(capacity);
72 });
73}
74
75} // namespace
76
77// CCodecBuffers
78
79void CCodecBuffers::setFormat(const sp<AMessage> &format) {
80 CHECK(format != nullptr);
81 mFormat = format;
82}
83
84sp<AMessage> CCodecBuffers::dupFormat() {
85 return mFormat != nullptr ? mFormat->dup() : nullptr;
86}
87
88void CCodecBuffers::handleImageData(const sp<Codec2Buffer> &buffer) {
89 sp<ABuffer> imageDataCandidate = buffer->getImageData();
90 if (imageDataCandidate == nullptr) {
Wonsik Kim4a3c0462021-03-09 15:45:05 -080091 if (mFormatWithImageData) {
92 // We previously sent the format with image data, so use the same format.
93 buffer->setFormat(mFormatWithImageData);
94 }
Wonsik Kim469c8342019-04-11 16:46:09 -070095 return;
96 }
Wonsik Kim4a3c0462021-03-09 15:45:05 -080097 if (!mLastImageData
98 || imageDataCandidate->size() != mLastImageData->size()
99 || memcmp(imageDataCandidate->data(),
100 mLastImageData->data(),
101 mLastImageData->size()) != 0) {
Wonsik Kim469c8342019-04-11 16:46:09 -0700102 ALOGD("[%s] updating image-data", mName);
Wonsik Kim4a3c0462021-03-09 15:45:05 -0800103 mFormatWithImageData = dupFormat();
104 mLastImageData = imageDataCandidate;
105 mFormatWithImageData->setBuffer("image-data", imageDataCandidate);
Wonsik Kim469c8342019-04-11 16:46:09 -0700106 MediaImage2 *img = (MediaImage2*)imageDataCandidate->data();
107 if (img->mNumPlanes > 0 && img->mType != img->MEDIA_IMAGE_TYPE_UNKNOWN) {
108 int32_t stride = img->mPlane[0].mRowInc;
Wonsik Kim4a3c0462021-03-09 15:45:05 -0800109 mFormatWithImageData->setInt32(KEY_STRIDE, stride);
Vinay Kaliaef5fc712021-09-15 23:59:50 +0000110 mFormatWithImageData->setInt32(KEY_WIDTH, img->mWidth);
111 mFormatWithImageData->setInt32(KEY_HEIGHT, img->mHeight);
112 ALOGD("[%s] updating stride = %d, width: %d, height: %d",
113 mName, stride, img->mWidth, img->mHeight);
Wonsik Kim469c8342019-04-11 16:46:09 -0700114 if (img->mNumPlanes > 1 && stride > 0) {
Taehwan Kimfd9b8092020-09-17 12:26:40 +0900115 int64_t offsetDelta =
116 (int64_t)img->mPlane[1].mOffset - (int64_t)img->mPlane[0].mOffset;
117 int32_t vstride = int32_t(offsetDelta / stride);
Wonsik Kim4a3c0462021-03-09 15:45:05 -0800118 mFormatWithImageData->setInt32(KEY_SLICE_HEIGHT, vstride);
Wonsik Kim469c8342019-04-11 16:46:09 -0700119 ALOGD("[%s] updating vstride = %d", mName, vstride);
Wonsik Kim2eb06312020-12-03 11:07:58 -0800120 buffer->setRange(
121 img->mPlane[0].mOffset,
122 buffer->size() - img->mPlane[0].mOffset);
Wonsik Kim469c8342019-04-11 16:46:09 -0700123 }
124 }
Wonsik Kim469c8342019-04-11 16:46:09 -0700125 }
Wonsik Kim4a3c0462021-03-09 15:45:05 -0800126 buffer->setFormat(mFormatWithImageData);
Wonsik Kim469c8342019-04-11 16:46:09 -0700127}
128
Songyue Han1e6769b2023-08-30 18:09:27 +0000129uint32_t CCodecBuffers::getPixelFormatIfApplicable() { return PIXEL_FORMAT_UNKNOWN; }
130
131bool CCodecBuffers::resetPixelFormatIfApplicable() { return false; }
132
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700133// InputBuffers
134
135sp<Codec2Buffer> InputBuffers::cloneAndReleaseBuffer(const sp<MediaCodecBuffer> &buffer) {
136 sp<Codec2Buffer> copy = createNewBuffer();
137 if (copy == nullptr) {
138 return nullptr;
139 }
140 std::shared_ptr<C2Buffer> c2buffer;
141 if (!releaseBuffer(buffer, &c2buffer, true)) {
142 return nullptr;
143 }
144 if (!copy->canCopy(c2buffer)) {
145 return nullptr;
146 }
147 if (!copy->copy(c2buffer)) {
148 return nullptr;
149 }
Wonsik Kimfb5ca492021-08-11 14:18:19 -0700150 copy->meta()->extend(buffer->meta());
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700151 return copy;
152}
153
Arun Johnsonf4a81f72023-11-09 21:22:48 +0000154// MultiAccessUnitSkipCutBuffer for buffer and bufferInfos
155
156class MultiAccessUnitSkipCutBuffer : public SkipCutBuffer {
157
158public:
159 explicit MultiAccessUnitSkipCutBuffer(
160 int32_t skip, int32_t cut, size_t num16BitChannels):
161 SkipCutBuffer(skip, cut, num16BitChannels),
162 mFrontPaddingDelay(0), mSize(0) {
163 }
Arun Johnsond43dc8c2024-02-07 01:14:15 +0000164 void clearAll() {
165 mInfos.clear();
166 mFrontPaddingDelay = 0;
167 mSize = 0;
168 SkipCutBuffer::clear();
169 }
Arun Johnsonf4a81f72023-11-09 21:22:48 +0000170
171 virtual ~MultiAccessUnitSkipCutBuffer() {
172
173 }
174
175 void submitMultiAccessUnits(
176 const sp<MediaCodecBuffer>& buffer,
177 int32_t sampleRate, size_t num16BitChannels,
178 std::shared_ptr<const C2AccessUnitInfos::output> &infos) {
179 if (infos == nullptr) {
180 // there is nothing to do more.
181 SkipCutBuffer::submit(buffer);
182 return;
183 }
184 typedef WrapperObject<std::vector<AccessUnitInfo>> BufferInfosWrapper;
185 CHECK_EQ(mSize, SkipCutBuffer::size());
186 sp<BufferInfosWrapper> bufferInfos{new BufferInfosWrapper(decltype(bufferInfos->value)())};
187 uint32_t availableSize = buffer->size() + SkipCutBuffer::size();
188 uint32_t frontPadding = mFrontPadding;
189 int32_t lastEmptyAccessUnitIndex = -1;
190 int64_t byteInUs = 0;
191 if (sampleRate > 0 && num16BitChannels > 0) {
192 byteInUs = (1000000u / (sampleRate * num16BitChannels * 2));
193 }
194 if (frontPadding > 0) {
195 mInfos.clear();
196 mSize = 0;
197 }
198 for (int i = 0 ; i < infos->flexCount() && frontPadding > 0; i++) {
199 uint32_t flagsInPadding = 0;
200 int64_t timeInPadding = 0;
201 if (infos->m.values[i].size <= frontPadding) {
202 // we have more front padding so this buffer is not going to be used.
203 int32_t consumed = infos->m.values[i].size;
204 frontPadding -= consumed;
205 mFrontPaddingDelay += byteInUs * (consumed);
206 availableSize -= consumed;
207 flagsInPadding |= toMediaCodecFlags(infos->m.values[i].flags);
208 timeInPadding = infos->m.values[i].timestamp;
209 } else {
210 C2AccessUnitInfosStruct info = infos->m.values[i];
211 mFrontPaddingDelay += byteInUs * (frontPadding);
212 info.size -= frontPadding;
213 info.timestamp -= mFrontPaddingDelay;
214 availableSize -= frontPadding;
215 flagsInPadding |= toMediaCodecFlags(infos->m.values[i].flags);
216 timeInPadding = infos->m.values[i].timestamp;
217 frontPadding = 0;
218 mInfos.push_back(info);
219 mSize += info.size;
220 }
221 if (flagsInPadding != 0) {
222 bufferInfos->value.emplace_back(
223 flagsInPadding, 0, timeInPadding);
224 }
225 lastEmptyAccessUnitIndex = i;
226 }
227 if (frontPadding <= 0) {
228 // process what's already in the buffer first
229 auto it = mInfos.begin();
230 while (it != mInfos.end() && availableSize > mBackPadding) {
231 // we have samples to send out.
232 if ((availableSize - it->size) >= mBackPadding) {
233 // this is totally used here.
234 int32_t consumed = it->size;
235 bufferInfos->value.emplace_back(
236 toMediaCodecFlags(it->flags), consumed, it->timestamp);
237 availableSize -= consumed;
238 mSize -= consumed;
239 it = mInfos.erase(it);
240 } else {
241 int32_t consumed = availableSize - mBackPadding;
242 bufferInfos->value.emplace_back(
243 toMediaCodecFlags(it->flags),
244 consumed,
245 it->timestamp);
246 it->size -= consumed;
247 it->timestamp += consumed * byteInUs;
248 availableSize -= consumed;
249 mSize -= consumed;
250 it++;
251 }
252 }
253 // if buffer has more process all of it and keep the remaining info.
254 for (int i = (lastEmptyAccessUnitIndex + 1) ; i < infos->flexCount() ; i++) {
255 // upddate updatedInfo and mInfos
256 if (availableSize > mBackPadding) {
257 // we have to take data from the new buffer.
258 if (availableSize - infos->m.values[i].size >= mBackPadding) {
259 // we are using this info
260 int32_t consumed = infos->m.values[i].size;
261 bufferInfos->value.emplace_back(
262 toMediaCodecFlags(infos->m.values[i].flags),
263 consumed,
264 infos->m.values[i].timestamp - mFrontPaddingDelay);
265 availableSize -= consumed;
266 } else {
267 // if we need to update the size
268 C2AccessUnitInfosStruct info = infos->m.values[i];
269 int32_t consumed = availableSize - mBackPadding;
270 bufferInfos->value.emplace_back(
271 toMediaCodecFlags(infos->m.values[i].flags),
272 consumed,
273 infos->m.values[i].timestamp - mFrontPaddingDelay);
274 info.size -= consumed;
275 info.timestamp = info.timestamp - mFrontPaddingDelay +
276 consumed * byteInUs;
277 mInfos.push_back(info);
278 availableSize -= consumed;
279 mSize += info.size;
280 }
281 } else {
282 // we have to maintain infos
283 C2AccessUnitInfosStruct info = infos->m.values[i];
284 info.timestamp -= mFrontPaddingDelay;
285 mInfos.push_back(info);
286 mSize += info.size;
287 }
288 }
289 }
290 SkipCutBuffer::submit(buffer);
291 infos = nullptr;
292 if (!bufferInfos->value.empty()) {
293 buffer->meta()->setObject("accessUnitInfo", bufferInfos);
294 }
295 }
296protected:
297 // Flags can come with individual BufferInfos
298 // when used with large frame audio
299 constexpr static std::initializer_list<std::pair<uint32_t, uint32_t>> flagList = {
300 {BUFFER_FLAG_CODEC_CONFIG, C2FrameData::FLAG_CODEC_CONFIG},
301 {BUFFER_FLAG_END_OF_STREAM, C2FrameData::FLAG_END_OF_STREAM},
302 {BUFFER_FLAG_DECODE_ONLY, C2FrameData::FLAG_DROP_FRAME}
303 };
304
305 static uint32_t toMediaCodecFlags(uint32_t flags) {
306 return std::transform_reduce(
307 flagList.begin(), flagList.end(),
308 0u,
309 std::bit_or{},
310 [flags](const std::pair<uint32_t, uint32_t> &entry) {
311 return (flags & entry.second) ? entry.first : 0;
312 });
313 }
314 std::list<C2AccessUnitInfosStruct> mInfos;
315 int64_t mFrontPaddingDelay;
316 size_t mSize;
317};
318
Wonsik Kim469c8342019-04-11 16:46:09 -0700319// OutputBuffers
320
Wonsik Kim41d83432020-04-27 16:40:49 -0700321OutputBuffers::OutputBuffers(const char *componentName, const char *name)
322 : CCodecBuffers(componentName, name) { }
323
324OutputBuffers::~OutputBuffers() = default;
325
Wonsik Kim469c8342019-04-11 16:46:09 -0700326void OutputBuffers::initSkipCutBuffer(
327 int32_t delay, int32_t padding, int32_t sampleRate, int32_t channelCount) {
328 CHECK(mSkipCutBuffer == nullptr);
329 mDelay = delay;
330 mPadding = padding;
331 mSampleRate = sampleRate;
Wonsik Kim40b0b1d2020-03-25 15:47:35 -0700332 mChannelCount = channelCount;
333 setSkipCutBuffer(delay, padding);
Wonsik Kim469c8342019-04-11 16:46:09 -0700334}
335
336void OutputBuffers::updateSkipCutBuffer(int32_t sampleRate, int32_t channelCount) {
337 if (mSkipCutBuffer == nullptr) {
338 return;
339 }
Wonsik Kim40b0b1d2020-03-25 15:47:35 -0700340 if (mSampleRate == sampleRate && mChannelCount == channelCount) {
341 return;
342 }
Wonsik Kim469c8342019-04-11 16:46:09 -0700343 int32_t delay = mDelay;
344 int32_t padding = mPadding;
345 if (sampleRate != mSampleRate) {
346 delay = ((int64_t)delay * sampleRate) / mSampleRate;
347 padding = ((int64_t)padding * sampleRate) / mSampleRate;
348 }
Wonsik Kim40b0b1d2020-03-25 15:47:35 -0700349 mSampleRate = sampleRate;
350 mChannelCount = channelCount;
351 setSkipCutBuffer(delay, padding);
Wonsik Kim469c8342019-04-11 16:46:09 -0700352}
353
Wonsik Kim3b4349a2020-11-10 11:54:15 -0800354void OutputBuffers::updateSkipCutBuffer(const sp<AMessage> &format) {
Pawin Vongmasa9b906982020-04-11 05:07:15 -0700355 AString mediaType;
356 if (format->findString(KEY_MIME, &mediaType)
357 && mediaType == MIMETYPE_AUDIO_RAW) {
358 int32_t channelCount;
359 int32_t sampleRate;
360 if (format->findInt32(KEY_CHANNEL_COUNT, &channelCount)
361 && format->findInt32(KEY_SAMPLE_RATE, &sampleRate)) {
362 updateSkipCutBuffer(sampleRate, channelCount);
363 }
364 }
Pawin Vongmasa9b906982020-04-11 05:07:15 -0700365}
366
Wonsik Kim469c8342019-04-11 16:46:09 -0700367void OutputBuffers::submit(const sp<MediaCodecBuffer> &buffer) {
368 if (mSkipCutBuffer != nullptr) {
369 mSkipCutBuffer->submit(buffer);
370 }
371}
372
Arun Johnsonf4a81f72023-11-09 21:22:48 +0000373bool OutputBuffers::submit(const sp<MediaCodecBuffer> &buffer, int32_t sampleRate,
374 int32_t channelCount, std::shared_ptr<const C2AccessUnitInfos::output> &infos) {
375 if (mSkipCutBuffer == nullptr) {
376 return false;
377 }
378 mSkipCutBuffer->submitMultiAccessUnits(buffer, sampleRate, channelCount, infos);
379 return true;
380}
381
Wonsik Kim40b0b1d2020-03-25 15:47:35 -0700382void OutputBuffers::setSkipCutBuffer(int32_t skip, int32_t cut) {
Wonsik Kim469c8342019-04-11 16:46:09 -0700383 if (mSkipCutBuffer != nullptr) {
384 size_t prevSize = mSkipCutBuffer->size();
385 if (prevSize != 0u) {
386 ALOGD("[%s] Replacing SkipCutBuffer holding %zu bytes", mName, prevSize);
387 }
388 }
Arun Johnsonf4a81f72023-11-09 21:22:48 +0000389 mSkipCutBuffer = new MultiAccessUnitSkipCutBuffer(skip, cut, mChannelCount);
Wonsik Kim469c8342019-04-11 16:46:09 -0700390}
391
Wonsik Kim6f23cfc2021-09-24 05:45:52 -0700392bool OutputBuffers::convert(
393 const std::shared_ptr<C2Buffer> &src, sp<Codec2Buffer> *dst) {
Wonsik Kim360ba0a2022-05-23 15:38:21 -0700394 if (src && src->data().type() != C2BufferData::LINEAR) {
Wonsik Kim6f23cfc2021-09-24 05:45:52 -0700395 return false;
396 }
397 int32_t configEncoding = kAudioEncodingPcm16bit;
398 int32_t codecEncoding = kAudioEncodingPcm16bit;
399 if (mFormat->findInt32("android._codec-pcm-encoding", &codecEncoding)
400 && mFormat->findInt32("android._config-pcm-encoding", &configEncoding)) {
401 if (mSrcEncoding != codecEncoding || mDstEncoding != configEncoding) {
402 if (codecEncoding != configEncoding) {
403 mDataConverter = AudioConverter::Create(
404 (AudioEncoding)codecEncoding, (AudioEncoding)configEncoding);
405 ALOGD_IF(mDataConverter, "[%s] Converter created from %d to %d",
406 mName, codecEncoding, configEncoding);
407 mFormatWithConverter = mFormat->dup();
408 mFormatWithConverter->setInt32(KEY_PCM_ENCODING, configEncoding);
409 } else {
410 mDataConverter = nullptr;
411 mFormatWithConverter = nullptr;
412 }
413 mSrcEncoding = codecEncoding;
414 mDstEncoding = configEncoding;
415 }
416 if (int encoding; !mFormat->findInt32(KEY_PCM_ENCODING, &encoding)
417 || encoding != mDstEncoding) {
418 }
419 }
420 if (!mDataConverter) {
421 return false;
422 }
Wonsik Kim360ba0a2022-05-23 15:38:21 -0700423 sp<MediaCodecBuffer> srcBuffer;
424 if (src) {
425 srcBuffer = ConstLinearBlockBuffer::Allocate(mFormat, src);
426 } else {
427 srcBuffer = new MediaCodecBuffer(mFormat, new ABuffer(0));
428 }
Wonsik Kim6f23cfc2021-09-24 05:45:52 -0700429 if (!srcBuffer) {
430 return false;
431 }
Greg Kaiser92dc4542021-10-08 06:58:19 -0700432 if (!*dst) {
Wonsik Kim6f23cfc2021-09-24 05:45:52 -0700433 *dst = new Codec2Buffer(
434 mFormat,
435 new ABuffer(mDataConverter->targetSize(srcBuffer->size())));
436 }
437 sp<MediaCodecBuffer> dstBuffer = *dst;
438 status_t err = mDataConverter->convert(srcBuffer, dstBuffer);
439 if (err != OK) {
440 ALOGD("[%s] buffer conversion failed: %d", mName, err);
441 return false;
442 }
443 dstBuffer->setFormat(mFormatWithConverter);
444 return true;
445}
446
Pawin Vongmasa9b906982020-04-11 05:07:15 -0700447void OutputBuffers::clearStash() {
448 mPending.clear();
449 mReorderStash.clear();
450 mDepth = 0;
451 mKey = C2Config::ORDINAL;
Pawin Vongmasa9b906982020-04-11 05:07:15 -0700452}
453
454void OutputBuffers::flushStash() {
455 for (StashEntry& e : mPending) {
456 e.notify = false;
457 }
458 for (StashEntry& e : mReorderStash) {
459 e.notify = false;
460 }
461}
462
463uint32_t OutputBuffers::getReorderDepth() const {
464 return mDepth;
465}
466
467void OutputBuffers::setReorderDepth(uint32_t depth) {
468 mPending.splice(mPending.end(), mReorderStash);
469 mDepth = depth;
470}
471
472void OutputBuffers::setReorderKey(C2Config::ordinal_key_t key) {
473 mPending.splice(mPending.end(), mReorderStash);
474 mKey = key;
475}
476
477void OutputBuffers::pushToStash(
478 const std::shared_ptr<C2Buffer>& buffer,
479 bool notify,
480 int64_t timestamp,
481 int32_t flags,
482 const sp<AMessage>& format,
483 const C2WorkOrdinalStruct& ordinal) {
My Nameac29e592022-03-28 13:53:32 -0700484 bool eos = flags & BUFFER_FLAG_END_OF_STREAM;
Pawin Vongmasa9b906982020-04-11 05:07:15 -0700485 if (!buffer && eos) {
486 // TRICKY: we may be violating ordering of the stash here. Because we
487 // don't expect any more emplace() calls after this, the ordering should
488 // not matter.
489 mReorderStash.emplace_back(
490 buffer, notify, timestamp, flags, format, ordinal);
491 } else {
My Nameac29e592022-03-28 13:53:32 -0700492 flags = flags & ~BUFFER_FLAG_END_OF_STREAM;
Pawin Vongmasa9b906982020-04-11 05:07:15 -0700493 auto it = mReorderStash.begin();
494 for (; it != mReorderStash.end(); ++it) {
495 if (less(ordinal, it->ordinal)) {
496 break;
497 }
498 }
499 mReorderStash.emplace(it,
500 buffer, notify, timestamp, flags, format, ordinal);
501 if (eos) {
502 mReorderStash.back().flags =
My Nameac29e592022-03-28 13:53:32 -0700503 mReorderStash.back().flags | BUFFER_FLAG_END_OF_STREAM;
Pawin Vongmasa9b906982020-04-11 05:07:15 -0700504 }
505 }
506 while (!mReorderStash.empty() && mReorderStash.size() > mDepth) {
507 mPending.push_back(mReorderStash.front());
508 mReorderStash.pop_front();
509 }
510 ALOGV("[%s] %s: pushToStash -- pending size = %zu", mName, __func__, mPending.size());
511}
512
513OutputBuffers::BufferAction OutputBuffers::popFromStashAndRegister(
514 std::shared_ptr<C2Buffer>* c2Buffer,
515 size_t* index,
516 sp<MediaCodecBuffer>* outBuffer) {
517 if (mPending.empty()) {
518 return SKIP;
519 }
520
521 // Retrieve the first entry.
522 StashEntry &entry = mPending.front();
523
524 *c2Buffer = entry.buffer;
525 sp<AMessage> outputFormat = entry.format;
526
Wonsik Kim3b4349a2020-11-10 11:54:15 -0800527 if (entry.notify && mFormat != outputFormat) {
528 updateSkipCutBuffer(outputFormat);
Wonsik Kim4a3c0462021-03-09 15:45:05 -0800529 // Trigger image data processing to the new format
530 mLastImageData.clear();
Wonsik Kim3b4349a2020-11-10 11:54:15 -0800531 ALOGV("[%s] popFromStashAndRegister: output format reference changed: %p -> %p",
532 mName, mFormat.get(), outputFormat.get());
Wonsik Kim4a3c0462021-03-09 15:45:05 -0800533 ALOGD("[%s] popFromStashAndRegister: at %lldus, output format changed to %s",
534 mName, (long long)entry.timestamp, outputFormat->debugString().c_str());
Wonsik Kim3b4349a2020-11-10 11:54:15 -0800535 setFormat(outputFormat);
Pawin Vongmasa9b906982020-04-11 05:07:15 -0700536 }
537
538 // Flushing mReorderStash because no other buffers should come after output
539 // EOS.
My Nameac29e592022-03-28 13:53:32 -0700540 if (entry.flags & BUFFER_FLAG_END_OF_STREAM) {
Pawin Vongmasa9b906982020-04-11 05:07:15 -0700541 // Flush reorder stash
542 setReorderDepth(0);
543 }
544
545 if (!entry.notify) {
546 mPending.pop_front();
547 return DISCARD;
548 }
549
550 // Try to register the buffer.
551 status_t err = registerBuffer(*c2Buffer, index, outBuffer);
552 if (err != OK) {
553 if (err != WOULD_BLOCK) {
554 return REALLOCATE;
555 }
556 return RETRY;
557 }
558
559 // Append information from the front stash entry to outBuffer.
560 (*outBuffer)->meta()->setInt64("timeUs", entry.timestamp);
561 (*outBuffer)->meta()->setInt32("flags", entry.flags);
Byeongjo Park2eef13e2020-06-12 17:24:21 +0900562 (*outBuffer)->meta()->setInt64("frameIndex", entry.ordinal.frameIndex.peekll());
Pawin Vongmasa9b906982020-04-11 05:07:15 -0700563 ALOGV("[%s] popFromStashAndRegister: "
564 "out buffer index = %zu [%p] => %p + %zu (%lld)",
565 mName, *index, outBuffer->get(),
566 (*outBuffer)->data(), (*outBuffer)->size(),
567 (long long)entry.timestamp);
568
569 // The front entry of mPending will be removed now that the registration
570 // succeeded.
571 mPending.pop_front();
572 return NOTIFY_CLIENT;
573}
574
575bool OutputBuffers::popPending(StashEntry *entry) {
576 if (mPending.empty()) {
577 return false;
578 }
579 *entry = mPending.front();
580 mPending.pop_front();
581 return true;
582}
583
584void OutputBuffers::deferPending(const OutputBuffers::StashEntry &entry) {
585 mPending.push_front(entry);
586}
587
588bool OutputBuffers::hasPending() const {
589 return !mPending.empty();
590}
591
592bool OutputBuffers::less(
593 const C2WorkOrdinalStruct &o1, const C2WorkOrdinalStruct &o2) const {
594 switch (mKey) {
595 case C2Config::ORDINAL: return o1.frameIndex < o2.frameIndex;
596 case C2Config::TIMESTAMP: return o1.timestamp < o2.timestamp;
597 case C2Config::CUSTOM: return o1.customOrdinal < o2.customOrdinal;
598 default:
599 ALOGD("Unrecognized key; default to timestamp");
600 return o1.frameIndex < o2.frameIndex;
601 }
602}
603
Wonsik Kim469c8342019-04-11 16:46:09 -0700604// LocalBufferPool
605
Wonsik Kim41d83432020-04-27 16:40:49 -0700606constexpr size_t kInitialPoolCapacity = kMaxLinearBufferSize;
607constexpr size_t kMaxPoolCapacity = kMaxLinearBufferSize * 32;
608
609std::shared_ptr<LocalBufferPool> LocalBufferPool::Create() {
610 return std::shared_ptr<LocalBufferPool>(new LocalBufferPool(kInitialPoolCapacity));
Wonsik Kim469c8342019-04-11 16:46:09 -0700611}
612
613sp<ABuffer> LocalBufferPool::newBuffer(size_t capacity) {
614 Mutex::Autolock lock(mMutex);
615 auto it = std::find_if(
616 mPool.begin(), mPool.end(),
617 [capacity](const std::vector<uint8_t> &vec) {
618 return vec.capacity() >= capacity;
619 });
620 if (it != mPool.end()) {
621 sp<ABuffer> buffer = new VectorBuffer(std::move(*it), shared_from_this());
622 mPool.erase(it);
623 return buffer;
624 }
625 if (mUsedSize + capacity > mPoolCapacity) {
626 while (!mPool.empty()) {
627 mUsedSize -= mPool.back().capacity();
628 mPool.pop_back();
629 }
Wonsik Kim41d83432020-04-27 16:40:49 -0700630 while (mUsedSize + capacity > mPoolCapacity && mPoolCapacity * 2 <= kMaxPoolCapacity) {
631 ALOGD("Increasing local buffer pool capacity from %zu to %zu",
632 mPoolCapacity, mPoolCapacity * 2);
633 mPoolCapacity *= 2;
634 }
Wonsik Kim469c8342019-04-11 16:46:09 -0700635 if (mUsedSize + capacity > mPoolCapacity) {
636 ALOGD("mUsedSize = %zu, capacity = %zu, mPoolCapacity = %zu",
637 mUsedSize, capacity, mPoolCapacity);
638 return nullptr;
639 }
640 }
641 std::vector<uint8_t> vec(capacity);
642 mUsedSize += vec.capacity();
643 return new VectorBuffer(std::move(vec), shared_from_this());
644}
645
646LocalBufferPool::VectorBuffer::VectorBuffer(
647 std::vector<uint8_t> &&vec, const std::shared_ptr<LocalBufferPool> &pool)
648 : ABuffer(vec.data(), vec.capacity()),
649 mVec(std::move(vec)),
650 mPool(pool) {
651}
652
653LocalBufferPool::VectorBuffer::~VectorBuffer() {
654 std::shared_ptr<LocalBufferPool> pool = mPool.lock();
655 if (pool) {
656 // If pool is alive, return the vector back to the pool so that
657 // it can be recycled.
658 pool->returnVector(std::move(mVec));
659 }
660}
661
662void LocalBufferPool::returnVector(std::vector<uint8_t> &&vec) {
663 Mutex::Autolock lock(mMutex);
664 mPool.push_front(std::move(vec));
665}
666
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700667// FlexBuffersImpl
668
Wonsik Kim469c8342019-04-11 16:46:09 -0700669size_t FlexBuffersImpl::assignSlot(const sp<Codec2Buffer> &buffer) {
670 for (size_t i = 0; i < mBuffers.size(); ++i) {
671 if (mBuffers[i].clientBuffer == nullptr
672 && mBuffers[i].compBuffer.expired()) {
673 mBuffers[i].clientBuffer = buffer;
674 return i;
675 }
676 }
677 mBuffers.push_back({ buffer, std::weak_ptr<C2Buffer>() });
678 return mBuffers.size() - 1;
679}
680
Wonsik Kim469c8342019-04-11 16:46:09 -0700681bool FlexBuffersImpl::releaseSlot(
682 const sp<MediaCodecBuffer> &buffer,
683 std::shared_ptr<C2Buffer> *c2buffer,
684 bool release) {
685 sp<Codec2Buffer> clientBuffer;
686 size_t index = mBuffers.size();
687 for (size_t i = 0; i < mBuffers.size(); ++i) {
688 if (mBuffers[i].clientBuffer == buffer) {
689 clientBuffer = mBuffers[i].clientBuffer;
690 if (release) {
691 mBuffers[i].clientBuffer.clear();
692 }
693 index = i;
694 break;
695 }
696 }
697 if (clientBuffer == nullptr) {
698 ALOGV("[%s] %s: No matching buffer found", mName, __func__);
699 return false;
700 }
701 std::shared_ptr<C2Buffer> result = mBuffers[index].compBuffer.lock();
702 if (!result) {
703 result = clientBuffer->asC2Buffer();
Wonsik Kimf9b32122020-04-02 11:30:17 -0700704 clientBuffer->clearC2BufferRefs();
Wonsik Kim469c8342019-04-11 16:46:09 -0700705 mBuffers[index].compBuffer = result;
706 }
707 if (c2buffer) {
708 *c2buffer = result;
709 }
710 return true;
711}
712
713bool FlexBuffersImpl::expireComponentBuffer(const std::shared_ptr<C2Buffer> &c2buffer) {
714 for (size_t i = 0; i < mBuffers.size(); ++i) {
715 std::shared_ptr<C2Buffer> compBuffer =
716 mBuffers[i].compBuffer.lock();
717 if (!compBuffer || compBuffer != c2buffer) {
718 continue;
719 }
720 mBuffers[i].compBuffer.reset();
721 ALOGV("[%s] codec released buffer #%zu", mName, i);
722 return true;
723 }
724 ALOGV("[%s] codec released an unknown buffer", mName);
725 return false;
726}
727
728void FlexBuffersImpl::flush() {
729 ALOGV("[%s] buffers are flushed %zu", mName, mBuffers.size());
730 mBuffers.clear();
731}
732
Wonsik Kim0487b782020-10-28 11:45:50 -0700733size_t FlexBuffersImpl::numActiveSlots() const {
Wonsik Kim469c8342019-04-11 16:46:09 -0700734 return std::count_if(
735 mBuffers.begin(), mBuffers.end(),
736 [](const Entry &entry) {
Wonsik Kim0487b782020-10-28 11:45:50 -0700737 return (entry.clientBuffer != nullptr
738 || !entry.compBuffer.expired());
Wonsik Kim469c8342019-04-11 16:46:09 -0700739 });
740}
741
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700742size_t FlexBuffersImpl::numComponentBuffers() const {
743 return std::count_if(
744 mBuffers.begin(), mBuffers.end(),
745 [](const Entry &entry) {
746 return !entry.compBuffer.expired();
747 });
748}
749
Wonsik Kim469c8342019-04-11 16:46:09 -0700750// BuffersArrayImpl
751
752void BuffersArrayImpl::initialize(
753 const FlexBuffersImpl &impl,
754 size_t minSize,
755 std::function<sp<Codec2Buffer>()> allocate) {
756 mImplName = impl.mImplName + "[N]";
757 mName = mImplName.c_str();
758 for (size_t i = 0; i < impl.mBuffers.size(); ++i) {
759 sp<Codec2Buffer> clientBuffer = impl.mBuffers[i].clientBuffer;
760 bool ownedByClient = (clientBuffer != nullptr);
761 if (!ownedByClient) {
762 clientBuffer = allocate();
763 }
764 mBuffers.push_back({ clientBuffer, impl.mBuffers[i].compBuffer, ownedByClient });
765 }
766 ALOGV("[%s] converted %zu buffers to array mode of %zu", mName, mBuffers.size(), minSize);
767 for (size_t i = impl.mBuffers.size(); i < minSize; ++i) {
768 mBuffers.push_back({ allocate(), std::weak_ptr<C2Buffer>(), false });
769 }
770}
771
772status_t BuffersArrayImpl::grabBuffer(
773 size_t *index,
774 sp<Codec2Buffer> *buffer,
775 std::function<bool(const sp<Codec2Buffer> &)> match) {
776 // allBuffersDontMatch remains true if all buffers are available but
777 // match() returns false for every buffer.
778 bool allBuffersDontMatch = true;
779 for (size_t i = 0; i < mBuffers.size(); ++i) {
780 if (!mBuffers[i].ownedByClient && mBuffers[i].compBuffer.expired()) {
781 if (match(mBuffers[i].clientBuffer)) {
782 mBuffers[i].ownedByClient = true;
783 *buffer = mBuffers[i].clientBuffer;
784 (*buffer)->meta()->clear();
785 (*buffer)->setRange(0, (*buffer)->capacity());
786 *index = i;
787 return OK;
788 }
789 } else {
790 allBuffersDontMatch = false;
791 }
792 }
793 return allBuffersDontMatch ? NO_MEMORY : WOULD_BLOCK;
794}
795
796bool BuffersArrayImpl::returnBuffer(
797 const sp<MediaCodecBuffer> &buffer,
798 std::shared_ptr<C2Buffer> *c2buffer,
799 bool release) {
800 sp<Codec2Buffer> clientBuffer;
801 size_t index = mBuffers.size();
802 for (size_t i = 0; i < mBuffers.size(); ++i) {
803 if (mBuffers[i].clientBuffer == buffer) {
804 if (!mBuffers[i].ownedByClient) {
805 ALOGD("[%s] Client returned a buffer it does not own according to our record: %zu",
806 mName, i);
807 }
808 clientBuffer = mBuffers[i].clientBuffer;
809 if (release) {
810 mBuffers[i].ownedByClient = false;
811 }
812 index = i;
813 break;
814 }
815 }
816 if (clientBuffer == nullptr) {
817 ALOGV("[%s] %s: No matching buffer found", mName, __func__);
818 return false;
819 }
820 ALOGV("[%s] %s: matching buffer found (index=%zu)", mName, __func__, index);
821 std::shared_ptr<C2Buffer> result = mBuffers[index].compBuffer.lock();
822 if (!result) {
823 result = clientBuffer->asC2Buffer();
Wonsik Kimf9b32122020-04-02 11:30:17 -0700824 clientBuffer->clearC2BufferRefs();
Wonsik Kim469c8342019-04-11 16:46:09 -0700825 mBuffers[index].compBuffer = result;
826 }
827 if (c2buffer) {
828 *c2buffer = result;
829 }
830 return true;
831}
832
833bool BuffersArrayImpl::expireComponentBuffer(const std::shared_ptr<C2Buffer> &c2buffer) {
834 for (size_t i = 0; i < mBuffers.size(); ++i) {
835 std::shared_ptr<C2Buffer> compBuffer =
836 mBuffers[i].compBuffer.lock();
837 if (!compBuffer) {
838 continue;
839 }
840 if (c2buffer == compBuffer) {
841 if (mBuffers[i].ownedByClient) {
842 // This should not happen.
843 ALOGD("[%s] codec released a buffer owned by client "
844 "(index %zu)", mName, i);
845 }
846 mBuffers[i].compBuffer.reset();
847 ALOGV("[%s] codec released buffer #%zu(array mode)", mName, i);
848 return true;
849 }
850 }
851 ALOGV("[%s] codec released an unknown buffer (array mode)", mName);
852 return false;
853}
854
855void BuffersArrayImpl::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
856 array->clear();
857 for (const Entry &entry : mBuffers) {
858 array->push(entry.clientBuffer);
859 }
860}
861
862void BuffersArrayImpl::flush() {
863 for (Entry &entry : mBuffers) {
864 entry.ownedByClient = false;
865 }
866}
867
868void BuffersArrayImpl::realloc(std::function<sp<Codec2Buffer>()> alloc) {
869 size_t size = mBuffers.size();
870 mBuffers.clear();
871 for (size_t i = 0; i < size; ++i) {
872 mBuffers.push_back({ alloc(), std::weak_ptr<C2Buffer>(), false });
873 }
874}
875
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700876void BuffersArrayImpl::grow(
877 size_t newSize, std::function<sp<Codec2Buffer>()> alloc) {
878 CHECK_LT(mBuffers.size(), newSize);
879 while (mBuffers.size() < newSize) {
880 mBuffers.push_back({ alloc(), std::weak_ptr<C2Buffer>(), false });
881 }
882}
883
Wonsik Kim0487b782020-10-28 11:45:50 -0700884size_t BuffersArrayImpl::numActiveSlots() const {
Wonsik Kim469c8342019-04-11 16:46:09 -0700885 return std::count_if(
886 mBuffers.begin(), mBuffers.end(),
887 [](const Entry &entry) {
Wonsik Kim0487b782020-10-28 11:45:50 -0700888 return entry.ownedByClient || !entry.compBuffer.expired();
Wonsik Kim469c8342019-04-11 16:46:09 -0700889 });
890}
891
Wonsik Kima39882b2019-06-20 16:13:56 -0700892size_t BuffersArrayImpl::arraySize() const {
893 return mBuffers.size();
894}
895
Wonsik Kim469c8342019-04-11 16:46:09 -0700896// InputBuffersArray
897
898void InputBuffersArray::initialize(
899 const FlexBuffersImpl &impl,
900 size_t minSize,
901 std::function<sp<Codec2Buffer>()> allocate) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700902 mAllocate = allocate;
Wonsik Kim469c8342019-04-11 16:46:09 -0700903 mImpl.initialize(impl, minSize, allocate);
904}
905
906void InputBuffersArray::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
907 mImpl.getArray(array);
908}
909
910bool InputBuffersArray::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
911 sp<Codec2Buffer> c2Buffer;
912 status_t err = mImpl.grabBuffer(index, &c2Buffer);
913 if (err == OK) {
914 c2Buffer->setFormat(mFormat);
915 handleImageData(c2Buffer);
916 *buffer = c2Buffer;
917 return true;
918 }
919 return false;
920}
921
922bool InputBuffersArray::releaseBuffer(
923 const sp<MediaCodecBuffer> &buffer,
924 std::shared_ptr<C2Buffer> *c2buffer,
925 bool release) {
926 return mImpl.returnBuffer(buffer, c2buffer, release);
927}
928
929bool InputBuffersArray::expireComponentBuffer(
930 const std::shared_ptr<C2Buffer> &c2buffer) {
931 return mImpl.expireComponentBuffer(c2buffer);
932}
933
934void InputBuffersArray::flush() {
935 mImpl.flush();
936}
937
Wonsik Kim0487b782020-10-28 11:45:50 -0700938size_t InputBuffersArray::numActiveSlots() const {
939 return mImpl.numActiveSlots();
Wonsik Kim469c8342019-04-11 16:46:09 -0700940}
941
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700942sp<Codec2Buffer> InputBuffersArray::createNewBuffer() {
943 return mAllocate();
944}
945
Wonsik Kimfb7a7672019-12-27 17:13:33 -0800946// SlotInputBuffers
947
948bool SlotInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
949 sp<Codec2Buffer> newBuffer = createNewBuffer();
950 *index = mImpl.assignSlot(newBuffer);
951 *buffer = newBuffer;
952 return true;
953}
954
955bool SlotInputBuffers::releaseBuffer(
956 const sp<MediaCodecBuffer> &buffer,
957 std::shared_ptr<C2Buffer> *c2buffer,
958 bool release) {
959 return mImpl.releaseSlot(buffer, c2buffer, release);
960}
961
962bool SlotInputBuffers::expireComponentBuffer(
963 const std::shared_ptr<C2Buffer> &c2buffer) {
964 return mImpl.expireComponentBuffer(c2buffer);
965}
966
967void SlotInputBuffers::flush() {
968 mImpl.flush();
969}
970
971std::unique_ptr<InputBuffers> SlotInputBuffers::toArrayMode(size_t) {
972 TRESPASS("Array mode should not be called at non-legacy mode");
973 return nullptr;
974}
975
Wonsik Kim0487b782020-10-28 11:45:50 -0700976size_t SlotInputBuffers::numActiveSlots() const {
977 return mImpl.numActiveSlots();
Wonsik Kimfb7a7672019-12-27 17:13:33 -0800978}
979
980sp<Codec2Buffer> SlotInputBuffers::createNewBuffer() {
981 return new DummyContainerBuffer{mFormat, nullptr};
982}
983
Wonsik Kim469c8342019-04-11 16:46:09 -0700984// LinearInputBuffers
985
986bool LinearInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -0700987 sp<Codec2Buffer> newBuffer = createNewBuffer();
Wonsik Kim469c8342019-04-11 16:46:09 -0700988 if (newBuffer == nullptr) {
989 return false;
990 }
991 *index = mImpl.assignSlot(newBuffer);
992 *buffer = newBuffer;
993 return true;
994}
995
996bool LinearInputBuffers::releaseBuffer(
997 const sp<MediaCodecBuffer> &buffer,
998 std::shared_ptr<C2Buffer> *c2buffer,
999 bool release) {
1000 return mImpl.releaseSlot(buffer, c2buffer, release);
1001}
1002
1003bool LinearInputBuffers::expireComponentBuffer(
1004 const std::shared_ptr<C2Buffer> &c2buffer) {
1005 return mImpl.expireComponentBuffer(c2buffer);
1006}
1007
1008void LinearInputBuffers::flush() {
1009 // This is no-op by default unless we're in array mode where we need to keep
1010 // track of the flushed work.
1011 mImpl.flush();
1012}
1013
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001014std::unique_ptr<InputBuffers> LinearInputBuffers::toArrayMode(size_t size) {
Wonsik Kim469c8342019-04-11 16:46:09 -07001015 std::unique_ptr<InputBuffersArray> array(
1016 new InputBuffersArray(mComponentName.c_str(), "1D-Input[N]"));
1017 array->setPool(mPool);
1018 array->setFormat(mFormat);
1019 array->initialize(
1020 mImpl,
1021 size,
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001022 [pool = mPool, format = mFormat] () -> sp<Codec2Buffer> {
1023 return Alloc(pool, format);
1024 });
Wonsik Kim469c8342019-04-11 16:46:09 -07001025 return std::move(array);
1026}
1027
Wonsik Kim0487b782020-10-28 11:45:50 -07001028size_t LinearInputBuffers::numActiveSlots() const {
1029 return mImpl.numActiveSlots();
Wonsik Kim469c8342019-04-11 16:46:09 -07001030}
1031
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001032// static
1033sp<Codec2Buffer> LinearInputBuffers::Alloc(
1034 const std::shared_ptr<C2BlockPool> &pool, const sp<AMessage> &format) {
1035 int32_t capacity = kLinearBufferSize;
1036 (void)format->findInt32(KEY_MAX_INPUT_SIZE, &capacity);
1037 if ((size_t)capacity > kMaxLinearBufferSize) {
1038 ALOGD("client requested %d, capped to %zu", capacity, kMaxLinearBufferSize);
1039 capacity = kMaxLinearBufferSize;
1040 }
1041
Wonsik Kim666604a2020-05-14 16:57:49 -07001042 int64_t usageValue = 0;
1043 (void)format->findInt64("android._C2MemoryUsage", &usageValue);
1044 C2MemoryUsage usage{usageValue | C2MemoryUsage::CPU_READ | C2MemoryUsage::CPU_WRITE};
Wonsik Kim469c8342019-04-11 16:46:09 -07001045 std::shared_ptr<C2LinearBlock> block;
1046
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001047 c2_status_t err = pool->fetchLinearBlock(capacity, usage, &block);
Wonsik Kim469c8342019-04-11 16:46:09 -07001048 if (err != C2_OK) {
1049 return nullptr;
1050 }
1051
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001052 return LinearBlockBuffer::Allocate(format, block);
1053}
1054
1055sp<Codec2Buffer> LinearInputBuffers::createNewBuffer() {
1056 return Alloc(mPool, mFormat);
Wonsik Kim469c8342019-04-11 16:46:09 -07001057}
1058
1059// EncryptedLinearInputBuffers
1060
1061EncryptedLinearInputBuffers::EncryptedLinearInputBuffers(
1062 bool secure,
1063 const sp<MemoryDealer> &dealer,
1064 const sp<ICrypto> &crypto,
1065 int32_t heapSeqNum,
1066 size_t capacity,
1067 size_t numInputSlots,
1068 const char *componentName, const char *name)
1069 : LinearInputBuffers(componentName, name),
1070 mUsage({0, 0}),
1071 mDealer(dealer),
1072 mCrypto(crypto),
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001073 mMemoryVector(new std::vector<Entry>){
Wonsik Kim469c8342019-04-11 16:46:09 -07001074 if (secure) {
1075 mUsage = { C2MemoryUsage::READ_PROTECTED, 0 };
1076 } else {
1077 mUsage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
1078 }
1079 for (size_t i = 0; i < numInputSlots; ++i) {
1080 sp<IMemory> memory = mDealer->allocate(capacity);
1081 if (memory == nullptr) {
1082 ALOGD("[%s] Failed to allocate memory from dealer: only %zu slots allocated",
1083 mName, i);
1084 break;
1085 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001086 mMemoryVector->push_back({std::weak_ptr<C2LinearBlock>(), memory, heapSeqNum});
Wonsik Kim469c8342019-04-11 16:46:09 -07001087 }
1088}
1089
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001090std::unique_ptr<InputBuffers> EncryptedLinearInputBuffers::toArrayMode(size_t size) {
1091 std::unique_ptr<InputBuffersArray> array(
1092 new InputBuffersArray(mComponentName.c_str(), "1D-EncryptedInput[N]"));
1093 array->setPool(mPool);
1094 array->setFormat(mFormat);
1095 array->initialize(
1096 mImpl,
1097 size,
1098 [pool = mPool,
1099 format = mFormat,
1100 usage = mUsage,
1101 memoryVector = mMemoryVector] () -> sp<Codec2Buffer> {
1102 return Alloc(pool, format, usage, memoryVector);
1103 });
1104 return std::move(array);
1105}
1106
1107
1108// static
1109sp<Codec2Buffer> EncryptedLinearInputBuffers::Alloc(
1110 const std::shared_ptr<C2BlockPool> &pool,
1111 const sp<AMessage> &format,
1112 C2MemoryUsage usage,
1113 const std::shared_ptr<std::vector<EncryptedLinearInputBuffers::Entry>> &memoryVector) {
1114 int32_t capacity = kLinearBufferSize;
1115 (void)format->findInt32(KEY_MAX_INPUT_SIZE, &capacity);
1116 if ((size_t)capacity > kMaxLinearBufferSize) {
1117 ALOGD("client requested %d, capped to %zu", capacity, kMaxLinearBufferSize);
1118 capacity = kMaxLinearBufferSize;
1119 }
1120
Wonsik Kim469c8342019-04-11 16:46:09 -07001121 sp<IMemory> memory;
1122 size_t slot = 0;
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001123 int32_t heapSeqNum = -1;
1124 for (; slot < memoryVector->size(); ++slot) {
1125 if (memoryVector->at(slot).block.expired()) {
1126 memory = memoryVector->at(slot).memory;
1127 heapSeqNum = memoryVector->at(slot).heapSeqNum;
Wonsik Kim469c8342019-04-11 16:46:09 -07001128 break;
1129 }
1130 }
1131 if (memory == nullptr) {
1132 return nullptr;
1133 }
1134
David Stevens94b608f2021-07-29 15:04:14 +09001135 int64_t usageValue = 0;
1136 (void)format->findInt64("android._C2MemoryUsage", &usageValue);
1137 usage = C2MemoryUsage(usage.expected | usageValue);
1138
Wonsik Kim469c8342019-04-11 16:46:09 -07001139 std::shared_ptr<C2LinearBlock> block;
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001140 c2_status_t err = pool->fetchLinearBlock(capacity, usage, &block);
Wonsik Kim469c8342019-04-11 16:46:09 -07001141 if (err != C2_OK || block == nullptr) {
1142 return nullptr;
1143 }
1144
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001145 memoryVector->at(slot).block = block;
1146 return new EncryptedLinearBlockBuffer(format, block, memory, heapSeqNum);
1147}
1148
1149sp<Codec2Buffer> EncryptedLinearInputBuffers::createNewBuffer() {
1150 // TODO: android_2020
1151 return nullptr;
Wonsik Kim469c8342019-04-11 16:46:09 -07001152}
1153
1154// GraphicMetadataInputBuffers
1155
1156GraphicMetadataInputBuffers::GraphicMetadataInputBuffers(
1157 const char *componentName, const char *name)
1158 : InputBuffers(componentName, name),
1159 mImpl(mName),
1160 mStore(GetCodec2PlatformAllocatorStore()) { }
1161
1162bool GraphicMetadataInputBuffers::requestNewBuffer(
1163 size_t *index, sp<MediaCodecBuffer> *buffer) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001164 sp<Codec2Buffer> newBuffer = createNewBuffer();
Wonsik Kim469c8342019-04-11 16:46:09 -07001165 if (newBuffer == nullptr) {
1166 return false;
1167 }
1168 *index = mImpl.assignSlot(newBuffer);
1169 *buffer = newBuffer;
1170 return true;
1171}
1172
1173bool GraphicMetadataInputBuffers::releaseBuffer(
1174 const sp<MediaCodecBuffer> &buffer,
1175 std::shared_ptr<C2Buffer> *c2buffer,
1176 bool release) {
1177 return mImpl.releaseSlot(buffer, c2buffer, release);
1178}
1179
1180bool GraphicMetadataInputBuffers::expireComponentBuffer(
1181 const std::shared_ptr<C2Buffer> &c2buffer) {
1182 return mImpl.expireComponentBuffer(c2buffer);
1183}
1184
1185void GraphicMetadataInputBuffers::flush() {
1186 // This is no-op by default unless we're in array mode where we need to keep
1187 // track of the flushed work.
1188}
1189
1190std::unique_ptr<InputBuffers> GraphicMetadataInputBuffers::toArrayMode(
1191 size_t size) {
1192 std::shared_ptr<C2Allocator> alloc;
1193 c2_status_t err = mStore->fetchAllocator(mPool->getAllocatorId(), &alloc);
1194 if (err != C2_OK) {
1195 return nullptr;
1196 }
1197 std::unique_ptr<InputBuffersArray> array(
1198 new InputBuffersArray(mComponentName.c_str(), "2D-MetaInput[N]"));
1199 array->setPool(mPool);
1200 array->setFormat(mFormat);
1201 array->initialize(
1202 mImpl,
1203 size,
1204 [format = mFormat, alloc]() -> sp<Codec2Buffer> {
1205 return new GraphicMetadataBuffer(format, alloc);
1206 });
1207 return std::move(array);
1208}
1209
Wonsik Kim0487b782020-10-28 11:45:50 -07001210size_t GraphicMetadataInputBuffers::numActiveSlots() const {
1211 return mImpl.numActiveSlots();
Wonsik Kim469c8342019-04-11 16:46:09 -07001212}
1213
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001214sp<Codec2Buffer> GraphicMetadataInputBuffers::createNewBuffer() {
1215 std::shared_ptr<C2Allocator> alloc;
1216 c2_status_t err = mStore->fetchAllocator(mPool->getAllocatorId(), &alloc);
1217 if (err != C2_OK) {
1218 return nullptr;
1219 }
1220 return new GraphicMetadataBuffer(mFormat, alloc);
1221}
1222
Wonsik Kim469c8342019-04-11 16:46:09 -07001223// GraphicInputBuffers
1224
1225GraphicInputBuffers::GraphicInputBuffers(
Wonsik Kim41d83432020-04-27 16:40:49 -07001226 const char *componentName, const char *name)
Wonsik Kim469c8342019-04-11 16:46:09 -07001227 : InputBuffers(componentName, name),
1228 mImpl(mName),
Songyue Han1e6769b2023-08-30 18:09:27 +00001229 mLocalBufferPool(LocalBufferPool::Create()),
1230 mPixelFormat(PIXEL_FORMAT_UNKNOWN) { }
Wonsik Kim469c8342019-04-11 16:46:09 -07001231
1232bool GraphicInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001233 sp<Codec2Buffer> newBuffer = createNewBuffer();
Wonsik Kim469c8342019-04-11 16:46:09 -07001234 if (newBuffer == nullptr) {
1235 return false;
1236 }
1237 *index = mImpl.assignSlot(newBuffer);
1238 handleImageData(newBuffer);
1239 *buffer = newBuffer;
1240 return true;
1241}
1242
1243bool GraphicInputBuffers::releaseBuffer(
1244 const sp<MediaCodecBuffer> &buffer,
1245 std::shared_ptr<C2Buffer> *c2buffer,
1246 bool release) {
1247 return mImpl.releaseSlot(buffer, c2buffer, release);
1248}
1249
1250bool GraphicInputBuffers::expireComponentBuffer(
1251 const std::shared_ptr<C2Buffer> &c2buffer) {
1252 return mImpl.expireComponentBuffer(c2buffer);
1253}
1254
1255void GraphicInputBuffers::flush() {
1256 // This is no-op by default unless we're in array mode where we need to keep
1257 // track of the flushed work.
1258}
1259
Wonsik Kimd79ee1f2020-08-27 17:41:56 -07001260static uint32_t extractPixelFormat(const sp<AMessage> &format) {
1261 int32_t frameworkColorFormat = 0;
1262 if (!format->findInt32("android._color-format", &frameworkColorFormat)) {
1263 return PIXEL_FORMAT_UNKNOWN;
1264 }
1265 uint32_t pixelFormat = PIXEL_FORMAT_UNKNOWN;
1266 if (C2Mapper::mapPixelFormatFrameworkToCodec(frameworkColorFormat, &pixelFormat)) {
1267 return pixelFormat;
1268 }
1269 return PIXEL_FORMAT_UNKNOWN;
1270}
1271
Wonsik Kim469c8342019-04-11 16:46:09 -07001272std::unique_ptr<InputBuffers> GraphicInputBuffers::toArrayMode(size_t size) {
1273 std::unique_ptr<InputBuffersArray> array(
1274 new InputBuffersArray(mComponentName.c_str(), "2D-BB-Input[N]"));
1275 array->setPool(mPool);
1276 array->setFormat(mFormat);
Wonsik Kimd79ee1f2020-08-27 17:41:56 -07001277 uint32_t pixelFormat = extractPixelFormat(mFormat);
Wonsik Kim469c8342019-04-11 16:46:09 -07001278 array->initialize(
1279 mImpl,
1280 size,
Wonsik Kimd79ee1f2020-08-27 17:41:56 -07001281 [pool = mPool, format = mFormat, lbp = mLocalBufferPool, pixelFormat]()
1282 -> sp<Codec2Buffer> {
Wonsik Kim469c8342019-04-11 16:46:09 -07001283 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
David Stevens94b608f2021-07-29 15:04:14 +09001284 return AllocateInputGraphicBuffer(
Wonsik Kimd79ee1f2020-08-27 17:41:56 -07001285 pool, format, pixelFormat, usage, lbp);
Wonsik Kim469c8342019-04-11 16:46:09 -07001286 });
1287 return std::move(array);
1288}
1289
Wonsik Kim0487b782020-10-28 11:45:50 -07001290size_t GraphicInputBuffers::numActiveSlots() const {
1291 return mImpl.numActiveSlots();
Wonsik Kim469c8342019-04-11 16:46:09 -07001292}
1293
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001294sp<Codec2Buffer> GraphicInputBuffers::createNewBuffer() {
David Stevens94b608f2021-07-29 15:04:14 +09001295 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
Songyue Han1e6769b2023-08-30 18:09:27 +00001296 mPixelFormat = extractPixelFormat(mFormat);
David Stevens94b608f2021-07-29 15:04:14 +09001297 return AllocateInputGraphicBuffer(
Songyue Han1e6769b2023-08-30 18:09:27 +00001298 mPool, mFormat, mPixelFormat, usage, mLocalBufferPool);
1299}
1300
1301uint32_t GraphicInputBuffers::getPixelFormatIfApplicable() { return mPixelFormat; }
1302
1303bool GraphicInputBuffers::resetPixelFormatIfApplicable() {
1304 mPixelFormat = PIXEL_FORMAT_UNKNOWN;
1305 return true;
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001306}
1307
Wonsik Kim469c8342019-04-11 16:46:09 -07001308// OutputBuffersArray
1309
1310void OutputBuffersArray::initialize(
1311 const FlexBuffersImpl &impl,
1312 size_t minSize,
1313 std::function<sp<Codec2Buffer>()> allocate) {
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001314 mAlloc = allocate;
Wonsik Kim469c8342019-04-11 16:46:09 -07001315 mImpl.initialize(impl, minSize, allocate);
1316}
1317
1318status_t OutputBuffersArray::registerBuffer(
1319 const std::shared_ptr<C2Buffer> &buffer,
1320 size_t *index,
1321 sp<MediaCodecBuffer> *clientBuffer) {
1322 sp<Codec2Buffer> c2Buffer;
1323 status_t err = mImpl.grabBuffer(
1324 index,
1325 &c2Buffer,
1326 [buffer](const sp<Codec2Buffer> &clientBuffer) {
1327 return clientBuffer->canCopy(buffer);
1328 });
1329 if (err == WOULD_BLOCK) {
1330 ALOGV("[%s] buffers temporarily not available", mName);
1331 return err;
1332 } else if (err != OK) {
1333 ALOGD("[%s] grabBuffer failed: %d", mName, err);
1334 return err;
1335 }
1336 c2Buffer->setFormat(mFormat);
Wonsik Kim6f23cfc2021-09-24 05:45:52 -07001337 if (!convert(buffer, &c2Buffer) && !c2Buffer->copy(buffer)) {
Wonsik Kim469c8342019-04-11 16:46:09 -07001338 ALOGD("[%s] copy buffer failed", mName);
1339 return WOULD_BLOCK;
1340 }
Arun Johnsonf4a81f72023-11-09 21:22:48 +00001341 if (buffer && buffer->hasInfo(C2AccessUnitInfos::output::PARAM_TYPE)) {
1342 std::shared_ptr<const C2AccessUnitInfos::output> bufferMetadata =
1343 std::static_pointer_cast<const C2AccessUnitInfos::output>(
1344 buffer->getInfo(C2AccessUnitInfos::output::PARAM_TYPE));
1345 if (submit(c2Buffer, mSampleRate, mChannelCount, bufferMetadata)) {
1346 buffer->removeInfo(C2AccessUnitInfos::output::PARAM_TYPE);
1347 }
1348 } else {
1349 submit(c2Buffer);
1350 }
Wonsik Kim469c8342019-04-11 16:46:09 -07001351 handleImageData(c2Buffer);
1352 *clientBuffer = c2Buffer;
1353 ALOGV("[%s] grabbed buffer %zu", mName, *index);
1354 return OK;
1355}
1356
1357status_t OutputBuffersArray::registerCsd(
1358 const C2StreamInitDataInfo::output *csd,
1359 size_t *index,
1360 sp<MediaCodecBuffer> *clientBuffer) {
1361 sp<Codec2Buffer> c2Buffer;
1362 status_t err = mImpl.grabBuffer(
1363 index,
1364 &c2Buffer,
1365 [csd](const sp<Codec2Buffer> &clientBuffer) {
1366 return clientBuffer->base() != nullptr
1367 && clientBuffer->capacity() >= csd->flexCount();
1368 });
1369 if (err != OK) {
1370 return err;
1371 }
1372 memcpy(c2Buffer->base(), csd->m.value, csd->flexCount());
1373 c2Buffer->setRange(0, csd->flexCount());
1374 c2Buffer->setFormat(mFormat);
1375 *clientBuffer = c2Buffer;
1376 return OK;
1377}
1378
1379bool OutputBuffersArray::releaseBuffer(
1380 const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) {
1381 return mImpl.returnBuffer(buffer, c2buffer, true);
1382}
1383
1384void OutputBuffersArray::flush(const std::list<std::unique_ptr<C2Work>> &flushedWork) {
1385 (void)flushedWork;
1386 mImpl.flush();
1387 if (mSkipCutBuffer != nullptr) {
Arun Johnsond43dc8c2024-02-07 01:14:15 +00001388 mSkipCutBuffer->clearAll();
Wonsik Kim469c8342019-04-11 16:46:09 -07001389 }
1390}
1391
1392void OutputBuffersArray::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
1393 mImpl.getArray(array);
1394}
1395
Wonsik Kim0487b782020-10-28 11:45:50 -07001396size_t OutputBuffersArray::numActiveSlots() const {
1397 return mImpl.numActiveSlots();
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001398}
1399
Wonsik Kim469c8342019-04-11 16:46:09 -07001400void OutputBuffersArray::realloc(const std::shared_ptr<C2Buffer> &c2buffer) {
Wonsik Kim469c8342019-04-11 16:46:09 -07001401 switch (c2buffer->data().type()) {
1402 case C2BufferData::LINEAR: {
1403 uint32_t size = kLinearBufferSize;
Nick Desaulniersd09eaea2019-10-07 20:19:39 -07001404 const std::vector<C2ConstLinearBlock> &linear_blocks = c2buffer->data().linearBlocks();
1405 const uint32_t block_size = linear_blocks.front().size();
1406 if (block_size < kMaxLinearBufferSize / 2) {
1407 size = block_size * 2;
Wonsik Kim469c8342019-04-11 16:46:09 -07001408 } else {
1409 size = kMaxLinearBufferSize;
1410 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001411 mAlloc = [format = mFormat, size] {
Wonsik Kim469c8342019-04-11 16:46:09 -07001412 return new LocalLinearBuffer(format, new ABuffer(size));
1413 };
Wonsik Kima39882b2019-06-20 16:13:56 -07001414 ALOGD("[%s] reallocating with linear buffer of size %u", mName, size);
Wonsik Kim469c8342019-04-11 16:46:09 -07001415 break;
1416 }
1417
Wonsik Kima39882b2019-06-20 16:13:56 -07001418 case C2BufferData::GRAPHIC: {
1419 // This is only called for RawGraphicOutputBuffers.
1420 mAlloc = [format = mFormat,
Wonsik Kim41d83432020-04-27 16:40:49 -07001421 lbp = LocalBufferPool::Create()] {
Wonsik Kima39882b2019-06-20 16:13:56 -07001422 return ConstGraphicBlockBuffer::AllocateEmpty(
1423 format,
1424 [lbp](size_t capacity) {
1425 return lbp->newBuffer(capacity);
1426 });
1427 };
1428 ALOGD("[%s] reallocating with graphic buffer: format = %s",
1429 mName, mFormat->debugString().c_str());
1430 break;
1431 }
Wonsik Kim469c8342019-04-11 16:46:09 -07001432
1433 case C2BufferData::INVALID: [[fallthrough]];
1434 case C2BufferData::LINEAR_CHUNKS: [[fallthrough]];
1435 case C2BufferData::GRAPHIC_CHUNKS: [[fallthrough]];
1436 default:
1437 ALOGD("Unsupported type: %d", (int)c2buffer->data().type());
1438 return;
1439 }
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001440 mImpl.realloc(mAlloc);
Wonsik Kim469c8342019-04-11 16:46:09 -07001441}
1442
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001443void OutputBuffersArray::grow(size_t newSize) {
1444 mImpl.grow(newSize, mAlloc);
Wonsik Kim469c8342019-04-11 16:46:09 -07001445}
1446
Pawin Vongmasa9b906982020-04-11 05:07:15 -07001447void OutputBuffersArray::transferFrom(OutputBuffers* source) {
1448 mFormat = source->mFormat;
1449 mSkipCutBuffer = source->mSkipCutBuffer;
Pawin Vongmasa9b906982020-04-11 05:07:15 -07001450 mPending = std::move(source->mPending);
1451 mReorderStash = std::move(source->mReorderStash);
1452 mDepth = source->mDepth;
1453 mKey = source->mKey;
1454}
1455
Wonsik Kim469c8342019-04-11 16:46:09 -07001456// FlexOutputBuffers
1457
1458status_t FlexOutputBuffers::registerBuffer(
1459 const std::shared_ptr<C2Buffer> &buffer,
1460 size_t *index,
1461 sp<MediaCodecBuffer> *clientBuffer) {
Wonsik Kim6f23cfc2021-09-24 05:45:52 -07001462 sp<Codec2Buffer> newBuffer;
1463 if (!convert(buffer, &newBuffer)) {
1464 newBuffer = wrap(buffer);
1465 if (newBuffer == nullptr) {
1466 return NO_MEMORY;
1467 }
Wonsik Kim360ba0a2022-05-23 15:38:21 -07001468 newBuffer->setFormat(mFormat);
Wonsik Kim469c8342019-04-11 16:46:09 -07001469 }
Wonsik Kim469c8342019-04-11 16:46:09 -07001470 *index = mImpl.assignSlot(newBuffer);
1471 handleImageData(newBuffer);
1472 *clientBuffer = newBuffer;
Songyue Han1e6769b2023-08-30 18:09:27 +00001473
1474 extractPixelFormatFromC2Buffer(buffer);
Wonsik Kim469c8342019-04-11 16:46:09 -07001475 ALOGV("[%s] registered buffer %zu", mName, *index);
1476 return OK;
1477}
1478
1479status_t FlexOutputBuffers::registerCsd(
1480 const C2StreamInitDataInfo::output *csd,
1481 size_t *index,
1482 sp<MediaCodecBuffer> *clientBuffer) {
1483 sp<Codec2Buffer> newBuffer = new LocalLinearBuffer(
1484 mFormat, ABuffer::CreateAsCopy(csd->m.value, csd->flexCount()));
1485 *index = mImpl.assignSlot(newBuffer);
1486 *clientBuffer = newBuffer;
1487 return OK;
1488}
1489
1490bool FlexOutputBuffers::releaseBuffer(
1491 const sp<MediaCodecBuffer> &buffer,
1492 std::shared_ptr<C2Buffer> *c2buffer) {
1493 return mImpl.releaseSlot(buffer, c2buffer, true);
1494}
1495
1496void FlexOutputBuffers::flush(
1497 const std::list<std::unique_ptr<C2Work>> &flushedWork) {
1498 (void) flushedWork;
1499 // This is no-op by default unless we're in array mode where we need to keep
1500 // track of the flushed work.
1501}
1502
Pawin Vongmasa9b906982020-04-11 05:07:15 -07001503std::unique_ptr<OutputBuffersArray> FlexOutputBuffers::toArrayMode(size_t size) {
Wonsik Kim469c8342019-04-11 16:46:09 -07001504 std::unique_ptr<OutputBuffersArray> array(new OutputBuffersArray(mComponentName.c_str()));
Pawin Vongmasa9b906982020-04-11 05:07:15 -07001505 array->transferFrom(this);
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001506 std::function<sp<Codec2Buffer>()> alloc = getAlloc();
1507 array->initialize(mImpl, size, alloc);
Pawin Vongmasa9b906982020-04-11 05:07:15 -07001508 return array;
Wonsik Kim469c8342019-04-11 16:46:09 -07001509}
1510
Wonsik Kim0487b782020-10-28 11:45:50 -07001511size_t FlexOutputBuffers::numActiveSlots() const {
1512 return mImpl.numActiveSlots();
Wonsik Kim469c8342019-04-11 16:46:09 -07001513}
1514
Songyue Han1e6769b2023-08-30 18:09:27 +00001515bool FlexOutputBuffers::extractPixelFormatFromC2Buffer(const std::shared_ptr<C2Buffer> &buffer) {
1516 if (buffer == nullptr) {
1517 return false;
1518 }
1519 const C2BufferData &data = buffer->data();
1520 // only extract the first pixel format in a metric session.
1521 if (mPixelFormat != PIXEL_FORMAT_UNKNOWN || data.type() != C2BufferData::GRAPHIC
1522 || data.graphicBlocks().empty()) {
1523 return false;
1524 }
1525 const C2Handle *const handle = data.graphicBlocks().front().handle();
1526 uint32_t pf = ExtractFormatFromCodec2GrallocHandle(handle);
1527 if (pf == PIXEL_FORMAT_UNKNOWN) {
1528 return false;
1529 }
1530 mPixelFormat = pf;
1531 return true;
1532}
1533
1534bool FlexOutputBuffers::resetPixelFormatIfApplicable() {
1535 mPixelFormat = PIXEL_FORMAT_UNKNOWN;
1536 return true;
1537}
1538
1539uint32_t FlexOutputBuffers::getPixelFormatIfApplicable() { return mPixelFormat; }
1540
Wonsik Kim469c8342019-04-11 16:46:09 -07001541// LinearOutputBuffers
1542
1543void LinearOutputBuffers::flush(
1544 const std::list<std::unique_ptr<C2Work>> &flushedWork) {
1545 if (mSkipCutBuffer != nullptr) {
Arun Johnsond43dc8c2024-02-07 01:14:15 +00001546 mSkipCutBuffer->clearAll();
Wonsik Kim469c8342019-04-11 16:46:09 -07001547 }
1548 FlexOutputBuffers::flush(flushedWork);
1549}
1550
1551sp<Codec2Buffer> LinearOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
1552 if (buffer == nullptr) {
Wonsik Kim68af8e52024-04-11 17:57:57 +00001553 ALOGD("[%s] received null buffer", mName);
Wonsik Kim469c8342019-04-11 16:46:09 -07001554 return new LocalLinearBuffer(mFormat, new ABuffer(0));
1555 }
1556 if (buffer->data().type() != C2BufferData::LINEAR) {
Wonsik Kim68af8e52024-04-11 17:57:57 +00001557 ALOGW("[%s] non-linear buffer %d", mName, buffer->data().type());
Wonsik Kim469c8342019-04-11 16:46:09 -07001558 // We expect linear output buffers from the component.
1559 return nullptr;
1560 }
1561 if (buffer->data().linearBlocks().size() != 1u) {
Wonsik Kim68af8e52024-04-11 17:57:57 +00001562 ALOGW("[%s] no linear buffers", mName);
Wonsik Kim469c8342019-04-11 16:46:09 -07001563 // We expect one and only one linear block from the component.
1564 return nullptr;
1565 }
Wonsik Kim68af8e52024-04-11 17:57:57 +00001566 if (buffer->data().linearBlocks().front().size() == 0) {
1567 ALOGD("[%s] received 0-sized buffer", mName);
1568 return new LocalLinearBuffer(mFormat, new ABuffer(0));
1569 }
Wonsik Kim469c8342019-04-11 16:46:09 -07001570 sp<Codec2Buffer> clientBuffer = ConstLinearBlockBuffer::Allocate(mFormat, buffer);
1571 if (clientBuffer == nullptr) {
1572 ALOGD("[%s] ConstLinearBlockBuffer::Allocate failed", mName);
1573 return nullptr;
1574 }
1575 submit(clientBuffer);
1576 return clientBuffer;
1577}
1578
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001579std::function<sp<Codec2Buffer>()> LinearOutputBuffers::getAlloc() {
1580 return [format = mFormat]{
1581 // TODO: proper max output size
1582 return new LocalLinearBuffer(format, new ABuffer(kLinearBufferSize));
1583 };
Wonsik Kim469c8342019-04-11 16:46:09 -07001584}
1585
1586// GraphicOutputBuffers
1587
1588sp<Codec2Buffer> GraphicOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
1589 return new DummyContainerBuffer(mFormat, buffer);
1590}
1591
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001592std::function<sp<Codec2Buffer>()> GraphicOutputBuffers::getAlloc() {
1593 return [format = mFormat]{
1594 return new DummyContainerBuffer(format);
1595 };
Wonsik Kim469c8342019-04-11 16:46:09 -07001596}
1597
1598// RawGraphicOutputBuffers
1599
1600RawGraphicOutputBuffers::RawGraphicOutputBuffers(
Wonsik Kim41d83432020-04-27 16:40:49 -07001601 const char *componentName, const char *name)
Wonsik Kim469c8342019-04-11 16:46:09 -07001602 : FlexOutputBuffers(componentName, name),
Wonsik Kim41d83432020-04-27 16:40:49 -07001603 mLocalBufferPool(LocalBufferPool::Create()) { }
Wonsik Kim469c8342019-04-11 16:46:09 -07001604
1605sp<Codec2Buffer> RawGraphicOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
1606 if (buffer == nullptr) {
Wonsik Kim6f116902021-07-14 08:58:07 -07001607 return new Codec2Buffer(mFormat, new ABuffer(nullptr, 0));
Wonsik Kim469c8342019-04-11 16:46:09 -07001608 } else {
1609 return ConstGraphicBlockBuffer::Allocate(
1610 mFormat,
1611 buffer,
1612 [lbp = mLocalBufferPool](size_t capacity) {
1613 return lbp->newBuffer(capacity);
1614 });
1615 }
1616}
1617
Wonsik Kim5ecf3832019-04-18 10:28:58 -07001618std::function<sp<Codec2Buffer>()> RawGraphicOutputBuffers::getAlloc() {
1619 return [format = mFormat, lbp = mLocalBufferPool]{
1620 return ConstGraphicBlockBuffer::AllocateEmpty(
1621 format,
1622 [lbp](size_t capacity) {
1623 return lbp->newBuffer(capacity);
1624 });
1625 };
Wonsik Kim469c8342019-04-11 16:46:09 -07001626}
1627
1628} // namespace android