1 /*
2  * Copyright 2017, 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 #include <utils/Errors.h>
19 #define LOG_TAG "CCodecBufferChannel"
20 #define ATRACE_TAG  ATRACE_TAG_VIDEO
21 #include <utils/Log.h>
22 #include <utils/Trace.h>
23 
24 #include <algorithm>
25 #include <atomic>
26 #include <list>
27 #include <numeric>
28 #include <thread>
29 #include <chrono>
30 
31 #include <android_media_codec.h>
32 
33 #include <C2AllocatorGralloc.h>
34 #include <C2PlatformSupport.h>
35 #include <C2BlockInternal.h>
36 #include <C2Config.h>
37 #include <C2Debug.h>
38 
39 #include <android/hardware/cas/native/1.0/IDescrambler.h>
40 #include <android/hardware/drm/1.0/types.h>
41 #include <android-base/parseint.h>
42 #include <android-base/properties.h>
43 #include <android-base/stringprintf.h>
44 #include <binder/MemoryBase.h>
45 #include <binder/MemoryDealer.h>
46 #include <cutils/properties.h>
47 #include <gui/Surface.h>
48 #include <hidlmemory/FrameworkUtils.h>
49 #include <media/openmax/OMX_Core.h>
50 #include <media/stagefright/foundation/ABuffer.h>
51 #include <media/stagefright/foundation/ALookup.h>
52 #include <media/stagefright/foundation/AMessage.h>
53 #include <media/stagefright/foundation/AUtils.h>
54 #include <media/stagefright/foundation/hexdump.h>
55 #include <media/stagefright/MediaCodecConstants.h>
56 #include <media/stagefright/SkipCutBuffer.h>
57 #include <media/stagefright/SurfaceUtils.h>
58 #include <media/MediaCodecBuffer.h>
59 #include <mediadrm/ICrypto.h>
60 #include <server_configurable_flags/get_flags.h>
61 #include <system/window.h>
62 
63 #include "CCodecBufferChannel.h"
64 #include "Codec2Buffer.h"
65 
66 namespace android {
67 
68 using android::base::StringPrintf;
69 using hardware::hidl_handle;
70 using hardware::hidl_string;
71 using hardware::hidl_vec;
72 using hardware::fromHeap;
73 using hardware::HidlMemory;
74 using server_configurable_flags::GetServerConfigurableFlag;
75 
76 using namespace hardware::cas::V1_0;
77 using namespace hardware::cas::native::V1_0;
78 
79 using CasStatus = hardware::cas::V1_0::Status;
80 using DrmBufferType = hardware::drm::V1_0::BufferType;
81 
82 namespace {
83 
84 constexpr size_t kSmoothnessFactor = 4;
85 
86 // This is for keeping IGBP's buffer dropping logic in legacy mode other
87 // than making it non-blocking. Do not change this value.
88 const static size_t kDequeueTimeoutNs = 0;
89 
areRenderMetricsEnabled()90 static bool areRenderMetricsEnabled() {
91     std::string v = GetServerConfigurableFlag("media_native", "render_metrics_enabled", "false");
92     return v == "true";
93 }
94 
95 // Flags can come with individual BufferInfos
96 // when used with large frame audio
97 constexpr static std::initializer_list<std::pair<uint32_t, uint32_t>> flagList = {
98         {BUFFER_FLAG_CODEC_CONFIG, C2FrameData::FLAG_CODEC_CONFIG},
99         {BUFFER_FLAG_END_OF_STREAM, C2FrameData::FLAG_END_OF_STREAM},
100         {BUFFER_FLAG_DECODE_ONLY, C2FrameData::FLAG_DROP_FRAME}
101 };
102 
convertFlags(uint32_t flags,bool toC2)103 static uint32_t convertFlags(uint32_t flags, bool toC2) {
104     return std::transform_reduce(
105             flagList.begin(), flagList.end(),
106             0u,
107             std::bit_or{},
108             [flags, toC2](const std::pair<uint32_t, uint32_t> &entry) {
109                 if (toC2) {
110                     return (flags & entry.first) ? entry.second : 0;
111                 } else {
112                     return (flags & entry.second) ? entry.first : 0;
113                 }
114             });
115 }
116 
117 }  // namespace
118 
QueueGuard(CCodecBufferChannel::QueueSync & sync)119 CCodecBufferChannel::QueueGuard::QueueGuard(
120         CCodecBufferChannel::QueueSync &sync) : mSync(sync) {
121     Mutex::Autolock l(mSync.mGuardLock);
122     // At this point it's guaranteed that mSync is not under state transition,
123     // as we are holding its mutex.
124 
125     Mutexed<CCodecBufferChannel::QueueSync::Counter>::Locked count(mSync.mCount);
126     if (count->value == -1) {
127         mRunning = false;
128     } else {
129         ++count->value;
130         mRunning = true;
131     }
132 }
133 
~QueueGuard()134 CCodecBufferChannel::QueueGuard::~QueueGuard() {
135     if (mRunning) {
136         // We are not holding mGuardLock at this point so that QueueSync::stop() can
137         // keep holding the lock until mCount reaches zero.
138         Mutexed<CCodecBufferChannel::QueueSync::Counter>::Locked count(mSync.mCount);
139         --count->value;
140         count->cond.broadcast();
141     }
142 }
143 
start()144 void CCodecBufferChannel::QueueSync::start() {
145     Mutex::Autolock l(mGuardLock);
146     // If stopped, it goes to running state; otherwise no-op.
147     Mutexed<Counter>::Locked count(mCount);
148     if (count->value == -1) {
149         count->value = 0;
150     }
151 }
152 
stop()153 void CCodecBufferChannel::QueueSync::stop() {
154     Mutex::Autolock l(mGuardLock);
155     Mutexed<Counter>::Locked count(mCount);
156     if (count->value == -1) {
157         // no-op
158         return;
159     }
160     // Holding mGuardLock here blocks creation of additional QueueGuard objects, so
161     // mCount can only decrement. In other words, threads that acquired the lock
162     // are allowed to finish execution but additional threads trying to acquire
163     // the lock at this point will block, and then get QueueGuard at STOPPED
164     // state.
165     while (count->value != 0) {
166         count.waitForCondition(count->cond);
167     }
168     count->value = -1;
169 }
170 
171 // Input
172 
Input()173 CCodecBufferChannel::Input::Input() : extraBuffers("extra") {}
174 
175 // CCodecBufferChannel
176 
CCodecBufferChannel(const std::shared_ptr<CCodecCallback> & callback)177 CCodecBufferChannel::CCodecBufferChannel(
178         const std::shared_ptr<CCodecCallback> &callback)
179     : mHeapSeqNum(-1),
180       mCCodecCallback(callback),
181       mFrameIndex(0u),
182       mFirstValidFrameIndex(0u),
183       mAreRenderMetricsEnabled(areRenderMetricsEnabled()),
184       mIsSurfaceToDisplay(false),
185       mHasPresentFenceTimes(false),
186       mRenderingDepth(3u),
187       mMetaMode(MODE_NONE),
188       mInputMetEos(false),
189       mSendEncryptedInfoBuffer(false) {
190     {
191         Mutexed<Input>::Locked input(mInput);
192         input->buffers.reset(new DummyInputBuffers(""));
193         input->extraBuffers.flush();
194         input->inputDelay = 0u;
195         input->pipelineDelay = 0u;
196         input->numSlots = kSmoothnessFactor;
197         input->numExtraSlots = 0u;
198         input->lastFlushIndex = 0u;
199     }
200     {
201         Mutexed<Output>::Locked output(mOutput);
202         output->outputDelay = 0u;
203         output->numSlots = kSmoothnessFactor;
204         output->bounded = false;
205     }
206     {
207         Mutexed<BlockPools>::Locked pools(mBlockPools);
208         pools->outputPoolId = C2BlockPool::BASIC_LINEAR;
209     }
210     std::string value = GetServerConfigurableFlag("media_native", "ccodec_rendering_depth", "3");
211     android::base::ParseInt(value, &mRenderingDepth);
212     mOutputSurface.lock()->maxDequeueBuffers = kSmoothnessFactor + mRenderingDepth;
213 }
214 
~CCodecBufferChannel()215 CCodecBufferChannel::~CCodecBufferChannel() {
216     if (mCrypto != nullptr && mHeapSeqNum >= 0) {
217         mCrypto->unsetHeap(mHeapSeqNum);
218     }
219 }
220 
setComponent(const std::shared_ptr<Codec2Client::Component> & component)221 void CCodecBufferChannel::setComponent(
222         const std::shared_ptr<Codec2Client::Component> &component) {
223     mComponent = component;
224     mComponentName = component->getName() + StringPrintf("#%d", int(uintptr_t(component.get()) % 997));
225     mName = mComponentName.c_str();
226 }
227 
setInputSurface(const std::shared_ptr<InputSurfaceWrapper> & surface)228 status_t CCodecBufferChannel::setInputSurface(
229         const std::shared_ptr<InputSurfaceWrapper> &surface) {
230     ALOGV("[%s] setInputSurface", mName);
231     mInputSurface = surface;
232     return mInputSurface->connect(mComponent);
233 }
234 
signalEndOfInputStream()235 status_t CCodecBufferChannel::signalEndOfInputStream() {
236     if (mInputSurface == nullptr) {
237         return INVALID_OPERATION;
238     }
239     return mInputSurface->signalEndOfInputStream();
240 }
241 
queueInputBufferInternal(sp<MediaCodecBuffer> buffer,std::shared_ptr<C2LinearBlock> encryptedBlock,size_t blockSize)242 status_t CCodecBufferChannel::queueInputBufferInternal(
243         sp<MediaCodecBuffer> buffer,
244         std::shared_ptr<C2LinearBlock> encryptedBlock,
245         size_t blockSize) {
246     int64_t timeUs;
247     CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
248 
249     if (mInputMetEos) {
250         ALOGD("[%s] buffers after EOS ignored (%lld us)", mName, (long long)timeUs);
251         return OK;
252     }
253 
254     int32_t flags = 0;
255     int32_t tmp = 0;
256     bool eos = false;
257     bool tunnelFirstFrame = false;
258     if (buffer->meta()->findInt32("eos", &tmp) && tmp) {
259         eos = true;
260         mInputMetEos = true;
261         ALOGV("[%s] input EOS", mName);
262     }
263     if (buffer->meta()->findInt32("csd", &tmp) && tmp) {
264         flags |= C2FrameData::FLAG_CODEC_CONFIG;
265     }
266     if (buffer->meta()->findInt32("tunnel-first-frame", &tmp) && tmp) {
267         tunnelFirstFrame = true;
268     }
269     if (buffer->meta()->findInt32("decode-only", &tmp) && tmp) {
270         flags |= C2FrameData::FLAG_DROP_FRAME;
271     }
272     ALOGV("[%s] queueInputBuffer: buffer->size() = %zu time: %lld",
273             mName, buffer->size(), (long long)timeUs);
274     std::list<std::unique_ptr<C2Work>> items;
275     std::unique_ptr<C2Work> work(new C2Work);
276     work->input.ordinal.timestamp = timeUs;
277     work->input.ordinal.frameIndex = mFrameIndex++;
278     // WORKAROUND: until codecs support handling work after EOS and max output sizing, use timestamp
279     // manipulation to achieve image encoding via video codec, and to constrain encoded output.
280     // Keep client timestamp in customOrdinal
281     work->input.ordinal.customOrdinal = timeUs;
282     work->input.buffers.clear();
283 
284     sp<Codec2Buffer> copy;
285     bool usesFrameReassembler = false;
286 
287     if (buffer->size() > 0u) {
288         Mutexed<Input>::Locked input(mInput);
289         std::shared_ptr<C2Buffer> c2buffer;
290         if (!input->buffers->releaseBuffer(buffer, &c2buffer, false)) {
291             return -ENOENT;
292         }
293         // TODO: we want to delay copying buffers.
294         if (input->extraBuffers.numComponentBuffers() < input->numExtraSlots) {
295             copy = input->buffers->cloneAndReleaseBuffer(buffer);
296             if (copy != nullptr) {
297                 (void)input->extraBuffers.assignSlot(copy);
298                 if (!input->extraBuffers.releaseSlot(copy, &c2buffer, false)) {
299                     return UNKNOWN_ERROR;
300                 }
301                 bool released = input->buffers->releaseBuffer(buffer, nullptr, true);
302                 ALOGV("[%s] queueInputBuffer: buffer copied; %sreleased",
303                       mName, released ? "" : "not ");
304                 buffer = copy;
305             } else {
306                 ALOGW("[%s] queueInputBuffer: failed to copy a buffer; this may cause input "
307                       "buffer starvation on component.", mName);
308             }
309         }
310         if (input->frameReassembler) {
311             usesFrameReassembler = true;
312             input->frameReassembler.process(buffer, &items);
313         } else {
314             int32_t cvo = 0;
315             if (buffer->meta()->findInt32("cvo", &cvo)) {
316                 int32_t rotation = cvo % 360;
317                 // change rotation to counter-clock wise.
318                 rotation = ((rotation <= 0) ? 0 : 360) - rotation;
319 
320                 Mutexed<OutputSurface>::Locked output(mOutputSurface);
321                 uint64_t frameIndex = work->input.ordinal.frameIndex.peeku();
322                 output->rotation[frameIndex] = rotation;
323             }
324             sp<RefBase> obj;
325             if (buffer->meta()->findObject("accessUnitInfo", &obj)) {
326                 ALOGV("Filling C2Info from multiple access units");
327                 sp<WrapperObject<std::vector<AccessUnitInfo>>> infos{
328                         (decltype(infos.get()))obj.get()};
329                 std::vector<AccessUnitInfo> &accessUnitInfoVec = infos->value;
330                 std::vector<C2AccessUnitInfosStruct> multipleAccessUnitInfos;
331                 uint32_t outFlags = 0;
332                 for (int i = 0; i < accessUnitInfoVec.size(); i++) {
333                     outFlags = 0;
334                     outFlags = convertFlags(accessUnitInfoVec[i].mFlags, true);
335                     if (eos && (outFlags & C2FrameData::FLAG_END_OF_STREAM)) {
336                         outFlags &= (~C2FrameData::FLAG_END_OF_STREAM);
337                     }
338                     multipleAccessUnitInfos.emplace_back(
339                             outFlags,
340                             accessUnitInfoVec[i].mSize,
341                             accessUnitInfoVec[i].mTimestamp);
342                     ALOGV("%d) flags: %d, size: %d, time: %llu",
343                             i, outFlags, accessUnitInfoVec[i].mSize,
344                             (long long)accessUnitInfoVec[i].mTimestamp);
345 
346                 }
347                 const std::shared_ptr<C2AccessUnitInfos::input> c2AccessUnitInfos =
348                         C2AccessUnitInfos::input::AllocShared(
349                                 multipleAccessUnitInfos.size(), 0u, multipleAccessUnitInfos);
350                 c2buffer->setInfo(c2AccessUnitInfos);
351             }
352             work->input.buffers.push_back(c2buffer);
353             if (encryptedBlock) {
354                 work->input.infoBuffers.emplace_back(C2InfoBuffer::CreateLinearBuffer(
355                         kParamIndexEncryptedBuffer,
356                         encryptedBlock->share(0, blockSize, C2Fence())));
357             }
358         }
359     } else if (eos) {
360         Mutexed<Input>::Locked input(mInput);
361         if (input->frameReassembler) {
362             usesFrameReassembler = true;
363             // drain any pending items with eos
364             input->frameReassembler.process(buffer, &items);
365         }
366         flags |= C2FrameData::FLAG_END_OF_STREAM;
367     }
368     if (usesFrameReassembler) {
369         if (!items.empty()) {
370             items.front()->input.configUpdate = std::move(mParamsToBeSet);
371             mFrameIndex = (items.back()->input.ordinal.frameIndex + 1).peek();
372         }
373     } else {
374         work->input.flags = (C2FrameData::flags_t)flags;
375 
376         // TODO: fill info's
377         if (android::media::codec::provider_->region_of_interest()
378                 && android::media::codec::provider_->region_of_interest_support()) {
379             if (mInfoBuffers.size()) {
380                 for (auto infoBuffer : mInfoBuffers) {
381                     work->input.infoBuffers.emplace_back(*infoBuffer);
382                 }
383                 mInfoBuffers.clear();
384             }
385         }
386 
387         work->input.configUpdate = std::move(mParamsToBeSet);
388         if (tunnelFirstFrame) {
389             C2StreamTunnelHoldRender::input tunnelHoldRender{
390                 0u /* stream */,
391                 C2_TRUE /* value */
392             };
393             work->input.configUpdate.push_back(C2Param::Copy(tunnelHoldRender));
394         }
395         work->worklets.clear();
396         work->worklets.emplace_back(new C2Worklet);
397 
398         items.push_back(std::move(work));
399 
400         eos = eos && buffer->size() > 0u;
401     }
402     if (eos) {
403         work.reset(new C2Work);
404         work->input.ordinal.timestamp = timeUs;
405         work->input.ordinal.frameIndex = mFrameIndex++;
406         // WORKAROUND: keep client timestamp in customOrdinal
407         work->input.ordinal.customOrdinal = timeUs;
408         work->input.buffers.clear();
409         work->input.flags = C2FrameData::FLAG_END_OF_STREAM;
410         work->worklets.emplace_back(new C2Worklet);
411         items.push_back(std::move(work));
412     }
413     c2_status_t err = C2_OK;
414     if (!items.empty()) {
415         ScopedTrace trace(ATRACE_TAG, android::base::StringPrintf(
416                 "CCodecBufferChannel::queue(%s@ts=%lld)", mName, (long long)timeUs).c_str());
417         {
418             Mutexed<PipelineWatcher>::Locked watcher(mPipelineWatcher);
419             PipelineWatcher::Clock::time_point now = PipelineWatcher::Clock::now();
420             for (const std::unique_ptr<C2Work> &work : items) {
421                 watcher->onWorkQueued(
422                         work->input.ordinal.frameIndex.peeku(),
423                         std::vector(work->input.buffers),
424                         now);
425             }
426         }
427         err = mComponent->queue(&items);
428     }
429     if (err != C2_OK) {
430         Mutexed<PipelineWatcher>::Locked watcher(mPipelineWatcher);
431         for (const std::unique_ptr<C2Work> &work : items) {
432             watcher->onWorkDone(work->input.ordinal.frameIndex.peeku());
433         }
434     } else {
435         Mutexed<Input>::Locked input(mInput);
436         bool released = false;
437         if (copy) {
438             released = input->extraBuffers.releaseSlot(copy, nullptr, true);
439         } else if (buffer) {
440             released = input->buffers->releaseBuffer(buffer, nullptr, true);
441         }
442         ALOGV("[%s] queueInputBuffer: buffer%s %sreleased",
443               mName, (buffer == nullptr) ? "(copy)" : "", released ? "" : "not ");
444     }
445 
446     feedInputBufferIfAvailableInternal();
447     return err;
448 }
449 
setParameters(std::vector<std::unique_ptr<C2Param>> & params)450 status_t CCodecBufferChannel::setParameters(std::vector<std::unique_ptr<C2Param>> &params) {
451     QueueGuard guard(mSync);
452     if (!guard.isRunning()) {
453         ALOGD("[%s] setParameters is only supported in the running state.", mName);
454         return -ENOSYS;
455     }
456     mParamsToBeSet.insert(mParamsToBeSet.end(),
457                           std::make_move_iterator(params.begin()),
458                           std::make_move_iterator(params.end()));
459     params.clear();
460     return OK;
461 }
462 
attachBuffer(const std::shared_ptr<C2Buffer> & c2Buffer,const sp<MediaCodecBuffer> & buffer)463 status_t CCodecBufferChannel::attachBuffer(
464         const std::shared_ptr<C2Buffer> &c2Buffer,
465         const sp<MediaCodecBuffer> &buffer) {
466     if (!buffer->copy(c2Buffer)) {
467         return -ENOSYS;
468     }
469     return OK;
470 }
471 
ensureDecryptDestination(size_t size)472 void CCodecBufferChannel::ensureDecryptDestination(size_t size) {
473     if (!mDecryptDestination || mDecryptDestination->size() < size) {
474         sp<IMemoryHeap> heap{new MemoryHeapBase(size * 2)};
475         if (mDecryptDestination && mCrypto && mHeapSeqNum >= 0) {
476             mCrypto->unsetHeap(mHeapSeqNum);
477         }
478         mDecryptDestination = new MemoryBase(heap, 0, size * 2);
479         if (mCrypto) {
480             mHeapSeqNum = mCrypto->setHeap(hardware::fromHeap(heap));
481         }
482     }
483 }
484 
getHeapSeqNum(const sp<HidlMemory> & memory)485 int32_t CCodecBufferChannel::getHeapSeqNum(const sp<HidlMemory> &memory) {
486     CHECK(mCrypto);
487     auto it = mHeapSeqNumMap.find(memory);
488     int32_t heapSeqNum = -1;
489     if (it == mHeapSeqNumMap.end()) {
490         heapSeqNum = mCrypto->setHeap(memory);
491         mHeapSeqNumMap.emplace(memory, heapSeqNum);
492     } else {
493         heapSeqNum = it->second;
494     }
495     return heapSeqNum;
496 }
497 
498 typedef WrapperObject<std::vector<AccessUnitInfo>> BufferInfosWrapper;
499 typedef WrapperObject<std::vector<std::unique_ptr<CodecCryptoInfo>>> CryptoInfosWrapper;
attachEncryptedBuffers(const sp<hardware::HidlMemory> & memory,size_t offset,const sp<MediaCodecBuffer> & buffer,bool secure,AString * errorDetailMsg)500 status_t CCodecBufferChannel::attachEncryptedBuffers(
501         const sp<hardware::HidlMemory> &memory,
502         size_t offset,
503         const sp<MediaCodecBuffer> &buffer,
504         bool secure,
505         AString* errorDetailMsg) {
506     static const C2MemoryUsage kDefaultReadWriteUsage{
507         C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE};
508     if (!hasCryptoOrDescrambler()) {
509         ALOGE("attachEncryptedBuffers requires Crypto/descrambler object");
510         return -ENOSYS;
511     }
512     size_t size = 0;
513     CHECK(buffer->meta()->findSize("ssize", &size));
514     if (size == 0) {
515         buffer->setRange(0, 0);
516         return OK;
517     }
518     sp<RefBase> obj;
519     CHECK(buffer->meta()->findObject("cryptoInfos", &obj));
520     sp<CryptoInfosWrapper> cryptoInfos{(CryptoInfosWrapper *)obj.get()};
521     CHECK(buffer->meta()->findObject("accessUnitInfo", &obj));
522     sp<BufferInfosWrapper> bufferInfos{(BufferInfosWrapper *)obj.get()};
523     if (secure || (mCrypto == nullptr)) {
524         if (cryptoInfos->value.size() != 1) {
525             ALOGE("Cannot decrypt multiple access units");
526             return -ENOSYS;
527         }
528         // we are dealing with just one cryptoInfo or descrambler.
529         std::unique_ptr<CodecCryptoInfo> info = std::move(cryptoInfos->value[0]);
530         if (info == nullptr) {
531             ALOGE("Cannot decrypt, CryptoInfos are null.");
532             return -ENOSYS;
533         }
534         return attachEncryptedBuffer(
535                 memory,
536                 secure,
537                 info->mKey,
538                 info->mIv,
539                 info->mMode,
540                 info->mPattern,
541                 offset,
542                 info->mSubSamples,
543                 info->mNumSubSamples,
544                 buffer,
545                 errorDetailMsg);
546     }
547     std::shared_ptr<C2BlockPool> pool = mBlockPools.lock()->inputPool;
548     std::shared_ptr<C2LinearBlock> block;
549     c2_status_t err = pool->fetchLinearBlock(
550             size,
551             kDefaultReadWriteUsage,
552             &block);
553     if (err != C2_OK) {
554         ALOGI("[%s] attachEncryptedBuffers: fetchLinearBlock failed: size = %zu (%s) err = %d",
555               mName, size, secure ? "secure" : "non-secure", err);
556         return NO_MEMORY;
557     }
558     ensureDecryptDestination(size);
559     C2WriteView wView = block->map().get();
560     if (wView.error() != C2_OK) {
561         ALOGI("[%s] attachEncryptedBuffers: block map error: %d (non-secure)",
562               mName, wView.error());
563         return UNKNOWN_ERROR;
564     }
565 
566     ssize_t result = -1;
567     size_t srcOffset = offset;
568     size_t outBufferSize = 0;
569     uint32_t cryptoInfoIdx = 0;
570     int32_t heapSeqNum = getHeapSeqNum(memory);
571     hardware::drm::V1_0::SharedBuffer src{(uint32_t)heapSeqNum, offset, size};
572     hardware::drm::V1_0::DestinationBuffer dst;
573     dst.type = DrmBufferType::SHARED_MEMORY;
574     IMemoryToSharedBuffer(
575             mDecryptDestination, mHeapSeqNum, &dst.nonsecureMemory);
576     for (int i = 0; i < bufferInfos->value.size(); i++) {
577         if (bufferInfos->value[i].mSize > 0) {
578             std::unique_ptr<CodecCryptoInfo> info = std::move(cryptoInfos->value[cryptoInfoIdx++]);
579             src.offset = srcOffset;
580             src.size = bufferInfos->value[i].mSize;
581             result = mCrypto->decrypt(
582                     (uint8_t*)info->mKey,
583                     (uint8_t*)info->mIv,
584                     info->mMode,
585                     info->mPattern,
586                     src,
587                     0,
588                     info->mSubSamples,
589                     info->mNumSubSamples,
590                     dst,
591                     errorDetailMsg);
592             srcOffset += bufferInfos->value[i].mSize;
593             if (result < 0) {
594                 ALOGI("[%s] attachEncryptedBuffers: decrypt failed: result = %zd",
595                         mName, result);
596                 return result;
597             }
598             if (wView.error() == C2_OK) {
599                 if (wView.size() < result) {
600                     ALOGI("[%s] attachEncryptedBuffers: block size too small:"
601                             "size=%u result=%zd (non-secure)", mName, wView.size(), result);
602                     return UNKNOWN_ERROR;
603                 }
604                 memcpy(wView.data(), mDecryptDestination->unsecurePointer(), result);
605                 bufferInfos->value[i].mSize = result;
606                 wView.setOffset(wView.offset() + result);
607             }
608             outBufferSize += result;
609         }
610     }
611     if (wView.error() == C2_OK) {
612         wView.setOffset(0);
613     }
614     std::shared_ptr<C2Buffer> c2Buffer{C2Buffer::CreateLinearBuffer(
615             block->share(0, outBufferSize, C2Fence{}))};
616     if (!buffer->copy(c2Buffer)) {
617         ALOGI("[%s] attachEncryptedBuffers: buffer copy failed", mName);
618         return -ENOSYS;
619     }
620     return OK;
621 }
622 
attachEncryptedBuffer(const sp<hardware::HidlMemory> & memory,bool secure,const uint8_t * key,const uint8_t * iv,CryptoPlugin::Mode mode,CryptoPlugin::Pattern pattern,size_t offset,const CryptoPlugin::SubSample * subSamples,size_t numSubSamples,const sp<MediaCodecBuffer> & buffer,AString * errorDetailMsg)623 status_t CCodecBufferChannel::attachEncryptedBuffer(
624         const sp<hardware::HidlMemory> &memory,
625         bool secure,
626         const uint8_t *key,
627         const uint8_t *iv,
628         CryptoPlugin::Mode mode,
629         CryptoPlugin::Pattern pattern,
630         size_t offset,
631         const CryptoPlugin::SubSample *subSamples,
632         size_t numSubSamples,
633         const sp<MediaCodecBuffer> &buffer,
634         AString* errorDetailMsg) {
635     static const C2MemoryUsage kSecureUsage{C2MemoryUsage::READ_PROTECTED, 0};
636     static const C2MemoryUsage kDefaultReadWriteUsage{
637         C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE};
638 
639     size_t size = 0;
640     for (size_t i = 0; i < numSubSamples; ++i) {
641         size += subSamples[i].mNumBytesOfClearData + subSamples[i].mNumBytesOfEncryptedData;
642     }
643     if (size == 0) {
644         buffer->setRange(0, 0);
645         return OK;
646     }
647     std::shared_ptr<C2BlockPool> pool = mBlockPools.lock()->inputPool;
648     std::shared_ptr<C2LinearBlock> block;
649     c2_status_t err = pool->fetchLinearBlock(
650             size,
651             secure ? kSecureUsage : kDefaultReadWriteUsage,
652             &block);
653     if (err != C2_OK) {
654         ALOGI("[%s] attachEncryptedBuffer: fetchLinearBlock failed: size = %zu (%s) err = %d",
655               mName, size, secure ? "secure" : "non-secure", err);
656         return NO_MEMORY;
657     }
658     if (!secure) {
659         ensureDecryptDestination(size);
660     }
661     ssize_t result = -1;
662     ssize_t codecDataOffset = 0;
663     if (mCrypto) {
664         int32_t heapSeqNum = getHeapSeqNum(memory);
665         hardware::drm::V1_0::SharedBuffer src{(uint32_t)heapSeqNum, offset, size};
666         hardware::drm::V1_0::DestinationBuffer dst;
667         if (secure) {
668             dst.type = DrmBufferType::NATIVE_HANDLE;
669             dst.secureMemory = hardware::hidl_handle(block->handle());
670         } else {
671             dst.type = DrmBufferType::SHARED_MEMORY;
672             IMemoryToSharedBuffer(
673                     mDecryptDestination, mHeapSeqNum, &dst.nonsecureMemory);
674         }
675         result = mCrypto->decrypt(
676                 key, iv, mode, pattern, src, 0, subSamples, numSubSamples,
677                 dst, errorDetailMsg);
678         if (result < 0) {
679             ALOGI("[%s] attachEncryptedBuffer: decrypt failed: result = %zd", mName, result);
680             return result;
681         }
682     } else {
683         // Here we cast CryptoPlugin::SubSample to hardware::cas::native::V1_0::SubSample
684         // directly, the structure definitions should match as checked in DescramblerImpl.cpp.
685         hidl_vec<SubSample> hidlSubSamples;
686         hidlSubSamples.setToExternal((SubSample *)subSamples, numSubSamples, false /*own*/);
687 
688         hardware::cas::native::V1_0::SharedBuffer src{*memory, offset, size};
689         hardware::cas::native::V1_0::DestinationBuffer dst;
690         if (secure) {
691             dst.type = BufferType::NATIVE_HANDLE;
692             dst.secureMemory = hardware::hidl_handle(block->handle());
693         } else {
694             dst.type = BufferType::SHARED_MEMORY;
695             dst.nonsecureMemory = src;
696         }
697 
698         CasStatus status = CasStatus::OK;
699         hidl_string detailedError;
700         ScramblingControl sctrl = ScramblingControl::UNSCRAMBLED;
701 
702         if (key != nullptr) {
703             sctrl = (ScramblingControl)key[0];
704             // Adjust for the PES offset
705             codecDataOffset = key[2] | (key[3] << 8);
706         }
707 
708         auto returnVoid = mDescrambler->descramble(
709                 sctrl,
710                 hidlSubSamples,
711                 src,
712                 0,
713                 dst,
714                 0,
715                 [&status, &result, &detailedError] (
716                         CasStatus _status, uint32_t _bytesWritten,
717                         const hidl_string& _detailedError) {
718                     status = _status;
719                     result = (ssize_t)_bytesWritten;
720                     detailedError = _detailedError;
721                 });
722         if (errorDetailMsg) {
723             errorDetailMsg->setTo(detailedError.c_str(), detailedError.size());
724         }
725         if (!returnVoid.isOk() || status != CasStatus::OK || result < 0) {
726             ALOGI("[%s] descramble failed, trans=%s, status=%d, result=%zd",
727                     mName, returnVoid.description().c_str(), status, result);
728             return UNKNOWN_ERROR;
729         }
730 
731         if (result < codecDataOffset) {
732             ALOGD("[%s] invalid codec data offset: %zd, result %zd",
733                   mName, codecDataOffset, result);
734             return BAD_VALUE;
735         }
736     }
737     if (!secure) {
738         C2WriteView view = block->map().get();
739         if (view.error() != C2_OK) {
740             ALOGI("[%s] attachEncryptedBuffer: block map error: %d (non-secure)",
741                   mName, view.error());
742             return UNKNOWN_ERROR;
743         }
744         if (view.size() < result) {
745             ALOGI("[%s] attachEncryptedBuffer: block size too small: size=%u result=%zd "
746                   "(non-secure)",
747                   mName, view.size(), result);
748             return UNKNOWN_ERROR;
749         }
750         memcpy(view.data(), mDecryptDestination->unsecurePointer(), result);
751     }
752     std::shared_ptr<C2Buffer> c2Buffer{C2Buffer::CreateLinearBuffer(
753             block->share(codecDataOffset, result - codecDataOffset, C2Fence{}))};
754     if (!buffer->copy(c2Buffer)) {
755         ALOGI("[%s] attachEncryptedBuffer: buffer copy failed", mName);
756         return -ENOSYS;
757     }
758     return OK;
759 }
760 
queueInputBuffer(const sp<MediaCodecBuffer> & buffer)761 status_t CCodecBufferChannel::queueInputBuffer(const sp<MediaCodecBuffer> &buffer) {
762     QueueGuard guard(mSync);
763     if (!guard.isRunning()) {
764         ALOGD("[%s] No more buffers should be queued at current state.", mName);
765         return -ENOSYS;
766     }
767     return queueInputBufferInternal(buffer);
768 }
769 
queueSecureInputBuffer(const sp<MediaCodecBuffer> & buffer,bool secure,const uint8_t * key,const uint8_t * iv,CryptoPlugin::Mode mode,CryptoPlugin::Pattern pattern,const CryptoPlugin::SubSample * subSamples,size_t numSubSamples,AString * errorDetailMsg)770 status_t CCodecBufferChannel::queueSecureInputBuffer(
771         const sp<MediaCodecBuffer> &buffer, bool secure, const uint8_t *key,
772         const uint8_t *iv, CryptoPlugin::Mode mode, CryptoPlugin::Pattern pattern,
773         const CryptoPlugin::SubSample *subSamples, size_t numSubSamples,
774         AString *errorDetailMsg) {
775     QueueGuard guard(mSync);
776     if (!guard.isRunning()) {
777         ALOGD("[%s] No more buffers should be queued at current state.", mName);
778         return -ENOSYS;
779     }
780 
781     if (!hasCryptoOrDescrambler()) {
782         return -ENOSYS;
783     }
784     sp<EncryptedLinearBlockBuffer> encryptedBuffer((EncryptedLinearBlockBuffer *)buffer.get());
785 
786     std::shared_ptr<C2LinearBlock> block;
787     size_t allocSize = buffer->size();
788     size_t bufferSize = 0;
789     c2_status_t blockRes = C2_OK;
790     bool copied = false;
791     ScopedTrace trace(ATRACE_TAG, android::base::StringPrintf(
792             "CCodecBufferChannel::decrypt(%s)", mName).c_str());
793     if (mSendEncryptedInfoBuffer) {
794         static const C2MemoryUsage kDefaultReadWriteUsage{
795             C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE};
796         constexpr int kAllocGranule0 = 1024 * 64;
797         constexpr int kAllocGranule1 = 1024 * 1024;
798         std::shared_ptr<C2BlockPool> pool = mBlockPools.lock()->inputPool;
799         // round up encrypted sizes to limit fragmentation and encourage buffer reuse
800         if (allocSize <= kAllocGranule1) {
801             bufferSize = align(allocSize, kAllocGranule0);
802         } else {
803             bufferSize = align(allocSize, kAllocGranule1);
804         }
805         blockRes = pool->fetchLinearBlock(
806                 bufferSize, kDefaultReadWriteUsage, &block);
807 
808         if (blockRes == C2_OK) {
809             C2WriteView view = block->map().get();
810             if (view.error() == C2_OK && view.size() == bufferSize) {
811                 copied = true;
812                 // TODO: only copy clear sections
813                 memcpy(view.data(), buffer->data(), allocSize);
814             }
815         }
816     }
817 
818     if (!copied) {
819         block.reset();
820     }
821 
822     ssize_t result = -1;
823     ssize_t codecDataOffset = 0;
824     if (numSubSamples == 1
825             && subSamples[0].mNumBytesOfClearData == 0
826             && subSamples[0].mNumBytesOfEncryptedData == 0) {
827         // We don't need to go through crypto or descrambler if the input is empty.
828         result = 0;
829     } else if (mCrypto != nullptr) {
830         hardware::drm::V1_0::DestinationBuffer destination;
831         if (secure) {
832             destination.type = DrmBufferType::NATIVE_HANDLE;
833             destination.secureMemory = hidl_handle(encryptedBuffer->handle());
834         } else {
835             destination.type = DrmBufferType::SHARED_MEMORY;
836             IMemoryToSharedBuffer(
837                     mDecryptDestination, mHeapSeqNum, &destination.nonsecureMemory);
838         }
839         hardware::drm::V1_0::SharedBuffer source;
840         encryptedBuffer->fillSourceBuffer(&source);
841         result = mCrypto->decrypt(
842                 key, iv, mode, pattern, source, buffer->offset(),
843                 subSamples, numSubSamples, destination, errorDetailMsg);
844         if (result < 0) {
845             ALOGI("[%s] decrypt failed: result=%zd", mName, result);
846             return result;
847         }
848         if (destination.type == DrmBufferType::SHARED_MEMORY) {
849             encryptedBuffer->copyDecryptedContent(mDecryptDestination, result);
850         }
851     } else {
852         // Here we cast CryptoPlugin::SubSample to hardware::cas::native::V1_0::SubSample
853         // directly, the structure definitions should match as checked in DescramblerImpl.cpp.
854         hidl_vec<SubSample> hidlSubSamples;
855         hidlSubSamples.setToExternal((SubSample *)subSamples, numSubSamples, false /*own*/);
856 
857         hardware::cas::native::V1_0::SharedBuffer srcBuffer;
858         encryptedBuffer->fillSourceBuffer(&srcBuffer);
859 
860         DestinationBuffer dstBuffer;
861         if (secure) {
862             dstBuffer.type = BufferType::NATIVE_HANDLE;
863             dstBuffer.secureMemory = hidl_handle(encryptedBuffer->handle());
864         } else {
865             dstBuffer.type = BufferType::SHARED_MEMORY;
866             dstBuffer.nonsecureMemory = srcBuffer;
867         }
868 
869         CasStatus status = CasStatus::OK;
870         hidl_string detailedError;
871         ScramblingControl sctrl = ScramblingControl::UNSCRAMBLED;
872 
873         if (key != nullptr) {
874             sctrl = (ScramblingControl)key[0];
875             // Adjust for the PES offset
876             codecDataOffset = key[2] | (key[3] << 8);
877         }
878 
879         auto returnVoid = mDescrambler->descramble(
880                 sctrl,
881                 hidlSubSamples,
882                 srcBuffer,
883                 0,
884                 dstBuffer,
885                 0,
886                 [&status, &result, &detailedError] (
887                         CasStatus _status, uint32_t _bytesWritten,
888                         const hidl_string& _detailedError) {
889                     status = _status;
890                     result = (ssize_t)_bytesWritten;
891                     detailedError = _detailedError;
892                 });
893 
894         if (!returnVoid.isOk() || status != CasStatus::OK || result < 0) {
895             ALOGI("[%s] descramble failed, trans=%s, status=%d, result=%zd",
896                     mName, returnVoid.description().c_str(), status, result);
897             return UNKNOWN_ERROR;
898         }
899 
900         if (result < codecDataOffset) {
901             ALOGD("invalid codec data offset: %zd, result %zd", codecDataOffset, result);
902             return BAD_VALUE;
903         }
904 
905         ALOGV("[%s] descramble succeeded, %zd bytes", mName, result);
906 
907         if (dstBuffer.type == BufferType::SHARED_MEMORY) {
908             encryptedBuffer->copyDecryptedContentFromMemory(result);
909         }
910     }
911 
912     buffer->setRange(codecDataOffset, result - codecDataOffset);
913 
914     return queueInputBufferInternal(buffer, block, bufferSize);
915 }
916 
queueSecureInputBuffers(const sp<MediaCodecBuffer> & buffer,bool secure,AString * errorDetailMsg)917 status_t CCodecBufferChannel::queueSecureInputBuffers(
918         const sp<MediaCodecBuffer> &buffer,
919         bool secure,
920         AString *errorDetailMsg) {
921     QueueGuard guard(mSync);
922     if (!guard.isRunning()) {
923         ALOGD("[%s] No more buffers should be queued at current state.", mName);
924         return -ENOSYS;
925     }
926 
927     if (!hasCryptoOrDescrambler()) {
928         ALOGE("queueSecureInputBuffers requires a Crypto/descrambler Object");
929         return -ENOSYS;
930     }
931     sp<RefBase> obj;
932     CHECK(buffer->meta()->findObject("cryptoInfos", &obj));
933     sp<CryptoInfosWrapper> cryptoInfos{(CryptoInfosWrapper *)obj.get()};
934     CHECK(buffer->meta()->findObject("accessUnitInfo", &obj));
935     sp<BufferInfosWrapper> bufferInfos{(BufferInfosWrapper *)obj.get()};
936     if (secure || mCrypto == nullptr) {
937         if (cryptoInfos->value.size() != 1) {
938             ALOGE("Cannot decrypt multiple access units on native handles");
939             return -ENOSYS;
940         }
941         std::unique_ptr<CodecCryptoInfo> info = std::move(cryptoInfos->value[0]);
942         if (info == nullptr) {
943             ALOGE("Cannot decrypt, CryptoInfos are null");
944             return -ENOSYS;
945         }
946         return queueSecureInputBuffer(
947                 buffer,
948                 secure,
949                 info->mKey,
950                 info->mIv,
951                 info->mMode,
952                 info->mPattern,
953                 info->mSubSamples,
954                 info->mNumSubSamples,
955                 errorDetailMsg);
956     }
957     sp<EncryptedLinearBlockBuffer> encryptedBuffer((EncryptedLinearBlockBuffer *)buffer.get());
958 
959     std::shared_ptr<C2LinearBlock> block;
960     size_t allocSize = buffer->size();
961     size_t bufferSize = 0;
962     c2_status_t blockRes = C2_OK;
963     bool copied = false;
964     ScopedTrace trace(ATRACE_TAG, android::base::StringPrintf(
965             "CCodecBufferChannel::decrypt(%s)", mName).c_str());
966     if (mSendEncryptedInfoBuffer) {
967         static const C2MemoryUsage kDefaultReadWriteUsage{
968             C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE};
969         constexpr int kAllocGranule0 = 1024 * 64;
970         constexpr int kAllocGranule1 = 1024 * 1024;
971         std::shared_ptr<C2BlockPool> pool = mBlockPools.lock()->inputPool;
972         // round up encrypted sizes to limit fragmentation and encourage buffer reuse
973         if (allocSize <= kAllocGranule1) {
974             bufferSize = align(allocSize, kAllocGranule0);
975         } else {
976             bufferSize = align(allocSize, kAllocGranule1);
977         }
978         blockRes = pool->fetchLinearBlock(
979                 bufferSize, kDefaultReadWriteUsage, &block);
980 
981         if (blockRes == C2_OK) {
982             C2WriteView view = block->map().get();
983             if (view.error() == C2_OK && view.size() == bufferSize) {
984                 copied = true;
985                 // TODO: only copy clear sections
986                 memcpy(view.data(), buffer->data(), allocSize);
987             }
988         }
989     }
990 
991     if (!copied) {
992         block.reset();
993     }
994     // size of cryptoInfo and accessUnitInfo should be the same?
995     ssize_t result = -1;
996     size_t srcOffset = 0;
997     size_t outBufferSize = 0;
998     uint32_t cryptoInfoIdx = 0;
999     {
1000         // scoped this block to enable destruction of mappedBlock
1001         std::unique_ptr<EncryptedLinearBlockBuffer::MappedBlock> mappedBlock = nullptr;
1002         hardware::drm::V1_0::DestinationBuffer destination;
1003         destination.type = DrmBufferType::SHARED_MEMORY;
1004         IMemoryToSharedBuffer(
1005                 mDecryptDestination, mHeapSeqNum, &destination.nonsecureMemory);
1006         encryptedBuffer->getMappedBlock(&mappedBlock);
1007         hardware::drm::V1_0::SharedBuffer source;
1008         encryptedBuffer->fillSourceBuffer(&source);
1009         srcOffset = source.offset;
1010         for (int i = 0 ; i < bufferInfos->value.size(); i++) {
1011             if (bufferInfos->value[i].mSize > 0) {
1012                 std::unique_ptr<CodecCryptoInfo> info =
1013                         std::move(cryptoInfos->value[cryptoInfoIdx++]);
1014                 if (info->mNumSubSamples == 1
1015                         && info->mSubSamples[0].mNumBytesOfClearData == 0
1016                         && info->mSubSamples[0].mNumBytesOfEncryptedData == 0) {
1017                     // no data so we only populate the bufferInfo
1018                     result = 0;
1019                 } else {
1020                     source.offset = srcOffset;
1021                     source.size = bufferInfos->value[i].mSize;
1022                     result = mCrypto->decrypt(
1023                             (uint8_t*)info->mKey,
1024                             (uint8_t*)info->mIv,
1025                             info->mMode,
1026                             info->mPattern,
1027                             source,
1028                             buffer->offset(),
1029                             info->mSubSamples,
1030                             info->mNumSubSamples,
1031                             destination,
1032                             errorDetailMsg);
1033                     srcOffset += bufferInfos->value[i].mSize;
1034                     if (result < 0) {
1035                         ALOGI("[%s] decrypt failed: result=%zd", mName, result);
1036                         return result;
1037                     }
1038                     if (destination.type == DrmBufferType::SHARED_MEMORY && mappedBlock) {
1039                         mappedBlock->copyDecryptedContent(mDecryptDestination, result);
1040                     }
1041                     bufferInfos->value[i].mSize = result;
1042                     outBufferSize += result;
1043                 }
1044             }
1045         }
1046         buffer->setRange(0, outBufferSize);
1047     }
1048     return queueInputBufferInternal(buffer, block, bufferSize);
1049 }
1050 
feedInputBufferIfAvailable()1051 void CCodecBufferChannel::feedInputBufferIfAvailable() {
1052     QueueGuard guard(mSync);
1053     if (!guard.isRunning()) {
1054         ALOGV("[%s] We're not running --- no input buffer reported", mName);
1055         return;
1056     }
1057     feedInputBufferIfAvailableInternal();
1058 }
1059 
feedInputBufferIfAvailableInternal()1060 void CCodecBufferChannel::feedInputBufferIfAvailableInternal() {
1061     if (mInputMetEos) {
1062         return;
1063     }
1064     {
1065         Mutexed<Output>::Locked output(mOutput);
1066         if (!output->buffers ||
1067                 output->buffers->hasPending() ||
1068                 (!output->bounded && output->buffers->numActiveSlots() >= output->numSlots)) {
1069             return;
1070         }
1071     }
1072     if (android::media::codec::provider_->input_surface_throttle()
1073             && mInputSurface != nullptr) {
1074         mInputSurface->onInputBufferEmptied();
1075     }
1076     size_t numActiveSlots = 0;
1077     while (!mPipelineWatcher.lock()->pipelineFull()) {
1078         sp<MediaCodecBuffer> inBuffer;
1079         size_t index;
1080         {
1081             Mutexed<Input>::Locked input(mInput);
1082             numActiveSlots = input->buffers->numActiveSlots();
1083             if (numActiveSlots >= input->numSlots) {
1084                 break;
1085             }
1086             if (!input->buffers->requestNewBuffer(&index, &inBuffer)) {
1087                 ALOGV("[%s] no new buffer available", mName);
1088                 break;
1089             }
1090         }
1091         ALOGV("[%s] new input index = %zu [%p]", mName, index, inBuffer.get());
1092         mCallback->onInputBufferAvailable(index, inBuffer);
1093     }
1094     ALOGV("[%s] # active slots after feedInputBufferIfAvailable = %zu", mName, numActiveSlots);
1095 }
1096 
renderOutputBuffer(const sp<MediaCodecBuffer> & buffer,int64_t timestampNs)1097 status_t CCodecBufferChannel::renderOutputBuffer(
1098         const sp<MediaCodecBuffer> &buffer, int64_t timestampNs) {
1099     ALOGV("[%s] renderOutputBuffer: %p", mName, buffer.get());
1100     std::shared_ptr<C2Buffer> c2Buffer;
1101     bool released = false;
1102     {
1103         Mutexed<Output>::Locked output(mOutput);
1104         if (output->buffers) {
1105             released = output->buffers->releaseBuffer(buffer, &c2Buffer);
1106         }
1107     }
1108     // NOTE: some apps try to releaseOutputBuffer() with timestamp and/or render
1109     //       set to true.
1110     sendOutputBuffers();
1111     // input buffer feeding may have been gated by pending output buffers
1112     feedInputBufferIfAvailable();
1113     if (!c2Buffer) {
1114         if (released) {
1115             std::call_once(mRenderWarningFlag, [this] {
1116                 ALOGW("[%s] The app is calling releaseOutputBuffer() with "
1117                       "timestamp or render=true with non-video buffers. Apps should "
1118                       "call releaseOutputBuffer() with render=false for those.",
1119                       mName);
1120             });
1121         }
1122         return INVALID_OPERATION;
1123     }
1124 
1125 #if 0
1126     const std::vector<std::shared_ptr<const C2Info>> infoParams = c2Buffer->info();
1127     ALOGV("[%s] queuing gfx buffer with %zu infos", mName, infoParams.size());
1128     for (const std::shared_ptr<const C2Info> &info : infoParams) {
1129         AString res;
1130         for (size_t ix = 0; ix + 3 < info->size(); ix += 4) {
1131             if (ix) res.append(", ");
1132             res.append(*((int32_t*)info.get() + (ix / 4)));
1133         }
1134         ALOGV("  [%s]", res.c_str());
1135     }
1136 #endif
1137     std::shared_ptr<const C2StreamRotationInfo::output> rotation =
1138         std::static_pointer_cast<const C2StreamRotationInfo::output>(
1139                 c2Buffer->getInfo(C2StreamRotationInfo::output::PARAM_TYPE));
1140     bool flip = rotation && (rotation->flip & 1);
1141     uint32_t quarters = ((rotation ? rotation->value : 0) / 90) & 3;
1142 
1143     {
1144         Mutexed<OutputSurface>::Locked output(mOutputSurface);
1145         if (output->surface == nullptr) {
1146             ALOGI("[%s] cannot render buffer without surface", mName);
1147             return OK;
1148         }
1149         int64_t frameIndex;
1150         buffer->meta()->findInt64("frameIndex", &frameIndex);
1151         if (output->rotation.count(frameIndex) != 0) {
1152             auto it = output->rotation.find(frameIndex);
1153             quarters = (it->second / 90) & 3;
1154             output->rotation.erase(it);
1155         }
1156     }
1157 
1158     uint32_t transform = 0;
1159     switch (quarters) {
1160         case 0: // no rotation
1161             transform = flip ? HAL_TRANSFORM_FLIP_H : 0;
1162             break;
1163         case 1: // 90 degrees counter-clockwise
1164             transform = flip ? (HAL_TRANSFORM_FLIP_V | HAL_TRANSFORM_ROT_90)
1165                     : HAL_TRANSFORM_ROT_270;
1166             break;
1167         case 2: // 180 degrees
1168             transform = flip ? HAL_TRANSFORM_FLIP_V : HAL_TRANSFORM_ROT_180;
1169             break;
1170         case 3: // 90 degrees clockwise
1171             transform = flip ? (HAL_TRANSFORM_FLIP_H | HAL_TRANSFORM_ROT_90)
1172                     : HAL_TRANSFORM_ROT_90;
1173             break;
1174     }
1175 
1176     std::shared_ptr<const C2StreamSurfaceScalingInfo::output> surfaceScaling =
1177         std::static_pointer_cast<const C2StreamSurfaceScalingInfo::output>(
1178                 c2Buffer->getInfo(C2StreamSurfaceScalingInfo::output::PARAM_TYPE));
1179     uint32_t videoScalingMode = NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW;
1180     if (surfaceScaling) {
1181         videoScalingMode = surfaceScaling->value;
1182     }
1183 
1184     // Use dataspace from format as it has the default aspects already applied
1185     android_dataspace_t dataSpace = HAL_DATASPACE_UNKNOWN; // this is 0
1186     (void)buffer->format()->findInt32("android._dataspace", (int32_t *)&dataSpace);
1187 
1188     // HDR static info
1189     std::shared_ptr<const C2StreamHdrStaticInfo::output> hdrStaticInfo =
1190         std::static_pointer_cast<const C2StreamHdrStaticInfo::output>(
1191                 c2Buffer->getInfo(C2StreamHdrStaticInfo::output::PARAM_TYPE));
1192 
1193     // HDR10 plus info
1194     std::shared_ptr<const C2StreamHdr10PlusInfo::output> hdr10PlusInfo =
1195         std::static_pointer_cast<const C2StreamHdr10PlusInfo::output>(
1196                 c2Buffer->getInfo(C2StreamHdr10PlusInfo::output::PARAM_TYPE));
1197     if (hdr10PlusInfo && hdr10PlusInfo->flexCount() == 0) {
1198         hdr10PlusInfo.reset();
1199     }
1200 
1201     // HDR dynamic info
1202     std::shared_ptr<const C2StreamHdrDynamicMetadataInfo::output> hdrDynamicInfo =
1203         std::static_pointer_cast<const C2StreamHdrDynamicMetadataInfo::output>(
1204                 c2Buffer->getInfo(C2StreamHdrDynamicMetadataInfo::output::PARAM_TYPE));
1205     // TODO: make this sticky & enable unset
1206     if (hdrDynamicInfo && hdrDynamicInfo->flexCount() == 0) {
1207         hdrDynamicInfo.reset();
1208     }
1209 
1210     if (hdr10PlusInfo) {
1211         // C2StreamHdr10PlusInfo is deprecated; components should use
1212         // C2StreamHdrDynamicMetadataInfo
1213         // TODO: #metric
1214         if (hdrDynamicInfo) {
1215             // It is unexpected that C2StreamHdr10PlusInfo and
1216             // C2StreamHdrDynamicMetadataInfo is both present.
1217             // C2StreamHdrDynamicMetadataInfo takes priority.
1218             // TODO: #metric
1219         } else {
1220             std::shared_ptr<C2StreamHdrDynamicMetadataInfo::output> info =
1221                     C2StreamHdrDynamicMetadataInfo::output::AllocShared(
1222                             hdr10PlusInfo->flexCount(),
1223                             0u,
1224                             C2Config::HDR_DYNAMIC_METADATA_TYPE_SMPTE_2094_40);
1225             memcpy(info->m.data, hdr10PlusInfo->m.value, hdr10PlusInfo->flexCount());
1226             hdrDynamicInfo = info;
1227         }
1228     }
1229 
1230     std::vector<C2ConstGraphicBlock> blocks = c2Buffer->data().graphicBlocks();
1231     if (blocks.size() != 1u) {
1232         ALOGD("[%s] expected 1 graphic block, but got %zu", mName, blocks.size());
1233         return UNKNOWN_ERROR;
1234     }
1235     const C2ConstGraphicBlock &block = blocks.front();
1236     C2Fence c2fence = block.fence();
1237     sp<Fence> fence = Fence::NO_FENCE;
1238     // TODO: it's not sufficient to just check isHW() and then construct android::fence from it.
1239     // Once C2Fence::type() is added, check the exact C2Fence type
1240     if (c2fence.isHW()) {
1241         int fenceFd = c2fence.fd();
1242         fence = sp<Fence>::make(fenceFd);
1243         if (!fence) {
1244             ALOGE("[%s] Failed to allocate a fence", mName);
1245             close(fenceFd);
1246             return NO_MEMORY;
1247         }
1248     }
1249 
1250     // TODO: revisit this after C2Fence implementation.
1251     IGraphicBufferProducer::QueueBufferInput qbi(
1252             timestampNs,
1253             false, // droppable
1254             dataSpace,
1255             Rect(blocks.front().crop().left,
1256                  blocks.front().crop().top,
1257                  blocks.front().crop().right(),
1258                  blocks.front().crop().bottom()),
1259             videoScalingMode,
1260             transform,
1261             fence, 0);
1262     if (hdrStaticInfo || hdrDynamicInfo) {
1263         HdrMetadata hdr;
1264         if (hdrStaticInfo) {
1265             // If mastering max and min luminance fields are 0, do not use them.
1266             // It indicates the value may not be present in the stream.
1267             if (hdrStaticInfo->mastering.maxLuminance > 0.0f &&
1268                 hdrStaticInfo->mastering.minLuminance > 0.0f) {
1269                 struct android_smpte2086_metadata smpte2086_meta = {
1270                     .displayPrimaryRed = {
1271                         hdrStaticInfo->mastering.red.x, hdrStaticInfo->mastering.red.y
1272                     },
1273                     .displayPrimaryGreen = {
1274                         hdrStaticInfo->mastering.green.x, hdrStaticInfo->mastering.green.y
1275                     },
1276                     .displayPrimaryBlue = {
1277                         hdrStaticInfo->mastering.blue.x, hdrStaticInfo->mastering.blue.y
1278                     },
1279                     .whitePoint = {
1280                         hdrStaticInfo->mastering.white.x, hdrStaticInfo->mastering.white.y
1281                     },
1282                     .maxLuminance = hdrStaticInfo->mastering.maxLuminance,
1283                     .minLuminance = hdrStaticInfo->mastering.minLuminance,
1284                 };
1285                 hdr.validTypes |= HdrMetadata::SMPTE2086;
1286                 hdr.smpte2086 = smpte2086_meta;
1287             }
1288             // If the content light level fields are 0, do not use them, it
1289             // indicates the value may not be present in the stream.
1290             if (hdrStaticInfo->maxCll > 0.0f && hdrStaticInfo->maxFall > 0.0f) {
1291                 struct android_cta861_3_metadata cta861_meta = {
1292                     .maxContentLightLevel = hdrStaticInfo->maxCll,
1293                     .maxFrameAverageLightLevel = hdrStaticInfo->maxFall,
1294                 };
1295                 hdr.validTypes |= HdrMetadata::CTA861_3;
1296                 hdr.cta8613 = cta861_meta;
1297             }
1298 
1299             // does not have valid info
1300             if (!(hdr.validTypes & (HdrMetadata::SMPTE2086 | HdrMetadata::CTA861_3))) {
1301                 hdrStaticInfo.reset();
1302             }
1303         }
1304         if (hdrDynamicInfo
1305                 && hdrDynamicInfo->m.type_ == C2Config::HDR_DYNAMIC_METADATA_TYPE_SMPTE_2094_40) {
1306             hdr.validTypes |= HdrMetadata::HDR10PLUS;
1307             hdr.hdr10plus.assign(
1308                     hdrDynamicInfo->m.data,
1309                     hdrDynamicInfo->m.data + hdrDynamicInfo->flexCount());
1310         }
1311         qbi.setHdrMetadata(hdr);
1312     }
1313     SetMetadataToGralloc4Handle(dataSpace, hdrStaticInfo, hdrDynamicInfo, block.handle());
1314 
1315     qbi.setSurfaceDamage(Region::INVALID_REGION); // we don't have dirty regions
1316     qbi.getFrameTimestamps = true; // we need to know when a frame is rendered
1317     IGraphicBufferProducer::QueueBufferOutput qbo;
1318     status_t result = mComponent->queueToOutputSurface(block, qbi, &qbo);
1319     if (result != OK) {
1320         ALOGI("[%s] queueBuffer failed: %d", mName, result);
1321         if (result == NO_INIT) {
1322             mCCodecCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL);
1323         }
1324         return result;
1325     }
1326 
1327     if(android::base::GetBoolProperty("debug.stagefright.fps", false)) {
1328         ALOGD("[%s] queue buffer successful", mName);
1329     } else {
1330         ALOGV("[%s] queue buffer successful", mName);
1331     }
1332 
1333     int64_t mediaTimeUs = 0;
1334     (void)buffer->meta()->findInt64("timeUs", &mediaTimeUs);
1335     if (mAreRenderMetricsEnabled && mIsSurfaceToDisplay) {
1336         trackReleasedFrame(qbo, mediaTimeUs, timestampNs);
1337         processRenderedFrames(qbo.frameTimestamps);
1338     } else {
1339         // When the surface is an intermediate surface, onFrameRendered is triggered immediately
1340         // when the frame is queued to the non-display surface
1341         mCCodecCallback->onOutputFramesRendered(mediaTimeUs, timestampNs);
1342     }
1343 
1344     return OK;
1345 }
1346 
initializeFrameTrackingFor(ANativeWindow * window)1347 void CCodecBufferChannel::initializeFrameTrackingFor(ANativeWindow * window) {
1348     mTrackedFrames.clear();
1349 
1350     int isSurfaceToDisplay = 0;
1351     window->query(window, NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER, &isSurfaceToDisplay);
1352     mIsSurfaceToDisplay = isSurfaceToDisplay == 1;
1353     // No frame tracking is needed if we're not sending frames to the display
1354     if (!mIsSurfaceToDisplay) {
1355         // Return early so we don't call into SurfaceFlinger (requiring permissions)
1356         return;
1357     }
1358 
1359     int hasPresentFenceTimes = 0;
1360     window->query(window, NATIVE_WINDOW_FRAME_TIMESTAMPS_SUPPORTS_PRESENT, &hasPresentFenceTimes);
1361     mHasPresentFenceTimes = hasPresentFenceTimes == 1;
1362     if (!mHasPresentFenceTimes) {
1363         ALOGI("Using latch times for frame rendered signals - present fences not supported");
1364     }
1365 }
1366 
trackReleasedFrame(const IGraphicBufferProducer::QueueBufferOutput & qbo,int64_t mediaTimeUs,int64_t desiredRenderTimeNs)1367 void CCodecBufferChannel::trackReleasedFrame(const IGraphicBufferProducer::QueueBufferOutput& qbo,
1368                                              int64_t mediaTimeUs, int64_t desiredRenderTimeNs) {
1369     // If the render time is earlier than now, then we're suggesting it should be rendered ASAP,
1370     // so track the frame as if the desired render time is now.
1371     int64_t nowNs = systemTime(SYSTEM_TIME_MONOTONIC);
1372     if (desiredRenderTimeNs < nowNs) {
1373         desiredRenderTimeNs = nowNs;
1374     }
1375 
1376     // If the render time is more than a second from now, then pretend the frame is supposed to be
1377     // rendered immediately, because that's what SurfaceFlinger heuristics will do. This is a tight
1378     // coupling, but is really the only way to optimize away unnecessary present fence checks in
1379     // processRenderedFrames.
1380     if (desiredRenderTimeNs > nowNs + 1*1000*1000*1000LL) {
1381         desiredRenderTimeNs = nowNs;
1382     }
1383 
1384     // We've just queued a frame to the surface, so keep track of it and later check to see if it is
1385     // actually rendered.
1386     TrackedFrame frame;
1387     frame.number = qbo.nextFrameNumber - 1;
1388     frame.mediaTimeUs = mediaTimeUs;
1389     frame.desiredRenderTimeNs = desiredRenderTimeNs;
1390     frame.latchTime = -1;
1391     frame.presentFence = nullptr;
1392     mTrackedFrames.push_back(frame);
1393 }
1394 
processRenderedFrames(const FrameEventHistoryDelta & deltas)1395 void CCodecBufferChannel::processRenderedFrames(const FrameEventHistoryDelta& deltas) {
1396     // Grab the latch times and present fences from the frame event deltas
1397     for (const auto& delta : deltas) {
1398         for (auto& frame : mTrackedFrames) {
1399             if (delta.getFrameNumber() == frame.number) {
1400                 delta.getLatchTime(&frame.latchTime);
1401                 delta.getDisplayPresentFence(&frame.presentFence);
1402             }
1403         }
1404     }
1405 
1406     // Scan all frames and check to see if the frames that SHOULD have been rendered by now, have,
1407     // in fact, been rendered.
1408     int64_t nowNs = systemTime(SYSTEM_TIME_MONOTONIC);
1409     while (!mTrackedFrames.empty()) {
1410         TrackedFrame & frame = mTrackedFrames.front();
1411         // Frames that should have been rendered at least 100ms in the past are checked
1412         if (frame.desiredRenderTimeNs > nowNs - 100*1000*1000LL) {
1413             break;
1414         }
1415 
1416         // If we don't have a render time by now, then consider the frame as dropped
1417         int64_t renderTimeNs = getRenderTimeNs(frame);
1418         if (renderTimeNs != -1) {
1419             mCCodecCallback->onOutputFramesRendered(frame.mediaTimeUs, renderTimeNs);
1420         }
1421         mTrackedFrames.pop_front();
1422     }
1423 }
1424 
getRenderTimeNs(const TrackedFrame & frame)1425 int64_t CCodecBufferChannel::getRenderTimeNs(const TrackedFrame& frame) {
1426     // If the device doesn't have accurate present fence times, then use the latch time as a proxy
1427     if (!mHasPresentFenceTimes) {
1428         if (frame.latchTime == -1) {
1429             ALOGD("no latch time for frame %d", (int) frame.number);
1430             return -1;
1431         }
1432         return frame.latchTime;
1433     }
1434 
1435     if (frame.presentFence == nullptr) {
1436         ALOGW("no present fence for frame %d", (int) frame.number);
1437         return -1;
1438     }
1439 
1440     nsecs_t actualRenderTimeNs = frame.presentFence->getSignalTime();
1441 
1442     if (actualRenderTimeNs == Fence::SIGNAL_TIME_INVALID) {
1443         ALOGW("invalid signal time for frame %d", (int) frame.number);
1444         return -1;
1445     }
1446 
1447     if (actualRenderTimeNs == Fence::SIGNAL_TIME_PENDING) {
1448         ALOGD("present fence has not fired for frame %d", (int) frame.number);
1449         return -1;
1450     }
1451 
1452     return actualRenderTimeNs;
1453 }
1454 
pollForRenderedBuffers()1455 void CCodecBufferChannel::pollForRenderedBuffers() {
1456     FrameEventHistoryDelta delta;
1457     mComponent->pollForRenderedFrames(&delta);
1458     processRenderedFrames(delta);
1459 }
1460 
onBufferReleasedFromOutputSurface(uint32_t generation)1461 void CCodecBufferChannel::onBufferReleasedFromOutputSurface(uint32_t generation) {
1462     // Note: Since this is called asynchronously from IProducerListener not
1463     // knowing the internal state of CCodec/CCodecBufferChannel,
1464     // prevent mComponent from being destroyed by holding the shared reference
1465     // during this interface being executed.
1466     std::shared_ptr<Codec2Client::Component> comp = mComponent;
1467     if (comp) {
1468         comp->onBufferReleasedFromOutputSurface(generation);
1469     }
1470 }
1471 
discardBuffer(const sp<MediaCodecBuffer> & buffer)1472 status_t CCodecBufferChannel::discardBuffer(const sp<MediaCodecBuffer> &buffer) {
1473     ALOGV("[%s] discardBuffer: %p", mName, buffer.get());
1474     bool released = false;
1475     {
1476         Mutexed<Input>::Locked input(mInput);
1477         if (input->buffers && input->buffers->releaseBuffer(buffer, nullptr, true)) {
1478             released = true;
1479         }
1480     }
1481     {
1482         Mutexed<Output>::Locked output(mOutput);
1483         if (output->buffers && output->buffers->releaseBuffer(buffer, nullptr)) {
1484             released = true;
1485         }
1486     }
1487     if (released) {
1488         sendOutputBuffers();
1489         feedInputBufferIfAvailable();
1490     } else {
1491         ALOGD("[%s] MediaCodec discarded an unknown buffer", mName);
1492     }
1493     return OK;
1494 }
1495 
getInputBufferArray(Vector<sp<MediaCodecBuffer>> * array)1496 void CCodecBufferChannel::getInputBufferArray(Vector<sp<MediaCodecBuffer>> *array) {
1497     array->clear();
1498     Mutexed<Input>::Locked input(mInput);
1499 
1500     if (!input->buffers) {
1501         ALOGE("getInputBufferArray: No Input Buffers allocated");
1502         return;
1503     }
1504     if (!input->buffers->isArrayMode()) {
1505         input->buffers = input->buffers->toArrayMode(input->numSlots);
1506     }
1507 
1508     input->buffers->getArray(array);
1509 }
1510 
getOutputBufferArray(Vector<sp<MediaCodecBuffer>> * array)1511 void CCodecBufferChannel::getOutputBufferArray(Vector<sp<MediaCodecBuffer>> *array) {
1512     array->clear();
1513     Mutexed<Output>::Locked output(mOutput);
1514     if (!output->buffers) {
1515         ALOGE("getOutputBufferArray: No Output Buffers allocated");
1516         return;
1517     }
1518     if (!output->buffers->isArrayMode()) {
1519         output->buffers = output->buffers->toArrayMode(output->numSlots);
1520     }
1521 
1522     output->buffers->getArray(array);
1523 }
1524 
start(const sp<AMessage> & inputFormat,const sp<AMessage> & outputFormat,bool buffersBoundToCodec)1525 status_t CCodecBufferChannel::start(
1526         const sp<AMessage> &inputFormat,
1527         const sp<AMessage> &outputFormat,
1528         bool buffersBoundToCodec) {
1529     C2StreamBufferTypeSetting::input iStreamFormat(0u);
1530     C2StreamBufferTypeSetting::output oStreamFormat(0u);
1531     C2ComponentKindSetting kind;
1532     C2PortReorderBufferDepthTuning::output reorderDepth;
1533     C2PortReorderKeySetting::output reorderKey;
1534     C2PortActualDelayTuning::input inputDelay(0);
1535     C2PortActualDelayTuning::output outputDelay(0);
1536     C2ActualPipelineDelayTuning pipelineDelay(0);
1537     C2SecureModeTuning secureMode(C2Config::SM_UNPROTECTED);
1538 
1539     c2_status_t err = mComponent->query(
1540             {
1541                 &iStreamFormat,
1542                 &oStreamFormat,
1543                 &kind,
1544                 &reorderDepth,
1545                 &reorderKey,
1546                 &inputDelay,
1547                 &pipelineDelay,
1548                 &outputDelay,
1549                 &secureMode,
1550             },
1551             {},
1552             C2_DONT_BLOCK,
1553             nullptr);
1554     if (err == C2_BAD_INDEX) {
1555         if (!iStreamFormat || !oStreamFormat || !kind) {
1556             return UNKNOWN_ERROR;
1557         }
1558     } else if (err != C2_OK) {
1559         return UNKNOWN_ERROR;
1560     }
1561 
1562     uint32_t inputDelayValue = inputDelay ? inputDelay.value : 0;
1563     uint32_t pipelineDelayValue = pipelineDelay ? pipelineDelay.value : 0;
1564     uint32_t outputDelayValue = outputDelay ? outputDelay.value : 0;
1565 
1566     size_t numInputSlots = inputDelayValue + pipelineDelayValue + kSmoothnessFactor;
1567     size_t numOutputSlots = outputDelayValue + kSmoothnessFactor;
1568 
1569     // TODO: get this from input format
1570     bool secure = mComponent->getName().find(".secure") != std::string::npos;
1571 
1572     // secure mode is a static parameter (shall not change in the executing state)
1573     mSendEncryptedInfoBuffer = secureMode.value == C2Config::SM_READ_PROTECTED_WITH_ENCRYPTED;
1574 
1575     std::shared_ptr<C2AllocatorStore> allocatorStore = GetCodec2PlatformAllocatorStore();
1576     int poolMask = GetCodec2PoolMask();
1577     C2PlatformAllocatorStore::id_t preferredLinearId = GetPreferredLinearAllocatorId(poolMask);
1578 
1579     if (inputFormat != nullptr) {
1580         bool graphic = (iStreamFormat.value == C2BufferData::GRAPHIC);
1581         bool audioEncoder = !graphic && (kind.value == C2Component::KIND_ENCODER);
1582         C2Config::api_feature_t apiFeatures = C2Config::api_feature_t(
1583                 API_REFLECTION |
1584                 API_VALUES |
1585                 API_CURRENT_VALUES |
1586                 API_DEPENDENCY |
1587                 API_SAME_INPUT_BUFFER);
1588         C2StreamAudioFrameSizeInfo::input encoderFrameSize(0u);
1589         C2StreamSampleRateInfo::input sampleRate(0u);
1590         C2StreamChannelCountInfo::input channelCount(0u);
1591         C2StreamPcmEncodingInfo::input pcmEncoding(0u);
1592         std::shared_ptr<C2BlockPool> pool;
1593         {
1594             Mutexed<BlockPools>::Locked pools(mBlockPools);
1595 
1596             // set default allocator ID.
1597             pools->inputAllocatorId = (graphic) ? C2PlatformAllocatorStore::GRALLOC
1598                                                 : preferredLinearId;
1599 
1600             // query C2PortAllocatorsTuning::input from component. If an allocator ID is obtained
1601             // from component, create the input block pool with given ID. Otherwise, use default IDs.
1602             std::vector<std::unique_ptr<C2Param>> params;
1603             C2ApiFeaturesSetting featuresSetting{apiFeatures};
1604             std::vector<C2Param *> stackParams({&featuresSetting});
1605             if (audioEncoder) {
1606                 stackParams.push_back(&encoderFrameSize);
1607                 stackParams.push_back(&sampleRate);
1608                 stackParams.push_back(&channelCount);
1609                 stackParams.push_back(&pcmEncoding);
1610             } else {
1611                 encoderFrameSize.invalidate();
1612                 sampleRate.invalidate();
1613                 channelCount.invalidate();
1614                 pcmEncoding.invalidate();
1615             }
1616             err = mComponent->query(stackParams,
1617                                     { C2PortAllocatorsTuning::input::PARAM_TYPE },
1618                                     C2_DONT_BLOCK,
1619                                     &params);
1620             if ((err != C2_OK && err != C2_BAD_INDEX) || params.size() != 1) {
1621                 ALOGD("[%s] Query input allocators returned %zu params => %s (%u)",
1622                         mName, params.size(), asString(err), err);
1623             } else if (params.size() == 1) {
1624                 C2PortAllocatorsTuning::input *inputAllocators =
1625                     C2PortAllocatorsTuning::input::From(params[0].get());
1626                 if (inputAllocators && inputAllocators->flexCount() > 0) {
1627                     std::shared_ptr<C2Allocator> allocator;
1628                     // verify allocator IDs and resolve default allocator
1629                     allocatorStore->fetchAllocator(inputAllocators->m.values[0], &allocator);
1630                     if (allocator) {
1631                         pools->inputAllocatorId = allocator->getId();
1632                     } else {
1633                         ALOGD("[%s] component requested invalid input allocator ID %u",
1634                                 mName, inputAllocators->m.values[0]);
1635                     }
1636                 }
1637             }
1638             if (featuresSetting) {
1639                 apiFeatures = featuresSetting.value;
1640             }
1641 
1642             // TODO: use C2Component wrapper to associate this pool with ourselves
1643             if ((poolMask >> pools->inputAllocatorId) & 1) {
1644                 err = CreateCodec2BlockPool(pools->inputAllocatorId, nullptr, &pool);
1645                 ALOGD("[%s] Created input block pool with allocatorID %u => poolID %llu - %s (%d)",
1646                         mName, pools->inputAllocatorId,
1647                         (unsigned long long)(pool ? pool->getLocalId() : 111000111),
1648                         asString(err), err);
1649             } else {
1650                 err = C2_NOT_FOUND;
1651             }
1652             if (err != C2_OK) {
1653                 C2BlockPool::local_id_t inputPoolId =
1654                     graphic ? C2BlockPool::BASIC_GRAPHIC : C2BlockPool::BASIC_LINEAR;
1655                 err = GetCodec2BlockPool(inputPoolId, nullptr, &pool);
1656                 ALOGD("[%s] Using basic input block pool with poolID %llu => got %llu - %s (%d)",
1657                         mName, (unsigned long long)inputPoolId,
1658                         (unsigned long long)(pool ? pool->getLocalId() : 111000111),
1659                         asString(err), err);
1660                 if (err != C2_OK) {
1661                     return NO_MEMORY;
1662                 }
1663             }
1664             pools->inputPool = pool;
1665         }
1666 
1667         bool forceArrayMode = false;
1668         Mutexed<Input>::Locked input(mInput);
1669         input->inputDelay = inputDelayValue;
1670         input->pipelineDelay = pipelineDelayValue;
1671         input->numSlots = numInputSlots;
1672         input->extraBuffers.flush();
1673         input->numExtraSlots = 0u;
1674         input->lastFlushIndex = mFrameIndex.load(std::memory_order_relaxed);
1675         if (audioEncoder && encoderFrameSize && sampleRate && channelCount) {
1676             input->frameReassembler.init(
1677                     pool,
1678                     {C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE},
1679                     encoderFrameSize.value,
1680                     sampleRate.value,
1681                     channelCount.value,
1682                     pcmEncoding ? pcmEncoding.value : C2Config::PCM_16);
1683         }
1684         bool conforming = (apiFeatures & API_SAME_INPUT_BUFFER);
1685         // For encrypted content, framework decrypts source buffer (ashmem) into
1686         // C2Buffers. Thus non-conforming codecs can process these.
1687         if (!buffersBoundToCodec
1688                 && !input->frameReassembler
1689                 && (hasCryptoOrDescrambler() || conforming)) {
1690             input->buffers.reset(new SlotInputBuffers(mName));
1691         } else if (graphic) {
1692             if (mInputSurface) {
1693                 input->buffers.reset(new DummyInputBuffers(mName));
1694             } else if (mMetaMode == MODE_ANW) {
1695                 input->buffers.reset(new GraphicMetadataInputBuffers(mName));
1696                 // This is to ensure buffers do not get released prematurely.
1697                 // TODO: handle this without going into array mode
1698                 forceArrayMode = true;
1699             } else {
1700                 input->buffers.reset(new GraphicInputBuffers(mName));
1701             }
1702         } else {
1703             if (hasCryptoOrDescrambler()) {
1704                 int32_t capacity = kLinearBufferSize;
1705                 (void)inputFormat->findInt32(KEY_MAX_INPUT_SIZE, &capacity);
1706                 if ((size_t)capacity > kMaxLinearBufferSize) {
1707                     ALOGD("client requested %d, capped to %zu", capacity, kMaxLinearBufferSize);
1708                     capacity = kMaxLinearBufferSize;
1709                 }
1710                 if (mDealer == nullptr) {
1711                     mDealer = new MemoryDealer(
1712                             align(capacity, MemoryDealer::getAllocationAlignment())
1713                                 * (numInputSlots + 1),
1714                             "EncryptedLinearInputBuffers");
1715                     mDecryptDestination = mDealer->allocate((size_t)capacity);
1716                 }
1717                 if (mCrypto != nullptr && mHeapSeqNum < 0) {
1718                     sp<HidlMemory> heap = fromHeap(mDealer->getMemoryHeap());
1719                     mHeapSeqNum = mCrypto->setHeap(heap);
1720                 } else {
1721                     mHeapSeqNum = -1;
1722                 }
1723                 input->buffers.reset(new EncryptedLinearInputBuffers(
1724                         secure, mDealer, mCrypto, mHeapSeqNum, (size_t)capacity,
1725                         numInputSlots, mName));
1726                 forceArrayMode = true;
1727             } else {
1728                 input->buffers.reset(new LinearInputBuffers(mName));
1729             }
1730         }
1731         input->buffers->setFormat(inputFormat);
1732 
1733         if (err == C2_OK) {
1734             input->buffers->setPool(pool);
1735         } else {
1736             // TODO: error
1737         }
1738 
1739         if (forceArrayMode) {
1740             input->buffers = input->buffers->toArrayMode(numInputSlots);
1741         }
1742     }
1743 
1744     if (outputFormat != nullptr) {
1745         sp<IGraphicBufferProducer> outputSurface;
1746         uint32_t outputGeneration;
1747         int maxDequeueCount = 0;
1748         {
1749             Mutexed<OutputSurface>::Locked output(mOutputSurface);
1750             maxDequeueCount = output->maxDequeueBuffers = numOutputSlots +
1751                     reorderDepth.value + mRenderingDepth;
1752             outputSurface = output->surface ?
1753                     output->surface->getIGraphicBufferProducer() : nullptr;
1754             if (outputSurface) {
1755                 output->surface->setMaxDequeuedBufferCount(output->maxDequeueBuffers);
1756             }
1757             outputGeneration = output->generation;
1758         }
1759 
1760         bool graphic = (oStreamFormat.value == C2BufferData::GRAPHIC);
1761         C2BlockPool::local_id_t outputPoolId_;
1762         C2BlockPool::local_id_t prevOutputPoolId;
1763 
1764         {
1765             Mutexed<BlockPools>::Locked pools(mBlockPools);
1766 
1767             prevOutputPoolId = pools->outputPoolId;
1768 
1769             // set default allocator ID.
1770             pools->outputAllocatorId = (graphic) ? C2PlatformAllocatorStore::GRALLOC
1771                                                  : preferredLinearId;
1772 
1773             // query C2PortAllocatorsTuning::output from component, or use default allocator if
1774             // unsuccessful.
1775             std::vector<std::unique_ptr<C2Param>> params;
1776             err = mComponent->query({ },
1777                                     { C2PortAllocatorsTuning::output::PARAM_TYPE },
1778                                     C2_DONT_BLOCK,
1779                                     &params);
1780             if ((err != C2_OK && err != C2_BAD_INDEX) || params.size() != 1) {
1781                 ALOGD("[%s] Query output allocators returned %zu params => %s (%u)",
1782                         mName, params.size(), asString(err), err);
1783             } else if (err == C2_OK && params.size() == 1) {
1784                 C2PortAllocatorsTuning::output *outputAllocators =
1785                     C2PortAllocatorsTuning::output::From(params[0].get());
1786                 if (outputAllocators && outputAllocators->flexCount() > 0) {
1787                     std::shared_ptr<C2Allocator> allocator;
1788                     // verify allocator IDs and resolve default allocator
1789                     allocatorStore->fetchAllocator(outputAllocators->m.values[0], &allocator);
1790                     if (allocator) {
1791                         pools->outputAllocatorId = allocator->getId();
1792                     } else {
1793                         ALOGD("[%s] component requested invalid output allocator ID %u",
1794                                 mName, outputAllocators->m.values[0]);
1795                     }
1796                 }
1797             }
1798 
1799             // use bufferqueue if outputting to a surface.
1800             // query C2PortSurfaceAllocatorTuning::output from component, or use default allocator
1801             // if unsuccessful.
1802             if (outputSurface) {
1803                 params.clear();
1804                 err = mComponent->query({ },
1805                                         { C2PortSurfaceAllocatorTuning::output::PARAM_TYPE },
1806                                         C2_DONT_BLOCK,
1807                                         &params);
1808                 if ((err != C2_OK && err != C2_BAD_INDEX) || params.size() != 1) {
1809                     ALOGD("[%s] Query output surface allocator returned %zu params => %s (%u)",
1810                             mName, params.size(), asString(err), err);
1811                 } else if (err == C2_OK && params.size() == 1) {
1812                     C2PortSurfaceAllocatorTuning::output *surfaceAllocator =
1813                         C2PortSurfaceAllocatorTuning::output::From(params[0].get());
1814                     if (surfaceAllocator) {
1815                         std::shared_ptr<C2Allocator> allocator;
1816                         // verify allocator IDs and resolve default allocator
1817                         allocatorStore->fetchAllocator(surfaceAllocator->value, &allocator);
1818                         if (allocator) {
1819                             pools->outputAllocatorId = allocator->getId();
1820                         } else {
1821                             ALOGD("[%s] component requested invalid surface output allocator ID %u",
1822                                     mName, surfaceAllocator->value);
1823                             err = C2_BAD_VALUE;
1824                         }
1825                     }
1826                 }
1827                 if (pools->outputAllocatorId == C2PlatformAllocatorStore::GRALLOC
1828                         && err != C2_OK
1829                         && ((poolMask >> C2PlatformAllocatorStore::BUFFERQUEUE) & 1)) {
1830                     pools->outputAllocatorId = C2PlatformAllocatorStore::BUFFERQUEUE;
1831                 }
1832             }
1833 
1834             if ((poolMask >> pools->outputAllocatorId) & 1) {
1835                 err = mComponent->createBlockPool(
1836                         pools->outputAllocatorId, &pools->outputPoolId, &pools->outputPoolIntf);
1837                 ALOGI("[%s] Created output block pool with allocatorID %u => poolID %llu - %s",
1838                         mName, pools->outputAllocatorId,
1839                         (unsigned long long)pools->outputPoolId,
1840                         asString(err));
1841             } else {
1842                 err = C2_NOT_FOUND;
1843             }
1844             if (err != C2_OK) {
1845                 // use basic pool instead
1846                 pools->outputPoolId =
1847                     graphic ? C2BlockPool::BASIC_GRAPHIC : C2BlockPool::BASIC_LINEAR;
1848             }
1849 
1850             // Configure output block pool ID as parameter C2PortBlockPoolsTuning::output to
1851             // component.
1852             std::unique_ptr<C2PortBlockPoolsTuning::output> poolIdsTuning =
1853                     C2PortBlockPoolsTuning::output::AllocUnique({ pools->outputPoolId });
1854 
1855             std::vector<std::unique_ptr<C2SettingResult>> failures;
1856             err = mComponent->config({ poolIdsTuning.get() }, C2_MAY_BLOCK, &failures);
1857             ALOGD("[%s] Configured output block pool ids %llu => %s",
1858                     mName, (unsigned long long)poolIdsTuning->m.values[0], asString(err));
1859             outputPoolId_ = pools->outputPoolId;
1860         }
1861 
1862         if (prevOutputPoolId != C2BlockPool::BASIC_LINEAR
1863                 && prevOutputPoolId != C2BlockPool::BASIC_GRAPHIC) {
1864             c2_status_t err = mComponent->destroyBlockPool(prevOutputPoolId);
1865             if (err != C2_OK) {
1866                 ALOGW("Failed to clean up previous block pool %llu - %s (%d)\n",
1867                         (unsigned long long) prevOutputPoolId, asString(err), err);
1868             }
1869         }
1870 
1871         Mutexed<Output>::Locked output(mOutput);
1872         output->outputDelay = outputDelayValue;
1873         output->numSlots = numOutputSlots;
1874         output->bounded = bool(outputSurface);
1875         if (graphic) {
1876             if (outputSurface || !buffersBoundToCodec) {
1877                 output->buffers.reset(new GraphicOutputBuffers(mName));
1878             } else {
1879                 output->buffers.reset(new RawGraphicOutputBuffers(mName));
1880             }
1881         } else {
1882             output->buffers.reset(new LinearOutputBuffers(mName));
1883         }
1884         output->buffers->setFormat(outputFormat);
1885 
1886         output->buffers->clearStash();
1887         if (reorderDepth) {
1888             output->buffers->setReorderDepth(reorderDepth.value);
1889         }
1890         if (reorderKey) {
1891             output->buffers->setReorderKey(reorderKey.value);
1892         }
1893 
1894         // Try to set output surface to created block pool if given.
1895         if (outputSurface) {
1896             mComponent->setOutputSurface(
1897                     outputPoolId_,
1898                     outputSurface,
1899                     outputGeneration,
1900                     maxDequeueCount);
1901         } else {
1902             // configure CPU read consumer usage
1903             C2StreamUsageTuning::output outputUsage{0u, C2MemoryUsage::CPU_READ};
1904             std::vector<std::unique_ptr<C2SettingResult>> failures;
1905             err = mComponent->config({ &outputUsage }, C2_MAY_BLOCK, &failures);
1906             // do not print error message for now as most components may not yet
1907             // support this setting
1908             ALOGD_IF(err != C2_BAD_INDEX, "[%s] Configured output usage [%#llx]",
1909                   mName, (long long)outputUsage.value);
1910         }
1911 
1912         if (oStreamFormat.value == C2BufferData::LINEAR) {
1913             if (buffersBoundToCodec) {
1914                 // WORKAROUND: if we're using early CSD workaround we convert to
1915                 //             array mode, to appease apps assuming the output
1916                 //             buffers to be of the same size.
1917                 output->buffers = output->buffers->toArrayMode(numOutputSlots);
1918             }
1919 
1920             int32_t channelCount;
1921             int32_t sampleRate;
1922             if (outputFormat->findInt32(KEY_CHANNEL_COUNT, &channelCount)
1923                     && outputFormat->findInt32(KEY_SAMPLE_RATE, &sampleRate)) {
1924                 int32_t delay = 0;
1925                 int32_t padding = 0;;
1926                 if (!outputFormat->findInt32("encoder-delay", &delay)) {
1927                     delay = 0;
1928                 }
1929                 if (!outputFormat->findInt32("encoder-padding", &padding)) {
1930                     padding = 0;
1931                 }
1932                 if (delay || padding) {
1933                     // We need write access to the buffers, so turn them into array mode.
1934                     // TODO: b/321930152 - define SkipCutOutputBuffers that takes output from
1935                     // component, runs it through SkipCutBuffer and allocate local buffer to be
1936                     // used by fwk. Make initSkipCutBuffer() return OutputBuffers similar to
1937                     // toArrayMode().
1938                     if (!output->buffers->isArrayMode()) {
1939                         output->buffers = output->buffers->toArrayMode(numOutputSlots);
1940                     }
1941                     output->buffers->initSkipCutBuffer(delay, padding, sampleRate, channelCount);
1942                 }
1943             }
1944         }
1945 
1946         int32_t tunneled = 0;
1947         if (!outputFormat->findInt32("android._tunneled", &tunneled)) {
1948             tunneled = 0;
1949         }
1950         mTunneled = (tunneled != 0);
1951     }
1952 
1953     // Set up pipeline control. This has to be done after mInputBuffers and
1954     // mOutputBuffers are initialized to make sure that lingering callbacks
1955     // about buffers from the previous generation do not interfere with the
1956     // newly initialized pipeline capacity.
1957 
1958     if (inputFormat || outputFormat) {
1959         Mutexed<PipelineWatcher>::Locked watcher(mPipelineWatcher);
1960         watcher->inputDelay(inputDelayValue)
1961                 .pipelineDelay(pipelineDelayValue)
1962                 .outputDelay(outputDelayValue)
1963                 .smoothnessFactor(kSmoothnessFactor)
1964                 .tunneled(mTunneled);
1965         watcher->flush();
1966     }
1967 
1968     mInputMetEos = false;
1969     mSync.start();
1970     return OK;
1971 }
1972 
prepareInitialInputBuffers(std::map<size_t,sp<MediaCodecBuffer>> * clientInputBuffers,bool retry)1973 status_t CCodecBufferChannel::prepareInitialInputBuffers(
1974         std::map<size_t, sp<MediaCodecBuffer>> *clientInputBuffers, bool retry) {
1975     if (mInputSurface) {
1976         return OK;
1977     }
1978 
1979     size_t numInputSlots = mInput.lock()->numSlots;
1980     int retryCount = 1;
1981     for (; clientInputBuffers->empty() && retryCount >= 0; retryCount--) {
1982         {
1983             Mutexed<Input>::Locked input(mInput);
1984             while (clientInputBuffers->size() < numInputSlots) {
1985                 size_t index;
1986                 sp<MediaCodecBuffer> buffer;
1987                 if (!input->buffers->requestNewBuffer(&index, &buffer)) {
1988                     break;
1989                 }
1990                 clientInputBuffers->emplace(index, buffer);
1991             }
1992         }
1993         if (!retry || (retryCount <= 0)) {
1994             break;
1995         }
1996         if (clientInputBuffers->empty()) {
1997             // wait: buffer may be in transit from component.
1998             std::this_thread::sleep_for(std::chrono::milliseconds(4));
1999         }
2000     }
2001     if (clientInputBuffers->empty()) {
2002         ALOGW("[%s] start: cannot allocate memory at all", mName);
2003         return NO_MEMORY;
2004     } else if (clientInputBuffers->size() < numInputSlots) {
2005         ALOGD("[%s] start: cannot allocate memory for all slots, "
2006               "only %zu buffers allocated",
2007               mName, clientInputBuffers->size());
2008     } else {
2009         ALOGV("[%s] %zu initial input buffers available",
2010               mName, clientInputBuffers->size());
2011     }
2012     return OK;
2013 }
2014 
requestInitialInputBuffers(std::map<size_t,sp<MediaCodecBuffer>> && clientInputBuffers)2015 status_t CCodecBufferChannel::requestInitialInputBuffers(
2016         std::map<size_t, sp<MediaCodecBuffer>> &&clientInputBuffers) {
2017     C2StreamBufferTypeSetting::output oStreamFormat(0u);
2018     C2PrependHeaderModeSetting prepend(PREPEND_HEADER_TO_NONE);
2019     c2_status_t err = mComponent->query({ &oStreamFormat, &prepend }, {}, C2_DONT_BLOCK, nullptr);
2020     if (err != C2_OK && err != C2_BAD_INDEX) {
2021         return UNKNOWN_ERROR;
2022     }
2023 
2024     std::list<std::unique_ptr<C2Work>> flushedConfigs;
2025     mFlushedConfigs.lock()->swap(flushedConfigs);
2026     if (!flushedConfigs.empty()) {
2027         {
2028             Mutexed<PipelineWatcher>::Locked watcher(mPipelineWatcher);
2029             PipelineWatcher::Clock::time_point now = PipelineWatcher::Clock::now();
2030             for (const std::unique_ptr<C2Work> &work : flushedConfigs) {
2031                 watcher->onWorkQueued(
2032                         work->input.ordinal.frameIndex.peeku(),
2033                         std::vector(work->input.buffers),
2034                         now);
2035             }
2036         }
2037         err = mComponent->queue(&flushedConfigs);
2038         if (err != C2_OK) {
2039             ALOGW("[%s] Error while queueing a flushed config", mName);
2040             return UNKNOWN_ERROR;
2041         }
2042     }
2043     if (oStreamFormat.value == C2BufferData::LINEAR &&
2044             (!prepend || prepend.value == PREPEND_HEADER_TO_NONE) &&
2045             !clientInputBuffers.empty()) {
2046         size_t minIndex = clientInputBuffers.begin()->first;
2047         sp<MediaCodecBuffer> minBuffer = clientInputBuffers.begin()->second;
2048         for (const auto &[index, buffer] : clientInputBuffers) {
2049             if (minBuffer->capacity() > buffer->capacity()) {
2050                 minIndex = index;
2051                 minBuffer = buffer;
2052             }
2053         }
2054         // WORKAROUND: Some apps expect CSD available without queueing
2055         //             any input. Queue an empty buffer to get the CSD.
2056         minBuffer->setRange(0, 0);
2057         minBuffer->meta()->clear();
2058         minBuffer->meta()->setInt64("timeUs", 0);
2059         if (queueInputBufferInternal(minBuffer) != OK) {
2060             ALOGW("[%s] Error while queueing an empty buffer to get CSD",
2061                   mName);
2062             return UNKNOWN_ERROR;
2063         }
2064         clientInputBuffers.erase(minIndex);
2065     }
2066 
2067     for (const auto &[index, buffer] : clientInputBuffers) {
2068         mCallback->onInputBufferAvailable(index, buffer);
2069     }
2070 
2071     return OK;
2072 }
2073 
stop()2074 void CCodecBufferChannel::stop() {
2075     mSync.stop();
2076     mFirstValidFrameIndex = mFrameIndex.load(std::memory_order_relaxed);
2077     mInfoBuffers.clear();
2078 }
2079 
stopUseOutputSurface(bool pushBlankBuffer)2080 void CCodecBufferChannel::stopUseOutputSurface(bool pushBlankBuffer) {
2081     sp<Surface> surface = mOutputSurface.lock()->surface;
2082     if (surface) {
2083         C2BlockPool::local_id_t outputPoolId;
2084         {
2085             Mutexed<BlockPools>::Locked pools(mBlockPools);
2086             outputPoolId = pools->outputPoolId;
2087         }
2088         if (mComponent) mComponent->stopUsingOutputSurface(outputPoolId);
2089 
2090         if (pushBlankBuffer) {
2091             sp<ANativeWindow> anw = static_cast<ANativeWindow *>(surface.get());
2092             if (anw) {
2093                 pushBlankBuffersToNativeWindow(anw.get());
2094             }
2095         }
2096     }
2097 }
2098 
reset()2099 void CCodecBufferChannel::reset() {
2100     stop();
2101     if (mInputSurface != nullptr) {
2102         mInputSurface.reset();
2103     }
2104     mPipelineWatcher.lock()->flush();
2105     {
2106         Mutexed<Input>::Locked input(mInput);
2107         input->buffers.reset(new DummyInputBuffers(""));
2108         input->extraBuffers.flush();
2109     }
2110     {
2111         Mutexed<Output>::Locked output(mOutput);
2112         output->buffers.reset();
2113     }
2114     // reset the frames that are being tracked for onFrameRendered callbacks
2115     mTrackedFrames.clear();
2116 }
2117 
release()2118 void CCodecBufferChannel::release() {
2119     mInfoBuffers.clear();
2120     mComponent.reset();
2121     mInputAllocator.reset();
2122     mOutputSurface.lock()->surface.clear();
2123     {
2124         Mutexed<BlockPools>::Locked blockPools{mBlockPools};
2125         blockPools->inputPool.reset();
2126         blockPools->outputPoolIntf.reset();
2127     }
2128     setCrypto(nullptr);
2129     setDescrambler(nullptr);
2130 }
2131 
flush(const std::list<std::unique_ptr<C2Work>> & flushedWork)2132 void CCodecBufferChannel::flush(const std::list<std::unique_ptr<C2Work>> &flushedWork) {
2133     ALOGV("[%s] flush", mName);
2134     std::list<std::unique_ptr<C2Work>> configs;
2135     mInput.lock()->lastFlushIndex = mFrameIndex.load(std::memory_order_relaxed);
2136     {
2137         Mutexed<PipelineWatcher>::Locked watcher(mPipelineWatcher);
2138         for (const std::unique_ptr<C2Work> &work : flushedWork) {
2139             uint64_t frameIndex = work->input.ordinal.frameIndex.peeku();
2140             if (!(work->input.flags & C2FrameData::FLAG_CODEC_CONFIG)) {
2141                 watcher->onWorkDone(frameIndex);
2142                 continue;
2143             }
2144             if (work->input.buffers.empty()
2145                     || work->input.buffers.front() == nullptr
2146                     || work->input.buffers.front()->data().linearBlocks().empty()) {
2147                 ALOGD("[%s] no linear codec config data found", mName);
2148                 watcher->onWorkDone(frameIndex);
2149                 continue;
2150             }
2151             std::unique_ptr<C2Work> copy(new C2Work);
2152             copy->input.flags = C2FrameData::flags_t(
2153                     work->input.flags | C2FrameData::FLAG_DROP_FRAME);
2154             copy->input.ordinal = work->input.ordinal;
2155             copy->input.ordinal.frameIndex = mFrameIndex++;
2156             for (size_t i = 0; i < work->input.buffers.size(); ++i) {
2157                 copy->input.buffers.push_back(watcher->onInputBufferReleased(frameIndex, i));
2158             }
2159             for (const std::unique_ptr<C2Param> &param : work->input.configUpdate) {
2160                 copy->input.configUpdate.push_back(C2Param::Copy(*param));
2161             }
2162             copy->input.infoBuffers.insert(
2163                     copy->input.infoBuffers.begin(),
2164                     work->input.infoBuffers.begin(),
2165                     work->input.infoBuffers.end());
2166             copy->worklets.emplace_back(new C2Worklet);
2167             configs.push_back(std::move(copy));
2168             watcher->onWorkDone(frameIndex);
2169             ALOGV("[%s] stashed flushed codec config data", mName);
2170         }
2171     }
2172     mFlushedConfigs.lock()->swap(configs);
2173     {
2174         Mutexed<Input>::Locked input(mInput);
2175         input->buffers->flush();
2176         input->extraBuffers.flush();
2177     }
2178     {
2179         Mutexed<Output>::Locked output(mOutput);
2180         if (output->buffers) {
2181             output->buffers->flush(flushedWork);
2182             output->buffers->flushStash();
2183         }
2184     }
2185     mInfoBuffers.clear();
2186 }
2187 
onWorkDone(std::unique_ptr<C2Work> work,const sp<AMessage> & outputFormat,const C2StreamInitDataInfo::output * initData)2188 void CCodecBufferChannel::onWorkDone(
2189         std::unique_ptr<C2Work> work, const sp<AMessage> &outputFormat,
2190         const C2StreamInitDataInfo::output *initData) {
2191     if (handleWork(std::move(work), outputFormat, initData)) {
2192         feedInputBufferIfAvailable();
2193     }
2194 }
2195 
onInputBufferDone(uint64_t frameIndex,size_t arrayIndex)2196 void CCodecBufferChannel::onInputBufferDone(
2197         uint64_t frameIndex, size_t arrayIndex) {
2198     if (mInputSurface) {
2199         return;
2200     }
2201     std::shared_ptr<C2Buffer> buffer =
2202             mPipelineWatcher.lock()->onInputBufferReleased(frameIndex, arrayIndex);
2203     bool newInputSlotAvailable = false;
2204     {
2205         Mutexed<Input>::Locked input(mInput);
2206         if (input->lastFlushIndex >= frameIndex) {
2207             ALOGD("[%s] Ignoring stale input buffer done callback: "
2208                   "last flush index = %lld, frameIndex = %lld",
2209                   mName, input->lastFlushIndex.peekll(), (long long)frameIndex);
2210         } else {
2211             newInputSlotAvailable = input->buffers->expireComponentBuffer(buffer);
2212             if (!newInputSlotAvailable) {
2213                 (void)input->extraBuffers.expireComponentBuffer(buffer);
2214             }
2215         }
2216     }
2217     if (newInputSlotAvailable) {
2218         feedInputBufferIfAvailable();
2219     }
2220 }
2221 
handleWork(std::unique_ptr<C2Work> work,const sp<AMessage> & outputFormat,const C2StreamInitDataInfo::output * initData)2222 bool CCodecBufferChannel::handleWork(
2223         std::unique_ptr<C2Work> work,
2224         const sp<AMessage> &outputFormat,
2225         const C2StreamInitDataInfo::output *initData) {
2226     {
2227         Mutexed<Output>::Locked output(mOutput);
2228         if (!output->buffers) {
2229             return false;
2230         }
2231     }
2232 
2233     // Whether the output buffer should be reported to the client or not.
2234     bool notifyClient = false;
2235 
2236     if (work->result == C2_OK){
2237         notifyClient = true;
2238     } else if (work->result == C2_NOT_FOUND) {
2239         ALOGD("[%s] flushed work; ignored.", mName);
2240     } else {
2241         // C2_OK and C2_NOT_FOUND are the only results that we accept for processing
2242         // the config update.
2243         ALOGD("[%s] work failed to complete: %d", mName, work->result);
2244         mCCodecCallback->onError(work->result, ACTION_CODE_FATAL);
2245         return false;
2246     }
2247 
2248     if ((work->input.ordinal.frameIndex -
2249             mFirstValidFrameIndex.load()).peek() < 0) {
2250         // Discard frames from previous generation.
2251         ALOGD("[%s] Discard frames from previous generation.", mName);
2252         notifyClient = false;
2253     }
2254 
2255     if (mInputSurface == nullptr && (work->worklets.size() != 1u
2256             || !work->worklets.front()
2257             || !(work->worklets.front()->output.flags &
2258                  C2FrameData::FLAG_INCOMPLETE))) {
2259         mPipelineWatcher.lock()->onWorkDone(
2260                 work->input.ordinal.frameIndex.peeku());
2261     }
2262 
2263     // NOTE: MediaCodec usage supposedly have only one worklet
2264     if (work->worklets.size() != 1u) {
2265         ALOGI("[%s] onWorkDone: incorrect number of worklets: %zu",
2266                 mName, work->worklets.size());
2267         mCCodecCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL);
2268         return false;
2269     }
2270 
2271     const std::unique_ptr<C2Worklet> &worklet = work->worklets.front();
2272 
2273     std::shared_ptr<C2Buffer> buffer;
2274     // NOTE: MediaCodec usage supposedly have only one output stream.
2275     if (worklet->output.buffers.size() > 1u) {
2276         ALOGI("[%s] onWorkDone: incorrect number of output buffers: %zu",
2277                 mName, worklet->output.buffers.size());
2278         mCCodecCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL);
2279         return false;
2280     } else if (worklet->output.buffers.size() == 1u) {
2281         buffer = worklet->output.buffers[0];
2282         if (!buffer) {
2283             ALOGD("[%s] onWorkDone: nullptr found in buffers; ignored.", mName);
2284         }
2285     }
2286 
2287     std::optional<uint32_t> newInputDelay, newPipelineDelay, newOutputDelay, newReorderDepth;
2288     std::optional<C2Config::ordinal_key_t> newReorderKey;
2289     bool needMaxDequeueBufferCountUpdate = false;
2290     while (!worklet->output.configUpdate.empty()) {
2291         std::unique_ptr<C2Param> param;
2292         worklet->output.configUpdate.back().swap(param);
2293         worklet->output.configUpdate.pop_back();
2294         switch (param->coreIndex().coreIndex()) {
2295             case C2PortReorderBufferDepthTuning::CORE_INDEX: {
2296                 C2PortReorderBufferDepthTuning::output reorderDepth;
2297                 if (reorderDepth.updateFrom(*param)) {
2298                     ALOGV("[%s] onWorkDone: updated reorder depth to %u",
2299                           mName, reorderDepth.value);
2300                     newReorderDepth = reorderDepth.value;
2301                     needMaxDequeueBufferCountUpdate = true;
2302                 } else {
2303                     ALOGD("[%s] onWorkDone: failed to read reorder depth",
2304                           mName);
2305                 }
2306                 break;
2307             }
2308             case C2PortReorderKeySetting::CORE_INDEX: {
2309                 C2PortReorderKeySetting::output reorderKey;
2310                 if (reorderKey.updateFrom(*param)) {
2311                     newReorderKey = reorderKey.value;
2312                     ALOGV("[%s] onWorkDone: updated reorder key to %u",
2313                           mName, reorderKey.value);
2314                 } else {
2315                     ALOGD("[%s] onWorkDone: failed to read reorder key", mName);
2316                 }
2317                 break;
2318             }
2319             case C2PortActualDelayTuning::CORE_INDEX: {
2320                 if (param->isGlobal()) {
2321                     C2ActualPipelineDelayTuning pipelineDelay;
2322                     if (pipelineDelay.updateFrom(*param)) {
2323                         ALOGV("[%s] onWorkDone: updating pipeline delay %u",
2324                               mName, pipelineDelay.value);
2325                         newPipelineDelay = pipelineDelay.value;
2326                         (void)mPipelineWatcher.lock()->pipelineDelay(
2327                                 pipelineDelay.value);
2328                     }
2329                 }
2330                 if (param->forInput()) {
2331                     C2PortActualDelayTuning::input inputDelay;
2332                     if (inputDelay.updateFrom(*param)) {
2333                         ALOGV("[%s] onWorkDone: updating input delay %u",
2334                               mName, inputDelay.value);
2335                         newInputDelay = inputDelay.value;
2336                         (void)mPipelineWatcher.lock()->inputDelay(
2337                                 inputDelay.value);
2338                     }
2339                 }
2340                 if (param->forOutput()) {
2341                     C2PortActualDelayTuning::output outputDelay;
2342                     if (outputDelay.updateFrom(*param)) {
2343                         ALOGV("[%s] onWorkDone: updating output delay %u",
2344                               mName, outputDelay.value);
2345                         (void)mPipelineWatcher.lock()->outputDelay(outputDelay.value);
2346                         newOutputDelay = outputDelay.value;
2347                         needMaxDequeueBufferCountUpdate = true;
2348 
2349                     }
2350                 }
2351                 break;
2352             }
2353             case C2PortTunnelSystemTime::CORE_INDEX: {
2354                 C2PortTunnelSystemTime::output frameRenderTime;
2355                 if (frameRenderTime.updateFrom(*param)) {
2356                     ALOGV("[%s] onWorkDone: frame rendered (sys:%lld ns, media:%lld us)",
2357                           mName, (long long)frameRenderTime.value,
2358                           (long long)worklet->output.ordinal.timestamp.peekll());
2359                     mCCodecCallback->onOutputFramesRendered(
2360                             worklet->output.ordinal.timestamp.peek(), frameRenderTime.value);
2361                 }
2362                 break;
2363             }
2364             case C2StreamTunnelHoldRender::CORE_INDEX: {
2365                 C2StreamTunnelHoldRender::output firstTunnelFrameHoldRender;
2366                 if (!(worklet->output.flags & C2FrameData::FLAG_INCOMPLETE)) break;
2367                 if (!firstTunnelFrameHoldRender.updateFrom(*param)) break;
2368                 if (firstTunnelFrameHoldRender.value != C2_TRUE) break;
2369                 ALOGV("[%s] onWorkDone: first tunnel frame ready", mName);
2370                 mCCodecCallback->onFirstTunnelFrameReady();
2371                 break;
2372             }
2373             default:
2374                 ALOGV("[%s] onWorkDone: unrecognized config update (%08X)",
2375                       mName, param->index());
2376                 break;
2377         }
2378     }
2379     if (newInputDelay || newPipelineDelay) {
2380         Mutexed<Input>::Locked input(mInput);
2381         size_t newNumSlots =
2382             newInputDelay.value_or(input->inputDelay) +
2383             newPipelineDelay.value_or(input->pipelineDelay) +
2384             kSmoothnessFactor;
2385         input->inputDelay = newInputDelay.value_or(input->inputDelay);
2386         if (input->buffers->isArrayMode()) {
2387             if (input->numSlots >= newNumSlots) {
2388                 input->numExtraSlots = 0;
2389             } else {
2390                 input->numExtraSlots = newNumSlots - input->numSlots;
2391             }
2392             ALOGV("[%s] onWorkDone: updated number of extra slots to %zu (input array mode)",
2393                   mName, input->numExtraSlots);
2394         } else {
2395             input->numSlots = newNumSlots;
2396         }
2397     }
2398     size_t numOutputSlots = 0;
2399     uint32_t reorderDepth = 0;
2400     bool outputBuffersChanged = false;
2401     if (newReorderKey || newReorderDepth || needMaxDequeueBufferCountUpdate) {
2402         Mutexed<Output>::Locked output(mOutput);
2403         if (!output->buffers) {
2404             return false;
2405         }
2406         numOutputSlots = output->numSlots;
2407         if (newReorderKey) {
2408             output->buffers->setReorderKey(newReorderKey.value());
2409         }
2410         if (newReorderDepth) {
2411             output->buffers->setReorderDepth(newReorderDepth.value());
2412         }
2413         reorderDepth = output->buffers->getReorderDepth();
2414         if (newOutputDelay) {
2415             output->outputDelay = newOutputDelay.value();
2416             numOutputSlots = newOutputDelay.value() + kSmoothnessFactor;
2417             if (output->numSlots < numOutputSlots) {
2418                 output->numSlots = numOutputSlots;
2419                 if (output->buffers->isArrayMode()) {
2420                     OutputBuffersArray *array =
2421                         (OutputBuffersArray *)output->buffers.get();
2422                     ALOGV("[%s] onWorkDone: growing output buffer array to %zu",
2423                           mName, numOutputSlots);
2424                     array->grow(numOutputSlots);
2425                     outputBuffersChanged = true;
2426                 }
2427             }
2428         }
2429         numOutputSlots = output->numSlots;
2430     }
2431     if (outputBuffersChanged) {
2432         mCCodecCallback->onOutputBuffersChanged();
2433     }
2434     if (needMaxDequeueBufferCountUpdate) {
2435         int maxDequeueCount = 0;
2436         {
2437             Mutexed<OutputSurface>::Locked output(mOutputSurface);
2438             maxDequeueCount = output->maxDequeueBuffers =
2439                     numOutputSlots + reorderDepth + mRenderingDepth;
2440             if (output->surface) {
2441                 output->surface->setMaxDequeuedBufferCount(output->maxDequeueBuffers);
2442             }
2443         }
2444         if (maxDequeueCount > 0) {
2445             mComponent->setOutputSurfaceMaxDequeueCount(maxDequeueCount);
2446         }
2447     }
2448 
2449     int32_t flags = 0;
2450     if (worklet->output.flags & C2FrameData::FLAG_END_OF_STREAM) {
2451         flags |= BUFFER_FLAG_END_OF_STREAM;
2452         ALOGV("[%s] onWorkDone: output EOS", mName);
2453     }
2454 
2455     // WORKAROUND: adjust output timestamp based on client input timestamp and codec
2456     // input timestamp. Codec output timestamp (in the timestamp field) shall correspond to
2457     // the codec input timestamp, but client output timestamp should (reported in timeUs)
2458     // shall correspond to the client input timesamp (in customOrdinal). By using the
2459     // delta between the two, this allows for some timestamp deviation - e.g. if one input
2460     // produces multiple output.
2461     c2_cntr64_t timestamp =
2462         worklet->output.ordinal.timestamp + work->input.ordinal.customOrdinal
2463                 - work->input.ordinal.timestamp;
2464     if (mInputSurface != nullptr) {
2465         // When using input surface we need to restore the original input timestamp.
2466         timestamp = work->input.ordinal.customOrdinal;
2467     }
2468     ScopedTrace trace(ATRACE_TAG, android::base::StringPrintf(
2469             "CCodecBufferChannel::onWorkDone(%s@ts=%lld)", mName, timestamp.peekll()).c_str());
2470     ALOGV("[%s] onWorkDone: input %lld, codec %lld => output %lld => %lld",
2471           mName,
2472           work->input.ordinal.customOrdinal.peekll(),
2473           work->input.ordinal.timestamp.peekll(),
2474           worklet->output.ordinal.timestamp.peekll(),
2475           timestamp.peekll());
2476 
2477     // csd cannot be re-ordered and will always arrive first.
2478     if (initData != nullptr) {
2479         Mutexed<Output>::Locked output(mOutput);
2480         if (!output->buffers) {
2481             return false;
2482         }
2483         if (outputFormat) {
2484             output->buffers->updateSkipCutBuffer(outputFormat);
2485             output->buffers->setFormat(outputFormat);
2486         }
2487         if (!notifyClient) {
2488             return false;
2489         }
2490         size_t index;
2491         sp<MediaCodecBuffer> outBuffer;
2492         if (output->buffers->registerCsd(initData, &index, &outBuffer) == OK) {
2493             outBuffer->meta()->setInt64("timeUs", timestamp.peek());
2494             outBuffer->meta()->setInt32("flags", BUFFER_FLAG_CODEC_CONFIG);
2495             ALOGV("[%s] onWorkDone: csd index = %zu [%p]", mName, index, outBuffer.get());
2496 
2497             // TRICKY: we want popped buffers reported in order, so sending
2498             // the callback while holding the lock here. This assumes that
2499             // onOutputBufferAvailable() does not block. onOutputBufferAvailable()
2500             // callbacks are always sent with the Output lock held.
2501             mCallback->onOutputBufferAvailable(index, outBuffer);
2502         } else {
2503             ALOGD("[%s] onWorkDone: unable to register csd", mName);
2504             output.unlock();
2505             mCCodecCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL);
2506             return false;
2507         }
2508     }
2509 
2510     bool drop = false;
2511     if (worklet->output.flags & C2FrameData::FLAG_DROP_FRAME) {
2512         ALOGV("[%s] onWorkDone: drop buffer but keep metadata", mName);
2513         drop = true;
2514     }
2515 
2516     // Workaround: if C2FrameData::FLAG_DROP_FRAME is not implemented in
2517     // HAL, the flag is then removed in the corresponding output buffer.
2518     if (work->input.flags & C2FrameData::FLAG_DROP_FRAME) {
2519         flags |= BUFFER_FLAG_DECODE_ONLY;
2520     }
2521 
2522     if (notifyClient && !buffer && !flags) {
2523         if (mTunneled && drop && outputFormat) {
2524             if (mOutputFormat != outputFormat) {
2525                 ALOGV("[%s] onWorkDone: Keep tunneled, drop frame with format change (%lld)",
2526                       mName, work->input.ordinal.frameIndex.peekull());
2527                 mOutputFormat = outputFormat;
2528             } else {
2529                 ALOGV("[%s] onWorkDone: Not reporting output buffer without format change (%lld)",
2530                       mName, work->input.ordinal.frameIndex.peekull());
2531                 notifyClient = false;
2532             }
2533         } else {
2534             ALOGV("[%s] onWorkDone: Not reporting output buffer (%lld)",
2535                   mName, work->input.ordinal.frameIndex.peekull());
2536             notifyClient = false;
2537         }
2538     }
2539 
2540     if (buffer) {
2541         for (const std::shared_ptr<const C2Info> &info : buffer->info()) {
2542             // TODO: properly translate these to metadata
2543             switch (info->coreIndex().coreIndex()) {
2544                 case C2StreamPictureTypeMaskInfo::CORE_INDEX:
2545                     if (((C2StreamPictureTypeMaskInfo *)info.get())->value & C2Config::SYNC_FRAME) {
2546                         flags |= BUFFER_FLAG_KEY_FRAME;
2547                     }
2548                     break;
2549                 default:
2550                     break;
2551             }
2552         }
2553     }
2554 
2555     {
2556         Mutexed<Output>::Locked output(mOutput);
2557         if (!output->buffers) {
2558             return false;
2559         }
2560         output->buffers->pushToStash(
2561                 buffer,
2562                 notifyClient,
2563                 timestamp.peek(),
2564                 flags,
2565                 outputFormat,
2566                 worklet->output.ordinal);
2567     }
2568     sendOutputBuffers();
2569     return true;
2570 }
2571 
sendOutputBuffers()2572 void CCodecBufferChannel::sendOutputBuffers() {
2573     OutputBuffers::BufferAction action;
2574     size_t index;
2575     sp<MediaCodecBuffer> outBuffer;
2576     std::shared_ptr<C2Buffer> c2Buffer;
2577 
2578     constexpr int kMaxReallocTry = 5;
2579     int reallocTryNum = 0;
2580 
2581     while (true) {
2582         Mutexed<Output>::Locked output(mOutput);
2583         if (!output->buffers) {
2584             return;
2585         }
2586         action = output->buffers->popFromStashAndRegister(
2587                 &c2Buffer, &index, &outBuffer);
2588         if (action != OutputBuffers::REALLOCATE) {
2589             reallocTryNum = 0;
2590         }
2591         switch (action) {
2592         case OutputBuffers::SKIP:
2593             return;
2594         case OutputBuffers::DISCARD:
2595             break;
2596         case OutputBuffers::NOTIFY_CLIENT:
2597         {
2598             // TRICKY: we want popped buffers reported in order, so sending
2599             // the callback while holding the lock here. This assumes that
2600             // onOutputBufferAvailable() does not block. onOutputBufferAvailable()
2601             // callbacks are always sent with the Output lock held.
2602             if (c2Buffer) {
2603                 std::shared_ptr<const C2AccessUnitInfos::output> bufferMetadata =
2604                         std::static_pointer_cast<const C2AccessUnitInfos::output>(
2605                         c2Buffer->getInfo(C2AccessUnitInfos::output::PARAM_TYPE));
2606                 if (bufferMetadata && bufferMetadata->flexCount() > 0) {
2607                     uint32_t flag = 0;
2608                     std::vector<AccessUnitInfo> accessUnitInfos;
2609                     for (int nMeta = 0; nMeta < bufferMetadata->flexCount(); nMeta++) {
2610                         const C2AccessUnitInfosStruct &bufferMetadataStruct =
2611                                 bufferMetadata->m.values[nMeta];
2612                         flag = convertFlags(bufferMetadataStruct.flags, false);
2613                         accessUnitInfos.emplace_back(flag,
2614                                 static_cast<size_t>(bufferMetadataStruct.size),
2615                                 static_cast<size_t>(bufferMetadataStruct.timestamp));
2616                     }
2617                     sp<WrapperObject<std::vector<AccessUnitInfo>>> obj{
2618                         new WrapperObject<std::vector<AccessUnitInfo>>{accessUnitInfos}};
2619                     outBuffer->meta()->setObject("accessUnitInfo", obj);
2620                 }
2621             }
2622             mCallback->onOutputBufferAvailable(index, outBuffer);
2623             break;
2624         }
2625         case OutputBuffers::REALLOCATE:
2626             if (++reallocTryNum > kMaxReallocTry) {
2627                 output.unlock();
2628                 ALOGE("[%s] sendOutputBuffers: tried %d realloc and failed",
2629                           mName, kMaxReallocTry);
2630                 mCCodecCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL);
2631                 return;
2632             }
2633             if (!output->buffers->isArrayMode()) {
2634                 output->buffers =
2635                     output->buffers->toArrayMode(output->numSlots);
2636             }
2637             static_cast<OutputBuffersArray*>(output->buffers.get())->
2638                     realloc(c2Buffer);
2639             output.unlock();
2640             mCCodecCallback->onOutputBuffersChanged();
2641             break;
2642         case OutputBuffers::RETRY:
2643             ALOGV("[%s] sendOutputBuffers: unable to register output buffer",
2644                   mName);
2645             return;
2646         default:
2647             LOG_ALWAYS_FATAL("[%s] sendOutputBuffers: "
2648                     "corrupted BufferAction value (%d) "
2649                     "returned from popFromStashAndRegister.",
2650                     mName, int(action));
2651             return;
2652         }
2653     }
2654 }
2655 
setSurface(const sp<Surface> & newSurface,uint32_t generation,bool pushBlankBuffer)2656 status_t CCodecBufferChannel::setSurface(const sp<Surface> &newSurface,
2657                                          uint32_t generation, bool pushBlankBuffer) {
2658     sp<IGraphicBufferProducer> producer;
2659     int maxDequeueCount;
2660     sp<Surface> oldSurface;
2661     {
2662         Mutexed<OutputSurface>::Locked outputSurface(mOutputSurface);
2663         maxDequeueCount = outputSurface->maxDequeueBuffers;
2664         oldSurface = outputSurface->surface;
2665     }
2666     if (newSurface) {
2667         newSurface->setScalingMode(NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
2668         newSurface->setDequeueTimeout(kDequeueTimeoutNs);
2669         newSurface->setMaxDequeuedBufferCount(maxDequeueCount);
2670         producer = newSurface->getIGraphicBufferProducer();
2671     } else {
2672         ALOGE("[%s] setting output surface to null", mName);
2673         return INVALID_OPERATION;
2674     }
2675 
2676     std::shared_ptr<Codec2Client::Configurable> outputPoolIntf;
2677     C2BlockPool::local_id_t outputPoolId;
2678     {
2679         Mutexed<BlockPools>::Locked pools(mBlockPools);
2680         outputPoolId = pools->outputPoolId;
2681         outputPoolIntf = pools->outputPoolIntf;
2682     }
2683 
2684     if (outputPoolIntf) {
2685         if (mComponent->setOutputSurface(
2686                 outputPoolId,
2687                 producer,
2688                 generation,
2689                 maxDequeueCount) != C2_OK) {
2690             ALOGI("[%s] setSurface: component setOutputSurface failed", mName);
2691             return INVALID_OPERATION;
2692         }
2693     }
2694 
2695     {
2696         Mutexed<OutputSurface>::Locked output(mOutputSurface);
2697         output->surface = newSurface;
2698         output->generation = generation;
2699         initializeFrameTrackingFor(static_cast<ANativeWindow *>(newSurface.get()));
2700     }
2701 
2702     if (oldSurface && pushBlankBuffer) {
2703         // When ReleaseSurface was set from MediaCodec,
2704         // pushing a blank buffer at the end might be necessary.
2705         sp<ANativeWindow> anw = static_cast<ANativeWindow *>(oldSurface.get());
2706         if (anw) {
2707             pushBlankBuffersToNativeWindow(anw.get());
2708         }
2709     }
2710 
2711     return OK;
2712 }
2713 
elapsed()2714 PipelineWatcher::Clock::duration CCodecBufferChannel::elapsed() {
2715     // Otherwise, component may have stalled work due to input starvation up to
2716     // the sum of the delay in the pipeline.
2717     // TODO(b/231253301): When client pushed EOS, the pipeline could have less
2718     //                    number of frames.
2719     size_t n = 0;
2720     size_t outputDelay = mOutput.lock()->outputDelay;
2721     {
2722         Mutexed<Input>::Locked input(mInput);
2723         n = input->inputDelay + input->pipelineDelay + outputDelay;
2724     }
2725     return mPipelineWatcher.lock()->elapsed(PipelineWatcher::Clock::now(), n);
2726 }
2727 
setMetaMode(MetaMode mode)2728 void CCodecBufferChannel::setMetaMode(MetaMode mode) {
2729     mMetaMode = mode;
2730 }
2731 
setCrypto(const sp<ICrypto> & crypto)2732 void CCodecBufferChannel::setCrypto(const sp<ICrypto> &crypto) {
2733     if (mCrypto != nullptr) {
2734         for (std::pair<wp<HidlMemory>, int32_t> entry : mHeapSeqNumMap) {
2735             mCrypto->unsetHeap(entry.second);
2736         }
2737         mHeapSeqNumMap.clear();
2738         if (mHeapSeqNum >= 0) {
2739             mCrypto->unsetHeap(mHeapSeqNum);
2740             mHeapSeqNum = -1;
2741         }
2742     }
2743     mCrypto = crypto;
2744 }
2745 
setDescrambler(const sp<IDescrambler> & descrambler)2746 void CCodecBufferChannel::setDescrambler(const sp<IDescrambler> &descrambler) {
2747     mDescrambler = descrambler;
2748 }
2749 
getBuffersPixelFormat(bool isEncoder)2750 uint32_t CCodecBufferChannel::getBuffersPixelFormat(bool isEncoder) {
2751     if (isEncoder) {
2752         return getInputBuffersPixelFormat();
2753     } else {
2754         return getOutputBuffersPixelFormat();
2755     }
2756 }
2757 
getInputBuffersPixelFormat()2758 uint32_t CCodecBufferChannel::getInputBuffersPixelFormat() {
2759     Mutexed<Input>::Locked input(mInput);
2760     if (input->buffers == nullptr) {
2761         return PIXEL_FORMAT_UNKNOWN;
2762     }
2763     return input->buffers->getPixelFormatIfApplicable();
2764 }
2765 
getOutputBuffersPixelFormat()2766 uint32_t CCodecBufferChannel::getOutputBuffersPixelFormat() {
2767     Mutexed<Output>::Locked output(mOutput);
2768     if (output->buffers == nullptr) {
2769         return PIXEL_FORMAT_UNKNOWN;
2770     }
2771     return output->buffers->getPixelFormatIfApplicable();
2772 }
2773 
resetBuffersPixelFormat(bool isEncoder)2774 void CCodecBufferChannel::resetBuffersPixelFormat(bool isEncoder) {
2775     if (isEncoder) {
2776         Mutexed<Input>::Locked input(mInput);
2777         if (input->buffers == nullptr) {
2778             return;
2779         }
2780         input->buffers->resetPixelFormatIfApplicable();
2781     } else {
2782         Mutexed<Output>::Locked output(mOutput);
2783         if (output->buffers == nullptr) {
2784             return;
2785         }
2786         output->buffers->resetPixelFormatIfApplicable();
2787     }
2788 }
2789 
setInfoBuffer(const std::shared_ptr<C2InfoBuffer> & buffer)2790 void CCodecBufferChannel::setInfoBuffer(const std::shared_ptr<C2InfoBuffer> &buffer) {
2791     if (mInputSurface == nullptr) {
2792         mInfoBuffers.push_back(buffer);
2793     } else {
2794         std::list<std::unique_ptr<C2Work>> items;
2795         std::unique_ptr<C2Work> work(new C2Work);
2796         work->input.infoBuffers.emplace_back(*buffer);
2797         work->worklets.emplace_back(new C2Worklet);
2798         items.push_back(std::move(work));
2799         c2_status_t err = mComponent->queue(&items);
2800     }
2801 }
2802 
toStatusT(c2_status_t c2s,c2_operation_t c2op)2803 status_t toStatusT(c2_status_t c2s, c2_operation_t c2op) {
2804     // C2_OK is always translated to OK.
2805     if (c2s == C2_OK) {
2806         return OK;
2807     }
2808 
2809     // Operation-dependent translation
2810     // TODO: Add as necessary
2811     switch (c2op) {
2812     case C2_OPERATION_Component_start:
2813         switch (c2s) {
2814         case C2_NO_MEMORY:
2815             return NO_MEMORY;
2816         default:
2817             return UNKNOWN_ERROR;
2818         }
2819     default:
2820         break;
2821     }
2822 
2823     // Backup operation-agnostic translation
2824     switch (c2s) {
2825     case C2_BAD_INDEX:
2826         return BAD_INDEX;
2827     case C2_BAD_VALUE:
2828         return BAD_VALUE;
2829     case C2_BLOCKING:
2830         return WOULD_BLOCK;
2831     case C2_DUPLICATE:
2832         return ALREADY_EXISTS;
2833     case C2_NO_INIT:
2834         return NO_INIT;
2835     case C2_NO_MEMORY:
2836         return NO_MEMORY;
2837     case C2_NOT_FOUND:
2838         return NAME_NOT_FOUND;
2839     case C2_TIMED_OUT:
2840         return TIMED_OUT;
2841     case C2_BAD_STATE:
2842     case C2_CANCELED:
2843     case C2_CANNOT_DO:
2844     case C2_CORRUPTED:
2845     case C2_OMITTED:
2846     case C2_REFUSED:
2847         return UNKNOWN_ERROR;
2848     default:
2849         return -static_cast<status_t>(c2s);
2850     }
2851 }
2852 
2853 }  // namespace android
2854