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