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 #define ATRACE_TAG ATRACE_TAG_VIDEO
20 #include <utils/Log.h>
21 #include <utils/Trace.h>
22
23 #include <numeric>
24
25 #include <C2AllocatorGralloc.h>
26 #include <C2PlatformSupport.h>
27
28 #include <media/stagefright/foundation/ADebug.h>
29 #include <media/stagefright/foundation/AUtils.h>
30 #include <media/stagefright/foundation/MediaDefs.h>
31 #include <media/stagefright/CodecBase.h>
32 #include <media/stagefright/MediaCodecConstants.h>
33 #include <media/stagefright/SkipCutBuffer.h>
34 #include <mediadrm/ICrypto.h>
35
36 #include "CCodecBuffers.h"
37 #include "Codec2Mapper.h"
38
39 namespace android {
40
41 namespace {
42
43 constexpr uint32_t PIXEL_FORMAT_UNKNOWN = 0;
44
AllocateInputGraphicBuffer(const std::shared_ptr<C2BlockPool> & pool,const sp<AMessage> & format,uint32_t pixelFormat,const C2MemoryUsage & usage,const std::shared_ptr<LocalBufferPool> & localBufferPool)45 sp<GraphicBlockBuffer> AllocateInputGraphicBuffer(
46 const std::shared_ptr<C2BlockPool> &pool,
47 const sp<AMessage> &format,
48 uint32_t pixelFormat,
49 const C2MemoryUsage &usage,
50 const std::shared_ptr<LocalBufferPool> &localBufferPool) {
51 int32_t width, height;
52 if (!format->findInt32("width", &width) || !format->findInt32("height", &height)) {
53 ALOGD("format lacks width or height");
54 return nullptr;
55 }
56
57 int64_t usageValue = 0;
58 (void)format->findInt64("android._C2MemoryUsage", &usageValue);
59 C2MemoryUsage fullUsage{usageValue | usage.expected};
60
61 std::shared_ptr<C2GraphicBlock> block;
62 c2_status_t err = pool->fetchGraphicBlock(
63 align(width, 2), align(height, 2), pixelFormat, fullUsage, &block);
64 if (err != C2_OK) {
65 ALOGD("fetch graphic block failed: %d", err);
66 return nullptr;
67 }
68
69 return GraphicBlockBuffer::Allocate(
70 format,
71 block,
72 [localBufferPool](size_t capacity) {
73 return localBufferPool->newBuffer(capacity);
74 });
75 }
76
77 } // namespace
78
79 // CCodecBuffers
80
setFormat(const sp<AMessage> & format)81 void CCodecBuffers::setFormat(const sp<AMessage> &format) {
82 CHECK(format != nullptr);
83 mFormat = format;
84 }
85
dupFormat()86 sp<AMessage> CCodecBuffers::dupFormat() {
87 return mFormat != nullptr ? mFormat->dup() : nullptr;
88 }
89
handleImageData(const sp<Codec2Buffer> & buffer)90 void CCodecBuffers::handleImageData(const sp<Codec2Buffer> &buffer) {
91 sp<ABuffer> imageDataCandidate = buffer->getImageData();
92 if (imageDataCandidate == nullptr) {
93 if (mFormatWithImageData) {
94 // We previously sent the format with image data, so use the same format.
95 buffer->setFormat(mFormatWithImageData);
96 }
97 return;
98 }
99 if (!mLastImageData
100 || imageDataCandidate->size() != mLastImageData->size()
101 || memcmp(imageDataCandidate->data(),
102 mLastImageData->data(),
103 mLastImageData->size()) != 0) {
104 ALOGD("[%s] updating image-data", mName);
105 mFormatWithImageData = dupFormat();
106 mLastImageData = imageDataCandidate;
107 mFormatWithImageData->setBuffer("image-data", imageDataCandidate);
108 MediaImage2 *img = (MediaImage2*)imageDataCandidate->data();
109 if (img->mNumPlanes > 0 && img->mType != img->MEDIA_IMAGE_TYPE_UNKNOWN) {
110 int32_t stride = img->mPlane[0].mRowInc;
111 mFormatWithImageData->setInt32(KEY_STRIDE, stride);
112 mFormatWithImageData->setInt32(KEY_WIDTH, img->mWidth);
113 mFormatWithImageData->setInt32(KEY_HEIGHT, img->mHeight);
114 ALOGD("[%s] updating stride = %d, width: %d, height: %d",
115 mName, stride, img->mWidth, img->mHeight);
116 if (img->mNumPlanes > 1 && stride > 0) {
117 int64_t offsetDelta =
118 (int64_t)img->mPlane[1].mOffset - (int64_t)img->mPlane[0].mOffset;
119 int32_t vstride = int32_t(offsetDelta / stride);
120 mFormatWithImageData->setInt32(KEY_SLICE_HEIGHT, vstride);
121 ALOGD("[%s] updating vstride = %d", mName, vstride);
122 buffer->setRange(
123 img->mPlane[0].mOffset,
124 buffer->size() - img->mPlane[0].mOffset);
125 }
126 }
127 }
128 buffer->setFormat(mFormatWithImageData);
129 }
130
getPixelFormatIfApplicable()131 uint32_t CCodecBuffers::getPixelFormatIfApplicable() { return PIXEL_FORMAT_UNKNOWN; }
132
resetPixelFormatIfApplicable()133 bool CCodecBuffers::resetPixelFormatIfApplicable() { return false; }
134
135 // InputBuffers
136
cloneAndReleaseBuffer(const sp<MediaCodecBuffer> & buffer)137 sp<Codec2Buffer> InputBuffers::cloneAndReleaseBuffer(const sp<MediaCodecBuffer> &buffer) {
138 sp<Codec2Buffer> copy = createNewBuffer();
139 if (copy == nullptr) {
140 return nullptr;
141 }
142 std::shared_ptr<C2Buffer> c2buffer;
143 if (!releaseBuffer(buffer, &c2buffer, true)) {
144 return nullptr;
145 }
146 if (!copy->canCopy(c2buffer)) {
147 return nullptr;
148 }
149 if (!copy->copy(c2buffer)) {
150 return nullptr;
151 }
152 copy->meta()->extend(buffer->meta());
153 return copy;
154 }
155
156 // MultiAccessUnitSkipCutBuffer for buffer and bufferInfos
157
158 class MultiAccessUnitSkipCutBuffer : public SkipCutBuffer {
159
160 public:
MultiAccessUnitSkipCutBuffer(int32_t skip,int32_t cut,size_t num16BitChannels)161 explicit MultiAccessUnitSkipCutBuffer(
162 int32_t skip, int32_t cut, size_t num16BitChannels):
163 SkipCutBuffer(skip, cut, num16BitChannels),
164 mFrontPaddingDelay(0), mSize(0) {
165 }
clearAll()166 void clearAll() {
167 mInfos.clear();
168 mFrontPaddingDelay = 0;
169 mSize = 0;
170 SkipCutBuffer::clear();
171 }
172
~MultiAccessUnitSkipCutBuffer()173 virtual ~MultiAccessUnitSkipCutBuffer() {
174
175 }
176
submitMultiAccessUnits(const sp<MediaCodecBuffer> & buffer,int32_t sampleRate,size_t num16BitChannels,std::shared_ptr<const C2AccessUnitInfos::output> & infos)177 void submitMultiAccessUnits(
178 const sp<MediaCodecBuffer>& buffer,
179 int32_t sampleRate, size_t num16BitChannels,
180 std::shared_ptr<const C2AccessUnitInfos::output> &infos) {
181 if (infos == nullptr) {
182 // there is nothing to do more.
183 SkipCutBuffer::submit(buffer);
184 return;
185 }
186 typedef WrapperObject<std::vector<AccessUnitInfo>> BufferInfosWrapper;
187 CHECK_EQ(mSize, SkipCutBuffer::size());
188 sp<BufferInfosWrapper> bufferInfos{new BufferInfosWrapper(decltype(bufferInfos->value)())};
189 uint32_t availableSize = buffer->size() + SkipCutBuffer::size();
190 uint32_t frontPadding = mFrontPadding;
191 int32_t lastEmptyAccessUnitIndex = -1;
192 int64_t byteInUs = 0;
193 if (sampleRate > 0 && num16BitChannels > 0) {
194 byteInUs = (1000000u / (sampleRate * num16BitChannels * 2));
195 }
196 if (frontPadding > 0) {
197 mInfos.clear();
198 mSize = 0;
199 }
200 for (int i = 0 ; i < infos->flexCount() && frontPadding > 0; i++) {
201 uint32_t flagsInPadding = 0;
202 int64_t timeInPadding = 0;
203 if (infos->m.values[i].size <= frontPadding) {
204 // we have more front padding so this buffer is not going to be used.
205 int32_t consumed = infos->m.values[i].size;
206 frontPadding -= consumed;
207 mFrontPaddingDelay += byteInUs * (consumed);
208 availableSize -= consumed;
209 flagsInPadding |= toMediaCodecFlags(infos->m.values[i].flags);
210 timeInPadding = infos->m.values[i].timestamp;
211 } else {
212 C2AccessUnitInfosStruct info = infos->m.values[i];
213 mFrontPaddingDelay += byteInUs * (frontPadding);
214 info.size -= frontPadding;
215 info.timestamp -= mFrontPaddingDelay;
216 availableSize -= frontPadding;
217 flagsInPadding |= toMediaCodecFlags(infos->m.values[i].flags);
218 timeInPadding = infos->m.values[i].timestamp;
219 frontPadding = 0;
220 mInfos.push_back(info);
221 mSize += info.size;
222 }
223 if (flagsInPadding != 0) {
224 bufferInfos->value.emplace_back(
225 flagsInPadding, 0, timeInPadding);
226 }
227 lastEmptyAccessUnitIndex = i;
228 }
229 if (frontPadding <= 0) {
230 // process what's already in the buffer first
231 auto it = mInfos.begin();
232 while (it != mInfos.end() && availableSize > mBackPadding) {
233 // we have samples to send out.
234 if ((availableSize - it->size) >= mBackPadding) {
235 // this is totally used here.
236 int32_t consumed = it->size;
237 bufferInfos->value.emplace_back(
238 toMediaCodecFlags(it->flags), consumed, it->timestamp);
239 availableSize -= consumed;
240 mSize -= consumed;
241 it = mInfos.erase(it);
242 } else {
243 int32_t consumed = availableSize - mBackPadding;
244 bufferInfos->value.emplace_back(
245 toMediaCodecFlags(it->flags),
246 consumed,
247 it->timestamp);
248 it->size -= consumed;
249 it->timestamp += consumed * byteInUs;
250 availableSize -= consumed;
251 mSize -= consumed;
252 it++;
253 }
254 }
255 // if buffer has more process all of it and keep the remaining info.
256 for (int i = (lastEmptyAccessUnitIndex + 1) ; i < infos->flexCount() ; i++) {
257 // upddate updatedInfo and mInfos
258 if (availableSize > mBackPadding) {
259 // we have to take data from the new buffer.
260 if (availableSize - infos->m.values[i].size >= mBackPadding) {
261 // we are using this info
262 int32_t consumed = infos->m.values[i].size;
263 bufferInfos->value.emplace_back(
264 toMediaCodecFlags(infos->m.values[i].flags),
265 consumed,
266 infos->m.values[i].timestamp - mFrontPaddingDelay);
267 availableSize -= consumed;
268 } else {
269 // if we need to update the size
270 C2AccessUnitInfosStruct info = infos->m.values[i];
271 int32_t consumed = availableSize - mBackPadding;
272 bufferInfos->value.emplace_back(
273 toMediaCodecFlags(infos->m.values[i].flags),
274 consumed,
275 infos->m.values[i].timestamp - mFrontPaddingDelay);
276 info.size -= consumed;
277 info.timestamp = info.timestamp - mFrontPaddingDelay +
278 consumed * byteInUs;
279 mInfos.push_back(info);
280 availableSize -= consumed;
281 mSize += info.size;
282 }
283 } else {
284 // we have to maintain infos
285 C2AccessUnitInfosStruct info = infos->m.values[i];
286 info.timestamp -= mFrontPaddingDelay;
287 mInfos.push_back(info);
288 mSize += info.size;
289 }
290 }
291 }
292 SkipCutBuffer::submit(buffer);
293 infos = nullptr;
294 if (!bufferInfos->value.empty()) {
295 buffer->meta()->setObject("accessUnitInfo", bufferInfos);
296 }
297 }
298 protected:
299 // Flags can come with individual BufferInfos
300 // when used with large frame audio
301 constexpr static std::initializer_list<std::pair<uint32_t, uint32_t>> flagList = {
302 {BUFFER_FLAG_CODEC_CONFIG, C2FrameData::FLAG_CODEC_CONFIG},
303 {BUFFER_FLAG_END_OF_STREAM, C2FrameData::FLAG_END_OF_STREAM},
304 {BUFFER_FLAG_DECODE_ONLY, C2FrameData::FLAG_DROP_FRAME}
305 };
306
toMediaCodecFlags(uint32_t flags)307 static uint32_t toMediaCodecFlags(uint32_t flags) {
308 return std::transform_reduce(
309 flagList.begin(), flagList.end(),
310 0u,
311 std::bit_or{},
312 [flags](const std::pair<uint32_t, uint32_t> &entry) {
313 return (flags & entry.second) ? entry.first : 0;
314 });
315 }
316 std::list<C2AccessUnitInfosStruct> mInfos;
317 int64_t mFrontPaddingDelay;
318 size_t mSize;
319 };
320
321 // OutputBuffers
322
OutputBuffers(const char * componentName,const char * name)323 OutputBuffers::OutputBuffers(const char *componentName, const char *name)
324 : CCodecBuffers(componentName, name) { }
325
326 OutputBuffers::~OutputBuffers() = default;
327
initSkipCutBuffer(int32_t delay,int32_t padding,int32_t sampleRate,int32_t channelCount)328 void OutputBuffers::initSkipCutBuffer(
329 int32_t delay, int32_t padding, int32_t sampleRate, int32_t channelCount) {
330 CHECK(mSkipCutBuffer == nullptr);
331 mDelay = delay;
332 mPadding = padding;
333 mSampleRate = sampleRate;
334 mChannelCount = channelCount;
335 setSkipCutBuffer(delay, padding);
336 }
337
updateSkipCutBuffer(int32_t sampleRate,int32_t channelCount)338 void OutputBuffers::updateSkipCutBuffer(int32_t sampleRate, int32_t channelCount) {
339 if (mSkipCutBuffer == nullptr) {
340 return;
341 }
342 if (mSampleRate == sampleRate && mChannelCount == channelCount) {
343 return;
344 }
345 int32_t delay = mDelay;
346 int32_t padding = mPadding;
347 if (sampleRate != mSampleRate) {
348 delay = ((int64_t)delay * sampleRate) / mSampleRate;
349 padding = ((int64_t)padding * sampleRate) / mSampleRate;
350 }
351 mSampleRate = sampleRate;
352 mChannelCount = channelCount;
353 setSkipCutBuffer(delay, padding);
354 }
355
updateSkipCutBuffer(const sp<AMessage> & format)356 void OutputBuffers::updateSkipCutBuffer(const sp<AMessage> &format) {
357 AString mediaType;
358 if (format->findString(KEY_MIME, &mediaType)
359 && mediaType == MIMETYPE_AUDIO_RAW) {
360 int32_t channelCount;
361 int32_t sampleRate;
362 if (format->findInt32(KEY_CHANNEL_COUNT, &channelCount)
363 && format->findInt32(KEY_SAMPLE_RATE, &sampleRate)) {
364 updateSkipCutBuffer(sampleRate, channelCount);
365 }
366 }
367 }
368
submit(const sp<MediaCodecBuffer> & buffer)369 void OutputBuffers::submit(const sp<MediaCodecBuffer> &buffer) {
370 if (mSkipCutBuffer != nullptr) {
371 mSkipCutBuffer->submit(buffer);
372 }
373 }
374
submit(const sp<MediaCodecBuffer> & buffer,int32_t sampleRate,int32_t channelCount,std::shared_ptr<const C2AccessUnitInfos::output> & infos)375 bool OutputBuffers::submit(const sp<MediaCodecBuffer> &buffer, int32_t sampleRate,
376 int32_t channelCount, std::shared_ptr<const C2AccessUnitInfos::output> &infos) {
377 if (mSkipCutBuffer == nullptr) {
378 return false;
379 }
380 mSkipCutBuffer->submitMultiAccessUnits(buffer, sampleRate, channelCount, infos);
381 return true;
382 }
383
setSkipCutBuffer(int32_t skip,int32_t cut)384 void OutputBuffers::setSkipCutBuffer(int32_t skip, int32_t cut) {
385 if (mSkipCutBuffer != nullptr) {
386 size_t prevSize = mSkipCutBuffer->size();
387 if (prevSize != 0u) {
388 ALOGD("[%s] Replacing SkipCutBuffer holding %zu bytes", mName, prevSize);
389 }
390 }
391 mSkipCutBuffer = new MultiAccessUnitSkipCutBuffer(skip, cut, mChannelCount);
392 }
393
convert(const std::shared_ptr<C2Buffer> & src,sp<Codec2Buffer> * dst)394 bool OutputBuffers::convert(
395 const std::shared_ptr<C2Buffer> &src, sp<Codec2Buffer> *dst) {
396 if (src && src->data().type() != C2BufferData::LINEAR) {
397 return false;
398 }
399 int32_t configEncoding = kAudioEncodingPcm16bit;
400 int32_t codecEncoding = kAudioEncodingPcm16bit;
401 if (mFormat->findInt32("android._codec-pcm-encoding", &codecEncoding)
402 && mFormat->findInt32("android._config-pcm-encoding", &configEncoding)) {
403 if (mSrcEncoding != codecEncoding || mDstEncoding != configEncoding) {
404 if (codecEncoding != configEncoding) {
405 mDataConverter = AudioConverter::Create(
406 (AudioEncoding)codecEncoding, (AudioEncoding)configEncoding);
407 ALOGD_IF(mDataConverter, "[%s] Converter created from %d to %d",
408 mName, codecEncoding, configEncoding);
409 mFormatWithConverter = mFormat->dup();
410 mFormatWithConverter->setInt32(KEY_PCM_ENCODING, configEncoding);
411 } else {
412 mDataConverter = nullptr;
413 mFormatWithConverter = nullptr;
414 }
415 mSrcEncoding = codecEncoding;
416 mDstEncoding = configEncoding;
417 }
418 if (int encoding; !mFormat->findInt32(KEY_PCM_ENCODING, &encoding)
419 || encoding != mDstEncoding) {
420 }
421 }
422 if (!mDataConverter) {
423 return false;
424 }
425 sp<MediaCodecBuffer> srcBuffer;
426 if (src) {
427 srcBuffer = ConstLinearBlockBuffer::Allocate(mFormat, src);
428 } else {
429 srcBuffer = new MediaCodecBuffer(mFormat, new ABuffer(0));
430 }
431 if (!srcBuffer) {
432 return false;
433 }
434 if (!*dst) {
435 *dst = new Codec2Buffer(
436 mFormat,
437 new ABuffer(mDataConverter->targetSize(srcBuffer->size())));
438 }
439 sp<MediaCodecBuffer> dstBuffer = *dst;
440 status_t err = mDataConverter->convert(srcBuffer, dstBuffer);
441 if (err != OK) {
442 ALOGD("[%s] buffer conversion failed: %d", mName, err);
443 return false;
444 }
445 dstBuffer->setFormat(mFormatWithConverter);
446 return true;
447 }
448
clearStash()449 void OutputBuffers::clearStash() {
450 mPending.clear();
451 mReorderStash.clear();
452 mDepth = 0;
453 mKey = C2Config::ORDINAL;
454 }
455
flushStash()456 void OutputBuffers::flushStash() {
457 for (StashEntry& e : mPending) {
458 e.notify = false;
459 }
460 for (StashEntry& e : mReorderStash) {
461 e.notify = false;
462 }
463 }
464
getReorderDepth() const465 uint32_t OutputBuffers::getReorderDepth() const {
466 return mDepth;
467 }
468
setReorderDepth(uint32_t depth)469 void OutputBuffers::setReorderDepth(uint32_t depth) {
470 mPending.splice(mPending.end(), mReorderStash);
471 mDepth = depth;
472 }
473
setReorderKey(C2Config::ordinal_key_t key)474 void OutputBuffers::setReorderKey(C2Config::ordinal_key_t key) {
475 mPending.splice(mPending.end(), mReorderStash);
476 mKey = key;
477 }
478
pushToStash(const std::shared_ptr<C2Buffer> & buffer,bool notify,int64_t timestamp,int32_t flags,const sp<AMessage> & format,const C2WorkOrdinalStruct & ordinal)479 void OutputBuffers::pushToStash(
480 const std::shared_ptr<C2Buffer>& buffer,
481 bool notify,
482 int64_t timestamp,
483 int32_t flags,
484 const sp<AMessage>& format,
485 const C2WorkOrdinalStruct& ordinal) {
486 bool eos = flags & BUFFER_FLAG_END_OF_STREAM;
487 if (!buffer && eos) {
488 // TRICKY: we may be violating ordering of the stash here. Because we
489 // don't expect any more emplace() calls after this, the ordering should
490 // not matter.
491 mReorderStash.emplace_back(
492 buffer, notify, timestamp, flags, format, ordinal);
493 } else {
494 flags = flags & ~BUFFER_FLAG_END_OF_STREAM;
495 auto it = mReorderStash.begin();
496 for (; it != mReorderStash.end(); ++it) {
497 if (less(ordinal, it->ordinal)) {
498 break;
499 }
500 }
501 mReorderStash.emplace(it,
502 buffer, notify, timestamp, flags, format, ordinal);
503 if (eos) {
504 mReorderStash.back().flags =
505 mReorderStash.back().flags | BUFFER_FLAG_END_OF_STREAM;
506 }
507 }
508 while (!mReorderStash.empty() && mReorderStash.size() > mDepth) {
509 mPending.push_back(mReorderStash.front());
510 mReorderStash.pop_front();
511 }
512 ALOGV("[%s] %s: pushToStash -- pending size = %zu", mName, __func__, mPending.size());
513 }
514
popFromStashAndRegister(std::shared_ptr<C2Buffer> * c2Buffer,size_t * index,sp<MediaCodecBuffer> * outBuffer)515 OutputBuffers::BufferAction OutputBuffers::popFromStashAndRegister(
516 std::shared_ptr<C2Buffer>* c2Buffer,
517 size_t* index,
518 sp<MediaCodecBuffer>* outBuffer) {
519 if (mPending.empty()) {
520 return SKIP;
521 }
522
523 // Retrieve the first entry.
524 StashEntry &entry = mPending.front();
525
526 *c2Buffer = entry.buffer;
527 sp<AMessage> outputFormat = entry.format;
528
529 if (entry.notify && mFormat != outputFormat) {
530 updateSkipCutBuffer(outputFormat);
531 // Trigger image data processing to the new format
532 mLastImageData.clear();
533 ALOGV("[%s] popFromStashAndRegister: output format reference changed: %p -> %p",
534 mName, mFormat.get(), outputFormat.get());
535 ALOGD("[%s] popFromStashAndRegister: at %lldus, output format changed to %s",
536 mName, (long long)entry.timestamp, outputFormat->debugString().c_str());
537 setFormat(outputFormat);
538 }
539
540 // Flushing mReorderStash because no other buffers should come after output
541 // EOS.
542 if (entry.flags & BUFFER_FLAG_END_OF_STREAM) {
543 // Flush reorder stash
544 setReorderDepth(0);
545 }
546
547 if (!entry.notify) {
548 mPending.pop_front();
549 return DISCARD;
550 }
551
552 // Try to register the buffer.
553 status_t err = registerBuffer(*c2Buffer, index, outBuffer);
554 if (err != OK) {
555 if (err != WOULD_BLOCK) {
556 return REALLOCATE;
557 }
558 return RETRY;
559 }
560
561 // Append information from the front stash entry to outBuffer.
562 (*outBuffer)->meta()->setInt64("timeUs", entry.timestamp);
563 (*outBuffer)->meta()->setInt32("flags", entry.flags);
564 (*outBuffer)->meta()->setInt64("frameIndex", entry.ordinal.frameIndex.peekll());
565 ALOGV("[%s] popFromStashAndRegister: "
566 "out buffer index = %zu [%p] => %p + %zu (%lld)",
567 mName, *index, outBuffer->get(),
568 (*outBuffer)->data(), (*outBuffer)->size(),
569 (long long)entry.timestamp);
570
571 // The front entry of mPending will be removed now that the registration
572 // succeeded.
573 mPending.pop_front();
574 return NOTIFY_CLIENT;
575 }
576
popPending(StashEntry * entry)577 bool OutputBuffers::popPending(StashEntry *entry) {
578 if (mPending.empty()) {
579 return false;
580 }
581 *entry = mPending.front();
582 mPending.pop_front();
583 return true;
584 }
585
deferPending(const OutputBuffers::StashEntry & entry)586 void OutputBuffers::deferPending(const OutputBuffers::StashEntry &entry) {
587 mPending.push_front(entry);
588 }
589
hasPending() const590 bool OutputBuffers::hasPending() const {
591 return !mPending.empty();
592 }
593
less(const C2WorkOrdinalStruct & o1,const C2WorkOrdinalStruct & o2) const594 bool OutputBuffers::less(
595 const C2WorkOrdinalStruct &o1, const C2WorkOrdinalStruct &o2) const {
596 switch (mKey) {
597 case C2Config::ORDINAL: return o1.frameIndex < o2.frameIndex;
598 case C2Config::TIMESTAMP: return o1.timestamp < o2.timestamp;
599 case C2Config::CUSTOM: return o1.customOrdinal < o2.customOrdinal;
600 default:
601 ALOGD("Unrecognized key; default to timestamp");
602 return o1.frameIndex < o2.frameIndex;
603 }
604 }
605
606 // LocalBufferPool
607
608 constexpr size_t kInitialPoolCapacity = kMaxLinearBufferSize;
609 constexpr size_t kMaxPoolCapacity = kMaxLinearBufferSize * 32;
610
Create()611 std::shared_ptr<LocalBufferPool> LocalBufferPool::Create() {
612 return std::shared_ptr<LocalBufferPool>(new LocalBufferPool(kInitialPoolCapacity));
613 }
614
newBuffer(size_t capacity)615 sp<ABuffer> LocalBufferPool::newBuffer(size_t capacity) {
616 Mutex::Autolock lock(mMutex);
617 auto it = std::find_if(
618 mPool.begin(), mPool.end(),
619 [capacity](const std::vector<uint8_t> &vec) {
620 return vec.capacity() >= capacity;
621 });
622 if (it != mPool.end()) {
623 sp<ABuffer> buffer = new VectorBuffer(std::move(*it), shared_from_this());
624 mPool.erase(it);
625 return buffer;
626 }
627 if (mUsedSize + capacity > mPoolCapacity) {
628 while (!mPool.empty()) {
629 mUsedSize -= mPool.back().capacity();
630 mPool.pop_back();
631 }
632 while (mUsedSize + capacity > mPoolCapacity && mPoolCapacity * 2 <= kMaxPoolCapacity) {
633 ALOGD("Increasing local buffer pool capacity from %zu to %zu",
634 mPoolCapacity, mPoolCapacity * 2);
635 mPoolCapacity *= 2;
636 }
637 if (mUsedSize + capacity > mPoolCapacity) {
638 ALOGD("mUsedSize = %zu, capacity = %zu, mPoolCapacity = %zu",
639 mUsedSize, capacity, mPoolCapacity);
640 return nullptr;
641 }
642 }
643 std::vector<uint8_t> vec(capacity);
644 mUsedSize += vec.capacity();
645 return new VectorBuffer(std::move(vec), shared_from_this());
646 }
647
VectorBuffer(std::vector<uint8_t> && vec,const std::shared_ptr<LocalBufferPool> & pool)648 LocalBufferPool::VectorBuffer::VectorBuffer(
649 std::vector<uint8_t> &&vec, const std::shared_ptr<LocalBufferPool> &pool)
650 : ABuffer(vec.data(), vec.capacity()),
651 mVec(std::move(vec)),
652 mPool(pool) {
653 }
654
~VectorBuffer()655 LocalBufferPool::VectorBuffer::~VectorBuffer() {
656 std::shared_ptr<LocalBufferPool> pool = mPool.lock();
657 if (pool) {
658 // If pool is alive, return the vector back to the pool so that
659 // it can be recycled.
660 pool->returnVector(std::move(mVec));
661 }
662 }
663
returnVector(std::vector<uint8_t> && vec)664 void LocalBufferPool::returnVector(std::vector<uint8_t> &&vec) {
665 Mutex::Autolock lock(mMutex);
666 mPool.push_front(std::move(vec));
667 }
668
669 // FlexBuffersImpl
670
assignSlot(const sp<Codec2Buffer> & buffer)671 size_t FlexBuffersImpl::assignSlot(const sp<Codec2Buffer> &buffer) {
672 for (size_t i = 0; i < mBuffers.size(); ++i) {
673 if (mBuffers[i].clientBuffer == nullptr
674 && mBuffers[i].compBuffer.expired()) {
675 mBuffers[i].clientBuffer = buffer;
676 return i;
677 }
678 }
679 mBuffers.push_back({ buffer, std::weak_ptr<C2Buffer>() });
680 return mBuffers.size() - 1;
681 }
682
releaseSlot(const sp<MediaCodecBuffer> & buffer,std::shared_ptr<C2Buffer> * c2buffer,bool release)683 bool FlexBuffersImpl::releaseSlot(
684 const sp<MediaCodecBuffer> &buffer,
685 std::shared_ptr<C2Buffer> *c2buffer,
686 bool release) {
687 sp<Codec2Buffer> clientBuffer;
688 size_t index = mBuffers.size();
689 for (size_t i = 0; i < mBuffers.size(); ++i) {
690 if (mBuffers[i].clientBuffer == buffer) {
691 clientBuffer = mBuffers[i].clientBuffer;
692 if (release) {
693 mBuffers[i].clientBuffer.clear();
694 }
695 index = i;
696 break;
697 }
698 }
699 if (clientBuffer == nullptr) {
700 ALOGV("[%s] %s: No matching buffer found", mName, __func__);
701 return false;
702 }
703 std::shared_ptr<C2Buffer> result = mBuffers[index].compBuffer.lock();
704 if (!result) {
705 result = clientBuffer->asC2Buffer();
706 clientBuffer->clearC2BufferRefs();
707 mBuffers[index].compBuffer = result;
708 }
709 if (c2buffer) {
710 *c2buffer = result;
711 }
712 return true;
713 }
714
expireComponentBuffer(const std::shared_ptr<C2Buffer> & c2buffer)715 bool FlexBuffersImpl::expireComponentBuffer(const std::shared_ptr<C2Buffer> &c2buffer) {
716 for (size_t i = 0; i < mBuffers.size(); ++i) {
717 std::shared_ptr<C2Buffer> compBuffer =
718 mBuffers[i].compBuffer.lock();
719 if (!compBuffer || compBuffer != c2buffer) {
720 continue;
721 }
722 mBuffers[i].compBuffer.reset();
723 ALOGV("[%s] codec released buffer #%zu", mName, i);
724 return true;
725 }
726 ALOGV("[%s] codec released an unknown buffer", mName);
727 return false;
728 }
729
flush()730 void FlexBuffersImpl::flush() {
731 ALOGV("[%s] buffers are flushed %zu", mName, mBuffers.size());
732 mBuffers.clear();
733 }
734
numActiveSlots() const735 size_t FlexBuffersImpl::numActiveSlots() const {
736 return std::count_if(
737 mBuffers.begin(), mBuffers.end(),
738 [](const Entry &entry) {
739 return (entry.clientBuffer != nullptr
740 || !entry.compBuffer.expired());
741 });
742 }
743
numComponentBuffers() const744 size_t FlexBuffersImpl::numComponentBuffers() const {
745 return std::count_if(
746 mBuffers.begin(), mBuffers.end(),
747 [](const Entry &entry) {
748 return !entry.compBuffer.expired();
749 });
750 }
751
752 // BuffersArrayImpl
753
initialize(const FlexBuffersImpl & impl,size_t minSize,std::function<sp<Codec2Buffer> ()> allocate)754 void BuffersArrayImpl::initialize(
755 const FlexBuffersImpl &impl,
756 size_t minSize,
757 std::function<sp<Codec2Buffer>()> allocate) {
758 mImplName = impl.mImplName + "[N]";
759 mName = mImplName.c_str();
760 for (size_t i = 0; i < impl.mBuffers.size(); ++i) {
761 sp<Codec2Buffer> clientBuffer = impl.mBuffers[i].clientBuffer;
762 bool ownedByClient = (clientBuffer != nullptr);
763 if (!ownedByClient) {
764 clientBuffer = allocate();
765 }
766 mBuffers.push_back({ clientBuffer, impl.mBuffers[i].compBuffer, ownedByClient });
767 }
768 ALOGV("[%s] converted %zu buffers to array mode of %zu", mName, mBuffers.size(), minSize);
769 for (size_t i = impl.mBuffers.size(); i < minSize; ++i) {
770 mBuffers.push_back({ allocate(), std::weak_ptr<C2Buffer>(), false });
771 }
772 }
773
grabBuffer(size_t * index,sp<Codec2Buffer> * buffer,std::function<bool (const sp<Codec2Buffer> &)> match)774 status_t BuffersArrayImpl::grabBuffer(
775 size_t *index,
776 sp<Codec2Buffer> *buffer,
777 std::function<bool(const sp<Codec2Buffer> &)> match) {
778 // allBuffersDontMatch remains true if all buffers are available but
779 // match() returns false for every buffer.
780 bool allBuffersDontMatch = true;
781 for (size_t i = 0; i < mBuffers.size(); ++i) {
782 if (!mBuffers[i].ownedByClient && mBuffers[i].compBuffer.expired()) {
783 if (match(mBuffers[i].clientBuffer)) {
784 mBuffers[i].ownedByClient = true;
785 *buffer = mBuffers[i].clientBuffer;
786 (*buffer)->meta()->clear();
787 (*buffer)->setRange(0, (*buffer)->capacity());
788 *index = i;
789 return OK;
790 }
791 } else {
792 allBuffersDontMatch = false;
793 }
794 }
795 return allBuffersDontMatch ? NO_MEMORY : WOULD_BLOCK;
796 }
797
returnBuffer(const sp<MediaCodecBuffer> & buffer,std::shared_ptr<C2Buffer> * c2buffer,bool release)798 bool BuffersArrayImpl::returnBuffer(
799 const sp<MediaCodecBuffer> &buffer,
800 std::shared_ptr<C2Buffer> *c2buffer,
801 bool release) {
802 sp<Codec2Buffer> clientBuffer;
803 size_t index = mBuffers.size();
804 for (size_t i = 0; i < mBuffers.size(); ++i) {
805 if (mBuffers[i].clientBuffer == buffer) {
806 if (!mBuffers[i].ownedByClient) {
807 ALOGD("[%s] Client returned a buffer it does not own according to our record: %zu",
808 mName, i);
809 }
810 clientBuffer = mBuffers[i].clientBuffer;
811 if (release) {
812 mBuffers[i].ownedByClient = false;
813 }
814 index = i;
815 break;
816 }
817 }
818 if (clientBuffer == nullptr) {
819 ALOGV("[%s] %s: No matching buffer found", mName, __func__);
820 return false;
821 }
822 ALOGV("[%s] %s: matching buffer found (index=%zu)", mName, __func__, index);
823 std::shared_ptr<C2Buffer> result = mBuffers[index].compBuffer.lock();
824 if (!result) {
825 result = clientBuffer->asC2Buffer();
826 clientBuffer->clearC2BufferRefs();
827 mBuffers[index].compBuffer = result;
828 }
829 if (c2buffer) {
830 *c2buffer = result;
831 }
832 return true;
833 }
834
expireComponentBuffer(const std::shared_ptr<C2Buffer> & c2buffer)835 bool BuffersArrayImpl::expireComponentBuffer(const std::shared_ptr<C2Buffer> &c2buffer) {
836 for (size_t i = 0; i < mBuffers.size(); ++i) {
837 std::shared_ptr<C2Buffer> compBuffer =
838 mBuffers[i].compBuffer.lock();
839 if (!compBuffer) {
840 continue;
841 }
842 if (c2buffer == compBuffer) {
843 if (mBuffers[i].ownedByClient) {
844 // This should not happen.
845 ALOGD("[%s] codec released a buffer owned by client "
846 "(index %zu)", mName, i);
847 }
848 mBuffers[i].compBuffer.reset();
849 ALOGV("[%s] codec released buffer #%zu(array mode)", mName, i);
850 return true;
851 }
852 }
853 ALOGV("[%s] codec released an unknown buffer (array mode)", mName);
854 return false;
855 }
856
getArray(Vector<sp<MediaCodecBuffer>> * array) const857 void BuffersArrayImpl::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
858 array->clear();
859 for (const Entry &entry : mBuffers) {
860 array->push(entry.clientBuffer);
861 }
862 }
863
flush()864 void BuffersArrayImpl::flush() {
865 for (Entry &entry : mBuffers) {
866 entry.ownedByClient = false;
867 }
868 }
869
realloc(std::function<sp<Codec2Buffer> ()> alloc)870 void BuffersArrayImpl::realloc(std::function<sp<Codec2Buffer>()> alloc) {
871 size_t size = mBuffers.size();
872 mBuffers.clear();
873 for (size_t i = 0; i < size; ++i) {
874 mBuffers.push_back({ alloc(), std::weak_ptr<C2Buffer>(), false });
875 }
876 }
877
grow(size_t newSize,std::function<sp<Codec2Buffer> ()> alloc)878 void BuffersArrayImpl::grow(
879 size_t newSize, std::function<sp<Codec2Buffer>()> alloc) {
880 CHECK_LT(mBuffers.size(), newSize);
881 while (mBuffers.size() < newSize) {
882 mBuffers.push_back({ alloc(), std::weak_ptr<C2Buffer>(), false });
883 }
884 }
885
numActiveSlots() const886 size_t BuffersArrayImpl::numActiveSlots() const {
887 return std::count_if(
888 mBuffers.begin(), mBuffers.end(),
889 [](const Entry &entry) {
890 return entry.ownedByClient || !entry.compBuffer.expired();
891 });
892 }
893
arraySize() const894 size_t BuffersArrayImpl::arraySize() const {
895 return mBuffers.size();
896 }
897
898 // InputBuffersArray
899
initialize(const FlexBuffersImpl & impl,size_t minSize,std::function<sp<Codec2Buffer> ()> allocate)900 void InputBuffersArray::initialize(
901 const FlexBuffersImpl &impl,
902 size_t minSize,
903 std::function<sp<Codec2Buffer>()> allocate) {
904 mAllocate = allocate;
905 mImpl.initialize(impl, minSize, allocate);
906 }
907
getArray(Vector<sp<MediaCodecBuffer>> * array) const908 void InputBuffersArray::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
909 mImpl.getArray(array);
910 }
911
requestNewBuffer(size_t * index,sp<MediaCodecBuffer> * buffer)912 bool InputBuffersArray::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
913 sp<Codec2Buffer> c2Buffer;
914 status_t err = mImpl.grabBuffer(index, &c2Buffer);
915 if (err == OK) {
916 c2Buffer->setFormat(mFormat);
917 handleImageData(c2Buffer);
918 *buffer = c2Buffer;
919 return true;
920 }
921 return false;
922 }
923
releaseBuffer(const sp<MediaCodecBuffer> & buffer,std::shared_ptr<C2Buffer> * c2buffer,bool release)924 bool InputBuffersArray::releaseBuffer(
925 const sp<MediaCodecBuffer> &buffer,
926 std::shared_ptr<C2Buffer> *c2buffer,
927 bool release) {
928 return mImpl.returnBuffer(buffer, c2buffer, release);
929 }
930
expireComponentBuffer(const std::shared_ptr<C2Buffer> & c2buffer)931 bool InputBuffersArray::expireComponentBuffer(
932 const std::shared_ptr<C2Buffer> &c2buffer) {
933 return mImpl.expireComponentBuffer(c2buffer);
934 }
935
flush()936 void InputBuffersArray::flush() {
937 mImpl.flush();
938 }
939
numActiveSlots() const940 size_t InputBuffersArray::numActiveSlots() const {
941 return mImpl.numActiveSlots();
942 }
943
createNewBuffer()944 sp<Codec2Buffer> InputBuffersArray::createNewBuffer() {
945 return mAllocate();
946 }
947
948 // SlotInputBuffers
949
requestNewBuffer(size_t * index,sp<MediaCodecBuffer> * buffer)950 bool SlotInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
951 sp<Codec2Buffer> newBuffer = createNewBuffer();
952 *index = mImpl.assignSlot(newBuffer);
953 *buffer = newBuffer;
954 return true;
955 }
956
releaseBuffer(const sp<MediaCodecBuffer> & buffer,std::shared_ptr<C2Buffer> * c2buffer,bool release)957 bool SlotInputBuffers::releaseBuffer(
958 const sp<MediaCodecBuffer> &buffer,
959 std::shared_ptr<C2Buffer> *c2buffer,
960 bool release) {
961 return mImpl.releaseSlot(buffer, c2buffer, release);
962 }
963
expireComponentBuffer(const std::shared_ptr<C2Buffer> & c2buffer)964 bool SlotInputBuffers::expireComponentBuffer(
965 const std::shared_ptr<C2Buffer> &c2buffer) {
966 return mImpl.expireComponentBuffer(c2buffer);
967 }
968
flush()969 void SlotInputBuffers::flush() {
970 mImpl.flush();
971 }
972
toArrayMode(size_t)973 std::unique_ptr<InputBuffers> SlotInputBuffers::toArrayMode(size_t) {
974 TRESPASS("Array mode should not be called at non-legacy mode");
975 return nullptr;
976 }
977
numActiveSlots() const978 size_t SlotInputBuffers::numActiveSlots() const {
979 return mImpl.numActiveSlots();
980 }
981
createNewBuffer()982 sp<Codec2Buffer> SlotInputBuffers::createNewBuffer() {
983 return new DummyContainerBuffer{mFormat, nullptr};
984 }
985
986 // LinearInputBuffers
987
requestNewBuffer(size_t * index,sp<MediaCodecBuffer> * buffer)988 bool LinearInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
989 ScopedTrace trace(ATRACE_TAG, "CCodec::LinearInputBuffers::requestNewBuffer");
990 sp<Codec2Buffer> newBuffer = createNewBuffer();
991 if (newBuffer == nullptr) {
992 return false;
993 }
994 *index = mImpl.assignSlot(newBuffer);
995 *buffer = newBuffer;
996 return true;
997 }
998
releaseBuffer(const sp<MediaCodecBuffer> & buffer,std::shared_ptr<C2Buffer> * c2buffer,bool release)999 bool LinearInputBuffers::releaseBuffer(
1000 const sp<MediaCodecBuffer> &buffer,
1001 std::shared_ptr<C2Buffer> *c2buffer,
1002 bool release) {
1003 return mImpl.releaseSlot(buffer, c2buffer, release);
1004 }
1005
expireComponentBuffer(const std::shared_ptr<C2Buffer> & c2buffer)1006 bool LinearInputBuffers::expireComponentBuffer(
1007 const std::shared_ptr<C2Buffer> &c2buffer) {
1008 return mImpl.expireComponentBuffer(c2buffer);
1009 }
1010
flush()1011 void LinearInputBuffers::flush() {
1012 // This is no-op by default unless we're in array mode where we need to keep
1013 // track of the flushed work.
1014 mImpl.flush();
1015 }
1016
toArrayMode(size_t size)1017 std::unique_ptr<InputBuffers> LinearInputBuffers::toArrayMode(size_t size) {
1018 std::unique_ptr<InputBuffersArray> array(
1019 new InputBuffersArray(mComponentName.c_str(), "1D-Input[N]"));
1020 array->setPool(mPool);
1021 array->setFormat(mFormat);
1022 array->initialize(
1023 mImpl,
1024 size,
1025 [pool = mPool, format = mFormat] () -> sp<Codec2Buffer> {
1026 return Alloc(pool, format);
1027 });
1028 return std::move(array);
1029 }
1030
numActiveSlots() const1031 size_t LinearInputBuffers::numActiveSlots() const {
1032 return mImpl.numActiveSlots();
1033 }
1034
1035 // static
Alloc(const std::shared_ptr<C2BlockPool> & pool,const sp<AMessage> & format)1036 sp<Codec2Buffer> LinearInputBuffers::Alloc(
1037 const std::shared_ptr<C2BlockPool> &pool, const sp<AMessage> &format) {
1038 int32_t capacity = kLinearBufferSize;
1039 (void)format->findInt32(KEY_MAX_INPUT_SIZE, &capacity);
1040 if ((size_t)capacity > kMaxLinearBufferSize) {
1041 ALOGD("client requested %d, capped to %zu", capacity, kMaxLinearBufferSize);
1042 capacity = kMaxLinearBufferSize;
1043 }
1044
1045 int64_t usageValue = 0;
1046 (void)format->findInt64("android._C2MemoryUsage", &usageValue);
1047 C2MemoryUsage usage{usageValue | C2MemoryUsage::CPU_READ | C2MemoryUsage::CPU_WRITE};
1048 std::shared_ptr<C2LinearBlock> block;
1049
1050 c2_status_t err = pool->fetchLinearBlock(capacity, usage, &block);
1051 if (err != C2_OK) {
1052 return nullptr;
1053 }
1054
1055 return LinearBlockBuffer::Allocate(format, block);
1056 }
1057
createNewBuffer()1058 sp<Codec2Buffer> LinearInputBuffers::createNewBuffer() {
1059 return Alloc(mPool, mFormat);
1060 }
1061
1062 // EncryptedLinearInputBuffers
1063
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)1064 EncryptedLinearInputBuffers::EncryptedLinearInputBuffers(
1065 bool secure,
1066 const sp<MemoryDealer> &dealer,
1067 const sp<ICrypto> &crypto,
1068 int32_t heapSeqNum,
1069 size_t capacity,
1070 size_t numInputSlots,
1071 const char *componentName, const char *name)
1072 : LinearInputBuffers(componentName, name),
1073 mUsage({0, 0}),
1074 mDealer(dealer),
1075 mCrypto(crypto),
1076 mMemoryVector(new std::vector<Entry>){
1077 if (secure) {
1078 mUsage = { C2MemoryUsage::READ_PROTECTED, 0 };
1079 } else {
1080 mUsage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
1081 }
1082 for (size_t i = 0; i < numInputSlots; ++i) {
1083 sp<IMemory> memory = mDealer->allocate(capacity);
1084 if (memory == nullptr) {
1085 ALOGD("[%s] Failed to allocate memory from dealer: only %zu slots allocated",
1086 mName, i);
1087 break;
1088 }
1089 mMemoryVector->push_back({std::weak_ptr<C2LinearBlock>(), memory, heapSeqNum});
1090 }
1091 }
1092
toArrayMode(size_t size)1093 std::unique_ptr<InputBuffers> EncryptedLinearInputBuffers::toArrayMode(size_t size) {
1094 std::unique_ptr<InputBuffersArray> array(
1095 new InputBuffersArray(mComponentName.c_str(), "1D-EncryptedInput[N]"));
1096 array->setPool(mPool);
1097 array->setFormat(mFormat);
1098 array->initialize(
1099 mImpl,
1100 size,
1101 [pool = mPool,
1102 format = mFormat,
1103 usage = mUsage,
1104 memoryVector = mMemoryVector] () -> sp<Codec2Buffer> {
1105 return Alloc(pool, format, usage, memoryVector);
1106 });
1107 return std::move(array);
1108 }
1109
1110
1111 // static
Alloc(const std::shared_ptr<C2BlockPool> & pool,const sp<AMessage> & format,C2MemoryUsage usage,const std::shared_ptr<std::vector<EncryptedLinearInputBuffers::Entry>> & memoryVector)1112 sp<Codec2Buffer> EncryptedLinearInputBuffers::Alloc(
1113 const std::shared_ptr<C2BlockPool> &pool,
1114 const sp<AMessage> &format,
1115 C2MemoryUsage usage,
1116 const std::shared_ptr<std::vector<EncryptedLinearInputBuffers::Entry>> &memoryVector) {
1117 int32_t capacity = kLinearBufferSize;
1118 (void)format->findInt32(KEY_MAX_INPUT_SIZE, &capacity);
1119 if ((size_t)capacity > kMaxLinearBufferSize) {
1120 ALOGD("client requested %d, capped to %zu", capacity, kMaxLinearBufferSize);
1121 capacity = kMaxLinearBufferSize;
1122 }
1123
1124 sp<IMemory> memory;
1125 size_t slot = 0;
1126 int32_t heapSeqNum = -1;
1127 for (; slot < memoryVector->size(); ++slot) {
1128 if (memoryVector->at(slot).block.expired()) {
1129 memory = memoryVector->at(slot).memory;
1130 heapSeqNum = memoryVector->at(slot).heapSeqNum;
1131 break;
1132 }
1133 }
1134 if (memory == nullptr) {
1135 return nullptr;
1136 }
1137
1138 int64_t usageValue = 0;
1139 (void)format->findInt64("android._C2MemoryUsage", &usageValue);
1140 usage = C2MemoryUsage(usage.expected | usageValue);
1141
1142 std::shared_ptr<C2LinearBlock> block;
1143 c2_status_t err = pool->fetchLinearBlock(capacity, usage, &block);
1144 if (err != C2_OK || block == nullptr) {
1145 return nullptr;
1146 }
1147
1148 memoryVector->at(slot).block = block;
1149 return new EncryptedLinearBlockBuffer(format, block, memory, heapSeqNum);
1150 }
1151
createNewBuffer()1152 sp<Codec2Buffer> EncryptedLinearInputBuffers::createNewBuffer() {
1153 // TODO: android_2020
1154 return nullptr;
1155 }
1156
1157 // GraphicMetadataInputBuffers
1158
GraphicMetadataInputBuffers(const char * componentName,const char * name)1159 GraphicMetadataInputBuffers::GraphicMetadataInputBuffers(
1160 const char *componentName, const char *name)
1161 : InputBuffers(componentName, name),
1162 mImpl(mName),
1163 mStore(GetCodec2PlatformAllocatorStore()) { }
1164
requestNewBuffer(size_t * index,sp<MediaCodecBuffer> * buffer)1165 bool GraphicMetadataInputBuffers::requestNewBuffer(
1166 size_t *index, sp<MediaCodecBuffer> *buffer) {
1167 sp<Codec2Buffer> newBuffer = createNewBuffer();
1168 if (newBuffer == nullptr) {
1169 return false;
1170 }
1171 *index = mImpl.assignSlot(newBuffer);
1172 *buffer = newBuffer;
1173 return true;
1174 }
1175
releaseBuffer(const sp<MediaCodecBuffer> & buffer,std::shared_ptr<C2Buffer> * c2buffer,bool release)1176 bool GraphicMetadataInputBuffers::releaseBuffer(
1177 const sp<MediaCodecBuffer> &buffer,
1178 std::shared_ptr<C2Buffer> *c2buffer,
1179 bool release) {
1180 return mImpl.releaseSlot(buffer, c2buffer, release);
1181 }
1182
expireComponentBuffer(const std::shared_ptr<C2Buffer> & c2buffer)1183 bool GraphicMetadataInputBuffers::expireComponentBuffer(
1184 const std::shared_ptr<C2Buffer> &c2buffer) {
1185 return mImpl.expireComponentBuffer(c2buffer);
1186 }
1187
flush()1188 void GraphicMetadataInputBuffers::flush() {
1189 // This is no-op by default unless we're in array mode where we need to keep
1190 // track of the flushed work.
1191 }
1192
toArrayMode(size_t size)1193 std::unique_ptr<InputBuffers> GraphicMetadataInputBuffers::toArrayMode(
1194 size_t size) {
1195 std::shared_ptr<C2Allocator> alloc;
1196 c2_status_t err = mStore->fetchAllocator(mPool->getAllocatorId(), &alloc);
1197 if (err != C2_OK) {
1198 return nullptr;
1199 }
1200 std::unique_ptr<InputBuffersArray> array(
1201 new InputBuffersArray(mComponentName.c_str(), "2D-MetaInput[N]"));
1202 array->setPool(mPool);
1203 array->setFormat(mFormat);
1204 array->initialize(
1205 mImpl,
1206 size,
1207 [format = mFormat, alloc]() -> sp<Codec2Buffer> {
1208 return new GraphicMetadataBuffer(format, alloc);
1209 });
1210 return std::move(array);
1211 }
1212
numActiveSlots() const1213 size_t GraphicMetadataInputBuffers::numActiveSlots() const {
1214 return mImpl.numActiveSlots();
1215 }
1216
createNewBuffer()1217 sp<Codec2Buffer> GraphicMetadataInputBuffers::createNewBuffer() {
1218 std::shared_ptr<C2Allocator> alloc;
1219 c2_status_t err = mStore->fetchAllocator(mPool->getAllocatorId(), &alloc);
1220 if (err != C2_OK) {
1221 return nullptr;
1222 }
1223 return new GraphicMetadataBuffer(mFormat, alloc);
1224 }
1225
1226 // GraphicInputBuffers
1227
GraphicInputBuffers(const char * componentName,const char * name)1228 GraphicInputBuffers::GraphicInputBuffers(
1229 const char *componentName, const char *name)
1230 : InputBuffers(componentName, name),
1231 mImpl(mName),
1232 mLocalBufferPool(LocalBufferPool::Create()),
1233 mPixelFormat(PIXEL_FORMAT_UNKNOWN) { }
1234
requestNewBuffer(size_t * index,sp<MediaCodecBuffer> * buffer)1235 bool GraphicInputBuffers::requestNewBuffer(size_t *index, sp<MediaCodecBuffer> *buffer) {
1236 sp<Codec2Buffer> newBuffer = createNewBuffer();
1237 if (newBuffer == nullptr) {
1238 return false;
1239 }
1240 *index = mImpl.assignSlot(newBuffer);
1241 handleImageData(newBuffer);
1242 *buffer = newBuffer;
1243 return true;
1244 }
1245
releaseBuffer(const sp<MediaCodecBuffer> & buffer,std::shared_ptr<C2Buffer> * c2buffer,bool release)1246 bool GraphicInputBuffers::releaseBuffer(
1247 const sp<MediaCodecBuffer> &buffer,
1248 std::shared_ptr<C2Buffer> *c2buffer,
1249 bool release) {
1250 return mImpl.releaseSlot(buffer, c2buffer, release);
1251 }
1252
expireComponentBuffer(const std::shared_ptr<C2Buffer> & c2buffer)1253 bool GraphicInputBuffers::expireComponentBuffer(
1254 const std::shared_ptr<C2Buffer> &c2buffer) {
1255 return mImpl.expireComponentBuffer(c2buffer);
1256 }
1257
flush()1258 void GraphicInputBuffers::flush() {
1259 // This is no-op by default unless we're in array mode where we need to keep
1260 // track of the flushed work.
1261 }
1262
extractPixelFormat(const sp<AMessage> & format)1263 static uint32_t extractPixelFormat(const sp<AMessage> &format) {
1264 int32_t frameworkColorFormat = 0;
1265 if (!format->findInt32("android._color-format", &frameworkColorFormat)) {
1266 return PIXEL_FORMAT_UNKNOWN;
1267 }
1268 uint32_t pixelFormat = PIXEL_FORMAT_UNKNOWN;
1269 if (C2Mapper::mapPixelFormatFrameworkToCodec(frameworkColorFormat, &pixelFormat)) {
1270 return pixelFormat;
1271 }
1272 return PIXEL_FORMAT_UNKNOWN;
1273 }
1274
toArrayMode(size_t size)1275 std::unique_ptr<InputBuffers> GraphicInputBuffers::toArrayMode(size_t size) {
1276 std::unique_ptr<InputBuffersArray> array(
1277 new InputBuffersArray(mComponentName.c_str(), "2D-BB-Input[N]"));
1278 array->setPool(mPool);
1279 array->setFormat(mFormat);
1280 uint32_t pixelFormat = extractPixelFormat(mFormat);
1281 array->initialize(
1282 mImpl,
1283 size,
1284 [pool = mPool, format = mFormat, lbp = mLocalBufferPool, pixelFormat]()
1285 -> sp<Codec2Buffer> {
1286 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
1287 return AllocateInputGraphicBuffer(
1288 pool, format, pixelFormat, usage, lbp);
1289 });
1290 return std::move(array);
1291 }
1292
numActiveSlots() const1293 size_t GraphicInputBuffers::numActiveSlots() const {
1294 return mImpl.numActiveSlots();
1295 }
1296
createNewBuffer()1297 sp<Codec2Buffer> GraphicInputBuffers::createNewBuffer() {
1298 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
1299 mPixelFormat = extractPixelFormat(mFormat);
1300 return AllocateInputGraphicBuffer(
1301 mPool, mFormat, mPixelFormat, usage, mLocalBufferPool);
1302 }
1303
getPixelFormatIfApplicable()1304 uint32_t GraphicInputBuffers::getPixelFormatIfApplicable() { return mPixelFormat; }
1305
resetPixelFormatIfApplicable()1306 bool GraphicInputBuffers::resetPixelFormatIfApplicable() {
1307 mPixelFormat = PIXEL_FORMAT_UNKNOWN;
1308 return true;
1309 }
1310
1311 // OutputBuffersArray
1312
initialize(const FlexBuffersImpl & impl,size_t minSize,std::function<sp<Codec2Buffer> ()> allocate)1313 void OutputBuffersArray::initialize(
1314 const FlexBuffersImpl &impl,
1315 size_t minSize,
1316 std::function<sp<Codec2Buffer>()> allocate) {
1317 mAlloc = allocate;
1318 mImpl.initialize(impl, minSize, allocate);
1319 }
1320
registerBuffer(const std::shared_ptr<C2Buffer> & buffer,size_t * index,sp<MediaCodecBuffer> * clientBuffer)1321 status_t OutputBuffersArray::registerBuffer(
1322 const std::shared_ptr<C2Buffer> &buffer,
1323 size_t *index,
1324 sp<MediaCodecBuffer> *clientBuffer) {
1325 sp<Codec2Buffer> c2Buffer;
1326 status_t err = mImpl.grabBuffer(
1327 index,
1328 &c2Buffer,
1329 [buffer](const sp<Codec2Buffer> &clientBuffer) {
1330 return clientBuffer->canCopy(buffer);
1331 });
1332 if (err == WOULD_BLOCK) {
1333 ALOGV("[%s] buffers temporarily not available", mName);
1334 return err;
1335 } else if (err != OK) {
1336 ALOGD("[%s] grabBuffer failed: %d", mName, err);
1337 return err;
1338 }
1339 c2Buffer->setFormat(mFormat);
1340 if (!convert(buffer, &c2Buffer) && !c2Buffer->copy(buffer)) {
1341 ALOGD("[%s] copy buffer failed", mName);
1342 return WOULD_BLOCK;
1343 }
1344 if (buffer && buffer->hasInfo(C2AccessUnitInfos::output::PARAM_TYPE)) {
1345 std::shared_ptr<const C2AccessUnitInfos::output> bufferMetadata =
1346 std::static_pointer_cast<const C2AccessUnitInfos::output>(
1347 buffer->getInfo(C2AccessUnitInfos::output::PARAM_TYPE));
1348 if (submit(c2Buffer, mSampleRate, mChannelCount, bufferMetadata)) {
1349 buffer->removeInfo(C2AccessUnitInfos::output::PARAM_TYPE);
1350 }
1351 } else {
1352 submit(c2Buffer);
1353 }
1354 handleImageData(c2Buffer);
1355 *clientBuffer = c2Buffer;
1356 ALOGV("[%s] grabbed buffer %zu", mName, *index);
1357 return OK;
1358 }
1359
registerCsd(const C2StreamInitDataInfo::output * csd,size_t * index,sp<MediaCodecBuffer> * clientBuffer)1360 status_t OutputBuffersArray::registerCsd(
1361 const C2StreamInitDataInfo::output *csd,
1362 size_t *index,
1363 sp<MediaCodecBuffer> *clientBuffer) {
1364 sp<Codec2Buffer> c2Buffer;
1365 status_t err = mImpl.grabBuffer(
1366 index,
1367 &c2Buffer,
1368 [csd](const sp<Codec2Buffer> &clientBuffer) {
1369 return clientBuffer->base() != nullptr
1370 && clientBuffer->capacity() >= csd->flexCount();
1371 });
1372 if (err != OK) {
1373 return err;
1374 }
1375 memcpy(c2Buffer->base(), csd->m.value, csd->flexCount());
1376 c2Buffer->setRange(0, csd->flexCount());
1377 c2Buffer->setFormat(mFormat);
1378 *clientBuffer = c2Buffer;
1379 return OK;
1380 }
1381
releaseBuffer(const sp<MediaCodecBuffer> & buffer,std::shared_ptr<C2Buffer> * c2buffer)1382 bool OutputBuffersArray::releaseBuffer(
1383 const sp<MediaCodecBuffer> &buffer, std::shared_ptr<C2Buffer> *c2buffer) {
1384 return mImpl.returnBuffer(buffer, c2buffer, true);
1385 }
1386
flush(const std::list<std::unique_ptr<C2Work>> & flushedWork)1387 void OutputBuffersArray::flush(const std::list<std::unique_ptr<C2Work>> &flushedWork) {
1388 (void)flushedWork;
1389 mImpl.flush();
1390 if (mSkipCutBuffer != nullptr) {
1391 mSkipCutBuffer->clearAll();
1392 }
1393 }
1394
getArray(Vector<sp<MediaCodecBuffer>> * array) const1395 void OutputBuffersArray::getArray(Vector<sp<MediaCodecBuffer>> *array) const {
1396 mImpl.getArray(array);
1397 }
1398
numActiveSlots() const1399 size_t OutputBuffersArray::numActiveSlots() const {
1400 return mImpl.numActiveSlots();
1401 }
1402
realloc(const std::shared_ptr<C2Buffer> & c2buffer)1403 void OutputBuffersArray::realloc(const std::shared_ptr<C2Buffer> &c2buffer) {
1404 switch (c2buffer->data().type()) {
1405 case C2BufferData::LINEAR: {
1406 uint32_t size = kLinearBufferSize;
1407 const std::vector<C2ConstLinearBlock> &linear_blocks = c2buffer->data().linearBlocks();
1408 const uint32_t block_size = linear_blocks.front().size();
1409 if (block_size < kMaxLinearBufferSize / 2) {
1410 size = block_size * 2;
1411 } else {
1412 size = kMaxLinearBufferSize;
1413 }
1414 mAlloc = [format = mFormat, size] {
1415 return new LocalLinearBuffer(format, new ABuffer(size));
1416 };
1417 ALOGD("[%s] reallocating with linear buffer of size %u", mName, size);
1418 break;
1419 }
1420
1421 case C2BufferData::GRAPHIC: {
1422 // This is only called for RawGraphicOutputBuffers.
1423 mAlloc = [format = mFormat,
1424 lbp = LocalBufferPool::Create()] {
1425 return ConstGraphicBlockBuffer::AllocateEmpty(
1426 format,
1427 [lbp](size_t capacity) {
1428 return lbp->newBuffer(capacity);
1429 });
1430 };
1431 ALOGD("[%s] reallocating with graphic buffer: format = %s",
1432 mName, mFormat->debugString().c_str());
1433 break;
1434 }
1435
1436 case C2BufferData::INVALID: [[fallthrough]];
1437 case C2BufferData::LINEAR_CHUNKS: [[fallthrough]];
1438 case C2BufferData::GRAPHIC_CHUNKS: [[fallthrough]];
1439 default:
1440 ALOGD("Unsupported type: %d", (int)c2buffer->data().type());
1441 return;
1442 }
1443 mImpl.realloc(mAlloc);
1444 }
1445
grow(size_t newSize)1446 void OutputBuffersArray::grow(size_t newSize) {
1447 mImpl.grow(newSize, mAlloc);
1448 }
1449
transferFrom(OutputBuffers * source)1450 void OutputBuffersArray::transferFrom(OutputBuffers* source) {
1451 mFormat = source->mFormat;
1452 mSkipCutBuffer = source->mSkipCutBuffer;
1453 mPending = std::move(source->mPending);
1454 mReorderStash = std::move(source->mReorderStash);
1455 mDepth = source->mDepth;
1456 mKey = source->mKey;
1457 }
1458
1459 // FlexOutputBuffers
1460
registerBuffer(const std::shared_ptr<C2Buffer> & buffer,size_t * index,sp<MediaCodecBuffer> * clientBuffer)1461 status_t FlexOutputBuffers::registerBuffer(
1462 const std::shared_ptr<C2Buffer> &buffer,
1463 size_t *index,
1464 sp<MediaCodecBuffer> *clientBuffer) {
1465 sp<Codec2Buffer> newBuffer;
1466 if (!convert(buffer, &newBuffer)) {
1467 newBuffer = wrap(buffer);
1468 if (newBuffer == nullptr) {
1469 return NO_MEMORY;
1470 }
1471 newBuffer->setFormat(mFormat);
1472 }
1473 *index = mImpl.assignSlot(newBuffer);
1474 handleImageData(newBuffer);
1475 *clientBuffer = newBuffer;
1476
1477 extractPixelFormatFromC2Buffer(buffer);
1478 ALOGV("[%s] registered buffer %zu", mName, *index);
1479 return OK;
1480 }
1481
registerCsd(const C2StreamInitDataInfo::output * csd,size_t * index,sp<MediaCodecBuffer> * clientBuffer)1482 status_t FlexOutputBuffers::registerCsd(
1483 const C2StreamInitDataInfo::output *csd,
1484 size_t *index,
1485 sp<MediaCodecBuffer> *clientBuffer) {
1486 sp<Codec2Buffer> newBuffer = new LocalLinearBuffer(
1487 mFormat, ABuffer::CreateAsCopy(csd->m.value, csd->flexCount()));
1488 *index = mImpl.assignSlot(newBuffer);
1489 *clientBuffer = newBuffer;
1490 return OK;
1491 }
1492
releaseBuffer(const sp<MediaCodecBuffer> & buffer,std::shared_ptr<C2Buffer> * c2buffer)1493 bool FlexOutputBuffers::releaseBuffer(
1494 const sp<MediaCodecBuffer> &buffer,
1495 std::shared_ptr<C2Buffer> *c2buffer) {
1496 return mImpl.releaseSlot(buffer, c2buffer, true);
1497 }
1498
flush(const std::list<std::unique_ptr<C2Work>> & flushedWork)1499 void FlexOutputBuffers::flush(
1500 const std::list<std::unique_ptr<C2Work>> &flushedWork) {
1501 (void) flushedWork;
1502 // This is no-op by default unless we're in array mode where we need to keep
1503 // track of the flushed work.
1504 }
1505
toArrayMode(size_t size)1506 std::unique_ptr<OutputBuffersArray> FlexOutputBuffers::toArrayMode(size_t size) {
1507 std::unique_ptr<OutputBuffersArray> array(new OutputBuffersArray(mComponentName.c_str()));
1508 array->transferFrom(this);
1509 std::function<sp<Codec2Buffer>()> alloc = getAlloc();
1510 array->initialize(mImpl, size, alloc);
1511 return array;
1512 }
1513
numActiveSlots() const1514 size_t FlexOutputBuffers::numActiveSlots() const {
1515 return mImpl.numActiveSlots();
1516 }
1517
extractPixelFormatFromC2Buffer(const std::shared_ptr<C2Buffer> & buffer)1518 bool FlexOutputBuffers::extractPixelFormatFromC2Buffer(const std::shared_ptr<C2Buffer> &buffer) {
1519 if (buffer == nullptr) {
1520 return false;
1521 }
1522 const C2BufferData &data = buffer->data();
1523 // only extract the first pixel format in a metric session.
1524 if (mPixelFormat != PIXEL_FORMAT_UNKNOWN || data.type() != C2BufferData::GRAPHIC
1525 || data.graphicBlocks().empty()) {
1526 return false;
1527 }
1528 const C2Handle *const handle = data.graphicBlocks().front().handle();
1529 uint32_t pf = ExtractFormatFromCodec2GrallocHandle(handle);
1530 if (pf == PIXEL_FORMAT_UNKNOWN) {
1531 return false;
1532 }
1533 mPixelFormat = pf;
1534 return true;
1535 }
1536
resetPixelFormatIfApplicable()1537 bool FlexOutputBuffers::resetPixelFormatIfApplicable() {
1538 mPixelFormat = PIXEL_FORMAT_UNKNOWN;
1539 return true;
1540 }
1541
getPixelFormatIfApplicable()1542 uint32_t FlexOutputBuffers::getPixelFormatIfApplicable() { return mPixelFormat; }
1543
1544 // LinearOutputBuffers
1545
flush(const std::list<std::unique_ptr<C2Work>> & flushedWork)1546 void LinearOutputBuffers::flush(
1547 const std::list<std::unique_ptr<C2Work>> &flushedWork) {
1548 if (mSkipCutBuffer != nullptr) {
1549 mSkipCutBuffer->clearAll();
1550 }
1551 FlexOutputBuffers::flush(flushedWork);
1552 }
1553
wrap(const std::shared_ptr<C2Buffer> & buffer)1554 sp<Codec2Buffer> LinearOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
1555 if (buffer == nullptr) {
1556 ALOGD("[%s] received null buffer", mName);
1557 return new LocalLinearBuffer(mFormat, new ABuffer(0));
1558 }
1559 if (buffer->data().type() != C2BufferData::LINEAR) {
1560 ALOGW("[%s] non-linear buffer %d", mName, buffer->data().type());
1561 // We expect linear output buffers from the component.
1562 return nullptr;
1563 }
1564 if (buffer->data().linearBlocks().size() != 1u) {
1565 ALOGW("[%s] no linear buffers", mName);
1566 // We expect one and only one linear block from the component.
1567 return nullptr;
1568 }
1569 if (buffer->data().linearBlocks().front().size() == 0) {
1570 ALOGD("[%s] received 0-sized buffer", mName);
1571 return new LocalLinearBuffer(mFormat, new ABuffer(0));
1572 }
1573 sp<Codec2Buffer> clientBuffer = ConstLinearBlockBuffer::Allocate(mFormat, buffer);
1574 if (clientBuffer == nullptr) {
1575 ALOGD("[%s] ConstLinearBlockBuffer::Allocate failed", mName);
1576 return nullptr;
1577 }
1578 submit(clientBuffer);
1579 return clientBuffer;
1580 }
1581
getAlloc()1582 std::function<sp<Codec2Buffer>()> LinearOutputBuffers::getAlloc() {
1583 return [format = mFormat]{
1584 // TODO: proper max output size
1585 return new LocalLinearBuffer(format, new ABuffer(kLinearBufferSize));
1586 };
1587 }
1588
1589 // GraphicOutputBuffers
1590
wrap(const std::shared_ptr<C2Buffer> & buffer)1591 sp<Codec2Buffer> GraphicOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
1592 return new DummyContainerBuffer(mFormat, buffer);
1593 }
1594
getAlloc()1595 std::function<sp<Codec2Buffer>()> GraphicOutputBuffers::getAlloc() {
1596 return [format = mFormat]{
1597 return new DummyContainerBuffer(format);
1598 };
1599 }
1600
1601 // RawGraphicOutputBuffers
1602
RawGraphicOutputBuffers(const char * componentName,const char * name)1603 RawGraphicOutputBuffers::RawGraphicOutputBuffers(
1604 const char *componentName, const char *name)
1605 : FlexOutputBuffers(componentName, name),
1606 mLocalBufferPool(LocalBufferPool::Create()) { }
1607
wrap(const std::shared_ptr<C2Buffer> & buffer)1608 sp<Codec2Buffer> RawGraphicOutputBuffers::wrap(const std::shared_ptr<C2Buffer> &buffer) {
1609 if (buffer == nullptr) {
1610 return new Codec2Buffer(mFormat, new ABuffer(nullptr, 0));
1611 } else {
1612 return ConstGraphicBlockBuffer::Allocate(
1613 mFormat,
1614 buffer,
1615 [lbp = mLocalBufferPool](size_t capacity) {
1616 return lbp->newBuffer(capacity);
1617 });
1618 }
1619 }
1620
getAlloc()1621 std::function<sp<Codec2Buffer>()> RawGraphicOutputBuffers::getAlloc() {
1622 return [format = mFormat, lbp = mLocalBufferPool]{
1623 return ConstGraphicBlockBuffer::AllocateEmpty(
1624 format,
1625 [lbp](size_t capacity) {
1626 return lbp->newBuffer(capacity);
1627 });
1628 };
1629 }
1630
1631 } // namespace android
1632