• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #define LOG_TAG "CCodecBufferChannel"
19 #include <utils/Log.h>
20 
21 #include <algorithm>
22 #include <list>
23 #include <numeric>
24 
25 #include <C2AllocatorGralloc.h>
26 #include <C2PlatformSupport.h>
27 #include <C2BlockInternal.h>
28 #include <C2Config.h>
29 #include <C2Debug.h>
30 
31 #include <android/hardware/cas/native/1.0/IDescrambler.h>
32 #include <android/hardware/drm/1.0/types.h>
33 #include <android-base/properties.h>
34 #include <android-base/stringprintf.h>
35 #include <binder/MemoryBase.h>
36 #include <binder/MemoryDealer.h>
37 #include <cutils/properties.h>
38 #include <gui/Surface.h>
39 #include <hidlmemory/FrameworkUtils.h>
40 #include <media/openmax/OMX_Core.h>
41 #include <media/stagefright/foundation/ABuffer.h>
42 #include <media/stagefright/foundation/ALookup.h>
43 #include <media/stagefright/foundation/AMessage.h>
44 #include <media/stagefright/foundation/AUtils.h>
45 #include <media/stagefright/foundation/hexdump.h>
46 #include <media/stagefright/MediaCodec.h>
47 #include <media/stagefright/MediaCodecConstants.h>
48 #include <media/stagefright/SkipCutBuffer.h>
49 #include <media/MediaCodecBuffer.h>
50 #include <mediadrm/ICrypto.h>
51 #include <system/window.h>
52 
53 #include "CCodecBufferChannel.h"
54 #include "Codec2Buffer.h"
55 
56 namespace android {
57 
58 using android::base::StringPrintf;
59 using hardware::hidl_handle;
60 using hardware::hidl_string;
61 using hardware::hidl_vec;
62 using hardware::fromHeap;
63 using hardware::HidlMemory;
64 
65 using namespace hardware::cas::V1_0;
66 using namespace hardware::cas::native::V1_0;
67 
68 using CasStatus = hardware::cas::V1_0::Status;
69 using DrmBufferType = hardware::drm::V1_0::BufferType;
70 
71 namespace {
72 
73 constexpr size_t kSmoothnessFactor = 4;
74 constexpr size_t kRenderingDepth = 3;
75 
76 // This is for keeping IGBP's buffer dropping logic in legacy mode other
77 // than making it non-blocking. Do not change this value.
78 const static size_t kDequeueTimeoutNs = 0;
79 
80 }  // namespace
81 
QueueGuard(CCodecBufferChannel::QueueSync & sync)82 CCodecBufferChannel::QueueGuard::QueueGuard(
83         CCodecBufferChannel::QueueSync &sync) : mSync(sync) {
84     Mutex::Autolock l(mSync.mGuardLock);
85     // At this point it's guaranteed that mSync is not under state transition,
86     // as we are holding its mutex.
87 
88     Mutexed<CCodecBufferChannel::QueueSync::Counter>::Locked count(mSync.mCount);
89     if (count->value == -1) {
90         mRunning = false;
91     } else {
92         ++count->value;
93         mRunning = true;
94     }
95 }
96 
~QueueGuard()97 CCodecBufferChannel::QueueGuard::~QueueGuard() {
98     if (mRunning) {
99         // We are not holding mGuardLock at this point so that QueueSync::stop() can
100         // keep holding the lock until mCount reaches zero.
101         Mutexed<CCodecBufferChannel::QueueSync::Counter>::Locked count(mSync.mCount);
102         --count->value;
103         count->cond.broadcast();
104     }
105 }
106 
start()107 void CCodecBufferChannel::QueueSync::start() {
108     Mutex::Autolock l(mGuardLock);
109     // If stopped, it goes to running state; otherwise no-op.
110     Mutexed<Counter>::Locked count(mCount);
111     if (count->value == -1) {
112         count->value = 0;
113     }
114 }
115 
stop()116 void CCodecBufferChannel::QueueSync::stop() {
117     Mutex::Autolock l(mGuardLock);
118     Mutexed<Counter>::Locked count(mCount);
119     if (count->value == -1) {
120         // no-op
121         return;
122     }
123     // Holding mGuardLock here blocks creation of additional QueueGuard objects, so
124     // mCount can only decrement. In other words, threads that acquired the lock
125     // are allowed to finish execution but additional threads trying to acquire
126     // the lock at this point will block, and then get QueueGuard at STOPPED
127     // state.
128     while (count->value != 0) {
129         count.waitForCondition(count->cond);
130     }
131     count->value = -1;
132 }
133 
134 // Input
135 
Input()136 CCodecBufferChannel::Input::Input() : extraBuffers("extra") {}
137 
138 // CCodecBufferChannel
139 
CCodecBufferChannel(const std::shared_ptr<CCodecCallback> & callback)140 CCodecBufferChannel::CCodecBufferChannel(
141         const std::shared_ptr<CCodecCallback> &callback)
142     : mHeapSeqNum(-1),
143       mCCodecCallback(callback),
144       mFrameIndex(0u),
145       mFirstValidFrameIndex(0u),
146       mMetaMode(MODE_NONE),
147       mInputMetEos(false),
148       mSendEncryptedInfoBuffer(false) {
149     mOutputSurface.lock()->maxDequeueBuffers = kSmoothnessFactor + kRenderingDepth;
150     {
151         Mutexed<Input>::Locked input(mInput);
152         input->buffers.reset(new DummyInputBuffers(""));
153         input->extraBuffers.flush();
154         input->inputDelay = 0u;
155         input->pipelineDelay = 0u;
156         input->numSlots = kSmoothnessFactor;
157         input->numExtraSlots = 0u;
158     }
159     {
160         Mutexed<Output>::Locked output(mOutput);
161         output->outputDelay = 0u;
162         output->numSlots = kSmoothnessFactor;
163     }
164     {
165         Mutexed<BlockPools>::Locked pools(mBlockPools);
166         pools->outputPoolId = C2BlockPool::BASIC_LINEAR;
167     }
168 }
169 
~CCodecBufferChannel()170 CCodecBufferChannel::~CCodecBufferChannel() {
171     if (mCrypto != nullptr && mHeapSeqNum >= 0) {
172         mCrypto->unsetHeap(mHeapSeqNum);
173     }
174 }
175 
setComponent(const std::shared_ptr<Codec2Client::Component> & component)176 void CCodecBufferChannel::setComponent(
177         const std::shared_ptr<Codec2Client::Component> &component) {
178     mComponent = component;
179     mComponentName = component->getName() + StringPrintf("#%d", int(uintptr_t(component.get()) % 997));
180     mName = mComponentName.c_str();
181 }
182 
setInputSurface(const std::shared_ptr<InputSurfaceWrapper> & surface)183 status_t CCodecBufferChannel::setInputSurface(
184         const std::shared_ptr<InputSurfaceWrapper> &surface) {
185     ALOGV("[%s] setInputSurface", mName);
186     mInputSurface = surface;
187     return mInputSurface->connect(mComponent);
188 }
189 
signalEndOfInputStream()190 status_t CCodecBufferChannel::signalEndOfInputStream() {
191     if (mInputSurface == nullptr) {
192         return INVALID_OPERATION;
193     }
194     return mInputSurface->signalEndOfInputStream();
195 }
196 
queueInputBufferInternal(sp<MediaCodecBuffer> buffer,std::shared_ptr<C2LinearBlock> encryptedBlock,size_t blockSize)197 status_t CCodecBufferChannel::queueInputBufferInternal(
198         sp<MediaCodecBuffer> buffer,
199         std::shared_ptr<C2LinearBlock> encryptedBlock,
200         size_t blockSize) {
201     int64_t timeUs;
202     CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
203 
204     if (mInputMetEos) {
205         ALOGD("[%s] buffers after EOS ignored (%lld us)", mName, (long long)timeUs);
206         return OK;
207     }
208 
209     int32_t flags = 0;
210     int32_t tmp = 0;
211     bool eos = false;
212     bool tunnelFirstFrame = false;
213     if (buffer->meta()->findInt32("eos", &tmp) && tmp) {
214         eos = true;
215         mInputMetEos = true;
216         ALOGV("[%s] input EOS", mName);
217     }
218     if (buffer->meta()->findInt32("csd", &tmp) && tmp) {
219         flags |= C2FrameData::FLAG_CODEC_CONFIG;
220     }
221     if (buffer->meta()->findInt32("tunnel-first-frame", &tmp) && tmp) {
222         tunnelFirstFrame = true;
223     }
224     ALOGV("[%s] queueInputBuffer: buffer->size() = %zu", mName, buffer->size());
225     std::list<std::unique_ptr<C2Work>> items;
226     std::unique_ptr<C2Work> work(new C2Work);
227     work->input.ordinal.timestamp = timeUs;
228     work->input.ordinal.frameIndex = mFrameIndex++;
229     // WORKAROUND: until codecs support handling work after EOS and max output sizing, use timestamp
230     // manipulation to achieve image encoding via video codec, and to constrain encoded output.
231     // Keep client timestamp in customOrdinal
232     work->input.ordinal.customOrdinal = timeUs;
233     work->input.buffers.clear();
234 
235     sp<Codec2Buffer> copy;
236     bool usesFrameReassembler = false;
237 
238     if (buffer->size() > 0u) {
239         Mutexed<Input>::Locked input(mInput);
240         std::shared_ptr<C2Buffer> c2buffer;
241         if (!input->buffers->releaseBuffer(buffer, &c2buffer, false)) {
242             return -ENOENT;
243         }
244         // TODO: we want to delay copying buffers.
245         if (input->extraBuffers.numComponentBuffers() < input->numExtraSlots) {
246             copy = input->buffers->cloneAndReleaseBuffer(buffer);
247             if (copy != nullptr) {
248                 (void)input->extraBuffers.assignSlot(copy);
249                 if (!input->extraBuffers.releaseSlot(copy, &c2buffer, false)) {
250                     return UNKNOWN_ERROR;
251                 }
252                 bool released = input->buffers->releaseBuffer(buffer, nullptr, true);
253                 ALOGV("[%s] queueInputBuffer: buffer copied; %sreleased",
254                       mName, released ? "" : "not ");
255                 buffer.clear();
256             } else {
257                 ALOGW("[%s] queueInputBuffer: failed to copy a buffer; this may cause input "
258                       "buffer starvation on component.", mName);
259             }
260         }
261         if (input->frameReassembler) {
262             usesFrameReassembler = true;
263             input->frameReassembler.process(buffer, &items);
264         } else {
265             int32_t cvo = 0;
266             if (buffer->meta()->findInt32("cvo", &cvo)) {
267                 int32_t rotation = cvo % 360;
268                 // change rotation to counter-clock wise.
269                 rotation = ((rotation <= 0) ? 0 : 360) - rotation;
270 
271                 Mutexed<OutputSurface>::Locked output(mOutputSurface);
272                 uint64_t frameIndex = work->input.ordinal.frameIndex.peeku();
273                 output->rotation[frameIndex] = rotation;
274             }
275             work->input.buffers.push_back(c2buffer);
276             if (encryptedBlock) {
277                 work->input.infoBuffers.emplace_back(C2InfoBuffer::CreateLinearBuffer(
278                         kParamIndexEncryptedBuffer,
279                         encryptedBlock->share(0, blockSize, C2Fence())));
280             }
281         }
282     } else if (eos) {
283         flags |= C2FrameData::FLAG_END_OF_STREAM;
284     }
285     if (usesFrameReassembler) {
286         if (!items.empty()) {
287             items.front()->input.configUpdate = std::move(mParamsToBeSet);
288             mFrameIndex = (items.back()->input.ordinal.frameIndex + 1).peek();
289         }
290     } else {
291         work->input.flags = (C2FrameData::flags_t)flags;
292         // TODO: fill info's
293 
294         work->input.configUpdate = std::move(mParamsToBeSet);
295         if (tunnelFirstFrame) {
296             C2StreamTunnelHoldRender::input tunnelHoldRender{
297                 0u /* stream */,
298                 C2_TRUE /* value */
299             };
300             work->input.configUpdate.push_back(C2Param::Copy(tunnelHoldRender));
301         }
302         work->worklets.clear();
303         work->worklets.emplace_back(new C2Worklet);
304 
305         items.push_back(std::move(work));
306 
307         eos = eos && buffer->size() > 0u;
308     }
309     if (eos) {
310         work.reset(new C2Work);
311         work->input.ordinal.timestamp = timeUs;
312         work->input.ordinal.frameIndex = mFrameIndex++;
313         // WORKAROUND: keep client timestamp in customOrdinal
314         work->input.ordinal.customOrdinal = timeUs;
315         work->input.buffers.clear();
316         work->input.flags = C2FrameData::FLAG_END_OF_STREAM;
317         work->worklets.emplace_back(new C2Worklet);
318         items.push_back(std::move(work));
319     }
320     c2_status_t err = C2_OK;
321     if (!items.empty()) {
322         {
323             Mutexed<PipelineWatcher>::Locked watcher(mPipelineWatcher);
324             PipelineWatcher::Clock::time_point now = PipelineWatcher::Clock::now();
325             for (const std::unique_ptr<C2Work> &work : items) {
326                 watcher->onWorkQueued(
327                         work->input.ordinal.frameIndex.peeku(),
328                         std::vector(work->input.buffers),
329                         now);
330             }
331         }
332         err = mComponent->queue(&items);
333     }
334     if (err != C2_OK) {
335         Mutexed<PipelineWatcher>::Locked watcher(mPipelineWatcher);
336         for (const std::unique_ptr<C2Work> &work : items) {
337             watcher->onWorkDone(work->input.ordinal.frameIndex.peeku());
338         }
339     } else {
340         Mutexed<Input>::Locked input(mInput);
341         bool released = false;
342         if (buffer) {
343             released = input->buffers->releaseBuffer(buffer, nullptr, true);
344         } else if (copy) {
345             released = input->extraBuffers.releaseSlot(copy, nullptr, true);
346         }
347         ALOGV("[%s] queueInputBuffer: buffer%s %sreleased",
348               mName, (buffer == nullptr) ? "(copy)" : "", released ? "" : "not ");
349     }
350 
351     feedInputBufferIfAvailableInternal();
352     return err;
353 }
354 
setParameters(std::vector<std::unique_ptr<C2Param>> & params)355 status_t CCodecBufferChannel::setParameters(std::vector<std::unique_ptr<C2Param>> &params) {
356     QueueGuard guard(mSync);
357     if (!guard.isRunning()) {
358         ALOGD("[%s] setParameters is only supported in the running state.", mName);
359         return -ENOSYS;
360     }
361     mParamsToBeSet.insert(mParamsToBeSet.end(),
362                           std::make_move_iterator(params.begin()),
363                           std::make_move_iterator(params.end()));
364     params.clear();
365     return OK;
366 }
367 
attachBuffer(const std::shared_ptr<C2Buffer> & c2Buffer,const sp<MediaCodecBuffer> & buffer)368 status_t CCodecBufferChannel::attachBuffer(
369         const std::shared_ptr<C2Buffer> &c2Buffer,
370         const sp<MediaCodecBuffer> &buffer) {
371     if (!buffer->copy(c2Buffer)) {
372         return -ENOSYS;
373     }
374     return OK;
375 }
376 
ensureDecryptDestination(size_t size)377 void CCodecBufferChannel::ensureDecryptDestination(size_t size) {
378     if (!mDecryptDestination || mDecryptDestination->size() < size) {
379         sp<IMemoryHeap> heap{new MemoryHeapBase(size * 2)};
380         if (mDecryptDestination && mCrypto && mHeapSeqNum >= 0) {
381             mCrypto->unsetHeap(mHeapSeqNum);
382         }
383         mDecryptDestination = new MemoryBase(heap, 0, size * 2);
384         if (mCrypto) {
385             mHeapSeqNum = mCrypto->setHeap(hardware::fromHeap(heap));
386         }
387     }
388 }
389 
getHeapSeqNum(const sp<HidlMemory> & memory)390 int32_t CCodecBufferChannel::getHeapSeqNum(const sp<HidlMemory> &memory) {
391     CHECK(mCrypto);
392     auto it = mHeapSeqNumMap.find(memory);
393     int32_t heapSeqNum = -1;
394     if (it == mHeapSeqNumMap.end()) {
395         heapSeqNum = mCrypto->setHeap(memory);
396         mHeapSeqNumMap.emplace(memory, heapSeqNum);
397     } else {
398         heapSeqNum = it->second;
399     }
400     return heapSeqNum;
401 }
402 
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)403 status_t CCodecBufferChannel::attachEncryptedBuffer(
404         const sp<hardware::HidlMemory> &memory,
405         bool secure,
406         const uint8_t *key,
407         const uint8_t *iv,
408         CryptoPlugin::Mode mode,
409         CryptoPlugin::Pattern pattern,
410         size_t offset,
411         const CryptoPlugin::SubSample *subSamples,
412         size_t numSubSamples,
413         const sp<MediaCodecBuffer> &buffer) {
414     static const C2MemoryUsage kSecureUsage{C2MemoryUsage::READ_PROTECTED, 0};
415     static const C2MemoryUsage kDefaultReadWriteUsage{
416         C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE};
417 
418     size_t size = 0;
419     for (size_t i = 0; i < numSubSamples; ++i) {
420         size += subSamples[i].mNumBytesOfClearData + subSamples[i].mNumBytesOfEncryptedData;
421     }
422     std::shared_ptr<C2BlockPool> pool = mBlockPools.lock()->inputPool;
423     std::shared_ptr<C2LinearBlock> block;
424     c2_status_t err = pool->fetchLinearBlock(
425             size,
426             secure ? kSecureUsage : kDefaultReadWriteUsage,
427             &block);
428     if (err != C2_OK) {
429         return NO_MEMORY;
430     }
431     if (!secure) {
432         ensureDecryptDestination(size);
433     }
434     ssize_t result = -1;
435     ssize_t codecDataOffset = 0;
436     if (mCrypto) {
437         AString errorDetailMsg;
438         int32_t heapSeqNum = getHeapSeqNum(memory);
439         hardware::drm::V1_0::SharedBuffer src{(uint32_t)heapSeqNum, offset, size};
440         hardware::drm::V1_0::DestinationBuffer dst;
441         if (secure) {
442             dst.type = DrmBufferType::NATIVE_HANDLE;
443             dst.secureMemory = hardware::hidl_handle(block->handle());
444         } else {
445             dst.type = DrmBufferType::SHARED_MEMORY;
446             IMemoryToSharedBuffer(
447                     mDecryptDestination, mHeapSeqNum, &dst.nonsecureMemory);
448         }
449         result = mCrypto->decrypt(
450                 key, iv, mode, pattern, src, 0, subSamples, numSubSamples,
451                 dst, &errorDetailMsg);
452         if (result < 0) {
453             return result;
454         }
455         if (dst.type == DrmBufferType::SHARED_MEMORY) {
456             C2WriteView view = block->map().get();
457             if (view.error() != C2_OK) {
458                 return false;
459             }
460             if (view.size() < result) {
461                 return false;
462             }
463             memcpy(view.data(), mDecryptDestination->unsecurePointer(), result);
464         }
465     } else {
466         // Here we cast CryptoPlugin::SubSample to hardware::cas::native::V1_0::SubSample
467         // directly, the structure definitions should match as checked in DescramblerImpl.cpp.
468         hidl_vec<SubSample> hidlSubSamples;
469         hidlSubSamples.setToExternal((SubSample *)subSamples, numSubSamples, false /*own*/);
470 
471         hardware::cas::native::V1_0::SharedBuffer src{*memory, offset, size};
472         hardware::cas::native::V1_0::DestinationBuffer dst;
473         if (secure) {
474             dst.type = BufferType::NATIVE_HANDLE;
475             dst.secureMemory = hardware::hidl_handle(block->handle());
476         } else {
477             dst.type = BufferType::SHARED_MEMORY;
478             dst.nonsecureMemory = src;
479         }
480 
481         CasStatus status = CasStatus::OK;
482         hidl_string detailedError;
483         ScramblingControl sctrl = ScramblingControl::UNSCRAMBLED;
484 
485         if (key != nullptr) {
486             sctrl = (ScramblingControl)key[0];
487             // Adjust for the PES offset
488             codecDataOffset = key[2] | (key[3] << 8);
489         }
490 
491         auto returnVoid = mDescrambler->descramble(
492                 sctrl,
493                 hidlSubSamples,
494                 src,
495                 0,
496                 dst,
497                 0,
498                 [&status, &result, &detailedError] (
499                         CasStatus _status, uint32_t _bytesWritten,
500                         const hidl_string& _detailedError) {
501                     status = _status;
502                     result = (ssize_t)_bytesWritten;
503                     detailedError = _detailedError;
504                 });
505 
506         if (!returnVoid.isOk() || status != CasStatus::OK || result < 0) {
507             ALOGI("[%s] descramble failed, trans=%s, status=%d, result=%zd",
508                     mName, returnVoid.description().c_str(), status, result);
509             return UNKNOWN_ERROR;
510         }
511 
512         if (result < codecDataOffset) {
513             ALOGD("invalid codec data offset: %zd, result %zd", codecDataOffset, result);
514             return BAD_VALUE;
515         }
516     }
517     if (!secure) {
518         C2WriteView view = block->map().get();
519         if (view.error() != C2_OK) {
520             return UNKNOWN_ERROR;
521         }
522         if (view.size() < result) {
523             return UNKNOWN_ERROR;
524         }
525         memcpy(view.data(), mDecryptDestination->unsecurePointer(), result);
526     }
527     std::shared_ptr<C2Buffer> c2Buffer{C2Buffer::CreateLinearBuffer(
528             block->share(codecDataOffset, result - codecDataOffset, C2Fence{}))};
529     if (!buffer->copy(c2Buffer)) {
530         return -ENOSYS;
531     }
532     return OK;
533 }
534 
queueInputBuffer(const sp<MediaCodecBuffer> & buffer)535 status_t CCodecBufferChannel::queueInputBuffer(const sp<MediaCodecBuffer> &buffer) {
536     QueueGuard guard(mSync);
537     if (!guard.isRunning()) {
538         ALOGD("[%s] No more buffers should be queued at current state.", mName);
539         return -ENOSYS;
540     }
541     return queueInputBufferInternal(buffer);
542 }
543 
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)544 status_t CCodecBufferChannel::queueSecureInputBuffer(
545         const sp<MediaCodecBuffer> &buffer, bool secure, const uint8_t *key,
546         const uint8_t *iv, CryptoPlugin::Mode mode, CryptoPlugin::Pattern pattern,
547         const CryptoPlugin::SubSample *subSamples, size_t numSubSamples,
548         AString *errorDetailMsg) {
549     QueueGuard guard(mSync);
550     if (!guard.isRunning()) {
551         ALOGD("[%s] No more buffers should be queued at current state.", mName);
552         return -ENOSYS;
553     }
554 
555     if (!hasCryptoOrDescrambler()) {
556         return -ENOSYS;
557     }
558     sp<EncryptedLinearBlockBuffer> encryptedBuffer((EncryptedLinearBlockBuffer *)buffer.get());
559 
560     std::shared_ptr<C2LinearBlock> block;
561     size_t allocSize = buffer->size();
562     size_t bufferSize = 0;
563     c2_status_t blockRes = C2_OK;
564     bool copied = false;
565     if (mSendEncryptedInfoBuffer) {
566         static const C2MemoryUsage kDefaultReadWriteUsage{
567             C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE};
568         constexpr int kAllocGranule0 = 1024 * 64;
569         constexpr int kAllocGranule1 = 1024 * 1024;
570         std::shared_ptr<C2BlockPool> pool = mBlockPools.lock()->inputPool;
571         // round up encrypted sizes to limit fragmentation and encourage buffer reuse
572         if (allocSize <= kAllocGranule1) {
573             bufferSize = align(allocSize, kAllocGranule0);
574         } else {
575             bufferSize = align(allocSize, kAllocGranule1);
576         }
577         blockRes = pool->fetchLinearBlock(
578                 bufferSize, kDefaultReadWriteUsage, &block);
579 
580         if (blockRes == C2_OK) {
581             C2WriteView view = block->map().get();
582             if (view.error() == C2_OK && view.size() == bufferSize) {
583                 copied = true;
584                 // TODO: only copy clear sections
585                 memcpy(view.data(), buffer->data(), allocSize);
586             }
587         }
588     }
589 
590     if (!copied) {
591         block.reset();
592     }
593 
594     ssize_t result = -1;
595     ssize_t codecDataOffset = 0;
596     if (numSubSamples == 1
597             && subSamples[0].mNumBytesOfClearData == 0
598             && subSamples[0].mNumBytesOfEncryptedData == 0) {
599         // We don't need to go through crypto or descrambler if the input is empty.
600         result = 0;
601     } else if (mCrypto != nullptr) {
602         hardware::drm::V1_0::DestinationBuffer destination;
603         if (secure) {
604             destination.type = DrmBufferType::NATIVE_HANDLE;
605             destination.secureMemory = hidl_handle(encryptedBuffer->handle());
606         } else {
607             destination.type = DrmBufferType::SHARED_MEMORY;
608             IMemoryToSharedBuffer(
609                     mDecryptDestination, mHeapSeqNum, &destination.nonsecureMemory);
610         }
611         hardware::drm::V1_0::SharedBuffer source;
612         encryptedBuffer->fillSourceBuffer(&source);
613         result = mCrypto->decrypt(
614                 key, iv, mode, pattern, source, buffer->offset(),
615                 subSamples, numSubSamples, destination, errorDetailMsg);
616         if (result < 0) {
617             ALOGI("[%s] decrypt failed: result=%zd", mName, result);
618             return result;
619         }
620         if (destination.type == DrmBufferType::SHARED_MEMORY) {
621             encryptedBuffer->copyDecryptedContent(mDecryptDestination, result);
622         }
623     } else {
624         // Here we cast CryptoPlugin::SubSample to hardware::cas::native::V1_0::SubSample
625         // directly, the structure definitions should match as checked in DescramblerImpl.cpp.
626         hidl_vec<SubSample> hidlSubSamples;
627         hidlSubSamples.setToExternal((SubSample *)subSamples, numSubSamples, false /*own*/);
628 
629         hardware::cas::native::V1_0::SharedBuffer srcBuffer;
630         encryptedBuffer->fillSourceBuffer(&srcBuffer);
631 
632         DestinationBuffer dstBuffer;
633         if (secure) {
634             dstBuffer.type = BufferType::NATIVE_HANDLE;
635             dstBuffer.secureMemory = hidl_handle(encryptedBuffer->handle());
636         } else {
637             dstBuffer.type = BufferType::SHARED_MEMORY;
638             dstBuffer.nonsecureMemory = srcBuffer;
639         }
640 
641         CasStatus status = CasStatus::OK;
642         hidl_string detailedError;
643         ScramblingControl sctrl = ScramblingControl::UNSCRAMBLED;
644 
645         if (key != nullptr) {
646             sctrl = (ScramblingControl)key[0];
647             // Adjust for the PES offset
648             codecDataOffset = key[2] | (key[3] << 8);
649         }
650 
651         auto returnVoid = mDescrambler->descramble(
652                 sctrl,
653                 hidlSubSamples,
654                 srcBuffer,
655                 0,
656                 dstBuffer,
657                 0,
658                 [&status, &result, &detailedError] (
659                         CasStatus _status, uint32_t _bytesWritten,
660                         const hidl_string& _detailedError) {
661                     status = _status;
662                     result = (ssize_t)_bytesWritten;
663                     detailedError = _detailedError;
664                 });
665 
666         if (!returnVoid.isOk() || status != CasStatus::OK || result < 0) {
667             ALOGI("[%s] descramble failed, trans=%s, status=%d, result=%zd",
668                     mName, returnVoid.description().c_str(), status, result);
669             return UNKNOWN_ERROR;
670         }
671 
672         if (result < codecDataOffset) {
673             ALOGD("invalid codec data offset: %zd, result %zd", codecDataOffset, result);
674             return BAD_VALUE;
675         }
676 
677         ALOGV("[%s] descramble succeeded, %zd bytes", mName, result);
678 
679         if (dstBuffer.type == BufferType::SHARED_MEMORY) {
680             encryptedBuffer->copyDecryptedContentFromMemory(result);
681         }
682     }
683 
684     buffer->setRange(codecDataOffset, result - codecDataOffset);
685 
686     return queueInputBufferInternal(buffer, block, bufferSize);
687 }
688 
feedInputBufferIfAvailable()689 void CCodecBufferChannel::feedInputBufferIfAvailable() {
690     QueueGuard guard(mSync);
691     if (!guard.isRunning()) {
692         ALOGV("[%s] We're not running --- no input buffer reported", mName);
693         return;
694     }
695     feedInputBufferIfAvailableInternal();
696 }
697 
feedInputBufferIfAvailableInternal()698 void CCodecBufferChannel::feedInputBufferIfAvailableInternal() {
699     if (mInputMetEos) {
700         return;
701     }
702     {
703         Mutexed<Output>::Locked output(mOutput);
704         if (!output->buffers ||
705                 output->buffers->hasPending() ||
706                 output->buffers->numActiveSlots() >= output->numSlots) {
707             return;
708         }
709     }
710     size_t numActiveSlots = 0;
711     while (!mPipelineWatcher.lock()->pipelineFull()) {
712         sp<MediaCodecBuffer> inBuffer;
713         size_t index;
714         {
715             Mutexed<Input>::Locked input(mInput);
716             numActiveSlots = input->buffers->numActiveSlots();
717             if (numActiveSlots >= input->numSlots) {
718                 break;
719             }
720             if (!input->buffers->requestNewBuffer(&index, &inBuffer)) {
721                 ALOGV("[%s] no new buffer available", mName);
722                 break;
723             }
724         }
725         ALOGV("[%s] new input index = %zu [%p]", mName, index, inBuffer.get());
726         mCallback->onInputBufferAvailable(index, inBuffer);
727     }
728     ALOGV("[%s] # active slots after feedInputBufferIfAvailable = %zu", mName, numActiveSlots);
729 }
730 
renderOutputBuffer(const sp<MediaCodecBuffer> & buffer,int64_t timestampNs)731 status_t CCodecBufferChannel::renderOutputBuffer(
732         const sp<MediaCodecBuffer> &buffer, int64_t timestampNs) {
733     ALOGV("[%s] renderOutputBuffer: %p", mName, buffer.get());
734     std::shared_ptr<C2Buffer> c2Buffer;
735     bool released = false;
736     {
737         Mutexed<Output>::Locked output(mOutput);
738         if (output->buffers) {
739             released = output->buffers->releaseBuffer(buffer, &c2Buffer);
740         }
741     }
742     // NOTE: some apps try to releaseOutputBuffer() with timestamp and/or render
743     //       set to true.
744     sendOutputBuffers();
745     // input buffer feeding may have been gated by pending output buffers
746     feedInputBufferIfAvailable();
747     if (!c2Buffer) {
748         if (released) {
749             std::call_once(mRenderWarningFlag, [this] {
750                 ALOGW("[%s] The app is calling releaseOutputBuffer() with "
751                       "timestamp or render=true with non-video buffers. Apps should "
752                       "call releaseOutputBuffer() with render=false for those.",
753                       mName);
754             });
755         }
756         return INVALID_OPERATION;
757     }
758 
759 #if 0
760     const std::vector<std::shared_ptr<const C2Info>> infoParams = c2Buffer->info();
761     ALOGV("[%s] queuing gfx buffer with %zu infos", mName, infoParams.size());
762     for (const std::shared_ptr<const C2Info> &info : infoParams) {
763         AString res;
764         for (size_t ix = 0; ix + 3 < info->size(); ix += 4) {
765             if (ix) res.append(", ");
766             res.append(*((int32_t*)info.get() + (ix / 4)));
767         }
768         ALOGV("  [%s]", res.c_str());
769     }
770 #endif
771     std::shared_ptr<const C2StreamRotationInfo::output> rotation =
772         std::static_pointer_cast<const C2StreamRotationInfo::output>(
773                 c2Buffer->getInfo(C2StreamRotationInfo::output::PARAM_TYPE));
774     bool flip = rotation && (rotation->flip & 1);
775     uint32_t quarters = ((rotation ? rotation->value : 0) / 90) & 3;
776 
777     {
778         Mutexed<OutputSurface>::Locked output(mOutputSurface);
779         if (output->surface == nullptr) {
780             ALOGI("[%s] cannot render buffer without surface", mName);
781             return OK;
782         }
783         int64_t frameIndex;
784         buffer->meta()->findInt64("frameIndex", &frameIndex);
785         if (output->rotation.count(frameIndex) != 0) {
786             auto it = output->rotation.find(frameIndex);
787             quarters = (it->second / 90) & 3;
788             output->rotation.erase(it);
789         }
790     }
791 
792     uint32_t transform = 0;
793     switch (quarters) {
794         case 0: // no rotation
795             transform = flip ? HAL_TRANSFORM_FLIP_H : 0;
796             break;
797         case 1: // 90 degrees counter-clockwise
798             transform = flip ? (HAL_TRANSFORM_FLIP_V | HAL_TRANSFORM_ROT_90)
799                     : HAL_TRANSFORM_ROT_270;
800             break;
801         case 2: // 180 degrees
802             transform = flip ? HAL_TRANSFORM_FLIP_V : HAL_TRANSFORM_ROT_180;
803             break;
804         case 3: // 90 degrees clockwise
805             transform = flip ? (HAL_TRANSFORM_FLIP_H | HAL_TRANSFORM_ROT_90)
806                     : HAL_TRANSFORM_ROT_90;
807             break;
808     }
809 
810     std::shared_ptr<const C2StreamSurfaceScalingInfo::output> surfaceScaling =
811         std::static_pointer_cast<const C2StreamSurfaceScalingInfo::output>(
812                 c2Buffer->getInfo(C2StreamSurfaceScalingInfo::output::PARAM_TYPE));
813     uint32_t videoScalingMode = NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW;
814     if (surfaceScaling) {
815         videoScalingMode = surfaceScaling->value;
816     }
817 
818     // Use dataspace from format as it has the default aspects already applied
819     android_dataspace_t dataSpace = HAL_DATASPACE_UNKNOWN; // this is 0
820     (void)buffer->format()->findInt32("android._dataspace", (int32_t *)&dataSpace);
821 
822     // HDR static info
823     std::shared_ptr<const C2StreamHdrStaticInfo::output> hdrStaticInfo =
824         std::static_pointer_cast<const C2StreamHdrStaticInfo::output>(
825                 c2Buffer->getInfo(C2StreamHdrStaticInfo::output::PARAM_TYPE));
826 
827     // HDR10 plus info
828     std::shared_ptr<const C2StreamHdr10PlusInfo::output> hdr10PlusInfo =
829         std::static_pointer_cast<const C2StreamHdr10PlusInfo::output>(
830                 c2Buffer->getInfo(C2StreamHdr10PlusInfo::output::PARAM_TYPE));
831     if (hdr10PlusInfo && hdr10PlusInfo->flexCount() == 0) {
832         hdr10PlusInfo.reset();
833     }
834 
835     std::vector<C2ConstGraphicBlock> blocks = c2Buffer->data().graphicBlocks();
836     if (blocks.size() != 1u) {
837         ALOGD("[%s] expected 1 graphic block, but got %zu", mName, blocks.size());
838         return UNKNOWN_ERROR;
839     }
840     const C2ConstGraphicBlock &block = blocks.front();
841 
842     // TODO: revisit this after C2Fence implementation.
843     android::IGraphicBufferProducer::QueueBufferInput qbi(
844             timestampNs,
845             false, // droppable
846             dataSpace,
847             Rect(blocks.front().crop().left,
848                  blocks.front().crop().top,
849                  blocks.front().crop().right(),
850                  blocks.front().crop().bottom()),
851             videoScalingMode,
852             transform,
853             Fence::NO_FENCE, 0);
854     if (hdrStaticInfo || hdr10PlusInfo) {
855         HdrMetadata hdr;
856         if (hdrStaticInfo) {
857             // If mastering max and min luminance fields are 0, do not use them.
858             // It indicates the value may not be present in the stream.
859             if (hdrStaticInfo->mastering.maxLuminance > 0.0f &&
860                 hdrStaticInfo->mastering.minLuminance > 0.0f) {
861                 struct android_smpte2086_metadata smpte2086_meta = {
862                     .displayPrimaryRed = {
863                         hdrStaticInfo->mastering.red.x, hdrStaticInfo->mastering.red.y
864                     },
865                     .displayPrimaryGreen = {
866                         hdrStaticInfo->mastering.green.x, hdrStaticInfo->mastering.green.y
867                     },
868                     .displayPrimaryBlue = {
869                         hdrStaticInfo->mastering.blue.x, hdrStaticInfo->mastering.blue.y
870                     },
871                     .whitePoint = {
872                         hdrStaticInfo->mastering.white.x, hdrStaticInfo->mastering.white.y
873                     },
874                     .maxLuminance = hdrStaticInfo->mastering.maxLuminance,
875                     .minLuminance = hdrStaticInfo->mastering.minLuminance,
876                 };
877                 hdr.validTypes |= HdrMetadata::SMPTE2086;
878                 hdr.smpte2086 = smpte2086_meta;
879             }
880             // If the content light level fields are 0, do not use them, it
881             // indicates the value may not be present in the stream.
882             if (hdrStaticInfo->maxCll > 0.0f && hdrStaticInfo->maxFall > 0.0f) {
883                 struct android_cta861_3_metadata cta861_meta = {
884                     .maxContentLightLevel = hdrStaticInfo->maxCll,
885                     .maxFrameAverageLightLevel = hdrStaticInfo->maxFall,
886                 };
887                 hdr.validTypes |= HdrMetadata::CTA861_3;
888                 hdr.cta8613 = cta861_meta;
889             }
890         }
891         if (hdr10PlusInfo) {
892             hdr.validTypes |= HdrMetadata::HDR10PLUS;
893             hdr.hdr10plus.assign(
894                     hdr10PlusInfo->m.value,
895                     hdr10PlusInfo->m.value + hdr10PlusInfo->flexCount());
896         }
897         qbi.setHdrMetadata(hdr);
898     }
899     // we don't have dirty regions
900     qbi.setSurfaceDamage(Region::INVALID_REGION);
901     android::IGraphicBufferProducer::QueueBufferOutput qbo;
902     status_t result = mComponent->queueToOutputSurface(block, qbi, &qbo);
903     if (result != OK) {
904         ALOGI("[%s] queueBuffer failed: %d", mName, result);
905         if (result == NO_INIT) {
906             mCCodecCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL);
907         }
908         return result;
909     }
910 
911     if(android::base::GetBoolProperty("debug.stagefright.fps", false)) {
912         ALOGD("[%s] queue buffer successful", mName);
913     } else {
914         ALOGV("[%s] queue buffer successful", mName);
915     }
916 
917     int64_t mediaTimeUs = 0;
918     (void)buffer->meta()->findInt64("timeUs", &mediaTimeUs);
919     mCCodecCallback->onOutputFramesRendered(mediaTimeUs, timestampNs);
920 
921     return OK;
922 }
923 
discardBuffer(const sp<MediaCodecBuffer> & buffer)924 status_t CCodecBufferChannel::discardBuffer(const sp<MediaCodecBuffer> &buffer) {
925     ALOGV("[%s] discardBuffer: %p", mName, buffer.get());
926     bool released = false;
927     {
928         Mutexed<Input>::Locked input(mInput);
929         if (input->buffers && input->buffers->releaseBuffer(buffer, nullptr, true)) {
930             released = true;
931         }
932     }
933     {
934         Mutexed<Output>::Locked output(mOutput);
935         if (output->buffers && output->buffers->releaseBuffer(buffer, nullptr)) {
936             released = true;
937         }
938     }
939     if (released) {
940         sendOutputBuffers();
941         feedInputBufferIfAvailable();
942     } else {
943         ALOGD("[%s] MediaCodec discarded an unknown buffer", mName);
944     }
945     return OK;
946 }
947 
getInputBufferArray(Vector<sp<MediaCodecBuffer>> * array)948 void CCodecBufferChannel::getInputBufferArray(Vector<sp<MediaCodecBuffer>> *array) {
949     array->clear();
950     Mutexed<Input>::Locked input(mInput);
951 
952     if (!input->buffers->isArrayMode()) {
953         input->buffers = input->buffers->toArrayMode(input->numSlots);
954     }
955 
956     input->buffers->getArray(array);
957 }
958 
getOutputBufferArray(Vector<sp<MediaCodecBuffer>> * array)959 void CCodecBufferChannel::getOutputBufferArray(Vector<sp<MediaCodecBuffer>> *array) {
960     array->clear();
961     Mutexed<Output>::Locked output(mOutput);
962 
963     if (!output->buffers->isArrayMode()) {
964         output->buffers = output->buffers->toArrayMode(output->numSlots);
965     }
966 
967     output->buffers->getArray(array);
968 }
969 
start(const sp<AMessage> & inputFormat,const sp<AMessage> & outputFormat,bool buffersBoundToCodec)970 status_t CCodecBufferChannel::start(
971         const sp<AMessage> &inputFormat,
972         const sp<AMessage> &outputFormat,
973         bool buffersBoundToCodec) {
974     C2StreamBufferTypeSetting::input iStreamFormat(0u);
975     C2StreamBufferTypeSetting::output oStreamFormat(0u);
976     C2ComponentKindSetting kind;
977     C2PortReorderBufferDepthTuning::output reorderDepth;
978     C2PortReorderKeySetting::output reorderKey;
979     C2PortActualDelayTuning::input inputDelay(0);
980     C2PortActualDelayTuning::output outputDelay(0);
981     C2ActualPipelineDelayTuning pipelineDelay(0);
982     C2SecureModeTuning secureMode(C2Config::SM_UNPROTECTED);
983 
984     c2_status_t err = mComponent->query(
985             {
986                 &iStreamFormat,
987                 &oStreamFormat,
988                 &kind,
989                 &reorderDepth,
990                 &reorderKey,
991                 &inputDelay,
992                 &pipelineDelay,
993                 &outputDelay,
994                 &secureMode,
995             },
996             {},
997             C2_DONT_BLOCK,
998             nullptr);
999     if (err == C2_BAD_INDEX) {
1000         if (!iStreamFormat || !oStreamFormat || !kind) {
1001             return UNKNOWN_ERROR;
1002         }
1003     } else if (err != C2_OK) {
1004         return UNKNOWN_ERROR;
1005     }
1006 
1007     uint32_t inputDelayValue = inputDelay ? inputDelay.value : 0;
1008     uint32_t pipelineDelayValue = pipelineDelay ? pipelineDelay.value : 0;
1009     uint32_t outputDelayValue = outputDelay ? outputDelay.value : 0;
1010 
1011     size_t numInputSlots = inputDelayValue + pipelineDelayValue + kSmoothnessFactor;
1012     size_t numOutputSlots = outputDelayValue + kSmoothnessFactor;
1013 
1014     // TODO: get this from input format
1015     bool secure = mComponent->getName().find(".secure") != std::string::npos;
1016 
1017     // secure mode is a static parameter (shall not change in the executing state)
1018     mSendEncryptedInfoBuffer = secureMode.value == C2Config::SM_READ_PROTECTED_WITH_ENCRYPTED;
1019 
1020     std::shared_ptr<C2AllocatorStore> allocatorStore = GetCodec2PlatformAllocatorStore();
1021     int poolMask = GetCodec2PoolMask();
1022     C2PlatformAllocatorStore::id_t preferredLinearId = GetPreferredLinearAllocatorId(poolMask);
1023 
1024     if (inputFormat != nullptr) {
1025         bool graphic = (iStreamFormat.value == C2BufferData::GRAPHIC);
1026         bool audioEncoder = !graphic && (kind.value == C2Component::KIND_ENCODER);
1027         C2Config::api_feature_t apiFeatures = C2Config::api_feature_t(
1028                 API_REFLECTION |
1029                 API_VALUES |
1030                 API_CURRENT_VALUES |
1031                 API_DEPENDENCY |
1032                 API_SAME_INPUT_BUFFER);
1033         C2StreamAudioFrameSizeInfo::input encoderFrameSize(0u);
1034         C2StreamSampleRateInfo::input sampleRate(0u);
1035         C2StreamChannelCountInfo::input channelCount(0u);
1036         C2StreamPcmEncodingInfo::input pcmEncoding(0u);
1037         std::shared_ptr<C2BlockPool> pool;
1038         {
1039             Mutexed<BlockPools>::Locked pools(mBlockPools);
1040 
1041             // set default allocator ID.
1042             pools->inputAllocatorId = (graphic) ? C2PlatformAllocatorStore::GRALLOC
1043                                                 : preferredLinearId;
1044 
1045             // query C2PortAllocatorsTuning::input from component. If an allocator ID is obtained
1046             // from component, create the input block pool with given ID. Otherwise, use default IDs.
1047             std::vector<std::unique_ptr<C2Param>> params;
1048             C2ApiFeaturesSetting featuresSetting{apiFeatures};
1049             std::vector<C2Param *> stackParams({&featuresSetting});
1050             if (audioEncoder) {
1051                 stackParams.push_back(&encoderFrameSize);
1052                 stackParams.push_back(&sampleRate);
1053                 stackParams.push_back(&channelCount);
1054                 stackParams.push_back(&pcmEncoding);
1055             } else {
1056                 encoderFrameSize.invalidate();
1057                 sampleRate.invalidate();
1058                 channelCount.invalidate();
1059                 pcmEncoding.invalidate();
1060             }
1061             err = mComponent->query(stackParams,
1062                                     { C2PortAllocatorsTuning::input::PARAM_TYPE },
1063                                     C2_DONT_BLOCK,
1064                                     &params);
1065             if ((err != C2_OK && err != C2_BAD_INDEX) || params.size() != 1) {
1066                 ALOGD("[%s] Query input allocators returned %zu params => %s (%u)",
1067                         mName, params.size(), asString(err), err);
1068             } else if (params.size() == 1) {
1069                 C2PortAllocatorsTuning::input *inputAllocators =
1070                     C2PortAllocatorsTuning::input::From(params[0].get());
1071                 if (inputAllocators && inputAllocators->flexCount() > 0) {
1072                     std::shared_ptr<C2Allocator> allocator;
1073                     // verify allocator IDs and resolve default allocator
1074                     allocatorStore->fetchAllocator(inputAllocators->m.values[0], &allocator);
1075                     if (allocator) {
1076                         pools->inputAllocatorId = allocator->getId();
1077                     } else {
1078                         ALOGD("[%s] component requested invalid input allocator ID %u",
1079                                 mName, inputAllocators->m.values[0]);
1080                     }
1081                 }
1082             }
1083             if (featuresSetting) {
1084                 apiFeatures = featuresSetting.value;
1085             }
1086 
1087             // TODO: use C2Component wrapper to associate this pool with ourselves
1088             if ((poolMask >> pools->inputAllocatorId) & 1) {
1089                 err = CreateCodec2BlockPool(pools->inputAllocatorId, nullptr, &pool);
1090                 ALOGD("[%s] Created input block pool with allocatorID %u => poolID %llu - %s (%d)",
1091                         mName, pools->inputAllocatorId,
1092                         (unsigned long long)(pool ? pool->getLocalId() : 111000111),
1093                         asString(err), err);
1094             } else {
1095                 err = C2_NOT_FOUND;
1096             }
1097             if (err != C2_OK) {
1098                 C2BlockPool::local_id_t inputPoolId =
1099                     graphic ? C2BlockPool::BASIC_GRAPHIC : C2BlockPool::BASIC_LINEAR;
1100                 err = GetCodec2BlockPool(inputPoolId, nullptr, &pool);
1101                 ALOGD("[%s] Using basic input block pool with poolID %llu => got %llu - %s (%d)",
1102                         mName, (unsigned long long)inputPoolId,
1103                         (unsigned long long)(pool ? pool->getLocalId() : 111000111),
1104                         asString(err), err);
1105                 if (err != C2_OK) {
1106                     return NO_MEMORY;
1107                 }
1108             }
1109             pools->inputPool = pool;
1110         }
1111 
1112         bool forceArrayMode = false;
1113         Mutexed<Input>::Locked input(mInput);
1114         input->inputDelay = inputDelayValue;
1115         input->pipelineDelay = pipelineDelayValue;
1116         input->numSlots = numInputSlots;
1117         input->extraBuffers.flush();
1118         input->numExtraSlots = 0u;
1119         if (audioEncoder && encoderFrameSize && sampleRate && channelCount) {
1120             input->frameReassembler.init(
1121                     pool,
1122                     {C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE},
1123                     encoderFrameSize.value,
1124                     sampleRate.value,
1125                     channelCount.value,
1126                     pcmEncoding ? pcmEncoding.value : C2Config::PCM_16);
1127         }
1128         bool conforming = (apiFeatures & API_SAME_INPUT_BUFFER);
1129         // For encrypted content, framework decrypts source buffer (ashmem) into
1130         // C2Buffers. Thus non-conforming codecs can process these.
1131         if (!buffersBoundToCodec
1132                 && !input->frameReassembler
1133                 && (hasCryptoOrDescrambler() || conforming)) {
1134             input->buffers.reset(new SlotInputBuffers(mName));
1135         } else if (graphic) {
1136             if (mInputSurface) {
1137                 input->buffers.reset(new DummyInputBuffers(mName));
1138             } else if (mMetaMode == MODE_ANW) {
1139                 input->buffers.reset(new GraphicMetadataInputBuffers(mName));
1140                 // This is to ensure buffers do not get released prematurely.
1141                 // TODO: handle this without going into array mode
1142                 forceArrayMode = true;
1143             } else {
1144                 input->buffers.reset(new GraphicInputBuffers(mName));
1145             }
1146         } else {
1147             if (hasCryptoOrDescrambler()) {
1148                 int32_t capacity = kLinearBufferSize;
1149                 (void)inputFormat->findInt32(KEY_MAX_INPUT_SIZE, &capacity);
1150                 if ((size_t)capacity > kMaxLinearBufferSize) {
1151                     ALOGD("client requested %d, capped to %zu", capacity, kMaxLinearBufferSize);
1152                     capacity = kMaxLinearBufferSize;
1153                 }
1154                 if (mDealer == nullptr) {
1155                     mDealer = new MemoryDealer(
1156                             align(capacity, MemoryDealer::getAllocationAlignment())
1157                                 * (numInputSlots + 1),
1158                             "EncryptedLinearInputBuffers");
1159                     mDecryptDestination = mDealer->allocate((size_t)capacity);
1160                 }
1161                 if (mCrypto != nullptr && mHeapSeqNum < 0) {
1162                     sp<HidlMemory> heap = fromHeap(mDealer->getMemoryHeap());
1163                     mHeapSeqNum = mCrypto->setHeap(heap);
1164                 } else {
1165                     mHeapSeqNum = -1;
1166                 }
1167                 input->buffers.reset(new EncryptedLinearInputBuffers(
1168                         secure, mDealer, mCrypto, mHeapSeqNum, (size_t)capacity,
1169                         numInputSlots, mName));
1170                 forceArrayMode = true;
1171             } else {
1172                 input->buffers.reset(new LinearInputBuffers(mName));
1173             }
1174         }
1175         input->buffers->setFormat(inputFormat);
1176 
1177         if (err == C2_OK) {
1178             input->buffers->setPool(pool);
1179         } else {
1180             // TODO: error
1181         }
1182 
1183         if (forceArrayMode) {
1184             input->buffers = input->buffers->toArrayMode(numInputSlots);
1185         }
1186     }
1187 
1188     if (outputFormat != nullptr) {
1189         sp<IGraphicBufferProducer> outputSurface;
1190         uint32_t outputGeneration;
1191         int maxDequeueCount = 0;
1192         {
1193             Mutexed<OutputSurface>::Locked output(mOutputSurface);
1194             maxDequeueCount = output->maxDequeueBuffers = numOutputSlots +
1195                     reorderDepth.value + kRenderingDepth;
1196             outputSurface = output->surface ?
1197                     output->surface->getIGraphicBufferProducer() : nullptr;
1198             if (outputSurface) {
1199                 output->surface->setMaxDequeuedBufferCount(output->maxDequeueBuffers);
1200             }
1201             outputGeneration = output->generation;
1202         }
1203 
1204         bool graphic = (oStreamFormat.value == C2BufferData::GRAPHIC);
1205         C2BlockPool::local_id_t outputPoolId_;
1206         C2BlockPool::local_id_t prevOutputPoolId;
1207 
1208         {
1209             Mutexed<BlockPools>::Locked pools(mBlockPools);
1210 
1211             prevOutputPoolId = pools->outputPoolId;
1212 
1213             // set default allocator ID.
1214             pools->outputAllocatorId = (graphic) ? C2PlatformAllocatorStore::GRALLOC
1215                                                  : preferredLinearId;
1216 
1217             // query C2PortAllocatorsTuning::output from component, or use default allocator if
1218             // unsuccessful.
1219             std::vector<std::unique_ptr<C2Param>> params;
1220             err = mComponent->query({ },
1221                                     { C2PortAllocatorsTuning::output::PARAM_TYPE },
1222                                     C2_DONT_BLOCK,
1223                                     &params);
1224             if ((err != C2_OK && err != C2_BAD_INDEX) || params.size() != 1) {
1225                 ALOGD("[%s] Query output allocators returned %zu params => %s (%u)",
1226                         mName, params.size(), asString(err), err);
1227             } else if (err == C2_OK && params.size() == 1) {
1228                 C2PortAllocatorsTuning::output *outputAllocators =
1229                     C2PortAllocatorsTuning::output::From(params[0].get());
1230                 if (outputAllocators && outputAllocators->flexCount() > 0) {
1231                     std::shared_ptr<C2Allocator> allocator;
1232                     // verify allocator IDs and resolve default allocator
1233                     allocatorStore->fetchAllocator(outputAllocators->m.values[0], &allocator);
1234                     if (allocator) {
1235                         pools->outputAllocatorId = allocator->getId();
1236                     } else {
1237                         ALOGD("[%s] component requested invalid output allocator ID %u",
1238                                 mName, outputAllocators->m.values[0]);
1239                     }
1240                 }
1241             }
1242 
1243             // use bufferqueue if outputting to a surface.
1244             // query C2PortSurfaceAllocatorTuning::output from component, or use default allocator
1245             // if unsuccessful.
1246             if (outputSurface) {
1247                 params.clear();
1248                 err = mComponent->query({ },
1249                                         { C2PortSurfaceAllocatorTuning::output::PARAM_TYPE },
1250                                         C2_DONT_BLOCK,
1251                                         &params);
1252                 if ((err != C2_OK && err != C2_BAD_INDEX) || params.size() != 1) {
1253                     ALOGD("[%s] Query output surface allocator returned %zu params => %s (%u)",
1254                             mName, params.size(), asString(err), err);
1255                 } else if (err == C2_OK && params.size() == 1) {
1256                     C2PortSurfaceAllocatorTuning::output *surfaceAllocator =
1257                         C2PortSurfaceAllocatorTuning::output::From(params[0].get());
1258                     if (surfaceAllocator) {
1259                         std::shared_ptr<C2Allocator> allocator;
1260                         // verify allocator IDs and resolve default allocator
1261                         allocatorStore->fetchAllocator(surfaceAllocator->value, &allocator);
1262                         if (allocator) {
1263                             pools->outputAllocatorId = allocator->getId();
1264                         } else {
1265                             ALOGD("[%s] component requested invalid surface output allocator ID %u",
1266                                     mName, surfaceAllocator->value);
1267                             err = C2_BAD_VALUE;
1268                         }
1269                     }
1270                 }
1271                 if (pools->outputAllocatorId == C2PlatformAllocatorStore::GRALLOC
1272                         && err != C2_OK
1273                         && ((poolMask >> C2PlatformAllocatorStore::BUFFERQUEUE) & 1)) {
1274                     pools->outputAllocatorId = C2PlatformAllocatorStore::BUFFERQUEUE;
1275                 }
1276             }
1277 
1278             if ((poolMask >> pools->outputAllocatorId) & 1) {
1279                 err = mComponent->createBlockPool(
1280                         pools->outputAllocatorId, &pools->outputPoolId, &pools->outputPoolIntf);
1281                 ALOGI("[%s] Created output block pool with allocatorID %u => poolID %llu - %s",
1282                         mName, pools->outputAllocatorId,
1283                         (unsigned long long)pools->outputPoolId,
1284                         asString(err));
1285             } else {
1286                 err = C2_NOT_FOUND;
1287             }
1288             if (err != C2_OK) {
1289                 // use basic pool instead
1290                 pools->outputPoolId =
1291                     graphic ? C2BlockPool::BASIC_GRAPHIC : C2BlockPool::BASIC_LINEAR;
1292             }
1293 
1294             // Configure output block pool ID as parameter C2PortBlockPoolsTuning::output to
1295             // component.
1296             std::unique_ptr<C2PortBlockPoolsTuning::output> poolIdsTuning =
1297                     C2PortBlockPoolsTuning::output::AllocUnique({ pools->outputPoolId });
1298 
1299             std::vector<std::unique_ptr<C2SettingResult>> failures;
1300             err = mComponent->config({ poolIdsTuning.get() }, C2_MAY_BLOCK, &failures);
1301             ALOGD("[%s] Configured output block pool ids %llu => %s",
1302                     mName, (unsigned long long)poolIdsTuning->m.values[0], asString(err));
1303             outputPoolId_ = pools->outputPoolId;
1304         }
1305 
1306         if (prevOutputPoolId != C2BlockPool::BASIC_LINEAR
1307                 && prevOutputPoolId != C2BlockPool::BASIC_GRAPHIC) {
1308             c2_status_t err = mComponent->destroyBlockPool(prevOutputPoolId);
1309             if (err != C2_OK) {
1310                 ALOGW("Failed to clean up previous block pool %llu - %s (%d)\n",
1311                         (unsigned long long) prevOutputPoolId, asString(err), err);
1312             }
1313         }
1314 
1315         Mutexed<Output>::Locked output(mOutput);
1316         output->outputDelay = outputDelayValue;
1317         output->numSlots = numOutputSlots;
1318         if (graphic) {
1319             if (outputSurface || !buffersBoundToCodec) {
1320                 output->buffers.reset(new GraphicOutputBuffers(mName));
1321             } else {
1322                 output->buffers.reset(new RawGraphicOutputBuffers(mName));
1323             }
1324         } else {
1325             output->buffers.reset(new LinearOutputBuffers(mName));
1326         }
1327         output->buffers->setFormat(outputFormat);
1328 
1329         output->buffers->clearStash();
1330         if (reorderDepth) {
1331             output->buffers->setReorderDepth(reorderDepth.value);
1332         }
1333         if (reorderKey) {
1334             output->buffers->setReorderKey(reorderKey.value);
1335         }
1336 
1337         // Try to set output surface to created block pool if given.
1338         if (outputSurface) {
1339             mComponent->setOutputSurface(
1340                     outputPoolId_,
1341                     outputSurface,
1342                     outputGeneration,
1343                     maxDequeueCount);
1344         } else {
1345             // configure CPU read consumer usage
1346             C2StreamUsageTuning::output outputUsage{0u, C2MemoryUsage::CPU_READ};
1347             std::vector<std::unique_ptr<C2SettingResult>> failures;
1348             err = mComponent->config({ &outputUsage }, C2_MAY_BLOCK, &failures);
1349             // do not print error message for now as most components may not yet
1350             // support this setting
1351             ALOGD_IF(err != C2_BAD_INDEX, "[%s] Configured output usage [%#llx]",
1352                   mName, (long long)outputUsage.value);
1353         }
1354 
1355         if (oStreamFormat.value == C2BufferData::LINEAR) {
1356             if (buffersBoundToCodec) {
1357                 // WORKAROUND: if we're using early CSD workaround we convert to
1358                 //             array mode, to appease apps assuming the output
1359                 //             buffers to be of the same size.
1360                 output->buffers = output->buffers->toArrayMode(numOutputSlots);
1361             }
1362 
1363             int32_t channelCount;
1364             int32_t sampleRate;
1365             if (outputFormat->findInt32(KEY_CHANNEL_COUNT, &channelCount)
1366                     && outputFormat->findInt32(KEY_SAMPLE_RATE, &sampleRate)) {
1367                 int32_t delay = 0;
1368                 int32_t padding = 0;;
1369                 if (!outputFormat->findInt32("encoder-delay", &delay)) {
1370                     delay = 0;
1371                 }
1372                 if (!outputFormat->findInt32("encoder-padding", &padding)) {
1373                     padding = 0;
1374                 }
1375                 if (delay || padding) {
1376                     // We need write access to the buffers, and we're already in
1377                     // array mode.
1378                     output->buffers->initSkipCutBuffer(delay, padding, sampleRate, channelCount);
1379                 }
1380             }
1381         }
1382     }
1383 
1384     // Set up pipeline control. This has to be done after mInputBuffers and
1385     // mOutputBuffers are initialized to make sure that lingering callbacks
1386     // about buffers from the previous generation do not interfere with the
1387     // newly initialized pipeline capacity.
1388 
1389     if (inputFormat || outputFormat) {
1390         Mutexed<PipelineWatcher>::Locked watcher(mPipelineWatcher);
1391         watcher->inputDelay(inputDelayValue)
1392                 .pipelineDelay(pipelineDelayValue)
1393                 .outputDelay(outputDelayValue)
1394                 .smoothnessFactor(kSmoothnessFactor);
1395         watcher->flush();
1396     }
1397 
1398     mInputMetEos = false;
1399     mSync.start();
1400     return OK;
1401 }
1402 
requestInitialInputBuffers()1403 status_t CCodecBufferChannel::requestInitialInputBuffers() {
1404     if (mInputSurface) {
1405         return OK;
1406     }
1407 
1408     C2StreamBufferTypeSetting::output oStreamFormat(0u);
1409     C2PrependHeaderModeSetting prepend(PREPEND_HEADER_TO_NONE);
1410     c2_status_t err = mComponent->query({ &oStreamFormat, &prepend }, {}, C2_DONT_BLOCK, nullptr);
1411     if (err != C2_OK && err != C2_BAD_INDEX) {
1412         return UNKNOWN_ERROR;
1413     }
1414     size_t numInputSlots = mInput.lock()->numSlots;
1415 
1416     struct ClientInputBuffer {
1417         size_t index;
1418         sp<MediaCodecBuffer> buffer;
1419         size_t capacity;
1420     };
1421     std::list<ClientInputBuffer> clientInputBuffers;
1422 
1423     {
1424         Mutexed<Input>::Locked input(mInput);
1425         while (clientInputBuffers.size() < numInputSlots) {
1426             ClientInputBuffer clientInputBuffer;
1427             if (!input->buffers->requestNewBuffer(&clientInputBuffer.index,
1428                                                   &clientInputBuffer.buffer)) {
1429                 break;
1430             }
1431             clientInputBuffer.capacity = clientInputBuffer.buffer->capacity();
1432             clientInputBuffers.emplace_back(std::move(clientInputBuffer));
1433         }
1434     }
1435     if (clientInputBuffers.empty()) {
1436         ALOGW("[%s] start: cannot allocate memory at all", mName);
1437         return NO_MEMORY;
1438     } else if (clientInputBuffers.size() < numInputSlots) {
1439         ALOGD("[%s] start: cannot allocate memory for all slots, "
1440               "only %zu buffers allocated",
1441               mName, clientInputBuffers.size());
1442     } else {
1443         ALOGV("[%s] %zu initial input buffers available",
1444               mName, clientInputBuffers.size());
1445     }
1446     // Sort input buffers by their capacities in increasing order.
1447     clientInputBuffers.sort(
1448             [](const ClientInputBuffer& a, const ClientInputBuffer& b) {
1449                 return a.capacity < b.capacity;
1450             });
1451 
1452     std::list<std::unique_ptr<C2Work>> flushedConfigs;
1453     mFlushedConfigs.lock()->swap(flushedConfigs);
1454     if (!flushedConfigs.empty()) {
1455         err = mComponent->queue(&flushedConfigs);
1456         if (err != C2_OK) {
1457             ALOGW("[%s] Error while queueing a flushed config", mName);
1458             return UNKNOWN_ERROR;
1459         }
1460     }
1461     if (oStreamFormat.value == C2BufferData::LINEAR &&
1462             (!prepend || prepend.value == PREPEND_HEADER_TO_NONE)) {
1463         sp<MediaCodecBuffer> buffer = clientInputBuffers.front().buffer;
1464         // WORKAROUND: Some apps expect CSD available without queueing
1465         //             any input. Queue an empty buffer to get the CSD.
1466         buffer->setRange(0, 0);
1467         buffer->meta()->clear();
1468         buffer->meta()->setInt64("timeUs", 0);
1469         if (queueInputBufferInternal(buffer) != OK) {
1470             ALOGW("[%s] Error while queueing an empty buffer to get CSD",
1471                   mName);
1472             return UNKNOWN_ERROR;
1473         }
1474         clientInputBuffers.pop_front();
1475     }
1476 
1477     for (const ClientInputBuffer& clientInputBuffer: clientInputBuffers) {
1478         mCallback->onInputBufferAvailable(
1479                 clientInputBuffer.index,
1480                 clientInputBuffer.buffer);
1481     }
1482 
1483     return OK;
1484 }
1485 
stop()1486 void CCodecBufferChannel::stop() {
1487     mSync.stop();
1488     mFirstValidFrameIndex = mFrameIndex.load(std::memory_order_relaxed);
1489 }
1490 
reset()1491 void CCodecBufferChannel::reset() {
1492     stop();
1493     if (mInputSurface != nullptr) {
1494         mInputSurface.reset();
1495     }
1496     mPipelineWatcher.lock()->flush();
1497     {
1498         Mutexed<Input>::Locked input(mInput);
1499         input->buffers.reset(new DummyInputBuffers(""));
1500         input->extraBuffers.flush();
1501     }
1502     {
1503         Mutexed<Output>::Locked output(mOutput);
1504         output->buffers.reset();
1505     }
1506 }
1507 
release()1508 void CCodecBufferChannel::release() {
1509     mComponent.reset();
1510     mInputAllocator.reset();
1511     mOutputSurface.lock()->surface.clear();
1512     {
1513         Mutexed<BlockPools>::Locked blockPools{mBlockPools};
1514         blockPools->inputPool.reset();
1515         blockPools->outputPoolIntf.reset();
1516     }
1517     setCrypto(nullptr);
1518     setDescrambler(nullptr);
1519 }
1520 
1521 
flush(const std::list<std::unique_ptr<C2Work>> & flushedWork)1522 void CCodecBufferChannel::flush(const std::list<std::unique_ptr<C2Work>> &flushedWork) {
1523     ALOGV("[%s] flush", mName);
1524     std::vector<uint64_t> indices;
1525     std::list<std::unique_ptr<C2Work>> configs;
1526     for (const std::unique_ptr<C2Work> &work : flushedWork) {
1527         indices.push_back(work->input.ordinal.frameIndex.peeku());
1528         if (!(work->input.flags & C2FrameData::FLAG_CODEC_CONFIG)) {
1529             continue;
1530         }
1531         if (work->input.buffers.empty()
1532                 || work->input.buffers.front() == nullptr
1533                 || work->input.buffers.front()->data().linearBlocks().empty()) {
1534             ALOGD("[%s] no linear codec config data found", mName);
1535             continue;
1536         }
1537         std::unique_ptr<C2Work> copy(new C2Work);
1538         copy->input.flags = C2FrameData::flags_t(work->input.flags | C2FrameData::FLAG_DROP_FRAME);
1539         copy->input.ordinal = work->input.ordinal;
1540         copy->input.ordinal.frameIndex = mFrameIndex++;
1541         copy->input.buffers.insert(
1542                 copy->input.buffers.begin(),
1543                 work->input.buffers.begin(),
1544                 work->input.buffers.end());
1545         for (const std::unique_ptr<C2Param> &param : work->input.configUpdate) {
1546             copy->input.configUpdate.push_back(C2Param::Copy(*param));
1547         }
1548         copy->input.infoBuffers.insert(
1549                 copy->input.infoBuffers.begin(),
1550                 work->input.infoBuffers.begin(),
1551                 work->input.infoBuffers.end());
1552         copy->worklets.emplace_back(new C2Worklet);
1553         configs.push_back(std::move(copy));
1554         ALOGV("[%s] stashed flushed codec config data", mName);
1555     }
1556     mFlushedConfigs.lock()->swap(configs);
1557     {
1558         Mutexed<Input>::Locked input(mInput);
1559         input->buffers->flush();
1560         input->extraBuffers.flush();
1561     }
1562     {
1563         Mutexed<Output>::Locked output(mOutput);
1564         if (output->buffers) {
1565             output->buffers->flush(flushedWork);
1566             output->buffers->flushStash();
1567         }
1568     }
1569     {
1570         Mutexed<PipelineWatcher>::Locked watcher(mPipelineWatcher);
1571         for (uint64_t index : indices) {
1572             watcher->onWorkDone(index);
1573         }
1574     }
1575 }
1576 
onWorkDone(std::unique_ptr<C2Work> work,const sp<AMessage> & outputFormat,const C2StreamInitDataInfo::output * initData)1577 void CCodecBufferChannel::onWorkDone(
1578         std::unique_ptr<C2Work> work, const sp<AMessage> &outputFormat,
1579         const C2StreamInitDataInfo::output *initData) {
1580     if (handleWork(std::move(work), outputFormat, initData)) {
1581         feedInputBufferIfAvailable();
1582     }
1583 }
1584 
onInputBufferDone(uint64_t frameIndex,size_t arrayIndex)1585 void CCodecBufferChannel::onInputBufferDone(
1586         uint64_t frameIndex, size_t arrayIndex) {
1587     if (mInputSurface) {
1588         return;
1589     }
1590     std::shared_ptr<C2Buffer> buffer =
1591             mPipelineWatcher.lock()->onInputBufferReleased(frameIndex, arrayIndex);
1592     bool newInputSlotAvailable;
1593     {
1594         Mutexed<Input>::Locked input(mInput);
1595         newInputSlotAvailable = input->buffers->expireComponentBuffer(buffer);
1596         if (!newInputSlotAvailable) {
1597             (void)input->extraBuffers.expireComponentBuffer(buffer);
1598         }
1599     }
1600     if (newInputSlotAvailable) {
1601         feedInputBufferIfAvailable();
1602     }
1603 }
1604 
handleWork(std::unique_ptr<C2Work> work,const sp<AMessage> & outputFormat,const C2StreamInitDataInfo::output * initData)1605 bool CCodecBufferChannel::handleWork(
1606         std::unique_ptr<C2Work> work,
1607         const sp<AMessage> &outputFormat,
1608         const C2StreamInitDataInfo::output *initData) {
1609     {
1610         Mutexed<Output>::Locked output(mOutput);
1611         if (!output->buffers) {
1612             return false;
1613         }
1614     }
1615 
1616     // Whether the output buffer should be reported to the client or not.
1617     bool notifyClient = false;
1618 
1619     if (work->result == C2_OK){
1620         notifyClient = true;
1621     } else if (work->result == C2_NOT_FOUND) {
1622         ALOGD("[%s] flushed work; ignored.", mName);
1623     } else {
1624         // C2_OK and C2_NOT_FOUND are the only results that we accept for processing
1625         // the config update.
1626         ALOGD("[%s] work failed to complete: %d", mName, work->result);
1627         mCCodecCallback->onError(work->result, ACTION_CODE_FATAL);
1628         return false;
1629     }
1630 
1631     if ((work->input.ordinal.frameIndex -
1632             mFirstValidFrameIndex.load()).peek() < 0) {
1633         // Discard frames from previous generation.
1634         ALOGD("[%s] Discard frames from previous generation.", mName);
1635         notifyClient = false;
1636     }
1637 
1638     if (mInputSurface == nullptr && (work->worklets.size() != 1u
1639             || !work->worklets.front()
1640             || !(work->worklets.front()->output.flags &
1641                  C2FrameData::FLAG_INCOMPLETE))) {
1642         mPipelineWatcher.lock()->onWorkDone(
1643                 work->input.ordinal.frameIndex.peeku());
1644     }
1645 
1646     // NOTE: MediaCodec usage supposedly have only one worklet
1647     if (work->worklets.size() != 1u) {
1648         ALOGI("[%s] onWorkDone: incorrect number of worklets: %zu",
1649                 mName, work->worklets.size());
1650         mCCodecCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL);
1651         return false;
1652     }
1653 
1654     const std::unique_ptr<C2Worklet> &worklet = work->worklets.front();
1655 
1656     std::shared_ptr<C2Buffer> buffer;
1657     // NOTE: MediaCodec usage supposedly have only one output stream.
1658     if (worklet->output.buffers.size() > 1u) {
1659         ALOGI("[%s] onWorkDone: incorrect number of output buffers: %zu",
1660                 mName, worklet->output.buffers.size());
1661         mCCodecCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL);
1662         return false;
1663     } else if (worklet->output.buffers.size() == 1u) {
1664         buffer = worklet->output.buffers[0];
1665         if (!buffer) {
1666             ALOGD("[%s] onWorkDone: nullptr found in buffers; ignored.", mName);
1667         }
1668     }
1669 
1670     std::optional<uint32_t> newInputDelay, newPipelineDelay, newOutputDelay, newReorderDepth;
1671     std::optional<C2Config::ordinal_key_t> newReorderKey;
1672     bool needMaxDequeueBufferCountUpdate = false;
1673     while (!worklet->output.configUpdate.empty()) {
1674         std::unique_ptr<C2Param> param;
1675         worklet->output.configUpdate.back().swap(param);
1676         worklet->output.configUpdate.pop_back();
1677         switch (param->coreIndex().coreIndex()) {
1678             case C2PortReorderBufferDepthTuning::CORE_INDEX: {
1679                 C2PortReorderBufferDepthTuning::output reorderDepth;
1680                 if (reorderDepth.updateFrom(*param)) {
1681                     ALOGV("[%s] onWorkDone: updated reorder depth to %u",
1682                           mName, reorderDepth.value);
1683                     newReorderDepth = reorderDepth.value;
1684                     needMaxDequeueBufferCountUpdate = true;
1685                 } else {
1686                     ALOGD("[%s] onWorkDone: failed to read reorder depth",
1687                           mName);
1688                 }
1689                 break;
1690             }
1691             case C2PortReorderKeySetting::CORE_INDEX: {
1692                 C2PortReorderKeySetting::output reorderKey;
1693                 if (reorderKey.updateFrom(*param)) {
1694                     newReorderKey = reorderKey.value;
1695                     ALOGV("[%s] onWorkDone: updated reorder key to %u",
1696                           mName, reorderKey.value);
1697                 } else {
1698                     ALOGD("[%s] onWorkDone: failed to read reorder key", mName);
1699                 }
1700                 break;
1701             }
1702             case C2PortActualDelayTuning::CORE_INDEX: {
1703                 if (param->isGlobal()) {
1704                     C2ActualPipelineDelayTuning pipelineDelay;
1705                     if (pipelineDelay.updateFrom(*param)) {
1706                         ALOGV("[%s] onWorkDone: updating pipeline delay %u",
1707                               mName, pipelineDelay.value);
1708                         newPipelineDelay = pipelineDelay.value;
1709                         (void)mPipelineWatcher.lock()->pipelineDelay(
1710                                 pipelineDelay.value);
1711                     }
1712                 }
1713                 if (param->forInput()) {
1714                     C2PortActualDelayTuning::input inputDelay;
1715                     if (inputDelay.updateFrom(*param)) {
1716                         ALOGV("[%s] onWorkDone: updating input delay %u",
1717                               mName, inputDelay.value);
1718                         newInputDelay = inputDelay.value;
1719                         (void)mPipelineWatcher.lock()->inputDelay(
1720                                 inputDelay.value);
1721                     }
1722                 }
1723                 if (param->forOutput()) {
1724                     C2PortActualDelayTuning::output outputDelay;
1725                     if (outputDelay.updateFrom(*param)) {
1726                         ALOGV("[%s] onWorkDone: updating output delay %u",
1727                               mName, outputDelay.value);
1728                         (void)mPipelineWatcher.lock()->outputDelay(outputDelay.value);
1729                         newOutputDelay = outputDelay.value;
1730                         needMaxDequeueBufferCountUpdate = true;
1731 
1732                     }
1733                 }
1734                 break;
1735             }
1736             case C2PortTunnelSystemTime::CORE_INDEX: {
1737                 C2PortTunnelSystemTime::output frameRenderTime;
1738                 if (frameRenderTime.updateFrom(*param)) {
1739                     ALOGV("[%s] onWorkDone: frame rendered (sys:%lld ns, media:%lld us)",
1740                           mName, (long long)frameRenderTime.value,
1741                           (long long)worklet->output.ordinal.timestamp.peekll());
1742                     mCCodecCallback->onOutputFramesRendered(
1743                             worklet->output.ordinal.timestamp.peek(), frameRenderTime.value);
1744                 }
1745                 break;
1746             }
1747             case C2StreamTunnelHoldRender::CORE_INDEX: {
1748                 C2StreamTunnelHoldRender::output firstTunnelFrameHoldRender;
1749                 if (!(worklet->output.flags & C2FrameData::FLAG_INCOMPLETE)) break;
1750                 if (!firstTunnelFrameHoldRender.updateFrom(*param)) break;
1751                 if (firstTunnelFrameHoldRender.value != C2_TRUE) break;
1752                 ALOGV("[%s] onWorkDone: first tunnel frame ready", mName);
1753                 mCCodecCallback->onFirstTunnelFrameReady();
1754                 break;
1755             }
1756             default:
1757                 ALOGV("[%s] onWorkDone: unrecognized config update (%08X)",
1758                       mName, param->index());
1759                 break;
1760         }
1761     }
1762     if (newInputDelay || newPipelineDelay) {
1763         Mutexed<Input>::Locked input(mInput);
1764         size_t newNumSlots =
1765             newInputDelay.value_or(input->inputDelay) +
1766             newPipelineDelay.value_or(input->pipelineDelay) +
1767             kSmoothnessFactor;
1768         if (input->buffers->isArrayMode()) {
1769             if (input->numSlots >= newNumSlots) {
1770                 input->numExtraSlots = 0;
1771             } else {
1772                 input->numExtraSlots = newNumSlots - input->numSlots;
1773             }
1774             ALOGV("[%s] onWorkDone: updated number of extra slots to %zu (input array mode)",
1775                   mName, input->numExtraSlots);
1776         } else {
1777             input->numSlots = newNumSlots;
1778         }
1779     }
1780     size_t numOutputSlots = 0;
1781     uint32_t reorderDepth = 0;
1782     bool outputBuffersChanged = false;
1783     if (newReorderKey || newReorderDepth || needMaxDequeueBufferCountUpdate) {
1784         Mutexed<Output>::Locked output(mOutput);
1785         if (!output->buffers) {
1786             return false;
1787         }
1788         numOutputSlots = output->numSlots;
1789         if (newReorderKey) {
1790             output->buffers->setReorderKey(newReorderKey.value());
1791         }
1792         if (newReorderDepth) {
1793             output->buffers->setReorderDepth(newReorderDepth.value());
1794         }
1795         reorderDepth = output->buffers->getReorderDepth();
1796         if (newOutputDelay) {
1797             output->outputDelay = newOutputDelay.value();
1798             numOutputSlots = newOutputDelay.value() + kSmoothnessFactor;
1799             if (output->numSlots < numOutputSlots) {
1800                 output->numSlots = numOutputSlots;
1801                 if (output->buffers->isArrayMode()) {
1802                     OutputBuffersArray *array =
1803                         (OutputBuffersArray *)output->buffers.get();
1804                     ALOGV("[%s] onWorkDone: growing output buffer array to %zu",
1805                           mName, numOutputSlots);
1806                     array->grow(numOutputSlots);
1807                     outputBuffersChanged = true;
1808                 }
1809             }
1810         }
1811         numOutputSlots = output->numSlots;
1812     }
1813     if (outputBuffersChanged) {
1814         mCCodecCallback->onOutputBuffersChanged();
1815     }
1816     if (needMaxDequeueBufferCountUpdate) {
1817         int maxDequeueCount = 0;
1818         {
1819             Mutexed<OutputSurface>::Locked output(mOutputSurface);
1820             maxDequeueCount = output->maxDequeueBuffers =
1821                     numOutputSlots + reorderDepth + kRenderingDepth;
1822             if (output->surface) {
1823                 output->surface->setMaxDequeuedBufferCount(output->maxDequeueBuffers);
1824             }
1825         }
1826         if (maxDequeueCount > 0) {
1827             mComponent->setOutputSurfaceMaxDequeueCount(maxDequeueCount);
1828         }
1829     }
1830 
1831     int32_t flags = 0;
1832     if (worklet->output.flags & C2FrameData::FLAG_END_OF_STREAM) {
1833         flags |= MediaCodec::BUFFER_FLAG_EOS;
1834         ALOGV("[%s] onWorkDone: output EOS", mName);
1835     }
1836 
1837     // WORKAROUND: adjust output timestamp based on client input timestamp and codec
1838     // input timestamp. Codec output timestamp (in the timestamp field) shall correspond to
1839     // the codec input timestamp, but client output timestamp should (reported in timeUs)
1840     // shall correspond to the client input timesamp (in customOrdinal). By using the
1841     // delta between the two, this allows for some timestamp deviation - e.g. if one input
1842     // produces multiple output.
1843     c2_cntr64_t timestamp =
1844         worklet->output.ordinal.timestamp + work->input.ordinal.customOrdinal
1845                 - work->input.ordinal.timestamp;
1846     if (mInputSurface != nullptr) {
1847         // When using input surface we need to restore the original input timestamp.
1848         timestamp = work->input.ordinal.customOrdinal;
1849     }
1850     ALOGV("[%s] onWorkDone: input %lld, codec %lld => output %lld => %lld",
1851           mName,
1852           work->input.ordinal.customOrdinal.peekll(),
1853           work->input.ordinal.timestamp.peekll(),
1854           worklet->output.ordinal.timestamp.peekll(),
1855           timestamp.peekll());
1856 
1857     // csd cannot be re-ordered and will always arrive first.
1858     if (initData != nullptr) {
1859         Mutexed<Output>::Locked output(mOutput);
1860         if (output->buffers && outputFormat) {
1861             output->buffers->updateSkipCutBuffer(outputFormat);
1862             output->buffers->setFormat(outputFormat);
1863         }
1864         if (!notifyClient) {
1865             return false;
1866         }
1867         size_t index;
1868         sp<MediaCodecBuffer> outBuffer;
1869         if (output->buffers && output->buffers->registerCsd(initData, &index, &outBuffer) == OK) {
1870             outBuffer->meta()->setInt64("timeUs", timestamp.peek());
1871             outBuffer->meta()->setInt32("flags", MediaCodec::BUFFER_FLAG_CODECCONFIG);
1872             ALOGV("[%s] onWorkDone: csd index = %zu [%p]", mName, index, outBuffer.get());
1873 
1874             output.unlock();
1875             mCallback->onOutputBufferAvailable(index, outBuffer);
1876         } else {
1877             ALOGD("[%s] onWorkDone: unable to register csd", mName);
1878             output.unlock();
1879             mCCodecCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL);
1880             return false;
1881         }
1882     }
1883 
1884     if (notifyClient && !buffer && !flags) {
1885         ALOGV("[%s] onWorkDone: Not reporting output buffer (%lld)",
1886               mName, work->input.ordinal.frameIndex.peekull());
1887         notifyClient = false;
1888     }
1889 
1890     if (buffer) {
1891         for (const std::shared_ptr<const C2Info> &info : buffer->info()) {
1892             // TODO: properly translate these to metadata
1893             switch (info->coreIndex().coreIndex()) {
1894                 case C2StreamPictureTypeMaskInfo::CORE_INDEX:
1895                     if (((C2StreamPictureTypeMaskInfo *)info.get())->value & C2Config::SYNC_FRAME) {
1896                         flags |= MediaCodec::BUFFER_FLAG_SYNCFRAME;
1897                     }
1898                     break;
1899                 default:
1900                     break;
1901             }
1902         }
1903     }
1904 
1905     {
1906         Mutexed<Output>::Locked output(mOutput);
1907         if (!output->buffers) {
1908             return false;
1909         }
1910         output->buffers->pushToStash(
1911                 buffer,
1912                 notifyClient,
1913                 timestamp.peek(),
1914                 flags,
1915                 outputFormat,
1916                 worklet->output.ordinal);
1917     }
1918     sendOutputBuffers();
1919     return true;
1920 }
1921 
sendOutputBuffers()1922 void CCodecBufferChannel::sendOutputBuffers() {
1923     OutputBuffers::BufferAction action;
1924     size_t index;
1925     sp<MediaCodecBuffer> outBuffer;
1926     std::shared_ptr<C2Buffer> c2Buffer;
1927 
1928     while (true) {
1929         Mutexed<Output>::Locked output(mOutput);
1930         if (!output->buffers) {
1931             return;
1932         }
1933         action = output->buffers->popFromStashAndRegister(
1934                 &c2Buffer, &index, &outBuffer);
1935         switch (action) {
1936         case OutputBuffers::SKIP:
1937             return;
1938         case OutputBuffers::DISCARD:
1939             break;
1940         case OutputBuffers::NOTIFY_CLIENT:
1941             output.unlock();
1942             mCallback->onOutputBufferAvailable(index, outBuffer);
1943             break;
1944         case OutputBuffers::REALLOCATE:
1945             if (!output->buffers->isArrayMode()) {
1946                 output->buffers =
1947                     output->buffers->toArrayMode(output->numSlots);
1948             }
1949             static_cast<OutputBuffersArray*>(output->buffers.get())->
1950                     realloc(c2Buffer);
1951             output.unlock();
1952             mCCodecCallback->onOutputBuffersChanged();
1953             break;
1954         case OutputBuffers::RETRY:
1955             ALOGV("[%s] sendOutputBuffers: unable to register output buffer",
1956                   mName);
1957             return;
1958         default:
1959             LOG_ALWAYS_FATAL("[%s] sendOutputBuffers: "
1960                     "corrupted BufferAction value (%d) "
1961                     "returned from popFromStashAndRegister.",
1962                     mName, int(action));
1963             return;
1964         }
1965     }
1966 }
1967 
setSurface(const sp<Surface> & newSurface)1968 status_t CCodecBufferChannel::setSurface(const sp<Surface> &newSurface) {
1969     static std::atomic_uint32_t surfaceGeneration{0};
1970     uint32_t generation = (getpid() << 10) |
1971             ((surfaceGeneration.fetch_add(1, std::memory_order_relaxed) + 1)
1972                 & ((1 << 10) - 1));
1973 
1974     sp<IGraphicBufferProducer> producer;
1975     int maxDequeueCount = mOutputSurface.lock()->maxDequeueBuffers;
1976     if (newSurface) {
1977         newSurface->setScalingMode(NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
1978         newSurface->setDequeueTimeout(kDequeueTimeoutNs);
1979         newSurface->setMaxDequeuedBufferCount(maxDequeueCount);
1980         producer = newSurface->getIGraphicBufferProducer();
1981         producer->setGenerationNumber(generation);
1982     } else {
1983         ALOGE("[%s] setting output surface to null", mName);
1984         return INVALID_OPERATION;
1985     }
1986 
1987     std::shared_ptr<Codec2Client::Configurable> outputPoolIntf;
1988     C2BlockPool::local_id_t outputPoolId;
1989     {
1990         Mutexed<BlockPools>::Locked pools(mBlockPools);
1991         outputPoolId = pools->outputPoolId;
1992         outputPoolIntf = pools->outputPoolIntf;
1993     }
1994 
1995     if (outputPoolIntf) {
1996         if (mComponent->setOutputSurface(
1997                 outputPoolId,
1998                 producer,
1999                 generation,
2000                 maxDequeueCount) != C2_OK) {
2001             ALOGI("[%s] setSurface: component setOutputSurface failed", mName);
2002             return INVALID_OPERATION;
2003         }
2004     }
2005 
2006     {
2007         Mutexed<OutputSurface>::Locked output(mOutputSurface);
2008         output->surface = newSurface;
2009         output->generation = generation;
2010     }
2011 
2012     return OK;
2013 }
2014 
elapsed()2015 PipelineWatcher::Clock::duration CCodecBufferChannel::elapsed() {
2016     // When client pushed EOS, we want all the work to be done quickly.
2017     // Otherwise, component may have stalled work due to input starvation up to
2018     // the sum of the delay in the pipeline.
2019     size_t n = 0;
2020     if (!mInputMetEos) {
2021         size_t outputDelay = mOutput.lock()->outputDelay;
2022         Mutexed<Input>::Locked input(mInput);
2023         n = input->inputDelay + input->pipelineDelay + outputDelay;
2024     }
2025     return mPipelineWatcher.lock()->elapsed(PipelineWatcher::Clock::now(), n);
2026 }
2027 
setMetaMode(MetaMode mode)2028 void CCodecBufferChannel::setMetaMode(MetaMode mode) {
2029     mMetaMode = mode;
2030 }
2031 
setCrypto(const sp<ICrypto> & crypto)2032 void CCodecBufferChannel::setCrypto(const sp<ICrypto> &crypto) {
2033     if (mCrypto != nullptr) {
2034         for (std::pair<wp<HidlMemory>, int32_t> entry : mHeapSeqNumMap) {
2035             mCrypto->unsetHeap(entry.second);
2036         }
2037         mHeapSeqNumMap.clear();
2038         if (mHeapSeqNum >= 0) {
2039             mCrypto->unsetHeap(mHeapSeqNum);
2040             mHeapSeqNum = -1;
2041         }
2042     }
2043     mCrypto = crypto;
2044 }
2045 
setDescrambler(const sp<IDescrambler> & descrambler)2046 void CCodecBufferChannel::setDescrambler(const sp<IDescrambler> &descrambler) {
2047     mDescrambler = descrambler;
2048 }
2049 
toStatusT(c2_status_t c2s,c2_operation_t c2op)2050 status_t toStatusT(c2_status_t c2s, c2_operation_t c2op) {
2051     // C2_OK is always translated to OK.
2052     if (c2s == C2_OK) {
2053         return OK;
2054     }
2055 
2056     // Operation-dependent translation
2057     // TODO: Add as necessary
2058     switch (c2op) {
2059     case C2_OPERATION_Component_start:
2060         switch (c2s) {
2061         case C2_NO_MEMORY:
2062             return NO_MEMORY;
2063         default:
2064             return UNKNOWN_ERROR;
2065         }
2066     default:
2067         break;
2068     }
2069 
2070     // Backup operation-agnostic translation
2071     switch (c2s) {
2072     case C2_BAD_INDEX:
2073         return BAD_INDEX;
2074     case C2_BAD_VALUE:
2075         return BAD_VALUE;
2076     case C2_BLOCKING:
2077         return WOULD_BLOCK;
2078     case C2_DUPLICATE:
2079         return ALREADY_EXISTS;
2080     case C2_NO_INIT:
2081         return NO_INIT;
2082     case C2_NO_MEMORY:
2083         return NO_MEMORY;
2084     case C2_NOT_FOUND:
2085         return NAME_NOT_FOUND;
2086     case C2_TIMED_OUT:
2087         return TIMED_OUT;
2088     case C2_BAD_STATE:
2089     case C2_CANCELED:
2090     case C2_CANNOT_DO:
2091     case C2_CORRUPTED:
2092     case C2_OMITTED:
2093     case C2_REFUSED:
2094         return UNKNOWN_ERROR;
2095     default:
2096         return -static_cast<status_t>(c2s);
2097     }
2098 }
2099 
2100 }  // namespace android
2101