1 /*
2 * Copyright 2019, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 //#define LOG_NDEBUG 0
18 #define LOG_TAG "CCodecBuffers"
19 #include <utils/Log.h>
20
21 #include <numeric>
22
23 #include <C2AllocatorGralloc.h>
24 #include <C2PlatformSupport.h>
25
26 #include <media/stagefright/foundation/ADebug.h>
27 #include <media/stagefright/foundation/AUtils.h>
28 #include <media/stagefright/foundation/MediaDefs.h>
29 #include <media/stagefright/CodecBase.h>
30 #include <media/stagefright/MediaCodecConstants.h>
31 #include <media/stagefright/SkipCutBuffer.h>
32 #include <mediadrm/ICrypto.h>
33
34 #include "CCodecBuffers.h"
35 #include "Codec2Mapper.h"
36
37 namespace android {
38
39 namespace {
40
41 constexpr uint32_t PIXEL_FORMAT_UNKNOWN = 0;
42
AllocateInputGraphicBuffer(const std::shared_ptr<C2BlockPool> & pool,const sp<AMessage> & format,uint32_t pixelFormat,const C2MemoryUsage & usage,const std::shared_ptr<LocalBufferPool> & localBufferPool)43 sp<GraphicBlockBuffer> AllocateInputGraphicBuffer(
44 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
55 int64_t usageValue = 0;
56 (void)format->findInt64("android._C2MemoryUsage", &usageValue);
57 C2MemoryUsage fullUsage{usageValue | usage.expected};
58
59 std::shared_ptr<C2GraphicBlock> block;
60 c2_status_t err = pool->fetchGraphicBlock(
61 align(width, 2), align(height, 2), pixelFormat, fullUsage, &block);
62 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
setFormat(const sp<AMessage> & format)79 void CCodecBuffers::setFormat(const sp<AMessage> &format) {
80 CHECK(format != nullptr);
81 mFormat = format;
82 }
83
dupFormat()84 sp<AMessage> CCodecBuffers::dupFormat() {
85 return mFormat != nullptr ? mFormat->dup() : nullptr;
86 }
87
handleImageData(const sp<Codec2Buffer> & buffer)88 void CCodecBuffers::handleImageData(const sp<Codec2Buffer> &buffer) {
89 sp<ABuffer> imageDataCandidate = buffer->getImageData();
90 if (imageDataCandidate == nullptr) {
91 if (mFormatWithImageData) {
92 // We previously sent the format with image data, so use the same format.
93 buffer->setFormat(mFormatWithImageData);
94 }
95 return;
96 }
97 if (!mLastImageData
98 || imageDataCandidate->size() != mLastImageData->size()
99 || memcmp(imageDataCandidate->data(),
100 mLastImageData->data(),
101 mLastImageData->size()) != 0) {
102 ALOGD("[%s] updating image-data", mName);
103 mFormatWithImageData = dupFormat();
104 mLastImageData = imageDataCandidate;
105 mFormatWithImageData->setBuffer("image-data", imageDataCandidate);
106 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;
109 mFormatWithImageData->setInt32(KEY_STRIDE, stride);
110 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);
114 if (img->mNumPlanes > 1 && stride > 0) {
115 int64_t offsetDelta =
116 (int64_t)img->mPlane[1].mOffset - (int64_t)img->mPlane[0].mOffset;
117 int32_t vstride = int32_t(offsetDelta / stride);
118 mFormatWithImageData->setInt32(KEY_SLICE_HEIGHT, vstride);
119 ALOGD("[%s] updating vstride = %d", mName, vstride);
120 buffer->setRange(
121 img->mPlane[0].mOffset,
122 buffer->size() - img->mPlane[0].mOffset);
123 }
124 }
125 }
126 buffer->setFormat(mFormatWithImageData);
127 }
128
getPixelFormatIfApplicable()129 uint32_t CCodecBuffers::getPixelFormatIfApplicable() { return PIXEL_FORMAT_UNKNOWN; }
130
resetPixelFormatIfApplicable()131 bool CCodecBuffers::resetPixelFormatIfApplicable() { return false; }
132
133 // InputBuffers
134
cloneAndReleaseBuffer(const sp<MediaCodecBuffer> & buffer)135 sp<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 }
150 copy->meta()->extend(buffer->meta());
151 return copy;
152 }
153
154 // MultiAccessUnitSkipCutBuffer for buffer and bufferInfos
155
156 class MultiAccessUnitSkipCutBuffer : public SkipCutBuffer {
157
158 public:
MultiAccessUnitSkipCutBuffer(int32_t skip,int32_t cut,size_t num16BitChannels)159 explicit MultiAccessUnitSkipCutBuffer(
160 int32_t skip, int32_t cut, size_t num16BitChannels):
161 SkipCutBuffer(skip, cut, num16BitChannels),
162 mFrontPaddingDelay(0), mSize(0) {
163 }
clearAll()164 void clearAll() {
165 mInfos.clear();
166 mFrontPaddingDelay = 0;
167 mSize = 0;
168 SkipCutBuffer::clear();
169 }
170
~MultiAccessUnitSkipCutBuffer()171 virtual ~MultiAccessUnitSkipCutBuffer() {
172
173 }
174
submitMultiAccessUnits(const sp<MediaCodecBuffer> & buffer,int32_t sampleRate,size_t num16BitChannels,std::shared_ptr<const C2AccessUnitInfos::output> & infos)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 }
296 protected:
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
toMediaCodecFlags(uint32_t flags)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
319 // OutputBuffers
320
OutputBuffers(const char * componentName,const char * name)321 OutputBuffers::OutputBuffers(const char *componentName, const char *name)
322 : CCodecBuffers(componentName, name) { }
323
324 OutputBuffers::~OutputBuffers() = default;
325
initSkipCutBuffer(int32_t delay,int32_t padding,int32_t sampleRate,int32_t channelCount)326 void 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;
332 mChannelCount = channelCount;
333 setSkipCutBuffer(delay, padding);
334 }
335
updateSkipCutBuffer(int32_t sampleRate,int32_t channelCount)336 void OutputBuffers::updateSkipCutBuffer(int32_t sampleRate, int32_t channelCount) {
337 if (mSkipCutBuffer == nullptr) {
338 return;
339 }
340 if (mSampleRate == sampleRate && mChannelCount == channelCount) {
341 return;
342 }
343 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 }
349 mSampleRate = sampleRate;
350 mChannelCount = channelCount;
351 setSkipCutBuffer(delay, padding);
352 }
353
updateSkipCutBuffer(const sp<AMessage> & format)354 void OutputBuffers::updateSkipCutBuffer(const sp<AMessage> &format) {
355 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 }
365 }
366
submit(const sp<MediaCodecBuffer> & buffer)367 void OutputBuffers::submit(const sp<MediaCodecBuffer> &buffer) {
368 if (mSkipCutBuffer != nullptr) {
369 mSkipCutBuffer->submit(buffer);
370 }
371 }
372
submit(const sp<MediaCodecBuffer> & buffer,int32_t sampleRate,int32_t channelCount,std::shared_ptr<const C2AccessUnitInfos::output> & infos)373 bool 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
setSkipCutBuffer(int32_t skip,int32_t cut)382 void OutputBuffers::setSkipCutBuffer(int32_t skip, int32_t cut) {
383 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 }
389 mSkipCutBuffer = new MultiAccessUnitSkipCutBuffer(skip, cut, mChannelCount);
390 }
391
convert(const std::shared_ptr<C2Buffer> & src,sp<Codec2Buffer> * dst)392 bool OutputBuffers::convert(
393 const std::shared_ptr<C2Buffer> &src, sp<Codec2Buffer> *dst) {
394 if (src && src->data().type() != C2BufferData::LINEAR) {
395 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 }
423 sp<MediaCodecBuffer> srcBuffer;
424 if (src) {
425 srcBuffer = ConstLinearBlockBuffer::Allocate(mFormat, src);
426 } else {
427 srcBuffer = new MediaCodecBuffer(mFormat, new ABuffer(0));
428 }
429 if (!srcBuffer) {
430 return false;
431 }
432 if (!*dst) {
433 *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
clearStash()447 void OutputBuffers::clearStash() {
448 mPending.clear();
449 mReorderStash.clear();
450 mDepth = 0;
451 mKey = C2Config::ORDINAL;
452 }
453
flushStash()454 void OutputBuffers::flushStash() {
455 for (StashEntry& e : mPending) {
456 e.notify = false;
457 }
458 for (StashEntry& e : mReorderStash) {
459 e.notify = false;
460 }
461 }
462
getReorderDepth() const463 uint32_t OutputBuffers::getReorderDepth() const {
464 return mDepth;
465 }
466
setReorderDepth(uint32_t depth)467 void OutputBuffers::setReorderDepth(uint32_t depth) {
468 mPending.splice(mPending.end(), mReorderStash);
469 mDepth = depth;
470 }
471
setReorderKey(C2Config::ordinal_key_t key)472 void OutputBuffers::setReorderKey(C2Config::ordinal_key_t key) {
473 mPending.splice(mPending.end(), mReorderStash);
474 mKey = key;
475 }
476
pushToStash(const std::shared_ptr<C2Buffer> & buffer,bool notify,int64_t timestamp,int32_t flags,const sp<AMessage> & format,const C2WorkOrdinalStruct & ordinal)477 void 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) {
484 bool eos = flags & BUFFER_FLAG_END_OF_STREAM;
485 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 {
492 flags = flags & ~BUFFER_FLAG_END_OF_STREAM;
493 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 =
503 mReorderStash.back().flags | BUFFER_FLAG_END_OF_STREAM;
504 }
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
popFromStashAndRegister(std::shared_ptr<C2Buffer> * c2Buffer,size_t * index,sp<MediaCodecBuffer> * outBuffer)513 OutputBuffers::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
527 if (entry.notify && mFormat != outputFormat) {
528 updateSkipCutBuffer(outputFormat);
529 // Trigger image data processing to the new format
530 mLastImageData.clear();
531 ALOGV("[%s] popFromStashAndRegister: output format reference changed: %p -> %p",
532 mName, mFormat.get(), outputFormat.get());
533 ALOGD("[%s] popFromStashAndRegister: at %lldus, output format changed to %s",
534 mName, (long long)entry.timestamp, outputFormat->debugString().c_str());
535 setFormat(outputFormat);
536 }
537
538 // Flushing mReorderStash because no other buffers should come after output
539 // EOS.
540 if (entry.flags & BUFFER_FLAG_END_OF_STREAM) {
541 // 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);
562 (*outBuffer)->meta()->setInt64("frameIndex", entry.ordinal.frameIndex.peekll());
563 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
popPending(StashEntry * entry)575 bool 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
deferPending(const OutputBuffers::StashEntry & entry)584 void OutputBuffers::deferPending(const OutputBuffers::StashEntry &entry) {
585 mPending.push_front(entry);
586 }
587
hasPending() const588 bool OutputBuffers::hasPending() const {
589 return !mPending.empty();
590 }
591
less(const C2WorkOrdinalStruct & o1,const C2WorkOrdinalStruct & o2) const592 bool 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
604 // LocalBufferPool
605
606 constexpr size_t kInitialPoolCapacity = kMaxLinearBufferSize;
607 constexpr size_t kMaxPoolCapacity = kMaxLinearBufferSize * 32;
608
Create()609 std::shared_ptr<LocalBufferPool> LocalBufferPool::Create() {
610 return std::shared_ptr<LocalBufferPool>(new LocalBufferPool(kInitialPoolCapacity));
611 }
612
newBuffer(size_t capacity)613 sp<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 }
630 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 }
635 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
VectorBuffer(std::vector<uint8_t> && vec,const std::shared_ptr<LocalBufferPool> & pool)646 LocalBufferPool::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
~VectorBuffer()653 LocalBufferPool::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
returnVector(std::vector<uint8_t> && vec)662 void LocalBufferPool::returnVector(std::vector<uint8_t> &&vec) {
663 Mutex::Autolock lock(mMutex);
664 mPool.push_front(std::move(vec));
665 }
666
667 // FlexBuffersImpl
668
assignSlot(const sp<Codec2Buffer> & buffer)669 size_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
releaseSlot(const sp<MediaCodecBuffer> & buffer,std::shared_ptr<C2Buffer> * c2buffer,bool release)681 bool 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();
704 clientBuffer->clearC2BufferRefs();
705 mBuffers[index].compBuffer = result;
706 }
707 if (c2buffer) {
708 *c2buffer = result;
709 }
710 return true;
711 }
712
expireComponentBuffer(const std::shared_ptr<C2Buffer> & c2buffer)713 bool 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
flush()728 void FlexBuffersImpl::flush() {
729 ALOGV("[%s] buffers are flushed %zu", mName, mBuffers.size());
730 mBuffers.clear();
731 }
732
numActiveSlots() const733 size_t FlexBuffersImpl::numActiveSlots() const {
734 return std::count_if(
735 mBuffers.begin(), mBuffers.end(),
736 [](const Entry &entry) {
737 return (entry.clientBuffer != nullptr
738 || !entry.compBuffer.expired());
739 });
740 }
741
numComponentBuffers() const742 size_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
750 // BuffersArrayImpl
751
initialize(const FlexBuffersImpl & impl,size_t minSize,std::function<sp<Codec2Buffer> ()> allocate)752 void 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
grabBuffer(size_t * index,sp<Codec2Buffer> * buffer,std::function<bool (const sp<Codec2Buffer> &)> match)772 status_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
returnBuffer(const sp<MediaCodecBuffer> & buffer,std::shared_ptr<C2Buffer> * c2buffer,bool release)796 bool 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();
824 clientBuffer->clearC2BufferRefs();
825 mBuffers[index].compBuffer = result;
826 }
827 if (c2buffer) {
828 *c2buffer = result;
829 }
830 return true;
831 }
832
expireComponentBuffer(const std::shared_ptr<C2Buffer> & c2buffer)833 bool 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
getArray(Vector<sp<MediaCodecBuffer>> * array) const855 void BuffersArrayImpl::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
856 array->clear();
857 for (const Entry &entry : mBuffers) {
858 array->push(entry.clientBuffer);
859 }
860 }
861
flush()862 void BuffersArrayImpl::flush() {
863 for (Entry &entry : mBuffers) {
864 entry.ownedByClient = false;
865 }
866 }
867
realloc(std::function<sp<Codec2Buffer> ()> alloc)868 void 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
grow(size_t newSize,std::function<sp<Codec2Buffer> ()> alloc)876 void 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
numActiveSlots() const884 size_t BuffersArrayImpl::numActiveSlots() const {
885 return std::count_if(
886 mBuffers.begin(), mBuffers.end(),
887 [](const Entry &entry) {
888 return entry.ownedByClient || !entry.compBuffer.expired();
889 });
890 }
891
arraySize() const892 size_t BuffersArrayImpl::arraySize() const {
893 return mBuffers.size();
894 }
895
896 // InputBuffersArray
897
initialize(const FlexBuffersImpl & impl,size_t minSize,std::function<sp<Codec2Buffer> ()> allocate)898 void InputBuffersArray::initialize(
899 const FlexBuffersImpl &impl,
900 size_t minSize,
901 std::function<sp<Codec2Buffer>()> allocate) {
902 mAllocate = allocate;
903 mImpl.initialize(impl, minSize, allocate);
904 }
905
getArray(Vector<sp<MediaCodecBuffer>> * array) const906 void InputBuffersArray::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
907 mImpl.getArray(array);
908 }
909
requestNewBuffer(size_t * index,sp<MediaCodecBuffer> * buffer)910 bool 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
releaseBuffer(const sp<MediaCodecBuffer> & buffer,std::shared_ptr<C2Buffer> * c2buffer,bool release)922 bool 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
expireComponentBuffer(const std::shared_ptr<C2Buffer> & c2buffer)929 bool InputBuffersArray::expireComponentBuffer(
930 const std::shared_ptr<C2Buffer> &c2buffer) {
931 return mImpl.expireComponentBuffer(c2buffer);
932 }
933
flush()934 void InputBuffersArray::flush() {
935 mImpl.flush();
936 }
937
numActiveSlots() const938 size_t InputBuffersArray::numActiveSlots() const {
939 return mImpl.numActiveSlots();
940 }
941
createNewBuffer()942 sp<Codec2Buffer> InputBuffersArray::createNewBuffer() {
943 return mAllocate();
944 }
945
946 // SlotInputBuffers
947
requestNewBuffer(size_t * index,sp<MediaCodecBuffer> * buffer)948 bool 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
releaseBuffer(const sp<MediaCodecBuffer> & buffer,std::shared_ptr<C2Buffer> * c2buffer,bool release)955 bool 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
expireComponentBuffer(const std::shared_ptr<C2Buffer> & c2buffer)962 bool SlotInputBuffers::expireComponentBuffer(
963 const std::shared_ptr<C2Buffer> &c2buffer) {
964 return mImpl.expireComponentBuffer(c2buffer);
965 }
966
flush()967 void SlotInputBuffers::flush() {
968 mImpl.flush();
969 }
970
toArrayMode(size_t)971 std::unique_ptr<InputBuffers> SlotInputBuffers::toArrayMode(size_t) {
972 TRESPASS("Array mode should not be called at non-legacy mode");
973 return nullptr;
974 }
975
numActiveSlots() const976 size_t SlotInputBuffers::numActiveSlots() const {
977 return mImpl.numActiveSlots();
978 }
979
createNewBuffer()980 sp<Codec2Buffer> SlotInputBuffers::createNewBuffer() {
981 return new DummyContainerBuffer{mFormat, nullptr};
982 }
983
984 // LinearInputBuffers
985
requestNewBuffer(size_t * index,sp<MediaCodecBuffer> * buffer)986 bool LinearInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
987 sp<Codec2Buffer> newBuffer = createNewBuffer();
988 if (newBuffer == nullptr) {
989 return false;
990 }
991 *index = mImpl.assignSlot(newBuffer);
992 *buffer = newBuffer;
993 return true;
994 }
995
releaseBuffer(const sp<MediaCodecBuffer> & buffer,std::shared_ptr<C2Buffer> * c2buffer,bool release)996 bool 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
expireComponentBuffer(const std::shared_ptr<C2Buffer> & c2buffer)1003 bool LinearInputBuffers::expireComponentBuffer(
1004 const std::shared_ptr<C2Buffer> &c2buffer) {
1005 return mImpl.expireComponentBuffer(c2buffer);
1006 }
1007
flush()1008 void 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
toArrayMode(size_t size)1014 std::unique_ptr<InputBuffers> LinearInputBuffers::toArrayMode(size_t size) {
1015 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,
1022 [pool = mPool, format = mFormat] () -> sp<Codec2Buffer> {
1023 return Alloc(pool, format);
1024 });
1025 return std::move(array);
1026 }
1027
numActiveSlots() const1028 size_t LinearInputBuffers::numActiveSlots() const {
1029 return mImpl.numActiveSlots();
1030 }
1031
1032 // static
Alloc(const std::shared_ptr<C2BlockPool> & pool,const sp<AMessage> & format)1033 sp<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
1042 int64_t usageValue = 0;
1043 (void)format->findInt64("android._C2MemoryUsage", &usageValue);
1044 C2MemoryUsage usage{usageValue | C2MemoryUsage::CPU_READ | C2MemoryUsage::CPU_WRITE};
1045 std::shared_ptr<C2LinearBlock> block;
1046
1047 c2_status_t err = pool->fetchLinearBlock(capacity, usage, &block);
1048 if (err != C2_OK) {
1049 return nullptr;
1050 }
1051
1052 return LinearBlockBuffer::Allocate(format, block);
1053 }
1054
createNewBuffer()1055 sp<Codec2Buffer> LinearInputBuffers::createNewBuffer() {
1056 return Alloc(mPool, mFormat);
1057 }
1058
1059 // EncryptedLinearInputBuffers
1060
EncryptedLinearInputBuffers(bool secure,const sp<MemoryDealer> & dealer,const sp<ICrypto> & crypto,int32_t heapSeqNum,size_t capacity,size_t numInputSlots,const char * componentName,const char * name)1061 EncryptedLinearInputBuffers::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),
1073 mMemoryVector(new std::vector<Entry>){
1074 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 }
1086 mMemoryVector->push_back({std::weak_ptr<C2LinearBlock>(), memory, heapSeqNum});
1087 }
1088 }
1089
toArrayMode(size_t size)1090 std::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
Alloc(const std::shared_ptr<C2BlockPool> & pool,const sp<AMessage> & format,C2MemoryUsage usage,const std::shared_ptr<std::vector<EncryptedLinearInputBuffers::Entry>> & memoryVector)1109 sp<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
1121 sp<IMemory> memory;
1122 size_t slot = 0;
1123 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;
1128 break;
1129 }
1130 }
1131 if (memory == nullptr) {
1132 return nullptr;
1133 }
1134
1135 int64_t usageValue = 0;
1136 (void)format->findInt64("android._C2MemoryUsage", &usageValue);
1137 usage = C2MemoryUsage(usage.expected | usageValue);
1138
1139 std::shared_ptr<C2LinearBlock> block;
1140 c2_status_t err = pool->fetchLinearBlock(capacity, usage, &block);
1141 if (err != C2_OK || block == nullptr) {
1142 return nullptr;
1143 }
1144
1145 memoryVector->at(slot).block = block;
1146 return new EncryptedLinearBlockBuffer(format, block, memory, heapSeqNum);
1147 }
1148
createNewBuffer()1149 sp<Codec2Buffer> EncryptedLinearInputBuffers::createNewBuffer() {
1150 // TODO: android_2020
1151 return nullptr;
1152 }
1153
1154 // GraphicMetadataInputBuffers
1155
GraphicMetadataInputBuffers(const char * componentName,const char * name)1156 GraphicMetadataInputBuffers::GraphicMetadataInputBuffers(
1157 const char *componentName, const char *name)
1158 : InputBuffers(componentName, name),
1159 mImpl(mName),
1160 mStore(GetCodec2PlatformAllocatorStore()) { }
1161
requestNewBuffer(size_t * index,sp<MediaCodecBuffer> * buffer)1162 bool GraphicMetadataInputBuffers::requestNewBuffer(
1163 size_t *index, sp<MediaCodecBuffer> *buffer) {
1164 sp<Codec2Buffer> newBuffer = createNewBuffer();
1165 if (newBuffer == nullptr) {
1166 return false;
1167 }
1168 *index = mImpl.assignSlot(newBuffer);
1169 *buffer = newBuffer;
1170 return true;
1171 }
1172
releaseBuffer(const sp<MediaCodecBuffer> & buffer,std::shared_ptr<C2Buffer> * c2buffer,bool release)1173 bool 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
expireComponentBuffer(const std::shared_ptr<C2Buffer> & c2buffer)1180 bool GraphicMetadataInputBuffers::expireComponentBuffer(
1181 const std::shared_ptr<C2Buffer> &c2buffer) {
1182 return mImpl.expireComponentBuffer(c2buffer);
1183 }
1184
flush()1185 void 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
toArrayMode(size_t size)1190 std::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
numActiveSlots() const1210 size_t GraphicMetadataInputBuffers::numActiveSlots() const {
1211 return mImpl.numActiveSlots();
1212 }
1213
createNewBuffer()1214 sp<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
1223 // GraphicInputBuffers
1224
GraphicInputBuffers(const char * componentName,const char * name)1225 GraphicInputBuffers::GraphicInputBuffers(
1226 const char *componentName, const char *name)
1227 : InputBuffers(componentName, name),
1228 mImpl(mName),
1229 mLocalBufferPool(LocalBufferPool::Create()),
1230 mPixelFormat(PIXEL_FORMAT_UNKNOWN) { }
1231
requestNewBuffer(size_t * index,sp<MediaCodecBuffer> * buffer)1232 bool GraphicInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
1233 sp<Codec2Buffer> newBuffer = createNewBuffer();
1234 if (newBuffer == nullptr) {
1235 return false;
1236 }
1237 *index = mImpl.assignSlot(newBuffer);
1238 handleImageData(newBuffer);
1239 *buffer = newBuffer;
1240 return true;
1241 }
1242
releaseBuffer(const sp<MediaCodecBuffer> & buffer,std::shared_ptr<C2Buffer> * c2buffer,bool release)1243 bool 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
expireComponentBuffer(const std::shared_ptr<C2Buffer> & c2buffer)1250 bool GraphicInputBuffers::expireComponentBuffer(
1251 const std::shared_ptr<C2Buffer> &c2buffer) {
1252 return mImpl.expireComponentBuffer(c2buffer);
1253 }
1254
flush()1255 void 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
extractPixelFormat(const sp<AMessage> & format)1260 static 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
toArrayMode(size_t size)1272 std::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);
1277 uint32_t pixelFormat = extractPixelFormat(mFormat);
1278 array->initialize(
1279 mImpl,
1280 size,
1281 [pool = mPool, format = mFormat, lbp = mLocalBufferPool, pixelFormat]()
1282 -> sp<Codec2Buffer> {
1283 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
1284 return AllocateInputGraphicBuffer(
1285 pool, format, pixelFormat, usage, lbp);
1286 });
1287 return std::move(array);
1288 }
1289
numActiveSlots() const1290 size_t GraphicInputBuffers::numActiveSlots() const {
1291 return mImpl.numActiveSlots();
1292 }
1293
createNewBuffer()1294 sp<Codec2Buffer> GraphicInputBuffers::createNewBuffer() {
1295 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
1296 mPixelFormat = extractPixelFormat(mFormat);
1297 return AllocateInputGraphicBuffer(
1298 mPool, mFormat, mPixelFormat, usage, mLocalBufferPool);
1299 }
1300
getPixelFormatIfApplicable()1301 uint32_t GraphicInputBuffers::getPixelFormatIfApplicable() { return mPixelFormat; }
1302
resetPixelFormatIfApplicable()1303 bool GraphicInputBuffers::resetPixelFormatIfApplicable() {
1304 mPixelFormat = PIXEL_FORMAT_UNKNOWN;
1305 return true;
1306 }
1307
1308 // OutputBuffersArray
1309
initialize(const FlexBuffersImpl & impl,size_t minSize,std::function<sp<Codec2Buffer> ()> allocate)1310 void OutputBuffersArray::initialize(
1311 const FlexBuffersImpl &impl,
1312 size_t minSize,
1313 std::function<sp<Codec2Buffer>()> allocate) {
1314 mAlloc = allocate;
1315 mImpl.initialize(impl, minSize, allocate);
1316 }
1317
registerBuffer(const std::shared_ptr<C2Buffer> & buffer,size_t * index,sp<MediaCodecBuffer> * clientBuffer)1318 status_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);
1337 if (!convert(buffer, &c2Buffer) && !c2Buffer->copy(buffer)) {
1338 ALOGD("[%s] copy buffer failed", mName);
1339 return WOULD_BLOCK;
1340 }
1341 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 }
1351 handleImageData(c2Buffer);
1352 *clientBuffer = c2Buffer;
1353 ALOGV("[%s] grabbed buffer %zu", mName, *index);
1354 return OK;
1355 }
1356
registerCsd(const C2StreamInitDataInfo::output * csd,size_t * index,sp<MediaCodecBuffer> * clientBuffer)1357 status_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
releaseBuffer(const sp<MediaCodecBuffer> & buffer,std::shared_ptr<C2Buffer> * c2buffer)1379 bool OutputBuffersArray::releaseBuffer(
1380 const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) {
1381 return mImpl.returnBuffer(buffer, c2buffer, true);
1382 }
1383
flush(const std::list<std::unique_ptr<C2Work>> & flushedWork)1384 void OutputBuffersArray::flush(const std::list<std::unique_ptr<C2Work>> &flushedWork) {
1385 (void)flushedWork;
1386 mImpl.flush();
1387 if (mSkipCutBuffer != nullptr) {
1388 mSkipCutBuffer->clearAll();
1389 }
1390 }
1391
getArray(Vector<sp<MediaCodecBuffer>> * array) const1392 void OutputBuffersArray::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
1393 mImpl.getArray(array);
1394 }
1395
numActiveSlots() const1396 size_t OutputBuffersArray::numActiveSlots() const {
1397 return mImpl.numActiveSlots();
1398 }
1399
realloc(const std::shared_ptr<C2Buffer> & c2buffer)1400 void OutputBuffersArray::realloc(const std::shared_ptr<C2Buffer> &c2buffer) {
1401 switch (c2buffer->data().type()) {
1402 case C2BufferData::LINEAR: {
1403 uint32_t size = kLinearBufferSize;
1404 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;
1408 } else {
1409 size = kMaxLinearBufferSize;
1410 }
1411 mAlloc = [format = mFormat, size] {
1412 return new LocalLinearBuffer(format, new ABuffer(size));
1413 };
1414 ALOGD("[%s] reallocating with linear buffer of size %u", mName, size);
1415 break;
1416 }
1417
1418 case C2BufferData::GRAPHIC: {
1419 // This is only called for RawGraphicOutputBuffers.
1420 mAlloc = [format = mFormat,
1421 lbp = LocalBufferPool::Create()] {
1422 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 }
1432
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 }
1440 mImpl.realloc(mAlloc);
1441 }
1442
grow(size_t newSize)1443 void OutputBuffersArray::grow(size_t newSize) {
1444 mImpl.grow(newSize, mAlloc);
1445 }
1446
transferFrom(OutputBuffers * source)1447 void OutputBuffersArray::transferFrom(OutputBuffers* source) {
1448 mFormat = source->mFormat;
1449 mSkipCutBuffer = source->mSkipCutBuffer;
1450 mPending = std::move(source->mPending);
1451 mReorderStash = std::move(source->mReorderStash);
1452 mDepth = source->mDepth;
1453 mKey = source->mKey;
1454 }
1455
1456 // FlexOutputBuffers
1457
registerBuffer(const std::shared_ptr<C2Buffer> & buffer,size_t * index,sp<MediaCodecBuffer> * clientBuffer)1458 status_t FlexOutputBuffers::registerBuffer(
1459 const std::shared_ptr<C2Buffer> &buffer,
1460 size_t *index,
1461 sp<MediaCodecBuffer> *clientBuffer) {
1462 sp<Codec2Buffer> newBuffer;
1463 if (!convert(buffer, &newBuffer)) {
1464 newBuffer = wrap(buffer);
1465 if (newBuffer == nullptr) {
1466 return NO_MEMORY;
1467 }
1468 newBuffer->setFormat(mFormat);
1469 }
1470 *index = mImpl.assignSlot(newBuffer);
1471 handleImageData(newBuffer);
1472 *clientBuffer = newBuffer;
1473
1474 extractPixelFormatFromC2Buffer(buffer);
1475 ALOGV("[%s] registered buffer %zu", mName, *index);
1476 return OK;
1477 }
1478
registerCsd(const C2StreamInitDataInfo::output * csd,size_t * index,sp<MediaCodecBuffer> * clientBuffer)1479 status_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
releaseBuffer(const sp<MediaCodecBuffer> & buffer,std::shared_ptr<C2Buffer> * c2buffer)1490 bool FlexOutputBuffers::releaseBuffer(
1491 const sp<MediaCodecBuffer> &buffer,
1492 std::shared_ptr<C2Buffer> *c2buffer) {
1493 return mImpl.releaseSlot(buffer, c2buffer, true);
1494 }
1495
flush(const std::list<std::unique_ptr<C2Work>> & flushedWork)1496 void 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
toArrayMode(size_t size)1503 std::unique_ptr<OutputBuffersArray> FlexOutputBuffers::toArrayMode(size_t size) {
1504 std::unique_ptr<OutputBuffersArray> array(new OutputBuffersArray(mComponentName.c_str()));
1505 array->transferFrom(this);
1506 std::function<sp<Codec2Buffer>()> alloc = getAlloc();
1507 array->initialize(mImpl, size, alloc);
1508 return array;
1509 }
1510
numActiveSlots() const1511 size_t FlexOutputBuffers::numActiveSlots() const {
1512 return mImpl.numActiveSlots();
1513 }
1514
extractPixelFormatFromC2Buffer(const std::shared_ptr<C2Buffer> & buffer)1515 bool 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
resetPixelFormatIfApplicable()1534 bool FlexOutputBuffers::resetPixelFormatIfApplicable() {
1535 mPixelFormat = PIXEL_FORMAT_UNKNOWN;
1536 return true;
1537 }
1538
getPixelFormatIfApplicable()1539 uint32_t FlexOutputBuffers::getPixelFormatIfApplicable() { return mPixelFormat; }
1540
1541 // LinearOutputBuffers
1542
flush(const std::list<std::unique_ptr<C2Work>> & flushedWork)1543 void LinearOutputBuffers::flush(
1544 const std::list<std::unique_ptr<C2Work>> &flushedWork) {
1545 if (mSkipCutBuffer != nullptr) {
1546 mSkipCutBuffer->clearAll();
1547 }
1548 FlexOutputBuffers::flush(flushedWork);
1549 }
1550
wrap(const std::shared_ptr<C2Buffer> & buffer)1551 sp<Codec2Buffer> LinearOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
1552 if (buffer == nullptr) {
1553 ALOGD("[%s] received null buffer", mName);
1554 return new LocalLinearBuffer(mFormat, new ABuffer(0));
1555 }
1556 if (buffer->data().type() != C2BufferData::LINEAR) {
1557 ALOGW("[%s] non-linear buffer %d", mName, buffer->data().type());
1558 // We expect linear output buffers from the component.
1559 return nullptr;
1560 }
1561 if (buffer->data().linearBlocks().size() != 1u) {
1562 ALOGW("[%s] no linear buffers", mName);
1563 // We expect one and only one linear block from the component.
1564 return nullptr;
1565 }
1566 if (buffer->data().linearBlocks().front().size() == 0) {
1567 ALOGD("[%s] received 0-sized buffer", mName);
1568 return new LocalLinearBuffer(mFormat, new ABuffer(0));
1569 }
1570 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
getAlloc()1579 std::function<sp<Codec2Buffer>()> LinearOutputBuffers::getAlloc() {
1580 return [format = mFormat]{
1581 // TODO: proper max output size
1582 return new LocalLinearBuffer(format, new ABuffer(kLinearBufferSize));
1583 };
1584 }
1585
1586 // GraphicOutputBuffers
1587
wrap(const std::shared_ptr<C2Buffer> & buffer)1588 sp<Codec2Buffer> GraphicOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
1589 return new DummyContainerBuffer(mFormat, buffer);
1590 }
1591
getAlloc()1592 std::function<sp<Codec2Buffer>()> GraphicOutputBuffers::getAlloc() {
1593 return [format = mFormat]{
1594 return new DummyContainerBuffer(format);
1595 };
1596 }
1597
1598 // RawGraphicOutputBuffers
1599
RawGraphicOutputBuffers(const char * componentName,const char * name)1600 RawGraphicOutputBuffers::RawGraphicOutputBuffers(
1601 const char *componentName, const char *name)
1602 : FlexOutputBuffers(componentName, name),
1603 mLocalBufferPool(LocalBufferPool::Create()) { }
1604
wrap(const std::shared_ptr<C2Buffer> & buffer)1605 sp<Codec2Buffer> RawGraphicOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
1606 if (buffer == nullptr) {
1607 return new Codec2Buffer(mFormat, new ABuffer(nullptr, 0));
1608 } else {
1609 return ConstGraphicBlockBuffer::Allocate(
1610 mFormat,
1611 buffer,
1612 [lbp = mLocalBufferPool](size_t capacity) {
1613 return lbp->newBuffer(capacity);
1614 });
1615 }
1616 }
1617
getAlloc()1618 std::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 };
1626 }
1627
1628 } // namespace android
1629